Thursday, 12 July 2018

Custom chooser activity: SecurityException UID n does not have permission to content:// uri

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.



from Custom chooser activity: SecurityException UID n does not have permission to content:// uri

No comments:

Post a Comment