Android6.0 otg插入U盘 流程

转自 http://blog.csdn.net/kc58236582/article/details/50577333——看看这两篇文章,也许能解决U盘不能在es 文件浏览器看见的问题

之前分析过vold插入sd卡的流程,本以为otg插入U盘与sd卡走的流程一样。想不到还是有差别的,下面我们来分析下:


一、kAdoptable flag

先来看otg插入卡,后handleBlockEvent的流程

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {  
  2.     std::lock_guard<std::mutex> lock(mLock);  
  3.   
  4.   
  5.     std::string eventPath(evt->findParam("DEVPATH"));  
  6.     std::string devType(evt->findParam("DEVTYPE"));  
  7.   
  8.     if (devType != "disk"return;  
  9.   
  10.     int major = atoi(evt->findParam("MAJOR"));  
  11.     int minor = atoi(evt->findParam("MINOR"));  
  12.     dev_t device = makedev(major, minor);  
  13.   
  14.     switch (evt->getAction()) {  
  15.     case NetlinkEvent::Action::kAdd: {  
  16.         for (auto source : mDiskSources) {  
  17.             if (source->matches(eventPath)) {  
  18.                 // For now, assume that MMC devices are SD, and that  
  19.                 // everything else is USB  
  20.                 int flags = source->getFlags();  
  21.                 if (flags & android::vold::Disk::Flags::kAdoptable) {//这边的log是自己调试的时候加的  
  22.                     PLOG(ERROR) << "add disk kAdoptable";  
  23.                 }  
  24.                 if (major == kMajorBlockMmc) {  
  25.                     flags |= android::vold::Disk::Flags::kSd;//加入sd的flag  
  26.                 } else {  
  27.                     LOG(DEBUG) << "usb disk add.";  
  28.                     flags |= android::vold::Disk::Flags::kUsb;//加入usb的flag  
  29.                 }  
  30.   
  31.                 auto disk = new android::vold::Disk(eventPath, device,  
  32.                         source->getNickname(), flags);  
  33.                 disk->create();  
  34.                 mDisks.push_back(std::shared_ptr<android::vold::Disk>(disk));  
  35.                 break;  
  36.             }  
  37.         }  
  38.         break;  
  39.     }  
  40. ......  
  41. }  

上面的函数我们自己加了log,当走sd卡的时候从底层传上来的flag中就有kAdoptable,而如果是usb的就没有kAdoptable这个flag。

这点差别也会导致上层MountService处理的差别。


二、MountFlags MOUNT_FLAG_VISIBLE


[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private void onVolumeCreatedLocked(VolumeInfo vol) {  
  2.     if (vol.type == VolumeInfo.TYPE_EMULATED) {  
  3.         final StorageManager storage = mContext.getSystemService(StorageManager.class);  
  4.         final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);  
  5.   
  6.         if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)  
  7.                 && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {  
  8.             Slog.v(TAG, "Found primary storage at " + vol);  
  9.             vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;  
  10.             vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;  
  11.             mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();  
  12.   
  13.         } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {  
  14.             Slog.v(TAG, "Found primary storage at " + vol);  
  15.             vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;  
  16.             vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;  
  17.             mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();  
  18.         }  
  19.   
  20.     } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {//sd卡和otg都是Public  
  21.         Slog.d(TAG, "kangchen VolumeInfo.TYPE_PUBLIC");  
  22.         // TODO: only look at first public partition  
  23.         if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)  
  24.                 && vol.disk.isDefaultPrimary()) {  
  25.             Slog.d(TAG, "kangchen UUID_PRIMARY_PHYSICAL");  
  26.             Slog.v(TAG, "Found primary storage at " + vol);  
  27.             vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;  
  28.             vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;  
  29.         }  
  30.   
  31.         // Adoptable public disks are visible to apps, since they meet  
  32.         // public API requirement of being in a stable location.  
  33.         if (vol.disk.isAdoptable()) {//如果有kAdoptable这个flag  
  34.             vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;  
  35.         }  
  36.   
  37.         vol.mountUserId = UserHandle.USER_OWNER;  
  38.         mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();  
  39.   
  40.     } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {  
  41.         mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();  
  42.   
  43.     } else {  
  44.         Slog.d(TAG, "Skipping automatic mounting of " + vol);  
  45.     }  
  46. }  

从上面处理volume创建来看,如果Disk有kAdoptable这个flag,那么往vold传的mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE


三、vold otg的挂载流程

下面我们再来看vold中PublicVolume的挂载:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t PublicVolume::doMount() {  
  2.     // TODO: expand to support mounting other filesystems  
  3.     readMetadata();  
  4.   
  5.     if (mFsType != "vfat") {  
  6.         LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;  
  7.         return -EIO;  
  8.     }  
  9.   
  10.     if (vfat::Check(mDevPath)) {  
  11.         LOG(ERROR) << getId() << " failed filesystem check";  
  12.         return -EIO;  
  13.     }  
  14.   
  15.     // Use UUID as stable name, if available  
  16.     std::string stableName = getId();  
  17.     if (!mFsUuid.empty()) {  
  18.         stableName = mFsUuid;  
  19.     }  
  20.   
  21.     mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str());  
  22.   
  23.     mFuseDefault = StringPrintf("/mnt/runtime/default/%s", stableName.c_str());  
  24.     mFuseRead = StringPrintf("/mnt/runtime/read/%s", stableName.c_str());  
  25.     mFuseWrite = StringPrintf("/mnt/runtime/write/%s", stableName.c_str());  
  26.   
  27.     setInternalPath(mRawPath);  
  28.     if (getMountFlags() & MountFlags::kVisible) {  
  29.         setPath(StringPrintf("/storage/%s", stableName.c_str()));  
  30.     } else {  
  31.         setPath(mRawPath);  
  32.     }  
  33.     //创建挂载目录,以及各个fuse目录  
  34.     if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT) ||  
  35.             fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||  
  36.             fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||  
  37.             fs_prepare_dir(mFuseWrite.c_str(), 0700, AID_ROOT, AID_ROOT)) {  
  38.         PLOG(ERROR) << getId() << " failed to create mount points";  
  39.         return -errno;  
  40.     }  
  41.   
  42.     if (vfat::Mount(mDevPath, mRawPath, falsefalsefalse,  
  43.             AID_MEDIA_RW, AID_MEDIA_RW, 0007true)) {  
  44.         PLOG(ERROR) << getId() << " failed to mount " << mDevPath;  
  45.         return -EIO;  
  46.     }  
  47.   
  48.     if (getMountFlags() & MountFlags::kPrimary) {  
  49.         initAsecStage();  
  50.     }  
  51.   
  52.   
  53.     if (!(getMountFlags() & MountFlags::kVisible)) {//如果MountService没有传kVisible这个flag下来,那么就不进行fuse操作了。  
  54.         // Not visible to apps, so no need to spin up FUSE  
  55.         return OK;  
  56.     }  
  57.   
  58.     dev_t before = GetDevice(mFuseWrite);  
  59.   
  60.     if (!(mFusePid = fork())) {  
  61.         if (getMountFlags() & MountFlags::kPrimary) {  
  62.             if (execl(kFusePath, kFusePath,  
  63.                     "-u""1023"// AID_MEDIA_RW  
  64.                     "-g""1023"// AID_MEDIA_RW  
  65.                     "-U", std::to_string(getMountUserId()).c_str(),  
  66.                     "-w",  
  67.                     mRawPath.c_str(),  
  68.                     stableName.c_str(),  
  69.                     NULL)) {  
  70.                 PLOG(ERROR) << "Failed to exec";  
  71.             }  
  72.         } else {  
  73.             if (execl(kFusePath, kFusePath,  
  74.                     "-u""1023"// AID_MEDIA_RW  
  75.                     "-g""1023"// AID_MEDIA_RW  
  76.                     "-U", std::to_string(getMountUserId()).c_str(),  
  77.                     mRawPath.c_str(),  
  78.                     stableName.c_str(),  
  79.                     NULL)) {  
  80.                 PLOG(ERROR) << "Failed to exec";  
  81.             }  
  82.         }  
  83.   
  84.         LOG(ERROR) << "FUSE exiting";  
  85.         _exit(1);  
  86.     }  
  87.   
  88.     if (mFusePid == -1) {  
  89.         PLOG(ERROR) << getId() << " failed to fork";  
  90.         return -errno;  
  91.     }  
  92.   
  93.     while (before == GetDevice(mFuseWrite)) {  
  94.         LOG(VERBOSE) << "Waiting for FUSE to spin up...";  
  95.         usleep(50000); // 50ms  
  96.     }  
  97.   
  98.   
  99.     return OK;  
  100. }  

