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.
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