Android PackageManager.queryintentactivities 查询不全问题

Posted 虫师魁拔

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android PackageManager.queryintentactivities 查询不全问题相关的知识,希望对你有一定的参考价值。

使用系统相关接口,可以根据 Intent 过滤查询对应的 Context

PackageManager.java

  • queryIntentActivities  查询符合Intent Activity
  • queryBroadcastReceivers  查询符合Intent BroadcastReceiver
  • queryIntentServices  查询符合Intent Service
  • queryIntentContentProviders 查询符合Intent ContentProvider

按照系统接口使用说明,查询桌面应用图标的 actvity 代码demo如下:

        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);

        List<ResolveInfo> list = getPackageManager().queryIntentActivities(intent, 0);

        for (ResolveInfo resolveInfo : list) {
            Log.i(Activity_TAG, "resolveInfo " + resolveInfo);
        }

实际打印中会发现,打印出来的 activity 不全。原因在于系统对查询的结果进行过滤了一部分

    private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
            String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags,
            int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits) {
        if (!mUserManager.exists(userId)) return Collections.emptyList();
        final String instantAppPkgName = getInstantAppPackageName(filterCallingUid);
        mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
                false /* requireFullPermission */, false /* checkShell */,
                "query intent activities");
        final String pkgName = intent.getPackage();
        ComponentName comp = intent.getComponent();
        if (comp == null) {
            if (intent.getSelector() != null) {
                intent = intent.getSelector();
                comp = intent.getComponent();
            }
        }

        flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
                comp != null || pkgName != null /*onlyExposedExplicitly*/,
                isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
                        flags));
        if (comp != null) {
            // 对指定了 ComponentName 的 Intent 查询
            return result;
        }

        // reader
        boolean sortResult = false;
        boolean addInstant = false;
        List<ResolveInfo> result;
        synchronized (mLock) {
            if (pkgName == null) {
                List<CrossProfileIntentFilter> matchingFilters =
                        getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
                // 判断当前查询的应用是否跳过接下来配置文件
                ResolveInfo xpResolveInfo  = querySkipCurrentProfileIntents(matchingFilters, intent,
                        resolvedType, flags, userId);
                if (xpResolveInfo != null) {
                    List<ResolveInfo> xpResult = new ArrayList<>(1);
                    xpResult.add(xpResolveInfo);
                    return applyPostResolutionFilter(
                            filterIfNotSystemUser(xpResult, userId), instantAppPkgName,
                            allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent);
                }

                // 判断当前用户是否是系统用户
                result = filterIfNotSystemUser(mComponentResolver.queryActivities(
                        intent, resolvedType, flags, userId), userId);
                addInstant = isInstantAppResolutionAllowed(intent, result, userId,
                        false /*skipPackageCheck*/);
                // Check for cross profile results.
                boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
                xpResolveInfo = queryCrossProfileIntents(
                        matchingFilters, intent, resolvedType, flags, userId,
                        hasNonNegativePriorityResult);
                if (xpResolveInfo != null && isUserEnabled(xpResolveInfo.targetUserId)) {
                    boolean isVisibleToUser = filterIfNotSystemUser(
                            Collections.singletonList(xpResolveInfo), userId).size() > 0;
                    if (isVisibleToUser) {
                        result.add(xpResolveInfo);
                        sortResult = true;
                    }
                }
                if (intent.hasWebURI()) {
                    // 设置 weburi 的部分
                }
            } else {
                // 设置了pkgName 的intent查询方式
            }
        }
        ... ...
        // 进行过滤操作
        return applyPostResolutionFilter(
                result, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
                userId, intent);
    }

queryIntentActivitiesInternal 中初步对调用的应用做了判断,最后调用 applyPostResolutionFilter 对进行进一步判断,在 applyPostResolutionFilter 方法中,一般的APP都是通过 !mAppsFilter.shouldFilterApplication( filterCallingUid, callingSetting, resolvedSetting, userId) 进行判断是否需要过滤删除查询到的 ResolveInfo 

AppsFilter -> shouldFilterApplication

方法中通过对 uid、sharedUserId 数据判断,进行过滤,按照系统默认规则:非 systemUid 应用只能获取到 systemUid 应用、静态库等模块中的 ResolveInfo。开启查询 pkg Feature 或者添加如下权限可以查询获取到全部模块中匹配项。 

android.permission.QUERY_ALL_PACKAGES

这里已经安装应用 uid 等信息都是保存在 /data/system/packages.xml 。系统的 PkgSetting 类就是获取这里内容,debug时候可以手动导出来查看下相关内容。

以上是关于Android PackageManager.queryintentactivities 查询不全问题的主要内容,如果未能解决你的问题,请参考以下文章

Android 逆向Android 权限 ( Android 逆向中使用的 android.permission 权限 | Android 系统中的 Linux 用户权限 )

android 21 是啥版本

Android逆向-Android基础逆向(2-2)

【Android笔记】android Toast

图解Android - Android核心机制

Android游戏开发大全的目录