问题场景:
在Android 12平台中通过自研多媒体应用打开U盘安装apk程序报URI权限错误
05-25 09:42:23.335 2753 2753 E AndroidRuntime: FATAL EXCEPTION: main
05-25 09:42:23.335 2753 2753 E AndroidRuntime: Process: com.android.packageinstaller, PID: 2753
05-25 09:42:23.335 2753 2753 E AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android.packageinstaller/com.android.packageinstaller.InstallStart}: java.lang.SecurityException: UID 10024 does not have permission to content://com.example.media.fileProvider/all_files/storage/762F-2749/YouTube_18.03.36_Apkpure.apk [user 0]
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3707)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3864)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2253)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:106)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:201)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.os.Looper.loop(Looper.java:288)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:7870)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: Caused by: java.lang.SecurityException: UID 10024 does not have permission to content://com.sx.tv.media.fileProvider/all_files/storage/762F-2749/YouTube_18.03.36_Apkpure.apk [user 0]
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.os.Parcel.createExceptionOrNull(Parcel.java:2425)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.os.Parcel.createException(Parcel.java:2409)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.os.Parcel.readException(Parcel.java:2392)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.os.Parcel.readException(Parcel.java:2334)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.app.IActivityTaskManager$Stub$Proxy.startActivity(IActivityTaskManager.java:2326)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.app.Instrumentation.execStartActivity(Instrumentation.java:1758)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.app.Activity.startActivityForResult(Activity.java:5422)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.app.Activity.startActivityForResult(Activity.java:5380)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.app.Activity.startActivity(Activity.java:5766)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.app.Activity.startActivity(Activity.java:5719)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at com.android.packageinstaller.InstallStart.onCreate(InstallStart.java:150)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.app.Activity.performCreate(Activity.java:8069)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.app.Activity.performCreate(Activity.java:8049)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1341)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3688)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: ... 12 more
05-25 09:42:23.335 2753 2753 E AndroidRuntime: Caused by: android.os.RemoteException: Remote stack trace:
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at com.android.server.uri.UriGrantsManagerService.checkGrantUriPermissionUnlocked(UriGrantsManagerService.java:1256)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at com.android.server.uri.UriGrantsManagerService.checkGrantUriPermissionFromIntentUnlocked(UriGrantsManagerService.java:621)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at com.android.server.uri.UriGrantsManagerService.access$1000(UriGrantsManagerService.java:107)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at com.android.server.uri.UriGrantsManagerService$LocalService.checkGrantUriPermissionFromIntent(UriGrantsManagerService.java:1412)
05-25 09:42:23.335 2753 2753 E AndroidRuntime: at com.android.server.wm.ActivityStarter$Request.resolveActivity(ActivityStarter.java:541)
05-25 09:42:23.335 2753 2753 E AndroidRuntime:
05-25 09:42:23.345 497 546 W ActivityTaskManager: Force finishing activity com.android.packageinstaller/.InstallStart
05-25 09:42:23.346 497 2777 I DropBoxManagerService: add tag=system_app_crash isTagEnabled=true flags=0x2
打开UriGrantsManagerService.java中的DEBUG后,发现如下log:
URiGrantsManagerService: For security reasons, the system cannot issue a Uri permission
通过如上log和前面的AndroidRuntime的堆栈打印,定位到是checkGrantUriPermissionUnlocked函数里面做的权限检查,如下是checkGrantUriPermissionUnlocked函数中做判断的部分代码
/**
* Check if the targetPkg can be granted permission to access uri by
* the callingUid using the given modeFlags. Throws a security exception
* if callingUid is not allowed to do this. Returns the uid of the target
* if the URI permission grant should be performed; returns -1 if it is not
* needed (for example targetPkg already has permission to access the URI).
* If you already know the uid of the target, you can supply it in
* lastTargetUid else set that to -1.
*/
private int checkGrantUriPermissionUnlocked(int callingUid, String targetPkg, GrantUri grantUri,
int modeFlags, int lastTargetUid) {
if (!Intent.isAccessUriMode(modeFlags)) {
return -1;
}
if (targetPkg != null) {
if (DEBUG) Slog.v(TAG, "Checking grant " + targetPkg + " permission to " + grantUri);
}
// If this is not a content: uri, we can't do anything with it.
if (!ContentResolver.SCHEME_CONTENT.equals(grantUri.uri.getScheme())) {
if (DEBUG) Slog.v(TAG, "Can't grant URI permission for non-content URI: " + grantUri);
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())) {
// 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;
}
}
解决方案
通过上面代码可以看出,针对是SYSTEM_ID和ROOT_UID应用,如果不是指定的授权包名就会直接返回-1,即not allow。所以要解决该问题,只要把自己的应用包名加进去就行了
--- a/Android/frameworks/base/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/Android/frameworks/base/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -1099,7 +1099,8 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
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.android.settings.module_licenses".equals(grantUri.uri.getAuthority())
+ || "com.example.media.fileProvider".equals(grantUri.uri.getAuthority())) {
// Exempted authority for
// 1. cropping user photos and sharing a generated license html
// file in Settings app