Android磁盘之U盘挂载

Android  源码分析  2024年1月4日 am8:08发布11个月前更新 城堡大人
115 0 0

前言

之前介绍Vold的启动,没有涉及U盘的挂载,今天在之前的基础上进行插入U盘时流程的分析。

Android P

这里很多都是网上的,我就走走流程。

正文

VolumeManager.cpp

handleBlockEvent()
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
    //申请一个lock
    std::lock_guard<std::mutex> lock(mLock);
    //在事件属性参数中查找设备的路径;
    std::string eventPath(evt->findParam("DEVPATH")?evt->findParam("DEVPATH"):"");
    //在事件属性参数中查找设备的类型;
    std::string devType(evt->findParam("DEVTYPE")?evt->findParam("DEVTYPE"):"");
    //判断是否是“disk”类型,磁盘设备,否的话,直接返回不做任何处理
    if (devType != "disk") return;
    //上报的数据中获取主设备号;
    int major = std::stoi(evt->findParam("MAJOR"));
    //上报的数据中获取次设备号;
    int minor = std::stoi(evt->findParam("MINOR"));
    //makedev()作用是将主次设备号联合得到具体可访问的设备对象索引;
    dev_t device = makedev(major, minor);
    //判断事件的动作类型
    switch (evt->getAction()) {
    case NetlinkEvent::Action::kAdd: {
        //循环判断mDiskSources,这个mDiskSources 在vold的main()函数时就已经配置好的。所以mDiskSources是固定的一些数据。 
        //在main()函数中调用了process_config()函数对VolumeManager::DiskSource进行赋值。具体是检索配置fstab文件,进行add操作。
        for (const auto& source : mDiskSources) {
            //从mDiskSources表获取的一个成员DiskSource类型的source,
            //调用该成员的matches函数对 第11行获取的设备路径eventPath,进行匹配字符串比较。
            if (source->matches(eventPath)) {
                // For now, assume that MMC and virtio-blk (the latter is
                // emulator-specific; see Disk.cpp for details) devices are SD,
                // and that everything else is USB
                int flags = source->getFlags();
                //判断主设备号是否是mmc的设备;
                if (major == kMajorBlockMmc
                    //判断是否是模拟器运行的;
                    || (android::vold::IsRunningInEmulator()
                    //判断主设备号必须在 block设备范围内
                    && major >= (int) kMajorBlockExperimentalMin
                    && major <= (int) kMajorBlockExperimentalMax)) {
                    //将该磁盘Disk的flag标志为kSd
                    flags |= android::vold::Disk::Flags::kSd;
                } else {
                    //将该磁盘Disk的flag标志为kUsb
                    flags |= android::vold::Disk::Flags::kUsb;
                }
                auto disk = new android::vold::Disk(eventPath, device,
                        source->getNickname(), flags);
                handleDiskAdded(std::shared_ptr<android::vold::Disk>(disk));
                break;
            }
        }
        break;
    }
    case NetlinkEvent::Action::kChange: {
        handleDiskChanged(device);
        break;
    }
    case NetlinkEvent::Action::kRemove: {
        handleDiskRemoved(device);
        break;
    }
    default: {
        break;
    }
    }
}

这里是event事件处理中心,主要处理disk类型事件。

以上注册都是摘抄,部分参考文章忘记附上了。

上面分别有三种状态

  1. kAdd 挂载

  2. kChange

  3. kRemove 卸载

这里以分析U盘的挂载流程

handleDiskAdded()
//创建DISK对象
auto disk = new android::vold::Disk(eventPath, device,
        source->getNickname(), flags);
handleDiskAdded(std::shared_ptr<android::vold::Disk>(disk));
void VolumeManager::handleDiskAdded(const std::shared_ptr<android::vold::Disk>& disk) {
    //锁屏未解锁,需要等待用户解锁
    //需要等待user0启动,因为我们需要在mount Fuse daemon处理磁盘前启用用户。
    if (mSecureKeyguardShowing) {
        mPendingDisks.push_back(disk);
    } else {
        //调用Disk对象的create()方法创建
        //创建一个Disk,并通过notifyEvent()方法通知广播Framework;
        disk->create();
        //将新建的Disk 放到VM管理的一个mDisks表里。
        mDisks.push_back(disk);
    }
}

