ADROID 2.1 架构解析 9 SD/USB

9 SD/USB

9.1 主流程

文件: system/core/vold/Vold.c

int main(int argc, char **argv)

{

       ...

mkdir("/dev/block/vold", 0755);

       ...

        /*

     * Bootstrap

     */

 

    bootstrap = 1;

    // Volume Manager

    volmgr_bootstrap();

 

    // SD Card system

    mmc_bootstrap();

 

       ...

    // Switch

    switch_bootstrap();

 

    bootstrap = 0;

       ...

}

volmgr_bootstrap : 加载配置文件

mmc_bootstrap    : 挂载 mmc/sdcard

switch_bootstrap   : 连接 usb

9.2 加载配置文件

文件: system/core/vold/Volmgr.c

int volmgr_bootstrap(void)

{

    int rc;

 

    if ((rc = volmgr_readconfig("/system/etc/vold.conf")) < 0) {

        LOGE("Unable to process config");

        return rc;

    }

 

    /*

     * Check to see if any of our volumes is mounted

      */

    volume_t *v = vol_root;

    while (v) {

        if (_mountpoint_mounted(v->mount_point)) {

            LOGW("Volume '%s' already mounted at startup", v->mount_point);

            v->state = volstate_mounted;

        }

        v = v->next;

    }

 

     return 0;

}

 

两部分功能:

1 读取配置文件: /system/etc/vold.conf

2 _mountpoint_mounted 检查设备是否挂载,若挂载则状态改为 volstate_mounted

 

static int volmgr_readconfig(char *cfg_path)

{

    cnode *root = config_node("", "");

    cnode *node;

 

     config_load_file(root, cfg_path);

    node = root->first_child;

 

    while (node) {

        if (!strncmp(node->name, "volume_", 7))

            volmgr_config_volume(node);

        else

            LOGE("Skipping unknown configuration node '%s'", node->name);

        node = node->next;

    }

     return 0;

}

9.2.1 读取配置文件

config_load_file 的功能是将配置文件的信息读出来,然后以 cnode 链表结构的方式保存。

cnode 结构如下:

struct cnode

{

    cnode *next;

    cnode *first_child;

    cnode *last_child;

    const char *name;

    const char *value;

};

如配置文件: /system/etc/vold.conf

volume_sdcard {

    ## This is the direct uevent device path to the SD slot on the device

    media_path     /devices/platform/msm_sdcc.2/mmc_host/mmc1

    emu_media_path /devices/platform/goldfish_mmc.0/mmc_host/mmc0

 

    media_type     mmc

    mount_point    /sdcard

    ums_path       /devices/platform/usb_mass_storage/lun0

}

读到链表后的形式是:

Root ---- first_child ---- name = volume_sdcard

                |--- next ---- name = media_path

                                      |--- value = /devices/platform/msm_sdcc.2/mmc_host/mmc1

                                      |--- next ---- name = emu_media_path

                                                |--- value = /devices/platform/goldfish_mmc.0 ...

                                                   |--- next ---- ...

按照这样的格式保存配置文件的信息。

9.2.2 分析配置文件

volmgr_config_volume 的功能是将 root 链表结构的信息存储到 vol_root 链表结构对应的项里。

vol_root 结构如下:

typedef struct volume {

    char            *media_paths[VOLMGR_MAX_MEDIAPATHS_PER_VOLUME];

 

    media_type_t      media_type;

    char              *mount_point;

    char              *ums_path;

    struct devmapping *dm;

 

    pthread_mutex_t          lock;

    volume_state_t           state;

    blkdev_t                 *dev;

    pid_t                     worker_pid;

    pthread_t                worker_thread;

    union {

        struct volmgr_start_args  start_args;

        struct volmgr_reaper_args reaper_args;

    } worker_args;

    boolean                  worker_running;

    pthread_mutex_t          worker_sem;

 

    struct volmgr_fstable_entry *fs;

 

    struct volume            *next;

} volume_t;

也就是说用 media_paths media_type media_type mount_point ums_path 等来存储配置文件里对应的值。

9.3 挂载 mmc/sdcard

文件: system/core/vold/Mmc.c

#define SYSFS_CLASS_MMC_PATH "/sys/class/mmc_host"

int mmc_bootstrap()

{

    DIR *d;

    struct dirent *de;

 

    if (!(d = opendir(SYSFS_CLASS_MMC_PATH) )) {

        LOG_ERROR("Unable to open '%s' (%s)", SYSFS_CLASS_MMC_PATH,

                  strerror(errno));

        return -errno;

    }

 

    while ((de = readdir(d))) {

        char tmp[255];

 

        if (de->d_name[0] == '.')

            continue;

 

        sprintf(tmp, "%s/%s", SYSFS_CLASS_MMC_PATH, de->d_name);

        if (mmc_bootstrap_controller(tmp) ) {

            LOG_ERROR("Error bootstrapping controller '%s' (%s)", tmp,

                      strerror(errno));

        }

    }

 

    closedir(d);

 

    return 0;

}

 

以下面 /sys/class/mmc_host 目录为例加以解说。

例子:

/sys/class/mmc_host/: mmc0 mmc1

/sys/class/mmc_host/mmc0/: uevent subsystem device power mmc0:e624

Mmc0:e624 是一个链接目录,其真实路径是:

/sys/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624

/sys/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624/name: SR016

/sys/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624/type:SD

/sys/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624/block/:mmcblk0

/sys/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624/block/mmcblk0/:

uevent  dev  subsystem  device  range  ext_range  removable  ro  size  capability

stat  power  holders  slaves  mmcblk0p1  queue  bdi

 

上面代码实现的功能是:扫描 /sys/class/mmc_hos 目录下的所有文件和文件夹,然后一个一个的将它的路径传入 mmc_bootstrap_controller, 如下,以例子路径来说,则会先把 /sys/class/mmc_host/mmc0 传给下面函数:

static int mmc_bootstrap_controller(char *sysfs_path)

