国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

詳談android 6.0 fuse文件系統的掛載和卸載問題

2019-10-21 21:43:25
字體:
來源:轉載
供稿:網友

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

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

一、掛載sd卡

下面是解析android6.0vold,掛載sd卡是的一段代碼,我們來看下。顯示掛載sd卡,然后進行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函數中獲取數據,

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卡實際掛載的地址,然后調用run函數,run函數中進行了一些初始化,然后掛載了default,read,write 3個fuse文件系統,后面又開啟3個線程處理這3個文件系統的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文件系統

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文件系統。

但好像只有default有用,因為在init.rc中將default目錄直接掛載到了storage,而應用也就只能拿到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文件系統,然后在卸載了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地址的時候,會去檢查哪些進程在使用sd卡中的文件。

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

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

但是這個時候去查找誰占用fuse文件又是查不出來的,因為是進程在操作sd卡文件,會導致fuse文件系統的操作,才會卸載不掉fuse文件系統。但是能找到占用的文件只能是sd卡的。

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

root@lte26007:/proc/2365/fd # ls -llrwx------ root  radio    2016-05-25 13:42 0 -> /dev/nulllrwx------ root  radio    2016-05-25 13:42 1 -> /dev/nulllrwx------ root  radio    2016-05-25 13:42 10 -> /storage/2C10-0CCC/elog/elog_20160525_134206/PHY0/test_20160525_134208_00.bin_last_0lrwx------ root  radio    2016-05-25 13:42 11 -> /storage/2C10-0CCC/elog/elog_20160525_134206/PHY0/log_up_data.datlrwx------ root  radio    2016-05-25 13:42 12 -> /storage/2C10-0CCC/elog/elog_20160525_134206/PHY1/test_20160525_134209_head.binlrwx------ root  radio    2016-05-25 13:42 13 -> /storage/2C10-0CCC/elog/elog_20160525_134206/PHY1/test_20160525_134209_00.bin_last_0lrwx------ root  radio    2016-05-25 13:42 14 -> /storage/2C10-0CCC/elog/elog_20160525_134206/PHY1/log_up_data.datlrwx------ root  radio    2016-05-25 13:42 15 -> /storage/2C10-0CCC/elog/elog_20160525_134206/PFM/test_20160525_134209_head.binlrwx------ root  radio    2016-05-25 13:42 16 -> /storage/2C10-0CCC/elog/elog_20160525_134206/PFM/test_20160525_134209_00.bin_last_0lrwx------ root  radio    2016-05-25 13:42 17 -> /storage/2C10-0CCC/elog/elog_20160525_134206/PFM/log_up_data.datlrwx------ root  radio    2016-05-25 13:42 18 -> /dev/lmi10lrwx------ root  radio    2016-05-25 13:42 19 -> /dev/TPC0lrwx------ root  radio    2016-05-25 13:42 2 -> /dev/nulllrwx------ root  radio    2016-05-25 13:42 20 -> /dev/modemlrwx------ root  radio    2016-05-25 13:42 21 -> /dev/TPC1lrwx------ root  radio    2016-05-25 13:42 22 -> /dev/modemlrwx------ root  radio    2016-05-25 13:42 23 -> /dev/lmi9lrwx------ 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.pidlrwx------ root  radio    2016-05-25 13:42 5 -> /storage/2C10-0CCC/elog/elog_20160525_134206/HLS/test_20160525_134208_head.binlrwx------ root  radio    2016-05-25 13:42 6 -> /storage/2C10-0CCC/elog/elog_20160525_134206/HLS/test_20160525_134208_00.bin_last_0lrwx------ root  radio    2016-05-25 13:42 7 -> /storage/2C10-0CCC/elog/elog_20160525_134206/HLS/log_up_data.datlrwx------ root  radio    2016-05-25 13:42 8 -> /storage/2C10-0CCC/elog/elog_20160525_134206/PHY0/test_20160525_134208_head.binlr-x------ root  radio    2016-05-25 13:42 9 -> /dev/__properties__root@lte26007:/proc/2365/fd 

至于如何kill正在使用sd卡的進程呢:

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文件系統之前,調用KillProcessesUsingPath,來kill那些正在使用sd卡目錄的進程。而這個mPath路徑,如果是sd卡的話,它是storage下的目錄,而不是sd卡的mount地址。如果是otg插的sd卡的話,是sd卡的mount地址,因為otg在storage目錄下沒有目錄,只有一個mount地址訪問,也有沒有fuse。這樣問題就解決了。

以上這篇詳談android 6.0 fuse文件系統的掛載和卸載問題就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 怀柔区| 峨眉山市| 苍溪县| 淅川县| 永平县| 崇信县| 电白县| 叶城县| 固始县| 丹巴县| 江安县| 潼关县| 吴忠市| 鞍山市| 盐城市| 阳城县| 溧水县| 保康县| 永兴县| 钟祥市| 栖霞市| 汽车| 栾川县| 肇州县| 镇赉县| 虎林市| 辽中县| 遂昌县| 万荣县| 苏尼特左旗| 沈丘县| 平湖市| 湖口县| 黑河市| 中西区| 山阳县| 自贡市| 溧水县| 凤城市| 海伦市| 黄浦区|