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

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

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

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

public final @Nullable String getCallingPackage() {
        final AttributionSource callingAttributionSource = getCallingAttributionSource();
        return (callingAttributionSource != null)
                ? callingAttributionSource.getPackageName() : null;
    }
public final @Nullable AttributionSource getCallingAttributionSource() {
        final AttributionSource attributionSource = mCallingAttributionSource.get();
        if (attributionSource != null) {
            mTransport.mAppOpsManager.checkPackage(Binder.getCallingUid(),
                    attributionSource.getPackageName());
        }
        return attributionSource;
    }

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

    /**
     * @deprecated Use {@link PackageManager#getPackageUid} instead
     */
    @Deprecated
    public void checkPackage(int uid, @NonNull String packageName) {
        try {
            if (mService.checkPackage(uid, packageName) != MODE_ALLOWED) {
                throw new SecurityException(
                        "Package " + packageName + " does not belong to " + uid);
            }
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

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

下面贴下如何解决的?

val token = Binder.clearCallingIdentity()
        val client =
            UMSEnv.applicationContext.contentResolver.acquireUnstableContentProviderClient(
                providerAuthorityUri
            )
        kotlin.runCatching {
            val extras = Bundle()
            extras.putInt(KEY_HOST_PID, pid)
            val bundle = client?.call(METHOD_QUERY_HOST_PACKAGE_NAME, null, extras)
            client?.close()
            hostPackageName = bundle?.getString(KEY_HOST_PACKAGE_NAME)
        }.onFailure {
            client?.close()
            LogUtils.e(TAG, "queryHostPackageName, exception: $it")
            it.printStackTrace()
        }
        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  

好了又可以愉快玩耍了。

猜你喜欢

转载自blog.csdn.net/msn465780/article/details/131035276