Android Fuse文件系统-3:vold和mount服务启动

1,770 阅读5分钟
vold  服务   VoldNativeService.cpp
mount 服务   StorageManagerService.java 

vold mount 以前代码使用的 socket 通信,现在改为binder通信。
9.0以及以后使用binder通信

system/vold/main.cpp

对应手机上的文件 /system/bin/vold

int main(int argc, char** argv) {
    atrace_set_tracing_enabled(false);
    setenv("ANDROID_LOG_TAGS", "*:d", 1);  // Do not submit with verbose logs enabled
    android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));

    LOG(INFO) << "Vold 3.0 (the awakening) firing up";

    ATRACE_BEGIN("main");

    LOG(DEBUG) << "Detected support for:"
               << (android::vold::IsFilesystemSupported("exfat") ? " exfat" : "")
               << (android::vold::IsFilesystemSupported("ext4") ? " ext4" : "")
               << (android::vold::IsFilesystemSupported("f2fs") ? " f2fs" : "")
               << (android::vold::IsFilesystemSupported("ntfs") ? " ntfs" : "")
               << (android::vold::IsFilesystemSupported("vfat") ? " vfat" : "");

    VolumeManager* vm;
    NetlinkManager* nm;

    parse_args(argc, argv);

    sehandle = selinux_android_file_context_handle();
    if (sehandle) {
        selinux_android_set_sehandle(sehandle);
    }

    mkdir("/dev/block/vold", 0755);

    /* For when cryptfs checks and mounts an encrypted filesystem */
    klog_set_level(6);

    //=================创建 VolumeManager 单例================!!!!!!!!!!!!!!
    /* Create our singleton managers */
    if (!(vm = VolumeManager::Instance())) {
        LOG(ERROR) << "Unable to create VolumeManager";
        exit(1);
    }

    if (!(nm = NetlinkManager::Instance())) {
        LOG(ERROR) << "Unable to create NetlinkManager";
        exit(1);
    }

    if (android::base::GetBoolProperty("vold.debug", false)) {
        vm->setDebug(true);
    }

    //=================调用 VolumeManager.start================!!!!!!!!!!!!!!
    if (vm->start()) {
        PLOG(ERROR) << "Unable to start VolumeManager";
        exit(1);
    }

    bool has_adoptable;
    bool has_quota;
    bool has_reserved;

    if (process_config(vm, &has_adoptable, &has_quota, &has_reserved)) {
        PLOG(ERROR) << "Error reading configuration... continuing anyways";
    }

    android::hardware::configureRpcThreadpool(1, false /* callerWillJoin */);

    //=================启动 vold 服务----调用 VoldNativeService.start================!!!!!!!!!!!!!!
    ATRACE_BEGIN("VoldNativeService::start");
    if (android::vold::VoldNativeService::start() != android::OK) {
        LOG(ERROR) << "Unable to start VoldNativeService";
        exit(1);
    }
    ATRACE_END();

    LOG(DEBUG) << "VoldNativeService::start() completed OK";

    ATRACE_BEGIN("NetlinkManager::start");
    if (nm->start()) {
        PLOG(ERROR) << "Unable to start NetlinkManager";
        exit(1);
    }
    ATRACE_END();

    // This call should go after listeners are started to avoid
    // a deadlock between vold and init (see b/34278978 for details)
    // MI MOD: START
    //android::base::SetProperty("vold.has_adoptable", has_adoptable ? "1" : "0");
    android::base::SetProperty("vold.has_adoptable", "0");
    // END
    android::base::SetProperty("vold.has_quota", has_quota ? "1" : "0");
    android::base::SetProperty("vold.has_reserved", has_reserved ? "1" : "0");

    // Do coldboot here so it won't block booting,
    // also the cold boot is needed in case we have flash drive
    // connected before Vold launched
    coldboot("/sys/block");

    ATRACE_END();

    android::IPCThreadState::self()->joinThreadPool();
    LOG(INFO) << "vold shutting down";

    exit(0);
}

vold启动过程流程图如下:

