V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
RikkaW
V2EX  ›  Android

Android Q 的 Scoped Storage 和 “沙盒”(早就没了)所有你需要知道的

  •  9
     
  •   RikkaW · 2019-09-04 16:09:19 +08:00 · 13230 次点击
    这是一个创建于 1689 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Scoped Storage ( Beta 3 起至今)

    官方文档 中的 "An app that uses scoped storage always has read/write access to the files that it creates, both inside and outside its app-specific directory." 这句话相当容易误解。其中的 "outside its app-specific directory" 并不是指应用可以像以前有存储权限时一样可以任意读写内置存储,而只是应用可以通过 Media Store 和 Storage Access Framework 在其专有文件夹以外建立文件并可任意访问。

    简而言之,使用 Scoped Storage 的行为如下:

    • 直接访问文件:只可访问 Android/data/<package> Android/media/<package>
    • 读取媒体(照片、影片、音乐):使用 Media Store,获取后使用 getContentResolver().openInputStream 打开文件
    • 插入 /删除媒体:使用 Media Store,文档并未提及
    • 访问任意文件:使用 Storage Access Framework

    使用 Media Store 插入图片的例子

    private boolean insertImage(File image) throws IOException {
        ContentValues values;
        // 向 Media Store 插入标记为待定的空白文件
        values = new ContentValues();
        values.put(MediaStore.Images.ImageColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "test"); // 不同类型文件可用 RELATIVE_PATH 不用,具体请参阅 MediaProvider 源码
        values.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, Long.toString(System.currentTimeMillis()));
        values.put(MediaStore.Images.ImageColumns.IS_PENDING, true);
        Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
        if (uri == null) {
            return false;
        }
        // 写入文件内容
        InputStream is = new FileInputStream(image);
        OutputStream os = getContentResolver().openOutputStream(uri, "rw");
        byte[] b = new byte[8192];
        for (int r; (r = is.read(b)) != -1; ) {
            os.write(b, 0, r);
        }
        os.flush();
        os.close();
        is.close();
        // 移除待定标记,其他应用可访问该文件
        values = new ContentValues();
        values.put(MediaStore.Images.ImageColumns.IS_PENDING, false);
        return getContentResolver().update(uri, values, null, null) == 1;
    }
    

    “沙盒”(只存在于 Beta 2,Beta 5 起删除相关代码

    Google 的“沙盒”的做法和 Rikka 的 Storage Redirect 核心部分原理相同,即使用挂载将一个只属于应用的文件夹(Android/sandbox)挂载为内置存储根目录,这样应用就只能访问该文件夹而不能访问真实的内置存储。

    但这样做显然会产生一些问题(包括但不限于):

    • 访问媒体文件:媒体存储返回假路径(/mnt/media 开头),在应用进程 hook 相关 IO 函数,如果是假路径就使用通过 content provider 获取到的远端 fd
    • 保存媒体文件:使媒体存储增加扫描 Android/sandbox
    • 跨挂载点移动文件:Google 未解决

    Google 在 Beta 2 的“沙盒”使用和 Rikka 一样的思路,即在最小化影响的前提下实现隔离应用产生的文件的功能。但结果是大部分用户根本不 care 有没有隔离(毕竟喜欢乱吐文件的应用几乎都来自中国大陆),只会关心自己要使用的应用有没有炸裂。

    个人觉得对 Google 来说,于其使用这样相对激进的方案到头来吃力不讨好,倒不如选择之后的更简单的 Scoped Storage,并给应用一个大版本的时间进行适配,因为毕竟哪种方案都需要应用开发者做出相同的适配工作。<del>然而现在文档既模糊又不全(</del>

    个人感慨

    应用滥用存储权限的问题自古以来就是一个大问题,Rikka 个人从小时候(划掉)起就一直想解决这个问题。所以 Rikka 从 2016 年底开始创造 Storage Redirect,至今已经有相当高的完成度,并且对各种问题都有相应的解决方案,只要使用者愿意稍微动一动脑子就可以获得相当好的体验。

    2019 年,Google 终于愿意开始解决这个问题,根据 Rikka 个人的实验和体验,绝大部分应用需要做的工作并没有很多,只是目前 Google 的文档过于模糊和残缺。

    只要 Google 在 Android R 时能真正推行所有应用必须作出改变,那 R 到来的一两年世界后将会变得更美好(划掉)。(当然如果有应用滥用 Storage Access Framework 的授权访问整个存储 Rikka 魔法还是有用的(划掉

    对某些过于乐观的人的疑惑(

    从 Beta 2 起,就不断地听到有人说“啊,有了 Q 就没有应用乱吐文件的问题啦”,Beta 2 之后砍掉沙盒也有人哀嚎“啊,怎么砍了”。然而即使保留,除非所有应用都进行适配,否则必然是无尽的“找不到文件”“打不开文件”。国内大厂的适配时间都是以年计算(想想 QQ WeChat 今年才支持接收 content uri ),所以即使予以保留,也肯定是要等待至少一两年后才能有比较好的体验(

    第 1 条附言  ·  2019-09-04 19:36:41 +08:00

    给普通用户的补充:

    在 Android 10 上,Scoped Storage 只针对 target 29 的应用启用,且应用还可以选择退出。换句话说,就 Android 10 而言,普通用户的体验没有任何变化

    根据 Google 的计划,在下个大版本对所有应用启用。

    给脑子不太够用的“高级用户”:

    Beta 2 的“沙盒”已经渣都不剩了,现在的 Scoped Storage 即使可以强制开启效果也与直接不给存储权限无异(正文第一大段)。

    31 条回复    2019-09-05 20:42:10 +08:00
    Love4Taylor
        1
    Love4Taylor  
       2019-09-04 16:11:28 +08:00
    rikka 大法好!
    z919126592
        2
    z919126592  
       2019-09-04 16:16:23 +08:00 via Android
    是 rikka 诶
    photon006
        3
    photon006  
       2019-09-04 16:17:47 +08:00
    今天升级 android 10 就遇到很多存储相关问题,play store 无法下载 app 更新,无法截图,微信无法选择图片发送给好友,photos 无法查看照片,很多网友也遇到:

    https://support.google.com/photos/thread/13511562?hl=en

    https://support.google.com/photos/thread/13518838?hl=en
    huaxianyan
        4
    huaxianyan  
       2019-09-04 16:25:09 +08:00
    Rikka 的钱钱又飞回来了

    今天用上了 Android 10,官方可以允许切换到三键模式好评,就是应用不能写剪贴板让我有点难受,其他设备给手机传点文本还要推送个通知过去再复制
    7654
        5
    7654  
       2019-09-04 16:27:31 +08:00
    不给权限不给用
    gz911122
        6
    gz911122  
       2019-09-04 16:28:33 +08:00
    是 rikka 耶
    Buges
        7
    Buges  
       2019-09-04 16:29:28 +08:00 via Android   ❤️ 1
    有一点不敢苟同的是,如果“沙盒”保留的话“找不到文件”等问题仅在最开始会存在,在国产厂商争相追 Android 版本的情况下,除非国内定制 ROM 魔改砍掉,否则定然会倒逼 app 做适配(大厂适配慢那是无足轻重的小问题,这种严重影响体验的 bug 不可能不跟进),不然新手机微信之类的都不能用了,怎么可能?
    虽然存储重定向的魔法确实好用,但从根本上让应用不再这么干不是更好么?
    起码到了 Q 终于不再需要 xprivacy 来阻止应用获取 IMEI 了,hook 一时爽,应用不再申请了当然更爽。
    expy
        8
    expy  
       2019-09-04 16:36:02 +08:00
    乐观的想法:不适配就崩溃,会倒逼应用适配啊。
    RikkaW
        9
    RikkaW  
    OP
       2019-09-04 16:44:36 +08:00
    @Buges 然而确实是可以选择完全不开启这个功能的(
    deorth
        10
    deorth  
       2019-09-04 16:48:44 +08:00
    是大佬,awsl
    tankren
        11
    tankren  
       2019-09-04 16:55:21 +08:00
    膜拜大佬 正在使用 Storage Redirect
    有个问题啊,微信启用了重定向之后 微博国际版的图片不能直接分享到微信了 分享操作可以无误的完成但是图片并没有发出去
    HankAviator
        12
    HankAviator  
       2019-09-04 16:59:09 +08:00 via Android
    逼一波大厂也得妥协,微信就是拖到不匹配通知渠道就从 play 下架的死线前不久才更新适配,之前拿各种借口搪塞,必须改时不也痛快。
    s82kd92l
        13
    s82kd92l  
       2019-09-04 18:09:07 +08:00
    好像 beta6 文档里面写了有新的 appops 类型可以强制 scoped storage, 不过正式发布的文档里面找不到这个描述了。不知道代码里面还有没有
    RikkaW
        15
    RikkaW  
    OP
       2019-09-04 18:33:20 +08:00
    @s82kd92l 相关的东西早就看过了 开了也没意义 “我求你了读一读第一段 Scoped Storage 的行为”
    (一种你就是最后讲的那种人的感觉
    momocraft
        16
    momocraft  
       2019-09-04 18:36:34 +08:00
    希望对国内厂家有效,play 版的 QQ 现在都不上架了...
    little_cup
        17
    little_cup  
       2019-09-04 18:37:29 +08:00
    @Buges 除了 Google,其他设备商只能逼小厂,大厂不愿适配那就只能乖乖 ROM 里写死给他们开白名单。
    echo314
        18
    echo314  
       2019-09-04 19:17:30 +08:00 via iPhone
    @little_cup Google 在这点考虑上可能并不是顾忌大厂不愿适配,而是因为直接强上影响用户体验,不管是厂商还是 Google 都会被用户骂。
    国内大厂不愿适配这点影响不大,Google 对海外安卓市场有极强的控制力,除非国内大厂想放弃海外市场,联合国内厂商搞白名单才有意义,毕竟面向海外的还是适配,既然都得适配为什么要搞两套呢?
    efsg
        19
    efsg  
       2019-09-04 19:27:34 +08:00
    不明觉厉 简单来说就是存储权限被废掉,不管怎么样都不能读写外部存储吗
    RikkaW
        20
    RikkaW  
    OP
       2019-09-04 19:29:10 +08:00
    @efsg 先读官方文档再读这个.. 现在是 target 29 才有(并且可以 opt-out ),计划是下个大版本强制
    huangyuanps2
        21
    huangyuanps2  
       2019-09-04 21:49:01 +08:00
    哇,是 RikkaW 大佬,感谢大佬做的储存重定向。给父母的 Android 一般装了稳定版系统,不开放 root,所以也挺期待 Android R 正式发布的。对往储存里乱扔垃圾的 app 早就受够了。。。
    jinyang656
        22
    jinyang656  
       2019-09-04 22:23:17 +08:00 via Android
    Google 真是太没魄力了,幸亏还有 Storage Redirect 可用
    Narcissu5
        23
    Narcissu5  
       2019-09-04 22:37:18 +08:00
    这个真的是 Android 和 ios 差距最大的地方了,而且一点好转的迹象都看不到

    我觉得 redirect 不一定会引起奔溃,最多一些功能比如发送文件不可用。启用与否完全可以交给用户,不知道为什么要移除
    KamenReborn
        24
    KamenReborn  
       2019-09-04 22:48:12 +08:00 via Android
    是 rikka,啊,我死了
    RikkaW
        25
    RikkaW  
    OP
       2019-09-05 00:17:47 +08:00
    @Narcissu5 然而一般用户真的没有这个脑子来理解这些(以及旧方案用系统的身份做那些稍微有点脏
    gzxu
        26
    gzxu  
       2019-09-05 06:33:21 +08:00 via Android
    所以这意味着终端模拟器不能好好地访问公共存储了🤔除非 root,毕竟纯 C 程序还没办法直接访问 SAF,当然 Beta2-5 的方案下面也没办法好好访问
    wanacry
        27
    wanacry  
       2019-09-05 08:06:09 +08:00 via iPhone
    想和 rikka 一起生猴子🐒
    fetich
        28
    fetich  
       2019-09-05 09:57:15 +08:00
    存储重定向真是个好东西,奈何必须 root
    lonelinsky
        29
    lonelinsky  
       2019-09-05 09:59:02 +08:00
    @photon006 感觉是 Media Storage(Media Provider) 数据库混乱了,可以试下清空 Media Storage 数据库重建看看,我碰到了,通过这个解决了。
    smarthing
        30
    smarthing  
       2019-09-05 16:31:11 +08:00
    SAF 被滥用的话,仍然然决不了乱写 sdcard 的问题。

    如果能做到只有默认文件管理器才能使用 SAF 的话,这个情况是否会有改善? @RikkaW
    kn007
        31
    kn007  
       2019-09-05 20:42:10 +08:00   ❤️ 1
    啊,钱钱还在!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1250 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 77ms · UTC 17:46 · PVG 01:46 · LAX 10:46 · JFK 13:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.