您的位置:首页 > 移动开发 > Android开发

android sdcard存储方案(基于fuse文件系统):之一

2014-05-15 17:45 881 查看

一、 启动三个相关service

按启动顺序,如下:

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 参数,[b] derive 为DERIVE_LEGACY或DERIVE_UNIFIED时。[/b]

  //为什么要两个线程?这两个线程要怎么同步吗?

        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_LEGACY

DERIVE_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_ROOT

06-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.location

drwxrwx--- u0_a3    sdcard_r          u:object_r:sdcard_external:s0 com.lenovo.carapplication

drwxrwx--- 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,3003

com.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;

    }

}

over !终于完成了,sdcard.c也基本搞明白啦!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: