在分析SD卡挂载过程前,先了解Android存储的一些杂乱概念吧。
Android存储类型
Internal vs External
对于Internal Storage 与 External Storage,官方文档上有这么一段话,描述得很详细了,我翻译了一段下来:
所有的Android设备都有两块存储区域:Internal Storage和External Storage。它们的名称来源于早期的Android系统,那时候大家的手机都内置(Permanent)一块较小存储板(即Internal Storage),并配上一个的外置的(Removable)储存卡(即External Storage)。后来部分手机开始将最初定义的“Internal Storage”,即内置存储,分成Internal和External两部分。这样一来就算没有外置储存,手机也有Internal和External两块存储区域。这两块存储区域的区别是:
Internal Storage:
12345 可信度:永远可用(Permanent)访问权限:App存储内容仅App本身(或共享uid的App)可访问(Root除外)内容持久:App存储内容随App卸载而消失适应情况:存储内容仅App自己访问时的最佳选择External Storage:
12345 可信度:最典型的当设备作为USB存储被mount时不可用访问权限:App存储内容全局可读内容持久:当App卸载时,只有存在getExternalFilesDir()路径下的文件会消失适应情况:存储内容希望与其他App共享或传到电脑上,但是不想申请任何权限时的最佳选择注:此处讨论的访问权限是应用路径下的权限。
总结下来,External存储区域有几个好处:
- 可以传到电脑上;
- 可以与其他app共享;
- 在4.4之后的App路径(Android/data/包名)下读写不需任何权限;
- 存在App路径之外的文件不会随App卸载。
相应的,也有几个缺点:
- 可能不可用;
- 会被其他应用读到;
- 在非App路径下写、修改文件需要权限。
Primary vs Secondary
这个Primary和Secondary是怎么来的呢?实际上最开始Android也没有考虑这个区分,但是后来有一个情况发生了,就是上面所说到的:
后来部分手机开始将最初定义的“Internal Storage”,即内置存储,分成Internal和External两部分。
那么如果这个时候手机再插入sd卡,那不是有多个External Storage了吗?
这个时候,从Internal Storage里面分出来的那块“External Storage”我们称之为主存储(Primary Storage),插入的外置储存称之为副存储(Secondary Storage)。
副存储路径在4.4及以上的Android系统中,可以使用Context.getExternalFilesDirs(null)(注意最后多了一个’s’),它返回的是一个字符串数组。第0个就是主存储路径,第1个是副存储路径(如果有的话)。
注:以上内容转载自:https://blog.csdn.net/tanranran/article/details/51386106
Adaptable Storage
Adoptable Storage Devices使系统获得了更大的存储容量,并且使用户可以自由移动应用和隐私数据到外部存储设备,不在需要第三方工具。用户使用Android设备时,可以主动的选择把外部存储设备格式化为常规移动存储或者系统内部存储。在格式化时系统给了两种选择:(1)Use as portable storage(for moving photos and other media between divices),仅仅作为外部存储设备;(2)Use as internal storage(for storing anything on this device only,including apps and photos),包裹一个加密层后,能够作为内部存储空间存储应用和隐私数据,经过加密后,该存储设备就不能再被别的设备使用。
底层处过程
下面是插入SD卡后截取的logcat main log信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
01-02 04:56:21.301 1675 1907 D VoldConnector: RCV <- {640 disk:179,64 7} 01-02 04:56:21.303 1675 1907 D VoldConnector: RCV <- {641 disk:179,64 15836643328} 01-02 04:56:21.304 1675 1907 D VoldConnector: RCV <- {642 disk:179,64 } 01-02 04:56:21.304 1675 1907 D VoldConnector: RCV <- {644 disk:179,64 /sys//devices/soc/7864900.sdhci/mmc_host/mmc1/mmc1:59b4/block/mmcblk1} 01-02 04:56:21.305 481 483 V vold : /system/bin/sgdisk 01-02 04:56:21.305 481 483 V vold : --android-dump 01-02 04:56:21.305 481 483 V vold : /dev/block/vold/disk:179,64 01-02 04:56:21.358 481 483 V vold : DISK mbr 01-02 04:56:21.358 481 483 V vold : 01-02 04:56:21.358 481 483 V vold : PART 1 c 01-02 04:56:21.358 481 483 V vold : 01-02 04:56:21.362 1675 1907 D VoldConnector: RCV <- {650 public:179,65 0 "disk:179,64" ""} 01-02 04:56:21.363 1675 1907 D VoldConnector: RCV <- {651 public:179,65 0} 01-02 04:56:21.363 1675 1906 D VoldConnector: SND -> {7 volume mount public:179,65 2 0} 01-02 04:56:21.363 1675 1907 D VoldConnector: RCV <- {643 disk:179,64} 01-02 04:56:21.364 481 484 V vold : /system/bin/blkid 01-02 04:56:21.364 481 484 V vold : -c 01-02 04:56:21.364 1675 1907 D VoldConnector: RCV <- {651 public:179,65 1} 01-02 04:56:21.364 481 484 V vold : /dev/null 01-02 04:56:21.364 481 484 V vold : -s 01-02 04:56:21.364 481 484 V vold : TYPE 01-02 04:56:21.364 481 484 V vold : -s 01-02 04:56:21.364 481 484 V vold : UUID 01-02 04:56:21.364 481 484 V vold : -s 01-02 04:56:21.364 481 484 V vold : LABEL 01-02 04:56:21.364 481 484 V vold : /dev/block/vold/public:179,65 01-02 04:56:21.365 2003 2003 D StorageNotification: Notifying about public volume: VolumeInfo{public:179,65}: 01-02 04:56:21.365 2003 2003 D StorageNotification: type=PUBLIC diskId=disk:179,64 partGuid=null mountFlags=VISIBLE 01-02 04:56:21.365 2003 2003 D StorageNotification: mountUserId=0 state=UNMOUNTED 01-02 04:56:21.365 2003 2003 D StorageNotification: fsType=null fsUuid=null fsLabel=null 01-02 04:56:21.365 2003 2003 D StorageNotification: path=null internalPath=null 01-02 04:56:21.367 2003 2003 D StorageNotification: Notifying about public volume: VolumeInfo{public:179,65}: 01-02 04:56:21.367 2003 2003 D StorageNotification: type=PUBLIC diskId=disk:179,64 partGuid=null mountFlags=VISIBLE 01-02 04:56:21.367 2003 2003 D StorageNotification: mountUserId=0 state=CHECKING 01-02 04:56:21.367 2003 2003 D StorageNotification: fsType=null fsUuid=null fsLabel=null 01-02 04:56:21.367 2003 2003 D StorageNotification: path=null internalPath=null 01-02 04:56:21.463 481 484 V vold : /dev/block/vold/public:179,65: UUID="9016-4EF8" TYPE="vfat" 01-02 04:56:21.463 481 484 V vold : 01-02 04:56:21.466 1675 1907 D VoldConnector: RCV <- {652 public:179,65 vfat} 01-02 04:56:21.466 1675 1907 D VoldConnector: RCV <- {653 public:179,65 9016-4EF8} 01-02 04:56:21.467 481 484 V vold : /system/bin/fsck_msdos 01-02 04:56:21.467 481 484 V vold : -p 01-02 04:56:21.467 481 484 V vold : -f 01-02 04:56:21.467 481 484 V vold : /dev/block/vold/public:179,65 01-02 04:56:21.467 1675 1907 D VoldConnector: RCV <- {654 public:179,65 } 01-02 04:56:21.505 481 484 I fsck_msdos: ** /dev/block/vold/public:179,65 01-02 04:56:21.508 481 484 I fsck_msdos: ** Phase 1 - Read and Compare FATs 01-02 04:56:21.508 481 484 I fsck_msdos: Attempting to allocate 1887 KB for FAT 01-02 04:56:21.653 481 484 I fsck_msdos: Attempting to allocate 1887 KB for FAT 01-02 04:56:21.722 481 484 I fsck_msdos: ** Phase 2 - Check Cluster Chains 01-02 04:56:21.734 481 484 I fsck_msdos: ** Phase 3 - Checking Directories 01-02 04:56:21.808 481 484 I fsck_msdos: ** Phase 4 - Checking for Lost Files 01-02 04:56:21.812 481 484 I fsck_msdos: 195 files, 3988544 free (386786 clusters) 01-02 04:56:21.827 481 484 I Vold : Filesystem check completed OK 01-02 04:56:21.827 1675 1907 D VoldConnector: RCV <- {656 public:179,65 /mnt/media_rw/9016-4EF8} 01-02 04:56:21.828 1675 1907 D VoldConnector: RCV <- {655 public:179,65 /storage/9016-4EF8} 01-02 04:56:21.857 481 484 V vold : Waiting for FUSE to spin up... 01-02 04:56:21.885 3452 3452 W /system/bin/sdcard: Device explicitly enabled sdcardfs 01-02 04:56:21.908 1675 1907 D VoldConnector: RCV <- {651 public:179,65 2} 01-02 04:56:21.909 1675 1907 D VoldConnector: RCV <- {200 7 Command succeeded} 01-02 04:56:21.909 1675 1906 E VoldConnector: NDC Command {7 volume mount public:179,65 2 0} took too long (546ms) 01-02 04:56:21.910 1675 1906 D StorageManagerService: Volume public:179,65 broadcasting checking to UserHandle{0} 01-02 04:56:21.926 2003 2003 D StorageNotification: Notifying about public volume: VolumeInfo{public:179,65}: 01-02 04:56:21.926 2003 2003 D StorageNotification: type=PUBLIC diskId=disk:179,64 partGuid=null mountFlags=VISIBLE 01-02 04:56:21.926 2003 2003 D StorageNotification: mountUserId=0 state=MOUNTED 01-02 04:56:21.926 2003 2003 D StorageNotification: fsType=vfat fsUuid=9016-4EF8 fsLabel= 01-02 04:56:21.926 2003 2003 D StorageNotification: path=/storage/9016-4EF8 internalPath=/mnt/media_rw/9016-4EF8 01-02 04:56:21.973 1675 1906 D StorageManagerService: Volume public:179,65 broadcasting mounted to UserHandle{0} 01-02 04:56:22.080 3453 3453 D ExternalStorage: After updating volumes, found 3 active roots 01-02 04:56:22.089 3453 3453 D ExternalStorage: After updating volumes, found 3 active roots 01-02 04:56:22.093 3453 3453 D ExternalStorage: After updating volumes, found 3 active roots 01-02 04:56:22.114 2886 2886 D MediaScannerReceiver: action: android.intent.action.MEDIA_MOUNTED path: /storage/9016-4EF8 01-02 04:56:22.310 2886 3469 W MediaScanner: Error opening directory '/storage/9016-4EF8/.android_secure/', skipping: Permission denied. |
至于最底层内核驱动上报插入SD卡部分这里就不分析了。我们直接从NetlinkHandler::onEvent()接收到插入SD卡事件通知开始。
NetlinkHandler::onEvent
NetlinkHandler::onEvent方法存在两个NetlinkHandler.cpp文件中,这里我们涉及的是vold下的NetlinkHandler::onEvent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void NetlinkHandler::onEvent(NetlinkEvent *evt) { // 单例模式,获取VolumeManager VolumeManager *vm = VolumeManager::Instance(); const char *subsys = evt->getSubsystem(); if (!subsys) { SLOGW("No subsystem found in netlink event"); return; } // block事件,调用VolumeManager的handleBlockEvent方法处理 if (!strcmp(subsys, "block")) { vm->handleBlockEvent(evt); } } |
此处对底层过滤选择底层上报的事件,具体是处理block事件
VolumeManager::handleBlockEvent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) { std::lock_guard<std::mutex> lock(mLock); // 定义为Debug的时候打印调试log if (mDebug) { LOG(VERBOSE) << "----------------"; LOG(VERBOSE) << "handleBlockEvent with action " << (int) evt->getAction(); evt->dump(); } std::string eventPath(evt->findParam("DEVPATH")?evt->findParam("DEVPATH"):""); std::string devType(evt->findParam("DEVTYPE")?evt->findParam("DEVTYPE"):""); if (devType != "disk") return; // 获取节点的major和minor int major = atoi(evt->findParam("MAJOR")); int minor = atoi(evt->findParam("MINOR")); // 创建节点 dev_t device = makedev(major, minor); switch (evt->getAction()) { // Add事件处理,我们主要分析这部分 case NetlinkEvent::Action::kAdd: { for (const auto& source : mDiskSources) { if (source->matches(eventPath)) { // 判断设备类型,这里是SD卡类型 int flags = source->getFlags(); if (major == kMajorBlockMmc || (eventPath.find("ufs") != std::string::npos) || (android::vold::IsRunningInEmulator() && major >= (int) kMajorBlockExperimentalMin && major <= (int) kMajorBlockExperimentalMax)) { flags |= android::vold::Disk::Flags::kSd; } else { flags |= android::vold::Disk::Flags::kUsb; } // 根据获取的信息创建一个disk类信息,然后将其push到mDisk链表中 // 下面分析Disk创建过程 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; } case NetlinkEvent::Action::kChange: { LOG(DEBUG) << "Disk at " << major << ":" << minor << " changed"; for (const auto& disk : mDisks) { if (disk->getDevice() == device) { disk->readMetadata(); disk->readPartitions(); } } break; } case NetlinkEvent::Action::kRemove: { auto i = mDisks.begin(); while (i != mDisks.end()) { if ((*i)->getDevice() == device) { (*i)->destroy(); i = mDisks.erase(i); } else { ++i; } } break; } default: { LOG(WARNING) << "Unexpected block event action " << (int) evt->getAction(); break; } } } |
Disk::Disk
1 2 3 4 5 6 7 8 9 10 11 12 |
Disk::Disk(const std::string& eventPath, dev_t device, const std::string& nickname, int flags) : // 初始化类成员变量 mDevice(device), mSize(-1), mNickname(nickname), mFlags(flags), mCreated( false), mJustPartitioned(false) { mId = StringPrintf("disk:%u,%u", major(device), minor(device)); mEventPath = eventPath; mSysPath = StringPrintf("/sys/%s", eventPath.c_str()); mDevPath = StringPrintf("/dev/block/vold/%s", mId.c_str()); // 创建设备节点,并设置Selinux类型 CreateDeviceNode(mDevPath, mDevice); } |
调用Disk类的构造函数后,接着就调用Disk类的create方法,接下来我们看看create的实现。
Disk::create
1 2 3 4 5 6 7 8 9 10 11 |
status_t Disk::create() { CHECK(!mCreated); mCreated = true; // 发出事件通知 notifyEvent(ResponseCode::DiskCreated, StringPrintf("%d", mFlags)); // 读取SD卡元数据 readMetadata(); // 读取SD卡分区表 readPartitions(); return OK; } |
首先发出DiskCreated事件通知,对应的log就是上面贴出的main log的第一句:
1 |
01-02 04:56:21.301 1675 1907 D VoldConnector: RCV <- {640 disk:179,64 7} |
Disk::readMetadata
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
status_t Disk::readMetadata() { mSize = -1; mLabel.clear(); // 打开SD卡设备 int fd = open(mDevPath.c_str(), O_RDONLY | O_CLOEXEC); // 通过BLKGETSIZE64 IOCTL方法获取SD卡容量大小 if (fd != -1) { if (ioctl(fd, BLKGETSIZE64, &mSize)) { mSize = -1; } close(fd); } unsigned int majorId = major(mDevice); switch (majorId) { case kMajorBlockLoop: { mLabel = "Virtual"; break; } case kMajorBlockScsiA: case kMajorBlockScsiB: case kMajorBlockScsiC: case kMajorBlockScsiD: case kMajorBlockScsiE: case kMajorBlockScsiF: case kMajorBlockScsiG: case kMajorBlockScsiH: case kMajorBlockScsiI: case kMajorBlockScsiJ: case kMajorBlockScsiK: case kMajorBlockScsiL: case kMajorBlockScsiM: case kMajorBlockScsiN: case kMajorBlockScsiO: case kMajorBlockScsiP: { std::string path(mSysPath + "/device/vendor"); std::string tmp; if (!ReadFileToString(path, &tmp)) { PLOG(WARNING) << "Failed to read vendor from " << path; return -errno; } mLabel = tmp; break; } // 通过上面第一句main log信息,显示设备类型179,对应的是KMajorBlockMmc case kMajorBlockMmc: { std::string path(mSysPath + "/device/manfid"); std::string tmp; if (!ReadFileToString(path, &tmp)) { PLOG(WARNING) << "Failed to read manufacturer from " << path; return -errno; } uint64_t manfid = strtoll(tmp.c_str(), nullptr, 16); // 读取SD卡制造商信息,用的杂牌SD卡,不在此列 switch (manfid) { case 0x000003: mLabel = "SanDisk"; break; case 0x00001b: mLabel = "Samsung"; break; case 0x000028: mLabel = "Lexar"; break; case 0x000074: mLabel = "Transcend"; break; } break; } default: { if (isVirtioBlkDevice(majorId)) { LOG(DEBUG) << "Recognized experimental block major ID " << majorId << " as virtio-blk (emulator's virtual SD card device)"; mLabel = "Virtual"; break; } LOG(WARNING) << "Unsupported block major type " << majorId; return -ENOTSUP; } } // 发出三个事件通知 notifyEvent(ResponseCode::DiskSizeChanged, StringPrintf("%" PRIu64, mSize)); notifyEvent(ResponseCode::DiskLabelChanged, mLabel); notifyEvent(ResponseCode::DiskSysPathChanged, mSysPath); return OK; } |
上面代码中最后三个事件通知对应下面main log信息:
1 2 3 |
01-02 04:56:21.303 1675 1907 D VoldConnector: RCV <- {641 disk:179,64 15836643328} 01-02 04:56:21.304 1675 1907 D VoldConnector: RCV <- {642 disk:179,64 } 01-02 04:56:21.304 1675 1907 D VoldConnector: RCV <- {644 disk:179,64 /sys//devices/soc/7864900.sdhci/mmc_host/mmc1/mmc1:59b4/block/mmcblk1} |
从log中获取到的信息为,mSize=15836643328,mLabel为空,mSysPath为/sys//devices/soc/7864900.sdhci/mmc_host/mmc1/mmc1:59b4/block/mmcblk1
Disk::readPartitions
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
status_t Disk::readPartitions() { int8_t maxMinors = getMaxMinors(); if (maxMinors < 0) { return -ENOTSUP; } destroyAllVolumes(); // Parse partition table // 构建sgdisk命令行,sgdisk是Linux下的操作GPT分区的工具 // 此处用来获取SD卡的分区信息 std::vector<std::string> cmd; cmd.push_back(kSgdiskPath); cmd.push_back("--android-dump"); cmd.push_back(mDevPath); std::vector<std::string> output; // Fork一个进程来操作sgdisk,执行的返回信息在下面列出,大家可以先去查看 status_t res = ForkExecvp(cmd, output); if (res != OK) { LOG(WARNING) << "sgdisk failed to scan " << mDevPath; notifyEvent(ResponseCode::DiskScanned); mJustPartitioned = false; return res; } Table table = Table::kUnknown; bool foundParts = false; // for循环解析执行结果 for (const auto& line : output) { char* cline = (char*) line.c_str(); char* token = strtok(cline, kSgdiskToken); if (token == nullptr) continue; // 获取到的token就是DISK if (!strcmp(token, "DISK")) { const char* type = strtok(nullptr, kSgdiskToken); // SD卡的分区类型是mbr if (!strcmp(type, "mbr")) { table = Table::kMbr; } else if (!strcmp(type, "gpt")) { table = Table::kGpt; } // 下一个对应的tocken为PART } else if (!strcmp(token, "PART")) { foundParts = true; int i = strtol(strtok(nullptr, kSgdiskToken), nullptr, 10); if (i <= 0 || i > maxMinors) { LOG(WARNING) << mId << " is ignoring partition " << i << " beyond max supported devices"; continue; } dev_t partDevice = makedev(major(mDevice), minor(mDevice) + i); // MBR分区方式 if (table == Table::kMbr) { const char* type = strtok(nullptr, kSgdiskToken); // type为c,所以分区格式是FAT32 switch (strtol(type, nullptr, 16)) { case 0x06: // FAT16 case 0x0b: // W95 FAT32 (LBA) case 0x0c: // W95 FAT32 (LBA) case 0x0e: // W95 FAT16 (LBA) // 调用createPublicVolume,创建PUBLIC类型Volume createPublicVolume(partDevice); break; } } else if (table == Table::kGpt) { const char* typeGuid = strtok(nullptr, kSgdiskToken); const char* partGuid = strtok(nullptr, kSgdiskToken); if (!strcasecmp(typeGuid, kGptBasicData)) { createPublicVolume(partDevice); } else if (!strcasecmp(typeGuid, kGptAndroidExpand)) { createPrivateVolume(partDevice, partGuid); } } } } // Ugly last ditch effort, treat entire disk as partition if (table == Table::kUnknown || !foundParts) { LOG(WARNING) << mId << " has unknown partition table; trying entire device"; std::string fsType; std::string unused; if (ReadMetadataUntrusted(mDevPath, fsType, unused, unused) == OK) { createPublicVolume(mDevice); } else { LOG(WARNING) << mId << " failed to identify, giving up"; } } // 发出DiskScanned事件通知 notifyEvent(ResponseCode::DiskScanned); mJustPartitioned = false; return OK; } |
执行sgdisk过程输出的log信息如下:
1 2 3 4 5 6 7 |
01-02 04:56:21.305 481 483 V vold : /system/bin/sgdisk 01-02 04:56:21.305 481 483 V vold : --android-dump 01-02 04:56:21.305 481 483 V vold : /dev/block/vold/disk:179,64 01-02 04:56:21.358 481 483 V vold : DISK mbr 01-02 04:56:21.358 481 483 V vold : 01-02 04:56:21.358 481 483 V vold : PART 1 c 01-02 04:56:21.358 481 483 V vold : |
其中DISK mbr
和PART 1 c
是执行sgdisk的返回值。
最后调用Disk::createPublicVolume来创建Volume,下面接着分析Volume的创建过程
Disk::createPublicVolume
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
void Disk::createPublicVolume(dev_t device) { // vol为VolumeBase型指针,实际指向PublicVolume类型 auto vol = std::shared_ptr<VolumeBase>(new PublicVolume(device)); // mJustPartitioned为false if (mJustPartitioned) { LOG(DEBUG) << "Device just partitioned; silently formatting"; vol->setSilent(true); vol->create(); vol->format("auto"); vol->destroy(); vol->setSilent(false); } // 将vol添加到mVolumes链表 mVolumes.push_back(vol); // PublicVolume没有实现setDiskId方法,调用的是基类的setDiskId vol->setDiskId(getId()); // PublicVolume没有实现create方法,调用的是基类的create vol->create(); } |
setDiskId没什么好分析的,接下来分析create方法
VolumeBase::create
1 2 3 4 5 6 7 8 9 10 11 12 |
status_t VolumeBase::create() { CHECK(!mCreated); mCreated = true; // 这里看的是PubicVolume的doCreate status_t res = doCreate(); // 发出VolumeCreated事件通知 notifyEvent(ResponseCode::VolumeCreated, StringPrintf("%d \"%s\" \"%s\"", mType, mDiskId.c_str(), mPartGuid.c_str())); setState(State::kUnmounted); return res; } |
volumeCreated事件通知对应如下log:
1 |
01-02 04:56:21.362 1675 1907 D VoldConnector: RCV <- {650 public:179,65 0 "disk:179,64" ""} |
到这里Volume相关操作就完成了,这里返回到Disk::readPartitions方法中,Disk::readPartitions最后会发出一个Disk::readPartitions事件通知,对应的log如下:
1 |
01-02 04:56:21.363 1675 1907 D VoldConnector: RCV <- {643 disk:179,64} |
StorageManagerService处理过程
底层中通过notifyEvent发出的事件,在上次会通过StorageManagerService::onEventLocked来进行统一处理
StorageManagerService::onEventLocked
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
private boolean onEventLocked(int code, String raw, String[] cooked) { // 根据传入的code做判断 switch (code) { // 对应的notifyEvent事件是DiskCreated // 对应log信息:{640 disk:179,64 7} case VoldResponseCode.DISK_CREATED: { if (cooked.length != 3) break; final String id = cooked[1]; int flags = Integer.parseInt(cooked[2]); // 判断persist.fw.force_adoptable属性是否为true或者mForceAdoptable是否为true if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false) || mForceAdoptable) { flags |= DiskInfo.FLAG_ADOPTABLE; } // Adoptable storage isn't currently supported on FBE devices // Adoptable存储目前在FBE设备上不支持 if (StorageManager.isFileEncryptedNativeOnly() && !SystemProperties.getBoolean(StorageManager.PROP_ADOPTABLE_FBE, false)) { flags &= ~DiskInfo.FLAG_ADOPTABLE; } // 根据传入的信息创建DiskInfo信息,并添加到mDisks ArrayMap中 mDisks.put(id, new DiskInfo(id, flags)); break; } // 对应log信息:{641 disk:179,64 15836643328} case VoldResponseCode.DISK_SIZE_CHANGED: { if (cooked.length != 3) break; // 将SD卡大小保存到DiskInfo中 final DiskInfo disk = mDisks.get(cooked[1]); if (disk != null) { disk.size = Long.parseLong(cooked[2]); } break; } // 对应log信息:{642 disk:179,64 } case VoldResponseCode.DISK_LABEL_CHANGED: { final DiskInfo disk = mDisks.get(cooked[1]); if (disk != null) { final StringBuilder builder = new StringBuilder(); for (int i = 2; i < cooked.length; i++) { builder.append(cooked[i]).append(' '); } disk.label = builder.toString().trim(); } break; } case VoldResponseCode.DISK_SCANNED: { if (cooked.length != 2) break; final DiskInfo disk = mDisks.get(cooked[1]); if (disk != null) { onDiskScannedLocked(disk); } break; } // 对应log信息:{644 disk:179,64 /sys//devices/soc/7864900.sdhci/mmc_host/mmc1/mmc1:59b4/block/mmcblk1} case VoldResponseCode.DISK_SYS_PATH_CHANGED: { if (cooked.length != 3) break; final DiskInfo disk = mDisks.get(cooked[1]); if (disk != null) { disk.sysPath = cooked[2]; } break; } case VoldResponseCode.DISK_DESTROYED: { if (cooked.length != 2) break; final DiskInfo disk = mDisks.remove(cooked[1]); if (disk != null) { mCallbacks.notifyDiskDestroyed(disk); } break; } // 对应log信息:{650 public:179,65 0 "disk:179,64" ""} 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); // 创建VolumeInfo,并添加到mVolumes中 final VolumeInfo vol = new VolumeInfo(id, type, disk, partGuid); mVolumes.put(id, vol); // 调用onVolumeCreateLocked onVolumeCreatedLocked(vol); break; } // 对应log信息:{651 public:179,65 0} 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; } case VoldResponseCode.VOLUME_FS_TYPE_CHANGED: { if (cooked.length != 3) break; final VolumeInfo vol = mVolumes.get(cooked[1]); if (vol != null) { vol.fsType = cooked[2]; } break; } case VoldResponseCode.VOLUME_FS_UUID_CHANGED: { if (cooked.length != 3) break; final VolumeInfo vol = mVolumes.get(cooked[1]); if (vol != null) { vol.fsUuid = cooked[2]; } break; } case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: { final VolumeInfo vol = mVolumes.get(cooked[1]); if (vol != null) { final StringBuilder builder = new StringBuilder(); for (int i = 2; i < cooked.length; i++) { builder.append(cooked[i]).append(' '); } vol.fsLabel = builder.toString().trim(); } // TODO: notify listeners that label changed break; } 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; } case VoldResponseCode.VOLUME_DESTROYED: { if (cooked.length != 2) break; mVolumes.remove(cooked[1]); break; } case VoldResponseCode.MOVE_STATUS: { final int status = Integer.parseInt(cooked[1]); onMoveStatusLocked(status); break; } case VoldResponseCode.BENCHMARK_RESULT: { if (cooked.length != 7) break; final String path = cooked[1]; final String ident = cooked[2]; final long create = Long.parseLong(cooked[3]); final long drop = Long.parseLong(cooked[4]); final long run = Long.parseLong(cooked[5]); final long destroy = Long.parseLong(cooked[6]); final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class); dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path) + " " + ident + " " + create + " " + run + " " + destroy); final VolumeRecord rec = findRecordForPath(path); if (rec != null) { rec.lastBenchMillis = System.currentTimeMillis(); writeSettingsLocked(); } break; } case VoldResponseCode.TRIM_RESULT: { if (cooked.length != 4) break; final String path = cooked[1]; final long bytes = Long.parseLong(cooked[2]); final long time = Long.parseLong(cooked[3]); final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class); dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path) + " " + bytes + " " + time); final VolumeRecord rec = findRecordForPath(path); if (rec != null) { rec.lastTrimMillis = System.currentTimeMillis(); writeSettingsLocked(); } break; } default: { Slog.d(TAG, "Unhandled vold event " + code); } } return true; } |
上面只添加了到目前为止遇到的log信息,之后再mount的时候还会有新的event log信息,到后面遇到再添加分析。这里我们主要看VOLUME_CREATED相关的内容,VOLUME_CREATED相关操作主要是通过调用onVolumeCreatedLocked来创建volume
StorageManagerService::onVolumeCreatedLocked
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
private void onVolumeCreatedLocked(VolumeInfo vol) { if (mPms.isOnlyCoreApps()) { Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId()); return; } if (vol.type == VolumeInfo.TYPE_EMULATED) { ...................... } else if (vol.type == VolumeInfo.TYPE_PUBLIC) { // TODO: only look at first public partition if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid) && vol.disk.isDefaultPrimary()) { 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()) { vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE; } vol.mountUserId = mCurrentUserId; mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget(); } else if (vol.type == VolumeInfo.TYPE_PRIVATE) { ................ |
我们这里mount的是PUBLIC设备,所以其余部分就省略了,另外从代码中看,也只是设置了一些标识位,这里较多关于Adoptable存储的相关设置的,可惜设备使用的是FBE,所以这里不能使用Adoptable存储方式,这样也就会导致MOUNT_FLAG_VISIBLE为也会被设置为false。导致通过MTP在PC端或者其他的FileManager APP都无法查看SD卡内的文件。最后通过mHandler发出H_VOLUME_MOUNT。
H_VOLUME_MOUNT处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public void handleMessage(Message msg) { switch (msg.what) { ......... 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; } ......... |
继续忽略不相关部分,只做主要的分析。这里其实也简单,只是通过mConnect,给vold发送相关指令,告诉vold需要需要执行什么操作而已。这个指令通过socket最终由vold的CommandListener::VolumeCmd::runCommand来处理,这行代码对应的log如下:
1 |
01-02 04:56:21.363 1675 1906 D VoldConnector: SND -> {7 volume mount public:179,65 2 0} |
CommandListener::VolumeCmd::runCommand
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
int CommandListener::VolumeCmd::runCommand(SocketClient *cli, int argc, char **argv) { dumpArgs(argc, argv, -1); if (argc < 2) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false); return 0; } VolumeManager *vm = VolumeManager::Instance(); std::lock_guard<std::mutex> lock(vm->getLock()); // TODO: tease out methods not directly related to volumes std::string cmd(argv[1]); if (cmd == "reset") { ............ } 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); } // 获取volume的mount flags int mountFlags = (argc > 3) ? atoi(argv[3]) : 0; // 获取volume的mount user ID userid_t mountUserId = (argc > 4) ? atoi(argv[4]) : -1; vol->setMountFlags(mountFlags); vol->setMountUserId(mountUserId); // 调用vol的mount方法 int res = vol->mount(); if (mountFlags & android::vold::VolumeBase::MountFlags::kPrimary) { vm->setPrimary(vol); } // 将结果返回 return sendGenericOkFail(cli, res); } else if (cmd == "unmount" && argc > 2) { .......... return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false); } |
在此之前,我们创建过PublicVolume类型的变量,并添加到链表里面了,这里取出之前创建的PublicVolume类型的变量。并调用其mount方法,但是因为PublicVolume没有实现mount方法,所以这里调用的是基类VolumeBase的mount方法。
VolumeBase::mount
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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); // 调用doMount方法完成剩余工作 status_t res = doMount(); if (res == OK) { setState(State::kMounted); } else { setState(State::kUnmountable); } return res; } |
PublicVolume::doMount
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
status_t PublicVolume::doMount() { // 首先调用readMetadata获取分区信息 readMetadata(); if (mFsType != "vfat") { LOG(ERROR) << getId() << " unsupported filesystem " << mFsType; return -EIO; } // 调用Check方法,对SD卡进行检查并修复文件系统错误 if (vfat::Check(mDevPath)) { LOG(ERROR) << getId() << " failed filesystem check"; return -EIO; } // 获取分配的UUID 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); // 判断是否带有VISUAL flags 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; } // 调用vfat的mount方法 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(); } // 如果没有设置VISUAL flag,直接返回 if (!(getMountFlags() & MountFlags::kVisible)) { // Not visible to apps, so no need to spin up FUSE return OK; } // 创建fuse相关文件路径 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 mount points"; return -errno; } dev_t before = GetDevice(mFuseWrite); // fork创建进程,并在子进程中执行如下操作 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 { // public类型的设备执行 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 } /* sdcardfs will have exited already. FUSE will still be running */ TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, WNOHANG)); return OK; } |
PublicVolume::readMetadata
1 2 3 4 5 6 7 8 9 10 |
status_t PublicVolume::readMetadata() { // 调用utils的ReadMetadataUntrusted status_t res = ReadMetadataUntrusted(mDevPath, mFsType, mFsUuid, mFsLabel); // 发出三个事件通知 notifyEvent(ResponseCode::VolumeFsTypeChanged, mFsType); notifyEvent(ResponseCode::VolumeFsUuidChanged, mFsUuid); notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel); return res; } |
readMetadata完成两件事,首先调用Utils.cpp中的ReadMetadataUntrusted方法,而后者继续调用Utils.cpp的readMetadata;其次调用notifyEvent发出三个事件通知,对应的log如下:
1 2 3 |
01-02 04:56:21.466 1675 1907 D VoldConnector: RCV <- {652 public:179,65 vfat} 01-02 04:56:21.466 1675 1907 D VoldConnector: RCV <- {653 public:179,65 9016-4EF8} 01-02 04:56:21.467 1675 1907 D VoldConnector: RCV <- {654 public:179,65 } |
Utils::readMetadata
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
static status_t readMetadata(const std::string& path, std::string& fsType, std::string& fsUuid, std::string& fsLabel, bool untrusted) { // 清除变量信息 fsType.clear(); fsUuid.clear(); fsLabel.clear(); // 生成blkid获取SD卡分区的各项信息,例如TYPE,UUID等 std::vector<std::string> cmd; cmd.push_back(kBlkidPath); cmd.push_back("-c"); cmd.push_back("/dev/null"); cmd.push_back("-s"); cmd.push_back("TYPE"); cmd.push_back("-s"); cmd.push_back("UUID"); cmd.push_back("-s"); cmd.push_back("LABEL"); cmd.push_back(path); std::vector<std::string> output; // status_t res = ForkExecvp(cmd, output, untrusted ? sBlkidUntrustedContext : sBlkidContext); if (res != OK) { LOG(WARNING) << "blkid failed to identify " << path; return res; } char value[128]; // 读取分析blkid的返回值 for (const auto& line : output) { // Extract values from blkid output, if defined const char* cline = line.c_str(); // 读取blkid返回的TYPE值 const char* start = strstr(cline, "TYPE="); if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) { fsType = value; } // 读取blkid返回的UUID值 start = strstr(cline, "UUID="); if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) { fsUuid = value; } // 读取blkid返回的LABEL值 start = strstr(cline, "LABEL="); if (start != nullptr && sscanf(start + 6, "\"%127[^\"]\"", value) == 1) { fsLabel = value; } } return OK; } |
readMetadata执行blkid的相应log信息如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
--------------调用的log 01-02 04:56:21.364 481 484 V vold : /system/bin/blkid 01-02 04:56:21.364 481 484 V vold : -c 01-02 04:56:21.364 481 484 V vold : /dev/null 01-02 04:56:21.364 481 484 V vold : -s 01-02 04:56:21.364 481 484 V vold : TYPE 01-02 04:56:21.364 481 484 V vold : -s 01-02 04:56:21.364 481 484 V vold : UUID 01-02 04:56:21.364 481 484 V vold : -s 01-02 04:56:21.364 481 484 V vold : LABEL 01-02 04:56:21.364 481 484 V vold : /dev/block/vold/public:179,65 -------------返回的结果 01-02 04:56:21.463 481 484 V vold : /dev/block/vold/public:179,65: UUID="9016-4EF8" TYPE="vfat" 01-02 04:56:21.463 481 484 V vold : |
到这里readMetadata方法的执行就结束了。接下来我们继续看doMount中关键的第二个方法vfat::Check
vFat::Check
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
status_t Check(const std::string& source) { // 检查fsck_msdos是否有执行权限 if (access(kFsckPath, X_OK)) { SLOGW("Skipping fs checks\n"); return 0; } int pass = 1; int rc = 0; do { // 构建执行命令行 std::vector<std::string> cmd; cmd.push_back(kFsckPath); cmd.push_back("-p"); cmd.push_back("-f"); cmd.push_back(source); // Fat devices are currently always untrusted rc = ForkExecvp(cmd, sFsckUntrustedContext); if (rc < 0) { SLOGE("Filesystem check failed due to logwrap error"); errno = EIO; return -1; } // 根据执行结果做判断 switch(rc) { case 0: SLOGI("Filesystem check completed OK"); return 0; case 2: SLOGE("Filesystem check failed (not a FAT filesystem)"); errno = ENODATA; return -1; case 4: if (pass++ <= 3) { SLOGW("Filesystem modified - rechecking (pass %d)", pass); continue; } SLOGE("Failing check after too many rechecks"); errno = EIO; return -1; case 8: SLOGE("Filesystem check failed (no filesystem)"); errno = ENODATA; return -1; default: SLOGE("Filesystem check failed (unknown exit code %d)", rc); errno = EIO; return -1; } } while (0); return 0; } |
上面执行对应的log如下:
1 2 3 4 5 6 7 8 9 10 11 12 |
01-02 04:56:21.467 481 484 V vold : /system/bin/fsck_msdos 01-02 04:56:21.467 481 484 V vold : -p 01-02 04:56:21.467 481 484 V vold : -f 01-02 04:56:21.467 481 484 V vold : /dev/block/vold/public:179,65 01-02 04:56:21.505 481 484 I fsck_msdos: ** /dev/block/vold/public:179,65 01-02 04:56:21.508 481 484 I fsck_msdos: ** Phase 1 - Read and Compare FATs 01-02 04:56:21.508 481 484 I fsck_msdos: Attempting to allocate 1887 KB for FAT 01-02 04:56:21.722 481 484 I fsck_msdos: ** Phase 2 - Check Cluster Chains 01-02 04:56:21.734 481 484 I fsck_msdos: ** Phase 3 - Checking Directories 01-02 04:56:21.808 481 484 I fsck_msdos: ** Phase 4 - Checking for Lost Files 01-02 04:56:21.812 481 484 I fsck_msdos: 195 files, 3988544 free (386786 clusters) 01-02 04:56:21.827 481 484 I Vold : Filesystem check completed OK |
至于fsck_msdos所完成的工作就不在此文讨论,有兴趣的朋友可以在网上搜到相关资料,后续有机会再分析。接下来我们接着看doMount后面的内容,下面就到设置路径了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
--------------------doMount节选 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); // mount的时候有带VISUAL标志 if (getMountFlags() & MountFlags::kVisible) { setPath(StringPrintf("/storage/%s", stableName.c_str())); } else { setPath(mRawPath); } |
VolumeBase::setInternalPath
1 2 3 4 5 6 7 8 9 10 11 12 |
status_t VolumeBase::setInternalPath(const std::string& internalPath) { if (mState != State::kChecking) { LOG(WARNING) << getId() << " internal path change requires state checking"; return -EBUSY; } // 设置Internal的路径为"/mnt/media_rw/%s",%s代表Label名 mInternalPath = internalPath; // 发出notifyEvent notifyEvent(ResponseCode::VolumeInternalPathChanged, mInternalPath); return OK; } |
对应log:
1 |
01-02 04:56:21.827 1675 1907 D VoldConnector: RCV <- {656 public:179,65 /mnt/media_rw/9016-4EF8} |
VolumeBase::setPath
1 2 3 4 5 6 7 8 9 10 11 12 |
status_t VolumeBase::setPath(const std::string& path) { if (mState != State::kChecking) { LOG(WARNING) << getId() << " path change requires state checking"; return -EBUSY; } // 设置path为"/storage/%s",%s代表Label名 mPath = path; // 发出notifyEvent notifyEvent(ResponseCode::VolumePathChanged, mPath); return OK; } |
对应log:
1 |
01-02 04:56:21.828 1675 1907 D VoldConnector: RCV <- {655 public:179,65 /storage/9016-4EF8} |
接下来继续回到doMount,下面就到vfat:Mount了
vfat::Mount
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
status_t Mount(const std::string& source, const std::string& target, bool ro, bool remount, bool executable, int ownerUid, int ownerGid, int permMask, bool createLost) { int rc; unsigned long flags; char mountData[255]; // 挂载源和挂载点 const char* c_source = source.c_str(); const char* c_target = target.c_str(); flags = MS_NODEV | MS_NOSUID | MS_DIRSYNC | MS_NOATIME; flags |= (executable ? 0 : MS_NOEXEC); flags |= (ro ? MS_RDONLY : 0); flags |= (remount ? MS_REMOUNT : 0); snprintf(mountData, sizeof(mountData), "utf8,uid=%d,gid=%d,fmask=%o,dmask=%o,shortname=mixed", ownerUid, ownerGid, permMask, permMask); // 调用mount,做挂载动作 rc = mount(c_source, c_target, "vfat", flags, mountData); // 如果返回错误为文件系统是只读的,就设置只读标识继续以只读方式挂载 if (rc && errno == EROFS) { SLOGE("%s appears to be a read only filesystem - retrying mount RO", c_source); flags |= MS_RDONLY; rc = mount(c_source, c_target, "vfat", flags, mountData); } if (rc == 0 && createLost) { char *lost_path; asprintf(&lost_path, "%s/LOST.DIR", c_target); if (access(lost_path, F_OK)) { /* * Create a LOST.DIR in the root so we have somewhere to put * lost cluster chains (fsck_msdos doesn't currently do this) */ if (mkdir(lost_path, 0755)) { SLOGE("Unable to create LOST.DIR (%s)", strerror(errno)); } } free(lost_path); } return rc; } |
其实到这里挂载成功的话,后续也就没有必要分析了。基本就是挂载成功后的一些收尾工作,后面的博主就不打算接着分析了,基本也是贴代码和log,大家应该也看得吃劲。有什么其他的问题,大家可以给我留言交流。
楼主,请教一个问题,我想挂载内部存储开机为只读文件系统,需要修改什么地方呢?