转自:http://blog.csdn.net/new_abc/article/details/7396733
流程图:
vold启动在init.rc中:
service vold /system/bin/vold socket vold stream 0660 root mount ioprio be 2注意这里创建了一个socket,用于vold和FrameWork层通信
vold代码在system/vold目录下面,函数入口main函数:
int main() { VolumeManager *vm; CommandListener *cl; NetlinkManager *nm; SLOGI("Vold 2.1 (the revenge) firing up"); mkdir("/dev/block/vold", 0755);这里建立了一个/dev/block/vold目录用于放置后面建立的vold节点
/* Create our singleton managers */ if (!(vm = VolumeManager::Instance())) { SLOGE("Unable to create VolumeManager"); exit(1); }; if (!(nm = NetlinkManager::Instance())) { SLOGE("Unable to create NetlinkManager"); exit(1); };
cl = new CommandListener();这里首先创建了CommandListener,CommandListener主要负责与FrameWork层的通信,处理从FrameWork层收到的各种命令,我们先看看他的构造函数:
CommandListener::CommandListener() : FrameworkListener("vold") { registerCmd(new DumpCmd()); registerCmd(new VolumeCmd()); registerCmd(new AsecCmd()); registerCmd(new ObbCmd()); registerCmd(new ShareCmd()); registerCmd(new StorageCmd()); registerCmd(new XwarpCmd()); }这里注册了各种命令,注意 FrameworkListener("vold"),FrameworkListener又继承了SocketListener,最终"vold"传到了SocketListener里面。
vm->setBroadcaster((SocketListener *) cl); nm->setBroadcaster((SocketListener *) cl);
if (vm->start()) { SLOGE("Unable to start VolumeManager (%s)", strerror(errno)); exit(1); }
if (process_config(vm)) { SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno)); }解析vold.fstab,我们看下process_config函数:
static int process_config(VolumeManager *vm){ FILE *fp; int n = 0; char line[255]; if (!(fp = fopen("/etc/vold.fstab", "r"))) { return -1; } while(fgets(line, sizeof(line), fp)) { char *next = line; char *type, *label, *mount_point; n++; line[strlen(line)-1] = '\0'; if (line[0] == '#' || line[0] == '\0') continue; if (!(type = strsep(&next, " \t"))) { SLOGE("Error parsing type"); goto out_syntax; } if (!(label = strsep(&next, " \t"))) { //标签 SLOGE("Error parsing label"); goto out_syntax; } if (!(mount_point = strsep(&next, " \t"))) { //挂载点 SLOGE("Error parsing mount point"); goto out_syntax; } if (!strcmp(type, "dev_mount")) { //挂载命令 DirectVolume *dv = NULL; char *part, *sysfs_path; if (!(part = strsep(&next, " \t"))) { //分区数 SLOGE("Error parsing partition"); goto out_syntax; } if (strcmp(part, "auto") && atoi(part) == 0) { //auto则表示只有1个子分区 SLOGE("Partition must either be 'auto' or 1 based index instead of '%s'", part); goto out_syntax; } if (!strcmp(part, "auto")) { dv = new DirectVolume(vm, label, mount_point, -1); } else { dv = new DirectVolume(vm, label, mount_point, atoi(part)); } while((sysfs_path = strsep(&next, " \t"))) { if (dv->addPath(sysfs_path)) { //这里的Path在挂载的时候会用到 SLOGE("Failed to add devpath %s to volume %s", sysfs_path, label); goto out_fail; } } vm->addVolume(dv); //添加到VolumeManager,由它负责统一管理 } else if (!strcmp(type, "map_mount")) { } else { SLOGE("Unknown type '%s'", type); goto out_syntax; } } fclose(fp); return 0; out_syntax: SLOGE("Syntax error on config line %d", n); errno = -EINVAL; out_fail: fclose(fp); return -1; }
if (nm->start()) { SLOGE("Unable to start NetlinkManager (%s)", strerror(errno)); exit(1); }我们跟进去看看:
int NetlinkManager::start() { struct sockaddr_nl nladdr; int sz = 64 * 1024; int on = 1; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nladdr.nl_pid = getpid(); nladdr.nl_groups = 0xffffffff; if ((mSock = socket(PF_NETLINK, SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) { //注册UEVENT事件,用于接收内核消息 SLOGE("Unable to create uevent socket: %s", strerror(errno)); return -1; } if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) { SLOGE("Unable to set uevent socket options: %s", strerror(errno)); return -1; } if (setsockopt(mSock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { LOGE("Unable to set SO_REUSEADDR options: %s", strerror(errno)); return -1; } if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) { SLOGE("Unable to bind uevent socket: %s", strerror(errno)); return -1; } mHandler = new NetlinkHandler(mSock); //NetlinkHandler用于对接收到的内核消息进行处理 if (mHandler->start()) { //开始监听内核消息 SLOGE("Unable to start NetlinkHandler: %s", strerror(errno)); return -1; } return 0; }
int SocketListener::startListener() { if (!mSocketName && mSock == -1) { //这里mSock 刚赋值了 SLOGE("Failed to start unbound listener"); errno = EINVAL; return -1; } else if (mSocketName) { if ((mSock = android_get_control_socket(mSocketName)) < 0) { SLOGE("Obtaining file descriptor socket '%s' failed: %s", mSocketName, strerror(errno)); return -1; } } if (mListen && listen(mSock, 4) < 0) { SLOGE("Unable to listen on socket (%s)", strerror(errno)); return -1; } else if (!mListen) mClients->push_back(new SocketClient(mSock)); if (pipe(mCtrlPipe)) { //建立管道,用于后面的关闭监听循环 SLOGE("pipe failed (%s)", strerror(errno)); return -1; } if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) { SLOGE("pthread_create (%s)", strerror(errno)); return -1; } return 0; }我们再看下threadStart,最终调用runListener
void SocketListener::runListener() { while(1) { SocketClientCollection::iterator it; fd_set read_fds; int rc = 0; int max = 0; FD_ZERO(&read_fds); if (mListen) { max = mSock; FD_SET(mSock, &read_fds); } FD_SET(mCtrlPipe[0], &read_fds); //把mCtrlPipe[0]也加入监听中 if (mCtrlPipe[0] > max) max = mCtrlPipe[0]; pthread_mutex_lock(&mClientsLock); for (it = mClients->begin(); it != mClients->end(); ++it) { FD_SET((*it)->getSocket(), &read_fds); if ((*it)->getSocket() > max) max = (*it)->getSocket(); } pthread_mutex_unlock(&mClientsLock); if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) { //阻塞直到有数据到来 SLOGE("select failed (%s)", strerror(errno)); sleep(1); continue; } else if (!rc) continue; if (FD_ISSET(mCtrlPipe[0], &read_fds)) //mCtrlPipe[0]有数据,则结循环,注意是在stopListener的时候 往mCtrlPipe[1]写数据 break; if (mListen && FD_ISSET(mSock, &read_fds)) { struct sockaddr addr; socklen_t alen = sizeof(addr); int c; if ((c = accept(mSock, &addr, &alen)) < 0) { //有新的连接来了,主要是FrameWork层的, SLOGE("accept failed (%s)", strerror(errno)); sleep(1); continue; } pthread_mutex_lock(&mClientsLock); mClients->push_back(new SocketClient(c)); //加到监听的列表 pthread_mutex_unlock(&mClientsLock); } do { pthread_mutex_lock(&mClientsLock); for (it = mClients->begin(); it != mClients->end(); ++it) { int fd = (*it)->getSocket(); if (FD_ISSET(fd, &read_fds)) { pthread_mutex_unlock(&mClientsLock); if (!onDataAvailable(*it)) { //处理消息 close(fd); pthread_mutex_lock(&mClientsLock); delete *it; it = mClients->erase(it); pthread_mutex_unlock(&mClientsLock); } FD_CLR(fd, &read_fds); pthread_mutex_lock(&mClientsLock); continue; } } pthread_mutex_unlock(&mClientsLock); } while (0); } }
coldboot("/sys/block"); // coldboot("/sys/class/switch"); /* * Now that we're up, we can respond to commands */ if (cl->startListener()) { SLOGE("Unable to start CommandListener (%s)", strerror(errno)); exit(1); }这里主要看cl->startListener,也跟前面 的一样,调用SocketListener::startListener(),注意这时
if (!mSocketName && mSock == -1) { SLOGE("Failed to start unbound listener"); errno = EINVAL; return -1; } else if (mSocketName) { if ((mSock = android_get_control_socket(mSocketName)) < 0) { SLOGE("Obtaining file descriptor socket '%s' failed: %s", mSocketName, strerror(errno)); return -1; } }
/* * android_get_control_socket - simple helper function to get the file * descriptor of our init-managed Unix domain socket. `name' is the name of the * socket, as given in init.rc. Returns -1 on error. * * This is inline and not in libcutils proper because we want to use this in * third-party daemons with minimal modification. */ static inline int android_get_control_socket(const char *name) { char key[64] = ANDROID_SOCKET_ENV_PREFIX; const char *val; int fd; /* build our environment variable, counting cycles like a wolf ... */ #if HAVE_STRLCPY strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, name, sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX)); #else /* for the host, which may lack the almightly strncpy ... */ strncpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, name, sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX)); key[sizeof(key)-1] = '\0'; #endif val = getenv(key); if (!val) return -1; errno = 0; fd = strtol(val, NULL, 10); if (errno) return -1; return fd; }
void service_start(struct service *svc, const char *dynamic_args) { ... for (si = svc->sockets; si; si = si->next) { int socket_type = ( !strcmp(si->type, "stream") ? SOCK_STREAM : (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET)); int s = create_socket(si->name, socket_type, si->perm, si->uid, si->gid); if (s >= 0) { publish_socket(si->name, s); } } }
static void publish_socket(const char *name, int fd) { char key[64] = ANDROID_SOCKET_ENV_PREFIX; char val[64]; strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, name, sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX)); snprintf(val, sizeof(val), "%d", fd); add_environment(key, val); /* make sure we don't close-on-exec */ fcntl(fd, F_SETFD, 0); }
Ok,到这里,vold基本就启动起来了,基本的通信环境也已经搭建好了,就等着u盘插入后kernel的消息的。。。。
以下博客写的比较详细,专业。
http://blog.csdn.net/gzshun/article/details/7172389
http://blog.csdn.net/gjsisi/article/details/7836446
http://www.rosoo.net/a/201209/16285.html