{

    DIR *d;

    struct dirent *de;

 

#if DEBUG_BOOTSTRAP

    LOG_VOL("bootstrap_controller(%s):", sysfs_path);

#endif

    if (!(d = opendir(sysfs_path))) {

        LOG_ERROR("Unable to open '%s' (%s)", sysfs_path, strerror(errno));

        return -errno;

    }

 

    while ((de = readdir(d))) {

        char tmp[255];

 

        if (de->d_name[0] == '.')

            continue;

 

        if ((!strcmp(de->d_name, "uevent")) ||

            (!strcmp(de->d_name, "subsystem")) ||

            (!strcmp(de->d_name, "device")) ||

            (!strcmp(de->d_name, "power"))) {

            continue;

        }

 

        sprintf(tmp, "%s/%s", sysfs_path, de->d_name);

 

        if (mmc_bootstrap_card(tmp) < 0)

            LOG_ERROR("Error bootstrapping card '%s' (%s)", tmp, strerror(errno));

    } // while

 

    closedir(d);

return 0;  

}

继续扫描传进来的路径,将文件名不在 {uevent,subsystem,device,power} 内的文件或文件夹传给 mmc_bootstrap_card ,如下,以例子路径来说,则会先把 /sys/class/mmc_host/mmc0/ mmc0:e624 传给下面函数

static int mmc_bootstrap_card(char *sysfs_path)

{

    char saved_cwd[255];

    char new_cwd[255];

    char *devpath;

    char *uevent_params[4];

    char *p;

    char filename[255];

    char tmp[255];

    ssize_t sz;

 

#if DEBUG_BOOTSTRAP

    LOG_VOL("bootstrap_card(%s):", sysfs_path);

#endif

 

    /*

     * sysfs_path is based on /sys/class, but we want the actual device class

     */

    if (!getcwd(saved_cwd, sizeof(saved_cwd))) {

        LOGE("Error getting working dir path");

        return -errno;

    }

   

    if (chdir(sysfs_path) < 0) {

        LOGE("Unable to chdir to %s (%s)", sysfs_path, strerror(errno));

        return -errno;

     }

 

    if (!getcwd(new_cwd, sizeof(new_cwd))) {

        LOGE("Buffer too small for device path");

        return -errno;

    }

 

    if (chdir(saved_cwd) < 0) {

        LOGE("Unable to restore working dir");

        return -errno;

    }

 

    devpath = &new_cwd[4]; // Skip over '/sys'

 

    /*

     * Collect parameters so we can simulate a UEVENT

     */

    sprintf(tmp, "DEVPATH=%s", devpath);

    uevent_params[0] = (char *) strdup(tmp);

 

    sprintf(filename, "/sys%s/type", devpath);

    p = read_file(filename, &sz);

    p[strlen(p) - 1] = '/0';

    sprintf(tmp, "MMC_TYPE=%s", p);

    free(p);

    uevent_params[1] = (char *) strdup(tmp);

 

    sprintf(filename, "/sys%s/name", devpath);

    p = read_file(filename, &sz);

    p[strlen(p) - 1] = '/0';

    sprintf(tmp, "MMC_NAME=%s", p);

    free(p);

    uevent_params[2] = (char *) strdup(tmp);

 

    uevent_params[3] = (char *) NULL;

 

    if (simulate_uevent("mmc", devpath, "add", uevent_params ) < 0) {

        LOGE("Error simulating uevent (%s)", strerror(errno));

        return -errno;

    }

 

    /*

     *  Check for block drivers

     */

    char block_devpath[255];

    sprintf(tmp, "%s/block", devpath);

    sprintf(filename, "/sys%s/block", devpath);

    if (!access(filename, F_OK)) {

        if (mmc_bootstrap_block(tmp) ) {

            LOGE("Error bootstrapping block @ %s", tmp);

        }

    }

 

    return 0;

}

Getcwd 获取当前路径

Chdir 更改路径

由于 sysfs_path 是一个链接路径,所以需要用 Chdir Getcwd 来获取它的真实路径。以例子路径来说,获得的真实路径是:

/sys/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624

所以 DEVPATH = /devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624 ,而这个也就是在配置文件 vold.conf media_path 的路径, media_path 的路径要与 DEVPATH 相同,否则不会加载 SD 卡,这个 <<9.5.1.3 处理 uevent 事件 >> 说明。

DEVPATH = /devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624

MMC_TYPE=SD

MMC_NAME= SR016

以上三个参数作 uevent 的参数,虚拟产生一个 add 事件:

simulate_uevent("mmc", devpath, "add", uevent_params);

然后将路径 /devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624/block

传给 mmc_bootstrap_block ,如下

static int mmc_bootstrap_block(char *devpath)

{

    char blockdir_path[255];

    DIR *d;

    struct dirent *de;

 

#if DEBUG_BOOTSTRAP

    LOG_VOL("mmc_bootstrap_block(%s):", devpath);

#endif

 

    sprintf(blockdir_path, "/sys%s", devpath);

 

    if (!(d = opendir(blockdir_path))) {

        LOGE("Failed to opendir %s", devpath);

        return -errno;

    }

 

    while ((de = readdir(d))) {

        char tmp[255];

 

        if (de->d_name[0] == '.')

            continue;

        sprintf(tmp, "%s/%s", devpath, de->d_name);

        if (mmc_bootstrap_mmcblk(tmp))

            LOGE("Error bootstraping mmcblk @ %s", tmp);

    }

    closedir(d);

    return 0;

}

会扫描所有文件或目录,将路径传给 mmc_bootstrap_mmcblk ,以例子路径来说,则会把 /sys/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624/block/mmcblk0/ 传给下面函数

static int mmc_bootstrap_mmcblk(char *devpath)

{

    char *mmcblk_devname;

    int part_no;

    int rc;

 

#if DEBUG_BOOTSTRAP

     LOG_VOL("mmc_bootstrap_mmcblk(%s):", devpath);

#endif

 

    if ((rc = mmc_bootstrap_mmcblk_partition (devpath))) {

        LOGE("Error bootstrapping mmcblk partition '%s'", devpath);

        return rc;

    }

 

    for (mmcblk_devname = &devpath[strlen(devpath)];

         *mmcblk_devname != '/'; mmcblk_devname--);

    mmcblk_devname++;

 

    for (part_no = 0; part_no < 4; part_no++) {

        char part_file[255];

        sprintf(part_file, "/sys%s/%sp%d", devpath, mmcblk_devname, part_no);

        if (!access(part_file, F_OK)) {

            char part_devpath[255];

 

            sprintf(part_devpath, "%s/%sp%d", devpath, mmcblk_devname, part_no);

            if (mmc_bootstrap_mmcblk_partition (part_devpath))

                LOGE("Error bootstrapping mmcblk partition '%s'", part_devpath);

        }

    }

 

    return 0;

}

