如何应对Android面试官 -> PKMS 安装与签名校验

前言


image.png

本章主要围绕以上几个知识点进行讲解,最后会手写一个 权限申请框架;

PKMS


PackageManagerService 的作用:

  1. PackageManagerService(简称 PKMS),是 Android 系统中核心服务之一,负责应用程序的安装,卸载,信息查询,等工作;
  2. 解析AndroidNanifest.xml清单文件,解析清单文件中的所有节点信息;
  3. 扫描.apk文件,安装系统应用,安装本地应用等;
  4. 管理本地应用,主要有, 安装,卸载,应用信息查询 等;

PKMS 概述来说:Android 系统启动时,会启动(应用程序管理服务器 PKMS ),此服务负责扫描系统中特定的目录,寻找里面的APK格式的文件,并对这些文件进行解析,然后得到应用程序相关信息,最后完成应用程序的安装PKMS在安装应用过程中, 会全面解析应用程序的 AndroidManifest.xml 文件, 来得到 Activity, Service, BroadcastReceiver, ContextProvider 等信息, 在结合 PKMS 服务就可以在 Android OS 中正常的使用应用程序了,在 Android 系统中, 系统启动时由 SystemServer 启动 PKMS 服务, 启动该服务后会执行应用程序的安装过程;

PKMS 的角色位置,我们来看一张图

image.png

客户端可通过 Context.getPackageManager() 获得 ApplicationPackageManager 对象, 而 mPM 指向的是 Proxy 代理,当调用到 mPM. 方法后,将会调用到 IPackageManager 的 Proxy 代理方法,然后通过Binder 机制中的 mRemote 与服务端 PackageManagerService 通信 并调用到 PackageManagerService 的方法;

PKMS 启动过程分析


启动过程,依然从 SystemServer 的 run 看起,我们进入这个 run 方法的 startBootstrapServices() 方法,这个方法主要用来启动引导服务;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
scss复制代码private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
// 第一步:创建安装器,并启动安装器
Installer installer = mSystemServiceManager.startService(Installer.class);

// 第二步:获取设置是否加密「例如设置了密码」
String cryptState = VoldProperties.decrypt().orElse("");

// 第三步:调用 PKMS 的 main 方法,实例化 PKMS
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
domainVerificationService, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF,
mOnlyCore);

// 第四步:如果设备没有加密,操作它,管理 A/B OAT dexopting
if (!mOnlyCore) {
boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
false);
if (!disableOtaDexopt) {
try {
//
OtaDexoptService.main(mSystemContext, mPackageManagerService);
} catch (Throwable e) {
reportWtf("starting OtaDexOptService", e);
} finally {
Watchdog.getInstance().resumeWatchingCurrentThread("moveab");
t.traceEnd();
}
}
}

// 第五步:如果设备没有加密,执行performDexOptUpdate 完成dex优化
// 构造PackageDexOptimizer及DexManager类,处理dex优化;
mPackageManagerService.updatePackagesIfNeeded();

// 第六步:执行performStrim 完成磁盘优化
mPackageManagerService.performFstrimIfNeeded();

// 第七步:PKMS准备就绪
mPackageManagerService.systemReady();
}

重点一在第五步,手机开机慢的主要原因:

手机开机,BootRoom 拉起BootLoader程序,BootLoader 会拉起 Linux 内核驱动,驱动会初始化init进程,init进程会创建zygote进程,zygote进程会fork出它的第大儿子 系统服务进程「system server」系统服务进程会初始化 PKMS,PKMS 在构造方法中 就会扫描手机上的所有应用,手机上应用越多,时间越长,扫描完之后 还会进行 dex 优化;

重点二在第三步,我们进入第三步的 main 方法看下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
java复制代码public static PackageManagerService main(Context context, Installer installer,
@NonNull DomainVerificationService domainVerificationService, boolean factoryTest,
boolean onlyCore) {
// 省略部分代码

// 实例化 PackageManagerService
PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest,
Build.FINGERPRINT, Build.IS_ENG, Build.IS_USERDEBUG, Build.VERSION.SDK_INT,
Build.VERSION.INCREMENTAL);
// 将 PMS 注册到 SystemServer 中
ServiceManager.addService("package", m);
//
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
}

这里主要是调用 PackageManagerService 的构造方法,进行实例化,并初始化相关信息,这里主要分为 5 个阶段;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
ini复制代码public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest,
final String buildFingerprint, final boolean isEngBuild,
final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
// 省略部分代码