sequenceDiagram
main.cpp ->> VolumeManager::Instance()
main.cpp ->> NetlinkManager::Instance()
main.cpp ->> VolumeManager:start()
VolumeManager ->>+ EmulatedVolume:vol=new EmulatedVolume("/data/media", 0)
EmulatedVolume -->>- VolumeManager:vol
VolumeManager ->> VolumeBase:vol->create()
				  VolumeBase ->> VolumeBase: auto listener = getListener();
				  		Note over VolumeBase : "第一次创建 EmulatedVolume 时,listener 是null"
				  		Note over VolumeBase : "因为此时 StorageManagerService 尚未启动"				  		
				  		VolumeBase ->> VolumeManager: getListener() = StorageManagerService.mListener
VolumeManager ->> VolumeManager:mInternalEmulatedVolumes.push_back(vol)
VolumeManager ->> VolumeManager:updateVirtualDisk()
main.cpp ->> VoldNativeService::start()
main.cpp ->> NetlinkManager:start()

mount服务启动过程

mount服务所在进程 system_server 启动过程--rc文件

/system/etc/init/hw/init.rc 中启动 zygote, zygote 进程会启动 system_server 进程,system_server 启动 mount(StorageManagerService)服务

# Mount filesystems and start core system services.
on late-init
    trigger early-fs  ###### 触发 early-fs 触发器,early-fs 会启动 vold 服务。vold在zygote之前启动,zygote 启动system_server,system_server启动mount服务。
    .......
    # Now we can mount /data. File encryption requires keymaster to decrypt
    # /data, which in turn can only be loaded when system properties are present.
    trigger post-fs-data
	.........
    # Now we can start zygote for devices with file based encryption
    trigger zygote-start    #####----------------触发  zygote-start !!!!!!!!!!!!!----所以 vold服务 在mount 服务之前启动
	......
    trigger early-boot
    trigger boot
    trigger mmi
StorageManagerService 启动以及setListener( IVoldListener ) 流程:
sequenceDiagram
participant SystemServer
participant SystemServiceManager
participant StorageManagerService.Lifecycle
participant StorageManagerService
participant VoldNativeService
participant SystemService
participant ServiceManager

SystemServer ->> SystemServer:startOtherServices()
					Note over SystemServer : "com.android.server.StorageManagerService$Lifecycle"
SystemServer ->> SystemServiceManager:startService(SystemService service)
				 SystemServiceManager ->> SystemServiceManager: private final ArrayList<SystemService> mServices.add(service)
				 							Note over StorageManagerService.Lifecycle : Lifecycle extends SystemService
                 SystemServiceManager ->>+ StorageManagerService.Lifecycle: service.onStart()                 						   
                 	StorageManagerService.Lifecycle ->> StorageManagerService.Lifecycle: mStorageManagerService = new StorageManagerService(getContext())
                 	StorageManagerService.Lifecycle ->> SystemService: publishBinderService("mount", mStorageManagerService);
                 									 SystemService ->> ServiceManager: addService(name, service)
                 	StorageManagerService.Lifecycle ->>+ StorageManagerService: start()
                 		StorageManagerService ->> StorageManagerService:connectStoraged() 获取 storaged 服务
                 		StorageManagerService ->>+ StorageManagerService:connectVold() 获取 vold 服务,即c++层 VoldNativeService
                 			StorageManagerService ->> VoldNativeService: mVold.setListener(mListener);
                 				VoldNativeService ->> VolumeManager: setListener
                 			StorageManagerService -->>- StorageManagerService:onDaemonConnected()  mDaemonConnected = true;
                   StorageManagerService -->>- StorageManagerService.Lifecycle: start() end
          		StorageManagerService.Lifecycle -->>- SystemServiceManager: onStart() end

StorageManagerService 在开机完成之后的流程:

frameworks/base/services/core/java/com/android/server/StorageManagerService.java

