apk的安裝有多種方式(系統(tǒng)、adb、應(yīng)用商店、第三方)。這里我們?nèi)∮寐窂阶铋L(zhǎng)的一種安裝方式(第三方安裝)進(jìn)行分析,先上一個(gè)整個(gè)流程的時(shí)序圖。

注意:本文是關(guān)于整個(gè)安裝流程的詳細(xì)調(diào)用鏈,文章較長(zhǎng)涉及代碼較多,適合源碼探索,androidstudio導(dǎo)入系統(tǒng)源碼
,需要可自取
第三方安裝調(diào)用
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
context.startActivity(intent);
這里就不用去區(qū)分7.0之前和之后,uri都代表了文件地址
安裝器AndroidManifest
路徑:frameworks/base/packages/PackageInstaller/AndroidManifest.xml
這里將安裝過(guò)程要用到的所有組件都列出來(lái)
<application >
//意圖接收頁(yè)面
<activity android:name=".InstallStart"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:exported="true"
android:excludeFromRecents="true">
<intent-filter android:priority="1">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
<data android:mimeType="application/vnd.android.package-archive" />
</intent-filter>
<intent-filter android:priority="1">
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="package" />
<data android:scheme="content" />
</intent-filter>
<intent-filter android:priority="1">
<action android:name="android.content.pm.action.CONFIRM_INSTALL" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
//中轉(zhuǎn)頁(yè)面,目的是將不同形式的文件路徑,轉(zhuǎn)為系統(tǒng)temp目錄下等待安裝
<activity android:name=".InstallStaging"
android:exported="false" />
//中轉(zhuǎn)頁(yè)面,安裝成功后刪除上面temp目錄下的安裝包
<activity android:name=".DeleteStagedFileOnResult"
android:theme="@style/Theme.AlertDialogActivity.NoActionBar"
android:exported="false" />
//包信息展示頁(yè)面,有icon、應(yīng)用名稱、安裝/取消按鈕的那個(gè)頁(yè)面
<activity android:name=".PackageInstallerActivity"
android:exported="false" />
//安裝進(jìn)程中頁(yè)面
<activity android:name=".InstallInstalling"
android:theme="@style/Theme.AlertDialogActivity.NoAnimation"
android:exported="false" />
//安裝session結(jié)果接受廣播
<receiver android:name=".InstallEventReceiver"
android:permission="android.permission.INSTALL_PACKAGES"
android:exported="false">
<intent-filter android:priority="1">
<action android:name="com.android.packageinstaller.ACTION_INSTALL_COMMIT" />
</intent-filter>
</receiver>
//安裝成功狀態(tài)展示頁(yè)面
<activity android:name=".InstallSuccess"
android:theme="@style/Theme.AlertDialogActivity.NoAnimation"
android:exported="false" />
//安裝失敗狀態(tài)展示頁(yè)面
<activity android:name=".InstallFailed"
android:theme="@style/Theme.AlertDialogActivity.NoAnimation"
android:exported="false" />
...
</application>
InstallStart
路徑:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallStart.java
根據(jù)意圖跳轉(zhuǎn)至InstallStart中
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
//是否是session安裝
final boolean isSessionInstall =
PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction());
....
Intent nextActivity = new Intent(intent);
nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
| Intent.FLAG_GRANT_READ_URI_PERMISSION);
// The the installation source as the nextActivity thinks this activity is the source, hence
// set the originating UID and sourceInfo explicitly
nextActivity.putExtra(PackageInstallerActivity.EXTRA_CALLING_PACKAGE, callingPackage);
nextActivity.putExtra(PackageInstallerActivity.EXTRA_CALLING_ATTRIBUTION_TAG,
callingAttributionTag);
nextActivity.putExtra(PackageInstallerActivity.EXTRA_ORIGINAL_SOURCE_INFO, sourceInfo);
nextActivity.putExtra(Intent.EXTRA_ORIGINATING_UID, originatingUid);
//根據(jù)前面獲取到的狀態(tài),跳轉(zhuǎn)不同的頁(yè)面
if (isSessionInstall) {
nextActivity.setClass(this, PackageInstallerActivity.class);
} else {
Uri packageUri = intent.getData();
if (packageUri != null && packageUri.getScheme().equals(
ContentResolver.SCHEME_CONTENT)) {
// 更注冊(cè)的意圖,可知第三方安裝滿足這個(gè)條件
nextActivity.setClass(this, InstallStaging.class);
} else if (packageUri != null && packageUri.getScheme().equals(
PackageInstallerActivity.SCHEME_PACKAGE)) {
nextActivity.setClass(this, PackageInstallerActivity.class);
} else {
Intent result = new Intent();
result.putExtra(Intent.EXTRA_INSTALL_RESULT,
PackageManager.INSTALL_FAILED_INVALID_URI);
setResult(RESULT_FIRST_USER, result);
nextActivity = null;
}
}
if (nextActivity != null) {
startActivity(nextActivity);
}
finish();
}
InstallStaging
路徑:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallStaging.java
中轉(zhuǎn)頁(yè)面,將意圖中提供的uri文件,拷貝至目錄(/data/user/0/com.android.packageinstaller/no_backup/packagexxx.apk)下
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//設(shè)置取消按鈕
mAlert.setIcon(R.drawable.ic_file_download);
mAlert.setTitle(getString(R.string.app_name_unknown));
mAlert.setView(R.layout.install_content_view);
mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
(ignored, ignored2) -> {
if (mStagingTask != null) {
mStagingTask.cancel(true);
}
setResult(RESULT_CANCELED);
finish();
}, null);
setupAlert();
requireViewById(R.id.staging).setVisibility(View.VISIBLE);
if (savedInstanceState != null) {
mStagedFile = new File(savedInstanceState.getString(STAGED_FILE));
if (!mStagedFile.exists()) {
mStagedFile = null;
}
}
}
//文件存在,異步拷貝
protected void onResume() {
super.onResume();
// This is the first onResume in a single life of the activity
if (mStagingTask == null) {
// File does not exist, or became invalid
if (mStagedFile == null) {
// Create file delayed to be able to show error
try {
mStagedFile = TemporaryFileManager.getStagedFile(this);
} catch (IOException e) {
showError();
return;
}
}
mStagingTask = new StagingAsyncTask();
mStagingTask.execute(getIntent().getData());
}
}
private final class StagingAsyncTask extends AsyncTask<Uri, Void, Boolean> {
@Override
protected Boolean doInBackground(Uri... params) {
if (params == null || params.length <= 0) {
return false;
}
//apk包拷貝至/data/user/0/com.android.packageinstaller/no_backup/packagexxx.apk
Uri packageUri = params[0];
try (InputStream in = getContentResolver().openInputStream(packageUri)) {
// Despite the comments in ContentResolver#openInputStream the returned stream can
// be null.
if (in == null) {
return false;
}
try (OutputStream out = new FileOutputStream(mStagedFile)) {
byte[] buffer = new byte[1024 * 1024];
int bytesRead;
while ((bytesRead = in.read(buffer)) >= 0) {
// Be nice and respond to a cancellation
if (isCancelled()) {
return false;
}
out.write(buffer, 0, bytesRead);
}
}
} catch (IOException | SecurityException | IllegalStateException e) {
Log.w(LOG_TAG, "Error staging apk from content URI", e);
return false;
}
return true;
}
@Override
protected void onPostExecute(Boolean success) {
// Now start the installation again from a file
Intent installIntent = new Intent(getIntent());
installIntent.setClass(InstallStaging.this, DeleteStagedFileOnResult.class);
installIntent.setData(Uri.fromFile(mStagedFile));
...
//拷貝完成,跳轉(zhuǎn)至刪除中轉(zhuǎn)Activity
startActivity(installIntent);
InstallStaging.this.finish();
}
}
DeleteStagedFileOnResult
路徑:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\DeleteStagedFileOnResult.java
刪除中轉(zhuǎn)頁(yè)面,安裝成功后刪除上面拷貝的安裝包
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
Intent installIntent = new Intent(getIntent());
installIntent.setClass(this, PackageInstallerActivity.class);
installIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
//跳轉(zhuǎn)至應(yīng)用安裝詳情頁(yè)面
startActivityForResult(installIntent, 0);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
setResult(resultCode, data);
finish();
}
//安裝流程結(jié)束,同時(shí)也刪除中轉(zhuǎn)的包
@Override
protected void onDestroy() {
super.onDestroy();
//刪除安裝包
if (isFinishing()) {
File sourceFile = new File(getIntent().getData().getPath());
new Thread(sourceFile::delete).start();
}
}
PackageInstallerActivity
路徑:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\PackageInstallerActivity.java
安裝確認(rèn)界面,也是應(yīng)用寶信息展示頁(yè)面,也是廠商廣告展示頁(yè)面?
protected void onCreate(Bundle icicle) {
...
//解析url,獲取應(yīng)用信息
boolean wasSetUp = processPackageUri(packageUri);
...
}
protected void onResume() {
super.onResume();
if (mLocalLOGV) Log.i(TAG, "onResume(): mAppSnippet=" + mAppSnippet);
if (mAppSnippet != null) {
//用獲取的應(yīng)用信息,填充頁(yè)面(icon,名稱,版本,權(quán)限等)
bindUi();
//檢查發(fā)起程序是否有第三方應(yīng)用安裝權(quán)限
checkIfAllowedAndInitiateInstall();
}
if (mOk != null) {
//還不允許點(diǎn)擊安裝按鈕
mOk.setEnabled(mEnableOk);
}
}
private void bindUi() {
...
mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.install),
(ignored, ignored2) -> {
if (mOk.isEnabled()) {
if (mSessionId != -1) {
mInstaller.setPermissionsResult(mSessionId, true);
finish();
} else {
//點(diǎn)擊安裝按鈕
startInstall();
}
}
}, null);
...
mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
mOk.setEnabled(false);
...
}
private void startInstall() {
Intent newIntent = new Intent();
newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
mPkgInfo.applicationInfo);
newIntent.setData(mPackageURI);
newIntent.setClass(this, InstallInstalling.class);
...
//點(diǎn)擊安裝按鈕后,跳轉(zhuǎn)至正在安裝頁(yè)面
startActivity(newIntent);
finish();
}
checkIfAllowedAndInitiateInstall:方法會(huì)去檢查發(fā)起安裝的應(yīng)用,是否有第三方安裝權(quán)限,沒(méi)有就彈出請(qǐng)求彈窗,然后跳轉(zhuǎn)至設(shè)置界面。根據(jù)授權(quán)結(jié)果,在onActivityResult更改安裝按鈕狀態(tài)
InstallInstalling
路徑:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallInstalling.java
安裝中頁(yè)面,在onCreate中初始化loading動(dòng)畫(huà)和取消按鈕
protected void onCreate(@Nullable Bundle savedInstanceState) {
...
//在安裝結(jié)束的廣播中添加監(jiān)聽(tīng),launchFinishBasedOnResult中根據(jù)狀態(tài)碼跳轉(zhuǎn)成功/失敗頁(yè)面
mInstallId = InstallEventReceiver.addObserver(this, EventResultPersister.GENERATE_NEW_ID,
this::launchFinishBasedOnResult);
...
//創(chuàng)建Session
mSessionId = getPackageManager().getPackageInstaller().createSession(params);
...
}
protected void onResume() {
super.onResume();
if (mInstallingTask == null) {
PackageInstaller installer = getPackageManager().getPackageInstaller();
//取出Seesion
PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);
//判斷Session活躍狀態(tài)
if (sessionInfo != null && !sessionInfo.isActive()) {
//未開(kāi)始安裝,進(jìn)行下一步安裝
mInstallingTask = new InstallingAsyncTask();
mInstallingTask.execute();
} else {
//正在安裝,等待安裝完成
mCancelButton.setEnabled(false);
setFinishOnTouchOutside(false);
}
}
}
private final class InstallingAsyncTask extends AsyncTask<Void, Void,
PackageInstaller.Session> {
volatile boolean isDone;
@Override
protected PackageInstaller.Session doInBackground(Void... params) {
PackageInstaller.Session session;
try {
//打開(kāi)Session
session = getPackageManager().getPackageInstaller().openSession(mSessionId);
} catch (IOException e) {
synchronized (this) {
isDone = true;
notifyAll();
}
return null;
}
//設(shè)置寫(xiě)入進(jìn)度
session.setStagingProgress(0);
try {
File file = new File(mPackageURI.getPath());
try (InputStream in = new FileInputStream(file)) {
long sizeBytes = file.length();
//設(shè)置文件大小,優(yōu)化寫(xiě)入磁盤(pán)操作
try (OutputStream out = session
.openWrite("PackageInstaller", 0, sizeBytes)) {
byte[] buffer = new byte[1024 * 1024];
while (true) {
int numRead = in.read(buffer);
if (numRead == -1) {
//更新到磁盤(pán)
session.fsync(out);
break;
}
if (isCancelled()) {
session.close();
break;
}
//寫(xiě)入數(shù)據(jù)
out.write(buffer, 0, numRead);
if (sizeBytes > 0) {
float fraction = ((float) numRead / (float) sizeBytes);
//設(shè)置進(jìn)度
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) {
//BROADCAST_ACTION的值為:com.android.packageinstaller.ACTION_INSTALL_COMMIT
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提交IntentSender,用于完成后發(fā)送完成的廣播
session.commit(pendingIntent.getIntentSender());
//取消按鈕設(shè)置為不可點(diǎn)擊
mCancelButton.setEnabled(false);
setFinishOnTouchOutside(false);
} else {
getPackageManager().getPackageInstaller().abandonSession(mSessionId);
if (!isCancelled()) {
launchFailure(PackageInstaller.STATUS_FAILURE,
PackageManager.INSTALL_FAILED_INVALID_APK, null);
}
}
}
}
- 給安裝結(jié)束的廣播中添加監(jiān)聽(tīng)
- 創(chuàng)建
Session - 通過(guò)
Session將安裝包寫(xiě)入磁盤(pán) -
Session提交具有發(fā)送安裝結(jié)束功能的IntentSender
PackageInstallerSession
路徑:frameworks\base\services\core\java\com\android\server\pm\PackageInstallerSession.java
PackageInstaller.Session.commit方法最終遠(yuǎn)程調(diào)用到了PackageInstallerSession.commit方法
@Override
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
if (hasParentSessionId()) {
throw new IllegalStateException(
"Session " + sessionId + " is a child of multi-package session "
+ getParentSessionId() + " and may not be committed directly.");
}
//標(biāo)識(shí)請(qǐng)求,同時(shí)記錄statusReceiver,用于發(fā)送安裝結(jié)果
if (!markAsSealed(statusReceiver, forTransfer)) {
return;
}
if (isMultiPackage()) {
//多包安裝
}
dispatchSessionSealed();
}
private void dispatchSessionSealed() {
mHandler.obtainMessage(MSG_ON_SESSION_SEALED).sendToTarget();
}
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_ON_SESSION_SEALED:
handleSessionSealed();
break;
case MSG_STREAM_VALIDATE_AND_COMMIT:
handleStreamValidateAndCommit();
break;
case MSG_INSTALL:
handleInstall();
break;
}
}
private void handleSessionSealed() {
...
dispatchStreamValidateAndCommit();
}
private void dispatchStreamValidateAndCommit() {
mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();
}
private void handleStreamValidateAndCommit() {
...
mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
}
private void handleInstall() {
//apex安裝這種大多數(shù)用于系統(tǒng)安裝
if (isApexSession()) {
...
}
//分階段安裝,一般需要重啟后會(huì)進(jìn)行后面的安裝步驟
if (params.isStaged) {
}
verify();
}
private void verify() {
verifyNonStaged();
}
private void verifyNonStaged()
throws PackageManagerException {
//創(chuàng)建驗(yàn)證參數(shù)
final PackageManagerService.VerificationParams verifyingSession =
prepareForVerification();
...
mPm.verifyStage(verifyingSession);
}
private PackageManagerService.VerificationParams prepareForVerification()
throws PackageManagerException {
....
synchronized (mLock) {
return makeVerificationParamsLocked();
}
}
private PackageManagerService.VerificationParams makeVerificationParamsLocked() {
final IPackageInstallObserver2 localObserver;
if (!hasParentSessionId()) {
//添加驗(yàn)證回調(diào)
localObserver = new IPackageInstallObserver2.Stub() {
@Override
public void onUserActionRequired(Intent intent) {
throw new IllegalStateException();
}
@Override
public void onPackageInstalled(String basePackageName, int returnCode, String msg,
Bundle extras) {
if (returnCode == INSTALL_SUCCEEDED) {
onVerificationComplete();
} else {
onSessionVerificationFailure(returnCode, msg);
}
}
};
...
return mPm.new VerificationParams(user, stageDir, localObserver, copiedParams,
mInstallSource, mInstallerUid, mSigningDetails, sessionId, mPackageLite);
}
- 記錄提交過(guò)來(lái)的
IntentSender用于后面發(fā)送廣播 - 創(chuàng)建驗(yàn)證回調(diào),并在創(chuàng)建驗(yàn)證參數(shù)是傳入
PackageManagerService
路徑:frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java
調(diào)用了pms的verifyStage方法
void verifyStage(VerificationParams params) {
mHandler.post(()-> {
params.startCopy();
});
}
VerificationParams
路徑:frameworks\base\services\core\java\com\android\server\pm\PackageManagerService$VerificationParams.java
調(diào)用的是VerificationParams對(duì)象的startCopy()方法,VerificationParams對(duì)象繼承了HandlerParams,并未重寫(xiě)startCopy()方法
final void startCopy() {
handleStartCopy();
handleReturnCode();
}
public void handleStartCopy() {
//獲取包信息
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);
//驗(yàn)證versioncode是否合法(降級(jí)等)
mRet = verifyReplacingVersionCode(pkgLite, requiredInstalledVersionCode, installFlags);
if (mRet != INSTALL_SUCCEEDED) {
return;
}
...
}
void handleReturnCode() {
if (mWaitForVerificationToComplete || mWaitForIntegrityVerificationToComplete
|| mWaitForEnableRollbackToComplete) {
return;
}
sendVerificationCompleteNotification();
}
private void sendVerificationCompleteNotification() {
//調(diào)用前面設(shè)置的回調(diào)
observer.onPackageInstalled(null, mRet, "Package Verification Result",
new Bundle());
}
PackageInstallerSession
驗(yàn)證回調(diào)中調(diào)用onVerificationComplete()方法
private void onVerificationComplete() {
...
install();
}
private void install() {
installNonStaged();
}
private void installNonStaged()
throws PackageManagerException {
//創(chuàng)建安裝參數(shù)
final PackageManagerService.InstallParams installingSession = makeInstallParams();
...
//開(kāi)始安裝
mPm.installStage(installingSession);
}
private PackageManagerService.InstallParams makeInstallParams()
throws PackageManagerException {
//創(chuàng)建安裝監(jiān)聽(tīng)
final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
@Override
public void onUserActionRequired(Intent intent) {
throw new IllegalStateException();
}
@Override
public void onPackageInstalled(String basePackageName, int returnCode, String msg,
Bundle extras) {
if (isStaged()) {
sendUpdateToRemoteStatusReceiver(returnCode, msg, extras);
} else {
//不是分段安裝,安裝成功后會(huì)回調(diào)這里
destroyInternal();
dispatchSessionFinished(returnCode, msg, extras);
}
}
};
.....
synchronized (mLock) {
return mPm.new InstallParams(stageDir, localObserver, params, mInstallSource, user,
mSigningDetails, mInstallerUid, mPackageLite);
}
}
調(diào)用makeInstallParams方法創(chuàng)建安裝參數(shù),并添加IPackageInstallObserver2監(jiān)聽(tīng)
當(dāng)安裝成功后會(huì)調(diào)用onPackageInstalled方法,returnCode為安裝狀態(tài)碼。后面會(huì)分析dispatchSessionFinished方法。
PackageManagerService
void installStage(InstallParams params) {
final Message msg = mHandler.obtainMessage(INIT_COPY);
...
mHandler.sendMessage(msg);
}
class PackageHandler extends Handler {
...
public void handleMessage(Message msg) {
try {
doHandleMessage(msg);
} finally {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
}
}
void doHandleMessage(Message msg) {
switch (msg.what) {
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");
執(zhí)行InstallParams.startCopy()方法
params.startCopy();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
break;
}
case POST_INSTALL: {
...
//安裝成功后發(fā)送消息
handlePackagePostInstall(parentRes, killApp, virtualPreload,
didRestore, args.installSource.installerPackageName, args.observer,
args.mDataLoaderType);
...
} break;
}
}
InstallParams
路徑:frameworks\base\services\core\java\com\android\server\pm\PackageManagerService$InstallParams.java
InstallParams類真正執(zhí)行了將apk安裝到系統(tǒng)的操作
final void startCopy() {
handleStartCopy();
handleReturnCode();
}
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;
//這里是分段安裝的再次驗(yàn)證,第三方安裝流程不會(huì)走這里
if (isStaged) {
mRet = verifyReplacingVersionCode(
pkgLite, requiredInstalledVersionCode, installFlags);
if (mRet != INSTALL_SUCCEEDED) {
return;
}
}
//獲取覆蓋安裝的位置
mRet = overrideInstallLocation(pkgLite);
}
void handleReturnCode() {
processPendingInstall();
}
private void processPendingInstall() {
InstallArgs args = createInstallArgs(this);
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
//拷貝安裝包和動(dòng)態(tài)鏈接庫(kù)
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);
//異步執(zhí)行解析、系統(tǒng)配置寫(xiě)入等操作
processInstallRequestsAsync(
res.returnCode == PackageManager.INSTALL_SUCCEEDED,
Collections.singletonList(new InstallRequest(args, res)));
}
}
private void processInstallRequestsAsync(boolean success,
List<InstallRequest> installRequests) {
...
if (success) {
for (InstallRequest request : apkInstallRequests) {
//清理安裝目錄,因?yàn)榘惭b失敗等原因,造成的無(wú)用文件,在這一步清理
request.args.doPreInstall(request.installResult.returnCode);
}
synchronized (mInstallLock) {
//解析包、驗(yàn)證包、提交到系統(tǒng)
installPackagesTracedLI(apkInstallRequests);
}
for (InstallRequest request : apkInstallRequests) {
//清理安裝過(guò)程造成的無(wú)用文件,和doPreInstall作用是一樣的
request.args.doPostInstall(
request.installResult.returnCode, request.installResult.uid);
}
}
for (InstallRequest request : apkInstallRequests) {
//發(fā)送廣播,通知系統(tǒng)更換或者添加icon、通知安裝應(yīng)用、通知監(jiān)聽(tīng)安裝事件的其他廣播等
//如果安裝失敗進(jìn)行回滾
restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
new PostInstallData(request.args, request.installResult, null));
}
});
private void installPackagesTracedLI(List<InstallRequest> requests) {
installPackagesLI(requests);
}
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) {
...
//1.準(zhǔn)備:分析當(dāng)前安裝狀態(tài),解析包并初始驗(yàn)證
prepareResult =
preparePackageLI(request.args, request.installResult);
...
//2.掃描:根據(jù)準(zhǔn)備階段解析的包信息上下文 進(jìn)一步解析
final ScanResult result = scanPackageTracedLI(
prepareResult.packageToScan, prepareResult.parseFlags,
prepareResult.scanFlags, System.currentTimeMillis(),
request.args.user, request.args.abiOverride);
//注冊(cè)appId
createdAppId.put(packageName, optimisticallyRegisterAppId(result));
//保存version信息
versionInfos.put(result.pkgSetting.pkg.getPackageName(),
getSettingsVersionForPackage(result.pkgSetting.pkg));
..
//3.核對(duì):驗(yàn)證掃描后的包信息和系統(tǒng)狀態(tài),確保安裝成功
reconciledPackages = reconcilePackagesLocked(
reconcileRequest, mSettings.getKeySetManagerService(), mInjector);
...
//4.提交:提交掃描的包、更新系統(tǒng)狀態(tài)。這是唯一可以修改系統(tǒng)狀態(tài)的地方,并且要對(duì)所有可預(yù)測(cè)的錯(cuò)誤進(jìn)行檢測(cè)。
commitRequest = new CommitRequest(reconciledPackages,
mUserManager.getUserIds());
commitPackagesLocked(commitRequest);
//安裝后續(xù),準(zhǔn)備App數(shù)據(jù)、編譯布局資源、執(zhí)行dexopt
executePostCommitSteps(commitRequest);
}
}
private void executePostCommitSteps(CommitRequest commitRequest) {
final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>();
for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
...
//準(zhǔn)備app目錄(/data/user/用戶ID/包名/code_cache)
prepareAppDataAfterInstallLIF(pkg);
...
//準(zhǔn)備應(yīng)用配置文件
mArtManagerService.prepareAppProfiles(
pkg,
resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()),
/* updateReferenceProfileContent= */ true);
...
//dexopt操作
mPackageDexOptimizer.performDexOpt(pkg, realPkgSetting,
null /* instructionSets */,
getOrCreateCompilerPackageStats(pkg),
mDexManager.getPackageUseInfoOrDefault(packageName),
dexoptOptions);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
...
}
}
將包拷貝到data/app目錄下后執(zhí)行了4個(gè)關(guān)鍵的操作:
-
準(zhǔn)備:分析當(dāng)前安裝狀態(tài),解析包并初始驗(yàn)證
- 對(duì)apk的
AndroidManifest.xml文件做了全面的解析,比如apk中的所有 -
activity、service、permission等信息,并將解析結(jié)果保存在了PackageParser.Package類里 - 通過(guò)
Dm-verity校驗(yàn)dex文件的有效性 - 解析apk簽名信息
- 解析android資源索引表
resources.arsc文件。
- 對(duì)apk的
- 掃描:根據(jù)準(zhǔn)備階段解析的包信息上下文 進(jìn)一步解析
- 核對(duì):驗(yàn)證掃描后的包信息和系統(tǒng)狀態(tài),確保安裝成功
- 提交:提交掃描的包、更新系統(tǒng)狀態(tài)。這是唯一可以修改系統(tǒng)狀態(tài)的地方,并且要對(duì)所有可預(yù)測(cè)的錯(cuò)誤進(jìn)行檢測(cè)。
安裝完成后,會(huì)進(jìn)行后續(xù)的步驟:
- 準(zhǔn)備App data目錄,如果已經(jīng)存在則對(duì)目錄進(jìn)行校驗(yàn)
- 準(zhǔn)備應(yīng)用配置文件
- 對(duì)dex進(jìn)行
dexopt操作
下圖附一張不同版本dexopt區(qū)別

