你好,游客 登录 注册 搜索
背景:
阅读新闻

Android 2.1 架构解析

[日期:2014-03-16] 来源:Linux社区  作者:skdev [字体: ]

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_typemmc

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_tmedia_type;

char*mount_point;

char*ums_path;

struct devmapping *dm;

 

pthread_mutex_tlock;

volume_state_tstate;

blkdev_t*dev;

pid_tworker_pid;

pthread_tworker_thread;

union {

struct volmgr_start_argsstart_args;

struct volmgr_reaper_args reaper_args;

} worker_args;

booleanworker_running;

pthread_mutex_tworker_sem;

 

struct volmgr_fstable_entry *fs;

 

struct volume*next;

} volume_t;

也就是说用media_pathsmedia_typemedia_typemount_pointums_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/:

ueventdevsubsystemdevicerangeext_rangeremovablerosizecapability

statpowerholdersslavesmmcblk0p1queuebdi

 

上面代码实现的功能是:扫描/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是一个链接路径,所以需要用ChdirGetcwd来获取它的真实路径。以例子路径来说,获得的真实路径是:

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

所以DEVPATH = /devices/platform/pxa2xx-mci.0/mmc_host/mmc0/mmc0:e624,而这个也就是在配置文件vold.confmedia_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,DEVTYPEMAJORMINOR,然后将这四个参数作为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_rootmedia_pathvol_rootmedia_path行比较,确定是否一致。

 

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

int volmgr_consider_disk(blkdev_t *dev)

{

volume_t *vol;

 

if (!(vol = volmgr_lookup_volume_by_mediapath(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_rootmedia_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 配置了SDCARDUSB的系统设备路径。

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_typemmc

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存储器。

linux
相关资讯       Android 2.1 
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数

       

评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款