而我们看PublicVolume的挂载流程,当MountService传的MountFlag没有kVisible这个flag的话,就直接挂载完就结束了,不会再走fuse流程了。

所以在storage下面是看不到otg的U盘路径的,这里说错了,因为前面fuse的路径是创建了,但是没有fuse上,所以storage下的这个路径是无效的。


所以上面的代码需要修改下:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t PublicVolume::doMount() {  
  2.     // TODO: expand to support mounting other filesystems  
  3.     readMetadata();  
  4.   
  5.     if (mFsType != "vfat") {  
  6.         LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;  
  7.         return -EIO;  
  8.     }  
  9.   
  10.     if (vfat::Check(mDevPath)) {  
  11.         LOG(ERROR) << getId() << " failed filesystem check";  
  12.         return -EIO;  
  13.     }  
  14.   
  15.     // Use UUID as stable name, if available  
  16.     std::string stableName = getId();  
  17.     if (!mFsUuid.empty()) {  
  18.         stableName = mFsUuid;  
  19.     }  
  20.   
  21.     mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str());  
  22.   
  23.     mFuseDefault = StringPrintf("/mnt/runtime/default/%s", stableName.c_str());  
  24.     mFuseRead = StringPrintf("/mnt/runtime/read/%s", stableName.c_str());  
  25.     mFuseWrite = StringPrintf("/mnt/runtime/write/%s", stableName.c_str());  
  26.   
  27.     setInternalPath(mRawPath);  
  28.     if (getMountFlags() & MountFlags::kVisible) {  
  29.         setPath(StringPrintf("/storage/%s", stableName.c_str()));  
  30.     } else {  
  31.         setPath(mRawPath);  
  32.     }  
  33.   
  34.     if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT)) {  
  35.         PLOG(ERROR) << getId() << " failed to create mount points";  
  36.         return -errno;  
  37.     }  
  38.   
  39.     if (vfat::Mount(mDevPath, mRawPath, falsefalsefalse,  
  40.             AID_MEDIA_RW, AID_MEDIA_RW, 0007true)) {  
  41.         PLOG(ERROR) << getId() << " failed to mount " << mDevPath;  
  42.         return -EIO;  
  43.     }  
  44.   
  45.     if (getMountFlags() & MountFlags::kPrimary) {  
  46.         initAsecStage();  
  47.     }  
  48.   
  49.     if (!(getMountFlags() & MountFlags::kVisible)) {  
  50.         // Not visible to apps, so no need to spin up FUSE  
  51.         return OK;  
  52.     }  
  53.   
  54.     if (fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||  
  55.         fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||  
  56.         fs_prepare_dir(mFuseWrite.c_str(), 0700, AID_ROOT, AID_ROOT)) {  
  57.         PLOG(ERROR) << getId() << " failed to create fuse points";  
  58.         return -errno;  
  59.     }     
  60.   
  61. //执行fuse操作  
  62. .......  
  63.   
  64.     return OK;  
  65. }  

上面如果是otg的话,创建的fuse路径也就没有什么用,所以我们把mount的路径放前面,fuse的路径放后面,这样挂载otg后也就不会有fuse这个没有用的路径生成了。

所以这样的话otg挂载的volume,拿到路径的话,也是没有权限的。因为挂载的路径是mnt/media下面的需要的权限需要:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <permission name="android.permission.WRITE_MEDIA_STORAGE" >  
  2.     <group gid="media_rw" />  
  3.     <group gid="sdcard_rw" />  
  4. </permission>  




android6.0 把sd卡可以设置成内部存储。

一、fatab文件匹配

我们先来看下,vold的main函数:

main函数在创建了VolumeManager后,调用了如下函数:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. if (process_config(vm)) {  
  2.     PLOG(ERROR) << "Error reading configuration... continuing anyways";  
  3. }  