mmc_bootstrap_mmcblk_partition 的功能是读取当前路径下的 uevent 文件里的四个参数:

DEVPATH,DEVTYPE MAJOR MINOR ,然后将这四个参数作为 uevent 参数,产生一个 uevent 事件:

simulate_uevent("block", devpath, "add", uevent_params)

所以上面代码的功能是:

1 /sys/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624/block/mmcblk0/uevent 里的参数产生一个 uevent 事件

2 /sys/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624/block/mmcblk0/mmcblk0p0

  /sys/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624/block/mmcblk0/mmcblk0p1

  /sys/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624/block/mmcblk0/mmcblk0p2

  /sys/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624/block/mmcblk0/mmcblk0p3

以上路径如存在 , 则读取目录下的 uevent 文件 , 产生一个 uevent 事件 .

 

所以 , 加载这部分的功能就是产生三个事件 :

devpath=/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624

simulate_uevent("mmc", devpath, "add", uevent_params);

 

devpath=/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624/block/mmcblk0/

simulate_uevent("block", devpath, "add", uevent_params)

 

devpath=/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624/block/mmcblk0/mmcblk0p1

simulate_uevent("block", devpath, "add", uevent_params)

9.4 连接 usb

文件 :system/core/vold/Switch.c

#define SYSFS_CLASS_SWITCH_PATH "/sys/class/switch"

int switch_bootstrap()

{

    DIR *d;

    struct dirent *de;

 

    if (!(d = opendir(SYSFS_CLASS_SWITCH_PATH))) {

        LOG_ERROR("Unable to open '%s' (%s)", SYSFS_CLASS_SWITCH_PATH,

                   strerror(errno));

        return -errno;

    }

 

    while ((de = readdir(d))) {

        char tmp[255];

 

        if (de->d_name[0] == '.')

            continue;

 

        sprintf(tmp, "%s/%s", SYSFS_CLASS_SWITCH_PATH, de->d_name);

        if (mmc_bootstrap_switch(tmp)) {

             LOG_ERROR("Error bootstrapping switch '%s' (%s)", tmp,

                      strerror(errno));

        }

    }

 

    closedir(d);

 

    return 0;

}

扫描路径 /sys/class/switch 下的文件和目录 , 并将路径传给函数 mmc_bootstrap_switch.

以下 /sys/class/switch 目录为例 , 来说明这个过程 .

 

例子 :

/sys/class/switch/

micco_hsdetect                                                                 

usb_mass_storage

 

/sys/class/switch/ usb_mass_storage/

uevent                                                                         

subsystem                                                                       

power                                                                          

state                                                                          

name

/sys/class/switch/ usb_mass_storage/name:usb_mass_storage

 

/sys/devices/virtual/switch/

micco_hsdetect                                                                 

usb_mass_storage

 

/sys/devices/virtual/switch/usb_mass_storage

uevent                                                                          

subsystem                                                                      

power                                                                          

state                                                                           

name

/sys/devices/virtual/switch/usb_mass_storage/state:online

 

以上代码实现的功能是分别将

/sys/class/switch/micco_hsdetect

/sys/class/switch/usb_mass_storage

两个路径传给函数 mmc_bootstrap_switch

static int mmc_bootstrap_switch(char *sysfs_path)

{

#if DEBUG_BOOTSTRAP

    LOG_VOL("bootstrap_switch(%s):", sysfs_path);

#endif

 

    char filename[255];

    char name[255];

    char state[255];

    char tmp[255];

    char *uevent_params[3];

    char devpath[255];

    FILE *fp;

 

    /*

     * Read switch name

     */

    sprintf(filename, "%s/name", sysfs_path);

    if (!(fp = fopen(filename, "r"))) {

        LOGE("Error opening switch name path '%s' (%s)",

             sysfs_path, strerror(errno));

       return -errno;

    }

    if (!fgets(name, sizeof(name), fp)) {

         LOGE("Unable to read switch name");

        fclose(fp);

        return -EIO;

    }

    fclose(fp);

 

    name[strlen(name) -1] = '/0';

    sprintf(devpath, "/devices/virtual/switch/%s", name);

    sprintf(tmp, "SWITCH_NAME=%s", name);

    uevent_params[0] = (char *) strdup(tmp);

 

    /*

     * Read switch state

     */

    sprintf(filename, "%s/state", sysfs_path);

    if (!(fp = fopen(filename, "r"))) {

        LOGE("Error opening switch state path '%s' (%s)",

             sysfs_path, strerror(errno));

        return -errno;

    }

    if (!fgets(state, sizeof(state), fp)) {

        LOGE("Unable to read switch state");

        fclose(fp);

        return -EIO;

    }

    fclose(fp);

 

    state[strlen(state) -1] = '/0';

    sprintf(tmp, "SWITCH_STATE=%s", state);

    uevent_params[1] = (char *) strdup(tmp);

 

    uevent_params[2] = (char *) NULL;

 

    if (simulate_uevent("switch", devpath, "add", uevent_params) < 0) {

        LOGE("Error simulating uevent (%s)", strerror(errno));

        return -errno;

    }

 

     return 0;  

}

 

转到 /sys/class/switch/usb_mass_storage 下,获取 state 的值,再作为 uevent 的参数,产生 switch uevent 事件。

SWITCH_NAME= usb_mass_storage

SWITCH_STATE= online

devpath= /devices/virtual/switch/usb_mass_storage

9.5 通信机制

9.5.1 uevent

文件: system/core/vold/Uevent.c

9.5.1.1 产生 uevent 事件

int simulate_uevent(char *subsys, char *path, char *action, char **params)

{

    struct uevent *event;

    char tmp[255];

    int i, rc;

 

    if (!(event = malloc(sizeof(struct uevent)))) {

        LOGE("Error allocating memory (%s)", strerror(errno));

        return -errno;

    }

 

    memset(event, 0, sizeof(struct uevent));

 

    event->subsystem = strdup(subsys);

 

    if (!strcmp(action, "add"))

        event->action = action_add;

    else if (!strcmp(action, "change"))

        event->action = action_change;

    else if (!strcmp(action, "remove"))

        event->action = action_remove;

    else {

        LOGE("Invalid action '%s'", action);

        return -1;

    }

 

    event->path = strdup(path);

 

    for (i = 0; i < UEVENT_PARAMS_MAX; i++) {

         if (!params[i])

            break;

        event->param[i] = strdup(params[i]);

    }

 

    rc = dispatch_uevent(event);

    free_uevent(event);

    return rc;

}