如果锁屏未解锁,添加到mPendingDisks中,等待解锁再处理。如果解锁了,走else,继续看。

Disk.cpp

create()
status_t Disk::create() {
    //检查是否已经创建过的标志位
    CHECK(!mCreated);
    //第一次创建置位 标志位
    mCreated = true;
    //调用notifyEvent()函数通知到广播中。
    auto listener = VolumeManager::Instance()->getListener();
    //第一个参数event:ResponseCode::DiskCreated  Disk创建;
    //第二个参数value:mFlags 是new Disk传入的参数。
    //只要知道notifyEvent()主要是发送广播给到Framework即可。
    if (listener) listener->onDiskCreated(getId(), mFlags);
    readMetadata();
    readPartitions();
    return OK;
}

这里主要如下内容

  1. 从VolumeManager中获取listener,并把状态通知到StorageManagerService。

  2. readMetadata()

  3. readPartitions()

VolumeManager.cpp

getListener()返回的是IVoldListener,其赋值是,在VoldNativeService中。

binder::Status VoldNativeService::setListener(
        const android::sp<android::os::IVoldListener>& listener) {
    ENFORCE_UID(AID_SYSTEM);
    ACQUIRE_LOCK;
    VolumeManager::Instance()->setListener(listener);
    return ok();
}

VoldNativeService的setListener,可以看《StorageManagerService的启动》,通过IBinder通信,

其中关系,我还不太理解~_~

只知道最后状态进入了StorageManagerService中的private final IVoldListener mListener = new IVoldListener.Stub() {}中。

Disk.cpp

