Android 中如何检查应用程序是否为非系统应用程序?

发布于 2024-12-25 12:40:11 字数 934 浏览 2 评论 0 原文

我正在获取 ApplicationInfo 对象列表="noreferrer">packageManager.getInstalledApplications(0) 并尝试根据它们是否是系统应用程序对它们进行分类。

一段时间以来,我一直在使用描述的技术 这里,但是在我的应用程序中看到,有些应用程序不在非系统应用程序列表中(例如例如Facebook,当可用时会要求系统将其自身安装到 SD 卡上)。接下来阅读 ApplicationInfo.FLAG_SYSTEM 的实际文档后,并了解它实际上并不过滤系统应用程序,我现在正在寻找一种新方法。

我的猜测是,系统应用程序和非系统应用程序的 UID 之间存在很大差距,我可以收集这些差距来进行区分,但到目前为止我还没有找到答案。我还研究了其他标志,例如 ApplicationInfo.FLAG_EXTERNAL_STORAGE,但我支持 API 1.5。

有人对此有真正的解决方案吗(不涉及FLAG_SYSTEM)?

I am getting a list of ApplicationInfo Objects with packageManager.getInstalledApplications(0) and attempting to categorize them by whether or not they are a system application.

For a while I have been using the technique described here, however after seeing that in my application, some of the apps were not in the non-system apps list (such as Facebook, which when available asks the system to install itself on the SD card). After next reading the actual documentation for ApplicationInfo.FLAG_SYSTEM, and understanding that it doesn't actually filter system apps, I am now looking for a new approach.

My guess is that there is a large gap between UIDs of System and non-system apps that I can gather to make this distinction, but as of yet I have not found an answer. I also looked into other flags, such as ApplicationInfo.FLAG_EXTERNAL_STORAGE, however I am supporting API 1.5.

Does anyone have a real solution to this (not involving FLAG_SYSTEM)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

习惯成性 2025-01-01 12:40:11
PackageManager pm = mcontext.getPackageManager();
List<PackageInfo> list = pm.getInstalledPackages(0);

