问题场景:
我们在使用FileProvider时遇到这个错误
java8.nio.file.AccessDeniedException: content://com.xxx.xxx.provider/external_files/DCIM/screen
shot/1709621636303.png: java.lang.SecurityException: Permission Denial: opening provider
androidx.core.content.FileProvider from ProcessRecord/7fdc1b8 4501:) that is not exported from UID 1000
这个问题一般是应用设置了‘android:sharedUserId="android.uid.system"
变成了系统应用。
(1)在高版本的Android系统上安装此应用提示出现这个错误
(2)利用FileProvider向外部的非系统应用(UID不是系统的UID)提供资源数据
如果大家已经确保权限什么的都没有任何问题,接着往下看
如何解决
方案一
如果是上面描述的第二种情况,把两个应用都添加android.uid.system
,都变成系统应用,拥有相同的UID。或者两个应用都去掉android.uid.system
,这样两个应用都是普通应用。就能使用FileProvider分享数据。
总之不改系统源码情况下,不能一个是系统应用,另一个是非系统应用,这种情况使用FileProvider肯定报上面的错误。
方案二
如果就必须是:系统应用和非系统应用之间使用FileProvider,或者文章开头提到的(1)中描述的情况。那么就需要改framework源码了。
Android 11-13
frameworks\base\services\core\java\com\android\server\uri\UriGrantsManagerService.java
#checkGrantUriPermissionUnlocked()方法
private int checkGrantUriPermissionUnlocked(int callingUid, String targetPkg, GrantUri grantUri,
int modeFlags, int lastTargetUid) {
if (!Intent.isAccessUriMode(modeFlags)) {
return -1;
}
......
// Bail early if system is trying to hand out permissions directly; it
// must always grant permissions on behalf of someone explicit.
final int callingAppId = UserHandle.getAppId(callingUid);
if ((callingAppId == SYSTEM_UID) || (callingAppId == ROOT_UID)) {
if ("com.android.settings.files".equals(grantUri.uri.getAuthority())
|| "com.android.rk.fileprovider".equals(grantUri.uri.getAuthority())
|| "com.rockchips.mediacenter.fileprovider".equals(grantUri.uri.getAuthority())
|| "com.android.settings.module_licenses".equals(grantUri.uri.getAuthority())
|| "com.xxx.xxx.fileprovider".equals(grantUri.uri.getAuthority()) /*新增一个URI过滤*/) {
// Exempted authority for
// 1. cropping user photos and sharing a generated license html
// file in Settings app
// 2. sharing a generated license html file in TvSettings app
// 3. Sharing module license files from Settings app
} else {
Slog.w(TAG, "For security reasons, the system cannot issue a Uri permission"
+ " grant to " + grantUri + "; use startActivityAsCaller() instead");
return -1;
}
}
在上面的if判断中,新增一个过滤条件。其中com.xxx.xxx.fileprovider就是想要过滤的FileProvider的authorities
Android10
frameworks\base\services\core\java\com\android\server\uri\UriGrantsManagerService.java
#checkGrantUriPermission()方法
看网上的参考资料
Android8
frameworks\base\services\core\java\com\android\server\am\a\ActivityManagerService.java
#checkGrantUriPermissionLocked()方法
总之改的都是在if条件中增加对应fileProvider的过滤条件,让系统不要截停这个fileProvider的URI资源
然后编译系统即可
参考资料:
Android 8.1安装以上app包解析包错误Permission Denial: that is not exported from UID 1000)
Permission Denial: opening provider that is not exported from UID 1000