定制选择器活动:SecurityException UID n没有对content://uri的许可 [英] Custom chooser activity: SecurityException UID n does not have permission to content:// uri
问题描述
我正在构建一个Chooser应用程序,该应用程序将替换本机的Android Share对话框.除我尝试通过长按图像>共享图像从Chrome共享图像外,它都可以正常工作.
I'm building a Chooser app that replaces the native Android Share dialog. It works fine except when I try to share an image from Chrome via longpress image > share image.
我发现Google+没有捕获到异常(崩溃),因此我可以通过Logcat进行查看:
I found that Google+ doesn't catch the exception (it crashes) so I can have a look at it via Logcat:
- 在Google上进行图片搜索.
- 选择一张图片(这应该显示预览)
- 长按图片
- 选择共享图片"
- 弹出我的选择器活动
- 选择Google +
- Google+因以下错误而崩溃:
java.lang.SecurityException:UID 10130没有对content://com.android.chrome.FileProvider/images/screenshot/15307295588677864462883877407218.jpg [user 0]的权限
java.lang.SecurityException: UID 10130 does not have permission to 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:
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
If I look at the documentation for Intent.ACTION_CHOOSER it says:
如果需要通过选择器授予URI权限,除了内部的EXTRA_INTENT之外,还必须指定要在ACTION_CHOOSER Intent上授予的权限.这意味着使用setClipData(ClipData)来指定要授予的URI以及相应的FLAG_GRANT_READ_URI_PERMISSION和/或FLAG_GRANT_WRITE_URI_PERMISSION.
If you need to grant URI permissions through a chooser, you must specify the permissions to be granted on the ACTION_CHOOSER Intent in addition to the EXTRA_INTENT inside. This means using setClipData(ClipData) to specify the URIs to be granted as well as FLAG_GRANT_READ_URI_PERMISSION and/or FLAG_GRANT_WRITE_URI_PERMISSION as appropriate.
我不确定这是我的应用程序必须执行的事情,还是调用选择器活动的应用程序的责任-但我认为是后者.我的应用无法为其接收的意图设置URI权限,可以吗?
I'm not completely sure if this is something my app has to do or if it's the responsibility of the app that invoked the chooser activity - but I would assume it's the latter. My app can't set URI permissions for intents it's receiving, can it?
无论如何,如果我检查mIntent
和mPayloadIntent
上的多余符号和标志,则会得到:
Anyway, if I inspect the extra's and flags on mIntent
and mPayloadIntent
I get:
mIntent仅具有附加功能,没有标志(据我所知):
mIntent only has extras, no flags (as far as I can tell):
android.intent.extra.CHOSEN_COMPONENT_INTENT_SENDER IntentSender {4fa3901:android.os.BinderProxy@3aec3a6}(android.content.IntentSender)
android.intent.extra.CHOSEN_COMPONENT_INTENT_SENDER IntentSender{4fa3901: android.os.BinderProxy@3aec3a6} (android.content.IntentSender)
android.intent.extra.INTENT 意图{act = android.intent.action.SEND typ = image/jpeg flg = 0x80001 clip = {image/jpeg U:content://com.android.chrome.FileProvider/images/screenshot/15307316967108618905905323381238187.jpg}(有其他功能) )}(android.content.Intent)
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} (has extras) } (android.content.Intent)
android.intent.extra.TITLE 通过(java.lang.String)共享
android.intent.extra.TITLE Share via (java.lang.String)
mPayloadIntent:
mPayloadIntent:
android.intent.extra.STREAM content://com.android.chrome.FileProvider/images/screenshot/1530731945132897653908815339041.jpg(android.net.Uri $ HierarchicalUri)
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
-
通过
Intent.createChooser()
因此mPayloadIntent
没有FLAG_GRANT_READ_URI_PERMISSION
,但是mIntent 没有.根据文档,应该这样.
So mPayloadIntent
does have the FLAG_GRANT_READ_URI_PERMISSION
but mIntent does not. According to the docs it should.
I've read that it's possible that my app consumed the URI permission so I tried caching the file myself but as soon as I try to access the URI through a ContentResolver, I get a - you guessed it - permission error.
I then realized that I probably shouldn't have to cache the file as Android's native Chooser Activity doesn't seem to do that either. So that's where I'm at now. Back to square one.
这是Chrome的错误吗?一个Android错误?还是我做错了什么?
Is this a Chrome bug? An Android bug? Or am I doing something wrong?
我很乐意归咎于Chrome并提交错误报告,但是从事类似项目(并遇到相同问题)的某人告诉我,Whatsapp也存在类似问题.它还通过content://uri共享图像.
I'd happily blame Chrome and file a bug report but someone who's working on a similar project (and ran into the same issue) told me Whatsapp has a similar problem. It, too, shares images via a content:// uri.
出于完整性考虑,我正在使用Android 8.1的Pixel 2016进行测试.我不知道另一个人(遇到WA的同一问题)正在使用什么.
For completeness, I'm testing this on a Pixel 2016 with Android 8.1. I have no idea what the other guy (who ran into the same issue with WA) is using.
推荐答案
这是Chrome的错误吗?一个Android错误?还是我做错了什么?
Is this a Chrome bug? An Android bug? Or am I doing something wrong?
我的猜测是这是一个客户端错误,来自于直接创建ACTION_CHOOSER
Intent
对象而不是通过Intent.createChooser()
创建对象的人. Intent.createChooser()
似乎正在从您所谓的mPayloadIntent
中获取标志并将其添加到mIntent
.
My guess is that it is a client-side bug, coming from people creating ACTION_CHOOSER
Intent
objects directly rather than through Intent.createChooser()
. Intent.createChooser()
looks like it is taking the flags from what you called mPayloadIntent
and adds them to mIntent
.
您应该可以自己进行测试.创建一个剪贴簿应用程序,该应用程序创建一个ACTION_SEND
Intent
,其中EXTRA_STREAM
指向某段内容(例如,由FileProvider
提供).然后,尝试通过三种方式调用选择器:
You should be able to test this yourself. Create a scrap app that creates an ACTION_SEND
Intent
with EXTRA_STREAM
pointing to some piece of content (e.g., served by FileProvider
). Then, try invoking your chooser three ways:
通过ACTION_CHOOSER
Intent
包裹Intent
,您可以按照文档的说明在两个Intent
对象上放置标志
Wrap the Intent
via an ACTION_CHOOSER
Intent
, where you follow what the docs say and put the flags on both Intent
objects
通过ACTION_CHOOSER
Intent
包裹Intent
,在此跳过ACTION_CHOOSER
Intent
Wrap the Intent
via an ACTION_CHOOSER
Intent
, where you skip the flags on the ACTION_CHOOSER
Intent
如果我是对的,则#1和#2可以工作,而#3将以与您看到的相同的基本故障模式失败.
If I am correct, #1 and #2 will work, and #3 will fail with the same basic failure mode that you're seeing.
如果到目前为止,我的理论仍然有效,请尝试再次运行这三个应用程序,但这一次使用系统选择器.我的猜测是,作为核心操作系统的一部分,系统选择器确实会获得一些特殊的好处,并且所有这三种都可以使用.否则,Chrome和WhatsApp的开发人员可能会在测试中遇到此问题并予以解决.
If my theory holds up so far, try running the three apps again, but this time use the system chooser. My guess is that the system chooser does get some special benefits from being part of the core OS and all three will work. Otherwise, the developers of Chrome and WhatsApp would have run into this problem in their testing and would have fixed it.
而且,如果所有这些理论都成立了,那您就有些困惑了.我认为使用Intent.createChooser()
的人数要多于直接使用ACTION_CHOOSER
的人数,因为Intent.createChooser()
更简单.而且,某些使用ACTION_CHOOSER
的人的子集可能实际上遵循了文档...
And, if all of this theory holds up... you're somewhat screwed. I would assume that more people use Intent.createChooser()
than use ACTION_CHOOSER
directly, as Intent.createChooser()
is simpler. And, some subset of the people who use ACTION_CHOOSER
might actually follow the documentation...
hahahahahahahahahaha ...... gasp ... hahahahahahahahahahahaha!
hahahahahahahahaha... gasp ...hahahahahahahahahaha!
...对于这些,您还可以.而且,某些使用ACTION_CHOOSER
的人可能在EXTRA_STREAM
中有一个Uri
,这是世界可读的(这不是一个好主意,但在这里对您有用).仅适用于手动创建ACTION_CHOOSER
,无法正确设置Intent
标志,但 do 正确保护其内容的错误客户端,您将无法正确处理Intent
.
...and for those, you're OK. And, some people using ACTION_CHOOSER
might have a Uri
in EXTRA_STREAM
that is world-readable (which isn't a good idea, but it works in your favor here). It will only be for buggy clients that create ACTION_CHOOSER
manually, fail to set the Intent
flags properly, but do secure their content properly, that you won't be able to correctly process the Intent
.
这篇关于定制选择器活动:SecurityException UID n没有对content://uri的许可的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!