for(PackageInfo pi : list) {
    ApplicationInfo ai = pm.getApplicationInfo(pi.packageName, 0);

    System.out.println(">>>>>>packages is<<<<<<<<" + ai.publicSourceDir);

    if ((ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
        System.out.println(">>>>>>packages is system package"+pi.packageName);          
    }
}
PackageManager pm = mcontext.getPackageManager();
List<PackageInfo> list = pm.getInstalledPackages(0);

for(PackageInfo pi : list) {
    ApplicationInfo ai = pm.getApplicationInfo(pi.packageName, 0);

    System.out.println(">>>>>>packages is<<<<<<<<" + ai.publicSourceDir);

    if ((ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
        System.out.println(">>>>>>packages is system package"+pi.packageName);          
    }
}
却一份温柔 2025-01-01 12:40:11

我的印象是系统映像中的所有应用程序都是系统应用程序(通常安装在 /system/app 中)。

如果 FLAG_SYSTEM 仅设置为系统应用程序,则这甚至适用于外部存储中的应用程序:

boolean isUserApp(ApplicationInfo ai) {
    int mask = ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
    return (ai.flags & mask) == 0;
}

另一种方法是使用手机中的 pm 命令行程序。

语法:

pm list packages [-f] [-d] [-e] [-s] [-3] [-i] [-u] [--user USER_ID] [FILTER]

pm list packages: prints all packages, optionally only
  those whose package name contains the text in FILTER.  Options:
    -f: see their associated file.
    -d: filter to only show disbled packages.
    -e: filter to only show enabled packages.
    -s: filter to only show system packages.
    -3: filter to only show third party packages.
    -i: see the installer for the packages.
    -u: also include uninstalled packages.

代码:

ProcessBuilder builder = new ProcessBuilder("pm", "list", "packages", "-s");
Process process = builder.start();

InputStream in = process.getInputStream();
Scanner scanner = new Scanner(in);
Pattern pattern = Pattern.compile("^package:.+");
int skip = "package:".length();

Set<String> systemApps = new HashSet<String>();
while (scanner.hasNext(pattern)) {
    String pckg = scanner.next().substring(skip);
    systemApps.add(pckg);
}

scanner.close();
process.destroy();

那么:

boolean isUserApp(String pckg) {
    return !mSystemApps.contains(pckg);
}

I was under the impression that all apps in the system image are system apps (and normally installed in /system/app).

If FLAG_SYSTEM is only set to system applications, this will work even for apps in external storage:

boolean isUserApp(ApplicationInfo ai) {
    int mask = ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
    return (ai.flags & mask) == 0;
}

An alternative is to use the pm command-line program in your phone.

Syntax:

pm list packages [-f] [-d] [-e] [-s] [-3] [-i] [-u] [--user USER_ID] [FILTER]

pm list packages: prints all packages, optionally only
  those whose package name contains the text in FILTER.  Options:
    -f: see their associated file.
    -d: filter to only show disbled packages.
    -e: filter to only show enabled packages.
    -s: filter to only show system packages.
    -3: filter to only show third party packages.
    -i: see the installer for the packages.
    -u: also include uninstalled packages.

Code:

ProcessBuilder builder = new ProcessBuilder("pm", "list", "packages", "-s");
Process process = builder.start();

InputStream in = process.getInputStream();
Scanner scanner = new Scanner(in);
Pattern pattern = Pattern.compile("^package:.+");
int skip = "package:".length();

Set<String> systemApps = new HashSet<String>();
while (scanner.hasNext(pattern)) {
    String pckg = scanner.next().substring(skip);
    systemApps.add(pckg);
}

scanner.close();
process.destroy();

Then:

boolean isUserApp(String pckg) {
    return !mSystemApps.contains(pckg);
}
可爱暴击 2025-01-01 12:40:11

您可以检查与系统签署的应用程序的签名。如下所示

/**
 * Match signature of application to identify that if it is signed by system
 * or not.
 * 
 * @param packageName
 *            package of application. Can not be blank.
 * @return <code>true</code> if application is signed by system certificate,
 *         otherwise <code>false</code>
 */
public boolean isSystemApp(String packageName) {
    try {
        // Get packageinfo for target application
        PackageInfo targetPkgInfo = mPackageManager.getPackageInfo(
                packageName, PackageManager.GET_SIGNATURES);
        // Get packageinfo for system package
        PackageInfo sys = mPackageManager.getPackageInfo(
                "android", PackageManager.GET_SIGNATURES);
        // Match both packageinfo for there signatures
        return (targetPkgInfo != null && targetPkgInfo.signatures != null && sys.signatures[0]
                .equals(targetPkgInfo.signatures[0]));
    } catch (PackageManager.NameNotFoundException e) {
        return false;
    }
}

您可以在我的博客上获取更多代码 如何检查应用程序是否为系统应用程序(通过签名)

You can check the signature of application which it signed with system. Like below

/**
 * Match signature of application to identify that if it is signed by system
 * or not.
 * 
 * @param packageName
 *            package of application. Can not be blank.
 * @return <code>true</code> if application is signed by system certificate,
 *         otherwise <code>false</code>
 */
public boolean isSystemApp(String packageName) {
    try {
        // Get packageinfo for target application
        PackageInfo targetPkgInfo = mPackageManager.getPackageInfo(
                packageName, PackageManager.GET_SIGNATURES);
        // Get packageinfo for system package
        PackageInfo sys = mPackageManager.getPackageInfo(
                "android", PackageManager.GET_SIGNATURES);
        // Match both packageinfo for there signatures
        return (targetPkgInfo != null && targetPkgInfo.signatures != null && sys.signatures[0]
                .equals(targetPkgInfo.signatures[0]));
    } catch (PackageManager.NameNotFoundException e) {
        return false;
    }
}

You can get more code on my blog How to check if application is system app or not (By signed signature)

绾颜 2025-01-01 12:40:11

有 2 种类型的非系统应用程序:

  1. 从 Google Play 商店下载的应用程序
  2. 由设备制造商预加载的应用程序

此代码将返回所有上述应用程序的列表:

ArrayList<ApplicationInfo> mAllApp = 
        mPackageManager.getInstalledApplications(PackageManager.GET_META_DATA);

for(int i = 0; i < mAllApp.size(); i++) {
    if((mAllApp.get(i).flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
         // 1. Applications downloaded from Google Play Store
        mAllApp1.add(mAllApp.get(i));
    }

    if((mAllApp.get(i).flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
        // 2. Applications preloaded in device by manufecturer
        mAllApp1.add(mAllApp.get(i));
    }
}

There are 2 type of Non - system applications :

  1. Apps downloaded from Google Play Store
  2. Preloaded apps by device manufacturer

This code will return a list of all above applications:

ArrayList<ApplicationInfo> mAllApp = 
        mPackageManager.getInstalledApplications(PackageManager.GET_META_DATA);

for(int i = 0; i < mAllApp.size(); i++) {
    if((mAllApp.get(i).flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
         // 1. Applications downloaded from Google Play Store
        mAllApp1.add(mAllApp.get(i));
    }

    if((mAllApp.get(i).flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
        // 2. Applications preloaded in device by manufecturer
        mAllApp1.add(mAllApp.get(i));
    }
}
離人涙 2025-01-01 12:40:11

好吧,在我看来,这是一个草率的解决方案(如果 /data/app 不是所有设备上的 apps 目录怎么办?),但经过彻底搜索后,这就是我想到的:

for (ApplicationInfo ai : appInfo) {
    if (ai.sourceDir.startsWith("/data/app/")) {
        //Non-system app
    }
    else {
        //System app
    }
}

Well, it's a sloppy solution in my opinion (what if /data/app isn't the apps directory on all devices?), but after a thorough search, this is what I have come up with:

for (ApplicationInfo ai : appInfo) {
    if (ai.sourceDir.startsWith("/data/app/")) {
        //Non-system app
    }
    else {
        //System app
    }
}
你在我安 2025-01-01 12:40:11

如果应用程序是非系统应用程序,则它必须具有可以启动它的启动意图。如果启动意图为空,那么它是一个系统应用程序。

系统应用程序示例:“com.android.browser.provider”、“com.google.android.voicesearch”。

对于上述应用程序,当您查询启动意图时,您将得到 NULL。

PackageManager pm = getPackageManager();
List<ApplicationInfo> packages = pm.getInstalledApplications(PackageManager.GET_META_DATA);
for(ApplicationInfo packageInfo:packages){
    if( pm.getLaunchIntentForPackage(packageInfo.packageName) != null ){
                String currAppName = pm.getApplicationLabel(packageInfo).toString();
               //This app is a non-system app
    }
}

If an Application is a non-system application it must have a launch Intent by which it can be launched. If the launch intent is null then its a system App.

Example of System Apps: "com.android.browser.provider", "com.google.android.voicesearch".

For the above apps you will get NULL when you query for launch Intent.

PackageManager pm = getPackageManager();
List<ApplicationInfo> packages = pm.getInstalledApplications(PackageManager.GET_META_DATA);
for(ApplicationInfo packageInfo:packages){
    if( pm.getLaunchIntentForPackage(packageInfo.packageName) != null ){
                String currAppName = pm.getApplicationLabel(packageInfo).toString();
               //This app is a non-system app
    }
}
<逆流佳人身旁 2025-01-01 12:40:11

这里有一点误解。对于 Android,“系统应用程序”的概念是安装在系统映像上的概念,它没有说明它来自哪个开发人员。因此,如果 OEM 决定将 Facebook 预加载到系统映像上,那么它就是一个系统应用程序,并且将继续如此,无论该应用程序的更新安装在何处。当然,它们不会安装在系统映像上,因为它是只读的。

所以 ApplicationInfo.FLAG_SYSTEM 是正确的,但这似乎不是您要问的问题。我认为您是在问软件包是否使用系统证书进行签名。这不一定是任何事情的良好指标,这可能因设备而异,并且普通 Android 上的一些令人惊讶的组件没有使用系统证书进行签名,即使您可能希望它们如此。

在较新版本的 Android 中,有一个新路径 /system/priv-app/ 尝试成为“真实”系统应用程序的安装位置。刚刚预加载到系统映像上的应用程序最终会位于 /system/app/ 中。请参阅AOSP 特权与系统应用

There is a little bit of misunderstanding here. For Android the notion of a "system app" is one that is install on the system image, it says nothing about what developer it came from. So, if an OEM decides to preload Facebook on to the system image, it is a system app and will continue to be so, regardless of where updates to the app get installed. They won't get installed on the system image, for sure, because it is read-only.

So ApplicationInfo.FLAG_SYSTEM is correct, but that doesn't seem to be the question you are asking. I think you're asking if a package is signed with the system certificate. Which is not necessarily a good indicator of anything, this may vary from device to device and some surprising components on vanilla Android are not signed with the system certificate, even though you might expect them to be.

In newer versions of Android there is a new path, /system/priv-app/ that attempts to be the install location for "real" system apps. Apps that are just pre-loaded on the system image then end up in /system/app/. See AOSP Privileged vs System app

攀登最高峰 2025-01-01 12:40:11

以下是通过包名称查看应用程序是否为系统应用程序的不同可能方法(使用了本文中的一些代码)

package com.test.util;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
import java.util.regex.Pattern;

import timber.log.Timber;


public class SystemAppChecker {
    private PackageManager packageManager = null;

    public SystemAppChecker(Context context) {
        packageManager = context.getPackageManager();
    }

    /**
     * Check if system app by 'pm' command-line program
     *
     * @param packageName
     *            package name of application. Cannot be null.
     * @return <code>true</code> if package is a system app.
     */
    public boolean isSystemAppByPM(String packageName) {
        if (packageName == null) {
            throw new IllegalArgumentException("Package name cannot be null");
        }
        ProcessBuilder builder = new ProcessBuilder("pm", "list", "packages", "-s");
        Process process = null;
        try {
            process = builder.start();
        } catch (IOException e) {
            Timber.e(e);
            return false;
        }

        InputStream in = process.getInputStream();
        Scanner scanner = new Scanner(in);
        Pattern pattern = Pattern.compile("^package:.+");
        int skip = "package:".length();

        Set<String> systemApps = new HashSet<String>();
        while (scanner.hasNext(pattern)) {
            String pckg = scanner.next().substring(skip);
            systemApps.add(pckg);
        }

        scanner.close();
        process.destroy();

        if (systemApps.contains(packageName)) {
            return true;
        }
        return false;
    }

    /**
     * Check if application is preloaded.
     *
     * @param packageName
     *            package name of application. Cannot be null.
     * @return <code>true</code> if package is preloaded.
     */
    public boolean isSystemPreloaded(String packageName) {
        if (packageName == null) {
            throw new IllegalArgumentException("Package name cannot be null");
        }
        try {
            ApplicationInfo ai = packageManager.getApplicationInfo(
                    packageName, 0);
            if (ai.sourceDir.startsWith("/system/app/") || ai.sourceDir.startsWith("/system/priv-app/")) {
                return true;
            }
        } catch (NameNotFoundException e) {
            Timber.e(e);
        }
        return false;
    }

    /**
     * Check if the app is system signed or not
     *
     * @param packageName
     *            package of application. Cannot be blank.
     * @return <code>true</code> if application is signed by system certificate,
     *         otherwise <code>false</code>
     */
    public boolean isSystemSigned(String packageName) {
        if (packageName == null) {
            throw new IllegalArgumentException("Package name cannot be null");
        }
        try {
            // Get packageinfo for target application
            PackageInfo targetPkgInfo = packageManager.getPackageInfo(
                    packageName, PackageManager.GET_SIGNATURES);
            // Get packageinfo for system package
            PackageInfo sys = packageManager.getPackageInfo(
                    "android", PackageManager.GET_SIGNATURES);
            // Match both packageinfo for there signatures
            return (targetPkgInfo != null && targetPkgInfo.signatures != null && sys.signatures[0]
                    .equals(targetPkgInfo.signatures[0]));
        } catch (PackageManager.NameNotFoundException e) {
            Timber.e(e);
        }
        return false;
    }

    /**
     * Check if application is installed in the device's system image
     *
     * @param packageName
     *            package name of application. Cannot be null.
     * @return <code>true</code> if package is a system app.
     */
    public boolean isSystemAppByFLAG(String packageName) {
        if (packageName == null) {
            throw new IllegalArgumentException("Package name cannot be null");
        }
        try {
            ApplicationInfo ai = packageManager.getApplicationInfo(
                    packageName, 0);
            // Check if FLAG_SYSTEM or FLAG_UPDATED_SYSTEM_APP are set.
            if (ai != null
                    && (ai.flags & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) {
                return true;
            }
        } catch (NameNotFoundException e) {
            Timber.e(e);
        }
        return false;
    }
}

Here are different possible ways to see if the app is a system app by its package name (used some of the codes in this post)

package com.test.util;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
import java.util.regex.Pattern;

import timber.log.Timber;


public class SystemAppChecker {
    private PackageManager packageManager = null;

    public SystemAppChecker(Context context) {
        packageManager = context.getPackageManager();
    }

    /**
     * Check if system app by 'pm' command-line program
     *
     * @param packageName
     *            package name of application. Cannot be null.
     * @return <code>true</code> if package is a system app.
     */
    public boolean isSystemAppByPM(String packageName) {
        if (packageName == null) {
            throw new IllegalArgumentException("Package name cannot be null");
        }
        ProcessBuilder builder = new ProcessBuilder("pm", "list", "packages", "-s");
        Process process = null;
        try {
            process = builder.start();
        } catch (IOException e) {
            Timber.e(e);
            return false;
        }

        InputStream in = process.getInputStream();
        Scanner scanner = new Scanner(in);
        Pattern pattern = Pattern.compile("^package:.+");
        int skip = "package:".length();

        Set<String> systemApps = new HashSet<String>();
        while (scanner.hasNext(pattern)) {
            String pckg = scanner.next().substring(skip);
            systemApps.add(pckg);
        }

        scanner.close();
        process.destroy();

        if (systemApps.contains(packageName)) {
            return true;
        }
        return false;
    }

    /**
     * Check if application is preloaded.
     *
     * @param packageName
     *            package name of application. Cannot be null.
     * @return <code>true</code> if package is preloaded.
     */
    public boolean isSystemPreloaded(String packageName) {
        if (packageName == null) {
            throw new IllegalArgumentException("Package name cannot be null");
        }
        try {
            ApplicationInfo ai = packageManager.getApplicationInfo(
                    packageName, 0);
            if (ai.sourceDir.startsWith("/system/app/") || ai.sourceDir.startsWith("/system/priv-app/")) {
                return true;
            }
        } catch (NameNotFoundException e) {
            Timber.e(e);
        }
        return false;
    }

    /**
     * Check if the app is system signed or not
     *
     * @param packageName
     *            package of application. Cannot be blank.
     * @return <code>true</code> if application is signed by system certificate,
     *         otherwise <code>false</code>
     */
    public boolean isSystemSigned(String packageName) {
        if (packageName == null) {
            throw new IllegalArgumentException("Package name cannot be null");
        }
        try {
            // Get packageinfo for target application
            PackageInfo targetPkgInfo = packageManager.getPackageInfo(
                    packageName, PackageManager.GET_SIGNATURES);
            // Get packageinfo for system package
            PackageInfo sys = packageManager.getPackageInfo(
                    "android", PackageManager.GET_SIGNATURES);
            // Match both packageinfo for there signatures
            return (targetPkgInfo != null && targetPkgInfo.signatures != null && sys.signatures[0]
                    .equals(targetPkgInfo.signatures[0]));
        } catch (PackageManager.NameNotFoundException e) {
            Timber.e(e);
        }
        return false;
    }

    /**
     * Check if application is installed in the device's system image
     *
     * @param packageName
     *            package name of application. Cannot be null.
     * @return <code>true</code> if package is a system app.
     */
    public boolean isSystemAppByFLAG(String packageName) {
        if (packageName == null) {
            throw new IllegalArgumentException("Package name cannot be null");
        }
        try {
            ApplicationInfo ai = packageManager.getApplicationInfo(
                    packageName, 0);
            // Check if FLAG_SYSTEM or FLAG_UPDATED_SYSTEM_APP are set.
            if (ai != null
                    && (ai.flags & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) {
                return true;
            }
        } catch (NameNotFoundException e) {
            Timber.e(e);
        }
        return false;
    }
}
小梨窩很甜 2025-01-01 12:40:11

这是此处列出的其他响应的简化且更有效的版本。如果直接迭代 ApplicationInfos 会更有效。

    List<ApplicationInfo> applications = context.getPackageManager()
            .getInstalledApplications(PackageManager.GET_META_DATA);
    for(ApplicationInfo appInfo : applications){
        if((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0){
            // Not a system app
        }
    }

This is a simplified and more efficient version of other responses listed here. It is more efficient if you just iterate directly over the ApplicationInfos.

    List<ApplicationInfo> applications = context.getPackageManager()
            .getInstalledApplications(PackageManager.GET_META_DATA);
    for(ApplicationInfo appInfo : applications){
        if((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0){
            // Not a system app
        }
    }
请叫√我孤独 2025-01-01 12:40:11

因此,我想在这里放置一个我根据该线程和其他一些线程的知识制作的实用程序类。但在我继续之前,先对一些术语进行解释(如果我理解正确的话),这是从该类中复制的,并在其中使用。

在 KitKat 4.4 以下,/system/app 中的所有应用程序都被授予特权
权限。甚至计算器应用程序也有它们。那可能是一个
安全漏洞。所以他们被分为普通和普通
特权系统应用程序和普通应用程序没有特权
KitKat 4.4 以上的权限。所以这些公用事业公司考虑到了这一点。
他们还考虑了以下名称:

  • 平台签名的应用:使用平台/系统密钥签名的任何应用(因此它们具有系统签名权限),无论是
    是否安装在系统分区上。
  • 系统应用:安装在系统分区上的任何应用。
  • 更新的系统应用:任何已更新的系统应用(意味着现在它也安装在 /data/app 上)。
  • 特权系统应用程序:KitKat 4.4 以下,安装在 /system/app 上的任何应用程序;从 KitKat 4.4 开始,仅安装在
    /system/priv-app(我的意思只是/system)。这些应用程序有
    特权权限。
  • 普通系统应用:仅从 KitKat 4.4 开始,那些没有特权的应用,即使它们仍然是系统应用。在 KitKat 4.4 以下,
    它们不存在。

系统分区说明:直到 Oreo 8.1,都有
只有一个:/system.从 Pie (9) 开始,还有 /vendor 和
/产品。

因此,考虑到这一点,这里有 2 个函数:

/**
 * <p>Checks if an app is installed on the system partitions and was updated.</p>
 *
 * @param applicationInfo an instance of {@link ApplicationInfo} for the package to be checked
 *
 * @return true if it is, false otherwise
 */
private static boolean isUpdatedSystemApp(@NonNull final ApplicationInfo applicationInfo) {
    return (applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
}

/**
 * <p>Checks if an app is installed in the system partitions (ordinary app or privileged app, doesn't matter).</p>
 *
 * @param applicationInfo an instance of {@link ApplicationInfo} for the package to be checked
 *
 * @return true if it is, false otherwise
 */
private static boolean isSystemApp(@NonNull final ApplicationInfo applicationInfo) {
    // Below Android Pie (9), all system apps were in /system. As of Pie, they can ALSO be in /vendor and /product.
    boolean ret_value = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        // FLAG_SYSTEM checks if it's on the system image, which means /system. So to check for /vendor and
        // /product, here are 2 special flags.
        ret_value = ret_value || (applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
        ret_value = ret_value || (applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
    }

    return ret_value;
}

要检查应用程序是特权系统应用程序还是普通系统应用程序,和/或使用平台/系统密钥签名,我将在下面留下 3 个函数。我相信这与这个问题无关,但我会把它放在以防像我这样的人需要它。

/**
 * <p>Checks if an app is an ordinary system app (installed on the system partitions, but no privileged or signature
 * permissions granted to it).</p>
 * <p>Note: will return false for any app on KitKat 4.4 and below.</p>
 *
 * @param applicationInfo an instance of {@link ApplicationInfo} for the package to be checked
 *
 * @return true if it is, false otherwise
 */
private static boolean isOrdinarySystemApp(@NonNull final ApplicationInfo applicationInfo) {
    // It's an ordinary system app if it doesn't have any special permission privileges (it's not a Privileged app
    // nor is it signed with the system key).
    boolean ret_value = isSystemApp(applicationInfo) && !hasPrivilegedPermissions(applicationInfo);
    final boolean signed_system_key = hasSystemSignaturePermissions(applicationInfo);
    ret_value = ret_value && signed_system_key;

    return ret_value;
}

/**
 * <p>Checks if an app has signature permissions - checks if it's signed with the platform/system certificate by
 * comparing it to the "android" package.</p>
 * <br>
 * <p>ATTENTION: if the chosen app was signed multiple times and the system is running below Android Pie, this check
 * may return false wrongly, since it checks if ALL the signatures from the "android" package and the chosen
 * application match. If at least one doesn't match in both, this will return false. So use with caution in case of
 * multiple signers. With only one signer, it's all right.</p>
 *
 * @param applicationInfo an instance of {@link ApplicationInfo} for the package to be checked
 * @return true if it is, false otherwise
 */
private static boolean hasSystemSignaturePermissions(@NonNull final ApplicationInfo applicationInfo) {
    // If on Pie or above, check with a private flag (appeared on Pie only).
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        return (applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY) != 0;
    }

    // Else, check by comparing signatures of a platform-signed app and the chosen app.
    return UtilsGeneral.getContext().getPackageManager().checkSignatures(applicationInfo.packageName, "android")
            == PackageManager.SIGNATURE_MATCH;
}

/**
 * <p>"Value for {@link ApplicationInfo#flags}: set to {@code true} if the application
 * is permitted to hold privileged permissions.</p>
 *
 * {@hide}"
 * <p>NOTE: Only on API 19 through API 22.</p>
 */
private static final int FLAG_PRIVILEGED = 1 << 30;

/**
 * <p>Checks if an app is a Privileged App.</p>
 * <p>Note: will return true for any system app below KitKat 4.4.</p>
 *
 * @param applicationInfo an instance of {@link ApplicationInfo} for the package to be checked
 *
 * @return true if it is, false otherwise
 */
private static boolean hasPrivilegedPermissions(@NonNull final ApplicationInfo applicationInfo) {
    // Check if it's an app installed in the system partitions. If it is, check with methods that apply only to
    // apps installed on the system partitions.
    if (isSystemApp(applicationInfo)) {
        // If it's below KitKat 4.4 and it's a system app, it's a privileged one automatically.
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
            return true;
        }

        // If on Marshmallow or above, check with a private flag.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
                return true;
            }
        }

        // If between KitKat 4.4 and Lollipop 5.1, use a deleted flag.
        if ((applicationInfo.flags & FLAG_PRIVILEGED) != 0) {
            return true;
        }
    }

    // In case none returned true above, the app may still be signed with the platform/system's key, which will
    // grant it exactly all permissions there are (which includes privileged permissions - ALL permissions).
    return hasSystemSignaturePermissions(applicationInfo);
}

如果你愿意,你可以将最后一个加入到上面的那个中,但我真的不推荐它。仅当系统应用程序尚未更新时,它才会起作用。

/**
 * <p>Gets a list of folders a system app might be installed in, depending on the device's Android version.</p>
 * <p>Note that an updated system app will report as being installed in /data/app. For these locations to be
 * checked, the app must not have been updated. If it has, it's not possible to tell using the directory, I think.</p>
 *
 * @param privileged_app true if it's to return a list for privileged apps, false if it's for ordinary system apps,
 *                       null if it's to return a list for both types
 *
 * @return a list of folders its APK might be in
 */
@NonNull
private static String[] getAppPossibleFolders(@Nullable final Boolean privileged_app) {
    final Collection<String> ret_folders = new ArrayList<>(5);

    final String PRIV_APP_FOLDER = "/system/priv-app";
    final String ORD_APP_SYSTEM_FOLDER = "/system/app";
    final String ORD_APP_VENDOR_FOLDER = "/vendor/app";
    final String ORD_APP_PRODUCT_FOLDER = "/product/app";

    if (privileged_app == null) {
        ret_folders.add(PRIV_APP_FOLDER);
        ret_folders.add(ORD_APP_SYSTEM_FOLDER);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            ret_folders.add(ORD_APP_VENDOR_FOLDER);
            ret_folders.add(ORD_APP_PRODUCT_FOLDER);
        }
    } else if (privileged_app) {
        ret_folders.add(PRIV_APP_FOLDER);
    } else {
        ret_folders.add(ORD_APP_SYSTEM_FOLDER);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            ret_folders.add(ORD_APP_VENDOR_FOLDER);
            ret_folders.add(ORD_APP_PRODUCT_FOLDER);
        }
    }

    // Leave it in 0 size allocation. Or null values will appear, and I don't want to need to be careful about it.
    return ret_folders.toArray(new String[0]);

    /*
    Use with:

    // If it's an updated system app, its APK will be said to be in /data/app, and the one on the system partitions
    // will become unused. But if it's not updated, it's all fine and the APK path can be used to check if it's
    // a privileged app or not.
    if (!isUpdatedSystemApp(applicationInfo)) {
        for (final String folder : getAppPossibleFolders(false)) {
            if (applicationInfo.sourceDir.startsWith(folder)) {
                return true;
            }
        }
    }
    */
}

So I'd like to put here an utility class I made with the knowledge of this thread and a few others. But before I continue, an explanation of some terms, if I got them all right, copied from that class, which are used on it.

Below KitKat 4.4, all apps in /system/app were given privileged
permissions. Even the Calculator app had them. That could be a
security breach. So they were separated between ordinary and
privileged system apps and ordinary ones don't have privileged
permissions above KitKat 4.4. So these utilities have that in mind.
They also have in mind the following designations:

  • Platform-signed app: any app that is signed with the platform/system key (so they have system signature permissions), whether it is
    installed on the system partitions or not.
  • System app: any app that is installed on the system partitions.
  • Updated system app: any system app that was updated (meaning now it is also installed on /data/app).
  • Privileged system app: below KitKat 4.4, any app installed on /system/app; from KitKat 4.4 onwards, only the apps installed on
    /system/priv-app (I really mean only /system). These apps have
    privileged permissions.
  • Ordinary system app: only as of KitKat 4.4, those without privileged permissions, even though they're still system apps. Below KitKat 4.4,
    they're non-existent.

System partition notes: until Oreo 8.1, there
was only one: /system. As of Pie (9), there is also /vendor and
/product.

So with that in mind, here are 2 functions:

/**
 * <p>Checks if an app is installed on the system partitions and was updated.</p>
 *
 * @param applicationInfo an instance of {@link ApplicationInfo} for the package to be checked
 *
 * @return true if it is, false otherwise
 */
private static boolean isUpdatedSystemApp(@NonNull final ApplicationInfo applicationInfo) {
    return (applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
}

/**
 * <p>Checks if an app is installed in the system partitions (ordinary app or privileged app, doesn't matter).</p>
 *
 * @param applicationInfo an instance of {@link ApplicationInfo} for the package to be checked
 *
 * @return true if it is, false otherwise
 */
private static boolean isSystemApp(@NonNull final ApplicationInfo applicationInfo) {
    // Below Android Pie (9), all system apps were in /system. As of Pie, they can ALSO be in /vendor and /product.
    boolean ret_value = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        // FLAG_SYSTEM checks if it's on the system image, which means /system. So to check for /vendor and
        // /product, here are 2 special flags.
        ret_value = ret_value || (applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
        ret_value = ret_value || (applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
    }

    return ret_value;
}

To check if an app is a privileged system app or is ordinary system app, and/or is signed with the platform/system key, I'll leave 3 functions below. I believe it's off-topic to the question, but I'll put it in case anyone like me needed it.

/**
 * <p>Checks if an app is an ordinary system app (installed on the system partitions, but no privileged or signature
 * permissions granted to it).</p>
 * <p>Note: will return false for any app on KitKat 4.4 and below.</p>
 *
 * @param applicationInfo an instance of {@link ApplicationInfo} for the package to be checked
 *
 * @return true if it is, false otherwise
 */
private static boolean isOrdinarySystemApp(@NonNull final ApplicationInfo applicationInfo) {
    // It's an ordinary system app if it doesn't have any special permission privileges (it's not a Privileged app
    // nor is it signed with the system key).
    boolean ret_value = isSystemApp(applicationInfo) && !hasPrivilegedPermissions(applicationInfo);
    final boolean signed_system_key = hasSystemSignaturePermissions(applicationInfo);
    ret_value = ret_value && signed_system_key;

    return ret_value;
}

/**
 * <p>Checks if an app has signature permissions - checks if it's signed with the platform/system certificate by
 * comparing it to the "android" package.</p>
 * <br>
 * <p>ATTENTION: if the chosen app was signed multiple times and the system is running below Android Pie, this check
 * may return false wrongly, since it checks if ALL the signatures from the "android" package and the chosen
 * application match. If at least one doesn't match in both, this will return false. So use with caution in case of
 * multiple signers. With only one signer, it's all right.</p>
 *
 * @param applicationInfo an instance of {@link ApplicationInfo} for the package to be checked
 * @return true if it is, false otherwise
 */
private static boolean hasSystemSignaturePermissions(@NonNull final ApplicationInfo applicationInfo) {
    // If on Pie or above, check with a private flag (appeared on Pie only).
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        return (applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY) != 0;
    }

    // Else, check by comparing signatures of a platform-signed app and the chosen app.
    return UtilsGeneral.getContext().getPackageManager().checkSignatures(applicationInfo.packageName, "android")
            == PackageManager.SIGNATURE_MATCH;
}

/**
 * <p>"Value for {@link ApplicationInfo#flags}: set to {@code true} if the application
 * is permitted to hold privileged permissions.</p>
 *
 * {@hide}"
 * <p>NOTE: Only on API 19 through API 22.</p>
 */
private static final int FLAG_PRIVILEGED = 1 << 30;

/**
 * <p>Checks if an app is a Privileged App.</p>
 * <p>Note: will return true for any system app below KitKat 4.4.</p>
 *
 * @param applicationInfo an instance of {@link ApplicationInfo} for the package to be checked
 *
 * @return true if it is, false otherwise
 */
private static boolean hasPrivilegedPermissions(@NonNull final ApplicationInfo applicationInfo) {
    // Check if it's an app installed in the system partitions. If it is, check with methods that apply only to
    // apps installed on the system partitions.
    if (isSystemApp(applicationInfo)) {
        // If it's below KitKat 4.4 and it's a system app, it's a privileged one automatically.
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
            return true;
        }

        // If on Marshmallow or above, check with a private flag.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
                return true;
            }
        }

        // If between KitKat 4.4 and Lollipop 5.1, use a deleted flag.
        if ((applicationInfo.flags & FLAG_PRIVILEGED) != 0) {
            return true;
        }
    }

    // In case none returned true above, the app may still be signed with the platform/system's key, which will
    // grant it exactly all permissions there are (which includes privileged permissions - ALL permissions).
    return hasSystemSignaturePermissions(applicationInfo);
}

If you want, you can join this last one to the ones above, but I don't really recommend it. It will only work work as long as the system app hasn't been updated.

/**
 * <p>Gets a list of folders a system app might be installed in, depending on the device's Android version.</p>
 * <p>Note that an updated system app will report as being installed in /data/app. For these locations to be
 * checked, the app must not have been updated. If it has, it's not possible to tell using the directory, I think.</p>
 *
 * @param privileged_app true if it's to return a list for privileged apps, false if it's for ordinary system apps,
 *                       null if it's to return a list for both types
 *
 * @return a list of folders its APK might be in
 */
@NonNull
private static String[] getAppPossibleFolders(@Nullable final Boolean privileged_app) {
    final Collection<String> ret_folders = new ArrayList<>(5);

    final String PRIV_APP_FOLDER = "/system/priv-app";
    final String ORD_APP_SYSTEM_FOLDER = "/system/app";
    final String ORD_APP_VENDOR_FOLDER = "/vendor/app";
    final String ORD_APP_PRODUCT_FOLDER = "/product/app";

    if (privileged_app == null) {
        ret_folders.add(PRIV_APP_FOLDER);
        ret_folders.add(ORD_APP_SYSTEM_FOLDER);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            ret_folders.add(ORD_APP_VENDOR_FOLDER);
            ret_folders.add(ORD_APP_PRODUCT_FOLDER);
        }
    } else if (privileged_app) {
        ret_folders.add(PRIV_APP_FOLDER);
    } else {
        ret_folders.add(ORD_APP_SYSTEM_FOLDER);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            ret_folders.add(ORD_APP_VENDOR_FOLDER);
            ret_folders.add(ORD_APP_PRODUCT_FOLDER);
        }
    }

    // Leave it in 0 size allocation. Or null values will appear, and I don't want to need to be careful about it.
    return ret_folders.toArray(new String[0]);

    /*
    Use with:

    // If it's an updated system app, its APK will be said to be in /data/app, and the one on the system partitions
    // will become unused. But if it's not updated, it's all fine and the APK path can be used to check if it's
    // a privileged app or not.
    if (!isUpdatedSystemApp(applicationInfo)) {
        for (final String folder : getAppPossibleFolders(false)) {
            if (applicationInfo.sourceDir.startsWith(folder)) {
                return true;
            }
        }
    }
    */
}
暗喜 2025-01-01 12:40:11
if (!packageInfo.sourceDir.toLowerCase().startsWith("/system/"))
if (!packageInfo.sourceDir.toLowerCase().startsWith("/system/"))
橙味迷妹 2025-01-01 12:40:11

如果有 APK 文件并想检查它是系统应用程序还是用户安装的
一个简单的逻辑:-
系统应用文件不可写

private boolean isSystemApkFile(File file){
   return !file.canWrite();
}

If having an APK file and want to check is it System app or User installed
a Simple logic:-
System app Files are not writable

private boolean isSystemApkFile(File file){
   return !file.canWrite();
}
极度宠爱 2025-01-01 12:40:11

您可以使用 checkSignatures 来确定应用程序是否是系统应用程序。

所有系统应用程序均使用相同的密钥进行签名。

https: //developer.android.com/reference/android/content/pm/PackageManager#checkSignatures(java.lang.String,%20java.lang.String)

而用系统密钥签名的就是“android”包。

    val checkPackage: String = "com.package.to.check"
    val systemPackageName = "android"
    if (packageManager.checkSignatures(systemPackageName, checkPackage) == PackageManager.SIGNATURE_MATCH) {
        Log.d("TUT", "System app")
    } else {
        Log.d("TUT", "Non-System app")
    }

You can use checkSignatures to determine if an app is a system app or not.

All system apps are signed with the same key.

https://developer.android.com/reference/android/content/pm/PackageManager#checkSignatures(java.lang.String,%20java.lang.String)

And signed with the system key is the "android" package.

    val checkPackage: String = "com.package.to.check"
    val systemPackageName = "android"
    if (packageManager.checkSignatures(systemPackageName, checkPackage) == PackageManager.SIGNATURE_MATCH) {
        Log.d("TUT", "System app")
    } else {
        Log.d("TUT", "Non-System app")
    }
十二 2025-01-01 12:40:11

这是我为此目的编写的 AppUtil。

使用示例:

new AppsUtil(this).printInstalledAppPackages(AppsUtil.AppType.USER);

AppsUtil.java

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.util.Log;

public class AppsUtil
{
    public static final String  TAG = "PackagesInfo";
    private Context             _context;
    private ArrayList<PckgInfo> _PckgInfoList;

    public enum AppType 
    {
        ALL {
            @Override
            public String toString() {
              return "ALL";
            }
          },
        USER {
            @Override
            public String toString() {
              return "USER";
            }
          },
        SYSTEM {
            @Override
            public String toString() {
              return "SYSTEM";
            }
          }
    }

    class PckgInfo
    {
        private AppType appType;
        private String  appName     = "";
        private String  packageName = "";
        private String  versionName = "";
        private int     versionCode = 0;

        private void prettyPrint()
        {
            Log.i(TAG, appName + "\n  AppType: " + appType.toString() + "\n  Package: " + packageName + "\n  VersionName: " + versionName + "\n  VersionCode: " + versionCode);
        }
    }

    public AppsUtil(Context context)
    {
        super();
        this._context = context;
        this._PckgInfoList = new ArrayList<PckgInfo>();
    }

    public void printInstalledAppPackages(AppType appType)
    {
        retrieveInstalledAppsPackages();
        Log.i(TAG, "");
        for (int i = 0; i < _PckgInfoList.size(); i++)
        {
            if (AppType.ALL == appType)
            {
                _PckgInfoList.get(i).prettyPrint();
            }
            else
            {
                if (_PckgInfoList.get(i).appType == appType)
                    _PckgInfoList.get(i).prettyPrint();
            }
        }
    }

    public ArrayList<PckgInfo> getInstalledAppPackages(AppType appType)
    {
        retrieveInstalledAppsPackages();
        ArrayList<PckgInfo> resultPInfoList = new ArrayList<PckgInfo>();

        if (AppType.ALL == appType)
        {
            return _PckgInfoList;
        }
        else
        {
            for (int i = 0; i < _PckgInfoList.size(); i++)
            {
                if (_PckgInfoList.get(i).appType == appType)
                    resultPInfoList.add(_PckgInfoList.get(i));
            }
            return resultPInfoList;
        }
    }

    private void retrieveInstalledAppsPackages()
    {
        PackageManager pm = _context.getPackageManager();
        List<PackageInfo> packs = pm.getInstalledPackages(0);
        for (PackageInfo pi : packs)
        {
            try
            {
                PckgInfo newInfo = new PckgInfo();
                ApplicationInfo ai = pm.getApplicationInfo(pi.packageName, 0);

                newInfo.appType = getAppType(ai);
                newInfo.appName = pi.applicationInfo.loadLabel(pm).toString();
                newInfo.packageName = pi.packageName;
                newInfo.versionName = pi.versionName;
                newInfo.versionCode = pi.versionCode;
                _PckgInfoList.add(newInfo);
            }
            catch (NameNotFoundException e)
            {
                e.printStackTrace();
            }
        }
    }

    AppType getAppType(ApplicationInfo ai)
    {
        AppType resultType ;
        if (isUserApp(ai))
            resultType = AppType.USER;
        else
            resultType = AppType.SYSTEM;

        return resultType;
    }

    boolean isUserApp(ApplicationInfo ai)
    {
        int mask = ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
        return (ai.flags & mask) == 0;
    }
}

Here is an AppUtil I wrote for that purpose.

Usage example:

new AppsUtil(this).printInstalledAppPackages(AppsUtil.AppType.USER);

AppsUtil.java

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.util.Log;

public class AppsUtil
{
    public static final String  TAG = "PackagesInfo";
    private Context             _context;
    private ArrayList<PckgInfo> _PckgInfoList;

    public enum AppType 
    {
        ALL {
            @Override
            public String toString() {
              return "ALL";
            }
          },
        USER {
            @Override
            public String toString() {
              return "USER";
            }
          },
        SYSTEM {
            @Override
            public String toString() {
              return "SYSTEM";
            }
          }
    }

    class PckgInfo
    {
        private AppType appType;
        private String  appName     = "";
        private String  packageName = "";
        private String  versionName = "";
        private int     versionCode = 0;

        private void prettyPrint()
        {
            Log.i(TAG, appName + "\n  AppType: " + appType.toString() + "\n  Package: " + packageName + "\n  VersionName: " + versionName + "\n  VersionCode: " + versionCode);
        }
    }

    public AppsUtil(Context context)
    {
        super();
        this._context = context;
        this._PckgInfoList = new ArrayList<PckgInfo>();
    }

    public void printInstalledAppPackages(AppType appType)
    {
        retrieveInstalledAppsPackages();
        Log.i(TAG, "");
        for (int i = 0; i < _PckgInfoList.size(); i++)
        {
            if (AppType.ALL == appType)
            {
                _PckgInfoList.get(i).prettyPrint();
            }
            else
            {
                if (_PckgInfoList.get(i).appType == appType)
                    _PckgInfoList.get(i).prettyPrint();
            }
        }
    }

    public ArrayList<PckgInfo> getInstalledAppPackages(AppType appType)
    {
        retrieveInstalledAppsPackages();
        ArrayList<PckgInfo> resultPInfoList = new ArrayList<PckgInfo>();

        if (AppType.ALL == appType)
        {
            return _PckgInfoList;
        }
        else
        {
            for (int i = 0; i < _PckgInfoList.size(); i++)
            {
                if (_PckgInfoList.get(i).appType == appType)
                    resultPInfoList.add(_PckgInfoList.get(i));
            }
            return resultPInfoList;
        }
    }

    private void retrieveInstalledAppsPackages()
    {
        PackageManager pm = _context.getPackageManager();
        List<PackageInfo> packs = pm.getInstalledPackages(0);
        for (PackageInfo pi : packs)
        {
            try
            {
                PckgInfo newInfo = new PckgInfo();
                ApplicationInfo ai = pm.getApplicationInfo(pi.packageName, 0);

                newInfo.appType = getAppType(ai);
                newInfo.appName = pi.applicationInfo.loadLabel(pm).toString();
                newInfo.packageName = pi.packageName;
                newInfo.versionName = pi.versionName;
                newInfo.versionCode = pi.versionCode;
                _PckgInfoList.add(newInfo);
            }
            catch (NameNotFoundException e)
            {
                e.printStackTrace();
            }
        }
    }

    AppType getAppType(ApplicationInfo ai)
    {
        AppType resultType ;
        if (isUserApp(ai))
            resultType = AppType.USER;
        else
            resultType = AppType.SYSTEM;

        return resultType;
    }

    boolean isUserApp(ApplicationInfo ai)
    {
        int mask = ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
        return (ai.flags & mask) == 0;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文