// 阶段1 BOOT_PROGRESS_PMS_START
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
mMetrics = injector.getDisplayMetrics();
mInstaller = injector.getInstaller();
mPermissionManager = injector.getPermissionManagerServiceInternal();
mSettings = injector.getSettings();
// 这里的目的是:如果想安装系统应用,必须得到系统厂商的签名,这些 UID 是由 Linux 来管理的,系统应用在安装的时候,权限校验就能通过;
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);
mSettings.addSharedUserLPw("android.uid.uwb", UWB_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
// 构造PackageDexOptimizer及DexManager类,处理dex优化;
mPackageDexOptimizer = injector.getPackageDexOptimizer();
mDexManager = injector.getDexManager();
// ART虚拟机管理服务
mArtManagerService = injector.getArtManagerService();
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
mViewCompiler = injector.getViewCompiler();
// 权限变化监听器
mProtectedPackages = new ProtectedPackages(mContext);
mApexManager = injector.getApexManager();
}
  1. BOOT_PROGRESS_PMS_START,PKMS 的构造方法中进行;
  • mMetrics = new DisplayMetrics();初始化屏幕相关类;
  • mInstaller = installer;赋值安装器;
  • mPermissionManager = injector.getPermissionManagerServiceInternal();创建PermissionManager 进行权限管理;
  • 创建 settings 保存安装包信息;

这个 Settings 比较关键,我们进入这个 Settings 的构造方法看下;

1
2
3
4
5
6
7
8
9
10
less复制代码Settings(File dataDir, RuntimePermissionsPersistence runtimePermissionsPersistence,
LegacyPermissionDataProvider permissionDataProvider,
@NonNull DomainVerificationManagerInternal domainVerificationManager,
@NonNull PackageManagerTracedLock lock) {
// 读取 dat/system/packages.xml 主要是为了读取系统应用并加载
mSettingsFilename = new File(mSystemDir, "packages.xml");
// 备份读取,为了加载过程中被打断之后可以继续加载
mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
mPackageListFilename = new File(mSystemDir, "packages.list");
}

packages.xml中 存放着所有的系统权限 以及 安装在手机上的每一个应用程序信息。每次开机都会执行这个 PKMS 的构造方法,进行应用的安装处理,如果手机上安装的应用很多很多,开机时间也会相应的变长;

  1. EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START;扫描系统的 apk 应用;

这个阶段就是开始扫描系统的 apk 应用,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
arduino复制代码public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest,
final String buildFingerprint, final boolean isEngBuild,
final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
// 阶段2:扫描系统的 apk 应用
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
startTime);
// 开始扫描
for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
final ScanPartition partition = mDirsToScanAsSystem.get(i);
if (partition.getOverlayFolder() == null) {
continue;
}
//
scanDirTracedLI(partition.getOverlayFolder(), systemParseFlags,
systemScanFlags | partition.scanFlag, 0,
packageParser, executorService);
}
// 扫描 framework
File frameworkDir = new File(Environment.getRootDirectory(), "framework");
scanDirTracedLI(frameworkDir, systemParseFlags,
systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
packageParser, executorService);

//
for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
final ScanPartition partition = mDirsToScanAsSystem.get(i);
if (partition.getPrivAppFolder() != null) {
scanDirTracedLI(partition.getPrivAppFolder(), systemParseFlags,
systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
packageParser, executorService);
}
scanDirTracedLI(partition.getAppFolder(), systemParseFlags,
systemScanFlags | partition.scanFlag, 0,
packageParser, executorService);
}
}

扫描系统的应用,主要扫描下面几个目录的 apk:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
arduino复制代码private static int scanFlagForPartition(PackagePartitions.SystemPartition partition) {
switch (partition.type) {
//
case PackagePartitions.PARTITION_SYSTEM:
return 0;
// vendor/overlay
case PackagePartitions.PARTITION_VENDOR:
return SCAN_AS_VENDOR;
// odm/overlay
case PackagePartitions.PARTITION_ODM:
return SCAN_AS_ODM;
// oem/overlay
case PackagePartitions.PARTITION_OEM:
return SCAN_AS_OEM;
// product/overlay
case PackagePartitions.PARTITION_PRODUCT:
return SCAN_AS_PRODUCT;
//
case PackagePartitions.PARTITION_SYSTEM_EXT:
return SCAN_AS_SYSTEM_EXT;
default:
throw new IllegalStateException("Unable to determine scan flag for "
+ partition.getFolder());
}
}
  1. BOOT_PROGRESS_PMS_DATA_SCAN_START,扫描data目录下的apk,这里主要是安装的第三方应用;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
