最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳談android 6.0 fuse文件系統(tǒng)的掛載和卸載問題

 更新時(shí)間:2018年08月02日 09:39:56   作者:kc專欄  
今天小編就為大家分享一篇詳談android 6.0 fuse文件系統(tǒng)的掛載和卸載問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧

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

然后android6.0直接在vold中,fork一個(gè)進(jìn)程直接開啟sdcard進(jìn)程掛載fuse文件系統(tǒng)。并且在卸載sd的時(shí)候,在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卡實(shí)際掛載的地址,然后調(diào)用run函數(shù),run函數(shù)中進(jìn)行了一些初始化,然后掛載了default,read,write 3個(gè)fuse文件系統(tǒng),后面又開啟3個(gè)線程處理這3個(gè)文件系統(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個(gè)fuse文件系統(tǒng)。

但好像只有default有用,因?yàn)樵趇nit.rc中將default目錄直接掛載到了storage,而應(yīng)用也就只能拿到storage目錄,所以只有default的fuse實(shí)際有用。

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卡的時(shí)候,是先卸載了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地址的時(shí)候,會(huì)去檢查哪些進(jìn)程在使用sd卡中的文件。

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

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

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

而且實(shí)際中也碰到這樣的問題,所以個(gè)人認(rèn)為應(yīng)該先kill正在使用sd卡的進(jìn)程,然后再卸載fuse文件系統(tǒng)。這樣就不會(huì)有進(jìn)程操作sd卡中的文件的時(shí)候,導(dǎo)致fuse文件系統(tǒng)也在忙而卸載不掉了。我碰到的問題是:一個(gè)如下進(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)程。而這個(gè)mPath路徑,如果是sd卡的話,它是storage下的目錄,而不是sd卡的mount地址。如果是otg插的sd卡的話,是sd卡的mount地址,因?yàn)閛tg在storage目錄下沒有目錄,只有一個(gè)mount地址訪問,也有沒有fuse。這樣問題就解決了。

以上這篇詳談android 6.0 fuse文件系統(tǒng)的掛載和卸載問題就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • AccessibilityService實(shí)現(xiàn)微信發(fā)紅包功能

    AccessibilityService實(shí)現(xiàn)微信發(fā)紅包功能

    這篇文章主要為大家詳細(xì)介紹了AccessibilityService實(shí)現(xiàn)微信發(fā)紅包功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • Android Studio獲取配置資源與第三方包信息的方法

    Android Studio獲取配置資源與第三方包信息的方法

    在 Android 開發(fā)中,我們經(jīng)常需要從資源文件中獲取顏色、字符串、數(shù)值等配置信息,以及獲取應(yīng)用的包信息和第三方依賴信息,下面詳細(xì)介紹這些操作的方法,需要的朋友可以參考下
    2025-04-04
  • flutter 屏幕尺寸適配和字體大小適配的實(shí)現(xiàn)

    flutter 屏幕尺寸適配和字體大小適配的實(shí)現(xiàn)

    這篇文章主要介紹了flutter 屏幕尺寸適配和字體大小適配的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • Android使用okHttp(get方式)下載圖片

    Android使用okHttp(get方式)下載圖片

    這篇文章主要為大家詳細(xì)介紹了Android使用okHttp(get方式)下載圖片,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-08-08
  • 詳解關(guān)于MIUI 9沉浸式狀態(tài)欄的最新適配

    詳解關(guān)于MIUI 9沉浸式狀態(tài)欄的最新適配

    由于各系統(tǒng)版本的限制,沉浸式狀態(tài)欄對(duì)系統(tǒng)有要求,本篇文章主要介紹了詳解關(guān)于MIUI 9沉浸式狀態(tài)欄的最新適配,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2018-05-05
  • Android6.0指紋識(shí)別開發(fā)實(shí)例詳解

    Android6.0指紋識(shí)別開發(fā)實(shí)例詳解

    這篇文章主要介紹了Android6.0指紋識(shí)別開發(fā)實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • Android?手寫RecyclerView實(shí)現(xiàn)列表加載

    Android?手寫RecyclerView實(shí)現(xiàn)列表加載

    這篇文章主要介紹了Android?手寫RecyclerView實(shí)現(xiàn)列表加載,涉及到列表的需求,肯定第一時(shí)間想到RecyclerView,即便是自定義View,那么RecyclerView也會(huì)是首選,為什么會(huì)選擇RecyclerView而不是ListView,主要就是RecyclerView的內(nèi)存復(fù)用機(jī)制,這也是RecyclerView的核心?
    2022-08-08
  • Android實(shí)現(xiàn)加載廣告圖片和倒計(jì)時(shí)的開屏布局

    Android實(shí)現(xiàn)加載廣告圖片和倒計(jì)時(shí)的開屏布局

    這篇文章主要介紹了Android實(shí)現(xiàn)加載廣告圖片和倒計(jì)時(shí)的開屏布局,需要的朋友可以參考下
    2014-07-07
  • Android 手勢操作編程詳解

    Android 手勢操作編程詳解

    本文主要介紹Android 手勢操作,這里整理了手勢操作的詳細(xì)資料和介紹相應(yīng)方法,有需要的小伙伴可以參考下
    2016-08-08
  • android 引導(dǎo)界面的實(shí)現(xiàn)方法

    android 引導(dǎo)界面的實(shí)現(xiàn)方法

    現(xiàn)在越來越多程序都有引導(dǎo)頁面了。網(wǎng)上資料不全?,F(xiàn)在自己實(shí)現(xiàn)下。
    2013-06-06

最新評(píng)論

淳化县| 拉萨市| 黎川县| 新民市| 荥阳市| 葫芦岛市| 钟山县| 邢台县| 惠来县| 五台县| 迁西县| 东宁县| 牡丹江市| 广平县| 大同县| 昭通市| 宝兴县| 嘉定区| 乌兰浩特市| 芦山县| 德清县| 巴林左旗| 华亭县| 昌邑市| 乌兰浩特市| 伽师县| 聂荣县| 厦门市| 韩城市| 天镇县| 齐河县| 凌海市| 十堰市| 遵义市| 怀柔区| 石首市| 巴青县| 游戏| 平原县| 潼南县| 榆社县|