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时候可以手动导出来查看下相关内容。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Ubuntu 中,我们可以使用 Make 工具来安装和卸载一些软件。Make 是一个非常强大的自动化工具,它可以根据预先定义的规则和指令来自动化编译、安装和卸载软件。 以下是使用 Make 工具安装和卸载软件的步骤: 1. 安装软件所需的依赖项: 在终端中输入以下命令: ``` sudo apt-get install build-essential ``` 这将安装一些必要的编译工具和依赖项。 2. 下载软件源代码: 使用浏览器或 wget 命令下载软件的源代码。例如,如果要下载示例软件的源代码,则可以运行以下命令: ``` wget https://example.com/software.tar.gz ``` 3. 解压缩源代码: 使用 tar 命令解压缩下载的源代码文件。例如,如果下载的文件名为 software.tar.gz,则可以运行以下命令: ``` tar -xvzf software.tar.gz ``` 4. 进入解压后的目录: 使用 cd 命令进入解压后的目录。例如,如果解压后的目录名为 software,则可以运行以下命令: ``` cd software ``` 5. 编译源代码: 运行以下命令来编译源代码: ``` make ``` 这将根据 Makefile 文件中的规则来编译源代码。 6. 安装软件: 运行以下命令来安装软件: ``` sudo make install ``` 这将根据 Makefile 文件中的规则来安装软件。 7. 卸载软件: 如果要卸载软件,则可以在软件源代码目录中运行以下命令: ``` sudo make uninstall ``` 这将根据 Makefile 文件中的规则来卸载软件。 请注意,不是所有软件都使用 Make 工具进行安装和卸载。有些软件可能使用其他工具或方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值