标签:volume mount socket sdcard vold
在前文Android—— 4.2 Vold挂载管理_VolumeManager (三) 中解析了VolumeManager是怎么样抽取Volume实例以及DirectVolume与Volume之间的关系,在上篇Android—— 4.2 Vold挂载管理_NetlinkManager (四)中从kernel开始调用到handleBlockEvent,这里解析一下Vold挂载的真正操作,也就是Volume的操作!
撰写不易,转载请注明出处:http://blog.csdn.net/jscese/article/details/38736481
源码位置:/system/vold/DirectVolume.cpp ,这个类是作为真正的Volume的一个抽象操作类,先看构造:
DirectVolume::DirectVolume(VolumeManager *vm, const char *label, const char *mount_point, int partIdx) : Volume(vm, label, mount_point) {//同时构造父类实例 mPartIdx = partIdx;//记录分区索引 mPaths = new PathCollection();//路径容器 for (int i = 0; i < MAX_PARTITIONS; i++) //google默认最多分区数为4 mPartMinors[i] = -1; mPendingPartMap = 0; mDiskMajor = -1; mDiskMinor = -1; mDiskNumParts = 0; setState(Volume::State_NoMedia);//初始设置状态 }
上一篇有解析到DirectVolume的handleBlockEvent:
int DirectVolume::handleBlockEvent(NetlinkEvent *evt) { const char *dp = evt->findParam("DEVPATH"); //获取事件的设备路径 PathCollection::iterator it; //这个DirectVolume的Path容器,容器在构建时初始化,在VolumeManager中根据vold.fstab添加path for (it = mPaths->begin(); it != mPaths->end(); ++it) { if (!strncmp(dp, *it, strlen(*it))) { //筛选符合此次事件的Path,如果没有匹配的就退出这个DirectVolume实例的处理,在VolumeManager中交由下一个DirectVolume来处理,依次类推 /* We can handle this disk */ int action = evt->getAction(); const char *devtype = evt->findParam("DEVTYPE"); if (action == NetlinkEvent::NlActionAdd) { //事件类型有好几种,这里单以Add 添加来分析 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); //处理型号为disk的事件,当插入一个移动设备,不管有多少个分区,首先第一个事件的类型就是disk,收集设备的相关信息,比如分区总数mDiskNumParts } else { handlePartitionAdded(dp, evt); //处理设备的分区事件信息 } /* Send notification iff disk is ready (ie all partitions found) */ if (getState() == Volume::State_Idle) { //通过上面的handle ,代表已经准备就绪 char msg[255]; snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)", getLabel(), getMountpoint(), mDiskMajor, mDiskMinor); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted, //发送广播,调用的是SocketListener的sendBroadcast msg, false); } } ... } } }
在handlePartitionAdded中有收集分区的节点信息 mPartMinors[part_num -1] = minor; 并且设置Volume的状态到 Volume::State_Idle ,最后调用VolumeManager的实例发送广播
实际调用的是SocketListener的sendBroadcast,在Android—— 4.2 Vold挂载管理_CommandListener (二)中有分析!
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) { //遍历在SocketListener时创建的Client 依次发送广播 // 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); }
int SocketClient::sendDataLocked(const void *data, int len) { int rc = 0; while (brtw > 0) { rc = send(mSocket, p, brtw, MSG_NOSIGNAL); ... } }
这里的mSocket 为 "vold" 这个socket的表述符!
在上面DirectVolume中发送出去广播之后,会到上层的MountService.java中,再通过"vold"socket 到Vold中,在SocketListener 中会接收到,依次会调用到FrameworkListener.cpp中的onDataAvailable,dispatchCommand
再到CommandListener.cpp中的runCommand,VolumeManager.cpp中的mountVolume Android—— 4.2 Vold挂载管理_CommandListener (二)中有分析!
int VolumeManager::mountVolume(const char *label) { Volume *v = lookupVolume(label); if (!v) { errno = ENOENT; return -1; } return v->mountVol(); //调用到Volume的mountVol }
看Volume.cpp中:
int Volume::mountVol() { dev_t deviceNodes[4]; int n, i, rc = 0; char errmsg[255]; const char* externalStorage = getenv("EXTERNAL_STORAGE"); bool primaryStorage = externalStorage && !strcmp(getMountpoint(), externalStorage); char decrypt_state[PROPERTY_VALUE_MAX]; char crypto_state[PROPERTY_VALUE_MAX]; char encrypt_progress[PROPERTY_VALUE_MAX]; int flags; 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]) && primaryStorage)) { //Volume的状态不对或者是加密的 snprintf(errmsg, sizeof(errmsg), "Volume %s %s mount failed - no media", getLabel(), getMountpoint()); mVm->getBroadcaster()->sendBroadcast( ResponseCode::VolumeMountFailedNoMedia, errmsg, false); errno = ENODEV; return -1; } else if (getState() != Volume::State_Idle) {// 正常的逻辑到这里的时候,该Volume的state应为State_Idle errno = EBUSY; if (getState() == Volume::State_Pending) { mRetryMount = true; } return -1; } ... 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)) { //调用Fat的check,检查是否为Fat的文件系统 if (errno == ENODATA) { SLOGW("%s does not contain a FAT filesystem\n", devicePath); continue; } ... if (primaryStorage) {//是否为指定的external storage 以不同的gid挂载 // Special case the primary SD card. // For this we grant write access to the SDCARD_RW group. gid = AID_SDCARD_RW; } else { // For secondary external storage we keep things locked up. gid = AID_MEDIA_RW; } if (Fat::doMount(devicePath, "/mnt/secure/staging", false, false, false, //这里就是整个Vold 里面真正的挂载 AID_SYSTEM, gid, 0702, true)) { SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno)); continue; } ... setState(Volume::State_Mounted); ... } }
在整个挂载流程中state至关重要,通过state对挂载流程进行管控:
Volume.h中定义:
static const int State_Init = -1; static const int State_NoMedia = 0; static const int State_Idle = 1; static const int State_Pending = 2; static const int State_Checking = 3; static const int State_Mounted = 4; static const int State_Unmounting = 5; static const int State_Formatting = 6; static const int State_Shared = 7; static const int State_SharedMnt = 8;
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(), getMountpoint(), oldState, stateToStr(oldState), mState, stateToStr(mState)); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeStateChange, msg, false); }
简单画了一张功能流程图:
DirectVolume/Volume的大体运作就是这样,后续分析与上层Framework层的交互。
Android—— 4.2 Vold挂载管理_DirectVolume/Volume (五)
标签:volume mount socket sdcard vold
原文地址:http://blog.csdn.net/jscese/article/details/38736481