scss复制代码mAppInstallDir = new File(Environment.getDataDirectory(), "app");

if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
packageParser, executorService);
// 移除通过OTA删除的更新系统应用程序的禁用package设置
// 如果更新不再存在,则完全删除该应用。否则,撤消其系统权限
for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {
final String packageName = possiblyDeletedUpdatedSystemApps.get(i);
final AndroidPackage pkg = mPackages.get(packageName);
final String msg;

// remove from the disabled system list; do this first so any future
// scans of this package are performed without this state
mSettings.removeDisabledSystemPackageLPw(packageName);
// ...
}

// 确保期望在userdata分区上显示的所有系统应用程序实际显示
// 如果从未出现过,需要回滚以恢复系统版本
for (int i = 0; i < mExpectingBetter.size(); i++) {
final String packageName = mExpectingBetter.keyAt(i);
if (!mPackages.containsKey(packageName)) {
final File scanFile = mExpectingBetter.valueAt(i);
// ...
mSettings.enableSystemPackageLPw(packageName);

// 扫描 APK
try {
final AndroidPackage newPkg = scanPackageTracedLI(
scanFile, reparseFlags, rescanFlags, 0, null);
// We rescanned a stub, add it to the list of stubbed system packages
if (newPkg.isStub()) {
stubSystemApps.add(packageName);
}
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse original system package: "
+ e.getMessage());
}
}
}
// 解压缩并安装任何存根系统应用程序。必须最后执行此操作以确保替换或禁用所有存根
installSystemStubPackages(stubSystemApps, scanFlags);
// 获取storage manager包名
mStorageManagerPackage = getStorageManagerPackageName();
// 解决受保护的action过滤器。只允许setup wizard(开机向导)为这些action设置高优先级过滤器
mSetupWizardPackage = getSetupWizardPackageNameImpl();
// 更新客户端以确保持有正确的共享库路径
updateAllSharedLibrariesLocked(null, null, Collections.unmodifiableMap(mPackages));
// 读取并更新要保留的package的上次使用时间
mPackageUsage.read(packageSettings);
mCompilerStats.read();
}

处理 data 目录的应用信息,及时更新,祛除不必要的数据;

  1. BOOT_PROGRESS_PMS_SCAN_END OTA 升级后首次启动要清除不必要的缓存数据,权限等默认项更新后要清理相关数据,将阶段2 阶段3扫描后的数据更新到 packages.xml 文件中;
1
2
ini复制代码EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
  1. BOOT_PROGRESS_PMS_READY GC 内存回收
1
2
3
4
5
6
7
8
scss复制代码EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis());
// PermissionController 主持 缺陷许可证的授予和角色管理,所以这是核心系统的一个关键部分。
mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr();
updateInstantAppInstallerLocked(null);
// 打开应用之后,及时回收处理
Runtime.getRuntime().gc();
// 上面的初始扫描在持有mPackage锁的同时对installd进行了多次调用
mInstaller.setWarnIfHeld(mPackages);

APK 的扫描


PKMS的构造函数中调用了 scanDirTracedLI 方法 来扫描某个目录的 apk 文件;

1
2
3
4
5
6
7
8
arduino复制代码private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
try {
scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}

从这里执行 APK 的扫描操作,我们进入这个 scanDirLI 看下;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
arduino复制代码private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
PackageParser2 packageParser, ExecutorService executorService) {
final File[] files = scanDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
return;
}

ParallelPackageParser parallelPackageParser =
new ParallelPackageParser(packageParser, executorService);

int fileCount = 0;
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
if (!isPackage) {
// Ignore entries which are not packages
continue;
}
// 收集apk文件 交给submit方法处理
parallelPackageParser.submit(file, parseFlags);
fileCount++;
}
}

这里主要是 收集 apk 文件 交给 submit 方法处理;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ini复制代码public void submit(File scanFile, int parseFlags) {
mExecutorService.submit(() -> {
ParseResult pr = new ParseResult();
try {
pr.scanFile = scanFile;
pr.parsedPackage = parsePackage(scanFile, parseFlags);
} catch (Throwable e) {
pr.throwable = e;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
mQueue.put(pr);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
mInterruptedInThread = Thread.currentThread().getName();
}
});
}

