上一章详细分析了PMS的启动流程,本章将继续探究PMS的应用安装流程。
1、APK结构
在探究PMS安装流程之前,先简单了解下APK的组成:
目录 or 文件 | 描述 |
---|---|
assert | 存放的原生资源文件,通过AssetManager类访问 |
lib | native库文件 |
META-INF | 存放签名信息,用来保证APK包的完整性和系统的安全。系统安装APK时,应用管理器会按照对应算法对包里文件做校验,如果校验结果与META-INF中内容不一致,则不会安装这个APK。 |
res | 种资源文件系统会在R.java里面自动生成该资源文件的ID,所以访问这种资源文件比较简单,通过R.XXX.ID即可 |
AndroidManifest.xml | 每个应用都必须定义和包含,描述应用的名字、版本权限、引用的库文件等信息。apk中的AndroidManifest.xml经过压缩,可以通过AXMLPrinter2工具解开。 |
classes.dex | 是JAVA源码编译后生成的JAVA字节码文件。但Android使用的dalvik虚拟机与标准的JAVA虚拟机不兼容,dex文件与class文件相比,不论是文件结构还是opcode都不一样。 |
resources.arsc | 编译后的二进制资源文件。 |
2、应用安装方法
安卓的应用安装方式可分为以下几种: APK有下面4种安装方法:
方法 | 描述 |
---|---|
开机过程中安装 | 开机时完成,没有安装界面,如系统应用、其它预置应用 |
adb工具安装 | 没有安装界面,adb install/push xxxx.apk |
第三方应用安装 | 通过packageinstaller.apk进行安装,有安装界面,如打开文件管理器并点击sdk卡里APK文件 |
网络下载应用安装 | 通过google market应用完成,没有安装界面 |
简单来说,apk的安装可以分为两步:
一是拷贝目标apk到指定文件目录
二是调用scanPackageLI为apk文件在系统中注册信息。
3、应用安装流程
这里主要来看一下通过ADB工具安装APK的流程。
3.1、adb install
当执行adb install
时,会调用packages/modules/adb/client/commandline.cpp
中的adb_commandline
函数,这个过程会把apk文件copy到data/local/tmp/
目录下,然后向shell服务发送pm命令安装apk,最后调用Pm.runInstall()
方法来安装apk。
3.2、 Pm.runInstall
frameworks/base/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
private int runInstall() throws RemoteException {
return doRunInstall(makeInstallParams());
}
private int doRunInstall(final InstallParams params) throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final boolean isStreaming = params.sessionParams.dataLoaderParams != null;
final boolean isApex =
(params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;
ArrayList<String> args = getRemainingArgs();
final boolean fromStdIn = args.isEmpty() || STDIN_PATH.equals(args.get(0));
final boolean hasSplits = args.size() > 1;
if (fromStdIn && params.sessionParams.sizeBytes == -1) {
pw.println("Error: must either specify a package size or an APK file");
return 1;
}
if (isApex && hasSplits) {
pw.println("Error: can't specify SPLIT(s) for APEX");
return 1;
}
if (!isStreaming) {
if (fromStdIn && hasSplits) {
pw.println("Error: can't specify SPLIT(s) along with STDIN");
return 1;
}
if (args.isEmpty()) {
args.add(STDIN_PATH);
} else {
setParamsSize(params, args);
}
}
//创建Session
final int sessionId = doCreateSession(params.sessionParams,
params.installerPackageName, params.userId);
boolean abandonSession = true;
try {
if (isStreaming) {
if (doAddFiles(sessionId, args, params.sessionParams.sizeBytes, isApex)
!= PackageInstaller.STATUS_SUCCESS) {
return 1;
}
} else {
// 写session
if (doWriteSplits(sessionId, args, params.sessionParams.sizeBytes, isApex)
!= PackageInstaller.STATUS_SUCCESS) {
return 1;
}
}
if (doCommitSession(sessionId, false /*logSuccess*/)
!= PackageInstaller.STATUS_SUCCESS) {
return 1;
}
abandonSession = false;
if (!params.sessionParams.isStaged || !params.mWaitForStagedSessionReady) {
pw.println("Success");
return 0;
}
return doWaitForStagedSessionRead(sessionId, params.timeoutMs, pw);
} finally {
if (abandonSession) {
try {
doAbandonSession(sessionId, false /*logSuccess*/);
} catch (Exception ignore) {
}
}
}
}
从上面的代码来看,runInstall主要进行了三件事,即创建session、对session进行写操作,最后提交session,这三步单独拆开如下:
3.2.1、 doCreateSession
实际调用的是PackageInstallerService
的createSession
,这个过程主要是为APK安装做好准备工作,例如权限检查、目的临时文件的创建等, 最终创建出PackageInstallerSession
对象。 PackageInstallerSession
可以看做是”安装APK”这个请求的封装,其中包含了处理这个请求需要的一些信息。 实际上PackageInstallerSession
不仅是封装请求的对象,其自身还是个服务端。
3.2.2、doWriteSession
通过PackageInstallerSession
将/data/local/tmp
的apk拷贝到终端目录内。
3.2.3、doCommitSession
doWriteSession
结束后,如果没有出现任何错误,那么APK源文件已经copy到目的地址了,doCommitSession最终会调用到PMS.installStage
来安装apk,调用流程如下:
PackageInstallerSession.commit ==> commitLocked(); ==> PMS.installStage()
PMS.installStage()会调用sendMessage将INIT_COPY发送给PackageHandler
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
// 进入安装阶段
void installStage(ActiveInstallSession activeInstallSession) {
if (DEBUG_INSTANT) {
if ((activeInstallSession.getSessionParams().installFlags
& PackageManager.INSTALL_INSTANT_APP) != 0) {
Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
}
}
final Message msg = mHandler.obtainMessage(INIT_COPY);
final InstallParams params = new InstallParams(activeInstallSession);
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);
}
PackageHandler用于处理apk的安装请求等消息,后面分析。
3.3、PackageHanlder
PackageHandler用于处理apk的安装请求等消息,在PMS构造函数中有初始化。其代码位于: frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
,实际处理消息的函数为doHandleMessage,由于此处代码较多,我们按照处理流程拆开分析。
3.3.1、INIT_COPY
我们来看看INIT_COPY的处理流程:
class PackageHandler extends Handler {
void doHandleMessage(Message msg) {
...
switch (msg.what) {
// 这里取出的其实就是InstallParams
HandlerParams params = (HandlerParams) msg.obj;
// 如果参数不为空则说明当前安装队列中有安装任务
if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(params));
// 开始安装流程
params.startCopy();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
break;
}
...
}
}
INIT_COPY主要是将安装请求队列中的任务取出,并复制开始安装流程。其中startCopy() 完成的工作:
1.超出最大重试次数,发送 MCS_GIVE_UP 消息放弃
2.实际调用 handleStartCopy() 开始处理拷贝
3.远程调用抛出异常,发出 MCS_RECONNECT 消息重连
4.最后调用 handleReturnCode() 处理返回值
这里需要注意的是,startCopy()
函数在安卓11以前是在MCS_BOUND
这个case下被调用的,但在Android 11下被放到了INIT_COPY这个case下执行,同时,INIT_COPY
的逻辑也发生了一些变化。
3.4、startCopy
InstallParams继承HandlerParams,实际调用的是HandlerParams.startCopy: frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private abstract class HandlerParams {
...
final void startCopy() {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
handleStartCopy();
handleReturnCode();
}
...
}
PMS将先后调用handleStartCopy
和handleReturnCode
来完成主要的工作。
3.4.1、handleStartCopy
handleStartCopy
函数在HandleParams抽象类定义,在其子类InstallParams
来实现,我们看看与实际安装相关的handleStartCopy函数:
public void handleStartCopy() {
if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
mRet = INSTALL_SUCCEEDED;
return;
}
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);
boolean isStaged = (installFlags & INSTALL_STAGED) != 0;
if (isStaged) {
mRet = verifyReplacingVersionCode(
pkgLite, requiredInstalledVersionCode, installFlags);
if (mRet != INSTALL_SUCCEEDED) {
return;
}
}
mRet = overrideInstallLocation(pkgLite);
}
3.4.2、overrideInstallLocation
在Android 11以前,handleStartCopy
一个函数就处理了apk的安装信息检查,但在Android 11内,这些逻辑被放到了overrideInstallLocation
中实现,下面分析一下overrideInstallLocation
的相关代码:
private int overrideInstallLocation(PackageInfoLite pkgLite) {
...
// 检查文件和cid是否已生成,如生成则设置installFlags
if (origin.staged) {
// If we're already onInt && onSdstaged, we've firmly committed to an install location
if (origin.file != null) {
installFlags |= PackageManager.INSTALL_INTERNAL;
} else {
throw new IllegalStateException("Invalid stage location");
}
} else if (pkgLite.recommendedInstallLocation == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE)
// 检查空间大小,如果空间不够则释放无用空间。
final StorageManager storage = StorageManager.from(mContext);
Environment.getDataDirectory());
final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
origin.resolvedPath, packageAbiOverride);
if (sizeBytes >= 0) {
try {
pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
mPackageLite, origin.resolvedPath, installFlags,
packageAbiOverride);
} catch (InstallerException e) {
Slog.w(TAG, "Failed to free cache", e);
}
}
...
}
3.4.3、handleReturnCode
在handleReturnCode中,调用handleReturnCode
方法处理安装
@Override
void handleReturnCode() {
processPendingInstall();
}
3.7.4、processPendingInstall
主要的安装流程都在这个方法里面: PMS.processPendingInstall
private void processPendingInstall() {
// createInstallArgs用于创建一个安装参数对象
InstallArgs args = createInstallArgs(this);
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
// 调用 copyApk() 进行APK的拷贝动作,通过文件流的操作,把APK拷贝到/data/app等目录
mRet = args.copyApk();
}
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
mContext.getContentResolver(), new File(args.getCodePath()));
}
// 当安装信息不为空时,尝试继续安装流程
mParentInstallParams.tryProcessInstallRequest(args, mRet);
} else {
// 设置安装参数
PackageInstalledInfo res = createPackageInstalledInfo(mRet);
// 创建一个新线程,处理安装参数,进行安装
processInstallRequestsAsync(
res.returnCode == PackageManager.INSTALL_SUCCEEDED,
}
}
private void processInstallRequestsAsync(boolean success,
List<InstallRequest> installRequests) {
mHandler.post(() -> {
...
if (success) {
for (InstallRequest request : apkInstallRequests) {
// 如果之前安装失败,清除无用信息
request.args.doPreInstall(request.installResult.returnCode);
}
}
}
在Android11中,加入了一个续装流程,既当安装信息不为空时,系统会尝试继续安装该应用,而不是创建一个新线程进行安装,这提高了应用安装的效率。
3.5、installPackageTracedLI
installPackageTracedLI
方法创建了一个新的线程,并在线程中执行了installPackagesLI
方法进行应用的安装。
@GuardedBy("mInstallLock")
private void installPackagesTracedLI(List<InstallRequest> requests) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
installPackagesLI(requests);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
3.6、installPackagesLI
以原子操作方式安装一个或多个包。此操作分为五个阶段:
1.Prepare 准备:分析任何当前安装状态,分析包并对其进行初始验证。
2.Scan 扫描:考虑到prepare中收集的上下文,询问已分析的包。
3.Reconcile 调和:在彼此的上下文和当前系统状态中验证扫描的包,以确保安装成功。
4.Commit 提交:提交所有扫描的包并更新系统状态。这是安装流中唯一可以修改系统状态的地方,必须在此阶段之前确定所有可预测的错误。
5.完成APK的安装
installPackagesLI
方法代码较多,大致架构如下:
private void installPackagesLI(List<InstallRequest> requests) {
...
//1.Prepare 准备:分析任何当前安装状态,分析包并对其进行初始验证。
prepareResult = preparePackageLI(request.args, request.installResult);
...
//2.Scan 扫描:考虑到prepare中收集的上下文,询问已分析的包。
final List<ScanResult> scanResults = scanPackageTracedLI(
prepareResult.packageToScan, prepareResult.parseFlags,
prepareResult.scanFlags, System.currentTimeMillis(),
...
//3.Reconcile 调和:在彼此的上下文和当前系统状态中验证扫描的包,以确保安装成功。
ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
installResults,
prepareResults,
mSharedLibraries,
Collections.unmodifiableMap(mPackages), versionInfos,
lastStaticSharedLibSettings);
...
//4.Commit 提交:提交所有扫描的包并更新系统状态。这是安装流中唯一可以修改系统状态的地方,必须在此阶段之前确定所有可预测的错误。
commitPackagesLocked(commitRequest);
...
//5.完成APK的安装
executePostCommitSteps(commitRequest);
}
3.7、安装过程细分为以下15步
3.7.1、 首先检查安装包的完整性并解析安装包。
[PackageManagerService.java] preparePackageLI()
// 完整性校验
if (instantApp && onExternal) {
Slog.i(TAG, "Incompatible ephemeral install; external=" + onExternal);
throw new PrepareFailure(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
}
// 检索包设置,并解析应用
@ParseFlags final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
| PackageParser.PARSE_ENFORCE_CODE
| (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setDisplayMetrics(mMetrics);
pp.setCallback(mPackageParserCallback);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final PackageParser.Package pkg;
try {
//解析安装包
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
DexMetadataHelper.validatePackageDexMetadata(pkg);
} catch (PackageParserException e) {
throw new PrepareFailure("Failed parse during installPackageLI", e);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
3.7.2、 检查SDK版本和沙箱版本,同时检查是否有静态共享库,如有则需要放在内部存储中。
[PackageManagerService.java] preparePackageLI()
//检查SDK版本和沙箱版本
if (instantApp) {
if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
Slog.w(TAG,
"Instant app package " + pkg.packageName + " does not target at least O");
throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
"Instant app package must target at least O");
}
if (pkg.mSharedUserId != null) {
Slog.w(TAG, "Instant app package " + pkg.packageName
+ " may not declare sharedUserId.");
throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
"Instant app package may not declare a sharedUserId");
}
}
//检查是否有静态共享库
if (pkg.applicationInfo.isStaticSharedLibrary()) {
// Static shared libraries have synthetic package names
renameStaticSharedLibraryPackage(pkg);
// No static shared libs on external storage
if (onExternal) {
Slog.i(TAG, "Static shared libs can only be installed on internal storage.");
throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
"Packages declaring static-shared libs cannot be updated");
}
}
3.7.3、 检查是否有子安装包,如有则子安装包也需要检测。
[PackageManagerService.java]preparePackageLI()
if(pkg.childPackages!=null){
synchronized (mPackages){
final int childCount=pkg.childPackages.size();
for(int i=0;i<childCount; i++){
PackageParser.Package childPkg=pkg.childPackages.get(i);
PackageInstalledInfo childRes=new PackageInstalledInfo();
childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
childRes.pkg=childPkg;
childRes.name=childPkg.packageName;
PackageSetting childPs=mSettings.getPackageLPr(childPkg.packageName);
if(childPs!=null){
childRes.origUsers=childPs.queryInstalledUsers(
sUserManager.getUserIds(),true);
}
if((mPackages.containsKey(childPkg.packageName))){
childRes.removedInfo=new PackageRemovedInfo(this);
childRes.removedInfo.removedPackage=childPkg.packageName;
childRes.removedInfo.installerPackageName=childPs.installerPackageName;
}
if(res.addedChildPackages==null){
res.addedChildPackages=new ArrayMap<>();
}
res.addedChildPackages.put(childPkg.packageName,childRes);
}
}
}
3.7.4、 校验安装包签名
[PackageManagerService.java] preparePackageLI()
PackageSetting signatureCheckPs = ps;
if (pkg.applicationInfo.isStaticSharedLibrary()) {
SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(pkg);
if (libraryInfo != null) {
signatureCheckPs = mSettings.getPackageLPr(libraryInfo.getPackageName());
}
}
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+ pkg.packageName + " upgrade keys do not match the "
+ "previously installed version");
}
}
3.7.5、 设置相关的权限,包括生成权限、移植权限等
3.7.6、 如果这是一个系统应用,则检查是否在外部存储上或是是否被其他应用替换等
[PackageManagerService.java]preparePackageLI()
if(systemApp){
if(onExternal){
// Abort update; system app can't be replaced with app on sdcard
throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
"Cannot install updates to system apps on sdcard");
}else if(instantApp){
// Abort update; system app can't be replaced with an instant app
throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
"Cannot update a system app with an instant app");
}
}
3.7.7、 生成安装包Abi(Application binary interface,应用二进制接口,描述应用程序和操作系统之间或其他应用程序的低级接口)
[PackageManagerService.java] preparePackageLI()
try {
String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
args.abiOverride : pkg.cpuAbiOverride);
final boolean extractNativeLibs = !pkg.isLibrary();
derivePackageAbi(pkg, abiOverride, extractNativeLibs);
} catch (PackageManagerException pme) {
Slog.e(TAG, "Error deriving application ABI", pme);
throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
}
3.7.8、 如有必要,优化dex文件
[PackageManagerService.java] executePostCommitSteps()
final boolean performDexopt =(!instantApp || Global.getInt(mContext.getContentResolver(),Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)&& ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
if (performDexopt) {
// Compile the layout resources.
if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts");
mViewCompiler.compileLayouts(pkg);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
DexoptOptions dexoptOptions = new DexoptOptions(packageName,
REASON_INSTALL,
DexoptOptions.DEXOPT_BOOT_COMPLETE
| DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
mPackageDexOptimizer.performDexOpt(pkg,null /* instructionSets */,
getOrCreateCompilerPackageStats(pkg),
mDexManager.getPackageUseInfoOrDefault(packageName),
dexoptOptions);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
3.7.9、 冻结APK,并决定是替换安装,还是新安装,组装参数
[PackageManagerService.java] preparePackageLI()
final PackageFreezer freezer =freezePackageForInstall(pkgName, installFlags, "installPackageLI");
if (replace) {
//替换安装
} else {// new package install
//安装新的APK
//1)已安装具有相同名称的包,但已将其重命名为旧名称
//2)不要允许在同一名称的现有包上安装。
renamedPackage = mSettings.getRenamedPackageLPr(pkgName1);
}
3.7.10、 扫描APK,将APK的信息存储在PackageParser.Package类型的newPackage中,一个Package的信息包含了1个base APK以及0个或者多个split APK。
进入 [PackageManagerService.java] scanPackageTracedLI
调用顺序: scanPackageTracedLI() => scanPackageLI() => parsePackage()
3.7.11、 更新共享库
[PackageManagerService.java] commitPackageSettings()
synchronized (mPackages) {
if (!ArrayUtils.isEmpty(reconciledPkg.allowedSharedLibraryInfos)) {
for (SharedLibraryInfo info : reconciledPkg.allowedSharedLibraryInfos) {
commitSharedLibraryInfoLocked(info);
final Map<String, PackageParser.Package> combinedPackages =reconciledPkg.getCombinedPackages();
try {
// Shared libraries for the package need to be updated.
updateSharedLibrariesLocked(pkg, null, combinedPackages);
} catch (PackageManagerException e) {
Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e);
}
// Update all applications that use this library. Skip when booting
// since this will be done after all packages are scaned.
if ((scanFlags & SCAN_BOOTING) == 0) {
clientLibPkgs = updateAllSharedLibrariesLocked(pkg, combinedPackages);
}
}
}
}
3.7.12、 更新该APK对应的Settings信息,Settings用于保存所有包的动态设置。
[PackageManagerService.java] commitPackageSettings()
synchronized (mPackages) {
// Add the new setting to mSettings
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// Add the new setting to mPackages
mPackages.put(pkg.applicationInfo.packageName, pkg);
}
3.7.13、 安装APK,并为新的代码路径准备应用程序配置文件,并再次检查是否需要dex优化
如果是直接安装新包,会为新的代码路径准备应用程序配置文件。 如果是替换安装:其主要过程为更新设置,清除原有的某些APP数据,重新生成相关的app数据目录等步骤,同时要区分系统应用替换和非系统应用替换。而安装新包:则直接更新设置,生成APP数据即可。
[PackageManagerService.java] executePostCommitSteps()
private void executePostCommitSteps(CommitRequest commitRequest) {
for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
...
//1)进行安装
prepareAppDataAfterInstallLIF(pkg);
//2)如果需要替换安装,则需要清楚原有的APP数据
if (reconciledPkg.prepareResult.clearCodeCache) {
clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
| FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
//3)为新的代码路径准备应用程序配置文件。这需要在调用dexopt之前完成,以便任何安装时配置文件都可以用于优化。
mArtManagerService.prepareAppProfiles(pkg,resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()),
/* updateReferenceProfileContent= */ true);
final boolean performDexopt =(!instantApp || Global.getInt(mContext.getContentResolver(),
Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)&& ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
if (performDexopt) {
...
//4)执行dex优化
mPackageDexOptimizer.performDexOpt(pkg,null /* instructionSets */,getOrCreateCompilerPackageStats(pkg),
mDexManager.getPackageUseInfoOrDefault(packageName),
dexoptOptions);
}
}
}
3.7.14、 APK的安装
[PackageManagerService.java] prepareAppDataAfterInstallLIF() 通过一系列的调用,最终会调用到[Installer.java] createAppData()进行安装,交给installed进程进行APK的安装
调用顺序如下: prepareAppDataAfterInstallLIF() => prepareAppDataLIF() => prepareAppDataLeafLIF() => Installer.java#createAppData()
private void prepareAppDataAfterInstallLIF(PackageParser.Package pkg) {
...
for (UserInfo user : um.getUsers()) {
...
if (ps.getInstalled(user.id)) {
// TODO: when user data is locked, mark that we're still dirty
prepareAppDataLIF(pkg, user.id, flags);
}
}
}
private void prepareAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
if (pkg == null) {
Slog.wtf(TAG, "Package was null!", new Throwable());
return;
}
prepareAppDataLeafLIF(pkg, userId, flags);
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
prepareAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
}
}
private void prepareAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
if (DEBUG_APP_DATA) {
Slog.v(TAG, "prepareAppData for " + pkg.getPackageName() + " u" + userId + " 0x"
+ Integer.toHexString(flags));
}
final PackageSetting ps;
synchronized (mLock) {
ps = mSettings.mPackages.get(pkg.getPackageName());
}
final String volumeUuid = pkg.getVolumeUuid();
final String packageName = pkg.getPackageName();
final int appId = UserHandle.getAppId(pkg.getUid());
String pkgSeInfo = AndroidPackageUtils.getSeInfo(pkg, ps);
Preconditions.checkNotNull(pkgSeInfo);
final String seInfo = pkgSeInfo + (pkg.getSeInfoUser() != null ? pkg.getSeInfoUser() : "");
long ceDataInode = -1;
try {
ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
appId, seInfo, pkg.getTargetSdkVersion());
} catch (InstallerException e) {
if (pkg.isSystem()) {
logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName
+ ", but trying to recover: " + e);
destroyAppDataLeafLIF(pkg, userId, flags);
try {
ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
appId, seInfo, pkg.getTargetSdkVersion());
logCriticalInfo(Log.DEBUG, "Recovery succeeded!");
} catch (InstallerException e2) {
logCriticalInfo(Log.DEBUG, "Recovery failed!");
}
} else {
Slog.e(TAG, "Failed to create app data for " + packageName + ": " + e);
}
}
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);
}
3.7.15、 安装完成后,更新设置,更新安装锁等
总结
以上就是对于PMS的安装流程的解析,大体上可以分为4步:
- 将APK的信息通过IO流的形式写入到PackageInstaller.Session中。
- 调用PackageInstaller.Session的commit方法,将APK的信息交由PKMS处理。
- 拷贝APK
- 最后进行安装
最终是交给installed守护进行完成真正的APK安装