一、fuse文件系统挂载
  从android4.4 以来,第三方应用程序是不能再随便的访问sdcard,sdcard的权限管理是fuse 即用户空间文件系统(Filesystem in Userspace)来实现的,android 7.0版本中的直接在vold中,fork一个进程直接开启sdcard进程挂载fuse文件系统。并且在卸载sd的时候,在vold中卸载fuse文件系统。
  在android源码system/core/sdcard/sdcard.c这么个文件。它最终被编译成为system/bin/sdcard可执行程序,这就是所谓的sdcard的守护进程。在sdcard守护进程中存在for (;;)的循环,一直从/dev/fuse这个设备中读取请求,然后交给handle_fuse_request去处理。
  sdcard守护进程的的启动实在init.project.rc文件中:

on init# Refer to http://source.android.com/devices/tech/storage/index.html# It said, "Starting in Android 4.4, multiple external storage devices are surfaced to developers through#           Context.getExternalFilesDirs(), Context.getExternalCacheDirs(), and Context.getObbDirs().#           External storage devices surfaced through these APIs must be a semi-permanent part of the device (such as an SD card slot in a battery compartment).#           Developers expect data stored in these locations to be available over long periods of time."# Therefore, if the target doesn't support sd hot-plugging (Ex: the SD card slot in a battery compartment), we need to export SECONDARY_STORAGE in 'boot' section## export SECONDARY_STORAGE /storage/sdcard1service fuse_usbotg /system/bin/sdcard -u 1023 -g 1023 -w 1023 -d /mnt/media_rw/usbotg /storage/usbotgclass late_startdisabled

  上面代码中/system/bin/sdcard 启动时候加了很多参数,其中:
    -u 1023 表示是uid;
    -g 1023 表示是gid;
  下面分析/system/core/sdcard/sdcard.c文件,先从mian函数介绍:

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;char load_buf[20]={0};   /*Add the default val buffer*/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();}}rlim.rlim_cur = 8192;rlim.rlim_max = 8192;if (setrlimit(RLIMIT_NOFILE, &rlim)) {ERROR("Error setting RLIMIT_NOFILE, errno = %d\n", errno);}if(get_boot_mode() == NORMAL_BOOT) {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);}}
#ifdef LIMIT_SDCARD_SIZEchar *tmp=malloc(30);if (!tmp) {ERROR("malloc value fail !\n");     } else {sprintf(load_buf,"%ld", DATA_FREE_SIZE_TH_DEFAULT);internal_sdcard_free_size_threshold =strtoll(load_buf,NULL,10);//设置预留空间大小if(set_env_value(DATA_FREE_SIZE_TH_NAME,load_buf,30)) {ERROR("set %s to lk_env fail\n",DATA_FREE_SIZE_TH_NAME);}}free(tmp);
#endif//调用run函数,run函数中进行一些初始化run(source_path, label, uid, gid, userid, multi_user, full_write);return 1;
}

  在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;//赋值给fuse.dest_path用于fuse_setup中挂载fuse文件系统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);//根据是否是multi_user,创建不同权限的fuse文件系统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);}//创建handler_default、thread_read、thread_write线程//并调用start_handler来执行相关处理工作if (pthread_create(&thread_default, NULL, start_handler, &handler_default)|| pthread_create(&thread_read, NULL, start_handler, &handler_default)|| pthread_create(&thread_write, NULL, start_handler, &handler_default)) {ERROR("failed to pthread_create\n");exit(1);}watch_package_list(&global);ERROR("terminated prematurely\n");exit(1);
}

  在run函数中,前面执行了fuse相关结构的初始化工作,真正挂载fuse文件系统的函数是fuse_setup。

//在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);//通过结构体fuse(fuse_read,fuse_write,fuse_default),来挂载不同的fuse系统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;
}

  上面fuse_setup中先open了/dev/fuse节点,然后将创建的fuse文件系统mount挂载在dev/fuse节点上,然后分别创建线程handler_default、thread_read、thread_write并调用start_handler函数来处理相关的数据。

static void* start_handler(void* data)
{struct fuse_handler* handler = data;handle_fuse_requests(handler);return NULL;
}

  在handle_fuse_requests中现将获取的数据进行前期处理,然后调用handle_fuse_request来对数据进行判断:

static void handle_fuse_requests(struct fuse_handler* handler)
{struct fuse* fuse = handler->fuse;for (;;) {//调用read函数从/dev/fuse中读取数据包并存放到handler->request_buffer中ssize_t len = TEMP_FAILURE_RETRY(read(fuse->fd,handler->request_buffer, sizeof(handler->request_buffer)));if (len < 0) {if (errno == ENODEV) {ERROR("[%d] someone stole our marbles!\n", handler->token);exit(2);}ERROR("[%d] handle_fuse_requests: errno=%d\n", handler->token, errno);continue;}if ((size_t)len < sizeof(struct fuse_in_header)) {ERROR("[%d] request too short: len=%zu\n", handler->token, (size_t)len);continue;}//强制转换handler->request_buffer的数据类型const struct fuse_in_header *hdr = (void*)handler->request_buffer;if (hdr->len != (size_t)len) {ERROR("[%d] malformed header: len=%zu, hdr->len=%u\n",handler->token, (size_t)len, hdr->len);continue;}const void *data = handler->request_buffer + sizeof(struct fuse_in_header);size_t data_len = len - sizeof(struct fuse_in_header);__u64 unique = hdr->unique;//调用handle_fuse_request处理kernel fuse requst请求包int res = handle_fuse_request(fuse, handler, hdr, data, data_len);/* We do not access the request again after this point because the underlying* buffer storage may have been reused while processing the request. */if (res != NO_STATUS) {if (res) {TRACE("[%d] ERROR %d\n", handler->token, res);}fuse_status(fuse, unique, res); //返回fuse request请求的处理结果}}
}

  下面看handle_fuse_request:

static int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,const struct fuse_in_header *hdr, const void *data, size_t data_len)
{...//打开要操作的文件获取记录文件描述符fdcase FUSE_OPEN: {  const struct fuse_open_in *req = data;return handle_open(fuse, handler, hdr, req);}//read和write都是sdcard usrspace与//kernel fuse kernel spcace之间的读、写数据的内存copy交互。case FUSE_READ: { /* read_in -> byte[] */const struct fuse_read_in *req = data;return handle_read(fuse, handler, hdr, req);}case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */const struct fuse_write_in *req = data;const void* buffer = (const __u8*)data + sizeof(*req);return handle_write(fuse, handler, hdr, req, buffer);}...
}

