自定义选择器活动:SecurityException UID n 没有对 content:// uri 的权限

Posted

技术标签:

【中文标题】自定义选择器活动:SecurityException UID n 没有对 content:// uri 的权限【英文标题】:Custom chooser activity: SecurityException UID n does not have permission to content:// uri 【发布时间】:2018-12-13 06:18:38 【问题描述】:

我正在构建一个选择器应用来替换原生 android 共享对话框。它工作正常,除非我尝试通过长按图像 > 共享图像从 Chrome 共享图像。

我发现 Google+ 没有捕捉到异常(它崩溃了),所以我可以通过 Logcat 查看它:

在 Google 上进行图片搜索。 选择一张图片(这应该会显示预览) 长按图片 选择“分享图片” 我的选择器活动弹出 选择 Google+ Google+ 因以下错误而崩溃:

java.lang.SecurityException:UID 10130 无权访问 content://com.android.chrome.FileProvider/images/screenshot/15307295588677864462883877407218.jpg [user 0]

我的代码(简化):

@Override
public void onCreate() 
    handleIntent();


private void handleIntent() 

    // Get intent and payload
    mIntent = getIntent();
    mPayloadIntent = (Intent) mIntent.getParcelableExtra(Intent.EXTRA_INTENT);

    // Nullify some things for queryIntentActivities (or no results will be found)
    mPayloadIntent.setComponent(null);
    mPayloadIntent.setPackage(null);

    // Retrieve a list of targets we can send mPayloadIntent to..
    List<ResolveInfo> targets = context.getPackageManager().queryIntentActivities(mPayloadIntent, 0);
    // etc...



private void onClickTarget(ResolveInfo target) 

    // Prepare..
    ComponentName compName = new ComponentName(
                target.activityInfo.applicationInfo.packageName,
                target.activityInfo.name);

    // Build a 'new' shareIntent
    Intent shareIntent = new Intent(mPayloadIntent);
    shareIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
    shareIntent.setComponent(compName);

    // Start the targeted activity with the shareIntent
    startActivity(shareIntent);
    finish();


AndroidManifest.xml:

<activity
    android:name=".ActShareReplace"
    android:label="Sharedr"
    android:theme="@style/AppTheme.TransparentActivity"
    >
    <intent-filter>
        <action android:name="android.intent.action.CHOOSER" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

如果我查看Intent.ACTION_CHOOSER 的文档,它会说:

如果需要通过选择器来授予URI权限,除了里面的EXTRA_INTENT外,还必须在ACTION_CHOOSER Intent上指定要授予的权限。这意味着使用 setClipData(ClipData) 来指定要授予的 URI 以及 FLAG_GRANT_READ_URI_PERMISSION 和/或 FLAG_GRANT_WRITE_URI_PERMISSION(视情况而定)。

我不完全确定这是否是我的应用程序必须做的事情,或者它是否是调用选择器活动的应用程序的责任 - 但我认为是后者。我的应用无法为其接收的意图设置 URI 权限,可以吗?

无论如何,如果我检查 mIntentmPayloadIntent 上的额外信息和标志,我会得到:

mIntent 只有附加功能,没有标志(据我所知):

android.intent.extra.CHOSEN_COMPONENT_INTENT_SENDER IntentSender4fa3901: android.os.BinderProxy@3aec3a6 (android.content.IntentSender)

android.intent.extra.INTENT Intent act=android.intent.action.SEND typ=image/jpeg flg=0x80001 clip=image/jpeg U:content://com.android.chrome.FileProvider/images/screenshot/15307316967108618905323381238187.jpg(有额外内容) (android.content.Intent)

android.intent.extra.TITLE 通过(java.lang.String)分享

mPayloadIntent:

android.intent.extra.STREAM content://com.android.chrome.FileProvider/images/screenshot/1530731945132897653908815339041.jpg (android.net.Uri$HierarchicalUri)

FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET FLAG_ACTIVITY_NEW_DOCUMENT FLAG_GRANT_READ_URI_PERMISSION

所以mPayloadIntentFLAG_GRANT_READ_URI_PERMISSION但mIntent没有。根据文档,它应该。

