1 概述
關(guān)于session的處理流程,我們要先了解session是什么碎绎,它用來(lái)做什么
PackageInstaller.Session 是 Android 系統(tǒng)提供的一個(gè)類(lèi),用于在運(yùn)行時(shí)安裝應(yīng)用程序包(APK)文件。通過(guò) PackageInstaller.Session,開(kāi)發(fā)者可以在應(yīng)用程序中實(shí)現(xiàn)動(dòng)態(tài)安裝應(yīng)用程序捏膨,而不需要依賴(lài)傳統(tǒng)的安裝方式(如通過(guò)應(yīng)用商店或命令行)。
使用 PackageInstaller 和 PackageInstaller.Session 類(lèi)食侮,開(kāi)發(fā)者可以進(jìn)行應(yīng)用程序的分階段安裝号涯,管理安裝過(guò)程中的權(quán)限請(qǐng)求、安裝進(jìn)度等操作锯七。這樣的安裝方式可以提供更好的用戶(hù)體驗(yàn)链快,同時(shí)也增加了安全性和靈活性。
通常情況下眉尸,PackageInstaller.Session 會(huì)被用于應(yīng)用程序更新域蜗、應(yīng)用內(nèi)動(dòng)態(tài)模塊安裝等場(chǎng)景中巨双。通過(guò)該類(lèi),開(kāi)發(fā)者可以控制應(yīng)用程序的安裝過(guò)程地消,并且可以處理各種安裝過(guò)程中可能出現(xiàn)的情況炉峰。
2 代碼流程
2.1 session的第一次處理
public void commit(@NonNull IntentSender statusReceiver) {
try {
//這里調(diào)用IPackageInstallerSession的commit方法
mSession.commit(statusReceiver, false);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
IPackageInstallerSession.aidl
interface IPackageInstallerSession
由此可以知道當(dāng)次我們進(jìn)行跨進(jìn)程通信,systemserver進(jìn)程
public class PackageInstallerSession extends IPackageInstallerSession.Stub {
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
/**
* 參數(shù) statusReceiver 用于組件通信
* 攜帶的數(shù)據(jù) 安裝包名稱(chēng) 安裝包id
* forTransfer false
*/
if (hasParentSessionId()) {
/**
* case 是否存在父session
*
* 拋出異常脉执,當(dāng)次session提交失效
*/
throw new IllegalStateException(
"Session " + sessionId + " is a child of multi-package session "
+ getParentSessionId() + " and may not be committed directly.");
}
//檢查當(dāng)次會(huì)話,無(wú)問(wèn)題的話 確定當(dāng)次session
if (!markAsSealed(statusReceiver, forTransfer)) {
return;
}
if (isMultiPackage()) {
/**
* case 多安裝包情況
*
* 過(guò)程 遍歷每一個(gè)安裝包 并且標(biāo)志 session確定
*
* 只要其中一個(gè)安裝包session不確定戒劫,都會(huì)導(dǎo)致安裝失敗
*/
synchronized (mLock) {
boolean sealFailed = false;
for (int i = mChildSessions.size() - 1; i >= 0; --i) {
// seal all children, regardless if any of them fail; we'll throw/return
// as appropriate once all children have been processed
if (!mChildSessions.valueAt(i).markAsSealed(null, forTransfer)) {
sealFailed = true;
}
}
if (sealFailed) {
return;
}
}
}
//當(dāng)會(huì)話確定完成 這里進(jìn)行會(huì)話派發(fā)
dispatchSessionSealed();
}
}
總結(jié): 系統(tǒng)應(yīng)用進(jìn)程封裝session參數(shù)傳入到system_server進(jìn)程后半夷,創(chuàng)建PackageinstallSession,開(kāi)啟異步任務(wù)向讓session保存安裝apk的文件數(shù)據(jù)迅细,接下來(lái)執(zhí)行session.commit跨進(jìn)程來(lái)到PMS進(jìn)行交互
當(dāng)前主要進(jìn)行session確定操作巫橄,檢查當(dāng)前系統(tǒng)frp是否開(kāi)啟且禁用安裝功能,sessionid是否存在轉(zhuǎn)移
檢查完畢 封裝會(huì)話茵典,派發(fā)出去
private boolean markAsSealed(@Nullable IntentSender statusReceiver, boolean forTransfer) {
/**
* 參數(shù) statusReceiver 不為null forTransfer false
*/
Preconditions.checkState(statusReceiver != null || hasParentSessionId(),
"statusReceiver can't be null for the root session");
assertCallerIsOwnerOrRoot();
synchronized (mLock) {
assertPreparedAndNotDestroyedLocked("commit of session " + sessionId);
assertNoWriteFileTransfersOpenLocked();
//獲取SECURE_FRP_MODE的值 FRP 是一種安全功能湘换,旨在保護(hù)設(shè)備免受未經(jīng)授權(quán)的訪問(wèn)和數(shù)據(jù)泄露。
final boolean isSecureFrpEnabled =
(Secure.getInt(mContext.getContentResolver(), Secure.SECURE_FRP_MODE, 0) == 1);
if (isSecureFrpEnabled
&& !isSecureFrpInstallAllowed(mContext, Binder.getCallingUid())) {
/**
* case frp開(kāi)啟且 frp禁止安裝操作
*
* 過(guò)程 拋出異常统阿,當(dāng)次安裝失敗
*/
throw new SecurityException("Can't install packages while in secure FRP");
}
if (forTransfer) {
/**
* case 檢查安裝會(huì)話是否被修改
*
* 過(guò)程 修改 檢查倆次安裝是否相同彩倚,相同 拋出異常
*
* 未修改 不相同拋出異常
*/
mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
if (mInstallerUid == mOriginalInstallerUid) {
throw new IllegalArgumentException("Session has not been transferred");
}
} else {
if (mInstallerUid != mOriginalInstallerUid) {
throw new IllegalArgumentException("Session has been transferred");
}
}
setRemoteStatusReceiver(statusReceiver);
// After updating the observer, we can skip re-sealing.
if (mSealed) {
return true;
}
try {
//設(shè)置mseal標(biāo)志位定義當(dāng)前會(huì)話已被seal確定
sealLocked();
} catch (PackageManagerException e) {
return false;
}
}
return true;
}
2.2 session的第二次處理
private void dispatchSessionSealed() {
//發(fā)送消息MSG_ON_SESSION_SEALED
mHandler.obtainMessage(MSG_ON_SESSION_SEALED).sendToTarget();
}
可以看到是通過(guò)handler消息機(jī)制來(lái)驅(qū)動(dòng)的,在android系統(tǒng)中這種驅(qū)動(dòng)方式很常見(jiàn)
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_ON_SESSION_SEALED:
handleSessionSealed();
break;
上面session剛確認(rèn)好扶平,這里執(zhí)行session確認(rèn)完成流程
private void handleSessionSealed() {
assertSealed("dispatchSessionSealed");
// Persist the fact that we've sealed ourselves to prevent
// mutations of any hard links we create.
/**
* 這里是一個(gè)回調(diào)操作帆离,了解這個(gè)回調(diào)的機(jī)制流程
* mCallback 是 PackageInstallerSession的內(nèi)部類(lèi) InternalCallback
* InternalCallback 執(zhí)行該方法時(shí)
* 又會(huì)引入一個(gè)新變量mCallbacks 他實(shí)際是一個(gè)handler子類(lèi)
* private class Callbacks extends Handler
*
* 通過(guò)handler來(lái)驅(qū)動(dòng)消息,最后你會(huì)看到IPackageInstallerCallback來(lái)處理回調(diào)
* 這個(gè)一看就知道是aidl回調(diào) 那么就是會(huì)通知相關(guān)進(jìn)程當(dāng)前安裝的一個(gè)狀態(tài)
* 可以先看我這個(gè)了解下 文章最后我會(huì)舉一個(gè)例子
*/
mCallback.onSessionSealedBlocking(this);
//接下來(lái)就是apk文件流的驗(yàn)證和提交
dispatchStreamValidateAndCommit();
}
private void dispatchStreamValidateAndCommit() {
mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();
}
case MSG_STREAM_VALIDATE_AND_COMMIT:
handleStreamValidateAndCommit();
break;
private void handleStreamValidateAndCommit() {
try {
// This will track whether the session and any children were validated and are ready to
// progress to the next phase of install
//allSessionsReady 作為標(biāo)志位 默認(rèn)當(dāng)前session都已經(jīng)準(zhǔn)備就緒
boolean allSessionsReady = true;
//這里如果是多包安裝结澄,需要對(duì)每個(gè)包的數(shù)據(jù)都進(jìn)行驗(yàn)證
/**
* case 多安裝包情況
* 過(guò)程 每個(gè)子安裝包都要進(jìn)行數(shù)據(jù)驗(yàn)證哥谷,最后確認(rèn)Session是否準(zhǔn)備就緒
*/
for (PackageInstallerSession child : getChildSessions()) {
allSessionsReady &= child.streamValidateAndCommit();
}
/**
* case 普通安裝單包情況
*
* 過(guò)程 直接進(jìn)行streamValidateAndCommit 數(shù)據(jù)包驗(yàn)證操作
* 驗(yàn)證成功會(huì)通過(guò)handler驅(qū)動(dòng)下一次操作
*/
if (allSessionsReady && streamValidateAndCommit()) {
mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
}
} catch (PackageManagerException e) {
//失敗了也要通知相關(guān)進(jìn)程或者服務(wù)
destroy();
String msg = ExceptionUtils.getCompleteMessage(e);
dispatchSessionFinished(e.error, msg, null);
maybeFinishChildSessions(e.error, msg);
}
}
總結(jié) 這里主要針對(duì)安裝apk的數(shù)據(jù)進(jìn)行一個(gè)驗(yàn)證,多安裝包麻献,分批檢查们妥,單安裝包,直接檢查
private void handleStreamValidateAndCommit() {
try {
// This will track whether the session and any children were validated and are ready to
// progress to the next phase of install
//allSessionsReady 作為標(biāo)志位 默認(rèn)當(dāng)前session都已經(jīng)準(zhǔn)備就緒
boolean allSessionsReady = true;
//這里如果是多包安裝勉吻,需要對(duì)每個(gè)包的數(shù)據(jù)都進(jìn)行驗(yàn)證
/**
* case 多安裝包情況
* 過(guò)程 每個(gè)子安裝包都要進(jìn)行數(shù)據(jù)驗(yàn)證监婶,最后確認(rèn)Session是否準(zhǔn)備就緒
*/
for (PackageInstallerSession child : getChildSessions()) {
allSessionsReady &= child.streamValidateAndCommit();
}
/**
* case 普通安裝單包情況
*
* 過(guò)程 直接進(jìn)行streamValidateAndCommit 數(shù)據(jù)包驗(yàn)證操作
* 驗(yàn)證成功會(huì)通過(guò)handler驅(qū)動(dòng)下一次操作
*/
if (allSessionsReady && streamValidateAndCommit()) {
mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
}
} catch (PackageManagerException e) {
//失敗了也要通知相關(guān)進(jìn)程或者服務(wù)
destroy();
String msg = ExceptionUtils.getCompleteMessage(e);
dispatchSessionFinished(e.error, msg, null);
maybeFinishChildSessions(e.error, msg);
}
}
總結(jié): session的派發(fā)中,第一次進(jìn)行了session的條件判斷確認(rèn)餐曼,第二次進(jìn)行了session內(nèi)安裝包的數(shù)據(jù)檢查驗(yàn)證压储,接下來(lái)該來(lái)到session的第三次處理流程
case MSG_INSTALL:
handleInstall();
break;
private void handleInstall() {
if (isInstallerDeviceOwnerOrAffiliatedProfileOwner()) {
//跟蹤設(shè)備上應(yīng)用程序的安裝情況
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.INSTALL_PACKAGE)
.setAdmin(getInstallSource().installerPackageName)
.write();
}
/**
* Stops the installation of the whole session set if one session needs user action
* in its belong session set. When the user answers the yes,
* {@link #setPermissionsResult(boolean)} is called and then {@link #MSG_INSTALL} is
* handled to come back here to check again.
*/
if (sendPendingUserActionIntentIfNeeded()) {
return;
}
//根據(jù)參數(shù)params的isStaged檢查當(dāng)前是否分階段驗(yàn)證
/**
* params 是packageInstallerSession構(gòu)建的時(shí)候傳入的 PackageInstaller.SessionParams
* 封裝著安裝包的相關(guān)信息
* case 是否分階段
* 過(guò)程 分階段使用mStagedSession
* 不分階段使用verify
* 這里分析不分階段
*/
if (params.isStaged) {
mStagedSession.verifySession();
} else {
//普通驗(yàn)證流程
verify();
}
}
private void verify() {
try {
/**
* 可以看到verify主要的工作就是解析安裝包的文件數(shù)據(jù)
* case 多安裝包
* 過(guò)程 遍歷子安裝包解析每一個(gè)子安裝包的文件
*
* case 單安裝包
*
* 直接解析
*/
List<PackageInstallerSession> children = getChildSessions();
if (isMultiPackage()) {
for (PackageInstallerSession child : children) {
child.prepareInheritedFiles();
child.parseApkAndExtractNativeLibraries();
}
} else {
prepareInheritedFiles();
parseApkAndExtractNativeLibraries();
}
//解析完成執(zhí)行
verifyNonStaged();
} catch (PackageManagerException e) {
final String completeMsg = ExceptionUtils.getCompleteMessage(e);
final String errorMsg = PackageManager.installStatusToString(e.error, completeMsg);
setSessionFailed(e.error, errorMsg);
onSessionVerificationFailure(e.error, errorMsg);
}
}
解析涉及代碼不多,我們也看下解析相關(guān)
private void parseApkAndExtractNativeLibraries() throws PackageManagerException {
synchronized (mLock) {
/**
* 在解析安裝包文件前會(huì)進(jìn)行一些case判斷
* case 當(dāng)前解析的目錄/文件是否已經(jīng)被使用了
*
* case mDestroyed = true
*
* case mSealed = false
*
* 這三種情況都會(huì)拋出異常源譬,提示安裝失敗原因
*/
if (mStageDirInUse) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
"Session files in use");
}
if (mDestroyed) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
"Session destroyed");
}
if (!mSealed) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
"Session not sealed");
}
Objects.requireNonNull(mPackageName);
Objects.requireNonNull(mSigningDetails);
Objects.requireNonNull(mResolvedBaseFile);
final PackageLite result;
/**
* case 判斷當(dāng)次解析的session是否為apex
*
* 過(guò)程 這里我們分析apk安裝 所以執(zhí)行g(shù)etOrParsePackageLiteLocked 解析拿到PackageLite
*
* 這個(gè)PackageLite是包含應(yīng)用程序相關(guān)信息集惋,當(dāng)然不是完整的,后續(xù)會(huì)看到他的具體作用
*
* 最后解析apk包含的lib庫(kù)文件
*/
if (!isApexSession()) {
// For mode inherit existing, it would link/copy existing files to stage dir in
// prepareInheritedFiles(). Therefore, we need to parse the complete package in
// stage dir here.
// Besides, PackageLite may be null for staged sessions that don't complete
// pre-reboot verification.
result = getOrParsePackageLiteLocked(stageDir, /* flags */ 0);
} else {
result = getOrParsePackageLiteLocked(mResolvedBaseFile, /* flags */ 0);
}
if (result != null) {
mPackageLite = result;
if (!isApexSession()) {
synchronized (mProgressLock) {
mInternalProgress = 0.5f;
computeProgressLocked(true);
}
extractNativeLibraries(
mPackageLite, stageDir, params.abiOverride, mayInheritNativeLibs());
}
}
}
}
總結(jié):主要就是解析apk部分信息拿到ePackageLite踩娘,解析native lib庫(kù)文件
解析完成開(kāi)始下一步流程
2.3 session的第三次處理
private void verifyNonStaged()
throws PackageManagerException {
synchronized (mLock) {
markStageDirInUseLocked();
}
//這里主要進(jìn)行session 驗(yàn)證 驗(yàn)證通過(guò)執(zhí)行內(nèi)部回調(diào)函數(shù)
/**
* 這里通過(guò)會(huì)話提供器獲取會(huì)話驗(yàn)證器刮刑,來(lái)驗(yàn)證當(dāng)前安裝會(huì)話
*
* 結(jié)果 error 報(bào)錯(cuò) msg 異常消息
*
* 驗(yàn)證安裝會(huì)話后喉祭,會(huì)通過(guò)匿名函數(shù)回調(diào)的方式通過(guò)handler來(lái)給到主線程處理callback任務(wù)
*
* case 安裝成功
*
* 執(zhí)行會(huì)話驗(yàn)證完成回調(diào)
*
* case 安裝失敗
* 執(zhí)行會(huì)話驗(yàn)證失敗的回調(diào)
*/
mSessionProvider.getSessionVerifier().verify(this, (error, msg) -> {
mHandler.post(() -> {
if (dispatchPendingAbandonCallback()) {
// No need to continue if abandoned
return;
}
if (error == INSTALL_SUCCEEDED) {
//這里執(zhí)行該方法
onVerificationComplete();
} else {
onSessionVerificationFailure(error, msg);
}
});
});
}
總結(jié) 主要是對(duì)安裝會(huì)話進(jìn)行驗(yàn)證相關(guān)操作,sessionVerifier.verify的具體處理流程的話雷绢,后續(xù)單獨(dú)出文章詳細(xì)分析泛烙,先了解宏觀的結(jié)構(gòu)
private void onVerificationComplete() {
//Android應(yīng)用安裝過(guò)程中,引入了"staged"(暫存)階段作為安裝的一部分翘紊。在這個(gè)階段蔽氨,
//安裝系統(tǒng)會(huì)將安裝操作拆分成多個(gè)步驟來(lái)執(zhí)行,而不是一次性完成整個(gè)安裝過(guò)程帆疟。
//這種方式有助于提高安裝的效率和穩(wěn)定性鹉究,尤其是對(duì)于大型應(yīng)用或多模塊應(yīng)用的安裝
/**
* case 檢查當(dāng)次安裝是否需要分階段
* 過(guò)程 這里執(zhí)行普通安裝操作
*/
if (isStaged()) {
//分階段安裝操作
mStagingManager.commitSession(mStagedSession);
sendUpdateToRemoteStatusReceiver(INSTALL_SUCCEEDED, "Session staged", null);
return;
}
//普通安裝操作
install();
}
在查看安裝操作時(shí),我們需要先了解踪宠,這里的一個(gè)用到的一個(gè)java語(yǔ)法CompletableFuture 它也是一個(gè)異步任務(wù)的對(duì)象
由java8 引入的一個(gè)概念自赔,我們可以管理異步任務(wù)的完成狀態(tài),并且可以對(duì)異步任務(wù)的處理結(jié)果進(jìn)行相關(guān)處理
如何創(chuàng)建completableFuture對(duì)象
CompletableFuture.supplyAsync方法柳琢,或者CompletableFuture.runAsync方法
我們也可以組成多個(gè)completableFuture對(duì)象绍妨,通過(guò)使用thenApply,thenAccept柬脸,thenCombine方法來(lái)管理這些異步任務(wù)的執(zhí)行順序
eg
java
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
public class CompletableFutureDemo {
public static void main(String[] args) {
// 創(chuàng)建一個(gè)CompletableFuture來(lái)執(zhí)行異步任務(wù)
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
// 模擬耗時(shí)操作
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello, CompletableFuture!";
});
// 定義在CompletableFuture完成后執(zhí)行的操作
CompletableFuture<Void> resultFuture = future.thenAccept(result -> {
System.out.println("Result received: " + result);
});
// 等待異步任務(wù)完成
resultFuture.join();
System.out.println("CompletableFuture demo finished.");
}
}
如何處理completableFuture拋出的異常
使用exceptionally方法
eg
import java.util.concurrent.CompletableFuture;
public class CompletableFutureExceptionDemo {
public static void main(String[] args) {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
// 模擬一個(gè)會(huì)拋出異常的異步任務(wù)
if (Math.random() < 0.5) {
throw new RuntimeException("Simulated exception");
}
return 42;
});
// 使用exceptionally()處理異常
CompletableFuture<Integer> resultFuture = future.exceptionally(ex -> {
System.out.println("Exception occurred: " + ex.getMessage());
return -1; // 返回一個(gè)備用結(jié)果
});
resultFuture.thenAccept(result -> {
System.out.println("Result: " + result);
});
try {
resultFuture.get(); // 等待異步任務(wù)完成
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用allof方法可以等待所有任務(wù)執(zhí)行完成
eg
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureAllOfDemo {
public static void main(String[] args) throws InterruptedException, ExecutionException {
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Result from future1");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Result from future2");
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "Result from future3");
CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2, future3);
// 等待所有CompletableFuture完成
allFutures.get();
System.out.println("All CompletableFuture completed.");
System.out.println("Result 1: " + future1.get());
System.out.println("Result 2: " + future2.get());
System.out.println("Result 3: " + future3.get());
}
接著我們接著看install函數(shù)
private CompletableFuture<Void> install() {
//獲取異步任務(wù)集合里面存放著安裝的結(jié)果
//從這里可以猜到installNonStaged可能是具體的安裝操作
List<CompletableFuture<InstallResult>> futures = installNonStaged();
//根據(jù)集合的數(shù)量創(chuàng)建對(duì)應(yīng)數(shù)組
CompletableFuture<InstallResult>[] arr = new CompletableFuture[futures.size()];
//這里當(dāng)安裝操作都完成后他去,獲取安裝的結(jié)果和異常,執(zhí)行異步任務(wù)
return CompletableFuture.allOf(futures.toArray(arr)).whenComplete((r, t) -> {
if (t == null) {
//沒(méi)有異常的情況肖粮,處理異步任務(wù)完成的結(jié)果孤页,派發(fā)通知當(dāng)前安裝會(huì)話完成
setSessionApplied();
for (CompletableFuture<InstallResult> f : futures) {
InstallResult result = f.join();
result.session.dispatchSessionFinished(
INSTALL_SUCCEEDED, "Session installed", result.extras);
}
} else {
//安裝存在異常,設(shè)置會(huì)話失敗涩馆,派發(fā)通知當(dāng)前安裝會(huì)話失敗
PackageManagerException e = (PackageManagerException) t.getCause();
setSessionFailed(e.error,
PackageManager.installStatusToString(e.error, e.getMessage()));
dispatchSessionFinished(e.error, e.getMessage(), null);
maybeFinishChildSessions(e.error, e.getMessage());
}
});
}
installNonStaged函數(shù)返回異步任務(wù)集合
現(xiàn)看installNonStaged函數(shù)
private List<CompletableFuture<InstallResult>> installNonStaged() {
try {
//構(gòu)建異步任務(wù)集合
List<CompletableFuture<InstallResult>> futures = new ArrayList<>();
//首先構(gòu)建異步任務(wù)加入集合
CompletableFuture<InstallResult> future = new CompletableFuture<>();
futures.add(future);
//將異步任務(wù)關(guān)聯(lián)到InstallParams中
final InstallParams installingSession = makeInstallParams(future);
if (isMultiPackage()) {
//case1 多apk情況
//獲取子會(huì)話
final List<PackageInstallerSession> childSessions = getChildSessions();
//創(chuàng)建子會(huì)話集合
List<InstallParams> installingChildSessions = new ArrayList<>(childSessions.size());
for (int i = 0; i < childSessions.size(); ++i) {
//遍歷子會(huì)話行施,構(gòu)建異步任務(wù)關(guān)聯(lián)子會(huì)話,
final PackageInstallerSession session = childSessions.get(i);
future = new CompletableFuture<>();
futures.add(future);
final InstallParams installingChildSession = session.makeInstallParams(future);
if (installingChildSession != null) {
installingChildSessions.add(installingChildSession);
}
}
//這里子會(huì)話不為空
if (!installingChildSessions.isEmpty()) {
//執(zhí)行安裝操作
installingSession.installStage(installingChildSessions);
}
} else if (installingSession != null) {
//對(duì)于普通安裝 正常執(zhí)行安裝操作
installingSession.installStage();
}
return futures;
} catch (PackageManagerException e) {
List<CompletableFuture<InstallResult>> futures = new ArrayList<>();
futures.add(CompletableFuture.failedFuture(e));
return futures;
}
}
總結(jié): 在這里可以看到根據(jù)多包安裝還是單包安裝魂那,我們會(huì)構(gòu)建CompletableFuture對(duì)象蛾号,通過(guò)makeInstallParams函數(shù)將future關(guān)聯(lián)到InstallParams中,當(dāng)InstallParams準(zhǔn)備好后涯雅,會(huì)調(diào)用installStage函數(shù)執(zhí)行安裝操作并且將InstallParams傳遞進(jìn)去
接著回到install函數(shù)鲜结,當(dāng)所有異步任務(wù)完成并且沒(méi)有異常的話,設(shè)置安裝session被使用活逆,主線程等待異步任務(wù)完成精刷,異步任務(wù)完成后執(zhí)行dispatchSessionFinished派發(fā)出去通知已安裝
到這里我們跟蹤了installSession的整個(gè)處理流程
接下來(lái)我們會(huì)詳細(xì)去看安裝的流程細(xì)節(jié),還有dispatchSessionFinished的派發(fā)最后通知了誰(shuí)