readMetadata()
status_t Disk::readMetadata() {
    //磁盘大小置为-1
    mSize = -1;
    //清除标签
    mLabel.clear();
    //以只读的原子操作打开设备
    int fd = open(mDevPath.c_str(), O_RDONLY | O_CLOEXEC);
    //不为1就打开成功
    if (fd != -1) {
        //获取空间大小
        if (ioctl(fd, BLKGETSIZE64, &mSize)) {
            //获取失败
            mSize = -1;
        }
        close(fd);
    }
    //获取主设备号ID
    unsigned int majorId = major(mDevice);
    //根据不同的block设备进行分类访问;
    switch (majorId) {
    //判断是循环block,则是虚拟设备标签设置为“Virtual”;
    case kMajorBlockLoop: {
        mLabel = "Virtual";
        break;
    }
    //判断是Scsi类型的block设备;
    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: {
        //path=mSysPath+“/device/vendor” = “/sys/”+eventPath+“/device/vendor”;
        std::string path(mSysPath + "/device/vendor");
        std::string tmp;
        //读取对应path路径下的字符串;
        if (!ReadFileToString(path, &tmp)) {
            PLOG(WARNING) << "Failed to read vendor from " << path;
            return -errno;
        }
        //将前面读取的字符串 赋值给“mLable”;
        tmp = android::base::Trim(tmp);
        mLabel = tmp;
        break;
    }
    //判断是Mmc类型block;
    case kMajorBlockMmc: {
        //path=mSysPath+“/device/manfid” = “/sys/”+eventPath+“/device/manfid”;
        std::string path(mSysPath + "/device/manfid");
        std::string tmp;
        //读取对应path路径下的字符串;
        if (!ReadFileToString(path, &tmp)) {
            return -errno;
        }
        tmp = android::base::Trim(tmp);
        //获得得到manfid;
        int64_t manfid;
        if (!android::base::ParseInt(tmp, &manfid)) {
            return -EINVAL;
        }
        /*
        manfid为0x000003 则是"SanDisk"的mmc
        manfid为0x00001b则是"Samsung"的mmc
        manfid为0x000028则是"Lexar"的mmc
        manfid为0x000074则是"Transcend"的mm
        */
        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)) {
            mLabel = "Virtual";
            break;
        }
        return -ENOTSUP;
    }
    }
    auto listener = VolumeManager::Instance()->getListener();
    /*
    发送广播,通知FW,Disk的Size发生变化;
    发送广播,通知FW,Disk的Lable发生变化;
    发送广播,通知FW,Disk的SysPath发生变化;
    */
    if (listener) listener->onDiskMetadataChanged(getId(),
            mSize, mLabel, mSysPath);
    return OK;
}
readPartitions()
status_t Disk::readPartitions() {
    //计算出支持的最大分区设备
    //计算出设备支持的最大分区;SCCI和虚拟设备固定默认最大为15,EMMC设备需要动态读取得到。
    int maxMinors = getMaxMinors();
    if (maxMinors < 0) {
        return -ENOTSUP;
    }
    //销毁所有卷
    destroyAllVolumes();
    //分析分区表
    std::vector<std::string> cmd;
    cmd.push_back(kSgdiskPath);
    cmd.push_back("--android-dump");
    cmd.push_back(mDevPath);

    std::vector<std::string> output;
    //sgdisk扫描
    //这里就是调用/system/bin/sgdisk工具读取分区信息
    status_t res = ForkExecvp(cmd, output);
    if (res != OK) {
        //通知FW扫描Disk
        auto listener = VolumeManager::Instance()->getListener();
        if (listener) listener->onDiskScanned(getId());
        //标记我们刚刚分区并应格式化所有卷
        mJustPartitioned = false;
        return res;
    }

    Table table = Table::kUnknown;
    bool foundParts = false;
    for (const auto& line : output) {
        auto split = android::base::Split(line, kSgdiskToken);
        auto it = split.begin();
        if (it == split.end()) continue;
        //比较分解后的字符串是否存在 “DISK”
        if (*it == "DISK") {
            if (++it == split.end()) continue;
             //继续分解 第一次分割 后的字串
            if (*it == "mbr") {
                table = Table::kMbr;
            } else if (*it == "gpt") {//继续比较是否存在 “gpt”
                table = Table::kGpt;
            } else {
                continue;
            }
        } else if (*it == "PART") {
            //比较分解后的字符串是否存在 “ PART ”
            foundParts = true;
            if (++it == split.end()) continue;
            int i = 0;
            //将继续分解后的字串 转换为10进制的长整型
            if (!android::base::ParseInt(*it, &i, 1, maxMinors)) {
                continue;
            }
            //创建分区设备
            dev_t partDevice = makedev(major(mDevice), minor(mDevice) + i);
            if (table == Table::kMbr) {
                //继续分解output的字符串 得到类型
                if (++it == split.end()) continue;
                int type = 0;
                //转换为16进制
                if (!android::base::ParseInt("0x" + *it, &type)) {
                    continue;
                }
                switch (type) {
                    case 0x06:  // FAT16
                    case 0x07:  // HPFS/NTFS/exFAT
                    case 0x0b:  // W95 FAT32 (LBA)
                    case 0x0c:  // W95 FAT32 (LBA)
                    case 0x0e:  // W95 FAT16 (LBA)
                    case 0x83:  // Support Linux LBA add by Barton 2019.03.19
                            createPublicVolume(partDevice);
                        break;
                }
            } else if (table == Table::kGpt) {
                if (++it == split.end()) continue;
                //继续分解 得到 typeGuid
                auto typeGuid = *it;
                if (++it == split.end()) continue;
                //继续分解 得到 partGuid
                auto partGuid = *it;
                //忽略大小写 比较字符串
                if (android::base::EqualsIgnoreCase(typeGuid, kGptBasicData)) {
                    ////根据分区设备 创建公用卷
                    createPublicVolume(partDevice);
                } else if (android::base::EqualsIgnoreCase(typeGuid, kGptAndroidExpand)) {
                    //根据分区设备 分区ID 创建专用卷
                    createPrivateVolume(partDevice, partGuid);
                }
            }
        }
    }
    // Ugly last ditch effort, treat entire disk as partition
    if (table == Table::kUnknown || !foundParts) {
        std::string fsType;
        std::string unused;
        //读取元数据不受信任
        if (ReadMetadataUntrusted(mDevPath, &fsType, &unused, &unused) == OK) {
            createPublicVolume(mDevice);
        }
    }
    //通知上层设备开始扫描
    auto listener = VolumeManager::Instance()->getListener();
    //所有创建完成后 通知FW  Disk扫描完成
    if (listener) listener->onDiskScanned(getId());
    //清除  标记我们刚刚分区并应格式化所有卷
    mJustPartitioned = false;
    return OK;
}