如:

devpath = “/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624”

uevent_params [0] = “MMC_TYPE=SD”

uevent_params [1] = “MMC_NAME= SR016”

simulate_uevent("mmc", devpath, "add", uevent_params);

则经过 simulate_uevent 后,打包成:

event->subsystem         =  “mmc”

event->action               =   action_add;

event->path                  =  “/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624”

event->param[0]           =  “MMC_TYPE=SD”

event->param[1]           =  “MMC_NAME=SR016”

然后发给 dispatch_uevent

9.5.1.2 分配 uevent 事件

static struct uevent_dispatch dispatch_table[] = {

    { "switch", handle_switch_event },

    { "battery", handle_battery_event },

    { "mmc", handle_mmc_event },

    { "block", handle_block_event },

    { "bdi", handle_bdi_event },

    { "power_supply", handle_powersupply_event },

    { NULL, NULL }

};

static int dispatch_uevent(struct uevent *event)

{

    int i;

 

#if DEBUG_UEVENT

    dump_uevent(event);

#endif

    for (i = 0; dispatch_table[i].subsystem != NULL; i++) {

        if (!strcmp(dispatch_table[i].subsystem, event->subsystem))

            return dispatch_table[i].dispatch(event);

    }

 

#if DEBUG_UEVENT

    LOG_VOL("No uevent handlers registered for '%s' subsystem", event->subsystem);

#endif

    return 0;

}

根据 subsystem 的类型来分配, event->subsystem          =  “mmc” ,则分配到 handle_mmc_event 进行处理

9.5.1.3 处理 uevent 事件

mmc 加载事件为例:

处理   << 9.3 挂载 mmc/sdcard>>     simulate_uevent("mmc", devpath, "add", uevent_params);

文件: system/core/vold/uevent.c

static int handle_mmc_event(struct uevent *event)

{

    if (event->action == action_add) {

        media_t *media;

        char serial[80];

        char *type;

 

        /*

         * Pull card information from sysfs

         */

        type = get_uevent_param(event, "MMC_TYPE");

        if (strcmp(type, "SD") && strcmp(type, "MMC"))

            return 0;

       

        read_sysfs_var(serial, sizeof(serial), event->path, "serial");

        if (!(media = media_create(event->path,

                                   get_uevent_param(event, "MMC_NAME"),

                                   serial,

                                   media_mmc)) ) {

            LOGE("Unable to allocate new media (%s)", strerror(errno));

             return -1;

        }

        LOGI("New MMC card '%s' (serial %u) added @ %s", media->name,

                  media->serial, media->devpath);

}

...

    }

 

    return 0;

}

文件: system/core/vold/Media.c

media_t *media_create(char *devpath, char *name, char *serial, media_type_t type)

{

    media_list_t *list_entry;

    media_t *new;

 

    if (!(new = malloc(sizeof(media_t))))

        return NULL;

 

    memset(new, 0, sizeof(media_t));

 

    if (!(list_entry = malloc(sizeof(media_list_t)))) {

        free(new);

        return NULL;

    }

    list_entry->media = new;

    list_entry->next = NULL;

 

    if (!list_root)

        list_root = list_entry;

    else {

        media_list_t *list_scan = list_root;

        while(list_scan->next)

            list_scan = list_scan->next;

        list_scan->next = list_entry;

    }

    

    new->devpath = strdup(devpath);

    new->name = strdup(name);

    if (!serial)

        new->serial = 0;

    else

        new->serial = strtoul(serial, NULL, 0);

 

    new->media_type = type;

 

    return new;

}

devpath, name, serial, media_type 等信息以 media 结构打包放到 list_root 链表里去。

处理 << 9.3 挂载 mmc/sdcard>> simulate_uevent("block", devpath, "add", uevent_params) ;其中有两个 block 的事件,对应两个目录,所以有  disk,partition 两个参数,处理如下:

文件: system/core/vold/uevent.c

static int handle_block_event(struct uevent *event)

{

    char mediapath[255];

    media_t *media;

    int n;

    int maj, min;

    blkdev_t *blkdev;

    char *mmcblk_devname;

    /*

     * Look for backing media for this block device

     */

    if (!strncmp(get_uevent_param(event, "DEVPATH"),

                 "/devices/virtual/",

                 strlen("/devices/virtual/"))) {

        n = 0;

    } else if (!strcmp(get_uevent_param(event, "DEVTYPE"), "disk"))

        n = 2;

    else if (!strcmp(get_uevent_param(event, "DEVTYPE"), "partition"))

        n = 3;

    else {

        LOGE("Bad blockdev type '%s'", get_uevent_param(event, "DEVTYPE"));

        return -EINVAL;

    }

  

     truncate_sysfs_path(event->path, n, mediapath, sizeof(mediapath));

 

    LOGE("PATH=  '%s' ,n=%d,mediapth = %s",event->path, n, mediapath);

 

    if (!(media = media_lookup_by_path(mediapath, false))) {

#if DEBUG_UEVENT

        LOG_VOL("No backend media found @ device path '%s'", mediapath);

#endif

        return 0;

    }

 

    maj = atoi(get_uevent_param(event, "MAJOR"));

    min = atoi(get_uevent_param(event, "MINOR"));

 

    if (event->action == action_add) {

        blkdev_t *disk;

 

        /*

         * If there isn't a disk already its because *we*

         * are the disk

         */

        if (media->media_type == media_mmc)

            disk = blkdev_lookup_by_devno(maj, ALIGN_MMC_MINOR(min));

        else

            disk = blkdev_lookup_by_devno(maj, 0);

 

        if (!(blkdev = blkdev_create(disk,

                                     event->path,

                                      maj,

                                     min,

                                     media,

                                     get_uevent_param(event, "DEVTYPE")))) {

            LOGE("Unable to allocate new blkdev (%s)", strerror(errno));

            return -1;

        }

 

        blkdev_refresh(blkdev);

 

        /*

         * Add the blkdev to media

         */

        int rc;

        if ((rc = media_add_blkdev(media, blkdev) ) < 0) {

            LOGE("Unable to add blkdev to card (%d)", rc);

            return rc;

        }

 

        LOGI("New blkdev %d.%d on media %s, media path %s, Dpp %d",

                blkdev->major, blkdev->minor, media->name, mediapath,

                blkdev_get_num_pending_partitions(blkdev->disk));

 

         if (blkdev_get_num_pending_partitions(blkdev->disk) == 0) {

            if ((rc = volmgr_consider_disk (blkdev->disk)) < 0) {

                if (rc == -EBUSY) {

                    LOGI("Volmgr not ready to handle device");

                } else {

                     LOGE("Volmgr failed to handle device (%d)", rc);

                    return rc;

                }

            }

        }

}

...

    return 0;

}

truncate_sysfs_path 的功能是后通 n 个目录,为了最终获得路径:

/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624          

blkdev_create 的功能是将 major,minor,media 等参数组成一个 blkdev 然后返回 blkdev

media_add_blkdev 的功能是将 blkdev 添加到 list_root 列表去

media_lookup_by_path 的功能是与 media_create 创建后的 media_path 行比较,确定是否一致。

volmgr_consider_disk 的功能是 list_root media_path vol_root media_path 行比较,确定是否一致。

 

文件: system/core/vold/volmgr.c

int volmgr_consider_disk(blkdev_t *dev)

{

    volume_t *vol;

 

    if (!(vol = volmgr_lookup_volume_by_mediapat h(dev->media->devpath, true)))

{

LOGE("volmgr_consider_disk:LOOKUP FAILED");

        return 0;

    }

   ...

}

static volume_t *volmgr_lookup_volume_by_mediapath(char *media_path, boolean fuzzy)

{

    volume_t *scan = vol_root;

    int i;

 

    while (scan) {

 

        for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) {

            if (!scan->media_paths[i])

                continue;

 

            if (fuzzy && !strncmp(media_path, scan->media_paths[i], strlen(scan->media_paths[i]) ))

                return scan;

            else if (!fuzzy && !strcmp(media_path, scan->media_paths[i]))

                return scan;

        }

 

         scan = scan->next;

    }

    return NULL;

}

