本来自己转载的两篇vold的文章已经分析的很详细了,有图有文字,但还是想把自己分析的见解写下来,毕竟自己的思路才是最清晰的,所以写了笔记供以后参考。
先把整体路程图画出来,再参考分析:
从vold的main函数说起:
nm->setBroadcaster((SocketListener *) cl) -> void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }简单赋值,后续再分析该过程。
接着main中nm->start()的调用过程:
NetlinkManager::start() -> mHandler = new NetlinkHandler(mSock); mHandler->start() -> 37 int NetlinkHandler::start() { 38 return this->startListener(); 39 } NetlinkHandler类: class NetlinkHandler: public NetlinkListener { public: NetlinkHandler(int listenerSocket); virtual ~NetlinkHandler(); int start(void); int stop(void); protected: virtual void onEvent(NetlinkEvent *evt); };
int 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; } SLOGV("got mSock = %d for %s", mSock, mSocketName); } 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, false, mUseCmdNum)); 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; }
void SocketListener::runListener() { while(1) { ................... if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) { ..................... if (!onDataAvailable(c) && mListen) { ......................... }
bool NetlinkListener::onDataAvailable(SocketClient *cli) { int socket = cli->getSocket(); ssize_t count; uid_t uid = -1; count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv( socket, mBuffer, sizeof(mBuffer), &uid)); if (count < 0) { if (uid > 0) LOG_EVENT_INT(65537, uid); SLOGE("recvmsg failed (%s)", strerror(errno)); return false; } NetlinkEvent *evt = new NetlinkEvent(); if (!evt->decode(mBuffer, count, mFormat)) { SLOGE("Error decoding NetlinkEvent"); } else { onEvent(evt); } delete evt; return true; }
E/NetlinkEvent( 1282): sclu add@/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa E/NetlinkEvent( 1281): sclu add@/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa E/NetlinkEvent( 1281): sclu ACTION=add E/NetlinkEvent( 1281): sclu DEVPATH=/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa E/NetlinkEvent( 1281): sclu SUBSYSTEM=mmc E/NetlinkEvent( 1281): sclu MMC_TYPE=SD E/NetlinkEvent( 1281): sclu MMC_NAME=SU08G E/NetlinkEvent( 1281): sclu MODALIAS=mmc:block E/NetlinkEvent( 1281): sclu SEQNUM=1244 E/NetlinkEvent( 1282): sclu ACTION=add E/NetlinkEvent( 1282): sclu DEVPATH=/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa E/NetlinkEvent( 1282): sclu SUBSYSTEM=mmc E/NetlinkEvent( 1282): sclu MMC_TYPE=SD E/NetlinkEvent( 1282): sclu MMC_NAME=SU08G E/NetlinkEvent( 1282): sclu MODALIAS=mmc:block E/NetlinkEvent( 1282): sclu SEQNUM=1244 E/NetlinkEvent( 1282): sclu add@/devices/virtual/bdi/179:0 E/NetlinkEvent( 1282): sclu ACTION=add E/NetlinkEvent( 1281): sclu add@/devices/virtual/bdi/179:0 E/NetlinkEvent( 1282): sclu DEVPATH=/devices/virtual/bdi/179:0 E/NetlinkEvent( 1281): sclu ACTION=add E/NetlinkEvent( 1282): sclu SUBSYSTEM=bdi E/NetlinkEvent( 1281): sclu DEVPATH=/devices/virtual/bdi/179:0 E/NetlinkEvent( 1282): sclu SEQNUM=1245 E/NetlinkEvent( 1281): sclu SUBSYSTEM=bdi E/NetlinkEvent( 1281): sclu SEQNUM=1245 E/NetlinkEvent( 1282): sclu add@/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa/block/mmcblk0 E/NetlinkEvent( 1282): sclu ACTION=add E/NetlinkEvent( 1282): sclu DEVPATH=/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa/block/mmcblk0 E/NetlinkEvent( 1282): sclu SUBSYSTEM=block E/NetlinkEvent( 1282): sclu MAJOR=179 E/NetlinkEvent( 1282): sclu MINOR=0 E/NetlinkEvent( 1282): sclu DEVNAME=mmcblk0 E/NetlinkEvent( 1282): sclu DEVTYPE=disk E/NetlinkEvent( 1282): sclu NPARTS=1 E/NetlinkEvent( 1282): sclu SEQNUM=1246 E/NetlinkEvent( 1281): sclu add@/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa/block/mmcblk0 E/NetlinkEvent( 1281): sclu ACTION=add E/NetlinkEvent( 1281): sclu DEVPATH=/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa/block/mmcblk0 E/NetlinkEvent( 1281): sclu SUBSYSTEM=block E/NetlinkEvent( 1281): sclu MAJOR=179 E/NetlinkEvent( 1281): sclu MINOR=0 E/NetlinkEvent( 1281): sclu DEVNAME=mmcblk0 E/NetlinkEvent( 1282): sclu add@/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa/block/mmcblk0/mmcblk0p1 E/NetlinkEvent( 1281): sclu DEVTYPE=disk E/NetlinkEvent( 1281): sclu NPARTS=1 E/NetlinkEvent( 1281): sclu SEQNUM=1246 D/Vold ( 1281): Volume SDCARD state changing 0 (No-Media) -> 2 (Pending) E/NetlinkEvent( 1282): sclu ACTION=add E/NetlinkEvent( 1282): sclu DEVPATH=/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa/block/mmcblk0/mmcblk0p1 E/NetlinkEvent( 1282): sclu SUBSYSTEM=block E/NetlinkEvent( 1282): sclu MAJOR=179 E/NetlinkEvent( 1282): sclu MINOR=1 E/NetlinkEvent( 1282): sclu DEVNAME=mmcblk0p1 E/NetlinkEvent( 1282): sclu DEVTYPE=partition E/NetlinkEvent( 1282): sclu PARTN=1 E/NetlinkEvent( 1282): sclu SEQNUM=1247 E/NetlinkEvent( 1281): sclu add@/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa/block/mmcblk0/mmcblk0p1 E/NetlinkEvent( 1281): sclu ACTION=add E/NetlinkEvent( 1281): sclu DEVPATH=/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa/block/mmcblk0/mmcblk0p1 E/NetlinkEvent( 1281): sclu SUBSYSTEM=block E/NetlinkEvent( 1281): sclu MAJOR=179 E/NetlinkEvent( 1281): sclu MINOR=1 E/NetlinkEvent( 1281): sclu DEVNAME=mmcblk0p1 E/NetlinkEvent( 1281): sclu DEVTYPE=partition E/NetlinkEvent( 1281): sclu PARTN=1 E/NetlinkEvent( 1281): sclu SEQNUM=1247
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); } }
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 } }
int VolumeManager::addVolume(Volume *v) { mVolumes->push_back(v); return 0; }
int DirectVolume::handleBlockEvent(NetlinkEvent *evt) { const char *dp = evt->findParam("DEVPATH"); PathCollection::iterator it; char *usbneedle = strstr(dp,"usb"); if( (evt->getAction() != NetlinkEvent::NlActionRemove) && !strncmp(getMountpoint(),"/mnt/udisk",10) && (getState() == Volume::State_NoMedia || getState() == Volume::State_Idle) && usbneedle != 0) { it = mPaths->begin(); while(it != mPaths->end()) { if (strncmp(dp, *it, strlen(*it))) { free(*it); it = mPaths->erase(it); } else { break; //++it; } } if(mPaths->size() < 1) { SLOGE("mPaths donot have the path,so add it\n"); addPath(dp); } } 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")) { handleDiskAdded(dp, evt); } 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; }
void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) { mDiskMajor = atoi(evt->findParam("MAJOR")); mDiskMinor = atoi(evt->findParam("MINOR")); const char *tmp = evt->findParam("NPARTS"); ....................... setState(Volume::State_Pending); } snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)", getLabel(), getMountpoint(), mDiskMajor, mDiskMinor); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted, msg, false); }
void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) { pthread_mutex_lock(&mClientsLock); SocketClientCollection::iterator i; for (i = mClients->begin(); i != mClients->end(); ++i) { // broadcasts are unsolicited and should not include a cmd number if ((*i)->sendMsg(code, msg, addErrno, false)) { SLOGW("Error sending broadcast (%s)", strerror(errno)); } } pthread_mutex_unlock(&mClientsLock); }
public boolean onEvent(int code, String raw, String[] cooked) { ...................... if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { .................. }
cl = new CommandListener(); cl->startListener();
CommandListener::CommandListener() : FrameworkListener("vold", true) { registerCmd(new DumpCmd()); registerCmd(new VolumeCmd()); registerCmd(new AsecCmd()); registerCmd(new ObbCmd()); registerCmd(new StorageCmd()); registerCmd(new XwarpCmd()); registerCmd(new CryptfsCmd()); }
bool FrameworkListener::onDataAvailable(SocketClient *c) { char buffer[255]; int len; len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer))); if (len < 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') { /* IMPORTANT: dispatchCommand() expects a zero-terminated string */ dispatchCommand(c, buffer + offset); offset = i + 1; } } return true; }
void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) { FrameworkCommandCollection::iterator i; ..................... for (i = mCommands->begin(); i != mCommands->end(); ++i) { FrameworkCommand *c = *i; if (!strcmp(argv[0], c->getCommand())) { if (c->runCommand(cli, argc, argv)) { SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno)); } goto out; } } ........................ }
遍历了mCommands容器,mCommands就是前面CommandListener中registerCmd注册进来的,根据名字调用各自的runCommand方法,在这个情景中:
registerCmd(new VolumeCmd()) -> CommandListener::VolumeCmd::VolumeCmd() :VoldCommand("volume") {}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(); ........................ } else if (!strcmp(argv[1], "mount")) { if (argc != 3) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false); return 0; } rc = vm->mountVolume(argv[2]); } else if (!strcmp(argv[1], "unmount")) { ..................... }
int VolumeManager::mountVolume(const char *label) { Volume *v = lookupVolume(label); if (!v) { errno = ENOENT; return -1; } return v->mountVol(); }