應用程式安裝流程
本文介紹APK的安裝流程。
一、安裝流程圖
APK安裝流程,總體可以下圖流程,用ProcessOn畫的,湊合看:
從上圖我們可以看到apk安裝到最後都會呼叫到這個flow:
PMS.scanPackageTracedLI => PMS.scanPackageLI => PMS.scanPackageDirtyLI
後續的博文會根據這張圖展開說明。
二、APK檔案結構
APK(Android Package),可以看做是一個zip壓縮包,可以通過解壓縮工具解開,其檔案結構如下:
目錄 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 | 編譯後的二進位制資原始檔。 |
三、APK安裝方法
APK有下面4種安裝方法:
方法 | 描述 |
---|---|
開機過程中安裝 | 開機時完成,沒有安裝介面,如系統應用、其它預置應用 |
adb工具安裝 | 沒有安裝介面,adb install/push xxxx.apk |
第三方應用安裝 | 通過packageinstaller.apk進行安裝,有安裝介面,如開啟檔案管理器並點選sdk卡里APK檔案 |
網路下載應用安裝 | 通過google market應用完成,沒有安裝介面 |
簡單說明下apk安裝的基本過程:
- 拷貝目標apk到指定檔案目錄
- 呼叫scanPackageLI為apk檔案在系統中註冊資訊
四、應用程式安裝過程
上述幾種安裝方法最終都通過PackageManagerService.scanPackageLI完成,總結起來大致有以下三種方式:
-
adb push:
PackageManagerService的內部類AppDirObserver實現了監聽app目錄的功能,當把某個APK檔案放到app目錄下面時,PMS會收到ADD_EVENTS事件
frameworks\base\services\java\com\android\server\pm\PackageManagerService.java -
adb install:
安裝入口函式為Pm.runInstall
frameworks\base\cmds\pm\src\com\android\commands\pm\Pm.java -
網路下載應用安裝和第三方應用安裝:
安裝入口函式為ApplicationPackageManager.installPackage
frameworks\base\core\java\android\app\ApplicationPackageManager.java
接下來我們來分別詳細說明這些安裝流程:
五、adb push
Android 4.4平臺,PackageManagerService的內部類AppDirObserver實現了監聽app目錄的功能,當把某個APK檔案放到app目錄下面時,PMS會收到ADD_EVENTS事件。
如果是新增事件,則呼叫scanPackageLI,並使用updatePermissionsLPw授權;如果是刪除事件則呼叫removePackageLI移除該apk的相關資訊。最後都要呼叫writeLPr重新儲存相關資訊到packages.xml。
關於AppDirObserver具體如何監聽的,可以檢視:AppDirObserver
不過我在android 7.0 sdk裡面沒有看到這個類,難道7.0把這個功能砍了?手頭沒有7.0平臺,不好驗證。
我猜測現在通過adb push apk到data/app或者system/app的apk,如果這個監聽的功能砍了,那麼應該是會通過reboot重啟系統,走PMS.main流程,scanDir–>scanPackageLI去安裝apk。
以上待填坑。
六、adb install
adb install 的安裝方式,會呼叫system/core/adb/commandline.cpp中的adb_commandline函式:
1 2 3 4 5 |
adb_commandline install_app_legacy or install_app pm_command send_shell_command Pm.runInstall() |
這個過程會把apk檔案copy到data/local/tmp/目錄下,然後向shell服務傳送pm命令安裝apk,最後呼叫Pm.runInstall()
方法來安裝apk。
6.1 pm.runInstall
frameworks\base\cmds\pm\src\com\android\commands\pm\Pm.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
private int runInstall() throws RemoteException { final InstallParams params = makeInstallParams(); // 1. 建立session final int sessionId = doCreateSession(params.sessionParams, params.installerPackageName, params.userId); try { final String inPath = nextArg(); if (inPath == null && params.sessionParams.sizeBytes == 0) { System.err.println("Error: must either specify a package size or an APK file"); return 1; } // 2. 寫session if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk", false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) { return 1; } // 3. 提交Session if (doCommitSession(sessionId, false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) { return 1; } System.out.println("Success"); return 0; } finally { try { mInstaller.abandonSession(sessionId); } catch (Exception ignore) { } } } |
從上面的程式碼來看,runInstall主要進行了三件事,即建立session、對session進行寫操作,最後提交session。
6.1.1 doCreateSession
實際呼叫的是PackageInstallerService的createSession,這個過程主要是為APK安裝做好準備工作,例如許可權檢查、目的臨時檔案的建立等, 最終創建出PackageInstallerSession物件。PackageInstallerSession可以看做是”安裝APK”這個請求的封裝,其中包含了處理這個請求需要的一些資訊。
實際上PackageInstallerSession不僅是分裝請求的物件,其自身還是個服務端。
6.1.2 doWriteSession
通過PackageInstallerSession將/data/local/tmp的apk拷貝到終端目錄內。
6.1.3 doCommitSession
doWriteSession結束後,如果沒有出現任何錯誤,那麼APK原始檔已經copy到目的地址了,doCommitSession最終會呼叫到PMS.installStage來安裝apk,呼叫流程如下:
PackageInstallerSession.commit ==> commitLocked(); ==> PMS.installStage()
PMS.installStage()會呼叫sendMessage將”INIT_COPY”傳送給PackageHandler:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
void installStage(String packageName, File stagedDir, String stagedCid, IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams, String installerPackageName, int installerUid, UserHandle user, Certificate[][] certificates) { if (DEBUG_EPHEMERAL) { if ((sessionParams.installFlags & PackageManager.INSTALL_EPHEMERAL) != 0) { Slog.d(TAG, "Ephemeral install of " + packageName); } } final VerificationInfo verificationInfo = new VerificationInfo( sessionParams.originatingUri, sessionParams.referrerUri, sessionParams.originatingUid, installerUid); final OriginInfo origin; if (stagedDir != null) { origin = OriginInfo.fromStagedFile(stagedDir); } else { origin = OriginInfo.fromStagedContainer(stagedCid); } final Message msg = mHandler.obtainMessage(INIT_COPY); final InstallParams params = new InstallParams(origin, null, observer, sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid, verificationInfo, user, sessionParams.abiOverride, sessionParams.grantedRuntimePermissions, certificates); 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的安裝請求等訊息,後面分析。
七、ApplicationPackageManager
網路下載應用安裝或者通過第三方應用安裝,最終都會通過ApplicationPackageManager.installPackage來安裝:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public void installPackage(Uri packageURI, PackageInstallObserver observer, int flags, String installerPackageName) { installCommon(packageURI, observer, flags, installerPackageName, mContext.getUserId()); } private void installCommon(Uri packageURI, PackageInstallObserver observer, int flags, String installerPackageName, int userId) { if (!"file".equals(packageURI.getScheme())) { throw new UnsupportedOperationException("Only file:// URIs are supported"); } final String originPath = packageURI.getPath(); try { // PMS.installPackageAsUser mPM.installPackageAsUser(originPath, observer.getBinder(), flags, installerPackageName, userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } |
PMS.installPackageAsUser呼叫sendMessage將”INIT_COPY”傳送給PackageHandler:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
@Override public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer, int installFlags, String installerPackageName, int userId) { ... final Message msg = mHandler.obtainMessage(INIT_COPY); final VerificationInfo verificationInfo = new VerificationInfo( null /*originatingUri*/, null /*referrer*/, -1 /*originatingUid*/, callingUid); final InstallParams params = new InstallParams(origin, null /*moveInfo*/, observer, installFlags, installerPackageName, null /*volumeUuid*/, verificationInfo, user, null /*packageAbiOverride*/, null /*grantedPermissions*/, null /*certificates*/); params.setTraceMethod("installAsUser").setTraceCookie(System.identityHashCode(params)); msg.obj = params; mHandler.sendMessage(msg); .... } |
PackageHandler用於處理apk的安裝請求等訊息,後面分析。
八、PackageHanlder
- PMS.installStage()會呼叫sendMessage將”INIT_COPY”傳送給PackageHandler
- PMS.installPackageAsUser呼叫sendMessage將”INIT_COPY”傳送給PackageHandler
8.1 INIT_COPY
PackageHandler用於處理apk的安裝請求等訊息,在PMS建構函式中有初始化。實際處理訊息的函式為doHandleMessage,我們來看看INIT_COPY的處理流程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
class PackageHandler extends Handler { ... void doHandleMessage(Message msg) { switch (msg.what) { case INIT_COPY: { //這裡取出的其實就是InstallParams HandlerParams params = (HandlerParams) msg.obj; //idx為當前等待處理處理的安裝請求的個數 int idx = mPendingInstalls.size(); ............ //初始時,mBound的值為false if (!mBound) { ............ // If this is the only one pending we might // have to bind to the service again. //連線安裝服務 if (!connectToService()) { .................. } else { // Once we bind to the service, the first // pending request will be processed. //繫結服務成功後,將新的請求加入到mPendingIntalls中,等待處理 mPendingInstalls.add(idx, params); } } else { //如果之前已經繫結過服務,同樣將新的請求加入到mPendingIntalls中,等待處理 mPendingInstalls.add(idx, params); // Already bound to the service. Just make // sure we trigger off processing the first request. if (idx == 0) { //如果是第一個請求,則直接傳送事件MCS_BOUND,觸發處理流程 mHandler.sendEmptyMessage(MCS_BOUND); } } break; } } } ... } |
INIT_COPY主要是將新的請求加入到mPendingIntalls中,等待MCS_BOUND階段處理。
8.2 MCS_BOUND
INIT_COPY最後會發送MCS_BOUND訊息觸發接下來的流程,MCS_BOUND對應的處理流程同樣定義於doHandleMessage中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
void doHandleMessage(Message msg) { ....... case MCS_BOUND: { ........ if (msg.obj != null) { mContainerService = (IMediaContainerService) msg.obj; ....... } if (mContainerService == null) { if (!mBound) { // Something seriously wrong since we are not bound and we are not // waiting for connection. Bail out. ............ } else { Slog.w(TAG, "Waiting to connect to media container service"); } // 請求佇列mPendingInstalls不為空 } else if (mPendingInstalls.size() > 0) { HandlerParams params = mPendingInstalls.get(0); if (params != null) { ........ //呼叫引數的startCopy函式處理安裝請求 if (params.startCopy()) { ........ // Delete pending install if (mPendingInstalls.size() > 0) { mPendingInstalls.remove(0); } if (mPendingInstalls.size() == 0) { if (mBound) { .......... removeMessages(MCS_UNBIND); Message ubmsg = obtainMessage(MCS_UNBIND); // Unbind after a little delay, to avoid // continual thrashing. sendMessageDelayed(ubmsg, 10000); } } else { // There are more pending requests in queue. // Just post MCS_BOUND message to trigger processing // of next pending install. ...... mHandler.sendEmptyMessage(MCS_BOUND); } } ......... } } else { // Should never happen ideally. Slog.w(TAG, "Empty queue"); } break; } ....... } |
這一段程式碼比較好理解:
- 如果mPendingInstalls不為空,呼叫
InstallParams.startCopy
函式處理安裝請求。 - 接著如果mPendingInstalls不為空,傳送MCS_BOUND繼續處理下一個,直到佇列為空。
- 如果佇列為空,則等待一段時間後,傳送MCS_UNBIND訊息斷開與安裝服務的繫結。
九、startCopy
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
InstallParams繼承HandlerParams,實際呼叫的是HandlerParams.startCopy:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
final boolean startCopy() { boolean res; try { if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this); if (++mRetries > MAX_RETRIES) { Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); mHandler.sendEmptyMessage(MCS_GIVE_UP); handleServiceError(); return false; } else { // 呼叫handleStartCopy()處理 handleStartCopy(); Slog.i(TAG, "Apk copy done"); res = true; } } catch (RemoteException e) { if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT"); mHandler.sendEmptyMessage(MCS_RECONNECT); res = false; } // handleReturnCode(); return res; } |
PMS將先後呼叫handleStartCopy和handleReturnCode來完成主要的工作。
9.1 handleStartCopy
handleStartCopy函式在HandleParams抽象類定義,在其子類InstallParams來實現,我們看看與實際安裝相關的handleStartCopy函式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
public void handleStartCopy() throws RemoteException { int ret = PackageManager.INSTALL_SUCCEEDED; // 決定是安裝在手機內還是sdcard中,設定對應標誌位 if (origin.staged) { if (origin.file != null) { installFlags |= PackageManager.INSTALL_INTERNAL; installFlags &= ~PackageManager.INSTALL_EXTERNAL; } else if (origin.cid != null) { installFlags |= PackageManager.INSTALL_EXTERNAL; installFlags &= ~PackageManager.INSTALL_INTERNAL; } else { throw new IllegalStateException("Invalid stage location"); } } ... // 檢查APK的安裝位置是否正確 if (onInt && onSd) { // Check if both bits are set. Slog.w(TAG, "Conflicting flags specified for installing on both internal and external"); ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; } else if (onSd && ephemeral) { Slog.w(TAG, "Conflicting flags specified for installing ephemeral on external"); ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; } else { ... } ... // createInstallArgs用於建立一個安裝引數物件 final InstallArgs args = createInstallArgs(this); if (ret == PackageManager.INSTALL_SUCCEEDED) { ... // 呼叫InstallArgs的copyApk函式 ret = args.copyApk(mContainerService, true); } } mRet = ret; } |
InstallParams$handleStartCopy()主要功能是獲取安裝位置資訊以及複製apk到指定位置。抽象類InstallArgs中的copyApk負責複製APK檔案,具體實現在子類FileInstallArgs和SdInstallArgs裡面。
9.2 handleReturnCode
InstallParams$handleReturnCode()中,呼叫processPendingInstall方法處理安裝:
1 2 3 4 5 6 7 8 |
void handleReturnCode() { // If mArgs is null, then MCS couldn't be reached. When it // reconnects, it will try again to install. At that point, this // will succeed. if (mArgs != null) { processPendingInstall(mArgs, mRet); } } |
9.3 processPendingInstall
主要的安裝流程都在這個方法裡面: PMS.processPendingInstall
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
private void processPendingInstall(final InstallArgs args, final int currentStatus) { mHandler.post(new Runnable() { public void run() { mHandler.removeCallbacks(this); // Result object to be returned PackageInstalledInfo res = new PackageInstalledInfo(); res.setReturnCode(currentStatus); res.uid = -1; res.pkg = null; res.removedInfo = null; if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { //1、預安裝,檢查包狀態,確保環境ok,如果環境不ok,那麼會清理拷貝的檔案 args.doPreInstall(res.returnCode); synchronized (mInstallLock) { //2、安裝,呼叫installPackageTracedLI進行安裝 installPackageTracedLI(args, res); } //3、安裝收尾 args.doPostInstall(res.returnCode, res.uid); } if (!doRestore) { ....... //4、生成一個POST_INSTALL訊息給PackageHanlder Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0); mHandler.sendMessage(msg); } } }); } |
安裝過程放在一個執行緒裡面,處理流程是預安裝-安裝-安裝收尾-傳送 POST_INSTALL訊息:
- 預安裝:檢查當前安裝包的狀態以及確保SDCARD的掛載,並返回狀態資訊。在安裝前確保安裝環境的可靠。
- 安裝:對mInstallLock加鎖,表明同時只能有一個安裝包進行安裝;然後呼叫installPackageTracedLI完成具體安裝操作。
- 安裝收尾: 檢查狀態,如果安裝不成功,刪除掉相關目錄檔案。
- 傳送POST_INSTALL訊息:該訊息由PackageHandler接收。POST_INSTALL的主要工作其實還是通過廣播、回撥介面通知系統中的其它元件,有新的Pacakge安裝或發生了改變。
從上面我們可以知道,具體安裝apk的函式是PMS.installPackageTracedLI
。
十、installPackageTracedLI
PMS.installPackageTracedLI函式:
1 2 3 4 5 6 7 8 |
private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) { try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage"); installPackageLI(args, res); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } |
十一、installPackageLI
繼續PMS.installPackageLI:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) { // PackageParser物件 PackageParser pp = new PackageParser(); pp.setSeparateProcesses(mSeparateProcesses); pp.setDisplayMetrics(mMetrics); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage"); final PackageParser.Package pkg; try { if (DEBUG_INSTALL) Slog.i(TAG, "Start parsing apk: " + installerPackageName); // 1.開始解析我們的package pkg = pp.parsePackage(tmpPackageFile, parseFlags); if (DEBUG_INSTALL) Slog.i(TAG, "Parsing done for apk: " + installerPackageName); } catch (PackageParserException e) { res.setError("Failed parse during installPackageLI", e); return; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } ... //2. 載入證書,獲取簽名信息 try { // either use what we've been given or parse directly from the APK if (args.certificates != null) { try { PackageParser.populateCertificates(pkg, args.certificates); } catch (PackageParserException e) { PackageParser.collectCertificates(pkg, parseFlags); } } else { PackageParser.collectCertificates(pkg, parseFlags); } } catch (PackageParserException e) { res.setError("Failed collect during installPackageLI", e); return; } ... synchronized (mPackages) { // 3.檢測packages是否存在 if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { ... replace = true; } else if (mPackages.containsKey(pkgName)) { ... replace = true; if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName); } ... } } ... try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags, "installPackageLI")) { if (replace) { // 4.更新已經存在的packages replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user, installerPackageName, res); } else { // 5.安裝新的packages installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES, args.user, installerPackageName, volumeUuid, res); } } ... } |
這個函式過程比較長,主要做了幾件事:
- PackageParser$parsePackage,主要是解析APK的AndroidManifest.xml,將每個標籤對應的資訊新增到Package的相關列表中,如將下的資訊新增到Package的activities列表等。
- 載入apk證書,獲取簽名信息
- 檢查目前安裝的APK是否在系統中已存在:
- 已存在,則呼叫
replacePackageLIF
進行替換安裝。 - 不存在,否則呼叫
installNewPackageLIF
進行安裝。
- 已存在,則呼叫
11.1 replacePackageLIF
如果需要替換的是系統APP,則呼叫Settings$disableSystemPackageLPw來disable舊的APK;如果替換的是非系統APP,則呼叫deletePackageLI刪除舊的APK。
因為這個過程實在太差,沒有必要貼出來一一分析,我來簡化一下flow,有興趣的讀者可以深入跟進:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
replacePackageLIF replaceSystemPackageLIF // 系統 pkg removePackageLI disableSystemPackageLPw clearAppDataLIF scanPackageTracedLI //安裝apk scanPackageLI scanPackageDirtyLI updateSettingsLI updatePermissionsLPw mSettings.writeLPr(); replaceNonSystemPackageLIF // 非系統 pkg deletePackageLIF clearAppDataLIF clearAppProfilesLIF scanPackageTracedLI // 安裝apk scanPackageLI scanPackageDirtyLI updateSettingsLI updatePermissionsLPw mSettings.writeLPr(); |
不管是更新系統還是非系統apk,都會先清除之前的packages資訊,然後通過scanPackageTracedLI去安裝apk,安裝完後更新permissions和setting,最後通過writeLPr更新packages.xml。
關於scanPackageTracedLI和Settings.writeLPr();我有在上一篇blog講過,可以回去看看。
11.2 installNewPackageLIF
PMS.installNewPackageLIF用於安裝新的apk:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags, int scanFlags, UserHandle user, String installerPackageName, String volumeUuid, PackageInstalledInfo res) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage"); // Remember this for later, in case we need to rollback this install String pkgName = pkg.packageName; if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg); // package已經存在 synchronized(mPackages) { if (mSettings.mRenamedPackages.containsKey(pkgName)) { // A package with the same name is already installed, though // it has been renamed to an older name. The package we // are trying to install should be installed as an update to // the existing one, but that has not been requested, so bail. res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName + " without first uninstalling package running as " + mSettings.mRenamedPackages.get(pkgName)); return; } if (mPackages.containsKey(pkgName)) { // Don't allow installation over an existing package with the same name. res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName + " without first uninstalling."); return; } } try { // 1. 安裝apk PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags, System.currentTimeMillis(), user); // 2. 更新setting updateSettingsLI(newPackage, installerPackageName, null, res, user); if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { prepareAppDataAfterInstallLIF(newPackage); } else { // Remove package from internal structures, but keep around any // data that might have already existed deletePackageLIF(pkgName, UserHandle.ALL, false, null, PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null); } } catch (PackageManagerException e) { res.setError("Package couldn't be installed in " + pkg.codePath, e); } Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } |
installNewPackageLIF會呼叫scanPackageTracedLI去安裝apk,最終會呼叫scanPackageLI->scanPackageDirtyLI實際去安裝apk。
由於之前有描述過,便不再敘述