参考资料:
路径链接关系:
/sdcard ---> /storage/self/primary
/mnt/sdcard ---> /storage/self/primary
/storage/self/primary ---> /mnt/user/0/primary
/mnt/runtime/default/self/primary ---> /mnt/user/0/primary
/mnt/user/0/primary ---> /storage/emulated/0
因此最终是链接到/storage/emulated/0目录,/storage/emulated是通过fuse系统挂载的/data/media
/dev/fuse on /storage/emulated type fuse (rw,nosuid,nodev,noexec,noatime,user_id=1023,group_id=1023,default_permissions,allow_other)
storage默认开机在init.rc中挂载的是/mnt/runtime/default
# Mount default storage into root namespace
mount none /mnt/runtime/default /storage slave bind rec
重新挂载动作在EmulatedVolume::doMount()@EmulatedVolume.cpp
中完成。
因此/storage/emulated/0和/data/media/0目录内容是相同的,区别在于权限:
rk3399_firefly_edp_box:/storage/emulated # ls -l
drwxrwx--x 19 root sdcard_rw 4096 2013-01-20 13:41 0
rk3399_firefly_edp_box:/data/media # ls -l
drwxrwx--- 19 media_rw media_rw 4096 2013-01-20 13:41 0
/mnt/runtime各个目录意义:
/mnt/runtime/default - 对所有的应用、root命名空间(adb和其他系统组件)可见,而无需任何权限.
/mnt/runtime/read - 对有READ_EXTERNAL_STORAGE权限的应用可见。
/mnt/runtime/write - 对有WRITE_EXTERNAL_STORAGE权限的应用可见。
出现这三个不同权限目录的原因是控制不同权限app访问。然后利用挂载命名空间实现了挂载点的隔离,在不同挂载命名空间的进程,看到的目录层次不同。
实现是通过在zygote fork app 时,为每个运行中的应用创建一个 mount 名字空间。在MountEmulatedStorage()@com_android_internal_os_Zygote.cpp
static bool MountEmulatedStorage(uid_t uid, jint mount_mode,
bool force_mount_namespace) {
// See storage config details at http://source.android.com/tech/storage/
// Create a second private mount namespace for our process
if (unshare(CLONE_NEWNS) == -1) {
ALOGW("Failed to unshare(): %s", strerror(errno));
return false;
}
String8 storageSource;
if (mount_mode == MOUNT_EXTERNAL_DEFAULT) {
storageSource = "/mnt/runtime/default";
} else if (mount_mode == MOUNT_EXTERNAL_READ) {
storageSource = "/mnt/runtime/read";
} else if (mount_mode == MOUNT_EXTERNAL_WRITE) {
storageSource = "/mnt/runtime/write";
} else {
// Sane default of no storage visible
return true;
}
if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage",
NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
ALOGW("Failed to mount %s to /storage: %s", storageSource.string(), strerror(errno));
return false;
}
// Mount user-specific symlink helper into place
userid_t user_id = multiuser_get_user_id(uid);
const String8 userSource(String8::format("/mnt/user/%d", user_id));
if (fs_prepare_dir(userSource.string(), 0751, 0, 0) == -1) {
return false;
}
if (TEMP_FAILURE_RETRY(mount(userSource.string(), "/storage/self",
NULL, MS_BIND, NULL)) == -1) {
ALOGW("Failed to mount %s to /storage/self: %s", userSource.string(), strerror(errno));
return false;
}
return true;
}
存储目录:
文件夹中的文件又分为两类,一类是公有目录,还有一类是私有目录,其中的公有目录有DCIM、DOWNLOAD等,私有目录就是Android这个文件夹,这里边有许多包名组成的文件夹。