sequenceDiagram
StorageManagerService.Lifecycle ->> StorageManagerService.Lifecycle: onBootPhase(int phase)
	alt phase == SystemService.PHASE_SYSTEM_SERVICES_READY
		StorageManagerService.Lifecycle ->> StorageManagerService: servicesReady();
	else phase == SystemService.PHASE_ACTIVITY_MANAGER_READY
		StorageManagerService.Lifecycle ->> StorageManagerService: systemReady();
	else phase == SystemService.PHASE_BOOT_COMPLETED
    	StorageManagerService.Lifecycle ->> StorageManagerService: bootCompleted();
    		Note over StorageManagerService : mBootCompleted = true;
    		Note over StorageManagerService : mHandler.obtainMessage(H_BOOT_COMPLETED).sendToTarget();
    		Note over StorageManagerService : updateFusePropFromSettings();
    		 activate StorageManagerService
    		 Note over StorageManagerService : handle 消息中调用 handleBootCompleted();
    			StorageManagerService ->> StorageManagerService: initIfBootedAndConnected();
    			StorageManagerService ->> StorageManagerService: resetIfBootedAndConnected() 内部调用onUserStarted;
    				StorageManagerService ->> VoldNativeService: onUserStarted(userId);
    					VoldNativeService ->> VolumeManager: onUserStarted(userId);
    						VolumeManager ->> VolumeManager: createEmulatedVolumesForUser(userId);
    							VolumeManager ->> EmulatedVolume: new EmulatedVolume("/data/media", userId));
    							VolumeManager ->> VolumeBase: vol->create();
    								VolumeBase ->> VolumeManager: getListener();
    								VolumeBase ->> StorageManagerService: mListener.onVolumeCreated(getId(), mType, mDiskId, mPartGuid,mMountUserId);
    									StorageManagerService ->> StorageManagerService: onVolumeCreatedLocked(vol);
    									Note over StorageManagerService : handle发送H_VOLUME_MOUNT消息,调用 mount(VolumeInfo vol);
    									
    		deactivate StorageManagerService
	end
	

核心重要过程 mount

sequenceDiagram
StorageManagerService ->> StorageManagerService: mount(VolumeInfo vol)
	StorageManagerService ->> VoldNativeService : mount(vol.id, vol.mountFlags, vol.mountUserId, new IVoldMountCallback.Stub());
		VoldNativeService ->> VolumeBase: mount();
			VolumeBase ->> EmulatedVolume: :doMount()

StorageManagerService .mount 源码 重点是调用 VoldNativeService : mount,以及传入的 IVoldMountCallback.Stub() 回调
    private void mount(VolumeInfo vol) {
        try {
            // TODO(b/135341433): Remove paranoid logging when FUSE is stable
            Slog.i(TAG, "Mounting volume " + vol);
            // mVold 即 VoldNativeService.cpp 实例,
            mVold.mount(vol.id, vol.mountFlags, vol.mountUserId, new IVoldMountCallback.Stub() {
                @Override
                public boolean onVolumeChecking(FileDescriptor fd, String path,
                        String internalPath) {
                    vol.path = path;
                    vol.internalPath = internalPath;
                    ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd);
                    try {
                        //===fuse文件系统挂载完成回调 onVolumeChecking,此处最终会通知 fuse 服务程序 FuseFaemon ===========!!!!!!!!!!
                        mStorageSessionController.onVolumeMount(pfd, vol);
                        return true;
                    } catch (ExternalStorageServiceException e) {
                        Slog.e(TAG, "Failed to mount volume " + vol, e);

                        int nextResetSeconds = FAILED_MOUNT_RESET_TIMEOUT_SECONDS;
                        Slog.i(TAG, "Scheduling reset in " + nextResetSeconds + "s");
                        mHandler.removeMessages(H_RESET);
                        mHandler.sendMessageDelayed(mHandler.obtainMessage(H_RESET),
                                TimeUnit.SECONDS.toMillis(nextResetSeconds));
                        return false;
                    } finally {
                        try {
                            pfd.close();
                        } catch (Exception e) {
                            Slog.e(TAG, "Failed to close FUSE device fd", e);
                        }
                    }
                }
            });
            Slog.i(TAG, "Mounted volume " + vol);
        } catch (Exception e) {
            Slog.wtf(TAG, e);
        }
    }