上面有几个方法比较重要createPublicVolume()和createPrivateVolume()。

createPublicVolume()
void Disk::createPublicVolume(dev_t device, const int partSeq) {
    //根据设备好,新建一个公共分区(PublicVolume)对象
    auto vol = std::shared_ptr<VolumeBase>(new PublicVolume(device, mEventPath, partSeq));
    //判断是否标记,我们刚刚分区并格式化所有卷
    if (mJustPartitioned) {
        //设置分区静音
        vol->setSilent(true);
        vol->create();
        //设置编码格式为自动
        //如果已挂在,则卸载分区,然后在设置分区的fstype;
        vol->format("auto");
        //清理分区内容
        vol->destroy();
        //取消分区静音
        vol->setSilent(false);
    }
    //将新建分区对象放到Disk对象的管理队列里
    //进行添加,后面会用到
    mVolumes.push_back(vol);
    //设置分区的磁盘ID; mDiskId = diskId;
    vol->setDiskId(getId());
    if (major(mDevice) == android::vold::Disk::kMajorBlockMmc) {
        if (minor(mDevice) == kMinorBlockEMMC) {
            vol->setStorageType(android::vold::VolumeBase::StorageType::kPhoneStorage);
        } else {
            vol->setStorageType(android::vold::VolumeBase::StorageType::kExternalSD);
        }
    }
    if (major(mDevice) == kMajorBlockLoop && minor(mDevice) == kMinorBlockFon) {
        vol->setStorageType(android::vold::VolumeBase::StorageType::kPhoneStorage);
    }
    //创建分区信息
    //VolumeBase.create
    vol->create();
}

VolumeBase.cpp

status_t VolumeBase::create() {
	//检查是否重复创建
    CHECK(!mCreated);
	//标记创建
    mCreated = true;
    status_t res = doCreate();
	//通知FW创建分区,并上传分区信息
    auto listener = getListener();
    //通知framework层
    if (listener) listener->onVolumeCreated(getId(),
            static_cast<int32_t>(mType), mDiskId, mPartGuid);
    //设置kUnmounted
    setState(State::kUnmounted);
    return res;
}

我们看listener->onVolumeCreated(),通过IBinder通信,进入StorageManagerService中的

private final IVoldListener mListener = new IVoldListener.Stub() {
	//略,都会走这里
}

StorageManagerService.java

onVolumeCreated()
@Override
public void onVolumeCreated(String volId, int type, String diskId, String partGuid) {
    synchronized (mLock) {
        final DiskInfo disk = mDisks.get(diskId);
        final VolumeInfo vol = new VolumeInfo(volId, type, disk, partGuid);
        mVolumes.put(volId, vol);
        onVolumeCreatedLocked(vol);
    }
}
onVolumeCreatedLocked()
@GuardedBy("mLock")
private void onVolumeCreatedLocked(VolumeInfo vol) {
    if (mPms.isOnlyCoreApps()) {
        return;
    }
    //这里的type是0,也就是TYPE_PUBLIC
    if (vol.type == VolumeInfo.TYPE_EMULATED) {
        final StorageManager storage = mContext.getSystemService(StorageManager.class);
        final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
        if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)
                && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
            vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
            vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
            mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
        } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
            vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
            vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
            mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
        }
    } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
        if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
                && vol.disk.isDefaultPrimary()) {
            vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
            vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
        }
        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) {
		mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
    } else {
        Slog.e(TAG, "Skipping automatic mounting of " + vol);
    }
}

进入了TYPE_PUBLIC分支,最后会发送,H_VOLUME_MOUNT。

