1 哪些app属于system app?
为了区分privilege app和system app,这里先说明system app是什么,避免之后的讨论概念混乱。
在PackageManagerService中对是否是system app的判断:
具有ApplicationInfo.FLAG_SYSTEM标记的,被视为System app。
frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java
final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting); private static boolean isSystemApp(PackageSetting ps) { return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0; } private static boolean isUpdatedSystemApp(PackageSetting ps) { return (ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; }
有两类app属于System app:
1.1 第一类System app: 特定的shared uid的app 属于system app
例如:shared uid为android.uid.system,android.uid.phone,android.uid.log,android.uid.nfc,android.uid.bluetooth,android.uid.shell。这类app都被赋予了ApplicationInfo.FLAG_SYSTEM标志。在PackageManagerService的构造方法中,代码如下:
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.log", LOG_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.se", SE_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
1.2 第二类System app: 特定目录中的app属于system app
特定目录包括:/vendor/overlay,/system/framework,/system/priv-app,/system/app,/vendor/app,/oem/app。这些目录中的app,被视为system app。
在PackageManagerService的构造方法中,代码如下:
// /vendor/overlay folder File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR); scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0); // Find base frameworks (resource packages without code). /system/framework folder File frameworkDir = new File(Environment.getRootDirectory(), "framework"); scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_IS_PRIVILEGED, scanFlags | SCAN_NO_DEX, 0); // Collected privileged system packages. /system/priv-app folder final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app"); scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0); // Collect ordinary system packages. /system/app folder final File systemAppDir = new File(Environment.getRootDirectory(), "app"); scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0); // Collect all vendor packages. File vendorAppDir = new File("/vendor/app"); scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0); // Collect all OEM packages. /oem/app folder final File oemAppDir = new File(Environment.getOemDirectory(), "app"); scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
2 什么是privileged app(特权app)
注:privileged app,在本文中称之为 特权app,主要原因是此类特权app可以使用protectionLevel为signatureOrSystem或者protectionLevel为signature|privileged的权限。
从PackageManagerService的isPrivilegedApp()可以看出特权app是具有ApplicationInfo.PRIVATE_FLAG_PRIVILEGED标志的一类app。
resolveInfo.activityInfo.applicationInfo.isPrivilegedApp() frameworks/base/core/java/android/content/pm/ApplicationInfo.java public boolean isPrivilegedApp() { return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; }
特权app首先必须是System app。也就是说 System app分为普通的system app和特权的system app。
直观的(但不准确严谨)说,普通的system app就是/system/app目录中的app,特权的system app就是/system/priv-app目录中的app。
区分普通system app和特权app的目的是澄清这个概念:"signatureOrSystem"权限中的System不是为普通system app提供的,而是只有特权app能够使用。
所以,当我们说起system app时,通常指具有特定uid和特定目录中的app,包含了普通的system app和特权app。当我们说起有访问System权限或者privileged权限的app时,通常指特权app。
3 哪些app属于privileged app(特权app)?
特权app首先是System app,然后要具有ApplicationInfo.PRIVATE_FLAG_PRIVILEGED标志。
有两类app属于privileged app(特权app):
参考PackageManagerService的构造方法。
3.1 第一类privileged app: 特定uid的app
shared uid为"android.uid.system","android.uid.phone","android.uid.log","android.uid.nfc","android.uid.bluetooth","android.uid.shell"的app被赋予了privileged的权限。这些app同时也是system app。
代码如下:
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.log", LOG_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.se", SE_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
3.2 第二类privileged app:/system/framework和/system/priv-app目录下的app
/system/framework和/system/priv-app目录下的app被赋予了privileged的权限。
其中/system/framework目录中的apk,只是包含资源,不包含代码(dex)。
/ PackageManagerService的构造方法 // /system/framework File frameworkDir = new File(Environment.getRootDirectory(), "framework"); scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_IS_PRIVILEGED, scanFlags | SCAN_NO_DEX, 0); // /system/priv-app final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app"); scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0); PackageParser.PARSE_IS_PRIVILEGED标志最终会转换为Package的ApplicationInfo.PRIVATE_FLAG_PRIVILEGED标志。大概的代码流程,如下: scanDirLI(PackageParser.PARSE_IS_PRIVILEGED) -> scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK, scanFlags, currentTime, null); -> PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user); -> final PackageParser.Package res = scanPackageDirtyLI(pkg, parseFlags, scanFlags, currentTime, user); -> scanPackageDirtyLI()中 if ((parseFlags & PackageParser.PARSE_IS_PRIVILEGED) != 0) { pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; }
4.1 验证某个app是否获得了某个权限的方法
可以用下面2个命令来验证:
adb shell dumpsys package permission <权限名>
adb shell dumpsys package <包名>
其中,adb shell dumpsys package permission <权限名>可以查看某个权限是谁声明的,谁使用了。
adb shell dumpsys package <包名>可以看到某个app是否获得了某个权限。
哪些app可以使用某app提供的signature权限或signatureOrSystem权限?
如果App A声明了signatureOrSystem权限,即android:protectionLevel="signature|privileged"或者android:protectionLevel="signatureOrSystem",则可以使用该权限的app包括:
(1)与App A有相同签名的app
(2)与系统签名相同的app,即与厂商签名(厂商ROM中的系统app签名)相同的app
(3)在/system/priv-app目录中的app,不管是否满足(1)和(2)的条件。即任意app只要放到了/system/priv-app就可以使用App A的signatureOrSystem级别的权限。
如果App A声明了signature权限,即android:protectionLevel="signature",则可以使用该权限的app包括:
(1)与App A有相同签名的app
(2)与系统签名相同的app,即与厂商签名(厂商ROM中的系统app签名)相同的app
注意:与系统签名相同,即与厂商签名相同,这是指厂商推出的app,这些app有很大的访问权限。