我们再来看看这个函数:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static int process_config(VolumeManager *vm) {  
  2.     std::string path(android::vold::DefaultFstabPath());  
  3.     fstab = fs_mgr_read_fstab(path.c_str());//获取fstab文件  
  4.     if (!fstab) {  
  5.         PLOG(ERROR) << "Failed to open default fstab " << path;  
  6.         return -1;  
  7.     }  
  8.   
  9.     /* Loop through entries looking for ones that vold manages */  
  10.     bool has_adoptable = false;  
  11.     for (int i = 0; i < fstab->num_entries; i++) {  
  12.         if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {//fastab文件满足vold的项  
  13.             if (fs_mgr_is_nonremovable(&fstab->recs[i])) {  
  14.                 LOG(WARNING) << "nonremovable no longer supported; ignoring volume";  
  15.                 continue;  
  16.             }  
  17.   
  18.             std::string sysPattern(fstab->recs[i].blk_device);  
  19.             std::string nickname(fstab->recs[i].label);  
  20.             int flags = 0;  
  21.   
  22.             if (fs_mgr_is_encryptable(&fstab->recs[i])) {  
  23.                 flags |= android::vold::Disk::Flags::kAdoptable;  
  24.                 has_adoptable = true;  
  25.             }  
  26.             if (fs_mgr_is_noemulatedsd(&fstab->recs[i])  
  27.                     || property_get_bool("vold.debug.default_primary"false)) {  
  28.                 flags |= android::vold::Disk::Flags::kDefaultPrimary;  
  29.             }  
  30.   
  31.             vm->addDiskSource(std::shared_ptr<VolumeManager::DiskSource>(  
  32.                     new VolumeManager::DiskSource(sysPattern, nickname, flags)));  
  33.         }  
  34.     }  
  35.     property_set("vold.has_adoptable", has_adoptable ? "1" : "0");  
  36.     return 0;  
  37. }  

这个函数先获取fstab文件,分析fstab文件,创建了DiskSource对象。然后调用了VolumeManager的addDiskSource函数:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void VolumeManager::addDiskSource(const std::shared_ptr<DiskSource>& diskSource) {  
  2.     mDiskSources.push_back(diskSource);  
  3. }  
保存在mDiskSources中。