handleMessage()
case H_VOLUME_MOUNT: {
    final VolumeInfo vol = (VolumeInfo) msg.obj;
    if (isMountDisallowed(vol)) {
        break;
    }
    //根据之前的type=TYPE_PUBLIC,不满足下面if的条件,因此走else
    if ( (0 == (vol.mountFlags & VolumeInfo.MOUNT_FLAG_PRIMARY)) &&
         (mATCPendigMountFeatureEnable && ( mATCPendigMountAfterFail || mATCPendigMount))) {
        if (mATCPendigMount) {
            try {
                mVold.pending_mount(vol.id, vol.mountFlags, vol.mountUserId);
            } catch (Exception e) {
                //Slog.wtf(TAG, e);
            }
        } else {
            try {
                mVold.mount(vol.id, vol.mountFlags, vol.mountUserId);
            } catch (Exception e) {
                //Slog.wtf(TAG, e);
            }
        }
        break;
    } else {
        try {
        	//条用mVold的mount()方法
            mVold.mount(vol.id, vol.mountFlags, vol.mountUserId);
        } catch (Exception e) {
            //Slog.wtf(TAG, e);
        }
        break;
    }
}

VoldNativeService.cpp

mount()
binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountFlags,
        int32_t mountUserId) {
    ENFORCE_UID(AID_SYSTEM);
    CHECK_ARGUMENT_ID(volId);
    ACQUIRE_LOCK;
    //找到VolumeBase
    auto vol = VolumeManager::Instance()->findVolume(volId);
    if (vol == nullptr) {
        return error("Failed to find volume " + volId);
    }
    vol->setMountFlags(mountFlags);
    vol->setMountUserId(mountUserId);
	/* 调用VolumeBase的mount方法 */
    int res = vol->mount();
    if ((mountFlags & MOUNT_FLAG_PRIMARY) != 0) {
        VolumeManager::Instance()->setPrimary(vol);
    }
    return translate(res);
}

这两个动作:

  1. findVolume()找到需要挂载的磁盘

  2. mount()进行磁盘挂载

需要注意,findVolume()返回的是PublicVolume对象,因此,调用的mount是PublicVolume->mount(),下面细细道来。

VolumeManager.cpp

findVolume()
std::shared_ptr<android::vold::VolumeBase> VolumeManager::findVolume(const std::string& id) {
    if (mInternalEmulated != nullptr && mInternalEmulated->getId() == id) {
        return mInternalEmulated;
    }
    for (const auto& disk : mDisks) {
        auto vol = disk->findVolume(id);
        if (vol != nullptr) {
            return vol;
        }
    }
    for (const auto& vol : mObbVolumes) {
        if (vol->getId() == id) {
            return vol;
        }
    }
    return nullptr;
}

这里调用的是disk的findVolume()

Disk.cpp

findVolume()
std::shared_ptr<VolumeBase> Disk::findVolume(const std::string& id) {
    for (auto vol : mVolumes) {
        if (vol->getId() == id) {
            return vol;
        }
        auto stackedVol = vol->findVolume(id);
        if (stackedVol != nullptr) {
            return stackedVol;
        }
    }
    return nullptr;
}

如果存在,返回的是mVolumes中的对象。

我们之前在createPublicVolume()中添加了PublicVolume的对象。

mVolumes.push_back(vol);

也就是返回的是PublicVolume对象。

因此,第一步的findVolume()结束了,我们看PublicVolume->mount()。

由于PublicVolume没有实现mount(),因此看起父类VolumeBase。

VolumeBase.cpp

mount()
status_t VolumeBase::mount() {
    if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) {
        return -EBUSY;
    }
	//设置状态kChecking
    setState(State::kChecking);
	/* 调用子类PublicVolume的doMount方法 */
    /* 注意:该方法是一个虚函数,对于EmulatedVolume,PublicVolume和PrivateVolume有不同的实现 */
    status_t res = doMount();
	/* 设置挂载成功状态,挂载成功就向上通知onVolumeStateChanged */
    if (res == OK) {
        setState(State::kMounted);
    } else {
        setState(State::kUnmountable);
    }
    return res;
}

改变磁盘状态和doMount()。

doMount()是一个虚函数,加上我们上面调用的是PublicVolume->mount(),这里看PublicVolume->doMount()。

PublicVolume.cpp

doMount()
status_t PublicVolume::doMount() {
#ifdef ATC_AOSP_ENHANCEMENT
    int ret = OK;
    char fsck_state[PROPERTY_VALUE_MAX] = {0};
    bool need_fsck = true;
    nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);;
    nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME);
    dev_t before;
    std::string res;
    LOG(ERROR) << "PublicVolume::doMount()";