如上代码,会比较 strncmp(media_path, scan->media_paths[i], strlen(scan->media_paths[i]) ,会以 vol_root media_path 的长度来比较 media_path 的路径是否与 devpath 一致。

比如, media_path = /devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624

则, vold.conf 文件里的 media_path 路径可以设成

/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624

/devices/platform/pxa2xx-mci.0/mmc_host/mmc0/

/devices/platform/pxa2xx-mci.0/mmc_host/

/devices/platform/pxa2xx-mci.0/

/devices/platform/

/devices/

都行

9.5.2 命令

9.5.2.1 发送命令

文件: system/core/vold/Vold.c

int send_msg(char* message)

{

    int result = -1;

 

    pthread_mutex_lock(&write_mutex);

 

//    LOG_VOL("send_msg(%s):", message);

 

    if (fw_sock >= 0)

        result = write(fw_sock, message, strlen(message) + 1);

 

    pthread_mutex_unlock(&write_mutex);

 

    return result;

}

 

int send_msg_with_data(char *message, char *data)

{

    int result = -1;

 

    char* buffer = (char *)alloca(strlen(message) + strlen(data) + 1);

    if (!buffer) {

        LOGE("alloca failed in send_msg_with_data");

        return -1;

    }

 

    strcpy(buffer, message);

    strcat(buffer, data);

    return send_msg(buffer);

}

将消息写到 sock 文件

9.5.2.2 接收命令

文件: system/core/vold/Cmd_dispatch.c

int process_framework_command(int socket)

{

    int rc;

    char buffer[101];

 

    if ((rc = read(socket, buffer, sizeof(buffer) -1)) < 0) {

        LOGE("Unable to read framework command (%s)", strerror(errno));

        return -errno;

    } else if (!rc)

        return -ECONNRESET;

 

    int start = 0;

    int i;

 

    buffer[rc] = 0;

 

    for (i = 0; i < rc; i++) {

         if (buffer[i] == 0) {

            dispatch_cmd(buffer + start);

            start = i + 1;

        }

    }

    return 0;

}

读出 socket 文件的数据,然后对数据所代表的命令进行分配。

9.5.2.3 分配命令

文件: system/core/vold/Cmd_dispatch.c

// These must match the strings in java/android/android/os/UsbListener.java

#define VOLD_CMD_ENABLE_UMS         "enable_ums"

#define VOLD_CMD_DISABLE_UMS        "disable_ums"

#define VOLD_CMD_SEND_UMS_STATUS    "send_ums_status"

 

// these commands should contain a volume mount point after the colon

#define VOLD_CMD_MOUNT_VOLUME       "mount_volume:"

#define VOLD_CMD_EJECT_MEDIA        "eject_media:"

#define VOLD_CMD_FORMAT_MEDIA        "format_media:"

 

static struct cmd_dispatch dispatch_table[] = {

    { VOLD_CMD_ENABLE_UMS,      do_set_ums_enable },

    { VOLD_CMD_DISABLE_UMS,     do_set_ums_enable },

    { VOLD_CMD_SEND_UMS_STATUS, do_send_ums_status },

    { VOLD_CMD_MOUNT_VOLUME,    do_mount_volume },

    { VOLD_CMD_EJECT_MEDIA,     do_eject_media },

    { VOLD_CMD_FORMAT_MEDIA,    do_format_media },

    { NULL, NULL }

};

static void dispatch_cmd(char *cmd)

{

    struct cmd_dispatch *c;

 

    LOG_VOL("dispatch_cmd(%s):", cmd);

 

    for (c = dispatch_table; c->cmd != NULL; c++) {

        if (!strncmp(c->cmd, cmd, strlen(c->cmd))) {

            c->dispatch(cmd);

            return;

        }

    }

 

    LOGE("No cmd handlers defined for '%s'", cmd);

}

命令格式: mount_volume:/sdcard ,将 mount_volume 分配表 dispatch_table 中的命令字进行匹配,合适的进行处理。

9.5.2.4 处理命令

文件: system/core/vold/Cmd_dispatch.c

static int do_mount_volume(char *cmd)

{

    return volmgr_start_volume_by_mountpoint(&cmd[strlen("mount_volume:")]);

}

过滤掉命令字,将其后的参数传递给相应的处理函数。

9.5.3 socket

9.5.3.1 socket 的服务程序

文件: system/core/vold/Vold.c

#define VOLD_SOCKET "vold"

nt main(int argc, char **argv)

{

    int door_sock = -1;

    int uevent_sock = -1;

    struct sockaddr_nl nladdr;

    int uevent_sz = 64 * 1024;

 

    LOGI("Android Volume Daemon version %d.%d", ver_major, ver_minor);

 

    /*

     * Create all the various sockets we'll need

     */

 

    // Socket to listen on for incomming framework connections

    if ((door_sock = android_get_control_socket(VOLD_SOCKET)) < 0) {

        LOGE("Obtaining file descriptor socket '%s' failed: %s",

             VOLD_SOCKET, strerror(errno));

        exit(1);

    }

 

    if (listen(door_sock, 4) < 0) {

        LOGE("Unable to listen on fd '%d' for socket '%s': %s",

             door_sock, VOLD_SOCKET, strerror(errno));

        exit(1);

    }

    ...

    // Socket to listen on for uevent changes

    memset(&nladdr, 0, sizeof(nladdr));

    nladdr.nl_family = AF_NETLINK;

    nladdr.nl_pid = getpid();

    nladdr.nl_groups = 0xffffffff;

 

     if ((uevent_sock = socket(PF_NETLINK,

                             SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {

        LOGE("Unable to create uevent socket: %s", strerror(errno));

        exit(1);

    }

 

    if (setsockopt(uevent_sock, SOL_SOCKET, SO_RCVBUFFORCE, &uevent_sz,

                   sizeof(uevent_sz)) < 0) {

        LOGE("Unable to set uevent socket options: %s", strerror(errno));

        exit(1);

    }

 

    if (bind(uevent_sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {

        LOGE("Unable to bind uevent socket: %s", strerror(errno));

        exit(1);

    }

...

    while(1) {

        fd_set read_fds;

        struct timeval to;

        int max = 0;

        int rc = 0;

 

        to.tv_sec = (60 * 60);

        to.tv_usec = 0;

 

        FD_ZERO(&read_fds);

        FD_SET(door_sock, &read_fds);

        if (door_sock > max)

            max = door_sock;

        FD_SET(uevent_sock, &read_fds);

        if (uevent_sock > max)

            max = uevent_sock;

 

        if (fw_sock != -1) {

            FD_SET(fw_sock, &read_fds);

            if (fw_sock > max)

                max = fw_sock;

        }

 

        if ((rc = select(max + 1, &read_fds, NULL, NULL, &to)) < 0) {

            LOGE("select() failed (%s)", strerror(errno));

            sleep(1);

             continue;

        }

 

        if (!rc) {

            continue;

        }

 

        if (FD_ISSET(door_sock, &read_fds)) {

            struct sockaddr addr;

            socklen_t alen;

 

            alen = sizeof(addr);

 

            if (fw_sock != -1) {

                LOGE("Dropping duplicate framework connection");

                int tmp = accept(door_sock, &addr, &alen);

                close(tmp);

                continue;

            }

 

            if ((fw_sock = accept(door_sock, &addr, &alen)) < 0) {

                LOGE("Unable to accept framework connection (%s)",

                     strerror(errno));

            }

            LOG_VOL("Accepted connection from framework");

            if ((rc = volmgr_send_states()) < 0) {

                LOGE("Unable to send volmgr status to framework (%d)", rc);

            }

        }

 

        if (FD_ISSET(fw_sock, &read_fds)) {

            if ((rc = process_framework_command(fw_sock)) < 0) {

                if (rc == -ECONNRESET) {

                    LOGE("Framework disconnected");

                    close(fw_sock);

                    fw_sock = -1;

                } else {

                    LOGE("Error processing framework command (%s)",

                         strerror(errno));

                }

             }

        }

 

        if (FD_ISSET(uevent_sock, &read_fds)) {

            if ((rc = process_uevent_message(uevent_sock)) < 0) {

                LOGE("Error processing uevent msg (%s)", strerror(errno));

            }

        }

    } // while

 

}

以上代码有两个 socket ,一个是 ”vold” socket ,负责接收和处理 vold 命令;一个是 uevent socket 负责接收和处理 uevent 事件。

9.5.3.2 “vold” socket 客户程序

文件: frameworks/base/services/java/com/android/server/MountListener.java

private void listenToSocket() {

       LocalSocket socket = null;

 

        try {

            socket = new LocalSocket();

            LocalSocketAddress address = new LocalSocketAddress(VOLD_SOCKET,

                    LocalSocketAddress.Namespace.RESERVED);

 

            socket.connect(address);

       ...

 

9.6 mount SDCARD

MountListener.java 启动后会去挂载 SDCARD.

文件: frameworks/base/services/java/com/android/server/MountListener.java

private static final String VOLD_CMD_SEND_UMS_STATUS = "send_ums_status";

private static final String VOLD_CMD_MOUNT_VOLUME = "mount_volume:";

private void listenToSocket() {

       LocalSocket socket = null;

 

        try {

            socket = new LocalSocket();

            LocalSocketAddress address = new LocalSocketAddress(VOLD_SOCKET,

                    LocalSocketAddress.Namespace.RESERVED);

 

            socket.connect(address);

                     writeCommand(VOLD_CMD_SEND_UMS_STATUS);

            mountMedia(Environment.getExternalStorageDirectory().getAbsolutePath());

                     ...

}

 

注: ExternalStorageDirectory 的定义在:

文件: frameworks/base/core/java/android/os/Environment.java

private static final File EXTERNAL_STORAGE_DIRECTORY

            = getDirectory("EXTERNAL_STORAGE", "/sdcard");

 

public void mountMedia(String mountPoint) {

        writeCommand2(VOLD_CMD_MOUNT_VOLUME, mountPoint);

}

 

mountPoint = /sdcard

由此向 ”vold” socket 发送一个 VOLD_CMD_MOUNT_VOLUME 命令,该命令处理如下:

文件: system/core/vold/Cmd_dispatch.c

static struct cmd_dispatch dispatch_table[] = {

    ...

    { VOLD_CMD_SEND_UMS_STATUS, do_send_ums_status },

{ VOLD_CMD_MOUNT_VOLUME,    do_mount_volume },

...

};

static int do_mount_volume(char *cmd)

{

    return volmgr_start_volume_by_mountpoint(&cmd[strlen("mount_volume:")]);

}

文件: system/core/vold/Volmgr.c

int volmgr_start_volume_by_mountpoint(char *mount_point)

{

       volume_t *v;

 

    v = volmgr_lookup_volume_by_mountpoint(mount_point, true);

    ...

 

        if (_volmgr_consider_disk_and_vol (v, v->dev->disk) < 0) {

            LOGE("volmgr failed to start volume '%s'", v->mount_point);

        }

     ...

    return 0;

}

static volume_t *volmgr_lookup_volume_by_mountpoint(char *mount_point, boolean leave_locked)

{

    volume_t *v = vol_root;

 

    while(v) {

        pthread_mutex_lock(&v->lock);

        if (!strcmp(v->mount_point, mount_point)) {

             if (!leave_locked)

                pthread_mutex_unlock(&v->lock);

            return v;

        }

        pthread_mutex_unlock(&v->lock);

        v = v->next;

    }

    return NULL;

}

vol_root 链表里找到对应的结点。

static int _volmgr_consider_disk_and_vol(volume_t *vol, blkdev_t *dev)

{

    ...

            part = blkdev_lookup_by_devno(dev->major, ALIGN_MMC_MINOR(dev->minor) + 1);

        ...

            rc = _volmgr_start(vol, part);

    return rc;

}

 

struct volmgr_fstable_entry {

    char *name;

    int      (*identify_fn) (blkdev_t *dev);

    int     (*check_fn) (blkdev_t *dev);

     int     (*mount_fn) (blkdev_t *dev, struct volume *vol, boolean safe_mode);

    boolean case_sensitive_paths;

};

static struct volmgr_fstable_entry fs_table[] = {

//    { "ext3", ext_identify, ext_check, ext_mount , true },

    { "vfat", vfat_identify, vfat_check, vfat_mount , false },

    { NULL, NULL, NULL, NULL , false}

};

 

static int _volmgr_start(volume_t *vol, blkdev_t *dev)

{

...

for (fs = fs_table; fs->name; fs++) {

         if (!fs->identify_fn(dev))

            break;

    }

...

     return volmgr_start_fs(fs, vol, dev);

}

static int volmgr_start_fs(struct volmgr_fstable_entry *fs, volume_t *vol, blkdev_t *dev)

{

    ...

 

    pthread_create(&vol->worker_thread, &attr, volmgr_start_fs_thread, vol);

 

    return 0;

}

static void *volmgr_start_fs_thread(void *arg)

{

    ...

 

    rc = fs->mount_fn(dev, vol, safe_mode);

   ...

}

由此 mount_fn 转向 vfat_mount

文件: system/core/vold/Volmgr_vfat.c

int vfat_mount(blkdev_t *dev, volume_t *vol, boolean safe_mode)

{

    int flags, rc;

    char *devpath;

 

    devpath = blkdev_get_devpath(dev);

 

#if VFAT_DEBUG

    LOG_VOL("vfat_mount(%d:%d, %s, %d):", dev->major, dev->minor, vol->mount_point, safe_mode);

#endif

 

    flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC;

 

    if (vol->state == volstate_mounted) {

        LOG_VOL("Remounting %d:%d on %s, safe mode %d", dev->major,

                dev->minor, vol->mount_point, safe_mode);

        flags |= MS_REMOUNT;

    }

 

    /*

     * Note: This is a temporary hack. If the sampling profiler is enabled,

     * we make the SD card world-writable so any process can write snapshots.

     *

     * TODO: Remove this code once we have a drop box in system_server.

     */

    char value[PROPERTY_VALUE_MAX];

     property_get("persist.sampling_profiler", value, "");

    if (value[0] == '1') {

        LOGW("The SD card is world-writable because the"

            " 'persist.sampling_profiler' system property is set to '1'.");

        rc = mount(devpath, vol->mount_point, "vfat", flags,

                "utf8,uid=1000,gid=1015,fmask=000,dmask=000,shortname=mixed");

    } else {

        /*

         * The mount masks restrict access so that:

         * 1. The 'system' user cannot access the SD card at all -

         *     (protects system_server from grabbing file references)

         * 2. Group users can RWX

         * 3. Others can only RX

         */

        rc = mount(devpath, vol->mount_point, "vfat", flags,

                "utf8,uid=1000,gid=1015,fmask=702,dmask=702,shortname=mixed");

    }

 

    if (rc && errno == EROFS) {

        LOGE("vfat_mount(%d:%d, %s): Read only filesystem - retrying mount RO",

             dev->major, dev->minor, vol->mount_point);

        flags |= MS_RDONLY;

        rc = mount(devpath, vol->mount_point, "vfat", flags,

                   "utf8,uid=1000,gid=1015,fmask=702,dmask=702,shortname=mixed");

    }

 

    if (rc == 0) {

        char *lost_path;

        asprintf(&lost_path, "%s/LOST.DIR", vol->mount_point);

        if (access(lost_path, F_OK)) {

            /*

             * Create a LOST.DIR in the root so we have somewhere to put

             * lost cluster chains (fsck_msdos doesn't currently do this)

             */

            if (mkdir(lost_path, 0755)) {

                LOGE("Unable to create LOST.DIR (%s)", strerror(errno));

            }

        }

        free(lost_path);

    }

 

#if VFAT_DEBUG

    LOG_VOL("vfat_mount(%s, %d:%d): mount rc = %d", dev->major,k dev->minor,

            vol->mount_point, rc);

#endif

    free (devpath);

     return rc;

}

至此, SDCARD 才真正被挂载。

9.7 switch USB

<<9.4 挂载 usb>> 提到的 simulate_uevent("switch", devpath, "add", uevent_params) 产生 add 事件后,会在文件: system/core/vold/Cmd_dispatch.c 里分配一个处理,如下:

static int handle_switch_event(struct uevent *event)

{

    char *name = get_uevent_param(event, "SWITCH_NAME");

    char *state = get_uevent_param(event, "SWITCH_STATE");

 

 

    if (!strcmp(name, "usb_mass_storage")) {

        if (!strcmp(state, "online")) {

            ums_hostconnected_set(true);

        } else {

            ums_hostconnected_set(false);

            volmgr_enable_ums(false);

        }

}

...

}

文件: system/core/vold/Ums.c

void ums_hostconnected_set(boolean connected)

{

    ...

    send_msg(connected ? VOLD_EVT_UMS_CONNECTED : VOLD_EVT_UMS_DISCONNECTED);

}

在这里向 “vold”socket 发送一个 VOLD_EVT_UMS_CONNECTED 消息。

该消息在如下文件得到处理:

文件: frameworks/base/services/java/com/android/server/MountListener.java

    // vold commands

    private static final String VOLD_CMD_ENABLE_UMS = "enable_ums";

    private static final String VOLD_CMD_DISABLE_UMS = "disable_ums";

    private static final String VOLD_CMD_SEND_UMS_STATUS = "send_ums_status";

    ...

    // vold events

    private static final String VOLD_EVT_UMS_ENABLED = "ums_enabled";

    private static final String VOLD_EVT_UMS_DISABLED = "ums_disabled";

    private static final String VOLD_EVT_UMS_CONNECTED = "ums_connected";

private static final String VOLD_EVT_UMS_DISCONNECTED = "ums_disconnected";

private void listenToSocket() {

       LocalSocket socket = null;

 

        try {

            socket = new LocalSocket();

            LocalSocketAddress address = new LocalSocketAddress(VOLD_SOCKET,

                    LocalSocketAddress.Namespace.RESERVED);

 

            socket.connect(address);

 

            InputStream inputStream = socket.getInputStream();

            mOutputStream = socket.getOutputStream();

...

           

            while (true) {

                int count = inputStream.read(buffer);

                if (count < 0) break;

 

                int start = 0;

                for (int i = 0; i < count; i++) {

                    if (buffer[i] == 0) {

                         String event = new String(buffer, start, i - start);

                        handleEvent(event);

                        start = i + 1;

                    }                  

                }

            }               

        }

...

}

private void handleEvent(String event) {

        if (Config.LOGD) Log.d(TAG, "handleEvent " + event);

   

        int colonIndex = event.indexOf(':');

        String path = (colonIndex > 0 ? event.substring(colonIndex + 1) : null);

       

        ...

}else if (event.equals(VOLD_EVT_UMS_CONNECTED)) {

            mUmsConnected = true;

            mService.notifyUmsConnected ();

        } ...

}

mService(mount service) notifyUmsConnected() 广播一下状态,再绕回 MountListenser 调用如下函数发送一个连接 USB 的命令:

void setMassStorageEnabled(boolean enable) {

        writeCommand(enable ? VOLD_CMD_ENABLE_UMS : VOLD_CMD_DISABLE_UMS);

    }

文件: frameworks/base/services/java/com/android/server/MountService.java

void notifyUmsConnected() {

       ...

setMassStorageEnabled(true);

        ...

    }

public void setMassStorageEnabled(boolean enable) throws RemoteException {

        mListener.setMassStorageEnabled(enable);

    }

由此向 ”vold” socket 发送一个 VOLD_CMD_ENABLE_UMS 的命令,该命令处理如下:

{ VOLD_CMD_ENABLE_UMS,      do_set_ums_enable },

文件: system/core/vold/Cmd_dispatch.c

static struct cmd_dispatch dispatch_table[] = {

    { VOLD_CMD_ENABLE_UMS,      do_set_ums_enable },

{ VOLD_CMD_DISABLE_UMS,      do_set_ums_enable },

...

static int do_set_ums_enable(char *cmd)

{

    if (!strcmp(cmd, VOLD_CMD_ENABLE_UMS))

        return volmgr_enable_ums(true);

 

    return volmgr_enable_ums(false);

}

转向文件: system/core/vold/Volmgr.c

int volmgr_enable_ums(boolean enable)

{

    volume_t *v = vol_root;

 

    while(v) {

        if (v->ums_path) {

            int rc;

 

            if (enable) {

                pthread_mutex_lock(&v->lock);

                            if (v->state == volstate_mounted)

                    volmgr_send_eject_request(v);

                ...

 

                // Stop the volume, and enable UMS in the callback

                rc = volmgr_shutdown_volume(v, _cb_volstopped_for_ums_enable, false);

                ...

                     }

        }

  next_vol:

        v = v->next;

    }

    return 0;

}

static void _cb_volstopped_for_ums_enable(volume_t *v, void *arg)

{

    ...

 

if ((rc = ums_enable(devdir_path, v->ums_path)) < 0)

...

}

再转向文件: system/core/vold/Ums.c

int ums_enable(char *dev_fspath, char *lun_syspath)

{

    LOG_VOL("ums_enable(%s, %s):", dev_fspath, lun_syspath);

 

    int fd;

    char filename[255];

 

    sprintf(filename, "/sys/%s/file", lun_syspath);

    if ((fd = open(filename, O_WRONLY)) < 0) {

        LOGE("Unable to open '%s' (%s)", filename, strerror(errno));

        return -errno;

    }

 

    if (write(fd, dev_fspath, strlen(dev_fspath)) < 0) {

        LOGE("Unable to write to ums lunfile (%s)", strerror(errno));

        close(fd);

        return -errno;

    }

   

    close(fd);

    return 0;

}

9.8 总结

vold.conf 配置了 SDCARD USB 的系统设备路径。

volume_sdcard {

    ## This is the direct uevent device path to the SD slot on the device

    media_path     /devices/platform/msm_sdcc.2/mmc_host/mmc1

    emu_media_path /devices/platform/goldfish_mmc.0/mmc_host/mmc0

 

    media_type     mmc

    mount_point    /sdcard

    ums_path       /devices/platform/usb_mass_storage/lun0

}

vold 程序启动后会加载 SDCARD 卡到 /sdcard 目录下; media_path 的路径是 cd /sys/class/mmc_host/mmc?/ 后使用 pwd 所获得的真实路径。

当有 USB 连接时,被要求使用 MASS STORAGE 模式时,则会停止 SDCARD 作为内部,而作为 USB 存储器。

 

From : http://blog.csdn.net/skdev/archive/2010/05/11/5579201.aspx

你可能感兴趣的:(ADROID 2.1 架构解析 9 SD/USB)