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.
I found that Google+ doesn't catch the exception (it crashes) so I can have a look at it via Logcat:
- Do an image search on Google.
- Select an image (this should show the preview)
- Longpress the image
- Choose "Share image"
- My chooser activity pops up
- Select Google+
- Google+ crashes with this error:
java.lang.SecurityException: UID 10130 does not have permission to content://com.android.chrome.FileProvider/images/screenshot/15307295588677864462883877407218.jpg [user 0]
My code (simplified):
@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>
If I look at the documentation for Intent.ACTION_CHOOSER it says:
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.
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?
Anyway, if I inspect the extra's and flags on mIntent
and mPayloadIntent
I get:
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.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 Share via (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
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.
Is this a Chrome bug? An Android bug? Or am I doing something wrong?
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.
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.
Is this a Chrome bug? An Android bug? Or am I doing something wrong?
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
.
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:
Wrap the
Intent
viaIntent.createChooser()
Wrap the
Intent
via anACTION_CHOOSER
Intent
, where you follow what the docs say and put the flags on bothIntent
objectsWrap the
Intent
via anACTION_CHOOSER
Intent
, where you skip the flags on theACTION_CHOOSER
Intent
If I am correct, #1 and #2 will work, and #3 will fail with the same basic failure mode that you're seeing.
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.
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...
hahahahahahahahaha... gasp ...hahahahahahahahahaha!
...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
.
来源:https://stackoverflow.com/questions/51179904/custom-chooser-activity-securityexception-uid-n-does-not-have-permission-to-con