下面我们来看下fstab文件,下面文件有机箱是voldmanaged的,就是上面函数满足的条件

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /dev/block/platform/comip-mmc.1/by-name/system                    /system          ext4    ro,barrier=1                                                    wait  
  2. /dev/block/platform/comip-mmc.1/by-name/cache                     /cache           ext4    noatime,nosuid,nodev,barrier=1,data=ordered                     wait,check  
  3. /dev/block/platform/comip-mmc.1/by-name/userdata                  /data            ext4    noatime,nosuid,nodev,barrier=1,data=ordered,noauto_da_alloc     resize,wait,check,encryptable=footer  
  4. #/dev/block/platform/comip-mmc.1/by-name/amt                      /amt             ext4    rw                                                              wait  
  5. /devices/platform/comip-mmc.0/mmc_host/mmc1/*                       auto             vfat    defaults                                                        voldmanaged=sdcard1:auto,encryptable=false  
  6. /devices/a0400000.usb_hcd/usb1/*                                    auto      vfat    defaults        voldmanaged=usbotg:auto,noemulatedsd  
  7. /dev/block/mmcblk1p1                                              /sdcard                vfat  defaults  recoveryonly  
  8. /dev/block/platform/comip-mmc.1/by-name/kernel                                /kernel          emmc        defaults    defaults  
  9. /dev/block/platform/comip-mmc.1/by-name/ramdisk                   /boot                  emmc    defaults    defaults  
  10. /dev/block/platform/comip-mmc.1/by-name/ramdisk_recovery          /recovery        emmc    defaults    defaults  
  11. /dev/block/platform/comip-mmc.1/by-name/ramdisk_amt1              /ramdisk_amt1    emmc    defaults    defaults  
  12. /dev/block/platform/comip-mmc.1/by-name/ramdisk_amt3              /ramdisk_amt3    emmc    defaults    defaults  
  13. /dev/block/platform/comip-mmc.1/by-name/kernel_recovery           /kernel_recovery emmc    defaults    defaults  
  14. /dev/block/platform/comip-mmc.1/by-name/logo                      /logo            emmc    defaults    defaults  
  15. /dev/block/platform/comip-mmc.1/by-name/misc                      /misc            emmc    defaults    defaults  
  16. /dev/block/platform/comip-mmc.1/by-name/fota                      /fota            emmc    defaults    defaults  
  17. /dev/block/platform/comip-mmc.1/by-name/modemarm                  /modemarm        emmc    defaults    defaults  
  18. /dev/block/platform/comip-mmc.1/by-name/modemdsp                  /modemdsp        emmc    defaults    defaults  
  19. /dev/block/mmcblk0boot0                                           /uboot           emmc    defaults    defaults  
  20. /dev/block/platform/comip-mmc.1/by-name/lcboot                          /lcboot          emmc    defaults    defaults  
  21. /dev/block/zram0                                                  none          swap    defaults        zramsize=268435456  


二、检测到设备

然后就是有检测到设备,到下面函数:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void NetlinkHandler::onEvent(NetlinkEvent *evt) {  
  2.     VolumeManager *vm = VolumeManager::Instance();  
  3.     const char *subsys = evt->getSubsystem();  
  4.   
  5.     if (!subsys) {  
  6.         SLOGW("No subsystem found in netlink event");  
  7.         return;  
  8.     }  
  9.   
  10.     if (!strcmp(subsys, "block")) {  
  11.         vm->handleBlockEvent(evt);  
  12.     }  
  13. }  

调用了VolumeManager的handleBlockEvent函数:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {  
  2.     std::lock_guard<std::mutex> lock(mLock);  
  3.   
  4.     if (mDebug) {  
  5.         LOG(VERBOSE) << "----------------";  
  6.         LOG(VERBOSE) << "handleBlockEvent with action " << (int) evt->getAction();  
  7.         evt->dump();  
  8.     }  
  9.   
  10.     std::string eventPath(evt->findParam("DEVPATH"));  
  11.     std::string devType(evt->findParam("DEVTYPE"));  
  12.   
  13.     if (devType != "disk"return;  
  14.   
  15.     int major = atoi(evt->findParam("MAJOR"));  
  16.     int minor = atoi(evt->findParam("MINOR"));  
  17.     dev_t device = makedev(major, minor);//创建设备  
  18.   
  19.     switch (evt->getAction()) {  
  20.     case NetlinkEvent::Action::kAdd: {  
  21.         for (auto source : mDiskSources) {  
  22.             if (source->matches(eventPath)) {//之前的mDiskSources就是用来匹配的  
  23.                 // For now, assume that MMC devices are SD, and that  
  24.                 // everything else is USB  
  25.                 int flags = source->getFlags();//从source获取flags  
  26.                 if (major == kMajorBlockMmc) {  
  27.                     flags |= android::vold::Disk::Flags::kSd;  
  28.                 } else {  
  29.                     flags |= android::vold::Disk::Flags::kUsb;  
  30.                 }  
  31.   
  32.                 auto disk = new android::vold::Disk(eventPath, device,  
  33.                         source->getNickname(), flags);//新建Disk  
  34.                 disk->create();  
  35.                 mDisks.push_back(std::shared_ptr<android::vold::Disk>(disk));  
  36.                 break;  
  37.             }  
  38.         }  
  39.         break;  
  40.     }  

有设备是主要是Aciton:kAdd,这个函数先创建了设备,根据major和minor。
从mDiskSources看是否有满足的DiskSource,然后获取其flags,然后新建Disk,调用create函数。

三、Disk创建

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. Disk::Disk(const std::string& eventPath, dev_t device,  
  2.         const std::string& nickname, int flags) :  
  3.         mDevice(device), mSize(-1), mNickname(nickname), mFlags(flags), mCreated(  
  4.                 false), mJustPartitioned(false) {  
  5.     mId = StringPrintf("disk:%u,%u", major(device), minor(device));  
  6.     mEventPath = eventPath;  
  7.     mSysPath = StringPrintf("/sys/%s", eventPath.c_str());  
  8.     mDevPath = StringPrintf("/dev/block/vold/%s", mId.c_str());//设备地址  
  9.     CreateDeviceNode(mDevPath, mDevice);  
  10. }  

我们再来看看CreateDeviceNode函数:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t CreateDeviceNode(const std::string& path, dev_t dev) {  
  2.     const char* cpath = path.c_str();  
  3.     status_t res = 0;  
  4.   
  5.     char* secontext = nullptr;  
  6.     if (sehandle) {  
  7.         if (!selabel_lookup(sehandle, &secontext, cpath, S_IFBLK)) {  
  8.             setfscreatecon(secontext);  
  9.         }  
  10.     }  
  11.   
  12.     mode_t mode = 0660 | S_IFBLK;  
  13.     if (mknod(cpath, mode, dev) < 0) {  
  14.         if (errno != EEXIST) {  
  15.             PLOG(ERROR) << "Failed to create device node for " << major(dev)  
  16.                     << ":" << minor(dev) << " at " << path;  
  17.             res = -errno;  
  18.         }  
  19.     }  
  20.   
  21.     if (secontext) {  
  22.         setfscreatecon(nullptr);  
  23.         freecon(secontext);  
  24.     }  
  25.   
  26.     return res;  
  27. }  

这个函数里面,其中最重要的就是mknod,把device的设备放在了dev,这个设备目录。等于创建了设备目录,等于我们就有了dev/block/vold/disk:179,128这个目录。
我们再来看,create函数

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t Disk::create() {  
  2.     CHECK(!mCreated);  
  3.     mCreated = true;  
  4.     notifyEvent(ResponseCode::DiskCreated, StringPrintf("%d", mFlags));  
  5.     readMetadata();  
  6.     readPartitions();  
  7.     return OK;  
  8. }  

readMetadata主要就是获取信息,然后和MountService通信,和MountService通信我们这里不说了,之前的博客都分析过很多。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t Disk::readMetadata() {  
  2.     mSize = -1;  
  3.     mLabel.clear();  
  4.   
  5.     int fd = open(mDevPath.c_str(), O_RDONLY | O_CLOEXEC);  
  6.     if (fd != -1) {  
  7.         if (ioctl(fd, BLKGETSIZE64, &mSize)) {  
  8.             mSize = -1;  
  9.         }  
  10.         close(fd);  
  11.     }  
  12.   
  13.     switch (major(mDevice)) {  
  14.     case kMajorBlockScsiA: case kMajorBlockScsiB: case kMajorBlockScsiC: case kMajorBlockScsiD:  
  15.     case kMajorBlockScsiE: case kMajorBlockScsiF: case kMajorBlockScsiG: case kMajorBlockScsiH:  
  16.     case kMajorBlockScsiI: case kMajorBlockScsiJ: case kMajorBlockScsiK: case kMajorBlockScsiL:  
  17.     case kMajorBlockScsiM: case kMajorBlockScsiN: case kMajorBlockScsiO: case kMajorBlockScsiP: {  
  18.         std::string path(mSysPath + "/device/vendor");  
  19.         std::string tmp;  
  20.         if (!ReadFileToString(path, &tmp)) {  
  21.             PLOG(WARNING) << "Failed to read vendor from " << path;  
  22.             return -errno;  
  23.         }  
  24.         mLabel = tmp;  
  25.         break;  
  26.     }  
  27.     case kMajorBlockMmc: {  
  28.         std::string path(mSysPath + "/device/manfid");  
  29.         std::string tmp;  
  30.         if (!ReadFileToString(path, &tmp)) {  
  31.             PLOG(WARNING) << "Failed to read manufacturer from " << path;  
  32.             return -errno;  
  33.         }  
  34.         uint64_t manfid = strtoll(tmp.c_str(), nullptr, 16);  
  35.         // Our goal here is to give the user a meaningful label, ideally  
  36.         // matching whatever is silk-screened on the card.  To reduce  
  37.         // user confusion, this list doesn't contain white-label manfid.  
  38.         switch (manfid) {  
  39.         case 0x000003: mLabel = "SanDisk"break;  
  40.         case 0x00001b: mLabel = "Samsung"break;  
  41.         case 0x000028: mLabel = "Lexar"break;  
  42.         case 0x000074: mLabel = "Transcend"break;  
  43.         }  
  44.         break;  
  45.     }  
  46.     default: {  
  47.         LOG(WARNING) << "Unsupported block major type" << major(mDevice);  
  48.         return -ENOTSUP;  
  49.     }  
  50.     }  
  51.   
  52.     notifyEvent(ResponseCode::DiskSizeChanged, StringPrintf("%" PRId64, mSize));  
  53.     notifyEvent(ResponseCode::DiskLabelChanged, mLabel);  
  54.     notifyEvent(ResponseCode::DiskSysPathChanged, mSysPath);  
  55.     return OK;  
  56. }  

我们主要看readPartitions这个函数:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t Disk::readPartitions() {  
  2.     int8_t maxMinors = getMaxMinors();  
  3.     if (maxMinors < 0) {  
  4.         return -ENOTSUP;  
  5.     }  
  6.   
  7.     destroyAllVolumes();  
  8.   
  9.     // Parse partition table  
  10.   
  11.     std::vector<std::string> cmd;  
  12.     cmd.push_back(kSgdiskPath);//"/system/bin/sgdisk";  
  13.     cmd.push_back("--android-dump");  
  14.     cmd.push_back(mDevPath);  
  15.   
  16.     std::vector<std::string> output;  
  17.     status_t res = ForkExecvp(cmd, output);  
  18.     if (res != OK) {  
  19.         LOG(WARNING) << "sgdisk failed to scan " << mDevPath;  
  20.         notifyEvent(ResponseCode::DiskScanned);  
  21.         mJustPartitioned = false;  
  22.         return res;  
  23.     }  
  24.   
  25.     Table table = Table::kUnknown;  
  26.     bool foundParts = false;  
  27.     for (auto line : output) {  
  28.         char* cline = (char*) line.c_str();  
  29.         char* token = strtok(cline, kSgdiskToken);  
  30.         if (token == nullptr) continue;  
  31.   
  32.         if (!strcmp(token, "DISK")) {  
  33.             const char* type = strtok(nullptr, kSgdiskToken);  
  34.             if (!strcmp(type, "mbr")) {//mbr  
  35.                 table = Table::kMbr;  
  36.             } else if (!strcmp(type, "gpt")) {  
  37.                 table = Table::kGpt;//gpt  
  38.             }  
  39.         } else if (!strcmp(token, "PART")) {  
  40.             foundParts = true;  
  41.             int i = strtol(strtok(nullptr, kSgdiskToken), nullptr, 10);  
  42.             if (i <= 0 || i > maxMinors) {  
  43.                 LOG(WARNING) << mId << " is ignoring partition " << i  
  44.                         << " beyond max supported devices";  
  45.                 continue;  
  46.             }  
  47.             dev_t partDevice = makedev(major(mDevice), minor(mDevice) + i);//和之前Disk一样根据disk的device的major和minor创建volume的device  
  48.   
  49.             if (table == Table::kMbr) {  
  50.                 const char* type = strtok(nullptr, kSgdiskToken);  
  51.   
  52.                 switch (strtol(type, nullptr, 16)) {  
  53.                 case 0x06: // FAT16  
  54.                 case 0x0b: // W95 FAT32 (LBA)  
  55.                 case 0x0c: // W95 FAT32 (LBA)  
  56.                 case 0x0e: // W95 FAT16 (LBA)  
  57.                     createPublicVolume(partDevice);  
  58.                     break;  
  59.                 }  
  60.             } else if (table == Table::kGpt) {//下面的就是gpt  
  61.                 const char* typeGuid = strtok(nullptr, kSgdiskToken);  
  62.                 const char* partGuid = strtok(nullptr, kSgdiskToken);  
  63.   
  64.                 if (!strcasecmp(typeGuid, kGptBasicData)) {  
  65.                     createPublicVolume(partDevice);  
  66.                 } else if (!strcasecmp(typeGuid, kGptAndroidExpand)) {//expand就是privatevolume  
  67.                     createPrivateVolume(partDevice, partGuid);  
  68.                 }  
  69.             }  
  70.         }  
  71.     }  
  72.   
  73.     // Ugly last ditch effort, treat entire disk as partition  
  74.     if (table == Table::kUnknown || !foundParts) {  
  75.         LOG(WARNING) << mId << " has unknown partition table; trying entire device";  
  76.   
  77.         std::string fsType;  
  78.         std::string unused;  
  79.         if (ReadMetadataUntrusted(mDevPath, fsType, unused, unused) == OK) {  
  80.             createPublicVolume(mDevice);  
  81.         } else {  
  82.             LOG(WARNING) << mId << " failed to identify, giving up";  
  83.         }  
  84.     }  
  85.   
  86.     notifyEvent(ResponseCode::DiskScanned);  
  87.     mJustPartitioned = false;  
  88.     return OK;  
  89. }  

上面函数,就是根据sgdisk这个工具,输入命令,去读取输出,相应创建privatevolume还是PublicVolume
下面我们结合sgdisk的命令输出来看:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. DISK gpt D25EA824-98CC-4390-899F-40F8B7609491  
  2. PART 1 193D1EA4-B3CA-11E4-B075-10604B889DCF 7F3EE593-E357-196F-7707-FA295A508E64 android_expand  

这里是内部存储sgdisk的输出。这里disk是gpt。


四、内部存储创建


我们再来看看createPrivatevolume,

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void Disk::createPrivateVolume(dev_t device, const std::string& partGuid) {  
  2.     std::string normalizedGuid;  
  3.     if (NormalizeHex(partGuid, normalizedGuid)) {  
  4.         LOG(WARNING) << "Invalid GUID " << partGuid;  
  5.         return;  
  6.     }  
  7.   
  8.     std::string keyRaw;  
  9.     if (!ReadFileToString(BuildKeyPath(normalizedGuid), &keyRaw)) {  
  10.         PLOG(ERROR) << "Failed to load key for GUID " << normalizedGuid;  
  11.         return;  
  12.     }  
  13.   
  14.     LOG(DEBUG) << "Found key for GUID " << normalizedGuid;  
  15.   
  16.     auto vol = std::shared_ptr<VolumeBase>(new PrivateVolume(device, keyRaw));  
  17.     if (mJustPartitioned) {  
  18.         LOG(DEBUG) << "Device just partitioned; silently formatting";  
  19.         vol->setSilent(true);  
  20.         vol->create();  
  21.         vol->format("auto");  
  22.         vol->destroy();  
  23.         vol->setSilent(false);  
  24.     }  
  25.   
  26.     mVolumes.push_back(vol);  
  27.     vol->setDiskId(getId());  
  28.     vol->setPartGuid(partGuid);  
  29.     vol->create();  
  30. }  

再来看Privatevolume的构造函数

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. PrivateVolume::PrivateVolume(dev_t device, const std::string& keyRaw) :  
  2.         VolumeBase(Type::kPrivate), mRawDevice(device), mKeyRaw(keyRaw) {  
  3.     setId(StringPrintf("private:%u,%u", major(device), minor(device)));  
  4.     mRawDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str());  
  5. }  

doFormat函数就是将sd卡格式化,比如格式化成ext4的。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t PrivateVolume::doFormat(const std::string& fsType) {  
  2.     std::string resolvedFsType = fsType;  
  3.     if (fsType == "auto") {  
  4.         // For now, assume that all MMC devices are flash-based SD cards, and  
  5.         // give everyone else ext4 because sysfs rotational isn't reliable.  
  6.         if ((major(mRawDevice) == kMajorBlockMmc) && f2fs::IsSupported()) {  
  7.             resolvedFsType = "f2fs";  
  8.         } else {  
  9.             resolvedFsType = "ext4";  
  10.         }  
  11.         LOG(DEBUG) << "Resolved auto to " << resolvedFsType;  
  12.     }  
  13.   
  14.     if (resolvedFsType == "ext4") {  
  15.         // TODO: change reported mountpoint once we have better selinux support  
  16.         if (ext4::Format(mDmDevPath, 0, "/data")) {  
  17.             PLOG(ERROR) << getId() << " failed to format";  
  18.             return -EIO;  
  19.         }  
  20.     } else if (resolvedFsType == "f2fs") {  
  21.         if (f2fs::Format(mDmDevPath)) {  
  22.             PLOG(ERROR) << getId() << " failed to format";  
  23.             return -EIO;  
  24.         }  
  25.     } else {  
  26.         LOG(ERROR) << getId() << " unsupported filesystem " << fsType;  
  27.         return -EINVAL;  
  28.     }  
  29.   
  30.     return OK;  
  31. }  

doCreate函数,就会调用CreateDeviceNode,来创建dev设备,就是将device绑在dev目录下。后面一些函数没有深入研究

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t PrivateVolume::doCreate() {  
  2.     if (CreateDeviceNode(mRawDevPath, mRawDevice)) {  
  3.         return -EIO;  
  4.     }  
  5.   
  6.     // Recover from stale vold by tearing down any old mappings  
  7.     cryptfs_revert_ext_volume(getId().c_str());  
  8.   
  9.     // TODO: figure out better SELinux labels for private volumes  
  10.   
  11.     unsigned char* key = (unsigned char*) mKeyRaw.data();  
  12.     char crypto_blkdev[MAXPATHLEN];  
  13.     int res = cryptfs_setup_ext_volume(getId().c_str(), mRawDevPath.c_str(),  
  14.             key, mKeyRaw.size(), crypto_blkdev);  
  15.     mDmDevPath = crypto_blkdev;  
  16.     if (res != 0) {  
  17.         PLOG(ERROR) << getId() << " failed to setup cryptfs";  
  18.         return -EIO;  
  19.     }  
  20.   
  21.     return OK;  
  22. }  

之后就是mount了,内部存储是将dev文件mount到mnt/expand下。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t PrivateVolume::doMount() {  
  2.     if (readMetadata()) {  
  3.         LOG(ERROR) << getId() << " failed to read metadata";  
  4.         return -EIO;  
  5.     }  
  6.   
  7.     mPath = StringPrintf("/mnt/expand/%s", mFsUuid.c_str());  
  8.     setPath(mPath);  
  9.   
  10.     if (PrepareDir(mPath, 0700, AID_ROOT, AID_ROOT)) {  
  11.         PLOG(ERROR) << getId() << " failed to create mount point " << mPath;  
  12.         return -EIO;  
  13.     }  
  14.   
  15.     if (mFsType == "ext4") {  
  16.         int res = ext4::Check(mDmDevPath, mPath);  
  17.         if (res == 0 || res == 1) {  
  18.             LOG(DEBUG) << getId() << " passed filesystem check";  
  19.         } else {  
  20.             PLOG(ERROR) << getId() << " failed filesystem check";  
  21.             return -EIO;  
  22.         }  
  23.   
  24.         if (ext4::Mount(mDmDevPath, mPath, falsefalsetrue)) {  
  25.             PLOG(ERROR) << getId() << " failed to mount";  
  26.             return -EIO;  
  27.         }  
  28.   
  29.     }   


五、创建外部存储

外部存储sgdisk的输出命令如下:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. 05-30 20:23:45.358   175   177 V vold    : DISK mbr  
  2. 05-30 20:23:45.359   175   177 V vold    : PART 1 c  

我们再来看Disk的readPartitions函数的其中一段

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. Table table = Table::kUnknown;  
  2.  bool foundParts = false;  
  3.  for (auto line : output) {  
  4.      char* cline = (char*) line.c_str();  
  5.      char* token = strtok(cline, kSgdiskToken);  
  6.      if (token == nullptr) continue;  
  7.   
  8.      if (!strcmp(token, "DISK")) {  
  9.          const char* type = strtok(nullptr, kSgdiskToken);  
  10.          if (!strcmp(type, "mbr")) {//mbr  
  11.              table = Table::kMbr;  
  12.          } else if (!strcmp(type, "gpt")) {  
  13.              table = Table::kGpt;  
  14.          }  
  15.      } else if (!strcmp(token, "PART")) {  
  16.          foundParts = true;  
  17.          int i = strtol(strtok(nullptr, kSgdiskToken), nullptr, 10);  
  18.          if (i <= 0 || i > maxMinors) {  
  19.              LOG(WARNING) << mId << " is ignoring partition " << i  
  20.                      << " beyond max supported devices";  
  21.              continue;  
  22.          }  
  23.          dev_t partDevice = makedev(major(mDevice), minor(mDevice) + i);  
  24.   
  25.          if (table == Table::kMbr) {  
  26.              const char* type = strtok(nullptr, kSgdiskToken);  
  27.   
  28.              switch (strtol(type, nullptr, 16)) {  
  29.              case 0x06: // FAT16  
  30.              case 0x0b: // W95 FAT32 (LBA)  
  31.              case 0x0c: // W95 FAT32 (LBA)  
  32.              case 0x0e: // W95 FAT16 (LBA)  
  33.                  createPublicVolume(partDevice);// 是mbr的就直接调用createPublicVolume函数  
  34.                  break;  
  35.              }  
  36.          } else if (table == Table::kGpt) {  
  37.              const char* typeGuid = strtok(nullptr, kSgdiskToken);  
  38.              const char* partGuid = strtok(nullptr, kSgdiskToken);  
  39.   
  40.              if (!strcasecmp(typeGuid, kGptBasicData)) {  
  41.                  createPublicVolume(partDevice);  
  42.              } else if (!strcasecmp(typeGuid, kGptAndroidExpand)) {  
  43.                  createPrivateVolume(partDevice, partGuid);  
  44.              }  
  45.          }  
  46.      }  
  47.  }  

然后我们看createPublicVolume函数:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void Disk::createPublicVolume(dev_t device) {  
  2.     auto vol = std::shared_ptr<VolumeBase>(new PublicVolume(device));  
  3.     if (mJustPartitioned) {  
  4.         LOG(DEBUG) << "Device just partitioned; silently formatting";  
  5.         vol->setSilent(true);  
  6.         vol->create();  
  7.         vol->format("auto");  
  8.         vol->destroy();  
  9.         vol->setSilent(false);  
  10.     }  
  11.   
  12.     mVolumes.push_back(vol);  
  13.     vol->setDiskId(getId());  
  14.     vol->create();  
  15. }  

构造函数

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. PublicVolume::PublicVolume(dev_t device) :  
  2.         VolumeBase(Type::kPublic), mDevice(device), mFusePid(0) {  
  3.     setId(StringPrintf("public:%u,%u", major(device), minor(device)));  
  4.     mDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str());  
  5. }  

创建设备

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t PublicVolume::doCreate() {  
  2.     return CreateDeviceNode(mDevPath, mDevice);  
  3. }  
格式化

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t PublicVolume::doFormat(const std::string& fsType) {  
  2.     if (fsType == "vfat" || fsType == "auto") {  
  3.         if (WipeBlockDevice(mDevPath) != OK) {  
  4.             LOG(WARNING) << getId() << " failed to wipe";  
  5.         }  
  6.         if (vfat::Format(mDevPath, 0)) {  
  7.             LOG(ERROR) << getId() << " failed to format";  
  8.             return -errno;  
  9.         }  
  10.     } else {  
  11.         LOG(ERROR) << "Unsupported filesystem " << fsType;  
  12.         return -EINVAL;  
  13.     }  
  14.   
  15.     return OK;  
  16. }  

我们再来看下mount的第一步流程:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t PublicVolume::doMount() {  
  2.     // TODO: expand to support mounting other filesystems  
  3.     readMetadata();  
  4.   
  5.     if (mFsType != "vfat") {  
  6.         LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;  
  7.         return -EIO;  
  8.     }  
  9.   
  10.     if (vfat::Check(mDevPath)) {  
  11.         LOG(ERROR) << getId() << " failed filesystem check";  
  12.         return -EIO;  
  13.     }  

doMount函数中显示调用了readMetadata函数:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t PublicVolume::readMetadata() {  
  2.     status_t res = ReadMetadataUntrusted(mDevPath, mFsType, mFsUuid, mFsLabel);  
  3.     notifyEvent(ResponseCode::VolumeFsTypeChanged, mFsType);  
  4.     notifyEvent(ResponseCode::VolumeFsUuidChanged, mFsUuid);  
  5.     notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel);  
  6.     return res;  
  7. }  

我们可以知道通过ReadMetadataUntrusted函数来获取mFsType, mFsUuid, mFsLabel3个值。

我们再来看下ReadMetadataUntrusted函数:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t ReadMetadataUntrusted(const std::string& path, std::string& fsType,  
  2.         std::string& fsUuid, std::string& fsLabel) {  
  3.     return readMetadata(path, fsType, fsUuid, fsLabel, true);  
  4. }  

readMetadata函数,我们通过blkid进程来获取这些值。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static status_t readMetadata(const std::string& path, std::string& fsType,  
  2.         std::string& fsUuid, std::string& fsLabel, bool untrusted) {  
  3.     fsType.clear();  
  4.     fsUuid.clear();  
  5.     fsLabel.clear();  
  6.   
  7.     std::vector<std::string> cmd;  
  8.     cmd.push_back(kBlkidPath);//"/system/bin/blkid"  
  9.     cmd.push_back("-c");  
  10.     cmd.push_back("/dev/null");  
  11.     cmd.push_back("-s");  
  12.     cmd.push_back("TYPE");  
  13.     cmd.push_back("-s");  
  14.     cmd.push_back("UUID");  
  15.     cmd.push_back("-s");  
  16.     cmd.push_back("LABEL");  
  17.     cmd.push_back(path);  
  18.   
  19.     std::vector<std::string> output;  
  20.     status_t res = ForkExecvp(cmd, output, untrusted ? sBlkidUntrustedContext : sBlkidContext);  
  21.     if (res != OK) {  
  22.         LOG(WARNING) << "blkid failed to identify " << path;  
  23.         return res;  
  24.     }  
  25.   
  26.     char value[128];  
  27.     for (auto line : output) {  
  28.         // Extract values from blkid output, if defined  
  29.         const char* cline = line.c_str();  
  30.         char* start = strstr(cline, "TYPE=");  
  31.         if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {  
  32.             fsType = value;  
  33.         }  
  34.   
  35.         start = strstr(cline, "UUID=");  
  36.         if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {  
  37.             fsUuid = value;  
  38.         }  
  39.   
  40.         start = strstr(cline, "LABEL=");  
  41.         if (start != nullptr && sscanf(start + 6, "\"%127[^\"]\"", value) == 1) {  
  42.             fsLabel = value;  
  43.         }  
  44.     }  
  45.   
  46.     return OK;  
  47. }  

在这里我们再看下ForkExecvp函数:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t ForkExecvp(const std::vector<std::string>& args,  
  2.         std::vector<std::string>& output, security_context_t context) {  
  3.     std::string cmd;  
  4.     for (size_t i = 0; i < args.size(); i++) {  
  5.         cmd += args[i] + " ";  
  6.         if (i == 0) {  
  7.             LOG(VERBOSE) << args[i];//输入的命令打印  
  8.         } else {  
  9.             LOG(VERBOSE) << "    " << args[i];  
  10.         }  
  11.     }  
  12.     output.clear();  
  13.   
  14.     if (setexeccon(context)) {  
  15.         LOG(ERROR) << "Failed to setexeccon";  
  16.         abort();  
  17.     }  
  18.     FILE* fp =  popen(cmd.c_str(), "r");//通过popen函数  
  19.     if (setexeccon(nullptr)) {  
  20.         LOG(ERROR) << "Failed to setexeccon";  
  21.         abort();  
  22.     }  
  23.   
  24.     if (!fp) {  
  25.         PLOG(ERROR) << "Failed to popen " << cmd;  
  26.         return -errno;  
  27.     }  
  28.     char line[1024];  
  29.     while (fgets(line, sizeof(line), fp) != nullptr) {//获取输出  
  30.         LOG(VERBOSE) << line;  
  31.         output.push_back(std::string(line));  
  32.     }  
  33.     if (pclose(fp) != 0) {  
  34.         PLOG(ERROR) << "Failed to pclose " << cmd;  
  35.         return -errno;  
  36.     }  
  37.   
  38.     return OK;  
  39. }  

上面通过popen来执行blkid进程获取信息,popen函数先fork,然后调用exec执行cmd,并且返回一个标准I/O的文件指针。

当type是r,文件指针连接到cmd的标准输出。如果是w,文件指针连接到cmd的标准输入。

最后pclose是关闭标准I/O流。



六、如何决定外部存储还是内部存储


流程我们看完了,但是disk在调用readPartitions函数时,根据sgdisk工具的输出,来决定是创建外部存储还是内部存储。但是这个sgdisk的输出又是谁来决定的,我们可以看下下面两个函数:

第一个就是格式化为内部存储:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t Disk::partitionPrivate() {  
  2.     return partitionMixed(0);  
  3. }  

partitionMixed函数同样调用了sgdisk工具

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t Disk::partitionMixed(int8_t ratio) {  
  2.     int res;  
  3.   
  4.     destroyAllVolumes();  
  5.     mJustPartitioned = true;  
  6.   
  7.     // First nuke any existing partition table  
  8.     std::vector<std::string> cmd;  
  9.     cmd.push_back(kSgdiskPath);  
  10.     cmd.push_back("--zap-all");  
  11.     cmd.push_back(mDevPath);  
  12.   
  13.     // Zap sometimes returns an error when it actually succeeded, so  
  14.     // just log as warning and keep rolling forward.  
  15.     if ((res = ForkExecvp(cmd)) != 0) {  
  16.         LOG(WARNING) << "Failed to zap; status " << res;  
  17.     }  
  18.   
  19.     // We've had some success above, so generate both the private partition  
  20.     // GUID and encryption key and persist them.  
  21.     std::string partGuidRaw;  
  22.     std::string keyRaw;  
  23.     if (ReadRandomBytes(16, partGuidRaw) || ReadRandomBytes(16, keyRaw)) {  
  24.         LOG(ERROR) << "Failed to generate GUID or key";  
  25.         return -EIO;  
  26.     }  
  27.   
  28.     std::string partGuid;  
  29.     StrToHex(partGuidRaw, partGuid);  
  30.   
  31.     if (!WriteStringToFile(keyRaw, BuildKeyPath(partGuid))) {  
  32.         LOG(ERROR) << "Failed to persist key";  
  33.         return -EIO;  
  34.     } else {  
  35.         LOG(DEBUG) << "Persisted key for GUID " << partGuid;  
  36.     }  
  37.   
  38.     // Now let's build the new GPT table. We heavily rely on sgdisk to  
  39.     // force optimal alignment on the created partitions.  
  40.     cmd.clear();  
  41.     cmd.push_back(kSgdiskPath);  
  42.   
  43.     // If requested, create a public partition first. Mixed-mode partitioning  
  44.     // like this is an experimental feature.  
  45.     if (ratio > 0) {  
  46.         if (ratio < 10 || ratio > 90) {  
  47.             LOG(ERROR) << "Mixed partition ratio must be between 10-90%";  
  48.             return -EINVAL;  
  49.         }  
  50.   
  51.         uint64_t splitMb = ((mSize / 100) * ratio) / 1024 / 1024;  
  52.         cmd.push_back(StringPrintf("--new=0:0:+%" PRId64 "M", splitMb));  
  53.         cmd.push_back(StringPrintf("--typecode=0:%s", kGptBasicData));  
  54.         cmd.push_back("--change-name=0:shared");  
  55.     }  
  56.   
  57.     // Define a metadata partition which is designed for future use; there  
  58.     // should only be one of these per physical device, even if there are  
  59.     // multiple private volumes.  
  60.     /*cmd.push_back("--new=0:0:+16M");// 这段代码被我注释了,因为在我们的手机上有错,不知为何 
  61.     cmd.push_back(StringPrintf("--typecode=0:%s", kGptAndroidMeta)); 
  62.     cmd.push_back("--change-name=0:android_meta");*/  
  63.   
  64.     // Define a single private partition filling the rest of disk.  
  65.     cmd.push_back("--new=0:0:-0");  
  66.     cmd.push_back(StringPrintf("--typecode=0:%s", kGptAndroidExpand));  
  67.     cmd.push_back(StringPrintf("--partition-guid=0:%s", partGuid.c_str()));  
  68.     cmd.push_back("--change-name=0:android_expand");// 这里就是对应我们的PART1 的expand  
  69.   
  70.     cmd.push_back(mDevPath);  
  71.   
  72.     if ((res = ForkExecvp(cmd)) != 0) {  
  73.         LOG(ERROR) << "Failed to partition; status " << res;  
  74.         return res;  
  75.     }  
  76.   
  77.     return OK;  
  78. }  

