转自: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);
};
这里创建了VolumeManager和NetlinkManager两个实例,VolumeManager主要负责Voluem的一些管理,NetlinkManager主要负责管理与内核之间的通信
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);
}
设置了Broadcaster,后面给FrameWork层发送消息就跟它有关了,
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;
}
解析了vold.fstab之后 ,就开始启动NetlinkManager,
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;
}
我们跟进mHandler->start()最终调用 SocketListener::startListener()
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;
}
}
这里mSocketName 为"vold",mSock = -1,所以会调用android_get_control_socket,我们看下这个函数
/*
* 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;
}
这里面通过组合成一个环境变量名,然后获取对应的值,那么这个值是什么时候设置的呢,我们看下系统初始化的时候调用的service_start
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);
}
}
}
跟进publish_socket
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