#endif
    readMetadata();
#ifdef ATC_AOSP_ENHANCEMENT
    // Use UUID as stable name, if available
    std::string stableName = getId();
    if (!mFsMountPoint.empty()) {
        stableName = mFsMountPoint;
    } else if (!mFsUuid.empty()){
        stableName = mFsUuid;
    }

    mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str());
	LOG(ERROR) << "doMount() mRawPath "<< mRawPath;
    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());
	LOG(ERROR) << "doMount() mFuseDefault "<< mFuseDefault;
	LOG(ERROR) << "doMount() mFuseRead "<< mFuseRead;
	LOG(ERROR) << "doMount() mFuseWrite "<< mFuseWrite;

    setInternalPath(mRawPath);

    if (getMountFlags() & MountFlags::kVisible) {
        setPath(StringPrintf("/storage/%s", stableName.c_str()));
    } else {
        setPath(mRawPath);
    }

    if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
        PLOG(ERROR) << getId() << " failed to create mount points";
        ret = -errno;
        goto error_out;
    }

	LOG(ERROR) << "doMount() PublicVolume kChecking ";
    setState(State::kChecking);

    LOG(ERROR) <<"doMount()  PublicVolume getId() : " << getId() << ",  mFsType: " << mFsType;

    if (mFsType != "vfat" && mFsType != "exfat" && mFsType != "ntfs") {
        LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;
        ret = -EIO;
        goto error_mount;
    }

    /*for external device fsck or not. false-not do fsck, true or null-do fsck. --atc0128 2017-09-22*/
    property_get(kFsckProperty, fsck_state, "");
    if (!strcmp(fsck_state, kNotFsck)) {
        LOG(VERBOSE) << "PublicVolume does not need to do fscking for external device";
        need_fsck = false;
    } else {
        LOG(ERROR) << stableName<< " start to fsck " << mFsType;
    }

    res = StringPrintf("/storage/%s", stableName.c_str()) + " " + StringPrintf("/storage/%s", stableName.c_str());
	LOG(ERROR) << "doMount() mFsType :  "<< mFsType;
    if (mFsType == "vfat" && vfat::IsSupported()) {
        if (need_fsck && vfat::Check(mDevPath)) {
            LOG(ERROR) << "doMount() " <<getId() << " failed vfat filesystem check, stop mounting";
            ret = -EIO;
            goto error_mount;
        }
    } else if (mFsType == "exfat" && exfat::IsSupported()) {
        if (need_fsck && exfat::Check(mDevPath)) {
            LOG(ERROR) << "doMount() "<< getId() << " failed exfat filesystem check, stop mounting";
            ret = -EIO;
            goto error_mount;
        }
    } else if (mFsType == "ntfs" && ntfs::IsSupported()) {
        if (need_fsck && ntfs::Check(mDevPath)) {
            LOG(ERROR) << "doMount() "<< getId() << " failed ntfs filesystem check, stop mounting";
            ret = -EIO;
            goto error_mount;
        }
    }
#else
    if (mFsType == "vfat" && vfat::IsSupported()) {
        if (vfat::Check(mDevPath)) {
            LOG(ERROR) << "doMount() "<< getId() << " failed filesystem check";
            return -EIO;
        }
    } else if (mFsType == "exfat" && exfat::IsSupported()) {
        if (exfat::Check(mDevPath)) {
            LOG(ERROR) << "doMount() "<< getId() << " failed filesystem check";
            return -EIO;
        }
    } else {
        LOG(ERROR) << "doMount() "<< getId() << " unsupported filesystem " << mFsType;
        return -EIO;
    }

    // Use UUID as stable name, if available
    std::string stableName = getId();
    if (!mFsUuid.empty()) {
        stableName = mFsUuid;
    }

    mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str());

    mFuseDefault = StringPrintf("/mnt/runtime/default/%s", stableName.c_str());
    mFuseRead = StringPrintf("/mnt/runtime/read/%s", stableName.c_str());
    mFuseWrite = StringPrintf("/mnt/runtime/write/%s", stableName.c_str());

    setInternalPath(mRawPath);

    if (getMountFlags() & MountFlags::kVisible) {
        setPath(StringPrintf("/storage/%s", stableName.c_str()));
    } else {
        setPath(mRawPath);
    }

    if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
        PLOG(ERROR) << "doMount() "<< getId() << " failed to create mount points";
        return -errno;
    }