原来的意思是先创建一个16M的part1为android_meta, 剩余的存储创建了part2,为android_expand。但是这样后面,在创建part2的时候createPrivatevolume,最后在Privatevolume的docreate函数出错了,没有找到设备。所以将part1,这段代码注释后是可以的。


第二个函数partitionPublic函数如下,变成外部存储。类似上面

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t Disk::partitionPublic() {  
  2.     int res;  
  3.   
  4.     // TODO: improve this code  
  5.     destroyAllVolumes();  
  6.     mJustPartitioned = true;  
  7.   
  8.     // First nuke any existing partition table  
  9.     std::vector<std::string> cmd;  
  10.     cmd.push_back(kSgdiskPath);  
  11.     cmd.push_back("--zap-all");  
  12.     cmd.push_back(mDevPath);  
  13.   
  14.     // Zap sometimes returns an error when it actually succeeded, so  
  15.     // just log as warning and keep rolling forward.  
  16.     if ((res = ForkExecvp(cmd)) != 0) {  
  17.         LOG(WARNING) << "Failed to zap; status " << res;  
  18.     }  
  19.   
  20.     struct disk_info dinfo;  
  21.     memset(&dinfo, 0, sizeof(dinfo));  
  22.   
  23.     if (!(dinfo.part_lst = (struct part_info *) malloc(  
  24.             MAX_NUM_PARTS * sizeof(struct part_info)))) {  
  25.         return -1;  
  26.     }  
  27.   
  28.     memset(dinfo.part_lst, 0, MAX_NUM_PARTS * sizeof(struct part_info));  
  29.     dinfo.device = strdup(mDevPath.c_str());  
  30.     dinfo.scheme = PART_SCHEME_MBR;  
  31.     dinfo.sect_size = 512;  
  32.     dinfo.skip_lba = 2048;  
  33.     dinfo.num_lba = 0;  
  34.     dinfo.num_parts = 1;  
  35.   
  36.     struct part_info *pinfo = &dinfo.part_lst[0];  
  37.   
  38.     pinfo->name = strdup("android_sdcard");  
  39.     pinfo->flags |= PART_ACTIVE_FLAG;  
  40.     pinfo->type = PC_PART_TYPE_FAT32;  
  41.     pinfo->len_kb = -1;  
  42.   
  43.     int rc = apply_disk_config(&dinfo, 0);  
  44.     if (rc) {  
  45.         LOG(ERROR) << "Failed to apply disk configuration: " << rc;  
  46.         goto out;  
  47.     }  
  48.   
  49. out:  
  50.     free(pinfo->name);  
  51.     free(dinfo.device);  
  52.     free(dinfo.part_lst);  
  53.   
  54.     return rc;  
  55. }  

而在调用这两个函数之后,应该是将某些数据烧录到了sd卡中。

因为下次开机,vold在Disk的readPartitions函数根据sgdisk工具输出,就自动识别出是publicvolume还是Privatevolume


  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值