看了前面的博客大家都发现,android6.0上vold对外置sd卡挂载都采用在storage增加一个sd卡的uuid的名字,作为文件名。
但是之前我们系统中很多系统应用都是直接写死的外置sd卡路径,是storage/sdcard1,那我们如何尽量少修改应用,并且在平台上左比较少的改动增加一个storage/scard1的外置sd卡路径呢。
符号链接:
我们熟悉之前的代码就知道:
在PublicVolume的doMount的最后我们增加一个linkExternal函数,把外置sd卡的路径在storage/sdcard1做了一符号链接。
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) || 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)) { // 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 } linkExternal(); return OK; } void PublicVolume::linkExternal() { std::string source(getPath()); std::string target("/storage/sdcard1"); if (TEMP_FAILURE_RETRY(unlink(target.c_str()))) { if (errno != ENOENT) { LOG(VERBOSE) << "Failed to unlink " << target.c_str() << strerror(errno); } } LOG(DEBUG) << "Linking " << source << " to " << target; if (TEMP_FAILURE_RETRY(symlink(source.c_str(), target.c_str()))) { LOG(ERROR) << "Failed to link " << source.c_str() << " to " << target.c_str() << strerror(errno); } }
至于为什么放在doMount的最后因为,启动system/bin/sdcard来进行fuse操作,而在fuse中创建storage下的sd卡的uuid的文件名作为fuse路径。
而我们也正是把这个fuse路径,创建软链接。尽管是在两个进程中,但是从逻辑上还是应该放在后面。
这样就创建了storage/sdcard1这个符号链接,作为外置sd卡的路径。