#endif

    if (mFsType == "vfat") {
        if (vfat::Mount(mDevPath, mRawPath, false, false, false, AID_MEDIA_RW, AID_MEDIA_RW, 0007,
                        false)) {
            PLOG(ERROR) << getId() << " failed to mount " << mDevPath;
#ifdef ATC_AOSP_ENHANCEMENT
            ret = -EIO;
            goto error_mount;
#else
            return -EIO;
#endif
        }
    } else if (mFsType == "exfat") {
        if (exfat::Mount(mDevPath, mRawPath, AID_MEDIA_RW, AID_MEDIA_RW, 0007)) {
            PLOG(ERROR) << getId() << " failed to mount " << mDevPath;
#ifdef ATC_AOSP_ENHANCEMENT
            ret = -EIO;
            goto error_mount;
#else
            return -EIO;
#endif
        }
#ifdef ATC_AOSP_ENHANCEMENT
    } else if (mFsType == "ntfs") {
        if (ntfs::Mount(mDevPath, mRawPath, AID_MEDIA_RW, AID_MEDIA_RW, 0007)) {
            PLOG(ERROR) << getId() << " ntfs: failed to mount " << mDevPath;
            ret = -EIO;
            goto error_mount;
        }
#endif
    }

    if (getMountFlags() & MountFlags::kPrimary) {
        initAsecStage();
    }

    if (!(getMountFlags() & MountFlags::kVisible)) {
        // Not visible to apps, so no need to spin up FUSE
        return OK;
    }

    if (fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||
            fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||
            fs_prepare_dir(mFuseWrite.c_str(), 0700, AID_ROOT, AID_ROOT)) {
        PLOG(ERROR) << getId() << " failed to create FUSE mount points";
#ifdef ATC_AOSP_ENHANCEMENT
        ret = -errno;
        goto error_premount_fuse;
#else
        return -errno;
#endif
    }

#ifdef ATC_AOSP_ENHANCEMENT
    before = GetDevice(mFuseWrite);
#else
    dev_t before = GetDevice(mFuseWrite);
#endif

    if (!(mFusePid = fork())) {
        if (getMountFlags() & MountFlags::kPrimary) {
            if (execl(kFusePath, kFusePath,
                    "-u", "1023", // AID_MEDIA_RW
                    "-g", "1023", // AID_MEDIA_RW
                    "-U", std::to_string(getMountUserId()).c_str(),
                    "-w",
                    mRawPath.c_str(),
                    stableName.c_str(),
                    NULL)) {
                PLOG(ERROR) << "Failed to exec";
            }
        } else {
            if (execl(kFusePath, kFusePath,
                    "-u", "1023", // AID_MEDIA_RW
                    "-g", "1023", // AID_MEDIA_RW
                    "-U", std::to_string(getMountUserId()).c_str(),
                    "-w",
                    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";
#ifdef ATC_AOSP_ENHANCEMENT
        ret = -errno;
        goto error_premount_fuse;
#else
        return -errno;
#endif
    }

#ifdef ATC_AOSP_ENHANCEMENT
    start = systemTime(SYSTEM_TIME_BOOTTIME);
#else
    nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
#endif
    while (before == GetDevice(mFuseWrite)) {
        LOG(VERBOSE) << "Waiting for FUSE to spin up...";
        usleep(50000); // 50ms

#ifdef ATC_AOSP_ENHANCEMENT
        now = systemTime(SYSTEM_TIME_BOOTTIME);
#else
        nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME);
#endif
        if (nanoseconds_to_milliseconds(now - start) > 5000) {
            LOG(WARNING) << "Timed out while waiting for FUSE to spin up";
#ifdef ATC_AOSP_ENHANCEMENT
            ret = -ETIMEDOUT;
            goto error_mount_fuse;
#else
            return -ETIMEDOUT;
#endif
        }
    }
#ifdef ATC_AOSP_ENHANCEMENT
    TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0));
    LOG(INFO) << "sdcard process(" << mFusePid << ") exited!!!";
