所以,我想在这里放一个实用类,它是我根据这个线程和其他一些线程的知识制作的。但在继续之前,我要解释一些术语,如果我都理解正确的话,这些术语是从那个类中复制出来的,并且在其中使用。
在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和/product。
所以,记住这一点,这里有两个函数:
private static boolean isUpdatedSystemApp(@NonNull final ApplicationInfo applicationInfo) {
return (applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
}
private static boolean isSystemApp(@NonNull final ApplicationInfo applicationInfo) {
boolean ret_value = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
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个函数。我相信这与问题无关,但我会放在这里以防像我这样的人需要它。
private static boolean isOrdinarySystemApp(@NonNull final ApplicationInfo applicationInfo) {
boolean ret_value = isSystemApp(applicationInfo) && !hasPrivilegedPermissions(applicationInfo);
final boolean signed_system_key = hasSystemSignaturePermissions(applicationInfo);
ret_value = ret_value && signed_system_key;
return ret_value;
}
private static boolean hasSystemSignaturePermissions(@NonNull final ApplicationInfo applicationInfo) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
return (applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY) != 0;
}
return UtilsGeneral.getContext().getPackageManager().checkSignatures(applicationInfo.packageName, "android")
== PackageManager.SIGNATURE_MATCH;
}
private static final int FLAG_PRIVILEGED = 1 << 30;
private static boolean hasPrivilegedPermissions(@NonNull final ApplicationInfo applicationInfo) {
if (isSystemApp(applicationInfo)) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
return true;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
return true;
}
}
if ((applicationInfo.flags & FLAG_PRIVILEGED) != 0) {
return true;
}
}
return hasSystemSignaturePermissions(applicationInfo);
}
如果您愿意,可以将此最后一个与上面的内容合并,但我并不推荐这样做。只有在系统应用程序未更新时才能正常工作。
@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);
}
}
return ret_folders.toArray(new String[0]);
}
FLAG_SYSTEM
实际上不起作用,所以这不是我要找的。 - PhilFLAG_SYSTEM
只会获取安装在设备系统镜像中的应用程序。这意味着它将无法获取安装在SD卡等位置的应用程序。获取所有应用程序的最佳方法是检查它们的目录("/data/apps")。 - Phil