android 解决java.lang.SecurityException: Package com.xxx.xxx does not belong to 1000

小咪咪 2024-04-17 06:21 197阅读 0赞

最近遇到一个怪事,访问ContentProvider的call方法一直报这个错,经过不断的研究,终于知道问题在哪了,这里做个记录;

比如,在进程A中调用进程B,进程B再去访问ContentProvider的call、query等方法,而call、query等方法里面又调用了ContentProvider.getCallingPackage(),那么就会报这个错;

先看下ContentProvider.getCallingPackage()的源码,

  1. public final @Nullable String getCallingPackage() {
  2. final AttributionSource callingAttributionSource = getCallingAttributionSource();
  3. return (callingAttributionSource != null)
  4. ? callingAttributionSource.getPackageName() : null;
  5. }
  6. public final @Nullable AttributionSource getCallingAttributionSource() {
  7. final AttributionSource attributionSource = mCallingAttributionSource.get();
  8. if (attributionSource != null) {
  9. mTransport.mAppOpsManager.checkPackage(Binder.getCallingUid(),
  10. attributionSource.getPackageName());
  11. }
  12. return attributionSource;
  13. }

这里可以看到源码中会拿调用方的包名和uid进行检查,查看是否配对,如果不是,就会抛出异常

  1. /**
  2. * @deprecated Use {@link PackageManager#getPackageUid} instead
  3. */
  4. @Deprecated
  5. public void checkPackage(int uid, @NonNull String packageName) {
  6. try {
  7. if (mService.checkPackage(uid, packageName) != MODE_ALLOWED) {
  8. throw new SecurityException(
  9. "Package " + packageName + " does not belong to " + uid);
  10. }
  11. } catch (RemoteException e) {
  12. throw e.rethrowFromSystemServer();
  13. }
  14. }

问题就出在进程A调用了进程B,进程B去访问ContentProvider.getCallingPackage(), 然后Binder.getCallingUid拿到的是进程A的身份的uid,而不是进程B的身份uid

下面贴下如何解决的?

  1. val token = Binder.clearCallingIdentity()
  2. val client =
  3. UMSEnv.applicationContext.contentResolver.acquireUnstableContentProviderClient(
  4. providerAuthorityUri
  5. )
  6. kotlin.runCatching {
  7. val extras = Bundle()
  8. extras.putInt(KEY_HOST_PID, pid)
  9. val bundle = client?.call(METHOD_QUERY_HOST_PACKAGE_NAME, null, extras)
  10. client?.close()
  11. hostPackageName = bundle?.getString(KEY_HOST_PACKAGE_NAME)
  12. }.onFailure {
  13. client?.close()
  14. LogUtils.e(TAG, "queryHostPackageName, exception: $it")
  15. it.printStackTrace()
  16. }
  17. Binder.restoreCallingIdentity(token)

看到上述代码了吗?解决问题的关键方法在于call()前后加上代码

Binder.clearCallingIdentity()

Binder.restoreCallingIdentity(token)

目的就是清除Binder中存储的进程A的身份,这2句代码需要成对使用哦!

下面是相关问题的链接:

Android ContentProvider调用报错”Bad call: specified package xxx under uid 10032 but it is really 10001”及Binder权限问题分析

https://www.jianshu.com/p/a609b965364b

好了又可以愉快玩耍了。

发表评论

表情:
评论列表 (有 0 条评论,197人围观)

还没有评论,来说两句吧...

相关阅读