- 由 b178903294创建, 最后修改于1月 15, 2020 , 版权所有,谢绝转载
前言: chromiumOS与安卓容器之间不仅需要有数据沟通的桥梁ArcBridgeService 还要有文件交换的通道,那就是我们两个系统的下载目录。
chromiumOS这边 编译时在build_packages添加esdfs USE标志 并且在platform2/arc/setup/etc/config.json 中设置为"USE_ESDFS": true,
在/src/overlays/overlay-variant-coral-cvte/profiles/base/make.defaults中添加USE="${USE} esdfs"
即可由arc-setup 将/opt/google/containers/android/rootfs/android-data/media 挂载到/run/arc/sdcrd/(default || write || read)/emulated 并绑定挂载到/home/chronos/user/Downloads
*原生安卓*执行挂载流程,是由/system/vold/model/EmulatedVolume.cpp 中执行execl system/bin/sdcard 来执行挂载的。sdcard里面的挂载逻辑是判断安卓系统编译属性来确定是挂载哪种格式,详见代码/system/sdcard/sdcard.cpp
由于看见谷歌网上论坛的一个回帖: https://groups.google.com/a/chromium.org/forum/#!searchin/chromium-os-reviews/vold-sdcard%7Csort:date/chromium-os-reviews/DSsvjJupI_I/MtrIg-JjBwAJ 里面写道:
The current Android upstream design is that
vold -> sdcard.cpp (responsible for mounting) -> esdfs
The ARC++ design could be
vold -> sdcard.cpp (running outside of Android container) -> esdfs
|
我就坚信了是由sdcard.cpp实现的挂载操作。然后就遇到了权限问题,一头扎进了内核,寻找许久未果。
后来把fydeos 中的sdcard 文件加进自己编译的包中运行,发现报错如下:
failed to open fuse device: No such file or directory
failed to fuse_setup: No such file or directory
|
然后再谷歌和fydeos的机器上手动运行也同样报错:
sdcard E 11-22 19:45:18 1153 1153 sdcard.cpp:295] setting RLIMIT_NOFILE failed: Operation not permitted (有时没有这句)
sdcard E 11-22 19:45:18 1153 1153 run_fuse.cpp:178] failed to open fuse device: No such file or directory
sdcard F 11-22 19:45:18 1153 1153 run_fuse.cpp:301] failed to fuse_setup: No such file or directory
|
既然是挂载esdfs 但是显然谷歌的sdcard文件还是在进行挂载fuse的逻辑中,并且同样会报错。 因为没有/dev/fuse这个设备可以来进行挂载。
然后想到是vold调取sdcard文件的 所以就查看了谷歌安卓容器中vold的log:
11-22 19:42:00.411 19 19 I vold : Vold 3.0 (the awakening) firing up
11-22 19:42:00.411 19 19 V vold : Detected support for : ext4
11-22 19:42:00.430 19 19 E vold : Failed open : No such file or directory
11-22 19:42:00.430 19 19 E vold : Failed to opendir: No such file or directory
11-22 19:42:00.437 19 19 I vold : [libfs_mgr]fs_mgr_read_fstab_dt(): failed to read fstab from dt
11-22 19:42:00.441 19 19 D vold : ArcVoldNativeService::start() completed OK
11-22 19:42:00.441 19 19 D vold : VoldNativeService::start() completed OK
11-22 19:42:00.456 19 21 D vold : e4crypt_init_user0
11-22 19:42:00.456 19 21 D vold : e4crypt_prepare_user_storage for volume null, user 0, serial 0, flags 1
11-22 19:42:00.456 19 21 D vold : Preparing: /data/system/users/0
11-22 19:42:00.456 19 21 E vold : Failed to prepare /data/system/users/0 : No such file or directory
11-22 19:42:00.456 19 21 E vold : Failed to prepare user 0 storage
11-22 19:42:08.030 19 23 D vold : e4crypt_init_user0
11-22 19:42:08.030 19 23 D vold : e4crypt_prepare_user_storage for volume null, user 0, serial 0, flags 1
11-22 19:42:08.030 19 23 D vold : Preparing: /data/system/users/0
11-22 19:42:08.030 19 23 D vold : Preparing: /data/misc/profiles/cur/0
11-22 19:42:08.047 19 23 D vold : Preparing: /data/system_de/0
11-22 19:42:08.056 19 23 D vold : Preparing: /data/misc_de/0
11-22 19:42:08.102 19 23 D vold : Preparing: /data/vendor_de/0
11-22 19:42:08.114 19 23 D vold : Preparing: /data/user_de/0
11-22 19:42:08.122 19 23 V vold : /system/bin/vold_prepare_subdirs
11-22 19:42:08.122 19 23 V vold : prepare
11-22 19:42:08.122 19 23 V vold :
11-22 19:42:08.122 19 23 V vold : 0
11-22 19:42:08.122 19 23 V vold : 1
11-22 19:42:08.231 19 23 I vold_prepare_subdirs: SELinux: Loaded file_contexts
11-22 19:42:08.234 111 111 D vold_prepare_subdirs: Setting up mode 700 uid 0 gid 0 context u:object_r:vold_data_file:s0 on path: /data/misc_de/0/vold
11-22 19:42:08.248 111 111 D vold_prepare_subdirs: Setting up mode 700 uid 0 gid 0 context u:object_r:storaged_data_file:s0 on path: /data/misc_de/0/storaged
11-22 19:42:08.248 111 111 D vold_prepare_subdirs: Setting up mode 700 uid 1000 gid 1000 context u:object_r:fingerprint_vendor_data_file:s0 on path: /data/vendor_de/0/fpdata
11-22 19:42:08.284 19 23 D vold : e4crypt_unlock_user_key 0 serial=0 token_present=0
11-22 19:42:12.683 19 23 D vold : e4crypt_unlock_user_key 0 serial=0 token_present=0
11-22 19:42:12.684 137 212 I ActivityManager: Force stopping com.android.providers.media appid=10006 user=-1: vold reset
11-22 19:42:12.687 19 23 I vold : Polling...: /var/run/arc/sdcard/write/emulated // 注意这两句
11-22 19:42:12.687 19 23 I vold : sdcard has been mounted
11-22 19:42:14.545 19 23 D vold : e4crypt_prepare_user_storage for volume null, user 0, serial 0, flags 2
11-22 19:42:14.545 19 23 D vold : Preparing: /data/system_ce/0
11-22 19:42:14.545 19 23 D vold : Preparing: /data/misc_ce/0
11-22 19:42:14.545 19 23 D vold : Preparing: /data/vendor_ce/0
11-22 19:42:14.545 19 23 D vold : Preparing: /data/media/0
11-22 19:42:14.545 19 23 D vold : Preparing: /data/data
11-22 19:42:14.545 19 23 V vold : Starting restorecon of /data/system_ce/0
11-22 19:42:14.592 19 23 V vold : Finished restorecon of /data/system_ce/0
11-22 19:42:14.592 19 23 V vold : Starting restorecon of /data/misc_ce/0
11-22 19:42:14.602 19 23 V vold : Finished restorecon of /data/misc_ce/0
11-22 19:42:14.602 19 23 V vold : /system/bin/vold_prepare_subdirs
|
看到了挂载成功的log,但是相关log在我们的代码中并没有。 并且谷歌安卓容器里面的log 并没有看到任何sdcard的信息,即使最初的挂载格式提示也没有:
static bool should_use_sdcardfs( void ) {
char property[PROPERTY_VALUE_MAX];
// Allow user to have a strong opinion about state
property_get(PROP_SDCARDFS_USER, property, "" );
if (! strcmp (property, "force_on" )) {
LOG(WARNING) << "User explicitly enabled sdcardfs" ;
return true ;
} else if (! strcmp (property, "force_off" )) {
LOG(WARNING) << "User explicitly disabled sdcardfs" ;
return !supports_esdfs();
}
// Fall back to device opinion about state
if (property_get_bool(PROP_SDCARDFS_DEVICE, true )) {
LOG(WARNING) << "Device explicitly enabled sdcardfs" ;
return true ;
} else {
LOG(WARNING) << "Device explicitly disabled sdcardfs" ;
return !supports_esdfs();
}
}
|
这段代码在https://chromium.googlesource.com/aosp/platform/system/core/+/refs/heads/upstream/sdcard/sdcard.cpp 无论是master分支和upstream分支 都有这段代码,所以就想知道为什么没有打印这段代码。 所以就把谷歌的sdcard文件直接二进制打开 然后读里面的log字符,发现确实没有这几句。可能谷歌的这个sdcard就是直接挂载fuse的。二进制文件读出的log如下:
sdcard.txt :sdcard
接着读谷歌vold二进制文件:
vold.txt :vold
发现了几个点:
9
10
11
|
ArcVoldNativeService::start.
Unable to start ArcVoldNativeService.
ArcVoldNativeService::start() completed OK.
|
上面这个显然是重写了VoldNativeService.cpp 文件
102
103
104
105
106
107
108
|
mountAppFuse.arc_app_fuse_mounter_service. 参考(VoldNativeService.cpp +503)
system /vold/VoldNativeService .cpp.
Can not get ArcAppFuseMounterService.
unmountAppFuse.
open AppFuseFile.
|
这里应该是用到了AppFuseMount mojom。
158
159
|
arc_volume_mounter_service.
Could not get ArcVolumeMounterService.VolumeManager::updateVirtualDisk.
|
这里使用VolumeMounter mojom 进行mountevent 更新。
system /vold/model/ArcEmulatedVolume .cpp .Polling...: .sdcard has been mounted.
|
这里原来调用sdcard的EmulatedVolume.cpp文件 重写了。 所以考虑到没有看到sdcard挂载fuse失败的log ,严重怀疑就是在这里面执行了挂载逻辑而并没有使用sdcard程序。具体怎样绕过内核权限和mount namespace 将/opt/google/containers/android/rootfs/android-data/media 挂载到安卓rootfs 里的/mnt/runtime/(default || write || read)/emulated 都应该是在这里面实现的。
目前了解到的几个点都在这里。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~下面分析vold sdcard挂载流程~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Volume Daemon,用于管理和控制Android平台外部存储设备的后台进程,这些管理和控制,包括SD卡的插拔事件检测/SD卡挂载/卸载/格式化等.
9.0以前framework java层(StorageManagerService)和native层(Vold)的通信是socket,9.0以后使用binder通信. 通过SD卡挂载流程,分析binder在vold服务中的使用.
vold服务在开机的时候会启动.定义于 system /vold/vold.rc文件中:
service vold / system /bin/vold \
--blkid_context=u:r:blkid:s0 --blkid_untrusted_context=u:r:blkid_untrusted:s0 \
--fsck_context=u:r:fsck:s0 --fsck_untrusted_context=u:r:fsck_untrusted:s0
class core
ioprio be 2
writepid /dev/cpuset/foreground/tasks
shutdown critical
group reserved_disk
|
被init进程启动后,将调用system/vold/main.cpp中的main函数,然后初始化VolumeManager,NetlinkManager等等.初始化Vold服务.
在看下StorageManagerService的初始化.StorageManagerService由SystemServer启动,我们简单看看它的启动流程:
//调用SystemServiceManager的startService
mSystemServiceManager.startService(STORAGE_MANAGER_SERVICE_CLASS);
最终的实现如下:
public void startService(@NonNull final SystemService service) {
// Register it.
mServices.add(service);
// Start it.
long time = SystemClock.elapsedRealtime();
try {
//调用服务的onStart方法.
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException( "Failed to start service " + service.getClass().getName()
+ ": onStart threw an exception" , ex);
}
warnIfTooLong(SystemClock.elapsedRealtime() - time , service, "onStart" );
}
//StorageManagerService的onStart方法如下:
@Override
public void onStart() {
//创建StorageManagerService
mStorageManagerService = new StorageManagerService(getContext());
//将StorageManagerService注册到ServiceManager中
publishBinderService( "mount" , mStorageManagerService);
//调用StorageManagerService的start方法
mStorageManagerService.start();
}
private void start() {
connect();
}
//主要建立和Vold的通信,获取mVold对象,与Vold进程通信.
private void connect() {
IBinder binder = ServiceManager.getService( "storaged" );
if (binder != null) {
try {
//为binder对象设置死亡代理。当binder死亡后重新建立连接.
binder.linkToDeath( new DeathRecipient() {
@Override
public void binderDied() {
Slog.w(TAG, "storaged died; reconnecting" );
mStoraged = null;
connect();
}
}, 0);
} catch (RemoteException e) {
binder = null;
}
}
if (binder != null) {
mStoraged = IStoraged.Stub.asInterface(binder);
} else {
Slog.w(TAG, "storaged not found; trying again" );
}
binder = ServiceManager.getService( "vold" );
if (binder != null) {
try {
//为binder对象设置死亡代理。当binder死亡后重新建立连接.
binder.linkToDeath( new DeathRecipient() {
@Override
public void binderDied() {
Slog.w(TAG, "vold died; reconnecting" );
mVold = null;
connect();
}
}, 0);
} catch (RemoteException e) {
binder = null;
}
}
if (binder != null) {
|