我读到我的应用程序可能使用了 URI 权限,所以 I tried caching the file myself 但是当我尝试通过 ContentResolver 访问 URI 时,我得到 - 你猜对了 - 权限错误。

然后我意识到我可能不应该缓存文件,因为 Android 的原生 Chooser Activity 似乎也没有这样做。这就是我现在所处的位置。回到第一格。

这是 Chrome 错误吗?安卓漏洞?还是我做错了什么?

我很乐意责怪 Chrome 并提交错误报告,但从事类似项目(并遇到相同问题)的人告诉我 Whatsapp 也有类似问题。它也通过 content:// uri 共享图像。

为了完整起见,我正在使用 Android 8.1 的 Pixel 2016 上进行测试。我不知道其他人(遇到与 WA 相同的问题)正在使用什么。

【问题讨论】:

【参考方案1】:

这是 Chrome 错误吗?安卓漏洞?还是我做错了什么?

我的猜测是这是一个客户端错误,来自人们直接创建ACTION_CHOOSERIntent 对象而不是通过Intent.createChooser()Intent.createChooser() 看起来它正在从你所谓的 mPayloadIntent 中获取标志并将它们添加到 mIntent

你应该可以自己测试一下。创建一个剪贴应用程序,该应用程序创建一个 IntentEXTRA_STREAM 指向某些内容(例如,由 FileProvider 提供服务)。然后,尝试以三种方式调用您的选择器:

    通过Intent.createChooser()包装Intent

    通过ACTION_CHOOSER Intent 包装Intent,您可以在其中按照文档所说的内容并将标志放在两个Intent 对象上

    通过ACTION_CHOOSER Intent 包装Intent,您可以跳过ACTION_CHOOSER Intent 上的标志

如果我是正确的,#1 和 #2 将起作用,而 #3 将失败并出现与您看到的相同的基本故障模式。

如果到目前为止我的理论成立,请尝试再次运行这三个应用程序,但这次使用系统选择器。我的猜测是,系统选择器确实从作为核心操作系统的一部分中获得了一些特殊的好处,并且所有三个都可以工作。否则,Chrome 和 WhatsApp 的开发者会在测试中遇到这个问题并修复它。

而且,如果所有这些理论都站得住脚……你有点搞砸了。我会假设更多的人使用Intent.createChooser() 而不是直接使用ACTION_CHOOSER,因为Intent.createChooser() 更简单。而且,使用ACTION_CHOOSER 的部分人实际上可能会遵循文档...

哈哈哈哈哈哈哈哈哈哈……喘息……哈哈哈哈哈哈哈哈哈!

...对于那些,你没事。而且,一些使用ACTION_CHOOSER 的人可能在EXTRA_STREAM 中有一个Uri,它是世界可读的(这不是一个好主意,但它在这里对你有利)。仅适用于手动创建 ACTION_CHOOSER、未能正确设置 Intent 标志但确实正确保护其内容的错误客户端,您将无法正确处理 @ 987654353@.

【讨论】:

谢谢,我会试一试的。也许我可以查看 Chrome 的源代码(它是操作系统),看看他们是如何将这个意图放在一起的。我确实找到了他们的(自定义/扩展)FileProvider 实现。 呸。看起来#1、#2 和#3 都有相同的问题。接收应用程序崩溃(或捕获错误并退出)。此外,看起来Intent.createChooser() 没有在意图或有效负载意图上添加 URI 权限标志,所以我尝试添加这些但没有雪茄。 通过Android原生ChooserActivity的代码阅读更多内容,我发现它使用startActivityAsCaller()方法来调用intent。它在 android/app/Activity.java 中声明,而不是公共 API 的一部分。 “这适用于作为中介运作的解析器和选择器活动”。我想我被****了:(((

以上是关于自定义选择器活动:SecurityException UID n 没有对 content:// uri 的权限的主要内容,如果未能解决你的问题,请参考以下文章

自定义列表项未响应选择器中的 state_checked

Laravel - 使用 Eloquent 查询构建器在选择中添加自定义列

如何在 Rails 中自定义活动管理视图?

使用自定义版本的 UITextField 时引发异常

iOS 自定义选择器ActionSheet

Android 自定义仿京东地址选择器