Jul*_* A. 13 android uid android-contentprovider android-securityexception
我有一个应用程序,当通过ContentObserver对a的更改通知时ContentProvider,尝试在后台线程上查询提供程序.这导致SecurityException抛出:
8-10 15:54:29.577 3057-3200/com.xxxx.mobile.android.xxx W/Binder? Caught a RuntimeException from the binder stub implementation.
java.lang.SecurityException: Permission Denial: reading com.xxx.mobile.android.mdk.model.customer.ContentProvider uri content://com.xxx.mobile.android.consumer.xxx/vehicle from pid=0, uid=1000 requires the provider be exported, or grantUriPermission()
at android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:539)
at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:452)
at android.content.ContentProvider$Transport.query(ContentProvider.java:205)
at android.content.ContentResolver.query(ContentResolver.java:478)
at android.content.ContentResolver.query(ContentResolver.java:422)
应用程序创建的线程如何以应用程序的ContentProvider中的不同UID结束?
通过将异常断点在android.content.ContentProvider我看到UserHandle.isSameApp(uid, mMyUid)的false和UserHandle.isSameUser(uid, mMyUid)是true.我还看到提供者UID是10087.
uid值1000属于Android系统.Android的许多功能涉及代理对系统线程的请求以进行处理.如果在此期间抛出异常,则错误将包括系统的uid,而不是原始请求者.
对于其他要点:
UserHandle.isSameApp(uid, mMyUid) is false
UserHandle.isSameUser(uid, mMyUid) is true
通过查看来源,这些最容易解释.在具有多用户支持的Android设备上,每个用户都由一系列UID定义.isSameApp是错误的,因为ids的模数不匹配:
public static final boolean isSameApp(int uid1, int uid2) {
return getAppId(uid1) == getAppId(uid2);
}
public static final int getAppId(int uid) {
return uid % PER_USER_RANGE;
}
Run Code Online (Sandbox Code Playgroud)
同样,这两个id属于同一个用户,因为它们位于相同的范围内:
public static final boolean isSameUser(int uid1, int uid2) {
return getUserId(uid1) == getUserId(uid2);
}
public static final int getUserId(int uid) {
if (MU_ENABLED) {
return uid / PER_USER_RANGE;
} else {
return 0;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,此逻辑存在缺陷,因为这意味着将假定所有Android系统uid(<10000)都"属于"第一个用户.
另请注意,如果第二个用户安装了超过1000个应用程序(!),则可能会将应用程序误认为系统应用程序(两者都uid % PER_USER_RANGE将返回1000).但这并不重要,因为强大的沙盒可以防止任何太糟糕的事情发生.
我在尝试在系统回调 ( ) 中与 ContentProvider 交互时遇到了同样的问题LeScanCallback。问题是回调线程属于 Android 系统,而不是我的应用程序,即使代码位于我的应用程序中。
在尝试与我的 ContentProvider 交互之前,将工作从回调传递到我的应用程序线程之一成功解决了该问题。
为了减少线程创建和回收的样板(需要频繁回调以减少开销),我在委托方法上使用了AndroidAnnotation 的@Background注释(但今天将使用 Kotlin 协程)。