#else
    /* sdcardfs will have exited already. FUSE will still be running */
    if (TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, WNOHANG)) == mFusePid)
#endif
        mFusePid = 0;

    return OK;
#ifdef ATC_AOSP_ENHANCEMENT
error_mount_fuse:
    ForceUnmount(getPath());
    ForceUnmount(kAsecPath);
    ForceUnmount(mFuseDefault);
    ForceUnmount(mFuseRead);
    ForceUnmount(mFuseWrite);

error_premount_fuse:
    ForceUnmount(mRawPath);
    if (mFusePid > 0) {
        kill(mFusePid, SIGTERM);
        TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0));
        mFusePid = 0;
    }
    rmdir(mFuseDefault.c_str());
    rmdir(mFuseRead.c_str());
    rmdir(mFuseWrite.c_str());
    mFuseDefault.clear();
    mFuseRead.clear();
    mFuseWrite.clear();

error_mount:
    rmdir(mRawPath.c_str());
    mRawPath.clear();

error_out:
    return ret;
#endif
}

其中execl是执行挂载命令。

本文很多都是参考网上,这里只是走走过程。

参考文章

  1. Android vold进程一 Vold启动和NetlinkManager数据获取

  2. Android P 储存设备挂载

  3. Android9.0版本Vold服务源码分析

 历史上的今天

  1. 2023: 修改Framework画中画(pip)中默认UI和逻辑定制(0条评论)
  2. 2020: 王小波:如何诚实地生活?(0条评论)
版权声明 1、 本站名称: 笔友城堡
2、 本站网址: https://www.biumall.com/
3、 本站部分文章来源于网络,仅供学习与参考,如有侵权,请留言

暂无评论

暂无评论...

随机推荐

博尔赫斯:我用什么才能留住你

我用什么才能留住你?我给你瘦落的街道、绝望的落日、荒郊的月亮。我给你一个久久地望着孤月的人的悲哀。 我给你我已死去的祖辈,后人们用大理石祭奠的先魂:我父亲的父亲,阵亡于布宜诺斯艾利斯的边境,两颗子弹射穿了他的胸膛,死的时候蓄着胡子,尸体被士兵们用牛皮裹起; ...

林白:过程

一月你还没有出现二月你睡在隔壁三月下起了大雨四月里遍地蔷薇五月我们对面坐着 犹如梦中 就这样六月到了六月里青草盛开 处处芬芳七月,悲喜交加 麦浪翻滚连同草地 直到天涯八月就是八月八月我守口如瓶 八月里我是瓶中的水 你是青天的云九月和十月是两只眼睛,装满了大海你在海上 我在海下...

[转]Android音频: 如何使用AudioTrack播放一个WAV格式文件?

抱歉,这篇文章代码不全,转载时没有尝试实现推荐看我新写的文章《AudioTrack简单简介之四:wav去掉文件头之解决爆音》如果你已经成功地了解了关于AudioTrack的一些话题,那么你可能享受它带来的好处,例如低延迟(在STATIC(静态)模式),能够生成流式音频(在STREAM(流)模...

[摘]adb命令行查询content-provider

偶尔需要使用adb明白改变和查询content-provider中的属性值一、conent 帮助文档如下usage: adb shell content [subcommand] [options]usage: adb shell content insert --uri <URI&g...

铁凝:幸福就在此刻

去探望一位生病的友人,聊起很多从前的事情,计划很多未来的事情,她忽然发问:对于你来说,幸福的时刻是什么?想了半天,竟然没有一个很适合的答案。那阵子,经常携带这个难题去和人打交道,不管是新朋还是故友,聊到酣畅总是抛出这个问题冷场,当然,收获的答案也是五花八门——有人说,幸福的时刻就是加官晋爵时买房...

[摘]Android混淆从入门到精通

前言本文摘抄,网上都写的很不错,我就摘抄于此。简介作为Android开发者,如果你不想开源你的应用,那么在应用发布前,就需要对代码进行混淆处理,从而让我们代码即使被反编译,也难以阅读。混淆概念虽然容易,但很多初学者也只是网上搜一些成型的混淆规则粘贴进自己项目,并没有对混淆有个深入的理解。本篇...