返回到上面的processInstallRequestsAsync()方法中,進(jìn)行安裝完成后的后續(xù)處理restoreAndPostInstall方法
PackageManagerService
private void restoreAndPostInstall(
int userId, PackageInstalledInfo res, @Nullable PostInstallData data) {
if (DEBUG_INSTALL) {
Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package=" + res.pkg);
}
//是否更新標(biāo)識(shí)
final boolean update = res.removedInfo != null
&& res.removedInfo.removedPackage != null;
//是否回滾
boolean doRestore = !update && res.pkg != null;
...
//安裝成功,并且需要回滾
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
if (res.freezer != null) {
res.freezer.close();
}
doRestore = performBackupManagerRestore(userId, token, res);
}
//更新應(yīng)用,做數(shù)據(jù)回滾
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) {
doRestore = performRollbackManagerRestore(userId, token, res, data);
}
//不回滾發(fā)送消息進(jìn)行后面的操作
if (!doRestore) {
// No restore possible, or the Backup Manager was mysteriously not
// available -- just fire the post-install work request directly.
if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
//這個(gè)消息最終會(huì)調(diào)用handlePackagePostInstall方法
Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
mHandler.sendMessage(msg);
}
}
private void handlePackagePostInstall(PackageInstalledInfo res, boolean killApp,
boolean virtualPreload, boolean launchedForRestore, String installerPackage,
IPackageInstallObserver2 installObserver, int dataLoaderType) {
...
//發(fā)送消息更新桌面icon
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
updateUserIds, instantUserIds, newBroadcastAllowList, null);
//通知上面InstallParams對(duì)象中注冊(cè)的監(jiān)聽(tīng)對(duì)象
notifyInstallObserver(res, installObserver);
}
PackageInstallerSession
private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
sendUpdateToRemoteStatusReceiver(returnCode, msg, extras);
...
}
private void sendUpdateToRemoteStatusReceiver(int returnCode, String msg, Bundle extras) {
...
//最終調(diào)用了sendOnPackageInstalled方法
mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget();
}
private static void sendOnPackageInstalled(Context context, IntentSender target, int sessionId,
boolean showNotification, int userId, String basePackageName, int returnCode,
String msg, Bundle extras) {
...
//target對(duì)象為commit提交的IntentSender對(duì)象。
target.sendIntent(context, 0, fillIn, null, null);
}
使用IntentSender對(duì)象發(fā)送action(com.android.packageinstaller.ACTION_INSTALL_COMMIT)廣播,根據(jù)上面AndroidManifest.xml中注冊(cè)的BroadcastReceiver,最終InstallEventReceiver會(huì)收到廣播
PackageInstallerSession
路徑:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallEventReceiver.java
public class InstallEventReceiver extends BroadcastReceiver {
...
@Override
public void onReceive(Context context, Intent intent) {
getReceiver(context).onEventReceived(context, intent);
}
...
}
InstallEventReceiver的onReceive中執(zhí)行了EventResultPersister.onEventReceivedf方法,最終回調(diào)InstallInstalling.launchFinishBasedOnResult方法,launchFinishBasedOnResult方法又根據(jù)安裝狀態(tài)碼展示成功或者失敗頁(yè)面。