1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務(wù)時間:8:30-17:00
      你可能遇到了下面的問題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
      android6.0中fuse文件系統(tǒng)如何掛載和卸載

      這篇文章主要介紹android6.0中fuse文件系統(tǒng)如何掛載和卸載,文中介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們一定要看完!

      成都創(chuàng)新互聯(lián)服務(wù)項目包括紅花崗網(wǎng)站建設(shè)、紅花崗網(wǎng)站制作、紅花崗網(wǎng)頁制作以及紅花崗網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,紅花崗網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到紅花崗省份的部分城市,未來相信會繼續(xù)擴大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!

      android4.4 的時候vold,也是利用fuse文件系統(tǒng)達(dá)到,將sd卡的目錄(storage目錄)獲取sd實際掛載目錄(mnt/media_rw)的權(quán)限。但是android4.4的時候vold只是寫屬性而已,然后init監(jiān)測這個屬性,屬性改變時,才會去啟動sdcard進(jìn)程。

      然后android6.0直接在vold中,fork一個進(jìn)程直接開啟sdcard進(jìn)程掛載fuse文件系統(tǒng)。并且在卸載sd的時候,在vold中卸載fuse文件系統(tǒng)。

      一、掛載sd卡

      下面是解析android6.0vold,掛載sd卡是的一段代碼,我們來看下。顯示掛載sd卡,然后進(jìn)行fuse操作。

       if (vfat::Mount(mDevPath, mRawPath, false, false, false,// 掛載sd卡
         AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) {
        PLOG(ERROR) << getId() << " failed to mount " << mDevPath;
        return -EIO;
       }
       
       if (getMountFlags() & MountFlags::kPrimary) {
        initAsecStage();
       }
       
       if (!(getMountFlags() & MountFlags::kVisible)) {
        // Not visible to apps, so no need to spin up FUSE
        return OK;
       }
       
       //creat dir by fuse before fuse action.
       if (fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||
         fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||
         fs_prepare_dir(mFuseWrite.c_str(), 0700, AID_ROOT, AID_ROOT)) {
        PLOG(ERROR) << getId() << " failed to create fuse points";
        return -errno;
       }
       
       dev_t before = GetDevice(mFuseWrite);
       
       if (!(mFusePid = fork())) {
        if (getMountFlags() & MountFlags::kPrimary) {
         if (execl(kFusePath, kFusePath,//fuse操作
           "-u", "1023", // AID_MEDIA_RW
           "-g", "1023", // AID_MEDIA_RW
           "-U", std::to_string(getMountUserId()).c_str(),
           "-w",
           mRawPath.c_str(),
           stableName.c_str(),
           NULL)) {
          PLOG(ERROR) << "Failed to exec";
         }
        } else {
         if (execl(kFusePath, kFusePath,
           "-u", "1023", // AID_MEDIA_RW
           "-g", "1023", // AID_MEDIA_RW
           "-U", std::to_string(getMountUserId()).c_str(),
           mRawPath.c_str(),
           stableName.c_str(),
           NULL)) {
          PLOG(ERROR) << "Failed to exec";
         }
        }

      我們再來看看fuse的代碼,也就是在sdcard中。先在main函數(shù)中獲取數(shù)據(jù),

      int main(int argc, char **argv) {
       const char *source_path = NULL;
       const char *label = NULL;
       uid_t uid = 0;
       gid_t gid = 0;
       userid_t userid = 0;
       bool multi_user = false;
       bool full_write = false;
       int i;
       struct rlimit rlim;
       int fs_version;
       
       int opt;
       while ((opt = getopt(argc, argv, "u:g:U:mw")) != -1) {
        switch (opt) {
         case 'u':
          uid = strtoul(optarg, NULL, 10);
          break;
         case 'g':
          gid = strtoul(optarg, NULL, 10);
          break;
         case 'U':
          userid = strtoul(optarg, NULL, 10);
          break;
         case 'm':
          multi_user = true;
          break;
         case 'w':
          full_write = true;
          break;
         case '?':
         default:
          return usage();
        }
       }
       
       for (i = optind; i < argc; i++) {
        char* arg = argv[i];
        if (!source_path) {
         source_path = arg;
        } else if (!label) {
         label = arg;
        } else {
         ERROR("too many arguments\n");
         return usage();
        }
       }
       
       if (!source_path) {
        ERROR("no source path specified\n");
        return usage();
       }
       if (!label) {
        ERROR("no label specified\n");
        return usage();
       }
       if (!uid || !gid) {
        ERROR("uid and gid must be nonzero\n");
        return usage();
       }
       
       rlim.rlim_cur = 8192;
       rlim.rlim_max = 8192;
       if (setrlimit(RLIMIT_NOFILE, &rlim)) {
        ERROR("Error setting RLIMIT_NOFILE, errno = %d\n", errno);
       }
       
       while ((fs_read_atomic_int("/data/.layout_version", &fs_version) == -1) || (fs_version < 3)) {
        ERROR("installd fs upgrade not yet complete. Waiting...\n");
        sleep(1);
       }
      	ERROR("kangchen sdcard path:%s label:%s\n", source_path, label);
       
       run(source_path, label, uid, gid, userid, multi_user, full_write);
       return 1;
      }

      其中source_path就是sd卡實際掛載的地址,然后調(diào)用run函數(shù),run函數(shù)中進(jìn)行了一些初始化,然后掛載了default,read,write 3個fuse文件系統(tǒng),后面又開啟3個線程處理這3個文件系統(tǒng)的read,write,open等處理。

      static void run(const char* source_path, const char* label, uid_t uid,
        gid_t gid, userid_t userid, bool multi_user, bool full_write) {
       struct fuse_global global;
       struct fuse fuse_default;
       struct fuse fuse_read;
       struct fuse fuse_write;
       struct fuse_handler handler_default;
       struct fuse_handler handler_read;
       struct fuse_handler handler_write;
       pthread_t thread_default;
       pthread_t thread_read;
       pthread_t thread_write;
       
       memset(&global, 0, sizeof(global));
       memset(&fuse_default, 0, sizeof(fuse_default));
       memset(&fuse_read, 0, sizeof(fuse_read));
       memset(&fuse_write, 0, sizeof(fuse_write));
       memset(&handler_default, 0, sizeof(handler_default));
       memset(&handler_read, 0, sizeof(handler_read));
       memset(&handler_write, 0, sizeof(handler_write));
       
       pthread_mutex_init(&global.lock, NULL);
       global.package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
       global.uid = uid;
       global.gid = gid;
       global.multi_user = multi_user;
       global.next_generation = 0;
       global.inode_ctr = 1;
       
       memset(&global.root, 0, sizeof(global.root));
       global.root.nid = FUSE_ROOT_ID; /* 1 */
       global.root.refcount = 2;
       global.root.namelen = strlen(source_path);
       global.root.name = strdup(source_path);
       global.root.userid = userid;
       global.root.uid = AID_ROOT;
       global.root.under_android = false;
       
       strcpy(global.source_path, source_path);
       
       if (multi_user) {
        global.root.perm = PERM_PRE_ROOT;
        snprintf(global.obb_path, sizeof(global.obb_path), "%s/obb", source_path);
       } else {
        global.root.perm = PERM_ROOT;
        snprintf(global.obb_path, sizeof(global.obb_path), "%s/Android/obb", source_path);
       }
       
       fuse_default.global = &global;
       fuse_read.global = &global;
       fuse_write.global = &global;
       
       global.fuse_default = &fuse_default;
       global.fuse_read = &fuse_read;
       global.fuse_write = &fuse_write;
       
       snprintf(fuse_default.dest_path, PATH_MAX, "/mnt/runtime/default/%s", label);
       snprintf(fuse_read.dest_path, PATH_MAX, "/mnt/runtime/read/%s", label);
       snprintf(fuse_write.dest_path, PATH_MAX, "/mnt/runtime/write/%s", label);
       
       handler_default.fuse = &fuse_default;
       handler_read.fuse = &fuse_read;
       handler_write.fuse = &fuse_write;
       
       handler_default.token = 0;
       handler_read.token = 1;
       handler_write.token = 2;
       
       umask(0);
       
       if (multi_user) {
        /* Multi-user storage is fully isolated per user, so "other"
         * permissions are completely masked off. */
        if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
          || fuse_setup(&fuse_read, AID_EVERYBODY, 0027)
          || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0027)) {
         ERROR("failed to fuse_setup\n");
         exit(1);
        }
       } else {
        /* Physical storage is readable by all users on device, but
         * the Android directories are masked off to a single user
         * deep inside attr_from_stat(). */
        if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
          || fuse_setup(&fuse_read, AID_EVERYBODY, full_write ? 0027 : 0022)
          || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0022)) {
         ERROR("failed to fuse_setup\n");
         exit(1);
        }
       }
       
       /* Drop privs */
       if (setgroups(sizeof(kGroups) / sizeof(kGroups[0]), kGroups) < 0) {
        ERROR("cannot setgroups: %s\n", strerror(errno));
        exit(1);
       }
       if (setgid(gid) < 0) {
        ERROR("cannot setgid: %s\n", strerror(errno));
        exit(1);
       }
       if (setuid(uid) < 0) {
        ERROR("cannot setuid: %s\n", strerror(errno));
        exit(1);
       }
       
       if (multi_user) {
        fs_prepare_dir(global.obb_path, 0775, uid, gid);
       }
       
       if (pthread_create(&thread_default, NULL, start_handler, &handler_default)
         || pthread_create(&thread_read, NULL, start_handler, &handler_read)
         || pthread_create(&thread_write, NULL, start_handler, &handler_write)) {
        ERROR("failed to pthread_create\n");
        exit(1);
       }
       
       watch_package_list(&global);
       ERROR("terminated prematurely\n");
       exit(1);
      }

      其中在fuse_setup中掛載了fuse文件系統(tǒng)

      static int fuse_setup(struct fuse* fuse, gid_t gid, mode_t mask) {
       char opts[256];
       
       fuse->fd = open("/dev/fuse", O_RDWR);
       if (fuse->fd == -1) {
        ERROR("failed to open fuse device: %s\n", strerror(errno));
        return -1;
       }
       
       umount2(fuse->dest_path, MNT_DETACH);
       
       snprintf(opts, sizeof(opts),
         "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d",
         fuse->fd, fuse->global->uid, fuse->global->gid);
       if (mount("/dev/fuse", fuse->dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC |
         MS_NOATIME, opts) != 0) {
        ERROR("failed to mount fuse filesystem: %s\n", strerror(errno));
        return -1;
       }
       
       fuse->gid = gid;
       fuse->mask = mask;
       
       return 0;
      }

      但是雖然掛載了default,read,write 3個fuse文件系統(tǒng)。

      但好像只有default有用,因為在init.rc中將default目錄直接掛載到了storage,而應(yīng)用也就只能拿到storage目錄,所以只有default的fuse實際有用。

      on post-fs 
       start logd 
       
       #add for amt 
       chmod 0755 /amt 
       # once everything is setup, no need to modify / 
       mount rootfs rootfs / ro remount 
       # Mount shared so changes propagate into child namespaces 
       mount rootfs rootfs / shared rec 
       # Mount default storage into root namespace 
       mount none /mnt/runtime/default /storage slave bind rec

      二、sd卡卸載過程

      然后我們再來看看android卸載sd卡的過程,卸載sd卡的時候,是先卸載了fuse文件系統(tǒng),然后在卸載了sd卡的mount地址。

      status_t PublicVolume::doUnmount() {
       if (mFusePid > 0) {
        kill(mFusePid, SIGTERM);
        TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0));
        mFusePid = 0;
       }
       
       ForceUnmount(kAsecPath);
       
       ForceUnmount(mFuseDefault);
       ForceUnmount(mFuseRead);
       ForceUnmount(mFuseWrite);
       ForceUnmount(mRawPath);
       
       rmdir(mFuseDefault.c_str());
       rmdir(mFuseRead.c_str());
       rmdir(mFuseWrite.c_str());
       rmdir(mRawPath.c_str());
       
       mFuseDefault.clear();
       mFuseRead.clear();
       mFuseWrite.clear();
       mRawPath.clear();
       
       return OK;
      }

      總所周知,卸載sd卡mount地址的時候,會去檢查哪些進(jìn)程在使用sd卡中的文件。

      如何檢查呢?是通過proc/pid下面各個文件的軟鏈接,然后通過readlink找到真正的文件地址,來判定是否正在占用sd卡中的文件。

      但是在卸載fuse文件系統(tǒng)的時候,比如你有進(jìn)程在操作sd卡中的文件,這個時候操作sd卡的storage目錄會fuse到sd卡真正的掛載地址上,實際上fuse文件系統(tǒng)是在工作的,導(dǎo)致不能卸載。

      但是這個時候去查找誰占用fuse文件又是查不出來的,因為是進(jìn)程在操作sd卡文件,會導(dǎo)致fuse文件系統(tǒng)的操作,才會卸載不掉fuse文件系統(tǒng)。但是能找到占用的文件只能是sd卡的。

      而且實際中也碰到這樣的問題,所以個人認(rèn)為應(yīng)該先kill正在使用sd卡的進(jìn)程,然后再卸載fuse文件系統(tǒng)。這樣就不會有進(jìn)程操作sd卡中的文件的時候,導(dǎo)致fuse文件系統(tǒng)也在忙而卸載不掉了。我碰到的問題是:一個如下進(jìn)程占用的sd卡文件

      root@lte26007:/proc/2365/fd # ls -l
      lrwx------ root  radio    2016-05-25 13:42 0 -> /dev/null
      lrwx------ root  radio    2016-05-25 13:42 1 -> /dev/null
      lrwx------ root  radio    2016-05-25 13:42 10 -> /storage/2C10-0CCC/elog/elog_20160525_134206/PHY0/test_20160525_134208_00.bin_last_0
      lrwx------ root  radio    2016-05-25 13:42 11 -> /storage/2C10-0CCC/elog/elog_20160525_134206/PHY0/log_up_data.dat
      lrwx------ root  radio    2016-05-25 13:42 12 -> /storage/2C10-0CCC/elog/elog_20160525_134206/PHY1/test_20160525_134209_head.bin
      lrwx------ root  radio    2016-05-25 13:42 13 -> /storage/2C10-0CCC/elog/elog_20160525_134206/PHY1/test_20160525_134209_00.bin_last_0
      lrwx------ root  radio    2016-05-25 13:42 14 -> /storage/2C10-0CCC/elog/elog_20160525_134206/PHY1/log_up_data.dat
      lrwx------ root  radio    2016-05-25 13:42 15 -> /storage/2C10-0CCC/elog/elog_20160525_134206/PFM/test_20160525_134209_head.bin
      lrwx------ root  radio    2016-05-25 13:42 16 -> /storage/2C10-0CCC/elog/elog_20160525_134206/PFM/test_20160525_134209_00.bin_last_0
      lrwx------ root  radio    2016-05-25 13:42 17 -> /storage/2C10-0CCC/elog/elog_20160525_134206/PFM/log_up_data.dat
      lrwx------ root  radio    2016-05-25 13:42 18 -> /dev/lmi10
      lrwx------ root  radio    2016-05-25 13:42 19 -> /dev/TPC0
      lrwx------ root  radio    2016-05-25 13:42 2 -> /dev/null
      lrwx------ root  radio    2016-05-25 13:42 20 -> /dev/modem
      lrwx------ root  radio    2016-05-25 13:42 21 -> /dev/TPC1
      lrwx------ root  radio    2016-05-25 13:42 22 -> /dev/modem
      lrwx------ root  radio    2016-05-25 13:42 23 -> /dev/lmi9
      lrwx------ root  radio    2016-05-25 13:42 24 -> socket:[14761]
      lrwx------ root  radio    2016-05-25 13:42 26 -> socket:[14764]
      lrwx------ root  radio    2016-05-25 13:42 3 -> socket:[15482]
      lrwx------ root  radio    2016-05-25 13:42 4 -> /tmp/lc-elog.pid
      lrwx------ root  radio    2016-05-25 13:42 5 -> /storage/2C10-0CCC/elog/elog_20160525_134206/HLS/test_20160525_134208_head.bin
      lrwx------ root  radio    2016-05-25 13:42 6 -> /storage/2C10-0CCC/elog/elog_20160525_134206/HLS/test_20160525_134208_00.bin_last_0
      lrwx------ root  radio    2016-05-25 13:42 7 -> /storage/2C10-0CCC/elog/elog_20160525_134206/HLS/log_up_data.dat
      lrwx------ root  radio    2016-05-25 13:42 8 -> /storage/2C10-0CCC/elog/elog_20160525_134206/PHY0/test_20160525_134208_head.bin
      lr-x------ root  radio    2016-05-25 13:42 9 -> /dev/__properties__
      root@lte26007:/proc/2365/fd

      至于如何kill正在使用sd卡的進(jìn)程呢:

      status_t PublicVolume::doUnmount() {
       if (mFusePid > 0) {
        kill(mFusePid, SIGTERM);
        TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0));
        mFusePid = 0;
       }
       
       ForceUnmount(kAsecPath);
       LOG(VERBOSE) << "start";
       KillProcessesUsingPath(getPath());
       LOG(VERBOSE) << "end";
       ForceUnmount(mFuseDefault);
       ForceUnmount(mFuseRead);
       ForceUnmount(mFuseWrite);
       ForceUnmount(mRawPath);
       
       rmdir(mFuseDefault.c_str());
       rmdir(mFuseRead.c_str());
       rmdir(mFuseWrite.c_str());
       rmdir(mRawPath.c_str());
       
       mFuseDefault.clear();
       mFuseRead.clear();
       mFuseWrite.clear();
       mRawPath.clear();
       
       return OK;
      }

      可以在卸載fuse文件系統(tǒng)之前,調(diào)用KillProcessesUsingPath,來kill那些正在使用sd卡目錄的進(jìn)程。而這個mPath路徑,如果是sd卡的話,它是storage下的目錄,而不是sd卡的mount地址。如果是otg插的sd卡的話,是sd卡的mount地址,因為otg在storage目錄下沒有目錄,只有一個mount地址訪問,也有沒有fuse。這樣問題就解決了。

      以上是“android6.0中fuse文件系統(tǒng)如何掛載和卸載”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!


      當(dāng)前題目:android6.0中fuse文件系統(tǒng)如何掛載和卸載
      URL分享:http://www.ef60e0e.cn/article/ppicds.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        普格县| 榆树市| 皋兰县| 宿迁市| 泗阳县| 石阡县| 滨海县| 蓝山县| 岳池县| 锡林郭勒盟| 望奎县| 仁寿县| 灵寿县| 勃利县| 靖州| 台山市| 邵武市| 陕西省| 宝清县| 汉沽区| 正宁县| 营口市| 益阳市| 白水县| 逊克县| 沙河市| 来安县| 阳山县| 衡东县| 大丰市| 新巴尔虎左旗| 泸定县| 吴桥县| 永寿县| 南阳市| 马龙县| 昌吉市| 崇礼县| 抚远县| 安吉县| 来安县|