前面的三篇博文《Android 2.3 SD卡挂载流程浅析(一)》、《Android
2.3 SD卡挂载流程浅析(二)》、《Android 2.3 SD卡挂载流程浅析(三)》的分析,知道了SD卡挂载的消息是如何从底层传递到上层的,在《Android
2.3 SD卡挂载流程浅析(三)》中,我们已经知道了最后是在updatePublicVolumeState()中调用onStorageStateChanged(),从而达到更新SD卡挂载信息的。在本文《Android 2.3
SD卡挂载流程浅析(四)》中,我会将前文提到的程序调用流程图画出来,并对代码进行简单的分析。
首先,还是挂出这张老图(因为每次都用这张图0_0...)。
就权当复习吧,这是SD卡的整个挂载流程,而程序的调用也是根据这个流程图来的。
1.接收并处理uevent
首先是接收因为插入SD卡被内核检测到而发出的Event;
NetlinkHandler::onEvent(NetlinkEvent *evt)
//代码路径:AndroidSourcecode2.3/system/vold/NetlinkHandler.cpp
//该方法主要通过evt->getSubsystem();方法来获取系统的event
- void NetlinkHandler::onEvent(NetlinkEvent *evt) {
- VolumeManager *vm = VolumeManager::Instance();
- const char *subsys = evt->getSubsystem();
- if (!subsys) {
- SLOGW("No subsystem found in netlink event");
- return;
- }
- if (!strcmp(subsys, "block")) {
- vm->handleBlockEvent(evt);
- } else if (!strcmp(subsys, "switch")) {
- vm->handleSwitchEvent(evt);
- } else if (!strcmp(subsys, "usb_composite")) {
- vm->handleUsbCompositeEvent(evt);
- } else if (!strcmp(subsys, "battery")) {
- } else if (!strcmp(subsys, "power_supply")) {
- }
- }
if (!subsys) {
SLOGW("No subsystem found in netlink event");
return;
}
if (!strcmp(subsys, "block")) {
vm->handleBlockEvent(evt);
} else if (!strcmp(subsys, "switch")) {
vm->handleSwitchEvent(evt);
} else if (!strcmp(subsys, "usb_composite")) {
vm->handleUsbCompositeEvent(evt);
} else if (!strcmp(subsys, "battery")) {
} else if (!strcmp(subsys, "power_supply")) {
}
} 2.对SD卡挂载事件开始处理
void VolumeManager::handleBlockEvent(NetlinkEvent *evt)
//代码路径:AndroidSourcecode2.3/system/vold/VolumeManager.cpp
//该方法的主要作用是:
//第一, 遍历mPath容器,寻找与event对应的sysfs_path是否存在与mPath容器中。
//第二, 针对Event中的action有4种处理方式:Add,Removed,Change,Noaction。
- void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
- const char *devpath = evt->findParam("DEVPATH");
- /* Lookup a volume to handle this device */
- VolumeCollection::iterator it;
- bool hit = false;
- for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
- if (!(*it)->handleBlockEvent(evt)) {
- #ifdef NETLINK_DEBUG
- SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
- #endif
- hit = true;
- break;
- }
- }
- if (!hit) {
- #ifdef NETLINK_DEBUG
- SLOGW("No volumes handled block event for '%s'", devpath);
- #endif
- }
- }
/* Lookup a volume to handle this device */
VolumeCollection::iterator it;
bool hit = false;
for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
if (!(*it)->handleBlockEvent(evt)) {
#ifdef NETLINK_DEBUG
SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
#endif
hit = true;
break;
}
}
if (!hit) {
#ifdef NETLINK_DEBUG
SLOGW("No volumes handled block event for '%s'", devpath);
#endif
}
} 3.对Block挂载事件进行处理
DirectVolume::handleBlockEvent(NetlinkEvent *evt)
//代码路径:AndroidSourcecode2.3/system/vold/DirectVolume.cpp
//在Add action中首先会创建设备节点,然后对disk和partion两种格式的设备分别进行处理。这里是disk格式。
- int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {
- const char *dp = evt->findParam("DEVPATH");
- PathCollection::iterator it;
- for (it = mPaths->begin(); it != mPaths->end(); ++it) {
- if (!strncmp(dp, *it, strlen(*it))) {
- /* We can handle this disk */
- int action = evt->getAction();
- const char *devtype = evt->findParam("DEVTYPE");
- if (action == NetlinkEvent::NlActionAdd) {
- int major = atoi(evt->findParam("MAJOR"));
- int minor = atoi(evt->findParam("MINOR"));
- char nodepath[255];
- snprintf(nodepath,
- sizeof(nodepath), "/dev/block/vold/%d:%d",
- major, minor);
- if (createDeviceNode(nodepath, major, minor)) {
- SLOGE("Error making device node '%s' (%s)", nodepath,
- strerror(errno));
- }
- if (!strcmp(devtype, "disk")) {
- <span style="color:#ff0000;">handleDiskAdded(dp, evt);<span style="color:#33cc00;">//SD卡插入是Add事件</span></span>
- } else {
- handlePartitionAdded(dp, evt);
- }
- } else if (action == NetlinkEvent::NlActionRemove) {
- if (!strcmp(devtype, "disk")) {
- handleDiskRemoved(dp, evt);
- } else {
- handlePartitionRemoved(dp, evt);
- }
- } else if (action == NetlinkEvent::NlActionChange) {
- if (!strcmp(devtype, "disk")) {
- handleDiskChanged(dp, evt);
- } else {
- handlePartitionChanged(dp, evt);
- }
- } else {
- SLOGW("Ignoring non add/remove/change event");
- }
- return 0;
- }
- }
- errno = ENODEV;
- return -1;
- }
PathCollection::iterator it;
for (it = mPaths->begin(); it != mPaths->end(); ++it) {
if (!strncmp(dp, *it, strlen(*it))) {
/* We can handle this disk */
int action = evt->getAction();
const char *devtype = evt->findParam("DEVTYPE");
if (action == NetlinkEvent::NlActionAdd) {
int major = atoi(evt->findParam("MAJOR"));
int minor = atoi(evt->findParam("MINOR"));
char nodepath[255];
snprintf(nodepath,
sizeof(nodepath), "/dev/block/vold/%d:%d",
major, minor);
if (createDeviceNode(nodepath, major, minor)) {
SLOGE("Error making device node '%s' (%s)",
nodepath,
strerror(errno));
}
if (!strcmp(devtype, "disk")) {
<span
style="color:#ff0000;">handleDiskAdded(dp, evt);<span
style="color:#33cc00;">//SD卡插入是Add事件</span></span>
} else {
handlePartitionAdded(dp, evt);
}
} else if (action == NetlinkEvent::NlActionRemove) {
if (!strcmp(devtype, "disk")) {
handleDiskRemoved(dp, evt);
} else {
handlePartitionRemoved(dp, evt);
}
} else if (action == NetlinkEvent::NlActionChange) {
if (!strcmp(devtype, "disk")) {
handleDiskChanged(dp, evt);
} else {
handlePartitionChanged(dp, evt);
}
} else {
SLOGW("Ignoring non add/remove/change event");
}
return 0;
}
}
errno = ENODEV;
return -1;
} 4.处理DiskAdd事件
DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt)
//代码路径:AndroidSourcecode2.3/system/vold/DirectVolume.cpp
//在该方法中广播disk
insert的广播消息(这里的广播不同于Java中的广播,这里实际上是Socket)。
- void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) {
- mDiskMajor = atoi(evt->findParam("MAJOR"));
- mDiskMinor = atoi(evt->findParam("MINOR"));
- const char *tmp = evt->findParam("NPARTS");
- if (tmp) {
- mDiskNumParts = atoi(tmp);
- } else {
- SLOGW("Kernel block uevent missing 'NPARTS'");
- mDiskNumParts = 1;
- }
- char msg[255];
- int partmask = 0;
- int i;
- for (i = 1; i <= mDiskNumParts; i++) {
- partmask |= (1 << i);
- }
- mPendingPartMap = partmask;
- if (mDiskNumParts == 0) {
- #ifdef PARTITION_DEBUG
- SLOGD("Dv::diskIns - No partitions - good to go son!");
- #endif
- setState(Volume::State_Idle);
- } else {
- #ifdef PARTITION_DEBUG
- SLOGD("Dv::diskIns - waiting for %d partitions (mask 0x%x)",
- mDiskNumParts, mPendingPartMap);
- #endif
- setState(Volume::State_Pending);
- }
- snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)",
- getLabel(), getMountpoint(), mDiskMajor, mDiskMinor);
- <span style="color:#ff0000;">mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,
- msg, false);
- </span>}
const char *tmp = evt->findParam("NPARTS");
if (tmp) {
mDiskNumParts = atoi(tmp);
} else {
SLOGW("Kernel block uevent missing 'NPARTS'");
mDiskNumParts = 1;
}
char msg[255];
int partmask = 0;
int i;
for (i = 1; i <= mDiskNumParts; i++) {
partmask |= (1 << i);
}
mPendingPartMap = partmask;
if (mDiskNumParts == 0) {
#ifdef PARTITION_DEBUG
SLOGD("Dv::diskIns - No partitions - good to go son!");
#endif
setState(Volume::State_Idle);
} else {
#ifdef PARTITION_DEBUG
SLOGD("Dv::diskIns - waiting for %d partitions (mask 0x%x)",
mDiskNumParts, mPendingPartMap);
#endif
setState(Volume::State_Pending);
}
snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)",
getLabel(), getMountpoint(), mDiskMajor, mDiskMinor);
<span style="color:#ff0000;">mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,
msg, false);
</span>} 5.处理广播消息
SocketListener::runListener()
//代码路径:AndroidSourcecode2.3/system/core/libsysutils/src/SocketListener.cpp
//完成对Socket的监听以及对数据的处理onDataAvailable(*
it );
- 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);
- 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))
- 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) {
- 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 (!<span style="color:#ff0000;">onDataAvailable(*it)</span>) {
- 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);
- }
- }
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);
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))
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) {
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 (!<span style="color:#ff0000;">onDataAvailable(*it)</span>) {
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);
}
} 6.处理消息内容
FrameworkListener::onDataAvailable(SocketClient *c)
//代码路径:AndroidSourcecode2.3/system/core/libsysutils/src/FrameworkListener.cpp
//对接收到的广播消息进行处理
- bool FrameworkListener::onDataAvailable(SocketClient *c) {
- char buffer[255];
- int len;
- if ((len = read(c->getSocket(), buffer, sizeof(buffer) -1)) < 0) {
- SLOGE("read() failed (%s)", strerror(errno));
- return false;
- } else if (!len)
- return false;
- int offset = 0;
- int i;
- for (i = 0; i < len; i++) {
- if (buffer[i] == '\0') {
- <span style="color:#ff0000;">dispatchCommand</span>(c, buffer + offset);
- offset = i + 1;
- }
- }
- return true;
- }
if ((len = read(c->getSocket(), buffer, sizeof(buffer) -1)) < 0) {
SLOGE("read() failed (%s)", strerror(errno));
return false;
} else if (!len)
return false;
int offset = 0;
int i;
for (i = 0; i < len; i++) {
if (buffer[i] == '\0') {
<span style="color:#ff0000;">dispatchCommand</span>(c, buffer + offset);
offset = i + 1;
}
}
return true;
} 7.分发指令
FrameworkListener::dispatchCommand(SocketClient *cli, char *data)
//代码路径:AndroidSourcecode2.3/system/core/libsysutils/src/FrameworkListener.cpp
//分配指令:DumpCmd、VolumeCmd、AsecCmd、ShareCmd、StorageCmd、XwarpCmd
- void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
- FrameworkCommandCollection::iterator i;
- int argc = 0;
- char *argv[FrameworkListener::CMD_ARGS_MAX];
- char tmp[255];
- char *p = data;
- char *q = tmp;
- bool esc = false;
- bool quote = false;
- int k;
- memset(argv, 0, sizeof(argv));
- memset(tmp, 0, sizeof(tmp));
- while(*p) {
- if (*p == '\\') {
- if (esc) {
- *q++ = '\\';
- esc = false;
- } else
- esc = true;
- p++;
- continue;
- } else if (esc) {
- if (*p == '"')
- *q++ = '"';
- else if (*p == '\\')
- *q++ = '\\';
- else {
- cli->sendMsg(500, "Unsupported escape sequence", false);
- goto out;
- }
- p++;
- esc = false;
- continue;
- }
- if (*p == '"') {
- if (quote)
- quote = false;
- else
- quote = true;
- p++;
- continue;
- }
- *q = *p++;
- if (!quote && *q == ' ') {
- *q = '\0';
- argv[argc++] = strdup(tmp);
- memset(tmp, 0, sizeof(tmp));
- q = tmp;
- continue;
- }
- q++;
- }
- argv[argc++] = strdup(tmp);
- #if 0
- for (k = 0; k < argc; k++) {
- SLOGD("arg[%d] = '%s'", k, argv[k]);
- }
- #endif
- if (quote) {
- cli->sendMsg(500, "Unclosed quotes error", false);
- goto out;
- }
- for (i = mCommands->begin(); i != mCommands->end(); ++i) {
- FrameworkCommand *c = *i;
- if (!strcmp(argv[0], c->getCommand())) {
- if (c-><span style="color:#ff0000;">runCommand</span>(cli, argc, argv)) {
- SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
- }
- goto out;
- }
- }
- cli->sendMsg(500, "Command not recognized", false);
- out:
- int j;
- for (j = 0; j < argc; j++)
- free(argv[j]);
- return;
- }
memset(argv, 0, sizeof(argv));
memset(tmp, 0, sizeof(tmp));
while(*p) {
if (*p == '\\') {
if (esc) {
*q++ = '\\';
esc = false;
} else
esc = true;
p++;
continue;
} else if (esc) {
if (*p == '"')
*q++ = '"';
else if (*p == '\\')
*q++ = '\\';
else {
cli->sendMsg(500, "Unsupported escape sequence", false);
goto out;
}
p++;
esc = false;
continue;
}
if (*p == '"') {
if (quote)
quote = false;
else
quote = true;
p++;
continue;
}
*q = *p++;
if (!quote && *q == ' ') {
*q = '\0';
argv[argc++] = strdup(tmp);
memset(tmp, 0, sizeof(tmp));
q = tmp;
continue;
}
q++;
}
argv[argc++] = strdup(tmp);
#if 0
for (k = 0; k < argc; k++) {
SLOGD("arg[%d] = '%s'", k, argv[k]);
}
#endif
if (quote) {
cli->sendMsg(500, "Unclosed quotes error", false);
goto out;
}
for (i = mCommands->begin(); i != mCommands->end(); ++i) {
FrameworkCommand *c = *i;
if (!strcmp(argv[0], c->getCommand())) {
if (c-><span style="color:#ff0000;">runCommand</span>(cli, argc, argv)) {
SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
}
goto out;
}
}
cli->sendMsg(500, "Command not recognized", false);
out:
int j;
for (j = 0; j < argc; j++)
free(argv[j]);
return;
} 8.开始执行挂载
CommandListener::VolumeCmd::runCommand(SocketClient *cli,int argc, char **argv)
//代码路径:AndroidSourcecode2.3/system/vold/CommandListener.cpp
//rc
= vm->mountVolume(argv[2]);
- int CommandListener::VolumeCmd::runCommand(SocketClient *cli,int argc, char **argv) {
- dumpArgs(argc, argv, -1);
- if (argc < 2) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
- return 0;
- }
- VolumeManager *vm = VolumeManager::Instance();
- int rc = 0;
- if (!strcmp(argv[1], "list")) {
- return vm->listVolumes(cli);
- } else if (!strcmp(argv[1], "debug")) {
- if (argc != 3 || (argc == 3 && (strcmp(argv[2], "off") && strcmp(argv[2], "on")))) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume debug <off/on>", false);
- return 0;
- }
- vm->setDebug(!strcmp(argv[2], "on") ? true : false);
- } else if (!strcmp(argv[1], "mount")) {
- if (argc != 3) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false);
- return 0;
- }
- <span style="color:#ff0000;">rc = vm->mountVolume(argv[2]);</span>
- } else if (!strcmp(argv[1],