EmulatedVolume::doMount() 源码:
status_t EmulatedVolume::doMount() {
    std::string label = getLabel();//  lable = emulated
    bool isVisible = getMountFlags() & MountFlags::kVisible;

    mSdcardFsDefault = StringPrintf("/mnt/runtime/default/%s", label.c_str());
    mSdcardFsRead = StringPrintf("/mnt/runtime/read/%s", label.c_str());
    mSdcardFsWrite = StringPrintf("/mnt/runtime/write/%s", label.c_str());
    mSdcardFsFull = StringPrintf("/mnt/runtime/full/%s", label.c_str());

	//==========================重要代码======= 
    // mRawPath =/data/media    
    // 内部赋值 mInternalPath = /data/media
    setInternalPath(mRawPath); 
    //==========================重要代码======= 
    // lable = emulated 这个path 会传递给 FuseDaemon 
    // mPath = /storage/emulated
    setPath(StringPrintf("/storage/%s", label.c_str()));

    if (fs_prepare_dir(mSdcardFsDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||
        fs_prepare_dir(mSdcardFsRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||
        fs_prepare_dir(mSdcardFsWrite.c_str(), 0700, AID_ROOT, AID_ROOT) ||
        fs_prepare_dir(mSdcardFsFull.c_str(), 0700, AID_ROOT, AID_ROOT)) {
        PLOG(ERROR) << getId() << " failed to create mount points";
        return -errno;
    }

    dev_t before = GetDevice(mSdcardFsFull);

    bool isFuse = base::GetBoolProperty(kPropFuse, false);

    // 使用 sdcardfs 文件系统时会走这里
    // Mount sdcardfs regardless of FUSE, since we need it to bind-mount on top of the
    // FUSE volume for various reasons.
    if (mUseSdcardFs && getMountUserId() == 0) {
        LOG(INFO) << "Executing sdcardfs";
        int sdcardFsPid;
        if (!(sdcardFsPid = fork())) {
            // clang-format off
            //kSdcardFsPath = "/system/bin/sdcard"
            // sdcard   -u 1023 -g 1023 -m -w -G -i -o /data/media emulated
            // sdcard  /system/bin/sdcard -u 1023 -g 1023 -m -w -G -i -o /data/media emulated
            if (execl(kSdcardFsPath, kSdcardFsPath,
                    "-u", "1023", // AID_MEDIA_RW
                    "-g", "1023", // AID_MEDIA_RW
                    "-m",
                    "-w",
                    "-G",
                    "-i",
                    "-o",
                    mRawPath.c_str(),
                    label.c_str(),
                    NULL)) {
                // clang-format on
                PLOG(ERROR) << "Failed to exec";
            }

            LOG(ERROR) << "sdcardfs exiting";
            _exit(1);
        }

        if (sdcardFsPid == -1) {
            PLOG(ERROR) << getId() << " failed to fork";
            return -errno;
        }

        nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
        while (before == GetDevice(mSdcardFsFull)) {
            LOG(DEBUG) << "Waiting for sdcardfs to spin up...";
            usleep(50000);  // 50ms

            nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME);
            if (nanoseconds_to_milliseconds(now - start) > 5000) {
                LOG(WARNING) << "Timed out while waiting for sdcardfs to spin up";
                return -ETIMEDOUT;
            }
        }
        /* sdcardfs will have exited already. The filesystem will still be running */
        TEMP_FAILURE_RETRY(waitpid(sdcardFsPid, nullptr, 0));
        sdcardFsPid = 0;
    }

    //--------------fuse 文件系统走这里
    if (isFuse && isVisible) {
        // Make sure we unmount sdcardfs if we bail out with an error below
        auto sdcardfs_unmounter = [&]() {
            LOG(INFO) << "sdcardfs_unmounter scope_guard running";
            unmountSdcardFs();
        };
        auto sdcardfs_guard = android::base::make_scope_guard(sdcardfs_unmounter);

        LOG(INFO) << "Mounting emulated fuse volume";
        android::base::unique_fd fd; // 创建 文件描述符变量 fd,此时还未赋值
        int user_id = getMountUserId();
        auto volumeRoot = getRootPath();// /data/media/0

        // Make sure Android/ dirs exist for bind mounting
        status_t res = PrepareAndroidDirs(volumeRoot);// /data/media/0
        if (res != OK) {
            LOG(ERROR) << "Failed to prepare Android/ directories";
            return res;
        }
		//======================================================核心代码=====================================!!!!!!!!!!!!!!
        // 参数 absolute_lower_path = getInternalPath() = /data/media
        // 参数 relative_upper_path = label             = emulated
        res = MountUserFuse(user_id, getInternalPath(), label, &fd);
        if (res != 0) {
            PLOG(ERROR) << "Failed to mount emulated fuse volume";
            return res;
        }

        mFuseMounted = true;
        auto fuse_unmounter = [&]() {
            LOG(INFO) << "fuse_unmounter scope_guard running";
            fd.reset();
            if (UnmountUserFuse(user_id, getInternalPath(), label) != OK) {
                PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume";
            }
            mFuseMounted = false;
        };
        auto fuse_guard = android::base::make_scope_guard(fuse_unmounter);

        auto callback = getMountCallback();
        if (callback) {
            bool is_ready = false;
            ///=======回调中 会调用 StorageManagerService.mStorageSessionController.onVolumeMount(pfd, vol);===启动 FuseFaemon===========!!!!!!!!!!
            // getPath()         = /storage/emulated
            // getInternalPath() = /data/media
            callback->onVolumeChecking(std::move(fd), getPath(), getInternalPath(), &is_ready);
            if (!is_ready) {
                return -EIO;
            }
        }

        // Only do the bind-mounts when we know for sure the FUSE daemon can resolve the path.
        // 把 /mnt/user/0/emulated/0/Android/data 指向  /data/media/0/Android/data
        // 把 /mnt/user/0/emulated/0/Android/obb 指向  /data/media/0/Android/obb
        res = mountFuseBindMounts();
        if (res != OK) {
            return res;
        }

        ConfigureReadAheadForFuse(GetFuseMountPathForUser(user_id, label), 256u);

        // By default, FUSE has a max_dirty ratio of 1%. This means that out of
        // all dirty pages in the system, only 1% is allowed to belong to any
        // FUSE filesystem. The reason this is in place is that FUSE
        // filesystems shouldn't be trusted by default; a FUSE filesystem could
        // take up say 100% of dirty pages, and subsequently refuse to write
        // them back to storage.  The kernel will then apply rate-limiting, and
        // block other tasks from writing.  For this particular FUSE filesystem
        // however, we trust the implementation, because it is a part of the
        // Android platform. So use the default ratio of 100%.
        //
        // The reason we're setting this is that there's a suspicion that the
        // kernel starts rate-limiting the FUSE filesystem under extreme
        // memory pressure scenarios. While the kernel will only rate limit if
        // the writeback can't keep up with the write rate, under extreme
        // memory pressure the write rate may dip as well, in which case FUSE
        // writes to a 1% max_ratio filesystem are throttled to an extreme amount.
        //
        // To prevent this, just give FUSE 40% max_ratio, meaning it can take
        // up to 40% of all dirty pages in the system.
        ConfigureMaxDirtyRatioForFuse(GetFuseMountPathForUser(user_id, label), 40u);

        // All mounts where successful, disable scope guards
        sdcardfs_guard.Disable();
        fuse_guard.Disable();
    }

    return OK;
}
/*
结:
1、挂载fuse文件系统
2、回调 StorageManagerService.mStorageSessionController.onVolumeMount(pfd, vol);   启动 fuse 服务端 FuseFaemon  
3、把 /mnt/user/0/emulated/0/Android/data 指向  /data/media/0/Android/data
   把 /mnt/user/0/emulated/0/Android/obb  指向  /data/media/0/Android/obb
   即,sdcard目录下的 Android/data 目录 Android/obb 目录,都不是fuse目录,都是直接访问底层文件系统
*/

/system/vold/Utils.cpp MountUserFuse 核心代码

status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path,
                       const std::string& relative_upper_path, android::base::unique_fd* fuse_fd) {
    // 参数 user_id = 0
    // 参数 absolute_lower_path = getInternalPath() = /data/media
    // 参数 relative_upper_path = label             = emulated
    
    // 创建路径的字符串变量
    // pre_fuse_path         = /mnt/user/0
    // fuse_path             = /mnt/user/0/emulated
    // pre_pass_through_path = /mnt/pass_through/0
    // pass_through_path     = /mnt/pass_through/0/emulated
    std::string pre_fuse_path(StringPrintf("/mnt/user/%d", user_id));
    std::string fuse_path(
            StringPrintf("%s/%s", pre_fuse_path.c_str(), relative_upper_path.c_str()));

    std::string pre_pass_through_path(StringPrintf("/mnt/pass_through/%d", user_id));
    std::string pass_through_path(
            StringPrintf("%s/%s", pre_pass_through_path.c_str(), relative_upper_path.c_str()));

    // 创建 /mnt/user 目录
    // Ensure that /mnt/user is 0700. With FUSE, apps don't need access to /mnt/user paths directly.
    // Without FUSE however, apps need /mnt/user access so /mnt/user in init.rc is 0755 until here
    auto result = PrepareDir("/mnt/user", 0750, AID_ROOT, AID_MEDIA_RW);
    if (result != android::OK) {
        PLOG(ERROR) << "Failed to prepare directory /mnt/user";
        return -1;
    }

    // 依次创建对应的目录
    // Shell is neither AID_ROOT nor AID_EVERYBODY. Since it equally needs 'execute' access to
    // /mnt/user/0 to 'adb shell ls /sdcard' for instance, we set the uid bit of /mnt/user/0 to
    // AID_SHELL. This gives shell access along with apps running as group everybody (user 0 apps)
    // These bits should be consistent with what is set in zygote in
    // com_android_internal_os_Zygote#MountEmulatedStorage on volume bind mount during app fork
    result = PrepareDir(pre_fuse_path, 0710, user_id ? AID_ROOT : AID_SHELL,
                             multiuser_get_uid(user_id, AID_EVERYBODY));
    if (result != android::OK) {
        PLOG(ERROR) << "Failed to prepare directory " << pre_fuse_path;
        return -1;
    }

    result = PrepareDir(fuse_path, 0700, AID_ROOT, AID_ROOT);
    if (result != android::OK) {
        PLOG(ERROR) << "Failed to prepare directory " << fuse_path;
        return -1;
    }

    result = PrepareDir(pre_pass_through_path, 0710, AID_ROOT, AID_MEDIA_RW);
    if (result != android::OK) {
        PLOG(ERROR) << "Failed to prepare directory " << pre_pass_through_path;
        return -1;
    }

    result = PrepareDir(pass_through_path, 0710, AID_ROOT, AID_MEDIA_RW);
    if (result != android::OK) {
        PLOG(ERROR) << "Failed to prepare directory " << pass_through_path;
        return -1;
    }

    if (relative_upper_path == "emulated") {
        // 创建 /mnt/user/0/self 目录
        std::string linkpath(StringPrintf("/mnt/user/%d/self", user_id));
        result = PrepareDir(linkpath, 0755, AID_ROOT, AID_ROOT);
        if (result != android::OK) {
            PLOG(ERROR) << "Failed to prepare directory " << linkpath;
            return -1;
        }
        linkpath += "/primary";
        // 创建链接,使 /mnt/user/0/self/primary 链接到 /storage/emulated/0 目录
        Symlink("/storage/emulated/" + std::to_string(user_id), linkpath);

        std::string pass_through_linkpath(StringPrintf("/mnt/pass_through/%d/self", user_id));
        result = PrepareDir(pass_through_linkpath, 0710, AID_ROOT, AID_MEDIA_RW);
        if (result != android::OK) {
            PLOG(ERROR) << "Failed to prepare directory " << pass_through_linkpath;
            return -1;
        }
        pass_through_linkpath += "/primary";
        // 创建链接,使 /mnt/pass_through/0/self/primary 链接到 /storage/emulated/0 目录
        Symlink("/storage/emulated/" + std::to_string(user_id), pass_through_linkpath);
    }

    // 拿到 fuse设备fd,给传递过来的参数 fuse_fd 指针赋值,用于通信
    // Open fuse fd.
    fuse_fd->reset(open("/dev/fuse", O_RDWR | O_CLOEXEC));
    if (fuse_fd->get() == -1) {
        PLOG(ERROR) << "Failed to open /dev/fuse";
        return -1;
    }

    // Note: leaving out default_permissions since we don't want kernel to do lower filesystem
    // permission checks before routing to FUSE daemon.
    const auto opts = StringPrintf(
        "fd=%i,"
        "rootmode=40000,"
        "allow_other,"
        "user_id=0,group_id=0,",
        fuse_fd->get());

    // 把目录 /mnt/user/0/emulated 挂载为 fuse 文件系统。mount("/dev/fuse", /mnt/user/0/emulated, "fuse", xxx, opts.c_str())
    result = TEMP_FAILURE_RETRY(mount("/dev/fuse", fuse_path.c_str(), "fuse",
                                      MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME | MS_LAZYTIME,
                                      opts.c_str()));
    if (result != 0) {
        PLOG(ERROR) << "Failed to mount " << fuse_path;
        return -errno;
    }

    if (IsSdcardfsUsed()) {
        std::string sdcardfs_path(
                StringPrintf("/mnt/runtime/full/%s", relative_upper_path.c_str()));

        LOG(INFO) << "Bind mounting " << sdcardfs_path << " to " << pass_through_path;
        return BindMount(sdcardfs_path, pass_through_path);
    } else {
        LOG(INFO) << "Bind mounting " << absolute_lower_path << " to " << pass_through_path;
        // absolute_lower_path   = getInternalPath() = /data/media
        // pass_through_path     = /mnt/pass_through/0/emulated
        // 把 /data/media   bindmount方式挂载到 /mnt/pass_through/0/emulated 目录
        // 即:访问 /mnt/pass_through/0/emulated 目录就是直接访问 /data/media 目录
        // 或者说,把 /mnt/pass_through/0/emulated 
        // /data/media 是整个 storage/emulated 目录的最底层目录
        return BindMount(absolute_lower_path, pass_through_path);
    }
}
// mount --bind命令是将前一个目录挂载到后一个目录上,所有对后一个目录的访问其实都是对前一个目录的访问
// 可以当做符号链接理解,但关机后失效,bindmount 配合 命名空间 mount 结合使用,能够使不同进程看到不同的目录
/*
总结:
1、       创建链接,使 /mnt/user/0/self/primary          指向 /storage/emulated/0 目录 
2、       创建链接,使 /mnt/pass_through/0/self/primary  指向 /storage/emulated/0 目录
3、 把 /mnt/user/0/emulated 目录挂载为 fuse 文件系统
4、 bindmount挂载,使 /mnt/pass_through/0/emulated      指向 /data/media 目录
*/

