androidandroid-fileproviderandroid-securityexceptionandroid-13

Android 13 FileProvider: Unable to access file descriptor from URI despite granting temporary permissions


For some time we have been using the FileProvider APIs to reading/writing a file in App A's internal data directory (/data/data/app.a.package/files/someFile) from App B using a BroadcastReceiver. Here is a flow of the communication between the apps:

App B -- broadcast intent requesting someFile --> App A
App A -> use FileProvider API to get URI for someFile 
App A -- broadcast intent with someFile URI --> App B
App B -> open file descriptor of URI and write contents

Here is a snippet of what has worked and continues to work on devices with Android 12 and lower (targetSdk bumped up to latest 33 on both App A and App B) but fails to work on Android 13 devices:

val fileUri = FileProvider.getUriForFile(context, "app.a.package.fileprovider", someFile)
if (fileUri != null) {
    resultIntent.putExtra(FILE_URI_EXTRA, fileUri)

   // We need to explicitly grant permissions to the package that will request the URI from this FileProvider
   context.grantUriPermission(
      "app.b.package", fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION or
                        Intent.FLAG_GRANT_WRITE_URI_PERMISSION
    )

    // Also tried adding these for good measure, not needed on Android 12 devices or lower, doesn't help on Android 13
    resultIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    resultIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)

    context.sendBroadcast(resultIntent)
}                                    

On the BroadcastReceiver side, here is a minimal snippet that generates a SecurityException only on Android 13 devices:

                Uri fileUri = intent.getParcelableExtra(FILE_URI_EXTRA);
                if (fileUri == null)
                    return; // failed to get data
                try {
                    /*
                     * Get the content resolver instance for this context, and use it
                     * to get a ParcelFileDescriptor for the file.
                     */
                    ParcelFileDescriptor inputPFD = context.getContentResolver().openFileDescriptor(fileUri, "rw");
                    if (inputPFD == null)
                        return;
                    FileDescriptor licenseFileFD = inputPFD.getFileDescriptor();

On Android 13, attempting to access the file descriptor is resulting in androidx.core.content.FileProvider from ProcessRecord{37fcd9d 7629:app.b.package/u0a245} (pid=7629, uid=10245) that is not exported from UID 10244

I've been combing through Google's behavior change documentation but can't seem to pinpoint what would cause this breaking change.


Solution

  • Figured out the issue, it is related to the package visibility behavior changes. I needed to make sure that both App A and App B had the following package visibilities.

    App A:

    <queries>
        <package android:name="app.b.package" />
    </queries>
    

    App B:

    <queries>
        <package android:name="app.a.package" />
    </queries>
    

    The following logcat log brought me to this conclusion: AppsFilter: interaction: PackageSetting{3ff3d93 com.tha.main/10244} -> PackageSetting{bc58197 com.tha.activator/10245} BLOCKED