SecurityException: Permission Denial: reading androidx.core.content.FileProvider

1,129 阅读1分钟

报错提示:

java.lang.SecurityException:Permission Denial: reading androidx.core.content.FileProvider uri 
content://com.softwinner.TvdFileManager.fileProvider/external_files/Download/iBiliTV-Y-release-
master-1.5.0-b0524.1810-konkabk.apk from pid=17457, uid=1000 requires the provider be exported, 
or grantUriPermission() at android.os.Parcel.createExceptionOrNull(Parcel.java:2386)
at android.os.Parcel.createException(Parcel.java:2370)
at android.os.Parcel.readException(Parcel.java:2353)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:190)
atandroid.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:153)
at android.content.ContentProviderProxy.openTypedAssetFile(ContentProviderNative.java:781) 
at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1983)
at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1798) 
at android.content.ContentResolver.openInputStream(ContentResolver.java:1475)
at com.android.packageinstaller.InstallStaging$StagingAsyncTask.doInBackground(InstallStaging.java:408)
at com.android.packageinstaller.InstallStaging$StagingAsyncTask.doInBackground(InstallStaging.java:400) at android.os.AsyncTask$3.call(AsyncTask.java:394) 
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:305)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)

报错的代码:

image.png

基本情况描述:

打开 A Activity, A Activity 会收到一个Intent,Intent.getData() 是传给 A Activity 的 URI。 现在, A Activity 打开 B Activity, 并将 A Activity 收到的 Intent 传给 B Activity, 让 B Activity 也同样能够复用同一个 URI。 同时, A Activity 调用了 finish() 方法。 如上述报错代码的图片,B Activity 读取 URI 时,就捕获到了java.lang.SecurityException。 该问题在 Android 11的设备上检测到该问题。

原因解析:

这是官方文档,关于访问 Content Provider 数据的可选方式之一

image.png 不请求对应 Content Provider 的访问权限,而是让拥有对应 Content Provider 访问权限的应用调用方法Intent.setFlag(),设置对应的读或者写的权限,然后将该 Intent 对象发送出去,收到该 Intent 对象的 Activity 会获得对该 URI 上的数据获得暂时的读或写权限, 直到收到该 Intent 对象的 Activity 调用了 finish() 方法才收回临时的读或写权限。

所以,在上述基本情况的描述中,A Activity是收到 Intent 的 Activity,它对 URI 上的数据拥有暂时的读或写权限,A Activity 将收到的 Intent 传给 B Activity,B Activity 也是能够获得对 URI 上的数据的暂时的读或写权限。 但 A Activity 调用 finish() 方法时,B Activity 对 URI 的暂时的读或写权限也会被收回。

解决方案:

A Activity 不调用 finish(), 改在其他合适的时机去关闭 A Activity。这样,B Activity 就能继续获得对 URI 的暂时的读或写权限。