作者:frank_zyp
您的支持是对博主最大的鼓励,感谢您的认真阅读。
本文无所谓版权,欢迎转载。

Android fuse文件系统相关推荐

  1. linux fuse文件系统在 android fuse sdcard的 运用

    一.android GB 及JB.KK版本内置sdcard效果对比图 从上面效果对比图,我们可以发现android fuse sdcard 有如下两个优点: 1.使用fuse后 /data 和  /s ...

  2. 基于fuse文件系统的android sdcard存储方案:之二

    续<基于fuse文件系统的android sdcard存储方案:之一>,再聊聊基于fuse文件系统的android sdcard存储方案:之二, 以后有空再谈谈该方案的缺点,及优化方案. ...

  3. linux文件系统启动流程,linux 内核启动过程以及挂载android 根文件系统的过程

    转载 作者:汕头大学-黄珠唐 时间:2009 年10 月29 日 主要介绍linux 内核启动过程以及挂载android 根文件系统的过程,以及介绍android 源代码中文件系统部分的浅析. 主要源 ...

  4. Android NFS文件系统挂载遇到的问题解决方法

    在网上他人博客中方法都大同小异,但是却无法解决我遇到的问题. 我随意挑选一个网友的方法http://blog.csdn.net/zjg555543/article/details/7792984 当然 ...

  5. Android加密文件系统

    系统和用户数据在文件系统中都是以明文进行保存的.这也为系统带来了不安全因素,例如,黑客在获取到设备后,由于文件系统没有密码保护,只要能设法挂载文件系统,就可以绕过用户权限等控制,获取其中存储的数据.A ...

  6. python画画bup_用Python编写一个简单的FUSE文件系统的教程

    如果你是我的长期读者,那么你应该知道我在寻找一个完美备份程序,最后我写了一个基于bup的我自己的加密层. 在写encbup的时候,我对仅仅恢复一个文件就必须要下载整个巨大的档案文件的做法不甚满意,但仍 ...

  7. linux fuse安装脚本,Linux FUSE(用户态文件系统)的使用:用libfuse创建FUSE文件系统...

    说明 FUSE 是Linux Kernel的特性之一:一个用户态文件系统框架,a userspace filesystem framework. 形象的说就是可以在用户态运行一个程序,这个程序暴露出一 ...

  8. fuse文件系统调试环境

    libfuse源码:GitHub - libfuse/libfuse: The reference implementation of the Linux FUSE (Filesystem in Us ...

  9. android 根文件系统,Android根文件系统相关应用介绍

    我们将会针对Android根文件系统的相关目录结构等方面的问题进行一个详细的讲解,以帮助大家快速掌握这方面的知识. 我们曾经在一篇文章中为大家详细介绍过Android文件系统的一些基本概念,相信大家已 ...

最新文章

  1. Oracle体系结构及备份(十六)——bg-ckpt
  2. 静态自动检查代码缺陷与隐患
  3. 查看分支编码_高性能编码规范驳斥(一)
  4. 人口普查系统_王佐镇全面开展第七次人口普查数据采集处理系统培训暨摸底动员部署会...
  5. python_day29_通过类创建多线程_队列
  6. SAP License:财务报表版本文本
  7. Web 组件势必取代前端?
  8. android服务器接口测试,使用Retrofit和Mockito进行可靠的Android API测试
  9. $(...).nicescroll is not a function报错分析
  10. 算法导论第三版第二章答案
  11. 理解Golang中的[]interface{}和interface{}
  12. 【读书笔记】好好思考-成甲
  13. 启动Activity的流程(Launcher中点击图标启动)
  14. RDS数据库申请外网地址
  15. VSCode C/C++ 使用指北
  16. 2022-2028年全球与中国蜗牛美容产品行业竞争格局与投资战略研究
  17. 一文彻底搞懂股权投资中GP/LP关系! | 资本智库
  18. 吴恩达深度学习编程题——0402(Keras-Tutorial-Happy House )遇到问题及解决方法
  19. win11抢先版体验
  20. arduino控制寻迹传感器

热门文章

  1. 深度学习模型压缩(量化、剪枝、轻量化结构、batch-normalization融合)
  2. 证券从业考试如何备考?
  3. HDLC面向比特的同步协议
  4. dump文件 修复iat_在OD中手工修复IAT重定向
  5. xamarin还有人用么_卡住了么?卡住了我就开始了
  6. 【Adams安装打开出现不是内部命令,也不是可运行程序问题】
  7. 模拟地和数字地之间的连接方法
  8. Java 递归数组求和
  9. 【慕课笔记】用技术打造小程序简历_3设计简历封面
  10. 怎么查看卫星地图的更新日期?