如何检查应用是否是Android中的非系统应用?

Phi*_*hil 35 android system uid android-applicationinfo

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

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

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

有没有人有这个真正的解决方案(不涉及FLAG_SYSTEM)?

Nit*_*tin 25

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);          
    }
}
Run Code Online (Sandbox Code Playgroud)


ser*_*1pt 24

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

如果FLAG_SYSTEM仅设置为系统应用程序,则即使对于外部存储中的应用程序也是如此:

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

另一种方法是使用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.
Run Code Online (Sandbox Code Playgroud)

码:

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();
Run Code Online (Sandbox Code Playgroud)

然后:

boolean isUserApp(String pckg) {
    return !mSystemApps.contains(pckg);
}
Run Code Online (Sandbox Code Playgroud)


Pan*_*mar 16

您可以检查它与系统签名的应用程序的签名.如下

/**
 * 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • @Basher51您的应用程序是系统应用程序。在本例中,您构建了一个应用程序并由您的证书签名(与签署 AOSP 代码的证书不同)。到目前为止,您的应用程序就像第三方应用程序。正确的?现在您将该 apk 复制到“system/app”中。此步骤不会使您的应用程序成为系统应用程序(您的应用程序无法访问太多 API,即使它们位于系统目录中)。为此,它必须由与您正在执行的操作相同的证书进行签名,并且位置必须是 /system/app。不用担心你的情况,你的做法是正确的。 (2认同)

Phi*_*hil 6

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

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

  • 如果您更新系统应用程序,它会将更新放入/ data/app目录.但它仍然是一个系统应用程序. (9认同)

Dar*_*tel 5

如果应用程序是非系统应用程序,则它必须具有启动Intent才能启动它.如果启动意图为null,那么它是一个系统App.

系统应用程序示例:"com.android.browser.provider","com.google.android.voicesearch".

对于上述应用程序,当您查询启动Intent时,您将获得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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 许多系统应用程序都有启动意图,例如com.android.settings (4认同)

cyn*_*gus 5

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

所以ApplicationInfo.FLAG_SYSTEM是正确的,但这似乎不是你问的问题.我想你问的是一个软件包是否与系统证书签名.这不一定是任何事情的好指标,这可能因设备而异,并且vanilla Android上的一些令人惊讶的组件未使用系统证书签名,即使您可能期望它们.

在较新版本的Android中,有一条新路径/ system/priv-app /试图成为"真正的"系统应用程序的安装位置.刚刚加载到系统映像上的应用程序最终会出现在/ system/app /中.请参阅AOSP Privileged vs System应用程序


Kus*_*hal 5

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

  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));
    }
}
Run Code Online (Sandbox Code Playgroud)


Vin*_*tti 5

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

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;
    }
}
Run Code Online (Sandbox Code Playgroud)


Tyl*_*ler 5

这是此处列出的其他响应的简化且更有效的版本。如果您直接遍历 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
        }
    }
Run Code Online (Sandbox Code Playgroud)