submit 把 PackageParser 封装好的信息交给 parsePackage 方法;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ini复制代码public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {
if (useCaches && mCacher != null) {
ParsedPackage parsed = mCacher.getCachedResult(packageFile, flags);
if (parsed != null) {
return parsed;
}
}

long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
ParseInput input = mSharedResult.get().reset();
// 解析 apk 文件
ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags);

ParsedPackage parsed = (ParsedPackage) result.getResult().hideAsParsed();
return parsed;
}

解析 apk 文件

1
2
3
4
5
6
7
8
9
10
arduino复制代码public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile,
int flags)
throws PackageParserException {
if (packageFile.isDirectory()) {
return parseClusterPackage(input, packageFile, flags);
} else {
// 解析
return parseMonolithicPackage(input, packageFile, flags);
}
}

我们进入 parseMonolithicPackage 这个方法看下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
java复制代码private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
int flags) throws PackageParserException {

final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
try {
// 通过 parseBaseApk 解析 apk 中的清单文件
final ParseResult<ParsingPackage> result = parseBaseApk(input,
apkFile,
apkFile.getCanonicalPath(),
assetLoader, flags);
if (result.isError()) {
return input.error(result);
}

return input.success(result.getResult()
.setUse32BitAbi(lite.isUse32bitAbi()));
} catch (IOException e) {
return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to get path: " + apkFile, e);
} finally {
IoUtils.closeQuietly(assetLoader);
}
}

通过 parseBaseApk 解析 apk 中的清单文件;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
ini复制代码private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
String codePath, SplitAssetLoader assetLoader, int flags)
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();

String volumeUuid = null;
if (apkPath.startsWith(MNT_EXPAND)) {
final int end = apkPath.indexOf('/', MNT_EXPAND.length());
volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
}

if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);

final AssetManager assets = assetLoader.getBaseAssetManager();
final int cookie = assets.findCookieForPath(apkPath);
if (cookie == 0) {
return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST,
"Failed adding asset path: " + apkPath);
}
// 解析 apk 中的清单文件
try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
ANDROID_MANIFEST_FILENAME)) {
final Resources res = new Resources(assets, mDisplayMetrics, null);
// 获取应用的相关信息,并存储起来
ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
parser, flags);
if (result.isError()) {
return input.error(result.getErrorCode(),
apkPath + " (at " + parser.getPositionDescription() + "): "
+ result.getErrorMessage());
}

final ParsingPackage pkg = result.getResult();
if (assets.containsAllocatedTable()) {
final ParseResult<?> deferResult = input.deferError(
"Targeting R+ (version " + Build.VERSION_CODES.R + " and above) requires"
+ " the resources.arsc of installed APKs to be stored uncompressed"
+ " and aligned on a 4-byte boundary",
DeferredError.RESOURCES_ARSC_COMPRESSED);
if (deferResult.isError()) {
return input.error(INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED,
deferResult.getErrorMessage());
}
}

ApkAssets apkAssets = assetLoader.getBaseApkAssets();
boolean definesOverlayable = false;
try {
definesOverlayable = apkAssets.definesOverlayable();
} catch (IOException ignored) {
// Will fail if there's no packages in the ApkAssets, which can be treated as false
}

if (definesOverlayable) {
SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers();
int size = packageNames.size();
for (int index = 0; index < size; index++) {
String packageName = packageNames.valueAt(index);
Map<String, String> overlayableToActor = assets.getOverlayableMap(packageName);
if (overlayableToActor != null && !overlayableToActor.isEmpty()) {
for (String overlayable : overlayableToActor.keySet()) {
pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable));
}
}
}
}

pkg.setVolumeUuid(volumeUuid);

if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
pkg.setSigningDetails(getSigningDetails(pkg, false));
} else {
pkg.setSigningDetails(SigningDetails.UNKNOWN);
}

return input.success(pkg);
} catch (Exception e) {
return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to read manifest from " + apkPath, e);
}
}

通过 XmlResourceParser parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME) 解析 apk 中的清单文件;

