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