本文轉(zhuǎn)載自:Android PackageManagerService總結(jié)(四) APK安裝流程
本文基于Android 10源碼分析
前言
??PackageManagerService(簡稱PKMS),是Android系統(tǒng)中核心服務(wù)之一,管理著所有與package相關(guān)的工作,常見的比如安裝桦山、卸載應(yīng)用, 信息查詢等工作馍资,主要完成以下核心功能:
解析AndroidManifest.xml清單文件咪辱,解析清單文件中的所有節(jié)點信息员凝;
掃描本地文件响鹃,主要針對apk依啰,主要是系統(tǒng)應(yīng)用乎串、本地安裝應(yīng)用等;
管理本地apk孔飒,主要包括安裝灌闺、刪除等等;
管理設(shè)備上安裝的所有應(yīng)用程序坏瞄,并在系統(tǒng)啟動時加載應(yīng)用程序桂对;
根據(jù)請求的Intent匹配到對應(yīng)的Activity、Provider鸠匀、Service蕉斜,提供包含包名和Component的信息對象;
調(diào)用需要權(quán)限的系統(tǒng)函數(shù)時缀棍,檢查程序是否具備相應(yīng)權(quán)限從而保證系統(tǒng)安全宅此;
提供應(yīng)用程序的安裝、卸載的接口爬范。
??本篇文章重點介紹一下apk安裝流程父腕。
1.安裝apk的方式
??Android應(yīng)用安裝有如下四種方式:
系統(tǒng)應(yīng)用和預(yù)制應(yīng)用安裝――開機時完成,沒有安裝界面青瀑,在PKMS的構(gòu)造函數(shù)中完成安裝璧亮;
網(wǎng)絡(luò)下載應(yīng)用安裝――通過應(yīng)用商店應(yīng)用完成萧诫,調(diào)用PackageManager.installPackages(),有安裝界面枝嘶;
ADB工具安裝――沒有安裝界面帘饶,它通過啟動pm腳本的形式,然后調(diào)用com.android.commands.pm.Pm類群扶,之后調(diào)用到PKMS.installStage()完成安裝及刻;
第三方應(yīng)用安裝――通過SD卡里的APK文件安裝,有安裝界面竞阐,由packageinstaller.apk應(yīng)用處理安裝及卸載過程的界面缴饭。
??上述幾種方式均通過PackageInstallObserver來監(jiān)聽安裝是否成功。
2.apk文件結(jié)構(gòu)
??生成的APK文件本質(zhì)還是一個zip文件馁菜,只不過被Google強行修改了一下后綴名稱而已茴扁。所以我們將APK的后綴修改成.zip就可以查看其包含的內(nèi)容了铃岔。
(1)主要由7部分組成 (下圖來源于其他作者博客: Android apk結(jié)構(gòu)分析)
(2)META-INF目錄下3個重要文件
(3)res目錄下的文件說明
(4)細節(jié)說明
META-INF:關(guān)于簽名的信息存放汪疮,應(yīng)用安裝驗證簽名的時候會驗證該文件里面的信息,里面的資源文件毁习,是被編譯過的智嚷。raw和圖片是保持原樣的,但是其他的文件會被編譯成二進制文件纺且;
res: 這里面的資源是不經(jīng)過編譯原樣打包進來的盏道;
AndroidManifest.xml:程序全局配置文件,該文件是每個應(yīng)用程序都必須定義和包含的文件载碌,它描述了應(yīng)用程序的名字猜嘱、版本、權(quán)限嫁艇、引用的庫文件等等信息朗伶;
classes.dex:Dalvik字節(jié)碼文件,Android會將所有的class文件全部放到這一個文件里步咪;
resources.arsc:編譯后的二進制資源文件论皆,保存資源文件的索引,由aapt生成猾漫;
lib: 如果存在的話点晴,存放的是ndk編出來的so庫。
3.apk安裝過程
??這里我們主要來講解下載APK后悯周,點擊進行安裝的過程粒督,整體上來說大致分為4個步驟:
將APK的信息通過IO流的形式寫入到PackageInstaller.Session中;
調(diào)用PackageInstaller.Session的commit方法禽翼,將APK的信息交由PKMS處理屠橄;
拷貝APK萨惑;
安裝apk。
??整個過程涉及到3個跨進程通信的Binder:
APK從應(yīng)用市場下載后點擊安裝仇矾,則會跳轉(zhuǎn)到(com.android.packageinstaller) PackageInstaller.apk 的安裝界面上庸蔼,供用戶選擇安裝或取消,之前也分析過前半段的流程贮匕,是怎么跳轉(zhuǎn)到PackageInstaller.apk 的安裝界面中, 請查閱:Android PackageManagerService--01:應(yīng)用市場下載安裝apk流程
3.1 點擊安裝到APK拷貝
(1)時序圖
(2)點擊一個未安裝的apk后姐仅,會彈出安裝界面,點擊確定按鈕后刻盐,會進入PackageInstallerActivity.java的bindUi()中的mAlert點擊事件(Activity中的onCreate中調(diào)用bindUi)掏膏;
??點擊apk后,彈出的安裝界面底部顯示的是一個Dialog敦锌,主要由bindUi構(gòu)成馒疹,上面有取消和安裝兩個按鈕,點擊安裝之后調(diào)用startInstall()進行安裝乙墙。bindUi方法的代碼如下:
// frameworks/base/packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
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 {
// 進行APK的安裝, 關(guān)鍵代碼
startInstall();
}
}
}, null);
mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
(ignored, ignored2) -> {
// Cancel and finish
setResult(RESULT_CANCELED);
if (mSessionId != -1) {
// 如果mSessionId存在颖变,執(zhí)行setPermissionResult()完成取消安裝
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();
}
}
(3)接下來看看startInstall()方法,封裝了一個Intent跳轉(zhuǎn)到InstallInstalling.java文件中
// frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
private void startInstall() {
Intent newIntent = new Intent();
...
newIntent.setClass(this, InstallInstalling.class);
...
startActivity(newIntent);
}
(4)InstallInstalling的Activity啟動后听想,進入onCreate方法
// frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
protected void onCreate(@Nullable Bundle savedInstanceState) {
....
if ("package".equals(mPackageURI.getScheme())) {
try {
getPackageManager().installExistingPackage(appInfo.packageName);
launchSuccess();
} catch (PackageManager.NameNotFoundException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
} else {
//根據(jù)mPackageURI創(chuàng)建一個對應(yīng)的File
final File sourceFile = new File(mPackageURI.getPath());
// 1.如果savedInstanceState不為null腥刹,獲取此前保存的mSessionId和mInstallId,
// 其中mSessionId是安裝包的會話Id汉买,mInstallId是等待安裝的事件Id
if (savedInstanceState != null) {
mSessionId = savedInstanceState.getInt(SESSION_ID);
mInstallId = savedInstanceState.getInt(INSTALL_ID);
// Reregister for result; might instantly call back if result was delivered while
// activity was destroyed
try {
// 2\. 根據(jù)mInstallId向InstallEventReceiver注冊一個觀察者衔峰,
// launchFinishBasedOnResult會接收到安裝事件的回調(diào),無論安裝成功還是失敗
// 都會關(guān)閉當(dāng)前的Activity(InstallInstalling)蛙粘。如果savedInstanceState為null垫卤,代碼的邏輯也是類似的
InstallEventReceiver.addObserver(this, mInstallId,
this::launchFinishBasedOnResult); // 監(jiān)聽安裝結(jié)果
} catch (EventResultPersister.OutOfIdsException e) {
// Does not happen
}
} else {
//3\. 創(chuàng)建SessionParams,它用來代表安裝會話的參數(shù)出牧,組裝params
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.setInstallAsInstantApp(false);
params.setReferrerUri(getIntent().getParcelableExtra(Intent.EXTRA_REFERRER));
params.setOriginatingUri(getIntent()
.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI));
params.setOriginatingUid(getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
UID_UNKNOWN));
params.setInstallerPackageName(getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME));
params.setInstallReason(PackageManager.INSTALL_REASON_USER);
// 4.根據(jù)mPackageUri對包進行輕量級的解析穴肘,并將解析的參數(shù)賦值給SessionParams
File file = new File(mPackageURI.getPath());
try {
PackageParser.PackageLite pkg = PackageParser.parsePackageLite(file, 0);
params.setAppPackageName(pkg.packageName);
//設(shè)置apk的安裝路徑
params.setInstallLocation(pkg.installLocation);
//設(shè)置apk的大小
params.setSize(
PackageHelper.calculateInstalledSize(pkg, false, params.abiOverride));
....
//5\. 向InstallEventReceiver注冊一個觀察者返回一個新的mInstallId,
// 其中InstallEventReceiver繼承自BroadcastReceiver崔列,用于接收安裝事件
// 并回調(diào)給EventResultPersister
try {
mInstallId = InstallEventReceiver
.addObserver(this, EventResultPersister.GENERATE_NEW_ID,
this::launchFinishBasedOnResult);
} catch (EventResultPersister.OutOfIdsException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
....
try {
// 6\. PackageInstaller的createSession方法內(nèi)部會通過IPackageInstaller與
// PackageInstallerService進行進程間通信梢褐,最終調(diào)用的是
// PackageInstallerService的createSession方法阿里創(chuàng)建并返回mSessionId
mSessionId = getPackageManager().getPackageInstaller().createSession(params);
} catch (IOException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
.....
}
再來總結(jié)一下上面onCreate方法中所做的工作:
如果savedInstanceState不為null,獲取此前保存的mSessionId和mInstallId赵讯,其中mSessionId是安裝包的會話Id盈咳,mInstallId是等待的安裝事件Id;
根據(jù)mInstallId向InstallEventReceiver注冊一個觀察者边翼,launchFinishBasedOnResult會接收到安裝事件的回調(diào)鱼响,無論安裝成功或者是安裝失敗都會關(guān)閉當(dāng)前的Activity(InstallInstalling)。如果saveInstanceState為null组底,代碼的邏輯也是類似的丈积。
創(chuàng)建SessionParams筐骇,它用來代表安裝會話的參數(shù),組裝Params江滨;
根據(jù)mPackageUri對包(APK)進行輕量級的解析铛纬,并將解析的參數(shù)賦值SessionParams;
向InstallEventReceiver注冊一個觀察者返回一個新的mInstallId唬滑;
PackageInstaller的createSession方法內(nèi)部會通過IPackageInstallerService進行進程間通信告唆,最終調(diào)用的是PackageInstallerService的createSession方法來創(chuàng)建并返回mSessionId。
(5)接下來繼續(xù)分析 InstallInstalling.java的onResume()方法
// frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
@Override
protected void onResume() {
super.onResume();
...
if (sessionInfo != null && !sessionInfo.isActive()) {
// 創(chuàng)建內(nèi)部類InstallingAsyncTask的對象晶密,調(diào)用execute()擒悬,最終進入onPostExecute()方法
mInstallingTask = new InstallingAsyncTask();
mInstallingTask.execute();
} else {
// we will receive a broadcast when the install is finished
mCancelButton.setEnabled(false);
setFinishOnTouchOutside(false);
}
...
}
(6)InstallingAsyncTask的doInBackground()會根據(jù)包(APK)的Uri,將APK的信息通過IO流的形式寫入到PackageInstaller.Session中, 最后在onPostExecute()中調(diào)用PackageInstaller.Session的commit方法稻艰,進行安裝懂牧。
// frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
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) {
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;
}
// 將APK的信息通過IO流的形式寫入到PackageInstaller.Session中
out.write(buffer, 0, numRead);
...
}
@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);
// 調(diào)用PackageInstaller.Session的commit方法,進行安裝
session.commit(pendingIntent.getIntentSender());
mCancelButton.setEnabled(false);
setFinishOnTouchOutside(false);
} else {
getPackageManager().getPackageInstaller().abandonSession(mSessionId);
if (!isCancelled()) {
launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);
}
}
}
}
(7)接著看一下PackageInstaller.Session的commit方法, 通過IPackageInstallerSession.aidl 跨進程通信,調(diào)用 PackageInstallerSession.java 中的commit方法
// frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
...
//調(diào)用markAsCommitted()
if (!markAsCommitted(statusReceiver, forTransfer)) {
return;
}
mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
...
}
markAsCommitted方法中會將包的信息封裝為PackageInstallObserverAdapter 尊勿,它在PKMS中被定義僧凤,然后返回到commit()中,向Handler發(fā)送一個類型為MSG_COMMIT的消息 运怖。
(8)接著看消息處理的方法
// frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_COMMIT:
handleCommit();// 處理消息
break;
....
}
-----------------------
private void handleCommit() {
.....
synchronized (mLock) {
commitNonStagedLocked(childSessions);
}
....
}
(9)commitNonStagedLocked()中首先調(diào)用了PackageInstallObserver的onPackageInstalled方法拼弃,將Complete方法出現(xiàn)的PackageManagerException的異常信息回調(diào)給PackageInstallObserverAdapter夏伊。
// frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java
@GuardedBy("mLock")
private void commitNonStagedLocked(List<PackageInstallerSession> childSessions)
throws PackageManagerException {
....
if (!success) {
try {
mRemoteObserver.onPackageInstalled(
null, failure.error, failure.getLocalizedMessage(), null);
} catch (RemoteException ignored) {
}
return;
}
// 最終調(diào)用這個方法
mPm.installStage(activeChildSessions);
....
}
(10)最終調(diào)用installStage()摇展,進入PKMS中
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
void installStage(List<ActiveInstallSession> children)
throws PackageManagerException {
final Message msg = mHandler.obtainMessage(INIT_COPY);
.....
mHandler.sendMessage(msg);
.....
}
-------------------------------------------
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í)行APK拷貝動作
params.startCopy();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
break;
}
......
(11)在Handler中對INIT_COPY消息的處理中,調(diào)用了HandlerParams.startCopy方法
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
final void startCopy() {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
handleStartCopy();
handleReturnCode();
}
(12)handleStartCopy()需要執(zhí)行下面幾步:
首先檢查文件和cid是否已經(jīng)生成溺忧,如果生成則設(shè)置installFlags咏连;
檢查空間大小,如果空間不夠就會釋放無用的空間鲁森;
覆蓋原有安裝位置的文件祟滴,并根據(jù)返回結(jié)果來確定函數(shù)的返回值,并設(shè)置installFlags歌溉;
確定是否有任何已安裝的包安裝器垄懂,如果有,則延遲檢測痛垛。主要分三步:
1)首先新建一個驗證Intent草慧,然后設(shè)置相關(guān)的信息;
2)之后獲取驗證器列表匙头;
3)最后向每個驗證器發(fā)送驗證Intent漫谷。
// Android 11.0
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public void handleStartCopy() {
int ret = PackageManager.INSTALL_SUCCEEDED;
// 1.首先檢查文件和cid是否已經(jīng)生成,如生成則設(shè)置installFlags
if (origin.staged) {
if (origin.file != null) {
installFlags |= PackageManager.INSTALL_INTERNAL;
} else {
throw new IllegalStateException("Invalid stage location");
}
}
.....
// 2\. 檢查空間大小蹂析,如果空間不夠則釋放無用空間
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) {
.....
{
// 3\. 覆蓋原有安裝位置的文件舔示,并根據(jù)返回結(jié)果來確定函數(shù)的返回值碟婆,
// 并設(shè)置installFlags
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;
}
}
}
}
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ā)送一個請求來檢查包的完整性
sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState);
// 向驗證者發(fā)送驗證包的請求
ret = sendPackageVerificationRequest(
verificationId, pkgLite, verificationState);
}
...
mRet = ret;
}
(13)在Android 11.0 中是通過sendPackageVerificationRequest來驗證包的
// Android 11.0
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
int sendPackageVerificationRequest(
int verificationId,
PackageInfoLite pkgLite,
PackageVerificationState verificationState) {
int ret = INSTALL_SUCCEEDED;
.....
if (!origin.existing
&& isVerificationEnabled
&& (!isIncrementalInstall || !isV4Signed)) {
// 4\. 確定是否有任何已安裝的包驗證器,如有惕稻,則延遲檢測竖共。主要分三步:
// 首先新建一個驗證Intent,然后設(shè)置相關(guān)的信息俺祠,之后獲取驗證器列表
// 最后向每個驗證器發(fā)送驗證Intent
// 4.1 構(gòu)造驗證Intent
final Intent verification = new Intent(
Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
PACKAGE_MIME_TYPE);
verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
....
populateInstallerExtras(verification);
// 4.2 獲取驗證器列表
final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
receivers, verificationState);
DeviceIdleInternal idleController =
mInjector.getLocalDeviceIdleController();
final long idleDuration = getVerificationTimeout();
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setTemporaryAppWhitelistDuration(idleDuration);
/*
* If any sufficient verifiers were listed in the package
* manifest, attempt to ask them.
*/
if (sufficientVerifiers != null) {
final int n = sufficientVerifiers.size();
if (n == 0) {
Slog.i(TAG, "Additional verifiers required, but none installed.");
ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
} else {
for (int i = 0; i < n; i++) {
final ComponentName verifierComponent = sufficientVerifiers.get(i);
idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
verifierComponent.getPackageName(), idleDuration,
verifierUser.getIdentifier(), false, "package verifier");
// 4.3 向每個驗證器發(fā)送驗證Intent
// 向驗證器客戶端發(fā)送Intent肘迎,只有當(dāng)驗證成功之后才開啟copy工作
// 如果沒有任何驗證器則直接拷貝
final Intent sufficientIntent = new Intent(verification);
sufficientIntent.setComponent(verifierComponent);
mContext.sendBroadcastAsUser(sufficientIntent, verifierUser,
/* receiverPermission= */ null,
options.toBundle());
}
}
}
.....
return ret;
}
(14)向驗證器客戶端發(fā)送Intent,只有當(dāng)驗證成功之后才會開啟copy工作锻煌。如果沒有任何驗證器則直接拷貝妓布。在handleReturnCode中調(diào)用copyApk()進行APK的拷貝工作。
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
void handleReturnCode() {
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) {
// 調(diào)用copyApk方法
mRet = mArgs.copyApk();
}
processPendingInstall(mArgs, mRet); // 這里是安裝apk的流程宋梧,放到3.2節(jié)中分析
}
}
(15)調(diào)用了InstallArgs.copyApk方法匣沼,最終會調(diào)用到FileInstallArgs.copyApk方法
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
int copyApk() {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
try {
// 調(diào)用doCopyApk方法
return doCopyApk();
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
------------------------------------------
private int doCopyApk() {
.....
// 調(diào)用PackageManagerServiceUtils.copyPackage方法
int ret = PackageManagerServiceUtils.copyPackage(
origin.file.getAbsolutePath(), codeFile);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
Slog.e(TAG, "Failed to copy package");
return ret;
}
.....
return ret;
}
(16)在doCopyApk方法中調(diào)用了PackageManagerServiceUtils.copyPackage方法,其代碼如下:
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java\
public static int copyPackage(String packagePath, File targetDir) {
if (packagePath == null) {
return PackageManager.INSTALL_FAILED_INVALID_URI;
}
try {
final File packageFile = new File(packagePath);
final PackageParser.PackageLite pkg = PackageParser.parsePackageLite(packageFile, 0);
copyFile(pkg.baseCodePath, targetDir, "base.apk");
if (!ArrayUtils.isEmpty(pkg.splitNames)) {
for (int i = 0; i < pkg.splitNames.length; i++) {
// 調(diào)用了copyFile方法
copyFile(pkg.splitCodePaths[i], targetDir,
"split_" + pkg.splitNames[i] + ".apk");
}
}
return PackageManager.INSTALL_SUCCEEDED;
} catch (PackageParserException | IOException | ErrnoException e) {
Slog.w(TAG, "Failed to copy package at " + packagePath + ": " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
}
(17)在copyFile方法中捂龄,通過文件流的操作释涛,把APK拷貝到/data/app等目錄
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java\
private static void copyFile(String sourcePath, File targetDir, String targetName)
throws ErrnoException, IOException {
if (!FileUtils.isValidExtFilename(targetName)) {
throw new IllegalArgumentException("Invalid filename: " + targetName);
}
Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);
final File targetFile = new File(targetDir, targetName);
final FileDescriptor targetFd = Os.open(targetFile.getAbsolutePath(),
O_RDWR | O_CREAT, 0644);
Os.chmod(targetFile.getAbsolutePath(), 0644);
FileInputStream source = null;
try {
source = new FileInputStream(sourcePath);
FileUtils.copy(source.getFD(), targetFd);
} finally {
IoUtils.closeQuietly(source);
}
}
3.2 安裝apk流程
??APK拷貝完成后,進入真正的安裝倦沧,時序圖如下:
(1)在上述handleReturnCode方法中唇撬,執(zhí)行了copyApk方法后,最后又執(zhí)行了processPendingInstall方法展融。
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
if (args.mMultiPackageInstallParams != null) {
args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
} else {
// 1\. 設(shè)置安裝參數(shù)
PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
// 2\. 創(chuàng)建一個新線程窖认,處理安裝參數(shù),進行安裝
processInstallRequestsAsync(
res.returnCode == PackageManager.INSTALL_SUCCEEDED,
Collections.singletonList(new InstallRequest(args, res)));
}
}
--------------------------------------------------
private void processInstallRequestsAsync(boolean success,
List<InstallRequest> installRequests) {
mHandler.post(() -> {
if (success) {
for (InstallRequest request : installRequests) {
// 1\. 如果之前安裝失敗告希,清除無用信息
request.args.doPreInstall(request.installResult.returnCode);
}
synchronized (mInstallLock) {
// 2\. installPackagesTracedLI是安裝過程的核心方法
// 然后調(diào)用installPackagesLI進行安裝
installPackagesTracedLI(installRequests);
}
for (InstallRequest request : installRequests) {
// 3\. 如果之前安裝失敗扑浸,清除無用信息
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));
}
});
}
--------------------------------------------------
int doPreInstall(int status) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
// 清除無用信息
cleanUp();
}
return status;
}
--------------------------------------------------
int doPostInstall(int status, int uid) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
// 調(diào)用cleanUp清除無用信息
cleanUp();
}
return status;
}
(2)在installPackagesLI方法中,以原子的方式安裝一個或多個包燕偶。此操作分為四個階段:
1)Prepare準備:分析任何當(dāng)前安裝狀態(tài)喝噪,分析包并對其進行初始驗證;
2)Scan 掃描:掃描分析準備階段拿到的包指么;
3) Reconcile協(xié)調(diào):包的掃描結(jié)果酝惧,用于協(xié)調(diào)可能向系統(tǒng)中添加的一個或多個包;
4) Commit提交:提交所有掃描的包并更新系統(tǒng)狀態(tài)伯诬,這是安裝流程中唯一可以修改系統(tǒng)狀態(tài)的地方晚唇,必須在此階段之前確定所有的可預(yù)測的錯誤;
5)完成APK的安裝姑廉。
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private void installPackagesLI(List<InstallRequest> requests) {
......
// 1\. Prepare 準備:分析任何當(dāng)前安裝狀態(tài)缺亮,分析包并對其進行初始驗證
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);
......
// 3\. Reconcile協(xié)調(diào):包的掃描結(jié)果,用于協(xié)調(diào)可能向系統(tǒng)中添加的一個或多個包
ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
installResults,
prepareResults,
mSharedLibraries,
Collections.unmodifiableMap(mPackages), versionInfos,
lastStaticSharedLibSettings);
......
// 4\. Commit 提交:提交所有掃描的包并更新系統(tǒng)狀態(tài)。這是安裝流程中唯一可以修改系統(tǒng)狀態(tài)的地方萌踱,
// 必須在此階段之前確定所有的可預(yù)測的錯誤
commitPackagesLocked(commitRequest);
......
// 5\. 完成APK的安裝
executePostCommitSteps(commitRequest);
}
(3)executePostCommitSteps安裝APK葵礼,并為新的代碼路徑準備應(yīng)用程序配置文件,并在此檢查是否需要dex優(yōu)化并鸵。
??如果是直接安裝新包鸳粉,會為新的代碼路徑準備應(yīng)用程序配置文件;如果是替換安裝园担,其主要過程為更新設(shè)置届谈,清除原有的某些APP數(shù)據(jù),重新生成相關(guān)的app數(shù)據(jù)目錄等步驟弯汰,同時要區(qū)分系統(tǒng)應(yīng)用替換和非系統(tǒng)應(yīng)用替換艰山。而安裝新包,則直接更新設(shè)置咏闪,生成APP數(shù)據(jù)即可曙搬。
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private void executePostCommitSteps(CommitRequest commitRequest) {
for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
......
// 1) 進行安裝
prepareAppDataAfterInstallLIF(pkg);
// 2) 如果需要替換安裝,則需要清除原有的App數(shù)據(jù)
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) 為新的代碼路徑準備應(yīng)用程序配置文件鸽嫂。這需要在調(diào)用dexopt之前完成纵装,
// 以便任何安裝時配置文件都可以用于優(yōu)化
mArtManagerService.prepareAppProfiles(
pkg,
resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()),
/* updateReferenceProfileContent= */ true);
// 4) 檢查是否需要優(yōu)化dex文件
final boolean performDexopt =
(!instantApp || Global.getInt(mContext.getContentResolver(),
Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
&& !pkg.isDebuggable()
&& (!onIncremental);
if (performDexopt) {
// 5) 執(zhí)行dex優(yōu)化
mPackageDexOptimizer.performDexOpt(pkg, realPkgSetting,
null /* instructionSets */,
getOrCreateCompilerPackageStats(pkg),
mDexManager.getPackageUseInfoOrDefault(packageName),
dexoptOptions);
}
BackgroundDexOptService.notifyPackageChanged(packageName);
notifyPackageChangeObserversOnUpdate(reconciledPkg);
}
}
(4)PackageManagerService.prepareAppDataAfterInstallLIF()通過一系列的調(diào)用,最終會調(diào)用到Installer.java的createAppData()方法進行安裝据某,交給installed進程進行APK的安裝橡娄。調(diào)用過程如下:
prepareAppDataAfterInstallLIF()
|
prepareAppDataLIF()
|
prepareAppDataLeafLIF()
|
[Installer.java]createAppData()
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private void prepareAppDataAfterInstallLIF(AndroidPackage pkg) {
......
for (UserInfo user : mUserManager.getUsers(false /*excludeDying*/)) {
......
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(AndroidPackage pkg, int userId, int flags) {
if (pkg == null) {
Slog.wtf(TAG, "Package was null!", new Throwable());
return;
}
// 調(diào)用prepareAppDataLeafLIF方法
prepareAppDataLeafLIF(pkg, userId, flags);
}
-----------------------------------------------------
private void prepareAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
......
try {
// 調(diào)用Install守護進程的入口
ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
appId, seInfo, pkg.getTargetSdkVersion());
} catch (InstallerException e) {
if (pkg.isSystem()) {
destroyAppDataLeafLIF(pkg, userId, flags);
try {
ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId,
flags,appId, seInfo, pkg.getTargetSdkVersion());
} catch (InstallerException e2) {
......
}
}
}
}
(5)跳轉(zhuǎn)到Installer.java
// frameworks/base/services/core/java/com/android/server/pm/Installer.java
public long createAppData(String uuid, String packageName, int userId, int flags, int
appId,String seInfo, int targetSdkVersion) throws InstallerException {
if (!checkBeforeRemote()) return -1;
try {
// mInstalld為IInstall的對象,即通過Binder調(diào)用到進程installd,
// 最終調(diào)用installd的createAppData()
return mInstalld.createAppData(uuid, packageName, userId, flags, appId, seInfo,
targetSdkVersion);
} catch (Exception e) {
throw InstallerException.from(e);
}
}
至于之后的IInstall服務(wù)安裝過程這里不再分析癣籽,可參考:Android安裝服務(wù)installd源碼分析和Android 源碼 installd 啟動流程分析挽唉。
4.總結(jié)
??APK的安裝主要分為以下四步:
1)將APK的信息通過IO流的形式寫入到 PackageInstaller.Session中;
2)調(diào)用PackageInstaller.Session的commit方法才避,將APK的信息交由PKMS處理橱夭;
3)拷貝APK;
4)最后進行安裝桑逝。
??最終是交給IInstalld守護進程進行真正的安裝操作。