通过 parseBaseApk 获取应用的相关信息,并存储起来;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
ini复制代码private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
String codePath, Resources res, XmlResourceParser parser, int flags)
throws XmlPullParserException, IOException {
final String splitName;
final String pkgName;

ParseResult<Pair<String, String>> packageSplitResult =
ApkLiteParseUtils.parsePackageSplitNames(input, parser);
if (packageSplitResult.isError()) {
return input.error(packageSplitResult);
}

Pair<String, String> packageSplit = packageSplitResult.getResult();
pkgName = packageSplit.first;
splitName = packageSplit.second;

if (!TextUtils.isEmpty(splitName)) {
return input.error(
PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
"Expected base APK, but found split " + splitName
);
}

final TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
try {
final boolean isCoreApp =
parser.getAttributeBooleanValue(null, "coreApp", false);
// 获取清单文件中的标签 例如「application」「permission」「package」「manifest」
final ParsingPackage pkg = mCallback.startParsingPackage(
pkgName, apkPath, codePath, manifestArray, isCoreApp);
// 获取application标签中的中的「activity」「service」「receiver」「provider」
final ParseResult<ParsingPackage> result =
parseBaseApkTags(input, pkg, manifestArray, res, parser, flags);
if (result.isError()) {
return result;
}

return input.success(pkg);
} finally {
manifestArray.recycle();
}
}

startParsingPackage 获取清单文件中的标签 例如「application」「permission」「package」「manifest」

parseBaseApkTags 获取application标签中的中的「activity」「service」「receiver」「provider」;

所以,静态广播是什么时候注册的?Activity的启动模式是在什么时候获取的呢? 答案就显而易见了;

开机的时候,在 PKMS 的构造方法中 会扫描所有的 apk,包括系统 apk 和应用 apk,并解析它们的清单文件,获取到 receiver 的时候就会注册,获取到 activity 的时候 一并获取了 launchMode;

扫描外部apk直接通过接口,获取 Package 对象,PackageParserCompat.parsePackage(context, apk, PackageParser.PARSE_MUST_BE_APK);

安装 APK


用户点击 xxx.apk 文件进行安装,从「开始安装」到「完成安装」到过程;这里分为两个步骤,一个是复制流程,一个是安装流程;

复制流程

点击xxx.apk执行onClick事件,通过Intent 发起startActivity 跳转到 PackageInstallerActivity 这个界面,这个界面是以 Dialog 形式展示,存在「安装」和「取消」事件,进入「安装」事件看下;

从 PackageInstallerActivity 的 bindUI 发起流程,会调用 startInstall 方法进行整个的安装流程;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
scss复制代码private void bindUi() {
mAlert.setIcon(mAppSnippet.icon);
mAlert.setTitle(mAppSnippet.label);
mAlert.setView(R.layout.install_content_view);
mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.install),
(ignored, ignored2) -> {
if (mOk.isEnabled()) {
if (mSessionId != -1) {
mInstaller.setPermissionsResult(mSessionId, true);
finish();
} else {
// 开始安装
startInstall();
}
}
}, null);
mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
(ignored, ignored2) -> {
// Cancel and finish
setResult(RESULT_CANCELED);
if (mSessionId != -1) {
mInstaller.setPermissionsResult(mSessionId, false);
}
finish();
}, null);
setupAlert();

mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
mOk.setEnabled(false);

if (!mOk.isInTouchMode()) {
mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).requestFocus();
}
}

调用 startInstall 发起安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
scss复制代码private void startInstall() {
// Start subactivity to actually install the application
Intent newIntent = new Intent();
newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
mPkgInfo.applicationInfo);
newIntent.setData(mPackageURI);
newIntent.setClass(this, InstallInstalling.class);
String installerPackageName = getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
if (mOriginatingURI != null) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
}
if (mReferrerURI != null) {
newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
}
if (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
}
if (installerPackageName != null) {
newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
installerPackageName);
}
if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
}
newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
if (mLocalLOGV) Log.i(TAG, "downloaded app uri=" + mPackageURI);
startActivity(newIntent);
finish();
}

跳转到 安装中 InstallInstalling.class 界面,在 onResume 执行安装逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
scss复制代码protected void onResume() {
super.onResume();

// This is the first onResume in a single life of the activity
if (mInstallingTask == null) {
PackageInstaller installer = getPackageManager().getPackageInstaller();
PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);

if (sessionInfo != null && !sessionInfo.isActive()) {
mInstallingTask = new InstallingAsyncTask();
// 执行 execute 方法进行安装
mInstallingTask.execute();
} else {
// we will receive a broadcast when the install is finished
mCancelButton.setEnabled(false);
setFinishOnTouchOutside(false);
}
}
}

