Jimmy Chen

A Programmer

(原创)根据log分析SD卡挂载过程

  在分析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:

可信度:永远可用(Permanent)
访问权限:App存储内容仅App本身(或共享uid的App)可访问(Root除外)
内容持久:App存储内容随App卸载而消失
适应情况:存储内容仅App自己访问时的最佳选择

External Storage:

可信度:最典型的当设备作为USB存储被mount时不可用
访问权限:App存储内容全局可读
内容持久:当App卸载时,只有存在getExternalFilesDir()路径下的文件会消失
适应情况:存储内容希望与其他App共享或传到电脑上,但是不想申请任何权限时的最佳选择

注:此处讨论的访问权限是应用路径下的权限。

总结下来,External存储区域有几个好处:

  1. 可以传到电脑上;
  2. 可以与其他app共享;
  3. 在4.4之后的App路径(Android/data/包名)下读写不需任何权限;
  4. 存在App路径之外的文件不会随App卸载。

相应的,也有几个缺点:

  1. 可能不可用;
  2. 会被其他应用读到;
  3. 在非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信息:

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

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

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

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

status_t Disk::create() {
    CHECK(!mCreated);
    mCreated = true;
    // 发出事件通知
    notifyEvent(ResponseCode::DiskCreated, StringPrintf("%d", mFlags));
    // 读取SD卡元数据
    readMetadata();
    // 读取SD卡分区表
    readPartitions();
    return OK;
}

  首先发出DiskCreated事件通知,对应的log就是上面贴出的main log的第一句:

01-02 04:56:21.301  1675  1907 D VoldConnector: RCV <- {640 disk:179,64 7}

Disk::readMetadata

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信息:

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

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信息如下:

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 mbrPART 1 c是执行sgdisk的返回值。

最后调用Disk::createPublicVolume来创建Volume,下面接着分析Volume的创建过程

Disk::createPublicVolume

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

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:

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如下:

01-02 04:56:21.363  1675  1907 D VoldConnector: RCV <- {643 disk:179,64}

StorageManagerService处理过程

  底层中通过notifyEvent发出的事件,在上次会通过StorageManagerService::onEventLocked来进行统一处理

StorageManagerService::onEventLocked

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

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处理

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如下:

01-02 04:56:21.363  1675  1906 D VoldConnector: SND -> {7 volume mount public:179,65 2 0}

CommandListener::VolumeCmd::runCommand

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

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

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

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如下:

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

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信息如下:

--------------调用的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

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如下:

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后面的内容,下面就到设置路径了:

--------------------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

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:

01-02 04:56:21.827  1675  1907 D VoldConnector: RCV <- {656 public:179,65 /mnt/media_rw/9016-4EF8}

VolumeBase::setPath

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:

01-02 04:56:21.828  1675  1907 D VoldConnector: RCV <- {655 public:179,65 /storage/9016-4EF8}

接下来继续回到doMount,下面就到vfat:Mount了

vfat::Mount

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,大家应该也看得吃劲。有什么其他的问题,大家可以给我留言交流。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d 博主赞过: