系統(tǒng)源碼參考:android 11。
系統(tǒng)側(cè)實(shí)現(xiàn)apk安裝鲤遥,主要通過PakcageManagerService來完成疚俱,安裝過程主要分為復(fù)制apk和安裝apk兩個(gè)階段书在,本篇文章現(xiàn)在針對(duì)整體安裝流程進(jìn)行梳理,中間牽扯到的重要模塊之后單獨(dú)梳理腮恩。
一梢杭、復(fù)制apk流程解析
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);
//初始化InstallParams,后續(xù)會(huì)由他來主導(dǎo)安裝任務(wù)
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));
//發(fā)送INIT_COPY消息
mHandler.sendMessage(msg);
}
這個(gè)方法主要干了兩件事:
- 初始化InstallParams
- 發(fā)送INIT_COPY消息
初始化InstallParams秸滴,在構(gòu)造方法中:
InstallParams(ActiveInstallSession activeInstallSession) {
super(activeInstallSession.getUser());
final PackageInstaller.SessionParams sessionParams =
activeInstallSession.getSessionParams();
if (DEBUG_INSTANT) {
if ((sessionParams.installFlags
& PackageManager.INSTALL_INSTANT_APP) != 0) {
Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
}
}
verificationInfo = new VerificationInfo(
sessionParams.originatingUri,
sessionParams.referrerUri,
sessionParams.originatingUid,
activeInstallSession.getInstallerUid());
origin = OriginInfo.fromStagedFile(activeInstallSession.getStagedDir());
move = null;
installReason = fixUpInstallReason(
activeInstallSession.getInstallSource().installerPackageName,
activeInstallSession.getInstallerUid(),
sessionParams.installReason);
observer = activeInstallSession.getObserver();
installFlags = sessionParams.installFlags;
installSource = activeInstallSession.getInstallSource();
volumeUuid = sessionParams.volumeUuid;
packageAbiOverride = sessionParams.abiOverride;
grantedRuntimePermissions = sessionParams.grantedRuntimePermissions;
whitelistedRestrictedPermissions = sessionParams.whitelistedRestrictedPermissions;
autoRevokePermissionsMode = sessionParams.autoRevokePermissionsMode;
signingDetails = activeInstallSession.getSigningDetails();
requiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
forceQueryableOverride = sessionParams.forceQueryableOverride;
mDataLoaderType = (sessionParams.dataLoaderParams != null)
? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
mSessionId = activeInstallSession.getSessionId();
}
這里很明顯武契,之前PackageInstaller將apk寫入session,這里通過session獲取到安裝包信息,并賦值給InstallParams吝羞,同時(shí)這里額外初始化了一個(gè)VerificationInfo驗(yàn)證信息類兰伤。
再來看發(fā)送INIT_COPY消息:
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;
if (params != null) {
if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(params));
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
params.startCopy();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
break;
}
這里的HandlerParams是抽象基類,具體實(shí)現(xiàn)是前面?zhèn)魅氲腎nstallParams钧排,由它來執(zhí)行startCopy
final void startCopy() {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
handleStartCopy();
handleReturnCode();
}
startCopy分了兩步敦腔,一個(gè)個(gè)來看。
/*
* Invoke remote method to get package information and install
* location values. Override install location based on default
* policy if needed and then create install arguments based
* on the install location.
*/
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;
final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
PackageInfoLite pkgLite = null;
//通過PackageParser.parsePackageLite解析一個(gè)精簡(jiǎn)版的包信息
pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
origin.resolvedPath, installFlags, packageAbiOverride);
if (DEBUG_INSTANT && ephemeral) {
Slog.v(TAG, "pkgLite for install: " + pkgLite);
}
/*
* If we have too little free space, try to free cache
* before giving up.
*/
//檢查剩余的磁盤空間
//如果是通過ActiveInstallSession 初始化的InstallParams恨溜,origin.staged為true
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);
}
}
/*
* The cache free must have deleted the file we downloaded to install.
*
* TODO: fix the "freeCache" call to not delete the file we care about.
*/
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) {
ret = PackageManager.INSTALL_FAILED_INVALID_URI;
} else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
} else {
// Override with defaults if needed.
//確定推薦安裝
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) {
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;
}
}
}
}
//創(chuàng)建InstallArgs
final InstallArgs args = createInstallArgs(this);
mVerificationCompleted = true;
mIntegrityVerificationCompleted = true;
mEnableRollbackCompleted = true;
mArgs = args;
if (ret == PackageManager.INSTALL_SUCCEEDED) {
final int verificationId = mPendingVerificationToken++;
// Perform package verification (unless we are simply moving the package).
if (!origin.existing) {
PackageVerificationState verificationState =
new PackageVerificationState(this);
mPendingVerification.append(verificationId, verificationState);
//發(fā)起安裝包完整性校驗(yàn)
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);
}
}
...
mRet = ret;
}
整個(gè)方法都是基于PackageManagerServiceUtils.getMinimalPackageInfo發(fā)起的符衔,根據(jù)對(duì)包解析的情況,來決定如下事情的處理:
- 是否有足夠的磁盤空間糟袁,不夠則清理判族;
- 確定推薦安裝位置
- 初始化InstallArgs來做后續(xù)的copy apk任務(wù);
- 發(fā)起包的完整性校驗(yàn)项戴;
然后接著走h(yuǎn)andleReturnCode方法
void handleReturnCode() {
//校驗(yàn)通過
if (mVerificationCompleted
&& mIntegrityVerificationCompleted && mEnableRollbackCompleted) {
if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
String packageName = "";
ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
new ParseTypeImpl(
(changeId, packageName1, targetSdkVersion) -> {
ApplicationInfo appInfo = new ApplicationInfo();
appInfo.packageName = packageName1;
appInfo.targetSdkVersion = targetSdkVersion;
return mPackageParserCallback.isChangeEnabled(changeId,
appInfo);
}).reset(),
origin.file, 0);
if (result.isError()) {
Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(),
result.getException());
} else {
packageName = result.getResult().packageName;
}
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) {
mRet = mArgs.copyApk();
}
processPendingInstall(mArgs, mRet);
}
}
校驗(yàn)完成形帮,由InstallArgs發(fā)起apk copy操作。之前在初始化的時(shí)候會(huì)根據(jù)是否已經(jīng)安裝了當(dāng)前應(yīng)用來初始化不同的實(shí)現(xiàn)類:
private InstallArgs createInstallArgs(InstallParams params) {
if (params.move != null) {
//處理已安裝的應(yīng)用程序
return new MoveInstallArgs(params);
} else {
//處理新安裝的應(yīng)用程序
return new FileInstallArgs(params);
}
}
而后續(xù)發(fā)起的copyApk流程最終結(jié)果是將apk和lib copy到確認(rèn)的安裝目錄下
void handleReturnCode() {
...
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
mRet = mArgs.copyApk();
}
processPendingInstall(mArgs, mRet);
}
}
/data/app/com.miui.packageinstaller-Qp2hRWM-6O9lWcKH-GT-dw== # ls -al
-rw-r--r-- 1 system system 6385298 2021-04-28 07:44 base.apk. //apk
drwxr-xr-x 3 system system 4096 2021-04-28 07:44 lib //native lib
整個(gè)流程粗略看起來比較簡(jiǎn)單周叮,但是其中有幾個(gè)細(xì)節(jié)值得深挖一下:確定推薦安裝位置辩撑、包完整性校驗(yàn)。這個(gè)后續(xù)有時(shí)間再單獨(dú)分析仿耽。
二合冀、安裝apk流程解析
handleReturnCode最終執(zhí)行processPendingInstall發(fā)起安裝:
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
if (args.mMultiPackageInstallParams != null) {
args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
} else {
PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
processInstallRequestsAsync(
res.returnCode == PackageManager.INSTALL_SUCCEEDED,
Collections.singletonList(new InstallRequest(args, res)));
}
}
多包和單包安裝,最終都會(huì)走到processInstallRequestsAsync方法
private void processInstallRequestsAsync(boolean success,
List<InstallRequest> installRequests) {
mHandler.post(() -> {
if (success) {
for (InstallRequest request : installRequests) {
//安裝前處理
request.args.doPreInstall(request.installResult.returnCode);
}
synchronized (mInstallLock) {
//發(fā)起安裝
installPackagesTracedLI(installRequests);
}
for (InstallRequest request : installRequests) {
//安裝后處理
request.args.doPostInstall(
request.installResult.returnCode, request.installResult.uid);
}
}
for (InstallRequest request : installRequests) {
restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
new PostInstallData(request.args, request.installResult, null));
}
});
}
這里分了三步:對(duì)安裝前项贺、中君躺、后分別做了處理。這里args對(duì)應(yīng)的是FileInstallArgs开缎。
2.1 安裝前后處理工作
FileInstallArgs
int doPreInstall(int status) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
cleanUp();
}
return status;
}
int doPostInstall(int status, int uid) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
cleanUp();
}
return status;
}
安裝前后棕叫,都會(huì)判斷是否安裝成功,如果不成功啥箭,走相同清理流程谍珊。clearup就是對(duì)安裝相關(guān)目錄文件進(jìn)行清理。
2.2 發(fā)起安裝流程
installPackagesTracedLI直接調(diào)用installPackagesLI來處理安裝:
/**
* Installs one or more packages atomically. This operation is broken up into four phases:
* <ul>
* <li><b>Prepare</b>
* <br/>Analyzes any current install state, parses the package and does initial
* validation on it.</li>
* <li><b>Scan</b>
* <br/>Interrogates the parsed packages given the context collected in prepare.</li>
* <li><b>Reconcile</b>
* <br/>Validates scanned packages in the context of each other and the current system
* state to ensure that the install will be successful.
* <li><b>Commit</b>
* <br/>Commits all scanned packages and updates system state. This is the only place
* that system state may be modified in the install flow and all predictable errors
* must be determined before this phase.</li>
* </ul>
*
* Failure at any phase will result in a full failure to install all packages.
*/
@GuardedBy("mInstallLock")
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 {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
for (InstallRequest request : requests) {
// TODO(b/109941548): remove this once we've pulled everything from it and into
// scan, reconcile or commit.
final PrepareResult prepareResult;
// 1.prepare
prepareResult =
preparePackageLI(request.args, request.installResult);
...
// 2.scan
final ScanResult result = scanPackageTracedLI(
prepareResult.packageToScan, prepareResult.parseFlags,
prepareResult.scanFlags, System.currentTimeMillis(),
request.args.user, request.args.abiOverride);
...
ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
installResults,
prepareResults,
mSharedLibraries,
Collections.unmodifiableMap(mPackages), versionInfos,
lastStaticSharedLibSettings);
CommitRequest commitRequest = null;
synchronized (mLock) {
Map<String, ReconciledPackage> reconciledPackages;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages”);
// 3.reconcile
reconciledPackages = reconcilePackagesLocked(
reconcileRequest, mSettings.mKeySetManagerService);
...
commitRequest = new CommitRequest(reconciledPackages,
mUserManager.getUserIds());
// 4.commit
commitPackagesLocked(commitRequest);
success = true;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
//5.執(zhí)行應(yīng)用程序安裝
executePostCommitSteps(commitRequest);
...
}
主要工作分四個(gè)階段:
- prepare: 解析apk急侥。
- scan: 掃描apk砌滞,更新共享庫(kù)和settings信息。
- reconcile:驗(yàn)證掃描包狀態(tài)以確保安裝成功坏怪。
- commit:提交所有掃描的包并更新系統(tǒng)狀態(tài)贝润。
這里后面會(huì)分別來進(jìn)行分析。
最后:executePostCommitSteps 執(zhí)行安裝后的掃尾工作
/**
* On successful install, executes remaining steps after commit completes and the package lock
* is released. These are typically more expensive or require calls to installd, which often
* locks on {@link #mLock}.
*/
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 boolean onIncremental = mIncrementalManager != null
&& isIncrementalPath(pkg.getCodePath());
…
//createAppData
prepareAppDataAfterInstallLIF(pkg);
…
//dex2oat編譯
mPackageDexOptimizer.performDexOpt(pkg, realPkgSetting,
null /* instructionSets */,
getOrCreateCompilerPackageStats(pkg),
mDexManager.getPackageUseInfoOrDefault(packageName),
dexoptOptions);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
// Notify BackgroundDexOptService that the package has been changed.
// If this is an update of a package which used to fail to compile,
// BackgroundDexOptService will remove it from its denylist.
// TODO: Layering violation
BackgroundDexOptService.notifyPackageChanged(packageName);
notifyPackageChangeObserversOnUpdate(reconciledPkg);
}
NativeLibraryHelper.waitForNativeBinariesExtraction(incrementalStorages);
}
這里主要是通過installd干兩件事:createAppData铝宵、dex2oat 編譯