mInstallingTask.execute(); 执行 execute 方法进行安装;这里是一个 AsyncTask,要处理 doInBackground 和 onPostExecute

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
ini复制代码private final class InstallingAsyncTask extends AsyncTask<Void, Void,
PackageInstaller.Session> {
volatile boolean isDone;

@Override
protected PackageInstaller.Session doInBackground(Void... params) {
PackageInstaller.Session session;
try {
session = getPackageManager().getPackageInstaller().openSession(mSessionId);
} catch (IOException e) {
synchronized (this) {
isDone = true;
notifyAll();
}
return null;
}

session.setStagingProgress(0);

try {
File file = new File(mPackageURI.getPath());

try (InputStream in = new FileInputStream(file)) {
long sizeBytes = file.length();
try (OutputStream out = session
.openWrite("PackageInstaller", 0, sizeBytes)) {
byte[] buffer = new byte[1024 * 1024];
while (true) {
int numRead = in.read(buffer);

if (numRead == -1) {
session.fsync(out);
break;
}

if (isCancelled()) {
session.close();
break;
}

out.write(buffer, 0, numRead);
if (sizeBytes > 0) {
float fraction = ((float) numRead / (float) sizeBytes);
session.addProgress(fraction);
}
}
}
}

return session;
} catch (IOException | SecurityException e) {
Log.e(LOG_TAG, "Could not write package", e);

session.close();

return null;
} finally {
synchronized (this) {
isDone = true;
notifyAll();
}
}
}

@Override
protected void onPostExecute(PackageInstaller.Session session) {
if (session != null) {
Intent broadcastIntent = new Intent(BROADCAST_ACTION);
broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
broadcastIntent.setPackage(getPackageName());
broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);

PendingIntent pendingIntent = PendingIntent.getBroadcast(
InstallInstalling.this,
mInstallId,
broadcastIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);

session.commit(pendingIntent.getIntentSender());
mCancelButton.setEnabled(false);
setFinishOnTouchOutside(false);
} else {
getPackageManager().getPackageInstaller().abandonSession(mSessionId);

if (!isCancelled()) {
launchFailure(PackageInstaller.STATUS_FAILURE,
PackageManager.INSTALL_FAILED_INVALID_APK, null);
}
}
}
}

doInBackground方法中:通过IO流 将apk文件写入session中;

onPostExecute方法中:通过 session.commit 方法,跨进程操作,将 session 交给 PKMS,最终走到 PKMS 的 installStage 方法;

1
2
3
4
5
6
7
8
9
10
11
12
ini复制代码void installStage(InstallParams params) {
final Message msg = mHandler.obtainMessage(INIT_COPY);
params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;

Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
System.identityHashCode(msg.obj));
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(msg.obj));

mHandler.sendMessage(msg);
}

msg.what == INIT_COPY; handleMessage 的这个 case 我们进入看下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
scala复制代码class PackageHandler extends Handler {

void doHandleMessage(Message msg) {

switch (msg.what) {
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;
if (params != null) {
params.startCopy();
}
break;
}
}
}
}

INIT_COPY 中最终执行的是 HandlerParams 的 startCopy 方法,将 apk 复制到 /data/app 目录下;

最终走到 PKMS 的 handleStartCopy() 方法 和 handleReturnCode 方法;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
scss复制代码public void handleStartCopy() {
if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
mRet = INSTALL_SUCCEEDED;
return;
}
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);

// For staged session, there is a delay between its verification and install. Device
// state can change within this delay and hence we need to re-verify certain conditions.
boolean isStaged = (installFlags & INSTALL_STAGED) != 0;
if (isStaged) {
mRet = verifyReplacingVersionCode(
pkgLite, requiredInstalledVersionCode, installFlags);
if (mRet != INSTALL_SUCCEEDED) {
return;
}
}

mRet = overrideInstallLocation(pkgLite);
}

主要是为了创建 InstallArgs,在 handleReturnCode 中执行 copyApk 方法;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
scss复制代码void handleReturnCode() {
processPendingInstall();
}

private void processPendingInstall() {
// 这里创建的是 FileInstallArgs
InstallArgs args = createInstallArgs(this);
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
mRet = args.copyApk();
}
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
F2fsUtils.releaseCompressedBlocks(
mContext.getContentResolver(), new File(args.getCodePath()));
}
if (mParentInstallParams != null) {
mParentInstallParams.tryProcessInstallRequest(args, mRet);
} else {
PackageInstalledInfo res = createPackageInstalledInfo(mRet);
processInstallRequestsAsync(
res.returnCode == PackageManager.INSTALL_SUCCEEDED,
Collections.singletonList(new InstallRequest(args, res)));
}
}

