之前分析过vold插入sd卡的流程,本以为otg插入U盘与sd卡走的流程一样。想不到还是有差别的,下面我们来分析下:
先来看otg插入卡,后handleBlockEvent的流程
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) { std::lock_guard<std::mutex> lock(mLock); std::string eventPath(evt->findParam("DEVPATH")); std::string devType(evt->findParam("DEVTYPE")); if (devType != "disk") return; int major = atoi(evt->findParam("MAJOR")); int minor = atoi(evt->findParam("MINOR")); dev_t device = makedev(major, minor); switch (evt->getAction()) { case NetlinkEvent::Action::kAdd: { for (auto source : mDiskSources) { if (source->matches(eventPath)) { // For now, assume that MMC devices are SD, and that // everything else is USB int flags = source->getFlags(); if (flags & android::vold::Disk::Flags::kAdoptable) {//这边的log是自己调试的时候加的 PLOG(ERROR) << "add disk kAdoptable"; } if (major == kMajorBlockMmc) { flags |= android::vold::Disk::Flags::kSd;//加入sd的flag } else { LOG(DEBUG) << "usb disk add."; flags |= android::vold::Disk::Flags::kUsb;//加入usb的flag } auto disk = new android::vold::Disk(eventPath, device, source->getNickname(), flags); disk->create(); mDisks.push_back(std::shared_ptr<android::vold::Disk>(disk)); break; } } break; } ...... }
上面的函数我们自己加了log,当走sd卡的时候从底层传上来的flag中就有kAdoptable,而如果是usb的就没有kAdoptable这个flag。
这点差别也会导致上层MountService处理的差别。
private void onVolumeCreatedLocked(VolumeInfo vol) { if (vol.type == VolumeInfo.TYPE_EMULATED) { final StorageManager storage = mContext.getSystemService(StorageManager.class); final VolumeInfo privateVol = storage.findPrivateForEmulated(vol); if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid) && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) { Slog.v(TAG, "Found primary storage at " + vol); vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY; vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE; mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget(); } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) { Slog.v(TAG, "Found primary storage at " + vol); vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY; vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE; mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget(); } } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {//sd卡和otg都是Public Slog.d(TAG, "kangchen VolumeInfo.TYPE_PUBLIC"); // TODO: only look at first public partition if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid) && vol.disk.isDefaultPrimary()) { Slog.d(TAG, "kangchen UUID_PRIMARY_PHYSICAL"); Slog.v(TAG, "Found primary storage at " + vol); vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY; vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE; } // Adoptable public disks are visible to apps, since they meet // public API requirement of being in a stable location. if (vol.disk.isAdoptable()) {//如果有kAdoptable这个flag vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE; } vol.mountUserId = UserHandle.USER_OWNER; mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget(); } else if (vol.type == VolumeInfo.TYPE_PRIVATE) { mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget(); } else { Slog.d(TAG, "Skipping automatic mounting of " + vol); } }
从上面处理volume创建来看,如果Disk有kAdoptable这个flag,那么往vold传的mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE
下面我们再来看vold中PublicVolume的挂载:
status_t PublicVolume::doMount() { // TODO: expand to support mounting other filesystems readMetadata(); if (mFsType != "vfat") { LOG(ERROR) << getId() << " unsupported filesystem " << mFsType; return -EIO; } if (vfat::Check(mDevPath)) { LOG(ERROR) << getId() << " failed filesystem check"; return -EIO; } // Use UUID as stable name, if available std::string stableName = getId(); if (!mFsUuid.empty()) { stableName = mFsUuid; } mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str()); mFuseDefault = StringPrintf("/mnt/runtime/default/%s", stableName.c_str()); mFuseRead = StringPrintf("/mnt/runtime/read/%s", stableName.c_str()); mFuseWrite = StringPrintf("/mnt/runtime/write/%s", stableName.c_str()); setInternalPath(mRawPath); if (getMountFlags() & MountFlags::kVisible) { setPath(StringPrintf("/storage/%s", stableName.c_str())); } else { setPath(mRawPath); } //创建挂载目录,以及各个fuse目录 if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT) || 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; } if (vfat::Mount(mDevPath, mRawPath, false, false, false, AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) { PLOG(ERROR) << getId() << " failed to mount " << mDevPath; return -EIO; } if (getMountFlags() & MountFlags::kPrimary) { initAsecStage(); } if (!(getMountFlags() & MountFlags::kVisible)) {//如果MountService没有传kVisible这个flag下来,那么就不进行fuse操作了。 // Not visible to apps, so no need to spin up FUSE return OK; } dev_t before = GetDevice(mFuseWrite); if (!(mFusePid = fork())) { if (getMountFlags() & MountFlags::kPrimary) { if (execl(kFusePath, kFusePath, "-u", "1023", // AID_MEDIA_RW "-g", "1023", // AID_MEDIA_RW "-U", std::to_string(getMountUserId()).c_str(), "-w", mRawPath.c_str(), stableName.c_str(), NULL)) { PLOG(ERROR) << "Failed to exec"; } } else { if (execl(kFusePath, kFusePath, "-u", "1023", // AID_MEDIA_RW "-g", "1023", // AID_MEDIA_RW "-U", std::to_string(getMountUserId()).c_str(), mRawPath.c_str(), stableName.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; }
而我们看PublicVolume的挂载流程,当MountService传的MountFlag没有kVisible这个flag的话,就直接挂载完就结束了,不会再走fuse流程了。
所以在storage下面是看不到otg的U盘路径的,这里说错了,因为前面fuse的路径是创建了,但是没有fuse上,所以storage下的这个路径是无效的。
所以上面的代码需要修改下:
status_t PublicVolume::doMount() { // TODO: expand to support mounting other filesystems readMetadata(); if (mFsType != "vfat") { LOG(ERROR) << getId() << " unsupported filesystem " << mFsType; return -EIO; } if (vfat::Check(mDevPath)) { LOG(ERROR) << getId() << " failed filesystem check"; return -EIO; } // Use UUID as stable name, if available std::string stableName = getId(); if (!mFsUuid.empty()) { stableName = mFsUuid; } mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str()); mFuseDefault = StringPrintf("/mnt/runtime/default/%s", stableName.c_str()); mFuseRead = StringPrintf("/mnt/runtime/read/%s", stableName.c_str()); mFuseWrite = StringPrintf("/mnt/runtime/write/%s", stableName.c_str()); setInternalPath(mRawPath); if (getMountFlags() & MountFlags::kVisible) { setPath(StringPrintf("/storage/%s", stableName.c_str())); } else { setPath(mRawPath); } if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT)) { PLOG(ERROR) << getId() << " failed to create mount points"; return -errno; } if (vfat::Mount(mDevPath, mRawPath, false, false, false, AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) { PLOG(ERROR) << getId() << " failed to mount " << mDevPath; return -EIO; } if (getMountFlags() & MountFlags::kPrimary) { initAsecStage(); } if (!(getMountFlags() & MountFlags::kVisible)) { // Not visible to apps, so no need to spin up FUSE return OK; } 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 fuse points"; return -errno; } //执行fuse操作 ....... return OK; }
上面如果是otg的话,创建的fuse路径也就没有什么用,所以我们把mount的路径放前面,fuse的路径放后面,这样挂载otg后也就不会有fuse这个没有用的路径生成了。
所以这样的话otg挂载的volume,拿到路径的话,也是没有权限的。因为挂载的路径是mnt/media下面的需要的权限需要:
<permission name="android.permission.WRITE_MEDIA_STORAGE" > <group gid="media_rw" /> <group gid="sdcard_rw" /> </permission>