再看 system/etc/init/hw/init.rc 文件

# Switch between sdcardfs and FUSE depending on persist property
# TODO: Move this to ro property before launch because FDE devices
# interact with persistent properties differently during boot
on zygote-start && property:persist.sys.fuse=true
  # Mount default storage into root namespace
  # zygote-start 会触发 zygote 启动,zygote 会启动 mount 服务。同时 zygote-start 也触发了此处的 bind mount
  # 此处bindmount核心逻辑:访问 storage 实际上访问 /mnt/user/0 目录
  # /mnt/user/0 目录下有个 emulated 目录,同样在 /storage目录下也能看到
  # /mnt/user/0/emulated 目录被挂载为了 fuse 文件系统。
  # 访问 storage/emulated 即访问 fuse 文件系统
  # fuse 文件系统 的访问被转发给了 MediaProvider 
  # 在 MediaProvider 进程创建时,使用了命名空间mount,把 /mnt/pass_through/0 bindmount 挂载到 /storage 目录, 
  # 此时 MediaProvider 访问 /storage/emulated 就是访问 /mnt/pass_through/0/emulated 
  # /mnt/pass_through/0/emulated 又直接指向了底层目录 /data/media,所以会直接访问底层系统 /data/media 目录
  mount none /mnt/user/0 /storage bind rec
  mount none none /storage slave rec
on zygote-start && property:persist.sys.fuse=false
  # Mount default storage into root namespace
  mount none /mnt/runtime/default /storage bind rec
  mount none none /storage slave rec
on zygote-start && property:persist.sys.fuse=""
  # Mount default storage into root namespace
  mount none /mnt/runtime/default /storage bind rec
  mount none none /storage slave rec

  # /sdcard 目录呢?
on init
    sysclktz 0  
	# Symlink to keep legacy apps working in multi-user world
 	symlink /storage/self/primary /mnt/sdcard
 	
# /system/core/rootdir/Android.mk
# create some directories (some are mount points) and symlinks
LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
    dev proc sys system data data_mirror odm oem acct config storage mnt apex debug_ramdisk \
    linkerconfig $(BOARD_ROOT_EXTRA_FOLDERS)); \
    ln -sf /system/bin $(TARGET_ROOT_OUT)/bin; \
    ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
    ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \
    ln -sfn /sys/kernel/debug $(TARGET_ROOT_OUT)/d; \
    ln -sf /storage/self/primary $(TARGET_ROOT_OUT)/sdcard