1. 程式人生 > >應用程式安裝流程

應用程式安裝流程

本文介紹APK的安裝流程。

一、安裝流程圖

APK安裝流程,總體可以下圖流程,用ProcessOn畫的,湊合看:

package_install

從上圖我們可以看到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。

由於之前有描述過,便不再敘述