Android磁盘之U盘挂载

Android  源码分析  2024年1月4日 am8:08发布10个月前更新 91es.com站长
76 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、 本站名称: 91易搜
2、 本站网址: 91es.com3xcn.com
3、 本站内容: 部分来源于网络,仅供学习和参考,若侵权请留言
3、 本站申明: 个人流水账日记,内容并不保证有效

暂无评论

暂无评论...

随机推荐

[摘]各种基本数据类型转byte数组并反转

int 转 byte[]   低字节在前(低字节序)public static byte[] toLH(int n) { byte[] b = new byte[4]; b[0] = (byte) (n & 0xff); b[1] = (byte) (n >&g...

《MySQL基础教程》笔记7

前言主要是记录一下join和where等命令的使用。根据《MySQL基础教程-西泽梦路》学习,简单的做一下笔记。记录于此,方便自己回忆。正文我这以Window版的phpstudy软件验证。需要进入这个目录,才可以使用mysql命令D:\phpstudy_pro\Extensions\M...

lnmp安装记录

前言简单记录一下使用 LNMP一键安装包,以及自己遇到的问题,主要是方便自己查阅。这里只是简单记录,推荐看参考文。正文LNMP一键安装包LNMP一键安装包是一个用Linux Shell编写的可以为 CentOS / RHEL / Fedora / Debian / Ubuntu / Ra...

重写TextView的setText出现异常问题

前言TextView重写setText(CharSequence text, BufferType type) 时出现如下异常日志(截取部分日志):java.lang.NullPointerException: Attempt to invoke interface method 'int j...

张晓风:经济学的旁听生

“什么是经济学呢?”他站在讲台上,戴眼镜,灰西装,声音平静,典型的中年学者。台下坐的是大学一年级的学生,而我,是置身在这二百人大教室里偷偷旁听的一个。从一开学我就昂奋起来,因为在课表上看见要开一门《社会科学概论》的课程,包括四位教授来设“政治”“法律”“经济”“人类学”四个讲座。想起可以重新做学...

蒋勋 : 孤独的乐趣

与孤独相处的时候,可以多一点思维的空间,生命的过程会不会更细腻一点?——蒋勋禅宗有一则有趣的故事,小徒弟整天跟老师父说:“我心不安,我心不安。”他觉得心好慌,上课没有心上课,做功课没有心做功课,问老师父到底该怎么办?师父拿出一把刀,说:“心拿出来,我帮你安一安。”心一直在自己身上,心会不安,是被...