一、 启动三个相关service
转载地址:http://blog.csdn.net/fybon/article/details/25904215
按启动顺序,如下:
service vold /system/bin/vold class core socket vold stream 0660 root mount
service installd /system/bin/installd class main socket installd stream 600 system system
service sdcard /system/bin/sdcard -u 1023 -g 1023 -l /data/media /mnt/shell/emulated class late_start
上面三个service启动后,内置sdcard状态如下图:

注:
android_filesystem_config.h
#define AID_MEDIA_RW 1023 /* internal media storage write access */
#define AID_SDCARD_RW 1015 /* external storage write access */
#define AID_SDCARD_R 1028 /* external storage read access */
二、insalld service
frameworks/native/cmds/installd/installd.c installd 启动时将/data/media 目录创建好,并将预置资源迁移到/data/media/0目录int initialize_directories() { int res = -1; // Read current filesystem layout version to handle upgrade paths char version_path[PATH_MAX]; snPRintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.path); int oldVersion; if (fs_read_atomic_int(version_path, &oldVersion) == -1) { oldVersion = 0; } int version = oldVersion; if (version == 0) { // Introducing multi-user, so migrate /data/media contents into /data/media/0 ALOGD("Upgrading /data/media for multi-user"); // Ensure /data/media if (fs_prepare_dir(android_media_dir.path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) { goto fail; } // /data/media.tmp char media_tmp_dir[PATH_MAX]; snprintf(media_tmp_dir, PATH_MAX, "%smedia.tmp", android_data_dir.path); // Only copy when upgrade not already in progress if (access(media_tmp_dir, F_OK) == -1) { if (rename(android_media_dir.path, media_tmp_dir) == -1) { ALOGE("Failed to move legacy media path: %s", strerror(errno)); goto fail; } } // Create /data/media again if (fs_prepare_dir(android_media_dir.path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) { goto fail; } // /data/media/0 char owner_media_dir[PATH_MAX]; snprintf(owner_media_dir, PATH_MAX, "%s0", android_media_dir.path); // Move any owner data into place if (access(media_tmp_dir, F_OK) == 0) { if (rename(media_tmp_dir, owner_media_dir) == -1) { ALOGE("Failed to move owner media path: %s", strerror(errno)); goto fail; } }
。。。。。。
}三、sdcard service
1、初始化fuse
static void fuse_init(struct fuse *fuse, int fd, const char *source_path, gid_t write_gid, derive_t derive, bool split_perms) {
//此函数初始化重要的全局数据结构fuse,供后面创建的多线程使用
这个全局结构体变量在run()函数中定义,因为run()函数永不退出,所以虽然fuse是函数内的局部变量,但它的内存其实永不释放。达相当于全局变量的效果啦。
/*********=============================================
提前将run函数注释说明fuse数据结构相关代码:
static int run(const char* source_path, const char* dest_path, uid_t uid, gid_t gid, gid_t write_gid, int num_threads, derive_t derive, bool split_perms) { int fd; char opts[256]; int res; struct fuse fuse; /* cleanup from previous instance, if necessary */ umount2(dest_path, 2);
...................
res = ignite_fuse(&fuse, num_threads); /* we do not attempt to umount the file system here because we are no longer * running as the root user */
*********================================================/
pthread_mutex_init(&fuse->lock, NULL); //初始化多线程互斥量 fuse->fd = fd; // dev/fuse 作为user space /kernel space 交互的设备节点 fuse->next_generation = 0; // 系统启动时带-d / -l 或者不速这两个参数,会对 fuse->derive赋不同的值: service sdcard /system/bin/sdcard -u 1023 -g 1023-l /data/media /mnt/shell/emulated
typedef enum { DERIVE_NONE, DERIVE_LEGACY, DERIVE_UNIFIED,} derive_t;
// -l :derive初始化为DERIVE_LEGACY , -d :derive初始化为DERIVE_UNIFIED ,无这两参数:derive初始化为DERIVE_NONE/
// derive 初始化这几值有什么不同呢???? fuse->derive = derive; fuse->split_perms = split_perms; fuse->write_gid = write_gid; //w memset(&fuse->root, 0, sizeof(fuse->root)); fuse->root.nid = FUSE_ROOT_ID; /* 1 */ fuse->root.refcount = 2; fuse->root.namelen = strlen(source_path); fuse->root.name = strdup(source_path); //这里记录根目录路径为:/data/media ,后面操作/mnt/shell/emulated会转换到/data/media fuse->root.userid = 0; fuse->root.uid = AID_ROOT; /* Set up root node for various modes of Operation */ switch (derive) { 。。。。。。。。。。。。//derive 初始化为DERIVE_LEGACY case DERIVE_LEGACY: /* Legacy behavior used to support internal multiuser layout which * places user_id at the top directory level, with the actual roots * just below that. Shared OBB path is also at top level. */ fuse->root.perm = PERM_LEGACY_PRE_ROOT; //初始化根目录node,sdcard.c也类似kernel fs为每个目录和文件维护了一个node结构体 fuse->root.mode = 0771; fuse->root.gid = AID_SDCARD_R; fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals); fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals); snprintf(fuse->obbpath, sizeof(fuse->obbpath), "%s/obb", source_path); fs_prepare_dir(fuse->obbpath, 0775, getuid(), getgid()); break; }
//容量控制#ifdef LIMIT_SDCARD_SIZE struct statfs stat; if (statfs(fuse->root.name, &stat) < 0) { ERROR("get %s fs status fail /n",fuse->root.name);fuse->free_size =0; }else{fuse->free_size = stat.f_bfree*stat.f_bsize;LOG("[fuse_debug]fuse.free_size =%lld /n",fuse->free_size); }#endif}
两个重要数据结构:fuse和node
/* Global data structure shared by all fuse handlers. */struct fuse { pthread_mutex_t lock; __u64 next_generation; int fd; derive_t derive; bool split_perms; gid_t write_gid; struct node root; char obbpath[PATH_MAX]; Hashmap* package_to_appid; //hash map Hashmap* appid_with_rw;#ifdef LIMIT_SDCARD_SIZE__u64 free_size; //add by mtk for limit internal sdcard size#endif};
struct node { __u32 refcount; __u64 nid; // node id __u64 gen; /* State derived based on current position in hierarchy. */ perm_t perm; userid_t userid; uid_t uid; gid_t gid; mode_t mode; struct node *next; /* per-dir sibling list */ struct node *child; /* first contained file by this dir */ struct node *parent; /* containing directory */ size_t namelen; char *name; /* If non-null, this is the real name of the file in the underlying storage. * This may differ from the field "name" only by case. * strlen(actual_name) will always equal strlen(name), so it is safe to use * namelen for both fields. */ char *actual_name; /* If non-null, an exact underlying path that should be grafted into this * position. Used to support things like OBB. */ char* graft_path; size_t graft_pathlen;};
2、启动fuse
static int run(const char* source_path, const char* dest_path, uid_t uid, gid_t gid, gid_t write_gid, int num_threads, derive_t derive, bool split_perms) { int fd; char opts[256]; int res; struct fuse fuse; //这个局部变量,却起到全局变量的效果。 /* cleanup from previous instance, if necessary */ umount2(dest_path, 2); //先做一次强制umount动作 fd = open("/dev/fuse", O_RDWR); //打开/dev/fuse字符型设备,这个fd将要传递到kernel fuse if (fd < 0){ ERROR("cannot open fuse device: %s/n", strerror(errno)); return -1; } snprintf(opts, sizeof(opts), "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d", fd, uid, gid); res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV, opts); //将 /mnt/shell/emulated 挂载到/dev/fuse设备 if (res < 0) { ERROR("cannot mount fuse filesystem: %s/n", strerror(errno)); goto error; } //将sdcard的权限由root降为media_rw res = setgid(gid); if (res < 0) { ERROR("cannot setgid: %s/n", strerror(errno)); goto error; } res = setuid(uid); if (res < 0) { ERROR("cannot setuid: %s/n", strerror(errno)); goto error; } // /初始化重要的fuse数据结构 , fuse_init(&fuse, fd, source_path, write_gid, derive, split_perms); umask(0); //创建 hander thread, 启动fuse res = ignite_fuse(&fuse, num_threads); /* we do not attempt to umount the file system here because we are no longer * running as the root user */error: close(fd); return res;}下面再看handler thread 创建,及启动。关于pthread请看我转的一篇blog,写得非常好。static int ignite_fuse(struct fuse* fuse, int num_threads){ struct fuse_handler* handlers; int i; handlers = malloc(num_threads * sizeof(struct fuse_handler)); if (!handlers) { ERROR("cannot allocate storage for threads/n"); return -ENOMEM; } for (i = 0; i < num_threads; i++) { // 默认num_threads==2 // #define DEFAULT_NUM_THREADS 2 handlers[i].fuse = fuse; handlers[i].token = i; // 以线程号作为 token,标识handler 。 } /* When deriving permissions, this thread is used to process inotify events, * otherwise it becomes one of the FUSE handlers. */ i = (fuse->derive == DERIVE_NONE) ? 1 : 0; for (; i < num_threads; i++) { ERROR("to start thread #%d /n", i); pthread_t thread;
//service sdcard /system/bin/sdcard -u 1023 -g 1023-l /data/media /mnt/shell/emulated
// 启动sdcard service时带 -d / -l 参数, derive 为DERIVE_LEGACY或DERIVE_UNIFIED时。
//为什么要两个线程?这两个线程要怎么同步吗?
int res = pthread_create(&thread, NULL, start_handler, &handlers[i]); if (res) { ERROR("failed to start thread #%d, error=%d/n", i, res); goto quit; } } ERROR("fuse->derive #%d /n", fuse->derive); if (fuse->derive == DERIVE_NONE) { handle_fuse_requests(&handlers[0]); //derive 为DERIVE_NONE,主进程处理handlers[0] } else { watch_package_list(fuse); // 主进程watch文件:"/data/system/packages.list" 的delete通知事件!
// 可是watch到delete事件后,并没有做什么?可以Android后续版本会有什么改进!!?? } ERROR("terminated prematurely/n"); /* don't bother killing all of the other threads or freeing anything, * should never get here anyhow */quit: exit(1);}
接上个的函数
static void handle_fuse_requests(struct fuse_handler* handler){ struct fuse* fuse = handler->fuse; for (;;) { ssize_t len = read(fuse->fd, //从字符型设备/dev/fuse中读取kernel fuse文件系统发送出来的处理请求包 handler->request_buffer, sizeof(handler->request_buffer)); 。。。。。。。 const struct fuse_in_header *hdr = (void*)handler->request_buffer; //请求包中解析出fuse request header 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; int res = handle_fuse_request(fuse, handler, hdr, data, data_len); //处理kernel fuse requst请求包 /* 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请求的处理结果。 } }}
3、fuse请求包处理
先看几个相关的宏定义,及重要的结构体:struct fuse_handler /* Maximum number of bytes to write in one request. */#define MAX_WRITE (256 * 1024)/* Maximum number of bytes to read in one request. */#define MAX_READ (128 * 1024)/* Largest possible request. * The request size is bounded by the maximum size of a FUSE_WRITE request because it has * the largest possible data payload. */#define MAX_REQUEST_SIZE (sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + MAX_WRITE)/* Private data used by a single fuse handler. */struct fuse_handler { struct fuse* fuse; //指向上面重点介绍过的全局变量fuse int token; // 以线程号作为 token,标识handler /* To save memory, we never use the contents of the request buffer and the read * buffer at the same time. This allows us to share the underlying storage. */ union { __u8 request_buffer[MAX_REQUEST_SIZE]; // 从这个数组大小的宏定义MAX_REQUEST_SIZE,可以看出它有两个作用: //1、保存从字符型设备/dev/fuse中读取kernel fuse文件系统发送出来的处理请求包。 //2、保存从内核fuse write请求copy而来的需要通过ext4写入到存储设备的数据。 __u8 read_buffer[MAX_READ]; //保存通过ext4从存储读取到的,需要通过内核fuse read请求,传上userspace app 的数据。 };};sdcard service 与 kernel 文件系统的交互请求:enum fuse_opcode {FUSE_LOOKUP = 1,FUSE_FORGET = 2, /* no reply */FUSE_GETATTR = 3,FUSE_SETATTR = 4,FUSE_READLINK = 5,FUSE_SYMLINK = 6,FUSE_MKNOD = 8,FUSE_MKDIR = 9,FUSE_UNLINK = 10,FUSE_RMDIR = 11,FUSE_RENAME = 12,FUSE_LINK = 13,FUSE_OPEN = 14,FUSE_READ = 15,FUSE_WRITE = 16,FUSE_STATFS = 17,FUSE_RELEASE = 18,FUSE_FSYNC = 20,FUSE_SETXATTR = 21,FUSE_GETXATTR = 22,FUSE_LISTXATTR = 23,FUSE_REMOVEXATTR = 24,FUSE_FLUSH = 25,FUSE_INIT = 26,FUSE_OPENDIR = 27,FUSE_READDIR = 28,FUSE_RELEASEDIR = 29,FUSE_FSYNCDIR = 30,FUSE_GETLK = 31,FUSE_SETLK = 32,FUSE_SETLKW = 33,FUSE_ACCESS = 34,FUSE_CREATE = 35,FUSE_INTERRUPT = 36,FUSE_BMAP = 37,FUSE_DESTROY = 38,FUSE_IOCTL = 39,FUSE_POLL = 40,/* CUSE specific operations */CUSE_INIT = 4096,};好了,了解上面这些后,看下面两fuse请求包处理函数就很容易了!static void handle_fuse_requests(struct fuse_handler* handler){ struct fuse* fuse = handler->fuse; for (;;) { ssize_t len = read(fuse->fd, //从字符型设备/dev/fuse中读取kernel fuse文件系统发送出来的处理请求包, handler->request_buffer, sizeof(handler->request_buffer)); //如果是write请求命令,此时包里还有要写的数据。 。。。。。。。 const struct fuse_in_header *hdr = (void*)handler->request_buffer; //请求包中解析出fuse request header 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; int res = handle_fuse_request(fuse, handler, hdr, data, data_len); //处理kernel fuse requst请求包 /* 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请求的处理结果。 } }}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){ switch (hdr->opcode) { 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 case FUSE_OPEN: { /* open_in -> open_out */ //打开要操作的文件, 记录文件描述符fd 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); } 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 }}4、derive permission授权
前面提到sdcard.c也类似kernel fs为每个目录和文件维护了一个node结构体,下面围绕这个node来看整个权限控限过程就很明白了。首先看看几个跟权限相关的enum :定义的文件几种权限选则:typedef enum {/* Nothing special; this node should just inherit from its parent. */PERM_INHERIT,/* This node is one level above a normal root; used for legacy layouts* which use the first level to represent user_id. */PERM_LEGACY_PRE_ROOT,/* This node is "/" */PERM_ROOT,/* This node is "/Android" */PERM_ANDROID,/* This node is "/Android/data" */PERM_ANDROID_DATA,/* This node is "/Android/obb" */PERM_ANDROID_OBB,/* This node is "/Android/user" */PERM_ANDROID_USER,} perm_t; 权限控制的三种方法,/* Permissions structure to derive */typedef enum {DERIVE_NONE,DERIVE_LEGACY, ====》用于内置sdcard ,主要用于多用户的权限控制DERIVE_UNIFIED, ====》用于外置sdcard} derive_t;==========================================DERIVE_LEGACYDERIVE_UNIFIED这两个枚举fuck地让我迷糊很久啊,到底有什么不一样啊???分析下面的代码很久才搞明白。==========================================即下来看重要的node结构体 : struct node { __u32 refcount; // node 的引用计数 __u64 nid; //node id ,用于唯一标识node,太聪明了,除root node 使用该node申请的内存指针地址作为id,肯定可以达到唯一性。 /* State derived based on current position in hierarchy. */ perm_t perm; //权限控制方式 userid_t userid; //用户id,即,0、 1、 2、 3、 。。。。 uid_t uid; //uid gid_t gid; //gid mode_t mode; //访问模式 //node链就和vfs类似了…… struct node *next; /* per-dir sibling list */ struct node *child; /* first contained file by this dir */ struct node *parent; /* containing directory */ size_t namelen; //node 名长度 char *name; //node 名};下面fuse_init函数初始化fuse结构体前面已经说过的。这里重点看fuse结构体里的root node结构的初始化。static void fuse_init(struct fuse *fuse, int fd, const char *source_path, gid_t write_gid, derive_t derive, bool split_perms) { pthread_mutex_init(&fuse->lock, NULL); fuse->fd = fd; fuse->next_generation = 0; fuse->derive = derive; fuse->split_perms = split_perms; fuse->write_gid = write_gid; //初始设置有sdcard读写权限的gid memset(&fuse->root, 0, sizeof(fuse->root)); // 创建第一个node,后面的node都往这里插入 fuse->root.nid = FUSE_ROOT_ID; /* 1 */ // root node id = 1 , fuse->root.refcount = 2; fuse->root.namelen = strlen(source_path); fuse->root.name = strdup(source_path); // root node 对应的是什么呢?? 即根目录:'/data/media' , 不要以为是为是'/data/media/0 ' 啊 ! fuse->root.userid = 0; fuse->root.uid = AID_ROOT; // uid : root /* Set up root node for various modes of operation */ switch (derive) { case DERIVE_NONE: //无权限控制的方式,现在一般不用。无法selinux的要求吧! /* Traditional behavior that treats entire device as being accessible * to sdcard_rw, and no permissions are derived. */ fuse->root.perm = PERM_ROOT; fuse->root.mode = 0775; fuse->root.gid = AID_SDCARD_RW; break; case DERIVE_LEGACY: //内置sdcard使用,支持多用户的访问独立sdcard数据权限控制方式,//内置sdcard目录顶层为用户id为名的0、1、2、3等用户目录, data/media/0, data/media/1, data/media/2 ............... 等//,目录顶层也包括/data/media/obb 目录// data/media/userid 目录下/data/media/userid/Android/data/ 子目录才是app的么有数据 。 /* Legacy behavior used to support internal multiuser layout which * places user_id at the top directory level, with the actual roots * just below that. Shared OBB path is also at top level. */ fuse->root.perm = PERM_LEGACY_PRE_ROOT; //root node 的权限,后面根目录下根据useid创建的的0 , 1 ,,2 , 3 .....目录权限为:PERM_ROOT fuse->root.mode = 0771; fuse->root.gid = AID_SDCARD_R; // gid = AID_SDCARD_R fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals); // 初始hash Map ,用于做什么? 下面会详细说明,它跟权限有关就是。 fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals); snprintf(fuse->obbpath, sizeof(fuse->obbpath), "%s/obb", source_path); fs_prepare_dir(fuse->obbpath, 0775, getuid(), getgid()); // 创建/data/media/obb 目录,用于apk独立数据访问权限控制的? LOG("[fuse_debug]obbpath =%s /n",fuse->obbpath); break; case DERIVE_UNIFIED: /* Unified multiuser layout which places secondary user_id under * /Android/user and shared OBB path under /Android/obb. */// 不支持多用户的的权限控制方式。// 外置sdcard目录顶层即为user 0的用户数据,及Android/obb// 而user 1开始的第二个用户数所都放在Android/user目录下 。 fuse->root.perm = PERM_ROOT; // root node 的权限就为PERM_ROOT fuse->root.mode = 0771; fuse->root.gid = AID_SDCARD_R; fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals); fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals); snprintf(fuse->obbpath, sizeof(fuse->obbpath), "%s/Android/obb", source_path); break; }}再看下面的这个函数的作用:根据parent node的权限为新的child node 分配权限。static void derive_permissions_locked(struct fuse* fuse, struct node *parent, struct node *node) { appid_t appid; /* By default, each node inherits from its parent */ node->perm = PERM_INHERIT; node->userid = parent->userid; node->uid = parent->uid; //新的node默认 继承父node uid / gid node->gid = parent->gid; node->mode = parent->mode; if (fuse->derive == DERIVE_NONE) { return; } //这里添加一条重要的log打印 TRACE("derive_permissions_locked %s 0%d (%s)/n", node->name, parent->perm, parent->name); /* Derive custom permissions based on parent and current node */ switch (parent->perm) { case PERM_INHERIT: /* Already inherited above */ break; case PERM_LEGACY_PRE_ROOT: // 内置sdcard的根目录权限为PERM_LEGACY_PRE_ROOT /* Legacy internal layout places users at top level */ node->perm = PERM_ROOT; /内置sdcard的/根目录下,根据用户id创建的0、1、2、3等用户子目录,授权为: PERM_ROOT node->userid = strtoul(node->name, NULL, 10); // userid设为0、1、2、3....... break; case PERM_ROOT: //外置sdcard,及内置sdcard根目录下的0、1、2、3等用户子目录的权限为:PERM_ROOT /* Assume masked off by default. */ node->mode = 0770; // 下面为外置sdcard根目录下的子目录,及内置sdcard根目录下的0、1、2、3等用户子目录 授予不同权限 : if (!strcasecmp(node->name, "Android")) { //root/Android目录授权 /* App-specific directories inside; let anyone traverse */ node->perm = PERM_ANDROID; node->mode = 0771; } break; case PERM_ANDROID: if (!strcasecmp(node->name, "data")) { // root/Android/data目录授权 /* App-specific directories inside; let anyone traverse */ node->perm = PERM_ANDROID_DATA; node->mode = 0771; } else if (!strcasecmp(node->name, "obb")) { // root/Android/obb目录授权 /* App-specific directories inside; let anyone traverse */ node->perm = PERM_ANDROID_OBB; node->mode = 0771; /* Single OBB directory is always shared */ node->graft_path = fuse->obbpath; node->graft_pathlen = strlen(fuse->obbpath); } else if (!strcasecmp(node->name, "user")) { //root/Android/user目录授权 , 同时修改gid /* User directories must only be accessible to system, protected * by sdcard_all. Zygote will bind mount the appropriate user- * specific path. */ node->perm = PERM_ANDROID_USER; node->gid = AID_SDCARD_ALL; node->mode = 0770; } break; case PERM_ANDROID_DATA: // root/Android/data 与 root/Android/obb 目录下的各子目录授权,appid作为uid,让该app独占该目录 case PERM_ANDROID_OBB: appid = (appid_t) hashmapGet(fuse->package_to_appid, node->name); //从haspMap里获取appid if (appid != 0) { node->uid = multiuser_get_uid(parent->userid, appid); // appid 作为uid,让该app才能有权限访问 } node->mode = 0770; break; case PERM_ANDROID_USER: //root/Android/user目录授权目录下的的子录目授权,比如外置多用户:sdcard2/user/2 授权为根目录 PERM_ROOT /* Root of a secondary user */ node->perm = PERM_ROOT; node->userid = strtoul(node->name, NULL, 10); node->gid = AID_SDCARD_R; node->mode = 0771; break; }}通过在derive_permissions_locked添加的一句打印log分析看看:#define FUSE_TRACE 1 //打出sdcard service debug log 可以看到下面这些sdcard service 针对内置sdcard的log信息:06-04 17:49:41.993 232 232 I sdcard : source_path='/data/media', dest_path='/mnt/shell/emulated', derive=1, write_gid=1015这里为根目录/data/media/0 授权02: PERM_ROOT06-04 17:50:03.904 232 251 D sdcard : [1] LOOKUP 0 @ 1 (/data/media) 06-04 17:50:03.904 232 251 D sdcard : derive_permissions_locked 0 01 (/data/media)// 为/data/media/0 /Android 授权06-04 17:50:09.023 232 251 D sdcard : derive_permissions_locked Android 02 (0)// 为/data/media/0 /Android/data 授权06-04 17:50:09.038 232 250 D sdcard : derive_permissions_locked data 03 (Android)06-04 17:50:09.052 232 251 D sdcard : derive_permissions_locked com.amap.android.location 04 (data)下面通过/sdcard/Android/data目录的实际的授权结果是什么样的:可以看到uid是随着app变化而变化的。root@S850:/sdcard/Android/data # ls -Z ////这个目录下创建的都是以app名为的子目录。drwxrwx--- u0_a0 sdcard_r u:object_r:sdcard_external:s0 com.amap.android.locationdrwxrwx--- u0_a3 sdcard_r u:object_r:sdcard_external:s0 com.lenovo.carapplicationdrwxrwx--- u0_a67 sdcard_r u:object_r:sdcard_external:s0 com.len通过上面的代码分析,DERIVE_LEGACY 与DERIVE_UNIFIED 的区别已经很清楚啦!5、sdcard node访问权限控制
上面提到很多对node授权,实际访问是如何进行权限控制的呢? 其实就是通过上面偶有提到HashMap,下面仔细再看看。fuse 结构体中有两个重要的HashMap变量,如下:struct fuse { 。。。。。。。 Hashmap* package_to_appid; Hashmap* appid_with_rw; 。。。。。。};fuse_init()函数中对这两个hashMap变量进行了初始化,请看:static void fuse_init(struct fuse *fuse, int fd, const char *source_path, gid_t write_gid, derive_t derive, bool split_perms) {。。。。。。。。。。。。。。。。 /* Set up root node for various modes of operation */ switch (derive) {。。。。。。。。。。。。。。。。 case DERIVE_LEGACY: //初始化了两个haspMap实例指针,具体怎么初始化的,请仔细看/system/core/libcutils/hashmap.c fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals); fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals);。。。。。。。。。。。。。。}hashMap是如何创建的呢? 继续 ~……ignite_fuse()函数启动两个fuse handle线程后,主进程调用watch_package_list()进入死循环,watch文件"/data/system/packages.list"。注:packages.list这个文件的内容是系统在启动时扫描出的已安装的应用apk列表信息。内容例子如下:root@:/data/system # cat packages.list com.lakala.android 10111 0 /data/data/com.lakala.android default 1028,1015,1023,3003com.android.defcontainer 10004 0 /data/data/com.android.defcontainer platform 1028,1015,1023,2001,1035下面我们分析一下主进程调用 watch_package_list()如何创建hashMap 的?static void watch_package_list(struct fuse* fuse) {。。。。。。 bool active = false; while (1) { if (!active) { int res = inotify_add_watch(nfd, kPackagesListFile, IN_DELETE_SELF);。。。。。。。。。 /* Watch above will tell us about any future changes, so * read the current state. */ if (read_package_list(fuse) == -1) { //解析文件packages.list内容,并创建hashMap ERROR("read_package_list failed: %s/n", strerror(errno)); return; } active = true; }。。。。。。。。。。。。。。}hashMap的创建一切就在这里了!static int read_package_list(struct fuse *fuse) { pthread_mutex_lock(&fuse->lock); //如果已有hashMap,则清干净。(如果watch到packages.list初删除,就要重新创建hashMap,那就要先清干净原来的旧值了) hashmapForEach(fuse->package_to_appid, remove_str_to_int, fuse->package_to_appid); hashmapForEach(fuse->appid_with_rw, remove_int_to_null, fuse->appid_with_rw); FILE* file = fopen(kPackagesListFile, "r"); //打开文件:packages.list if (!file) { ERROR("failed to open package list: %s/n", strerror(errno)); pthread_mutex_unlock(&fuse->lock); return -1; } char buf[512]; bool is_found = false; while (fgets(buf, sizeof(buf), file) != NULL) { //读packages.list一行 char package_name[512]; int appid; char gids[512]; is_found = false; //从packages.list读取的一行内容,比如:com.lakala.android 10111 0 /data/data/com.lakala.android default 1028,1015,1023,3003 // 解析app名,appid,数据所在目录,app所属组s (可能属于多组啊!) if (sscanf(buf, "%s %d %*d %*s %*s %s", package_name, &appid, gids) == 3) { // char* package_name_dup = strdup(package_name); hashmapPut(fuse->package_to_appid, package_name_dup, (void*) appid); // 以app name , app id 创建一个新的hashMap添加到package_to_appid, Map 如下:/* 注:struct Entry { void* key; //app name int hash; // app name's hash value void* value; // app id Entry* next;};*/ char* token = strtok(gids, ","); while (token != NULL) { if (strtoul(token, NULL, 10) == fuse->write_gid) { //从上面获取到的app所属组s, 判断是否该app属组 fuse->write_gid(AID_SDCARD_RW)。 hashmapPut(fuse->appid_with_rw, (void*) appid, (void*) 1); //属于组AID_SDCARD_RW,则有sdcard rw权限,则以app id 和1创建一个新的hashMap添加到appid_with_rw ,Map如下; /* 注: struct Entry { void* key; //app id int hash; // app ids hash value void* value; // 1 Entry* next; }; */ is_found = true; break; } token = strtok(NULL, ","); } if (is_found == false) { if (!hashmapContainsKey(fuse->appid_with_rw, (void*) appid)){ hashmapPut(fuse->appid_with_rw, (void*) appid, (void*) 0); } } } } TRACE("read_package_list: found %d packages, %d with write_gid/n", hashmapSize(fuse->package_to_appid), hashmapSize(fuse->appid_with_rw)); fclose(file); pthread_mutex_unlock(&fuse->lock); return 0;}好的,这样hashMap package_to_appid 和appid_with_rw就创建好了。 接着,看看derive_permissions_locked()是如何根据hashMap进行授权工作的啦!static void derive_permissions_locked(struct fuse* fuse, struct node *parent, struct node *node) { appid_t appid; /* By default, each node inherits from its parent */ node->perm = PERM_INHERIT; node->userid = parent->userid; node->uid = parent->uid; node->gid = parent->gid; node->mode = parent->mode;。。。。。。。。。。。。。。。。。。。。。。。。 TRACE("derive_permissions_locked %s 0%d (%s)/n", node->name, parent->perm, parent->name); /* Derive custom permissions based on parent and current node */ switch (parent->perm) {。。。。。。。。。。。。。。。。。。。。。。。。 case PERM_ANDROID_DATA: case PERM_ANDROID_OBB: appid = (appid_t) hashmapGet(fuse->package_to_appid, node->name); // 通过node name, 即app名,获取appid。(上面说过,他们有创建过map的) if (appid != 0) { node->uid = multiuser_get_uid(parent->userid, appid); // 通过appid 和 userid 计算出一个唯一的uid(算法:multiuser_get_uid),分配给该app,下面马上用到它了!! } node->mode = 0770; break;。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 }}下面最后看看如何通过get_caller_has_rw_locked进行访问权限控制的吧!/* Return if the calling UID holds sdcard_rw. */static bool get_caller_has_rw_locked(struct fuse* fuse, const struct fuse_in_header *hdr) {。。。。。。。。。 appid_t appid = multiuser_get_app_id(hdr->uid); //uid 反算出appid if (appid == AID_SHELL) { /* for mtklogger with uid, shell, grant the write permisssion to them */ TRACE("WARNING: appid is AID_SHELL. Grant the write permission to it/n"); return true; } else if (hashmapContainsKey(fuse->appid_with_rw, (void*) appid)) { //判断appid对应的app是否在有权限RW sdcard的hashMap中。 return (bool)hashmapGet(fuse->appid_with_rw, appid); //返回derive_permissions_locked所授权value: 1,表未有rw权限。//appid_with_rw中的hashMap如下: struct Entry { void* key; //app id int hash; // app ids hash value void* value; // 1 or 0 Entry* next; }; */ } else { TRACE("WARNING: appid=%d is NOT in packages.list. Grant the write permission to it/n", appid); //没有授权RW sdcard return true; }}