handleReturnCode 执行到 args.copyApk() 的时候,才真正的将 apk 文件复制到了 /data/app 目录下;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
ini复制代码int copyApk() {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
try {
return doCopyApk();
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}

private int doCopyApk() {
if (origin.staged) {
if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
codeFile = origin.file;
return PackageManager.INSTALL_SUCCEEDED;
}

try {
final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
final File tempDir =
mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
codeFile = tempDir;
} catch (IOException e) {
Slog.w(TAG, "Failed to create copy file: " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}

int ret = PackageManagerServiceUtils.copyPackage(
origin.file.getAbsolutePath(), codeFile);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
Slog.e(TAG, "Failed to copy package");
return ret;
}

final boolean isIncremental = isIncrementalPath(codeFile.getAbsolutePath());
final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(codeFile);
ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
abiOverride, isIncremental);
} catch (IOException e) {
Slog.e(TAG, "Copying native libraries failed", e);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
} finally {
IoUtils.closeQuietly(handle);
}

return ret;
}

通过 IO 流 执行 copy 操作;这也就能解释为什么 apk 安装包可以删除的原因了;

扫描流程大致可以理解为:

  1. 在 PackageParser 扫描完一个 APK 后,此时系统已经根据该 APK 中 AndroidManifest.xml,创建了一个完整的 Package 对象;
  2. 扫描APK,解析AndroidManifest.xml文件,得到清单文件各个标签内容;
  3. 解析清单文件的信息由 Package 保存,从该类的成员变量可看出,和 Android 四大组件相关
    的信息分别由 activites、receivers、providers、services 保存,由于一个 APK 可声明多个组件,因此 activites 和 receivers 等均声明为 ArrayList;

安装流程

安装流程也是有 PKMS 发起的,它发起的起点就是 handleReturnCode 的回调中调用了processPendingInstall 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
scss复制代码void handleReturnCode() {
processPendingInstall();
}

private void processPendingInstall() {
InstallArgs args = createInstallArgs(this);
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
mRet = args.copyApk();
}
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
F2fsUtils.releaseCompressedBlocks(
mContext.getContentResolver(), new File(args.getCodePath()));
}
if (mParentInstallParams != null) {
mParentInstallParams.tryProcessInstallRequest(args, mRet);
} else {
PackageInstalledInfo res = createPackageInstalledInfo(mRet);
// 执行安装逻辑
processInstallRequestsAsync(
res.returnCode == PackageManager.INSTALL_SUCCEEDED,
Collections.singletonList(new InstallRequest(args, res)));
}
}

通过调用 processInstallRequestsAsync 执行安装逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
scss复制代码private void processInstallRequestsAsync(boolean success,
List<InstallRequest> installRequests) {

mHandler.post(() -> {
// 省略部分代码
if (success) {
// 省略部分代码
synchronized (mInstallLock) {
installPackagesTracedLI(apkInstallRequests);
}
}
})
}

这里直接调用 installPackagesTracedLI 进行安装;

1
2
3
4
5
6
7
8
typescript复制代码private void installPackagesTracedLI(List<InstallRequest> requests) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
installPackagesLI(requests);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}

这里直接调用 installPackagesLI 方法进行 apk 扫描以及安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
ini复制代码private void installPackagesLI(List<InstallRequest> requests) {
//
// 省略部分代码
final ScanResult result = scanPackageTracedLI(
prepareResult.packageToScan, prepareResult.parseFlags,
prepareResult.scanFlags, System.currentTimeMillis(),
request.args.user, request.args.abiOverride);

// 构建安装请求,然后调用 executePostCommitSteps 进行安装
CommitRequest commitRequest = null;
synchronized (mLock) {
Map<String, ReconciledPackage> reconciledPackages;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
reconciledPackages = reconcilePackagesLocked(
reconcileRequest, mSettings.getKeySetManagerService(), mInjector);
} catch (ReconcileFailure e) {
for (InstallRequest request : requests) {
request.installResult.setError("Reconciliation failed...", e);
}
return;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
commitRequest = new CommitRequest(reconciledPackages,
mUserManager.getUserIds());
commitPackagesLocked(commitRequest);
success = true;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
executePostCommitSteps(commitRequest);
}

构建安装请求,然后调用 executePostCommitSteps 进行安装;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
ini复制代码private void executePostCommitSteps(CommitRequest commitRequest) {
// 省略部分代码
final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>();
for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags
& PackageManagerService.SCAN_AS_INSTANT_APP) != 0);
final AndroidPackage pkg = reconciledPkg.pkgSetting.pkg;
final String packageName = pkg.getPackageName();
final String codePath = pkg.getPath();
final boolean onIncremental = mIncrementalManager != null
&& isIncrementalPath(codePath);
if (onIncremental) {
IncrementalStorage storage = mIncrementalManager.openStorage(codePath);
if (storage == null) {
throw new IllegalArgumentException(
"Install: null storage for incremental package " + packageName);
}
incrementalStorages.add(storage);
}
prepareAppDataAfterInstallLIF(pkg);

