[AndroidContainer]sdcard分区挂载问题已知点分析

本文分析了ChromiumOS与Android容器之间的sdcard挂载问题,探讨了从Android的EmulatedVolume到ChromiumOS的挂载流程,涉及到esdfs、mount --bind、VoldNativeService以及binder通信。在ChromiumOS中,通过arc-setup将Android的数据目录挂载到容器内的相应位置,解决了权限和文件系统格式的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 由 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) {
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值