《Android外部存储》

本文详细探讨了Android外部存储从Android 4.0到7.0的演变过程,包括模拟外部存储、多用户支持和动态权限管理等关键特性。模拟外部存储通过FUSE实现,解决了FAT32的法律问题,为多用户提供基础。Android 4.2开始支持多用户,利用挂载命名空间和绑定挂载实现用户间的存储隔离。动态权限管理在Android 6.0引入,允许用户动态授权外部存储访问权限,利用FUSE和挂载命名空间实现不重启进程的权限切换。
摘要由CSDN通过智能技术生成

本文来自于腾讯Bugly公众号(weixinBugly), 作者:chivyzhuang,未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/qT5waBvKVbqhuqXYHC-3cA

| 导语 外部存储作为开发中经常接触的一个重要系统组成,在Android历代版本中,有过许许多多重要的变更。我也曾疑惑过,为什么一个简简单单外部存储,会存在存在这么多奇奇怪怪的路径
:/sdcard、/mnt/sdacrd、/storage/extSdCard、/mnt/shell/emulated/0、/storage/emulated/0、/mnt/shell/runtime/default/emulated/0…其实,这背后代表了一项项技术的成熟与发布:模拟外部存储、多用户、运行时权限…

一、各版本外部存储特性

Android 4.0

支持模拟外部存储(通过FUSE实现)
出现了主外部存储,以及二级外部存储(没有接口对外暴露)
支持MTP(Media Transfer Protocol)、PTP协议(Picture Transfer Protocol)

Android 4.1

开发者选项出现”强制应用声明读权限才可以进行读操作”的开关

Android 4.2

支持多用户,每个用户拥有独立的外部存储

Android 4.4

  • 读操作需要声明READ_EXTERNAL_STORAGE权限
  • 应用读写在外部存储的应用目录(/sdcard/Android//)不需要声明权限
  • 增加了Context.getExternalFilesDirs() 接口,可以获取应用在主外部存储和其他二级外部存储下的files路径
  • 引入存储访问框架(SAF,Storage Access Framework)

这里写图片描述

Android 6.0

外部存储支持动态权限管理
Adoptable Storage特性

Android 7.0

  • 引入作用域目录访问

这里写图片描述

补充一个点:如果应用的minSdkVersion和targetSdkVersion设置成<=3,系统会默认授予READ_EXTERNAL_STORAGE权限

二、部分特性讲解

1. 模拟外部存储

a. 必要性

b. 实现原理

系统/system/bin/sdcard守护进程,使用FUSE实现类FAT格式SD卡文件系统的模拟,也就是我们经常说的内置SD卡。(详细代码可以参考:/xref/system/core/sdcard/sdcard.c)

用户空间文件系统(Filesystem in Userspace,简称FUSE)是一个面向类Unix计算机操作系统的软件接口,它使无特权的用户能够无需编辑内核代码而创建自己的文件系统。目前Linux通过内核模块对此进行支持。

>![](3.png)

sdcard守护进程模拟外部存储大致流程(Android 4.0为例):

  • 首先,指定/data/media目录用于模拟外部存储。该路径的owner和group一般为media_rw,这样保证只有sdcard程序或root进程能够访问该目录。
# create virtual SD card at /mnt/sdcard, based on the /data/media directory
# daemon will drop to user/group system/media_rw after initializing
# underlying files in /data/media will be created with user and group media_rw (1023)
service sdcard /system/bin/sdcard /data/media 1023 1023
    class late_start
  • sdcard守护进程启动后,打开/dev/fuse设备。
fd = open("/dev/fuse", O_RDWR);
if (fd < 0) {
    ERROR("cannot open fuse device (%d)\n", errno);
    return -1;
}
  • 在/mnt/sdcard目录挂载fuse文件系统。
#define MOUNT_POINT "/mnt/sdcard"
...
sprintf(opts, "fd=%i,rootmode=40000,default_permissions,allow_other,"
        "user_id=%d,group_id=%d", fd, uid, gid);

res = mount("/dev/fuse", MOUNT_POINT, "fuse", MS_NOSUID | MS_NODEV, opts);
if (res < 0) {
  ERROR("cannot mount fuse filesystem (%d)\n", errno);
  return -1;
}

*开线程,在线程中处理文件系统事件,并将结果写回。

void handle_fuse_requests(struct fuse *fuse)
{
    unsigned char req[256 * 1024 + 128];
    int len;

    for (;;) {
        len = read(fuse->fd, req, 8192);
        if (len < 0) {
            if (errno == EINTR)
                continue;
            ERROR("handle_fuse_requests: errno=%d\n", errno);
            return;
        }
        handle_fuse_request(fuse, (void*) req, (void*) (req + sizeof(struct fuse_in_header)), len);
    }
}

经过上面一系列步骤,sdcard进程在/mnt/sdcard路径上创建了一个FUSE文件系统,所有对/mnt/sdcard将转为事件由sdcard守护进程处理,并对应到/data/media目录。
例如,应用创建/mnt/sdcard/a文件,实际是创建/data/media/a文件。

c. 优点

模拟外部存储容量和/data分区是共享的,用户数据在内外存储的分配更加自由;
模拟外部存储本身不可卸载,不会因为卸载导致应用访问出现问题,也减少了外部因素导致被破坏的情况;
所有的访问都经过sdcard守护进程,Android可以定制访问规则;

d. 劣势

性能上存在一定损失

e. 影响

Android 6.0以后,由于动态权限管理的需要,会存在多个fuse挂载点,这导致inotify/FileObserver对外部存储进行文件事件监控时,会丢失事件。

inotify是Linux核心子系统之一,做为文件系统的附加功能,它可监控文件系统并将异动通知应用程序。 —— 维基百科(

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android系统在访问外部存储设备时,需要获取相应的权限。外部存储权限允许应用程序访问设备上的SD卡、USB存储器等外部存储设备,以便应用程序可以读取、写入和删除存储设备上的文件。 要在Android应用程序中请求外部存储权限,首先需要在AndroidManifest.xml文件中声明相应的权限: <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 在Android 6.0及以上版本中,还需要在运行时向用户请求外部存储权限。可以在应用程序中通过检查权限是否被授予来确定用户是否已经允许了外部存储权限。如果权限未被授予,可以通过以下步骤向用户请求权限: 1. 创建一个权限请求对话框,向用户解释为何需要外部存储权限。 2. 使用requestPermissions()方法向用户请求权限。 3. 在onRequestPermissionsResult()方法中处理权限请求的结果,根据用户的选择对应用程序进行响应。 一旦应用程序被授予了外部存储权限,就可以使用相关的API来访问外部存储设备上的文件。例如,可以使用File类或者DocumentFile类来读取、写入和删除文件。另外,还可以使用SAF(Storage Access Framework)来允许用户通过文件选择器来选择外部存储中的文件。 需要注意的是,在访问外部存储设备时,开发人员需要小心谨慎,以避免对用户数据造成破坏或泄露。所以在写入或删除文件时,应该确保用户已经授予相应的权限,并且要谨慎处理文件操作,以避免不必要的损失。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值