上一篇文章:
Android10 APK 安装流程解析之PackageInstaller篇(一)
我们上一篇文章对PacakgeInstaller
做了一个简单的流程分析,在最后,我们可以看到,PacakgeInstaller
调用了PMS的installStage
方法,将APK的安装工作委托给PMS去执行。这篇文章,我们便从PMS的installStage
方法处,继续分析PMS在APK安装过程中做的工作。
PackageManagerService.installStage
void installStage(ActiveInstallSession activeInstallSession) {
final Message msg = mHandler.obtainMessage(INIT_COPY);
final InstallParams params = new InstallParams(activeInstallSession);
msg.obj = params;
mHandler.sendMessage(msg);
}
代码的内容很简单,向PMS里的Handler发了一个what 为INIT_COPY
的Message.
我们继续看Handler里的内容:
HandlerParams params = (HandlerParams) msg.obj;
if (params != null) {
params.startCopy();
}
它调用了HandlerPararms
类里的startCopy
方法。
HandlerParams.startCopy
final void startCopy() {
handleStartCopy();
handleReturnCode();
}
HandlerParams
是一个abstract类,handleStartCopy
和handleReturnCode
同样也是两个abstract方法。在整包的安装流程中,它由InstallParams
这个类去实现。
InstallParams.handleStartCopy
public void handleStartCopy() {
int ret = PackageManager.INSTALL_SUCCEEDED;
// If we're already staged, we've firmly committed to an install location
if (origin.staged) {
if (origin.file != null) {
installFlags |= PackageManager.INSTALL_INTERNAL;
} else {
throw new IllegalStateException("Invalid stage location");
}
}
//是否安装在内部存储中
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
//是否安装文件为Instant App
final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
PackageInfoLite pkgLite = null;
//解析给定的包并返回最小的细节
//在这个方法里,将会解析AndroidManifest.xml文件,并获得targetSdkVersion、
//minSdkVersion、versionCode、debuggable等信息
//与此同时,它还会去计算安装时需要的空间大小
pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
origin.resolvedPath, installFlags, packageAbiOverride);
//如果磁盘可用空间太少,先尝试释放缓存。
if (!origin.staged && pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
// TODO: focus freeing disk space on the target device
final StorageManager storage = StorageManager.from(mContext);
final long lowThreshold = storage.getStorageLowBytes(
Environment.getDataDirectory());
final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
origin.resolvedPath, packageAbiOverride);
if (sizeBytes >= 0) {
try {
mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
origin.resolvedPath, installFlags, packageAbiOverride);
} catch (InstallerException e) {
Slog.w(TAG, "Failed to free cache", e);
}
}
if (pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
pkgLite.recommendedInstallLocation
= PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
}
}
if (ret == PackageManager.INSTALL_SUCCEEDED) {
int loc = pkgLite.recommendedInstallLocation;
if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
//无法在指定的安装位置安装新包
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
//已安装相同的包
ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
} else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
//设备剩余磁盘空间不足
ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
} else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
//无效的安装文件
ret = PackageManager.INSTALL_FAILED_INVALID_APK;
} else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
//安装文件的URI无效
ret = PackageManager.INSTALL_FAILED_INVALID_URI;
} else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
//由于介质不可用而无法在指定的安装位置安装新软件包
ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
} else {
//检查安装状态,并根据安装的flag重新确定安装位置
loc = installLocationPolicy(pkgLite);
if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
//安装不可降级
ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
} else if (loc == PackageHelper.RECOMMEND_FAILED_WRONG_INSTALLED_VERSION) {
//要求的版本号和当前安装的apk的版本号不匹配
ret = PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
} else if (!onInt) {
// Override install location with flags
if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
// Set the flag to install on external media.
installFlags &= ~PackageManager.INSTALL_INTERNAL;
} else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {
if (DEBUG_INSTANT) {
Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
}
installFlags |= PackageManager.INSTALL_INSTANT_APP;
installFlags &= ~PackageManager.INSTALL_INTERNAL;
} else {
// Make sure the flag for installing on external
// media is unset
installFlags |= PackageManager.INSTALL_INTERNAL;
}
}
}
}
final InstallArgs args = createInstallArgs(this);
mVerificationCompleted = true;
mIntegrityVerificationCompleted = true;
mEnableRollbackCompleted = true;
mArgs = args;
if (ret == PackageManager.INSTALL_SUCCEEDED) {
final int verificationId = mPendingVerificationToken++;
// 校验APK
if (!origin.existing) {
PackageVerificationState verificationState =
new PackageVerificationState(this);
mPendingVerification.append(verificationId, verificationState);
sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState);
ret = sendPackageVerificationRequest(
verificationId, pkgLite, verificationState);
// If both verifications are skipped, we should remove the state.
if (verificationState.areAllVerificationsComplete()) {
mPendingVerification.remove(verificationId);
}
}
//APK 回滚相关的逻辑
if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
// TODO(ruhler) b/112431924: Don't do this in case of 'move'?
final int enableRollbackToken = mPendingEnableRollbackToken++;
Trace.asyncTraceBegin(
TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
mPendingEnableRollback.append(enableRollbackToken, this);
Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
enableRollbackIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
enableRollbackToken);
enableRollbackIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,
mSessionId);
enableRollbackIntent.setType(PACKAGE_MIME_TYPE);
enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// Allow the broadcast to be sent before boot complete.
// This is needed when committing the apk part of a staged
// session in early boot. The rollback manager registers
// its receiver early enough during the boot process that
// it will not miss the broadcast.
enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendOrderedBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM,
android.Manifest.permission.PACKAGE_ROLLBACK_AGENT,
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// the duration to wait for rollback to be enabled, in millis
long rollbackTimeout = DeviceConfig.getLong(
DeviceConfig.NAMESPACE_ROLLBACK,
PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
if (rollbackTimeout < 0) {
rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
}
final Message msg = mHandler.obtainMessage(
ENABLE_ROLLBACK_TIMEOUT);
msg.arg1 = enableRollbackToken;
msg.arg2 = mSessionId;
mHandler.sendMessageDelayed(msg, rollbackTimeout);
}
}, null, 0, null, null);
mEnableRollbackCompleted = false;
}
}
mRet = ret;
}
handleStartCopy
主要做了以下工作:
- 解析APK的简略信息,以满足安装的初始化要求以及信息校验需求
- 进一步确定APK的安装位置,并确定磁盘是否有足够的安装空间,没有的话尝试释放缓存
- 对APK安装信息做校验
HandlerParams.handleReturnCode
void handleReturnCode() {
if (mVerificationCompleted && mEnableRollbackCompleted) {
if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
String packageName = "";
try {
PackageLite packageInfo =
new PackageParser().parsePackageLite(origin.file, 0);
packageName = packageInfo.packageName;
} catch (PackageParserException e) {
Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(), e);
}
try {
observer.onPackageInstalled(packageName, mRet, "Dry run", new Bundle());
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
return;
}
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
//这里并没有真正执行复制操作,只是将InstallArgs里的codeFile和
//resourceFile指向InstallParam里的文件对象
mRet = mArgs.copyApk();
}
//执行安装操作
processPendingInstall(mArgs, mRet);
}
}
processPendingInstall
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
if (args.mMultiPackageInstallParams != null) {
args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
} else {
//单包走这个分支
//PackageInstalledInfo 用于保存 安装的结果,成功还是失败,失败原因是什么
PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
processInstallRequestsAsync(
res.returnCode == PackageManager.INSTALL_SUCCEEDED,
Collections.singletonList(new InstallRequest(args, res)));
}
}
processInstallRequestsAsync
private void processInstallRequestsAsync(boolean success,
List<InstallRequest> installRequests) {
//在Handler所在的线程执行安装操作,这是个子线程
mHandler.post(() -> {
if (success) {
for (InstallRequest request : installRequests) {
//检测returnCode是否为INSTALL_SUCCEEDED,否的话清除复制的APK并删除相关目录与文件
request.args.doPreInstall(request.installResult.returnCode);
}
synchronized (mInstallLock) {
//解析APK
installPackagesTracedLI(installRequests);
}
for (InstallRequest request : installRequests) {
//和doPreInstall方法一样
request.args.doPostInstall(
request.installResult.returnCode, request.installResult.uid);
}
}
for (InstallRequest request : installRequests) {
//APK安装完成的后续操作,如apk备份、回滚、发送安装相关的广播
restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
new PostInstallData(request.args, request.installResult, null));
}
});
}
installPackagesTracedLI
方法里只是简单的调用installPackagesLI
。我们重点来看installPackagesLI
方法,它负责Apk的内容的解析,属于安装过程中的核心方法。
installPackagesLI
private void installPackagesLI(List<InstallRequest> requests) {
final Map<String, ScanResult> preparedScans = new ArrayMap<>(requests.size());
final Map<String, InstallArgs> installArgs = new ArrayMap<>(requests.size());
final Map<String, PackageInstalledInfo> installResults = new ArrayMap<>(requests.size());
final Map<String, PrepareResult> prepareResults = new ArrayMap<>(requests.size());
final Map<String, VersionInfo> versionInfos = new ArrayMap<>(requests.size());
final Map<String, PackageSetting> lastStaticSharedLibSettings =
new ArrayMap<>(requests.size());
final Map<String, Boolean> createdAppId = new ArrayMap<>(requests.size());
boolean success = false;
try {
for (InstallRequest request : requests) {
final PrepareResult prepareResult;
try {
//准备阶段,根据安装信息确定扫描Flags,在这个方法里,主要做了以下几件事
//1、对apk的AndroidManifest.xml文件做了全面的解析,比如apk中的所有
//activity、service、permission等信息,并将解析结果保存在了PackageParser.Package类里
//2、通过Dm-verity校验dex文件的有效性
//3、解析apk签名信息
//4、解析android资源索引表resources.arsc文件
prepareResult = preparePackageLI(request.args, request.installResult);
} catch (PrepareFailure prepareFailure) {
request.installResult.setError(prepareFailure.error,
prepareFailure.getMessage());
request.installResult.origPackage = prepareFailure.conflictingPackage;
request.installResult.origPermission = prepareFailure.conflictingPermission;
return;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
request.installResult.installerPackageName = request.args.installerPackageName;
final String packageName = prepareResult.packageToScan.packageName;
//保存了APK预解析信息
prepareResults.put(packageName, prepareResult);
//保存安装结果
installResults.put(packageName, request.installResult);
//保存安装的请求参数
installArgs.put(packageName, request.args);
try {
//扫描阶段,进一步搜集apk信息,比如PackageSetting、apk里的动态库和静态库的位置
final List<ScanResult> scanResults = scanPackageTracedLI(
prepareResult.packageToScan, prepareResult.parseFlags,
prepareResult.scanFlags, System.currentTimeMillis(),
request.args.user);
for (ScanResult result : scanResults) {
//保存APK扫描结果
if (null != preparedScans.put(result.pkgSetting.pkg.packageName, result)) {
request.installResult.setError(
PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
"Duplicate package " + result.pkgSetting.pkg.packageName
+ " in multi-package install request.");
return;
}
//向系统中注册一个appId
createdAppId.put(packageName, optimisticallyRegisterAppId(result));
//app版本信息管理
versionInfos.put(result.pkgSetting.pkg.packageName,
getSettingsVersionForPackage(result.pkgSetting.pkg));
if (result.staticSharedLibraryInfo != null) {
final PackageSetting sharedLibLatestVersionSetting =
getSharedLibLatestVersionSetting(result);
if (sharedLibLatestVersionSetting != null) {
//lib库信息管理 lastStaticSharedLibSettings.put(result.pkgSetting.pkg.packageName,
sharedLibLatestVersionSetting);
}
}
}
} catch (PackageManagerException e) {
request.installResult.setError("Scanning Failed.", e);
return;
}
}
//验证阶段,需要对apk的签名进行校验,是否与已安装的apk签名不一致。还有是否需要在安装前先执行删除动作
ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
installResults,
prepareResults,
mSharedLibraries,
Collections.unmodifiableMap(mPackages), versionInfos,
lastStaticSharedLibSettings);
CommitRequest commitRequest = null;
synchronized (mPackages) {
Map<String, ReconciledPackage> reconciledPackages;
try {
//开始校验apk能否安装
reconciledPackages = reconcilePackagesLocked(
reconcileRequest, mSettings.mKeySetManagerService);
} 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,
sUserManager.getUserIds());
//如果需要对应用做覆盖安装,首先删掉已安装的应用
//并更新PackageSetting信息
commitPackagesLocked(commitRequest);
success = true;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
//安装成功后的后续操作
//1、为安装的app 创建app data目录,已存在时对目录进行校验,该操作主要是Installd进程负责完成
//2. 准备新代码路径的应用程序配置文件,需要在调用dexopt之前完成
//3. 检查是否需要对dex文件做优化,如果需要的话执行优化操作
executePostCommitSteps(commitRequest);
} finally {
if (!success) {
for (ScanResult result : preparedScans.values()) {
if (createdAppId.getOrDefault(result.request.pkg.packageName, false)) {
cleanUpAppIdCreation(result);
}
}
// TODO(patb): create a more descriptive reason than unknown in future release
// mark all non-failure installs as UNKNOWN so we do not treat them as success
for (InstallRequest request : requests) {
if (request.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) {
request.installResult.returnCode = PackageManager.INSTALL_UNKNOWN;
}
}
}
for (PrepareResult result : prepareResults.values()) {
if (result.freezer != null) {
result.freezer.close();
}
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
installPackagesLI
以原子方式安装一个或多个程序包。此操作分为四个阶段:
- 准备阶段 : 分析当前的安装信息,解析包的AndroidManifest.xml文件并对其进行初始验证。
- 扫描阶段 : 根据准备阶段中收集的上下文扫描包并进一步解析的包里的内容。
- 验证阶段 : 对软件包信息进行校验,比如校验签名,以确保安装成功。
- 提交阶段 : 提交所有扫描的包的信息并更新系统状态。这是安装流程中唯一可以修改系统状态的地方,在此阶段之前必须对所有可预测的错误做检查。
有读者就会问了,上面的流程都是对apk文件里的信息做解析,安装的过程在哪里?
android的安装主要生成了以下文件:
-
PackageInstallerSession
的doWriteInternal
方法,将apk文件复制到/data/app/vmdl${sessionId}.tmp/base.apk
路径下。 -
PackageInstallerSession
的commitNonStagedLocked
方法中会调用extractNativeLibraries
方法,将apk文件里的Native Lib文件解压到/data/app/vmdl${sessionId}.tmp/lib
目录下。 -
准备阶段
preparePackageLI
会将安装目录由vmdl${sessionId}.tmp
重命名为${packageName}-${Base64.encodeToString(随机16位byte数组)}
。 -
提交阶段
executePostCommitSteps
方法会调用PackageDexOptimizer
中的performDexOpt
方法,在/data/app/${packageName}-${Base64.encodeToString(随机16位byte数组)}/oat
目录下生成base.art
,base.odex
,base.vdex
三个文件。
最后,我们用流程图来总结一下Apk的安装过程: