Android6.0vold除了通信部分改动不大,其他基本改动很大,那我们就从头开始分析一下吧。
先看下main函数中下面这段代码
if (!(vm = VolumeManager::Instance())) {//new 了volumemanager,构造函数中就是一些成员变量初始化 LOG(ERROR) << "Unable to create VolumeManager"; exit(1); } if (!(nm = NetlinkManager::Instance())) {//new 了NetlinkManager,构造函数中就是一些成员变量初始化 LOG(ERROR) << "Unable to create NetlinkManager"; exit(1); } if (property_get_bool("vold.debug", false)) { vm->setDebug(true); } cl = new CommandListener();//新建一个CommandListener ccl = new CryptCommandListener(); vm->setBroadcaster((SocketListener *) cl);//CommandListener也负责和MountService通信 nm->setBroadcaster((SocketListener *) cl); if (vm->start()) {//VolumManager的start方法 PLOG(ERROR) << "Unable to start VolumeManager"; exit(1); }
下面我们主要看下VolumManager的start方法:
int VolumeManager::start() { // Always start from a clean slate by unmounting everything in // directories that we own, in case we crashed. unmountAll();//unmount所有的 // Assume that we always have an emulated volume on internal // storage; the framework will decide if it should be mounted. CHECK(mInternalEmulated == nullptr); mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>( new android::vold::EmulatedVolume("/data/media")); mInternalEmulated->create(); return 0; }
新建了一个EmulatedVolume,先看下构造函数
EmulatedVolume::EmulatedVolume(const std::string& rawPath) : VolumeBase(Type::kEmulated), mFusePid(0) { setId("emulated"); mRawPath = rawPath; mLabel = "emulated"; }
把data/media赋给了mRawPath变量
接下来我们再看下EmulatedVolume的create函数,因为EmulatedVolume没有create函数,我们就看VolumeBase::create
status_t VolumeBase::create() { CHECK(!mCreated); mCreated = true; status_t res = doCreate(); notifyEvent(ResponseCode::VolumeCreated, StringPrintf("%d \"%s\" \"%s\"", mType, mDiskId.c_str(), mPartGuid.c_str())); setState(State::kUnmounted); return res; }
在create函数中给MountService发送VolumeCreated命令,然后将该volume设置成Unmounted状态
我们看下MountService的onEvent处理:
case VoldResponseCode.VOLUME_CREATED: { final String id = cooked[1]; final int type = Integer.parseInt(cooked[2]); final String diskId = TextUtils.nullIfEmpty(cooked[3]); final String partGuid = TextUtils.nullIfEmpty(cooked[4]); final DiskInfo disk = mDisks.get(diskId); final VolumeInfo vol = new VolumeInfo(id, type, disk, partGuid); mVolumes.put(id, vol); onVolumeCreatedLocked(vol); break; }
注意本来MountService就在addInternalVolume函数中,在mVolumes加了data目录的volume。和这个不同
我们再来看看onVolumeCreatedLocked函数
onVolumeCreatedLocked方法会发送H_VOLUME_MOUNT消息,我们就不详细说这个函数了。因为vold发送上来的type是emulated的,于是
vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
来看看这个消息的处理吧:
case H_VOLUME_MOUNT: { final VolumeInfo vol = (VolumeInfo) msg.obj; if (isMountDisallowed(vol)) { Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy"); break; } try { mConnector.execute("volume", "mount", vol.id, vol.mountFlags, vol.mountUserId); } catch (NativeDaemonConnectorException ignored) { } break; }
处理是直接给vold发送的mount的命令。
下面我们看看VolumeCmd::runCommand下的这段代码是处理MountService发给来的mount命令的
} else if (cmd == "mount" && argc > 2) { // mount [volId] [flags] [user] std::string id(argv[2]); auto vol = vm->findVolume(id); if (vol == nullptr) { return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false); } int mountFlags = (argc > 3) ? atoi(argv[3]) : 0; userid_t mountUserId = (argc > 4) ? atoi(argv[4]) : -1; vol->setMountFlags(mountFlags); vol->setMountUserId(mountUserId); int res = vol->mount(); if (mountFlags & android::vold::VolumeBase::MountFlags::kPrimary) {//如果是Primary的调用volumeManager的setprimary方法 vm->setPrimary(vol); } return sendGenericOkFail(cli, res); }
int VolumeManager::setPrimary(const std::shared_ptr<android::vold::VolumeBase>& vol) { mPrimary = vol; for (userid_t userId : mStartedUsers) { linkPrimary(userId); } return 0; }
遍历已经启动的user,再调用linkPrimary方法:
int VolumeManager::linkPrimary(userid_t userId) { std::string source(mPrimary->getPath()); if (mPrimary->getType() == android::vold::VolumeBase::Type::kEmulated) { source = StringPrintf("%s/%d", source.c_str(), userId); fs_prepare_dir(source.c_str(), 0755, AID_ROOT, AID_ROOT); } std::string target(StringPrintf("/mnt/user/%d/primary", userId)); if (TEMP_FAILURE_RETRY(unlink(target.c_str()))) { if (errno != ENOENT) { SLOGW("Failed to unlink %s: %s", target.c_str(), strerror(errno)); } } LOG(DEBUG) << "Linking " << source << " to " << target; if (TEMP_FAILURE_RETRY(symlink(source.c_str(), target.c_str()))) { SLOGW("Failed to link %s to %s: %s", source.c_str(), target.c_str(), strerror(errno)); return -errno; } return 0; }上面这段代码就是把storage/emulated/0/ 创建软链接到mnt/user/0/primary
我们来看下volumeBase的mout函数
status_t VolumeBase::mount() { if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) { LOG(WARNING) << getId() << " mount requires state unmounted or unmountable"; return -EBUSY; } setState(State::kChecking);//设置状态,没设置一个状态都会往MountService发送 status_t res = doMount(); if (res == OK) { setState(State::kMounted); } else { setState(State::kUnmountable); } return res; }
我们再来看看EmulatedVolume的doMount函数
status_t EmulatedVolume::doMount() { // We could have migrated storage to an adopted private volume, so always // call primary storage "emulated" to avoid media rescans. std::string label = mLabel; if (getMountFlags() & MountFlags::kPrimary) { label = "emulated"; } mFuseDefault = StringPrintf("/mnt/runtime/default/%s", label.c_str()); mFuseRead = StringPrintf("/mnt/runtime/read/%s", label.c_str()); mFuseWrite = StringPrintf("/mnt/runtime/write/%s", label.c_str()); setInternalPath(mRawPath); setPath(StringPrintf("/storage/%s", label.c_str())); if (fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) || fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) || fs_prepare_dir(mFuseWrite.c_str(), 0700, AID_ROOT, AID_ROOT)) { PLOG(ERROR) << getId() << " failed to create mount points"; return -errno; } dev_t before = GetDevice(mFuseWrite); if (!(mFusePid = fork())) { if (execl(kFusePath, kFusePath, "-u", "1023", // AID_MEDIA_RW "-g", "1023", // AID_MEDIA_RW "-m", "-w", mRawPath.c_str(), label.c_str(), NULL)) { PLOG(ERROR) << "Failed to exec"; } LOG(ERROR) << "FUSE exiting"; _exit(1); } if (mFusePid == -1) { PLOG(ERROR) << getId() << " failed to fork"; return -errno; } while (before == GetDevice(mFuseWrite)) { LOG(VERBOSE) << "Waiting for FUSE to spin up..."; usleep(50000); // 50ms } return OK; }这个函数中先设置了setInternalPath,setPath,这两个函数最终都会通知MountService,在下面两个地方进行处理
case VoldResponseCode.VOLUME_PATH_CHANGED: { if (cooked.length != 3) break; final VolumeInfo vol = mVolumes.get(cooked[1]); if (vol != null) { vol.path = cooked[2]; } break; } case VoldResponseCode.VOLUME_INTERNAL_PATH_CHANGED: { if (cooked.length != 3) break; final VolumeInfo vol = mVolumes.get(cooked[1]); if (vol != null) { vol.internalPath = cooked[2]; } break; }
其实InternalPath就是一个内存存储真正的路径data/media,path就是storage/emulated,而我们再看init.rc中一段
mount none /mnt/runtime/default /storage slave bind rec
将mnt/runtime/default挂载到storage上,
symlink /mnt/user/0/primary /mnt/runtime/default/self/primaryinit.rc中还有上面一个软链接,也就是说storage/self/primary也是/mnt/user/0/primary 的一个软链接
而对storage/emulated是利用fuse文件系统,再去读取data/media的
mount结束后最后在mount函数中setState(State::kMounted);
然后在MountService做如下处理,把mVolumes新的状态保存下来,再调用onVolumeStateChangedLocked
case VoldResponseCode.VOLUME_STATE_CHANGED: { if (cooked.length != 3) break; final VolumeInfo vol = mVolumes.get(cooked[1]); if (vol != null) { final int oldState = vol.state; final int newState = Integer.parseInt(cooked[2]); vol.state = newState; onVolumeStateChangedLocked(vol, oldState, newState); } break; }
onVolumeStateChangedLocked函数中会去调用mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);通知各个listener状态改变