// 省略部分代码
}

// 省略部分代码
}

这里调用 prepareAppDataAfterInstallLIF 最终调用到 prepareAppDataLeaf 中的 batch.createAppData

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
less复制代码private @NonNull CompletableFuture<?> prepareAppDataLeaf(@NonNull Installer.Batch batch,
@NonNull AndroidPackage pkg, int userId, int flags) {
return batch.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo,
targetSdkVersion).whenComplete((ceDataInode, e) -> {

if (e != null) {

destroyAppDataLeafLIF(pkg, userId, flags);
try {
ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId,
flags, appId, seInfo, pkg.getTargetSdkVersion());

} catch (InstallerException e2) {

}
} else if (e != null) {

}
if (mIsUpgrade || mFirstBoot || (userId != UserHandle.USER_SYSTEM)) {
mArtManagerService.prepareAppProfiles(pkg, userId,
/* updateReferenceProfileContent= */ false);
}

if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {
synchronized (mLock) {
if (ps != null) {
ps.setCeDataInode(ceDataInode, userId);
}
}
}

prepareAppDataContentsLeafLIF(pkg, ps, userId, flags);
});
}

Batch 的 createAppData 最终调用到的是其 execute 方法;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ini复制代码public synchronized void execute(@NonNull Installer installer) throws InstallerException {
if (mExecuted) throw new IllegalStateException();
mExecuted = true;

final int size = mArgs.size();
for (int i = 0; i < size; i += CREATE_APP_DATA_BATCH_SIZE) {
final CreateAppDataArgs[] args = new CreateAppDataArgs[Math.min(size - i,
CREATE_APP_DATA_BATCH_SIZE)];
for (int j = 0; j < args.length; j++) {
args[j] = mArgs.get(i + j);
}
final CreateAppDataResult[] results = installer.createAppDataBatched(args);
for (int j = 0; j < args.length; j++) {
final CreateAppDataResult result = results[j];
final CompletableFuture<Long> future = mFutures.get(i + j);
if (result.exceptionCode == 0) {
future.complete(result.ceDataInode);
} else {
future.completeExceptionally(
new InstallerException(result.exceptionMessage));
}
}
}
}

通过 installer.createAppDataBatched(args) 方法进行 app 的创建;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
less复制代码public @NonNull CreateAppDataResult[] createAppDataBatched(@NonNull CreateAppDataArgs[] args)
throws InstallerException {
if (!checkBeforeRemote()) {
final CreateAppDataResult[] results = new CreateAppDataResult[args.length];
Arrays.fill(results, buildPlaceholderCreateAppDataResult());
return results;
}
try {
// 进入 linux 底层的安装逻辑
return mInstalld.createAppDataBatched(args);
} catch (Exception e) {
throw InstallerException.from(e);
}
}

最终 mInstalld.createAppDataBatched(args); 进入 linux 底层的安装逻辑,底层的安装逻辑我也不太清楚,只能到这里了;

权限扫描


PKMS 的构造方法中会调用到 SystemConfig systemConfig = SystemConfig.getInstance(); 方法,此方法会执行权限的扫描/system/etc/permissions

image.png

SytestemConfig 的构造方法中 会执行权限的读取操作;

image.png

readPermissions 和扫描到的AndroidManifest文件中声明的权限会和这里进行一个匹配,匹配上了给予权限;

image.png

好了,本章的讲解就到这里吧,静默安装和权限申请框架我们放在了下一章;

下一章预告


PMS 权限管理

欢迎三连


来都来了,点个关注点个赞吧,你的支持是我最大的动力~~

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%