深入分析vold、MountService(and5.1)
来源:互联网 发布:淘宝lolita代购 编辑:程序博客网 时间:2024/05/20 11:37
Vold:Volume Daemon,管理和控制Android平台外部存储设备的后台进程,包括SD卡的插拔时间检测、SD卡挂载、卸载、格式化等等。
MountService和Vold交互,比如会发送一些广播,是接受到了vold的信息之后采取的动作。另外也会向vold发送挂载SD卡等命令。
Vold中的NetlinkManager模块(NM)接受来自linux内核的uevent消息。例如SD卡插拔等动作会引起Kernel向NM发送uevent消息。
NM将这些消息转发给VolumManager模块(VM)。VM会对应做一些操作,然后把相关信息通过CommandListener(CL)发送给MountService,MountService根据收到的消息会发送相关的处理命令给VM做进一步的处理。例如:SD卡插入后,VM会将来自NM的“Disk Insert”消息发送给MountService,而后MountService则发送“Mount”给Vold,指示它挂载这个SD卡。
CL模块内部封装了一个socket用于跨进程通信。它在vold进程中属于监听端,而连接端是MountService。它一方面接受来自MountService的控制命令(例如卸载存储卡、格式化存储卡),另一方面VM和NM模块又会通过它将一些信息发送给MountService。
下面我们开始分析Vold代码:
先从main函数:
int main() { VolumeManager *vm; CommandListener *cl; NetlinkManager *nm; mkdir("/dev/block/vold", 0755); klog_set_level(6); if (!(vm = VolumeManager::Instance())) {//创建VolumeManager SLOGE("Unable to create VolumeManager"); exit(1); }; if (!(nm = NetlinkManager::Instance())) {//创建NetlinkManager SLOGE("Unable to create NetlinkManager"); exit(1); }; cl = new CommandListener(); vm->setBroadcaster((SocketListener *) cl);//设置Broadcaster用来vold向MountService通信 nm->setBroadcaster((SocketListener *) cl); if (vm->start()) { SLOGE("Unable to start VolumeManager (%s)", strerror(errno)); exit(1); } if (process_config(vm)) {//根据文件配置VM对象,后面详细介绍 SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno)); } if (nm->start()) { SLOGE("Unable to start NetlinkManager (%s)", strerror(errno)); exit(1); } coldboot("/sys/block");//通过往/sys/block目录下对应的uevent文件写入“add\n"来触发内核发送Uevent消息,通过这种方式得到这些设备的当前信息。// 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); } // Eventually we'll become the monitoring thread while(1) {//无限循环 sleep(1000); } SLOGI("Vold exiting"); exit(0);}
接下来我们看下NetlinkManager模块:
NetlinkManager *NetlinkManager::Instance() { if (!sInstance) sInstance = new NetlinkManager(); return sInstance;}NetlinkManager::NetlinkManager() { mBroadcaster = NULL;}int NetlinkManager::start() { struct sockaddr_nl nladdr; int sz = 64 * 1024; int on = 1; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK;//用来接受内核的netlink消息 nladdr.nl_pid = getpid(); nladdr.nl_groups = 0xffffffff; if ((mSock = socket(PF_NETLINK, SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) { 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 SO_RCVBUFFORCE option: %s", strerror(errno)); goto out; } if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) { SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno)); goto out; } if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) { SLOGE("Unable to bind uevent socket: %s", strerror(errno)); goto out; } mHandler = new NetlinkHandler(mSock); if (mHandler->start()) {//主要看下NetlinkHandler SLOGE("Unable to start NetlinkHandler: %s", strerror(errno)); goto out; } return 0;out: close(mSock); return -1;}
而接下来我们看下NetlinkHandler
NetlinkHandler::NetlinkHandler(int listenerSocket) : NetlinkListener(listenerSocket) {}NetlinkHandler::~NetlinkHandler() {}int NetlinkHandler::start() { return this->startListener();}int NetlinkHandler::stop() { return this->stopListener();}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); }}
NetlinkHandler中的start调用了startListener函数,而NetlinkHandler继承了NetlinkListener类,因此看下NetlinkListener有没有startListener函数:
NetlinkListener::NetlinkListener(int socket) : SocketListener(socket, false) { mFormat = NETLINK_FORMAT_ASCII;}#endifNetlinkListener::NetlinkListener(int socket, int format) : SocketListener(socket, false), mFormat(format) {}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)) { onEvent(evt); } else if (mFormat != NETLINK_FORMAT_BINARY) { // Don't complain if parseBinaryNetlinkMessage returns false. That can // just mean that the buffer contained no messages we're interested in. SLOGE("Error decoding NetlinkEvent"); } delete evt; return true;}
也没有,NetlinkListener继承了SocketListener类,再看看SocketListener类中有没有startListener函数,
int SocketListener::startListener() { return startListener(4);}int SocketListener::startListener(int backlog) { 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, backlog) < 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;}SocketListener果然有startListener函数,开启了一个线程,再看看threadStart函数
void *SocketListener::threadStart(void *obj) { SocketListener *me = reinterpret_cast<SocketListener *>(obj); me->runListener(); pthread_exit(NULL); return NULL;}直接调用了runlistener,在runlistener使用了select进行了IO复用。
void SocketListener::runListener() { SocketClientCollection pendingList; while(1) { SocketClientCollection::iterator it; fd_set read_fds; int rc = 0; int max = -1; 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) { // NB: calling out to an other object with mClientsLock held (safe) int fd = (*it)->getSocket(); FD_SET(fd, &read_fds); if (fd > max) { max = fd; } } pthread_mutex_unlock(&mClientsLock); SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName); if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) { if (errno == EINTR) continue; SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max); sleep(1); continue; } else if (!rc) continue; if (FD_ISSET(mCtrlPipe[0], &read_fds)) { char c = CtrlPipe_Shutdown; TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1)); if (c == CtrlPipe_Shutdown) { break; } continue; } if (mListen && FD_ISSET(mSock, &read_fds)) { struct sockaddr addr; socklen_t alen; int c; do { alen = sizeof(addr); c = accept(mSock, &addr, &alen); SLOGV("%s got %d from accept", mSocketName, c); } while (c < 0 && errno == EINTR); if (c < 0) { SLOGE("accept failed (%s)", strerror(errno)); sleep(1); continue; } pthread_mutex_lock(&mClientsLock); mClients->push_back(new SocketClient(c, true, mUseCmdNum)); pthread_mutex_unlock(&mClientsLock); } /* Add all active clients to the pending list first */ pendingList.clear(); pthread_mutex_lock(&mClientsLock); for (it = mClients->begin(); it != mClients->end(); ++it) { SocketClient* c = *it; // NB: calling out to an other object with mClientsLock held (safe) int fd = c->getSocket(); if (FD_ISSET(fd, &read_fds)) { pendingList.push_back(c); c->incRef(); } } pthread_mutex_unlock(&mClientsLock); /* Process the pending list, since it is owned by the thread, * there is no need to lock it */ while (!pendingList.empty()) { /* Pop the first item from the list */ it = pendingList.begin(); SocketClient* c = *it; pendingList.erase(it); /* Process it, if false is returned, remove from list */ if (!onDataAvailable(c)) {//onDataAviailable是一个虚函数在NetlinkListener类中有实现 release(c, false); } c->decRef(); } }}
而在NetlinkListener类中的onDataAvailable函数中又调用了onEvent函数,而这个函数是一个虚函数在NetlinkHandler类中实现,如下:
void NetlinkHandler::onEvent(NetlinkEvent *evt) { VolumeManager *vm = VolumeManager::Instance();//调用VolumeManager单例 const char *subsys = evt->getSubsystem(); if (!subsys) { SLOGW("No subsystem found in netlink event"); return; } if (!strcmp(subsys, "block")) { vm->handleBlockEvent(evt);//如果是这个子系统的继续调用VM的handleBlockEvent }}
下面再看VolumeManager中的handleBlockEvent函数:
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) {//根据VolumeManager中的mVolumes一个个遍历去处理 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 }}
VolumeManager中根据Volumes的list一个个去遍历根据每个volume的handleBlockEvent函数处理。接下来我们需要看,何时volume加入到VolumeManager中去的:答案是在main函数中调用了process_config函数,其根据配置文件配置VM对象。
static int process_config(VolumeManager *vm){ char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)]; char propbuf[PROPERTY_VALUE_MAX]; int i; int ret = -1; int flags; property_get("ro.hardware", propbuf, ""); snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf); fstab = fs_mgr_read_fstab(fstab_filename); if (!fstab) { SLOGE("failed to open %s\n", fstab_filename); return -1; } /* Loop through entries looking for ones that vold manages */ for (i = 0; i < fstab->num_entries; i++) { if (fs_mgr_is_voldmanaged(&fstab->recs[i])) { DirectVolume *dv = NULL; flags = 0; /* Set any flags that might be set for this volume */ if (fs_mgr_is_nonremovable(&fstab->recs[i])) { flags |= VOL_NONREMOVABLE; } if (fs_mgr_is_encryptable(&fstab->recs[i])) { flags |= VOL_ENCRYPTABLE; } /* Only set this flag if there is not an emulated sd card */ if (fs_mgr_is_noemulatedsd(&fstab->recs[i]) && !strcmp(fstab->recs[i].fs_type, "vfat")) { flags |= VOL_PROVIDES_ASEC; } dv = new DirectVolume(vm, &(fstab->recs[i]), flags);//新建DirectVolume对象 if (dv->addPath(fstab->recs[i].blk_device)) {//添加设备在sysfs中的路径 SLOGE("Failed to add devpath %s to volume %s", fstab->recs[i].blk_device, fstab->recs[i].label); goto out_fail; } vm->addVolume(dv);//VM中加入DirectVolume对象 } } ret = 0;out_fail: return ret;}
process_config主要是解析/etc/vold.fstab。这个文件就是设置一些存储设备的挂载点,并且在VM中添加了DirectVolume对象。
DirectVolume从Volume派生,可以看成是外部存储卡的代表。封装了加载、卸载存储卡、格式化等。
DirectVolume::DirectVolume(VolumeManager *vm, const fstab_rec* rec, int flags) : Volume(vm, rec, flags) {//参数rec->label: “sdcard” rec->mount_point: "/mnt/sdcard" mPaths = new PathCollection(); for (int i = 0; i < MAX_PARTITIONS; i++) mPartMinors[i] = -1; mPendingPartCount = 0; mDiskMajor = -1; mDiskMinor = -1; mDiskNumParts = 0; mIsDecrypted = 0; if (strcmp(rec->mount_point, "auto") != 0) { ALOGE("Vold managed volumes must have auto mount point; ignoring %s", rec->mount_point); } char mount[PATH_MAX]; snprintf(mount, PATH_MAX, "%s/%s", Volume::MEDIA_DIR, rec->label); mMountpoint = strdup(mount); snprintf(mount, PATH_MAX, "%s/%s", Volume::FUSE_DIR, rec->label); mFuseMountpoint = strdup(mount); setState(Volume::State_NoMedia);}
addPath函数,主要是添加设备在sysfs中的路径,把某个存储卡相关的设备路径与这个DirectVolume绑定到一起,这个设备路径和Uevent中的DEVPATH对应的,这样就可以根据Uevent的DEVPATH找到是哪个存储卡的DirectVolume发生了变动。不过一般手机只有一个存储卡接口,所以vold也只有一个DirectVolume。
int DirectVolume::addPath(const char *path) { mPaths->push_back(new PathInfo(path)); return 0;}
继续回到主题,前面分析到VM中遍历mVolumes,去执行DirectVolume中的handleBlockEvent,如下
int DirectVolume::handleBlockEvent(NetlinkEvent *evt) { const char *dp = evt->findParam("DEVPATH"); PathCollection::iterator it; for (it = mPaths->begin(); it != mPaths->end(); ++it) { if ((*it)->match(dp)) {//去看Uevent中的DEVPATH是否在mPaths中 /* 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); } /* Send notification iff disk is ready (ie all partitions found) */ if (getState() == Volume::State_Idle) { char msg[255]; snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)", getLabel(), getFuseMountpoint(), mDiskMajor, mDiskMinor); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted, msg, false); } } 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;}
上面函数就是内核发送的Uevent最后的处理函数,详细的分析我们最后通过一个SD卡插入的实例看。
下面我们分析下CommandListener,CommandListener在main函数中,实例化,并且调用startListener函数,而发现CommandListener中没有startListener函数,就去父类FrameworkListener中找,也没有再去FrameworkListener的父类SocketListener中找,前面分析NetlinkHandler已经分析过这个类,它会开启一个线程,并且在线程中使用select的IO复用监听socket(是由MountService传过来的数据),最后调用onDataAvailable虚函数,而FrameworkListener实现了这个函数,在onDataAvailable函数中调用了FrameworkListener::dispatchCommand函数,在这个函数最后会调用各个command中的runCommand。
下面直接通过一个SD卡插入的实例说明整个过程:
先看SD卡插入,的Uevent信息:
add@/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0ACTION=add //add表示设备插入动作 ,还有remove change动作//DEVPATH表示设备位于/sys目录中的设备路径DEVPATH=/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0//SUBSYSTEM表示该设备属于哪一类设备,block块设备,磁盘也属于这类,另外还有字符型设备SUBSYSTEM=blockMAJOR=179 //MAJOR和MINOR分别表示该设备的主次设备号,两者联合起来表示一个设备。MINOR=0DEVNAME=mmcblk0DEVTYPE=disk //设备Type为diskNPARTS=3 //表示该SD卡上的分区,这里表示有3块分区SEQNUM=1357 //序号DirectVolume会处理这个Uevent信息,
int DirectVolume::handleBlockEvent(NetlinkEvent *evt) { const char *dp = evt->findParam("DEVPATH"); PathCollection::iterator it; for (it = mPaths->begin(); it != mPaths->end(); ++it) { if ((*it)->match(dp)) { /* 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")) {//是disk类型的 handleDiskAdded(dp, evt); } else { handlePartitionAdded(dp, evt); } /* Send notification iff disk is ready (ie all partitions found) */ if (getState() == Volume::State_Idle) { char msg[255]; snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)", getLabel(), getFuseMountpoint(), mDiskMajor, mDiskMinor); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted, msg, false);//给MountService发送VolumeDiskInserted信息 } } 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;}
下面来看下handleDiskAdded函数
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; } mPendingPartCount = mDiskNumParts; for (int i = 0; i < MAX_PARTITIONS; i++) mPartMinors[i] = -1; 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 pending partitions", mPendingPartCount);#endif setState(Volume::State_Pending); }}
我们来分析下setState这个函数
void Volume::setState(int state) { char msg[255]; int oldState = mState; if (oldState == state) {//一样的状态 SLOGW("Duplicate state (%d)\n", state); return; } if ((oldState == Volume::State_Pending) && (state != Volume::State_Idle)) { mRetryMount = false; } mState = state; SLOGD("Volume %s state changing %d (%s) -> %d (%s)", mLabel, oldState, stateToStr(oldState), mState, stateToStr(mState)); snprintf(msg, sizeof(msg), "Volume %s %s state changed from %d (%s) to %d (%s)", getLabel(), getFuseMountpoint(), oldState, stateToStr(oldState), mState, stateToStr(mState)); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeStateChange, msg, false);//给MountService发送VolumeStateChange信息}
接下来我们看看MountService收到VolumeDiskInserted信息后会怎么处理:
public boolean onEvent(int code, String raw, String[] cooked) { if (DEBUG_EVENTS) { StringBuilder builder = new StringBuilder(); builder.append("onEvent::"); builder.append(" raw= " + raw); if (cooked != null) { builder.append(" cooked = " ); for (String str : cooked) { builder.append(" " + str); } } Slog.i(TAG, builder.toString()); } if (code == VoldResponseCode.VolumeStateChange) { /* * One of the volumes we're managing has changed state. * Format: "NNN Volume <label> <path> state changed * from <old_#> (<old_str>) to <new_#> (<new_str>)" */ notifyVolumeStateChange( cooked[2], cooked[3], Integer.parseInt(cooked[7]), Integer.parseInt(cooked[10])); } else if (code == VoldResponseCode.VolumeUuidChange) { // Format: nnn <label> <path> <uuid> final String path = cooked[2]; final String uuid = (cooked.length > 3) ? cooked[3] : null; final StorageVolume vol = mVolumesByPath.get(path); if (vol != null) { vol.setUuid(uuid); } } else if (code == VoldResponseCode.VolumeUserLabelChange) { // Format: nnn <label> <path> <label> final String path = cooked[2]; final String userLabel = (cooked.length > 3) ? cooked[3] : null; final StorageVolume vol = mVolumesByPath.get(path); if (vol != null) { vol.setUserLabel(userLabel); } } else if ((code == VoldResponseCode.VolumeDiskInserted) ||//插入设备 (code == VoldResponseCode.VolumeDiskRemoved) || (code == VoldResponseCode.VolumeBadRemoval)) { // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>) // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>) // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>) String action = null; final String label = cooked[2]; final String path = cooked[3]; int major = -1; int minor = -1; try { String devComp = cooked[6].substring(1, cooked[6].length() -1); String[] devTok = devComp.split(":"); major = Integer.parseInt(devTok[0]); minor = Integer.parseInt(devTok[1]); } catch (Exception ex) { Slog.e(TAG, "Failed to parse major/minor", ex); } final StorageVolume volume; final String state; synchronized (mVolumesLock) { volume = mVolumesByPath.get(path); state = mVolumeStates.get(path); } if (code == VoldResponseCode.VolumeDiskInserted) {//如果是插入设备 new Thread("MountService#VolumeDiskInserted") { @Override public void run() { try { int rc; if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {//开启线程执行doMountVolume Slog.w(TAG, String.format("Insertion mount failed (%d)", rc)); } } catch (Exception ex) { Slog.w(TAG, "Failed to mount media on insertion", ex); } } }.start(); } else if (code == VoldResponseCode.VolumeDiskRemoved) { /* * This event gets trumped if we're already in BAD_REMOVAL state */ if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) { return true; } /* Send the media unmounted event first */ if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first"); updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED); sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL); if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed"); updatePublicVolumeState(volume, Environment.MEDIA_REMOVED); action = Intent.ACTION_MEDIA_REMOVED; } else if (code == VoldResponseCode.VolumeBadRemoval) { if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first"); /* Send the media unmounted event first */ updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED); sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL); if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal"); updatePublicVolumeState(volume, Environment.MEDIA_BAD_REMOVAL); action = Intent.ACTION_MEDIA_BAD_REMOVAL; } else if (code == VoldResponseCode.FstrimCompleted) { EventLogTags.writeFstrimFinish(SystemClock.elapsedRealtime()); } else { Slog.e(TAG, String.format("Unknown code {%d}", code)); } if (action != null) { sendStorageIntent(action, volume, UserHandle.ALL); } } else { return false; } return true; }
private int doMountVolume(String path) { int rc = StorageResultCode.OperationSucceeded; final StorageVolume volume; synchronized (mVolumesLock) { volume = mVolumesByPath.get(path); } if (!volume.isEmulated() && hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA)) { Slog.w(TAG, "User has restriction DISALLOW_MOUNT_PHYSICAL_MEDIA; cannot mount volume."); return StorageResultCode.OperationFailedInternalError; } if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path); try { mConnector.execute("volume", "mount", path);//mConnector是与vold通信部分,发送volume mount命令挂载磁盘 } catch (NativeDaemonConnectorException e) {//异常处理}
再回到vold中,看处理mount命令:
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")) { bool broadcast = argc >= 3 && !strcmp(argv[2], "broadcast"); return vm->listVolumes(cli, broadcast); } 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")) {//处理mount命令 if (argc != 3) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false); return 0; } rc = vm->mountVolume(argv[2]);//调用mountVolume函数 } 。。。。。。。。。。 if (!rc) { cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);//发送Okay消息返回 } else { int erno = errno; rc = ResponseCode::convertFromErrno(); cli->sendMsg(rc, "volume operation failed", true); } return 0;}
mountVolume函数如下:
int VolumeManager::mountVolume(const char *label) { Volume *v = lookupVolume(label);//查找Volume if (!v) { errno = ENOENT; return -1; } return v->mountVol();}
mountVol函数如下:
int Volume::mountVol() { dev_t deviceNodes[4]; int n, i, rc = 0; char errmsg[255]; int flags = getFlags(); bool providesAsec = (flags & VOL_PROVIDES_ASEC) != 0; // TODO: handle "bind" style mounts, for emulated storage char decrypt_state[PROPERTY_VALUE_MAX]; char crypto_state[PROPERTY_VALUE_MAX]; char encrypt_progress[PROPERTY_VALUE_MAX]; property_get("vold.decrypt", decrypt_state, ""); property_get("vold.encrypt_progress", encrypt_progress, ""); /* Don't try to mount the volumes if we have not yet entered the disk password * or are in the process of encrypting. */ if ((getState() == Volume::State_NoMedia) ||//还没初始化 ((!strcmp(decrypt_state, "1") || encrypt_progress[0]) && providesAsec)) { snprintf(errmsg, sizeof(errmsg), "Volume %s %s mount failed - no media", getLabel(), getFuseMountpoint()); mVm->getBroadcaster()->sendBroadcast( ResponseCode::VolumeMountFailedNoMedia, errmsg, false); errno = ENODEV; return -1; } else if (getState() != Volume::State_Idle) {//当前状态正忙 errno = EBUSY; if (getState() == Volume::State_Pending) { mRetryMount = true; } return -1; } if (isMountpointMounted(getMountpoint())) {//是否已经挂载 SLOGW("Volume is idle but appears to be mounted - fixing"); setState(Volume::State_Mounted);//设置挂载状态 // mCurrentlyMountedKdev = XXX return 0; } n = getDeviceNodes((dev_t *) &deviceNodes, 4); 。。。。。。。。 for (i = 0; i < n; i++) { char devicePath[255]; sprintf(devicePath, "/dev/block/vold/%d:%d", major(deviceNodes[i]), minor(deviceNodes[i])); SLOGI("%s being considered for volume %s\n", devicePath, getLabel()); errno = 0; setState(Volume::State_Checking); if (Fat::check(devicePath)) { if (errno == ENODATA) { SLOGW("%s does not contain a FAT filesystem\n", devicePath); continue; } errno = EIO; /* Badness - abort the mount */ SLOGE("%s failed FS checks (%s)", devicePath, strerror(errno)); setState(Volume::State_Idle); return -1; } errno = 0; int gid; //把设备mount一个地址 if (Fat::doMount(devicePath, getMountpoint(), false, false, false, AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) { SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno)); continue; } extractMetadata(devicePath); if (providesAsec && mountAsecExternal() != 0) { SLOGE("Failed to mount secure area (%s)", strerror(errno)); umount(getMountpoint()); setState(Volume::State_Idle); return -1; } char service[64]; snprintf(service, 64, "fuse_%s", getLabel()); property_set("ctl.start", service); setState(Volume::State_Mounted);//设置设备状态State_Mounted mCurrentlyMountedKdev = deviceNodes[i]; return 0; } SLOGE("Volume %s found no suitable devices for mounting :(\n", getLabel()); setState(Volume::State_Idle); return -1;}
设置设备状态State_Mounted会发送VolumeStateChange消息给MountService,当MountService收到后会发送广播
public boolean onEvent(int code, String raw, String[] cooked) { if (DEBUG_EVENTS) { StringBuilder builder = new StringBuilder(); builder.append("onEvent::"); builder.append(" raw= " + raw); if (cooked != null) { builder.append(" cooked = " ); for (String str : cooked) { builder.append(" " + str); } } Slog.i(TAG, builder.toString()); } if (code == VoldResponseCode.VolumeStateChange) { /* * One of the volumes we're managing has changed state. * Format: "NNN Volume <label> <path> state changed * from <old_#> (<old_str>) to <new_#> (<new_str>)" */ notifyVolumeStateChange( cooked[2], cooked[3], Integer.parseInt(cooked[7]), Integer.parseInt(cooked[10])); }
最后会在notifyVolumeStateChange发送广播:
private void notifyVolumeStateChange(String label, String path, int oldState, int newState) { final StorageVolume volume; final String state; synchronized (mVolumesLock) { volume = mVolumesByPath.get(path); state = getVolumeState(path); } if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChange::" + state); String action = null; if (oldState == VolumeState.Shared && newState != oldState) { if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_UNSHARED intent"); sendStorageIntent(Intent.ACTION_MEDIA_UNSHARED, volume, UserHandle.ALL); } if (newState == VolumeState.Init) { } else if (newState == VolumeState.NoMedia) { // NoMedia is handled via Disk Remove events } else if (newState == VolumeState.Idle) { /* * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or * if we're in the process of enabling UMS */ if (!state.equals( Environment.MEDIA_BAD_REMOVAL) && !state.equals( Environment.MEDIA_NOFS) && !state.equals( Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) { if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable"); updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED); action = Intent.ACTION_MEDIA_UNMOUNTED; } } else if (newState == VolumeState.Pending) { } else if (newState == VolumeState.Checking) { if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state checking"); updatePublicVolumeState(volume, Environment.MEDIA_CHECKING); action = Intent.ACTION_MEDIA_CHECKING; } else if (newState == VolumeState.Mounted) { if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted"); updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED); action = Intent.ACTION_MEDIA_MOUNTED; } else if (newState == VolumeState.Unmounting) { action = Intent.ACTION_MEDIA_EJECT; } else if (newState == VolumeState.Formatting) { } else if (newState == VolumeState.Shared) { if (DEBUG_EVENTS) Slog.i(TAG, "Updating volume state media mounted"); /* Send the media unmounted event first */ updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED); sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL); if (DEBUG_EVENTS) Slog.i(TAG, "Updating media shared"); updatePublicVolumeState(volume, Environment.MEDIA_SHARED); action = Intent.ACTION_MEDIA_SHARED; if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_SHARED intent"); } else if (newState == VolumeState.SharedMnt) { Slog.e(TAG, "Live shared mounts not supported yet!"); return; } else { Slog.e(TAG, "Unhandled VolumeState {" + newState + "}"); } if (action != null) { sendStorageIntent(action, volume, UserHandle.ALL); } }至此Vold、和MountService分析结束。
- 深入分析vold、MountService(and5.1)
- 深入解析vold、MountService(二)(and5.1)
- 深入解析MountService、vold(三)--fuse_sdcard1(and5.1)
- 深入Mountservice vold(六) handleDiskRemoved handlePartitionRemoved(and5.1)
- 深入MountService、vold(四) 大容量存储和MountService的消息机制(and5.1)
- 深入MountService、vold(五) MountService中通信(NativeDaemonConnector)(and5.1)
- Android的存储系统—Vold与MountService分析
- android(ics)vold,mountservice
- vold/mountservice框架
- and5.1PowerManagerService深入分析(三)updatePowerStateLocked函数
- and5.1PowerManagerService深入分析(三)updatePowerStateLocked函数
- 深入init进程(and5.1)
- Android7.0 Vold 进程工作机制分析之由MountService发起挂载请求
- Android BatteryStatsHelper深入理解(and5.1)
- and5.1PowerManagerService深入分析(一) PMS的初始化以及低功耗模式
- and5.1PowerManagerService深入分析(二)PowerManager中各函数
- and5.1PowerManagerService深入分析(四)PMS与Display模块
- and5.1PowerManagerService深入分析(四)PMS与Display模块
- 视图Ext.Viewport和窗口Ext.Window用法
- js连接小票打印机
- ubuntu目录结构
- Zend Framework 中render、_forward 、redirect的区别
- 最小二乘法拟合平面。
- 深入分析vold、MountService(and5.1)
- HDOJ 1005:吃糖果
- 编程之美3——N!末尾有多少个0
- 黑马程序员——多线程
- 系统配置技巧
- [mongodb翻译]选择合适的shard key
- 四川川早核桃苗批发,四川核桃苗基地,四川核桃苗价格
- LCM lightoj1215
- 对Objective-C中Block的追探