logo图案素材免费网站,贸易有限公司,怎么样自己建设网站,助贷获客系统现在马上进入正式的安装流程。 从前面文章 Android 安装过程四 MSG_INSTALL消息的处理 安装之前的验证知道#xff0c;在验证之后没有什么问题的情况下#xff0c;会回调onVerificationComplete()方法#xff0c;它位于PackageInstallerSession类中。 private void onVe… 现在马上进入正式的安装流程。 从前面文章 Android 安装过程四 MSG_INSTALL消息的处理 安装之前的验证知道在验证之后没有什么问题的情况下会回调onVerificationComplete()方法它位于PackageInstallerSession类中。 private void onVerificationComplete() {// Staged sessions will be installed later during bootif (isStaged()) {// TODO(b/136257624): Remove this once all verification logic has been transferred out// of StagingManager.mStagingManager.notifyPreRebootVerification_Apk_Complete(mStagedSession);// TODO(b/136257624): We also need to destroy internals for verified staged session,// otherwise file descriptors are never closed for verified staged session until rebootreturn;}install();}……private void install() {try {installNonStaged();} catch (PackageManagerException e) {final String completeMsg ExceptionUtils.getCompleteMessage(e);onSessionInstallationFailure(e.error, completeMsg);}}看到不是在缓存下来进行安装的情况下会继续调用installNonStaged()方法。 private void installNonStaged()throws PackageManagerException {final PackageManagerService.InstallParams installingSession makeInstallParams();if (installingSession null) {throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,Session should contain at least one apk session for installation);}if (isMultiPackage()) {final ListPackageInstallerSession childSessions;synchronized (mLock) {childSessions getChildSessionsLocked();}ListPackageManagerService.InstallParams installingChildSessions new ArrayList(childSessions.size());boolean success true;PackageManagerException failure null;for (int i 0; i childSessions.size(); i) {final PackageInstallerSession session childSessions.get(i);try {final PackageManagerService.InstallParams installingChildSession session.makeInstallParams();if (installingChildSession ! null) {installingChildSessions.add(installingChildSession);}} catch (PackageManagerException e) {failure e;success false;}}if (!success) {final IntentSender statusReceiver;synchronized (mLock) {statusReceiver mRemoteStatusReceiver;}sendOnPackageInstalled(mContext, statusReceiver, sessionId,isInstallerDeviceOwnerOrAffiliatedProfileOwner(), userId, null,failure.error, failure.getLocalizedMessage(), null);return;}mPm.installStage(installingSession, installingChildSessions);} else {mPm.installStage(installingSession);}}构造安装参数InstallParams对象 和验证那块的代码有些像先调用makeInstallParams()构造安装参数InstallParams对象installingSession。暂时忽略多包安装的情况接着就是到PackageManagerService对象中调用installStage(installingSession)方法执行安装。 先看一下安装参数的构成方法makeInstallParams() Nullableprivate PackageManagerService.InstallParams makeInstallParams()throws PackageManagerException {synchronized (mLock) {if (mDestroyed) {throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, Session destroyed);}if (!mSealed) {throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, Session not sealed);}}// Do not try to install staged apex session. Parent session will have at least one apk// session.if (!isMultiPackage() isApexSession() params.isStaged) {sendUpdateToRemoteStatusReceiver(INSTALL_SUCCEEDED,Apex package should have been installed by apexd, null);return null;}final IPackageInstallObserver2 localObserver new IPackageInstallObserver2.Stub() {Overridepublic void onUserActionRequired(Intent intent) {throw new IllegalStateException();}Overridepublic void onPackageInstalled(String basePackageName, int returnCode, String msg,Bundle extras) {if (isStaged()) {sendUpdateToRemoteStatusReceiver(returnCode, msg, extras);} else {// Weve reached point of no return; call into PMS to install the stage.// Regardless of success or failure we always destroy session.destroyInternal();dispatchSessionFinished(returnCode, msg, extras);}}};final UserHandle user;if ((params.installFlags PackageManager.INSTALL_ALL_USERS) ! 0) {user UserHandle.ALL;} else {user new UserHandle(userId);}if (params.isStaged) {params.installFlags | INSTALL_STAGED;}if (!isMultiPackage() !isApexSession()) {synchronized (mLock) {// This shouldnt be null, but have this code path just in case.if (mPackageLite null) {Slog.wtf(TAG, Session: sessionId . Dont have a valid PackageLite.);}mPackageLite getOrParsePackageLiteLocked(stageDir, /* flags */ 0);}}synchronized (mLock) {return mPm.new InstallParams(stageDir, localObserver, params, mInstallSource, user,mSigningDetails, mInstallerUid, mPackageLite);}}首先检查Session对象的状态如果是mDestroyed或!mSealed都会抛出PackageManagerException。 接着会生成一个回调对象localObserver。等待后面安装完毕之后会调用它的onPackageInstalled回调接口。 如果不是多包安装和不是apex安装的情况下如果成员变量为null会调用getOrParsePackageLiteLocked(stageDir, /* flags */ 0)再次生成它。 最后就是调用InstallParams 的构造函数来生成InstallParams 对象了。
进入PackageManagerService中执行安装 PackageManagerService类中的installStage(InstallParams params)如下 void installStage(InstallParams params) {final Message msg mHandler.obtainMessage(INIT_COPY);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);}看下INIT_COPY消息的处理 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);params.startCopy();Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}break;}…………msg.obj就是前面构造的InstallParams 对象这里调用它的startCopy()方法。InstallParams 是继承自HandlerParams类它的startCopy()就是调用handleStartCopy()和handleReturnCode()。这俩方法是实现在InstallParams 类中的。
InstallParams 类的handleStartCopy() 先看InstallParams 类的handleStartCopy() public void handleStartCopy() {if ((installFlags PackageManager.INSTALL_APEX) ! 0) {mRet INSTALL_SUCCEEDED;return;}PackageInfoLite pkgLite PackageManagerServiceUtils.getMinimalPackageInfo(mContext,mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);// For staged session, there is a delay between its verification and install. Device// state can change within this delay and hence we need to re-verify certain conditions.boolean isStaged (installFlags INSTALL_STAGED) ! 0;if (isStaged) {mRet verifyReplacingVersionCode(pkgLite, requiredInstalledVersionCode, installFlags);if (mRet ! INSTALL_SUCCEEDED) {return;}}mRet overrideInstallLocation(pkgLite);}通过PackageManagerServiceUtils.getMinimalPackageInfo()得到包信息对象pkgLite。接着就调用overrideInstallLocation(pkgLite)重写安装位置主要是可能改变安装标识。 这两个方法咱们主要关注一下关于安装位置方面的东西。 先看下PackageManagerServiceUtils.getMinimalPackageInfo()方法 public static PackageInfoLite getMinimalPackageInfo(Context context, PackageLite pkg,String packagePath, int flags, String abiOverride) {final PackageInfoLite ret new PackageInfoLite();if (packagePath null || pkg null) {Slog.i(TAG, Invalid package file packagePath);ret.recommendedInstallLocation PackageHelper.RECOMMEND_FAILED_INVALID_APK;return ret;}final File packageFile new File(packagePath);final long sizeBytes;try {sizeBytes PackageHelper.calculateInstalledSize(pkg, abiOverride);} catch (IOException e) {if (!packageFile.exists()) {ret.recommendedInstallLocation PackageHelper.RECOMMEND_FAILED_INVALID_URI;} else {ret.recommendedInstallLocation PackageHelper.RECOMMEND_FAILED_INVALID_APK;}return ret;}final int recommendedInstallLocation PackageHelper.resolveInstallLocation(context,pkg.getPackageName(), pkg.getInstallLocation(), sizeBytes, flags);ret.packageName pkg.getPackageName();ret.splitNames pkg.getSplitNames();ret.versionCode pkg.getVersionCode();ret.versionCodeMajor pkg.getVersionCodeMajor();ret.baseRevisionCode pkg.getBaseRevisionCode();ret.splitRevisionCodes pkg.getSplitRevisionCodes();ret.installLocation pkg.getInstallLocation();ret.verifiers pkg.getVerifiers();ret.recommendedInstallLocation recommendedInstallLocation;ret.multiArch pkg.isMultiArch();ret.debuggable pkg.isDebuggable();return ret;}这里需要关注的是PackageInfoLite对象的recommendedInstallLocation和installLocation成员变量。 这里看到recommendedInstallLocation的意思是推荐的安装位置如果结果如果是以PackageHelper.RECOMMEND_FAILED 开头的代表失败出问题了。 像这里计算安装大小sizeBytes时出现异常时RECOMMEND_FAILED_INVALID_URI代表文件不存在RECOMMEND_FAILED_INVALID_APK代表不是有效的APK文件。 installLocation是来自安装包的解析属性它是配置在Manifest中的installLocation属性如果没有配置默认为PackageInfo.INSTALL_LOCATION_UNSPECIFIED。 推荐安装位置主要是通过PackageHelper.resolveInstallLocation()方法来得到。再看一下它 public static int resolveInstallLocation(Context context, SessionParams params)throws IOException {ApplicationInfo existingInfo null;try {existingInfo context.getPackageManager().getApplicationInfo(params.appPackageName,PackageManager.MATCH_ANY_USER);} catch (NameNotFoundException ignored) {}final int prefer;final boolean checkBoth;boolean ephemeral false;if ((params.installFlags PackageManager.INSTALL_INSTANT_APP) ! 0) {prefer RECOMMEND_INSTALL_INTERNAL;ephemeral true;checkBoth false;} else if ((params.installFlags PackageManager.INSTALL_INTERNAL) ! 0) {prefer RECOMMEND_INSTALL_INTERNAL;checkBoth false;} else if (params.installLocation PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {prefer RECOMMEND_INSTALL_INTERNAL;checkBoth false;} else if (params.installLocation PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {prefer RECOMMEND_INSTALL_EXTERNAL;checkBoth true;} else if (params.installLocation PackageInfo.INSTALL_LOCATION_AUTO) {// When app is already installed, prefer same mediumif (existingInfo ! null) {// TODO: distinguish if this is external ASECif ((existingInfo.flags ApplicationInfo.FLAG_EXTERNAL_STORAGE) ! 0) {prefer RECOMMEND_INSTALL_EXTERNAL;} else {prefer RECOMMEND_INSTALL_INTERNAL;}} else {prefer RECOMMEND_INSTALL_INTERNAL;}checkBoth true;} else {prefer RECOMMEND_INSTALL_INTERNAL;checkBoth false;}boolean fitsOnInternal false;if (checkBoth || prefer RECOMMEND_INSTALL_INTERNAL) {fitsOnInternal fitsOnInternal(context, params);}boolean fitsOnExternal false;if (checkBoth || prefer RECOMMEND_INSTALL_EXTERNAL) {fitsOnExternal fitsOnExternal(context, params);}if (prefer RECOMMEND_INSTALL_INTERNAL) {// The ephemeral case will either fit and return EPHEMERAL, or will not fit// and will fall through to return INSUFFICIENT_STORAGEif (fitsOnInternal) {return (ephemeral)? PackageHelper.RECOMMEND_INSTALL_EPHEMERAL: PackageHelper.RECOMMEND_INSTALL_INTERNAL;}} else if (prefer RECOMMEND_INSTALL_EXTERNAL) {if (fitsOnExternal) {return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;}}if (checkBoth) {if (fitsOnInternal) {return PackageHelper.RECOMMEND_INSTALL_INTERNAL;} else if (fitsOnExternal) {return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;}}return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;}从这里可以看到推荐安装的值。 这里定义变量prefer是比较推荐安装的地方。checkBoth是检查内部存储和外部存储空间是否满足。 优先判断的是标识installFlags。如果它不满足会去判断installLocation中的值。 如果明确推荐位置checkBoth为false它之后不会内部和外部存储空间两个都做判断。 像满足安装位置为INSTALL_LOCATION_PREFER_EXTERNAL或PackageInfo.INSTALL_LOCATION_AUTO的情况下将checkBoth true。像INSTALL_LOCATION_INTERNAL_ONLY明确就在内部安装就将checkBoth false。 fitsOnInternal()和fitsOnExternal()两个方法就是去判断内部空间和外部空间是否满足安装大小。如果满足返回true。 如果推荐内部安装并且内部大小充足就返回RECOMMEND_INSTALL_INTERNALInstant安装返回RECOMMEND_INSTALL_EPHEMERAL。推荐外部安装外部空间满足就返回RECOMMEND_INSTALL_EXTERNAL。 如果前面两个都不是并且满足需要检查两个空间的情况如果空间足够优先内部安装返回RECOMMEND_INSTALL_INTERNAL再外部安装。 如果以上都不满足返回RECOMMEND_FAILED_INSUFFICIENT_STORAGE代表空间不足。 handleStartCopy()接下来执行overrideInstallLocation(pkgLite)看一下它 private int overrideInstallLocation(PackageInfoLite pkgLite) {final boolean ephemeral (installFlags PackageManager.INSTALL_INSTANT_APP) ! 0;if (DEBUG_INSTANT ephemeral) {Slog.v(TAG, pkgLite for install: pkgLite);}if (origin.staged) {// If were already staged, weve firmly committed to an install locationif (origin.file ! null) {installFlags | PackageManager.INSTALL_INTERNAL;} else {throw new IllegalStateException(Invalid stage location);}} else if (pkgLite.recommendedInstallLocation PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {/** If we are not staged and have too little free space, try to free cache* before giving up.*/// TODO: focus freeing disk space on the target devicefinal 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,mPackageLite, origin.resolvedPath, installFlags,packageAbiOverride);} catch (InstallerException e) {Slog.w(TAG, Failed to free cache, e);}}/** The cache free must have deleted the file we downloaded to install.** TODO: fix the freeCache call to not delete the file we care about.*/if (pkgLite.recommendedInstallLocation PackageHelper.RECOMMEND_FAILED_INVALID_URI) {pkgLite.recommendedInstallLocation PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;}}int ret INSTALL_SUCCEEDED;int loc pkgLite.recommendedInstallLocation;if (loc PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {ret PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;} else if (loc PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {ret PackageManager.INSTALL_FAILED_ALREADY_EXISTS;} else if (loc PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {ret PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;} else if (loc PackageHelper.RECOMMEND_FAILED_INVALID_APK) {ret PackageManager.INSTALL_FAILED_INVALID_APK;} else if (loc PackageHelper.RECOMMEND_FAILED_INVALID_URI) {ret PackageManager.INSTALL_FAILED_INVALID_URI;} else if (loc PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {ret PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;} else {// Override with defaults if needed.loc installLocationPolicy(pkgLite);final boolean onInt (installFlags PackageManager.INSTALL_INTERNAL) ! 0;if (!onInt) {// Override install location with flagsif (loc PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {// Set the flag to install on external media.installFlags ~PackageManager.INSTALL_INTERNAL;} else {// Make sure the flag for installing on external// media is unsetinstallFlags | PackageManager.INSTALL_INTERNAL;}}}return ret;}可以看到的是如果pkgLite的recommendedInstallLocation为RECOMMEND_FAILED_INSUFFICIENT_STORAGE时从上面我们知道这是由于存储空间不足了。在这种情况下它会尝试去释放一些空间调用的是mInstaller.freeCache(null, sizeBytes lowThreshold, 0, 0)。在释放一些空间之后接着再去执行一遍PackageManagerServiceUtils.getMinimalPackageInfo()看看能不能后续得到满足的结果。 接下来判断pkgLite.recommendedInstallLocation的值如果是以PackageManager.INSTALL_FAILED开头的结果都直接设置返回结果。 如果不是失败的结果会接着调用installLocationPolicy(pkgLite)。该方法是又去根据该应用之前的安装包信息来再次做判断。例如安装包是系统应用包则返回PackageHelper.RECOMMEND_INSTALL_INTERNAL。在配置文件没有明确指定位置的情况下安装包在外部存储空间则返回PackageHelper.RECOMMEND_INSTALL_EXTERNAL。如果没有之前的安装包则返回它自己的推荐值。 如果installFlags里面有INSTALL_INTERNAL标识则结果返回INSTALL_SUCCEEDED。如果没有INSTALL_INTERNAL标识假如loc为不等于PackageHelper.RECOMMEND_INSTALL_EXTERNAL则将installFlags里加上INSTALL_INTERNAL标识。
InstallParams 类的handleReturnCode() 它执行processPendingInstall()方法 private void processPendingInstall() {InstallArgs args createInstallArgs(this);if (mRet PackageManager.INSTALL_SUCCEEDED) {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);processInstallRequestsAsync(res.returnCode PackageManager.INSTALL_SUCCEEDED,Collections.singletonList(new InstallRequest(args, res)));}}}首先通过createInstallArgs(this)生成一个InstallArgs 对象。将InstallParams 里的信息转到InstallArgs 类对象中。在这里对于我们的例子它是FileInstallArgs对象。 接着mRet PackageManager.INSTALL_SUCCEEDED的情况下这里会执行FileInstallArgs对象的copyApk()。FileInstallArgs对象的copyApk()如果文件还没有缓存到对应的文件夹下面需要执行复制。如果文件已经复制过则不需要再次复制直接返回INSTALL_SUCCEEDED结果。像例子中的目前已经复制过所以直接返回INSTALL_SUCCEEDED结果。 下面mRet PackageManager.INSTALL_SUCCEEDED的情况下如果文件系统是F2Fs启动压缩情况下需要先释放压缩的数据块以备下面读取使用所以调用F2fsUtils.releaseCompressedBlocks()方法。 如果mParentInstallParams不为null它是一个MultiPackageInstallParams对象用来在多包安装时使用目前的InstallParams对象是多包安装中的一个。需要调用MultiPackageInstallParams类的tryProcessInstallRequest()方法。 如果是单文件安装包则先生成一个PackageInstalledInfo对象res。然后将InstallArgs 对象和res封装到InstallRequest对象中。最后是调用processInstallRequestsAsync()方法来执行后续安装。
处理安装请求 看下processInstallRequestsAsync()代码 // Queue up an async operation since the package installation may take a little while.private void processInstallRequestsAsync(boolean success,ListInstallRequest installRequests) {mHandler.post(() - {ListInstallRequest apexInstallRequests new ArrayList();ListInstallRequest apkInstallRequests new ArrayList();for (InstallRequest request : installRequests) {if ((request.args.installFlags PackageManager.INSTALL_APEX) ! 0) {apexInstallRequests.add(request);} else {apkInstallRequests.add(request);}}// Note: supporting multi package install of both APEXes and APKs might requir some// thinking to ensure atomicity of the install.if (!apexInstallRequests.isEmpty() !apkInstallRequests.isEmpty()) {// This shouldve been caught at the validation step, but for some reason wasnt.throw new IllegalStateException(Attempted to do a multi package install of both APEXes and APKs);}if (!apexInstallRequests.isEmpty()) {if (success) {// Since installApexPackages requires talking to external service (apexd), we// schedule to run it async. Once it finishes, it will resume the install.Thread t new Thread(() - installApexPackagesTraced(apexInstallRequests),installApexPackages);t.start();} else {// Non-staged APEX installation failed somewhere before// processInstallRequestAsync. In that case just notify the observer about the// failure.InstallRequest request apexInstallRequests.get(0);notifyInstallObserver(request.installResult, request.args.observer);}return;}if (success) {for (InstallRequest request : apkInstallRequests) {request.args.doPreInstall(request.installResult.returnCode);}synchronized (mInstallLock) {installPackagesTracedLI(apkInstallRequests);}for (InstallRequest request : apkInstallRequests) {request.args.doPostInstall(request.installResult.returnCode, request.installResult.uid);}}for (InstallRequest request : apkInstallRequests) {restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,new PostInstallData(request.args, request.installResult, null));}});}参数installRequests是List格式因为多包安装也是调用的它。 显然是将操作封装成消息了mHandler发送的消息是在叫PackageManager的线程中执行的。 这里有Apex安装方式的处理。可以看到多包装时是不能既用Apex又用Apk安装方式的。咱们这里主要看Apk的安装方式。 在目前没错误的情况下会调用installPackagesTracedLI(apkInstallRequests)执行安装。在安装之前和之后都会执行对应InstallArgs对象的doPreInstall和doPostInstall方法。从名字能看出来是安装之前的操作和安装之后的操作。由于这里是FileInstallArgs类对象所以执行的是FileInstallArgs类的doPreInstall和doPostInstall方法。FileInstallArgs类的doPreInstall和doPostInstall方法都是根据参数状态如果不是INSTALL_SUCCEEDED则执行清理操作。具体看下面。咱们这里按照还没发生错误的情况下继续往下看。 restoreAndPostInstall()方法在不是升级包的情况下首次安装属于这种情况会向备份管理服务要求执行回复数据当然是在合适的情况下备份服务可能不会启动得配置PackageManager.FEATURE_BACKUP Feature才会启动才会具体执行。如果它是替换升级的情况它还可能会向RollbackManager请求回退数据得配置安装参数中的PackageManager.INSTALL_ENABLE_ROLLBACK或者PackageManager.INSTALL_REQUEST_DOWNGRADE标识。如果这两个都没满足条件它会做安装之后的工作。在这里它是向PackageManager线程发送POST_INSTALL消息。它的处理实现在PackageHandler的handleMessage(Message msg)方法中在处理POST_INSTALL消息时会调用handlePackagePostInstall()方法详见下面。
安装 接下来继续查看installPackagesTracedLI(List requests)的实现 GuardedBy(mInstallLock)private void installPackagesTracedLI(ListInstallRequest requests) {try {Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, installPackages);installPackagesLI(requests);} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}}主要是调用installPackagesLI(requests)继续看它的实现 /*** Installs one or more packages atomically. This operation is broken up into four phases:* ul* libPrepare/b* br/Analyzes any current install state, parses the package and does initial* validation on it./li* libScan/b* br/Interrogates the parsed packages given the context collected in prepare./li* libReconcile/b* br/Validates scanned packages in the context of each other and the current system* state to ensure that the install will be successful.* libCommit/b* br/Commits all scanned packages and updates system state. This is the only place* that system state may be modified in the install flow and all predictable errors* must be determined before this phase./li* /ul** Failure at any phase will result in a full failure to install all packages.*/GuardedBy(mInstallLock)private void installPackagesLI(ListInstallRequest requests) {final MapString, ScanResult preparedScans new ArrayMap(requests.size());final MapString, InstallArgs installArgs new ArrayMap(requests.size());final MapString, PackageInstalledInfo installResults new ArrayMap(requests.size());final MapString, PrepareResult prepareResults new ArrayMap(requests.size());final MapString, VersionInfo versionInfos new ArrayMap(requests.size());final MapString, PackageSetting lastStaticSharedLibSettings new ArrayMap(requests.size());final MapString, Boolean createdAppId new ArrayMap(requests.size());boolean success false;try {Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, installPackagesLI);for (InstallRequest request : requests) {// TODO(b/109941548): remove this once weve pulled everything from it and into// scan, reconcile or commit.final PrepareResult prepareResult;try {Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, preparePackage);prepareResult preparePackageLI(request.args, request.installResult);} catch (PrepareFailure prepareFailure) {request.installResult.setError(prepareFailure.error,prepareFailure.getMessage());request.installResult.origPackage prepareFailure.conflictingPackage;request.installResult.origPermission prepareFailure.conflictingPermission;return;} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);request.installResult.installerPackageName request.args.installSource.installerPackageName;final String packageName prepareResult.packageToScan.getPackageName();prepareResults.put(packageName, prepareResult);installResults.put(packageName, request.installResult);installArgs.put(packageName, request.args);try {final ScanResult result scanPackageTracedLI(prepareResult.packageToScan, prepareResult.parseFlags,prepareResult.scanFlags, System.currentTimeMillis(),request.args.user, request.args.abiOverride);if (null ! preparedScans.put(result.pkgSetting.pkg.getPackageName(), result)) {request.installResult.setError(PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,Duplicate package result.pkgSetting.pkg.getPackageName() in multi-package install request.);return;}createdAppId.put(packageName, optimisticallyRegisterAppId(result));versionInfos.put(result.pkgSetting.pkg.getPackageName(),getSettingsVersionForPackage(result.pkgSetting.pkg));if (result.staticSharedLibraryInfo ! null) {final PackageSetting sharedLibLatestVersionSetting getSharedLibLatestVersionSetting(result);if (sharedLibLatestVersionSetting ! null) {lastStaticSharedLibSettings.put(result.pkgSetting.pkg.getPackageName(),sharedLibLatestVersionSetting);}}} catch (PackageManagerException e) {request.installResult.setError(Scanning Failed., e);return;}}ReconcileRequest reconcileRequest new ReconcileRequest(preparedScans, installArgs,installResults,prepareResults,mSharedLibraries,Collections.unmodifiableMap(mPackages), versionInfos,lastStaticSharedLibSettings);CommitRequest commitRequest null;synchronized (mLock) {MapString, ReconciledPackage reconciledPackages;try {Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, reconcilePackages);reconciledPackages reconcilePackagesLocked(reconcileRequest, mSettings.getKeySetManagerService(), mInjector);} catch (ReconcileFailure e) {for (InstallRequest request : requests) {request.installResult.setError(Reconciliation failed..., e);}return;} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}try {Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, commitPackages);commitRequest new CommitRequest(reconciledPackages,mUserManager.getUserIds());commitPackagesLocked(commitRequest);success true;} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}}executePostCommitSteps(commitRequest);} finally {if (success) {for (InstallRequest request : requests) {final InstallArgs args request.args;if (args.mDataLoaderType ! DataLoaderType.INCREMENTAL) {continue;}if (args.signingDetails.signatureSchemeVersion ! SIGNING_BLOCK_V4) {continue;}// For incremental installs, we bypass the verifier prior to install. Now// that we know the package is valid, send a notice to the verifier with// the root hash of the base.apk.final String baseCodePath request.installResult.pkg.getBaseApkPath();final String[] splitCodePaths request.installResult.pkg.getSplitCodePaths();final Uri originUri Uri.fromFile(args.origin.resolvedFile);final int verificationId mPendingVerificationToken;final String rootHashString PackageManagerServiceUtils.buildVerificationRootHashString(baseCodePath, splitCodePaths);broadcastPackageVerified(verificationId, originUri,PackageManager.VERIFICATION_ALLOW, rootHashString,args.mDataLoaderType, args.getUser());}} else {for (ScanResult result : preparedScans.values()) {if (createdAppId.getOrDefault(result.request.parsedPackage.getPackageName(),false)) {cleanUpAppIdCreation(result);}}// TODO(patb): create a more descriptive reason than unknown in future release// mark all non-failure installs as UNKNOWN so we do not treat them as successfor (InstallRequest request : requests) {if (request.installResult.freezer ! null) {request.installResult.freezer.close();}if (request.installResult.returnCode PackageManager.INSTALL_SUCCEEDED) {request.installResult.returnCode PackageManager.INSTALL_UNKNOWN;}}}Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}}参数requests是List类型是个集合代表它可以安装1个或者多个应用每个应用安装对应一个InstallRequest。通过注释可以看到将安装分成了4个阶段准备、浏览、协调、提交。当然翻译不一定准确这里就这样称呼它们。 开始时按照参数requests的数量生成了好几个ArrayMap对象。prepareResults里的是准备阶段返回的结果preparedScans里面是浏览阶段返回的结果installArgs则是安装参数installResults是安装结果versionInfos里面放的是和存储卷相关的版本信息。lastStaticSharedLibSettings存放的则是最新版本的静态库对应的PackageSetting对象。createdAppId则是存放的对应应用的AppId是否创建。 下面根据请求数组进行遍历。 preparePackageLI(request.args, request.installResult)是准备阶段的实现具体见 Android 安装应用-准备阶段。如果准备阶段抛出异常PrepareFailure将失败信息收集到request.installResult中。然后就直接整个返回不再向下进行。如果没有抛出异常将安装成功PackageManager.INSTALL_SUCCEEDED设置到request.installResult的返回代码中。然后收集准备结果安装结果安装参数都是以包名为key。 scanPackageTracedLI()则是浏览阶段的实现具体见文章 Android 安装应用-浏览阶段。然后将浏览结果对象result收集到集合preparedScans中也是以包名作为key。继续将appId存储卷的版本信息添加到createdAppId、versionInfos中。 如果应用是静态库则得到最新版本的PackageSetting对象sharedLibLatestVersionSetting如果它不为空则将它放到lastStaticSharedLibSettings中。 下面就是退出循环了。接着使用之前的结果构造ReconcileRequest对象reconcileRequest。 下面reconcilePackagesLocked()就是协商阶段的实现详见 Android 应用安装-协调阶段。 继续构造CommitRequest对象commitRequest调用commitPackagesLocked(commitRequest)它是提交阶段的实现详见文章 Android 应用安装-提交阶段。并且将变量success true代表提交成功。 executePostCommitSteps(commitRequest)则是提交之后的操作步骤详见 Android 安装应用-提交阶段之后剩下的操作。 继续往下如果success为true则代表安装成功。继续遍历安装请求如果是增量安装则跳出循环。如果不是增量安装发送一个广播给验证者注册接收Intent.ACTION_PACKAGE_VERIFIED的广播。 如果success为false则遍历浏览结果集合如果在之前没有创建成功AppId则这里调用cleanUpAppIdCreation(result)清理Settings对象中维持的appId。 在success为false的情况下它接着遍历安装请求。将该应用对应的freezer关闭其实就是将该包从PackageManagerService对象的成员mFrozenPackages中删除。对于安装结果为PackageManager.INSTALL_SUCCEEDED的也将返回代码设置为PackageManager.INSTALL_UNKNOWN。
安装之后的处理 看下handlePackagePostInstall()的实现代码如下 private void handlePackagePostInstall(PackageInstalledInfo res, boolean killApp,boolean virtualPreload, boolean launchedForRestore, String installerPackage,IPackageInstallObserver2 installObserver, int dataLoaderType) {boolean succeeded res.returnCode PackageManager.INSTALL_SUCCEEDED;final boolean update res.removedInfo ! null res.removedInfo.removedPackage ! null;final String packageName res.name;final PackageSetting pkgSetting succeeded ? getPackageSetting(packageName) : null;final boolean removedBeforeUpdate (pkgSetting null)|| (pkgSetting.isSystem() !pkgSetting.getPathString().equals(res.pkg.getPath()));if (succeeded removedBeforeUpdate) {Slog.e(TAG, packageName was removed before handlePackagePostInstall could be executed);res.returnCode INSTALL_FAILED_PACKAGE_CHANGED;res.returnMsg Package was removed before install could complete.;// Remove the update failed packages older resources safely nowInstallArgs args res.removedInfo ! null ? res.removedInfo.args : null;if (args ! null) {synchronized (mInstallLock) {args.doPostDeleteLI(true);}}notifyInstallObserver(res, installObserver);return;}if (succeeded) {// Clear the uid cache after we installed a new package.mPerUidReadTimeoutsCache null;// Send the removed broadcastsif (res.removedInfo ! null) {res.removedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);}final String installerPackageName res.installerPackageName ! null? res.installerPackageName: res.removedInfo ! null? res.removedInfo.installerPackageName: null;synchronized (mLock) {mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers);}// Determine the set of users who are adding this package for// the first time vs. those who are seeing an update.int[] firstUserIds EMPTY_INT_ARRAY;int[] firstInstantUserIds EMPTY_INT_ARRAY;int[] updateUserIds EMPTY_INT_ARRAY;int[] instantUserIds EMPTY_INT_ARRAY;final boolean allNewUsers res.origUsers null || res.origUsers.length 0;final PackageSetting ps pkgSetting;for (int newUser : res.newUsers) {final boolean isInstantApp ps.getInstantApp(newUser);if (allNewUsers) {if (isInstantApp) {firstInstantUserIds ArrayUtils.appendInt(firstInstantUserIds, newUser);} else {firstUserIds ArrayUtils.appendInt(firstUserIds, newUser);}continue;}boolean isNew true;for (int origUser : res.origUsers) {if (origUser newUser) {isNew false;break;}}if (isNew) {if (isInstantApp) {firstInstantUserIds ArrayUtils.appendInt(firstInstantUserIds, newUser);} else {firstUserIds ArrayUtils.appendInt(firstUserIds, newUser);}} else {if (isInstantApp) {instantUserIds ArrayUtils.appendInt(instantUserIds, newUser);} else {updateUserIds ArrayUtils.appendInt(updateUserIds, newUser);}}}// Send installed broadcasts if the package is not a static shared lib.if (res.pkg.getStaticSharedLibName() null) {mProcessLoggingHandler.invalidateBaseApkHash(res.pkg.getBaseApkPath());// Send added for users that see the package for the first time// sendPackageAddedForNewUsers also deals with system appsint appId UserHandle.getAppId(res.uid);boolean isSystem res.pkg.isSystem();sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds,dataLoaderType);// Send added for users that dont see the package for the first timeBundle extras new Bundle(1);extras.putInt(Intent.EXTRA_UID, res.uid);if (update) {extras.putBoolean(Intent.EXTRA_REPLACING, true);}extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);// Send to all running apps.final SparseArrayint[] newBroadcastAllowList;synchronized (mLock) {newBroadcastAllowList mAppsFilter.getVisibilityAllowList(getPackageSettingInternal(res.name, Process.SYSTEM_UID),updateUserIds, mSettings.getPackagesLocked());}sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,extras, 0 /*flags*/,null /*targetPackage*/, null /*finishedReceiver*/,updateUserIds, instantUserIds, newBroadcastAllowList, null);if (installerPackageName ! null) {// Send to the installer, even if its not running.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,extras, 0 /*flags*/,installerPackageName, null /*finishedReceiver*/,updateUserIds, instantUserIds, null /* broadcastAllowList */, null);}// if the required verifier is defined, but, is not the installer of record// for the package, it gets notifiedfinal boolean notifyVerifier mRequiredVerifierPackage ! null !mRequiredVerifierPackage.equals(installerPackageName);if (notifyVerifier) {sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,extras, 0 /*flags*/,mRequiredVerifierPackage, null /*finishedReceiver*/,updateUserIds, instantUserIds, null /* broadcastAllowList */, null);}// If package installer is defined, notify package installer about new// app installedif (mRequiredInstallerPackage ! null) {sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND /*flags*/,mRequiredInstallerPackage, null /*finishedReceiver*/,firstUserIds, instantUserIds, null /* broadcastAllowList */, null);}// Send replaced for users that dont see the package for the first timeif (update) {sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,packageName, extras, 0 /*flags*/,null /*targetPackage*/, null /*finishedReceiver*/,updateUserIds, instantUserIds, res.removedInfo.broadcastAllowList,null);if (installerPackageName ! null) {sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,extras, 0 /*flags*/,installerPackageName, null /*finishedReceiver*/,updateUserIds, instantUserIds, null /*broadcastAllowList*/, null);}if (notifyVerifier) {sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,extras, 0 /*flags*/,mRequiredVerifierPackage, null /*finishedReceiver*/,updateUserIds, instantUserIds, null /*broadcastAllowList*/, null);}sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,null /*package*/, null /*extras*/, 0 /*flags*/,packageName /*targetPackage*/,null /*finishedReceiver*/, updateUserIds, instantUserIds,null /*broadcastAllowList*/,getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED).toBundle());} else if (launchedForRestore !res.pkg.isSystem()) {// First-install and we did a restore, so were responsible for the// first-launch broadcast.if (DEBUG_BACKUP) {Slog.i(TAG, Post-restore of packageName sending FIRST_LAUNCH in Arrays.toString(firstUserIds));}sendFirstLaunchBroadcast(packageName, installerPackage,firstUserIds, firstInstantUserIds);}// Send broadcast package appeared if external for all usersif (res.pkg.isExternalStorage()) {if (!update) {final StorageManager storage mInjector.getSystemService(StorageManager.class);VolumeInfo volume storage.findVolumeByUuid(res.pkg.getStorageUuid().toString());int packageExternalStorageType getPackageExternalStorageType(volume, res.pkg.isExternalStorage());// If the package was installed externally, log it.if (packageExternalStorageType ! StorageEnums.UNKNOWN) {FrameworkStatsLog.write(FrameworkStatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,packageExternalStorageType, packageName);}}if (DEBUG_INSTALL) {Slog.i(TAG, upgrading pkg res.pkg is external);}final int[] uidArray new int[]{res.pkg.getUid()};ArrayListString pkgList new ArrayList(1);pkgList.add(packageName);sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);}} else if (!ArrayUtils.isEmpty(res.libraryConsumers)) { // if static shared libint[] allUsers mInjector.getUserManagerService().getUserIds();for (int i 0; i res.libraryConsumers.size(); i) {AndroidPackage pkg res.libraryConsumers.get(i);// send broadcast that all consumers of the static shared library have changedsendPackageChangedBroadcast(pkg.getPackageName(), false /* dontKillApp */,new ArrayList(Collections.singletonList(pkg.getPackageName())),pkg.getUid(), null);}}// Work that needs to happen on first install within each userif (firstUserIds ! null firstUserIds.length 0) {for (int userId : firstUserIds) {restorePermissionsAndUpdateRolesForNewUserInstall(packageName,pkgSetting.getInstallReason(userId), userId);}}if (allNewUsers !update) {notifyPackageAdded(packageName, res.uid);} else {notifyPackageChanged(packageName, res.uid);}// Log current value of unknown sources settingEventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,getUnknownSourcesSettings());// Remove the replaced packages older resources safely nowInstallArgs args res.removedInfo ! null ? res.removedInfo.args : null;if (args ! null) {if (!killApp) {// If we didnt kill the app, defer the deletion of code/resource files, since// they may still be in use by the running application. This mitigates problems// in cases where resources or code is loaded by a new Activity before// ApplicationInfo changes have propagated to all application threads.scheduleDeferredNoKillPostDelete(args);} else {synchronized (mInstallLock) {args.doPostDeleteLI(true);}}} else {// Force a gc to clear up things. Ask for a background one, its fine to go on// and not block here.VMRuntime.getRuntime().requestConcurrentGC();}// Notify DexManager that the package was installed for new users.// The updated users should already be indexed and the package code paths// should not change.// Dont notify the manager for ephemeral apps as they are not expected to// survive long enough to benefit of background optimizations.for (int userId : firstUserIds) {PackageInfo info getPackageInfo(packageName, /*flags*/ 0, userId);// Theres a race currently where some install events may interleave with an// uninstall. This can lead to package info being null (b/36642664).if (info ! null) {mDexManager.notifyPackageInstalled(info, userId);}}}final boolean deferInstallObserver succeeded update !killApp;if (deferInstallObserver) {scheduleDeferredNoKillInstallObserver(res, installObserver);} else {notifyInstallObserver(res, installObserver);}}succeeded为true代表安装成功update为true代表是更新升级。removedBeforeUpdate代表更新失败或者是系统应用包更新但是PackageSetting对象的文件路径和文件安装路径不一致代表更新之前需要删除。 如果succeeded为true并且removedBeforeUpdate也为true的情况会将res.returnCode INSTALL_FAILED_PACKAGE_CHANGED将安装成功的返回码改成安装失败。并且如果res.removedInfo.args不为null的情况下会执行删除旧包路径及其包下面内容。接着调用notifyInstallObserver(res, installObserver)执行回调。 接下来succeeded如果为true代表着安装成功的情况。在res.removedInfo不为null的情况下将调用它的sendPackageRemovedBroadcasts(killApp, false)发送包被删除的广播。在前面 Android 安装应用-准备阶段 中会在更新安装的情况下初始化res.removedInfo更新安装涉及到旧包的删除这里会发送包被删除的广播。res.removedInfo是PackageRemovedInfo对象所以会调用它的sendPackageRemovedBroadcasts(killApp, false)方法它会向能看到它的普通应用发送Intent.ACTION_PACKAGE_REMOVED广播向安装该应用的应用发送Intent.ACTION_PACKAGE_REMOVED广播。向平台包应用包名为android发送Intent.ACTION_PACKAGE_REMOVED_INTERNAL广播。如果数据都被删除并且不是系统应用包更新的情况它会向能看到它的普通应用发送Intent.ACTION_PACKAGE_FULLY_REMOVED广播。它还会向能看到它的普通应用发送Intent.ACTION_UID_REMOVED广播。 下面的四个数组变量firstUserIds、firstInstantUserIds、updateUserIds、instantUserIds是和用户有关前面两个是首次添加该包的用户分普通应用安装和Instant安装后面两个是之前就添加过该包的用户现在更新安装依然存在的用户。res.origUsers就是之前添加过该包的用户res.newUsers则是目前更新添加该包的用户。这块处理的逻辑就是res.origUsers不存在res.newUsers存在的就放入firstUserIds或firstInstantUserIds中res.origUsers存在res.newUsers存在的就放入updateUserIds或instantUserIds中。 res.pkg.getStaticSharedLibName() null代表安装应用不是静态分享包在该种情况下sendPackageAddedForNewUsers()方法会向firstUserIds或firstInstantUserIds对应的能看到的普通应用发送Intent.ACTION_PACKAGE_ADDED广播。对于这些首次添加该包的用户如果应用是系统应用或者虚拟预加载的如果这些用户是运行状态它会该用户的应用发送Intent.ACTION_LOCKED_BOOT_COMPLETED广播如果该用户没有被锁定它还会发送Intent.ACTION_BOOT_COMPLETED广播。 下面还会接着处理应用不是静态分享包时还会向updateUserIds或instantUserIds中的普通应用发送Intent.ACTION_PACKAGE_ADDED广播。如果安装者应用不为null向它发送Intent.ACTION_PACKAGE_ADDED广播。如果mRequiredVerifierPackage不为null并且它不为安装者应用则它向mRequiredVerifierPackage发送Intent.ACTION_PACKAGE_ADDED广播。如果包安装者定义了mRequiredInstallerPackage ! null会向它发送Intent.ACTION_PACKAGE_ADDED广播。 如果是在更新安装的情况下它会向updateUserIds或instantUserIds应用中的普通应用发送Intent.ACTION_PACKAGE_REPLACED广播如果安装者应用不为null向它发送Intent.ACTION_PACKAGE_REPLACED广播如果mRequiredVerifierPackage不为null并且它不为安装者应用则它向mRequiredVerifierPackage发送Intent.ACTION_PACKAGE_REPLACED广播。它还会向自己发送Intent.ACTION_MY_PACKAGE_REPLACED广播。 如果不是更新安装是恢复数据的普通应用它将向第一次添加该包的用户的安装它的应用包发送Intent.ACTION_PACKAGE_FIRST_LAUNCH广播。 接下来如果包是在外部存储空间中它将发送Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE广播将该应用发生了变化进行通知。 下面进入else if (!ArrayUtils.isEmpty(res.libraryConsumers))分支意味着它是一个库被别的应用引用res.libraryConsumers就是引用它的应用。它会发送Intent.ACTION_PACKAGE_CHANGED广播通知其他能看到引用库的应用的其他普通应用发生了变化。 在安装的过程中如果有新增的用户会执行恢复新增用户的运行时权限更新对应用户的更喜欢的Activity。 在allNewUsers为trueupdate为false的情况下代表第一次安装会通过notifyPackageAdded(packageName, res.uid)调用成员变量mPackageListObservers中的onPackageAdded接口。其他情况下会调用成员变量mPackageListObservers中的onPackageChanged接口。 如果res.removedInfo.args不为null会调用它的doPostDeleteLI(true)执行删除资源和代码。不过如果设置了不杀死应用的情况会调用scheduleDeferredNoKillPostDelete(args)延迟删除。 对于新增的用户调用mDexManager.notifyPackageInstalled(info, userId)通知包安装了。 最后就是处理返回结果。不过也分是否杀死应用两种情况如果是不杀死应用的情况也是延迟消息处理。最后都是通过调用notifyInstallObserver(res, installObserver)来处理。
将处理结果返回给应用 notifyInstallObserver(res, installObserver)的代码如下 private void notifyInstallObserver(PackageInstalledInfo info,IPackageInstallObserver2 installObserver) {if (installObserver ! null) {try {Bundle extras extrasForInstallResult(info);installObserver.onPackageInstalled(info.name, info.returnCode,info.returnMsg, extras);} catch (RemoteException e) {Slog.i(TAG, Observer no longer exists.);}}}可见是通过参数IPackageInstallObserver2 类型的onPackageInstalled接口返回。这个回调接口是来自安装参数FileInstallArgs类对象的成员变量observer。它又来自InstallParams类对象的observer。InstallParams类对象的创建来自PackageInstallerSession的makeInstallParams()。 Nullableprivate PackageManagerService.InstallParams makeInstallParams()throws PackageManagerException {……final IPackageInstallObserver2 localObserver new IPackageInstallObserver2.Stub() {Overridepublic void onUserActionRequired(Intent intent) {throw new IllegalStateException();}Overridepublic void onPackageInstalled(String basePackageName, int returnCode, String msg,Bundle extras) {if (isStaged()) {sendUpdateToRemoteStatusReceiver(returnCode, msg, extras);} else {// Weve reached point of no return; call into PMS to install the stage.// Regardless of success or failure we always destroy session.destroyInternal();dispatchSessionFinished(returnCode, msg, extras);}}};……synchronized (mLock) {return mPm.new InstallParams(stageDir, localObserver, params, mInstallSource, user,mSigningDetails, mInstallerUid, mPackageLite);}} IPackageInstallObserver2 对象是通过构造InstallParams对象时作为参数传递过去的。 isStaged()代表这个安装是需要重启才执行安装。普通应用的安装是走else分支。 destroyInternal()是用来销毁session因为目前已经安装完毕有结果了。 dispatchSessionFinished(returnCode, msg, extras)用来派发结果。看一下它的代码 private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {sendUpdateToRemoteStatusReceiver(returnCode, msg, extras);synchronized (mLock) {mFinalStatus returnCode;mFinalMessage msg;}final boolean success (returnCode INSTALL_SUCCEEDED);// Send broadcast to default launcher only if its a new install// TODO(b/144270665): Secure the usage of this broadcast.final boolean isNewInstall extras null || !extras.getBoolean(Intent.EXTRA_REPLACING);if (success isNewInstall mPm.mInstallerService.okToSendBroadcasts()) {mPm.sendSessionCommitBroadcast(generateInfoScrubbed(true /*icon*/), userId);}mCallback.onSessionFinished(this, success);if (isDataLoaderInstallation()) {logDataLoaderInstallationSession(returnCode);}}sendUpdateToRemoteStatusReceiver(returnCode, msg, extras)是向应用端发送广播安装结果。 给mFinalStatus、mFinalMessage赋值存放结果。 如果是新安装就是不是更新安装并且安装成功的情况下mPm.sendSessionCommitBroadcast(generateInfoScrubbed(true /icon/), userId)会发送对应的广播。 mCallback.onSessionFinished(this, success)主要是Session已经完成了所以需要将它去除。 咱们这里主要看看sendUpdateToRemoteStatusReceiver(returnCode, msg, extras)代码如下 private void sendUpdateToRemoteStatusReceiver(int returnCode, String msg, Bundle extras) {final IntentSender statusReceiver;final String packageName;synchronized (mLock) {statusReceiver mRemoteStatusReceiver;packageName mPackageName;}if (statusReceiver ! null) {// Execute observer.onPackageInstalled on different thread as we dont want callers// inside the system server have to worry about catching the callbacks while they are// calling into the sessionfinal SomeArgs args SomeArgs.obtain();args.arg1 packageName;args.arg2 msg;args.arg3 extras;args.arg4 statusReceiver;args.argi1 returnCode;mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget();}}这里的mRemoteStatusReceiver就是在 Android 安装过程一 界面跳转 中InstallInstalling Activity中session.commit(pendingIntent.getIntentSender())里的pendingIntent.getIntentSender()。pendingIntent是待发送的BROADCAST_ACTION广播详见Android 安装过程一 界面跳转它的接收是在安装进程中的InstallEventReceiver中它是配置在Manifest文件中。 在这里是通过消息MSG_ON_PACKAGE_INSTALLED的处理它的处理是在sendOnPackageInstalled()中看一下 private static void sendOnPackageInstalled(Context context, IntentSender target, int sessionId,boolean showNotification, int userId, String basePackageName, int returnCode,String msg, Bundle extras) {if (INSTALL_SUCCEEDED returnCode showNotification) {boolean update (extras ! null) extras.getBoolean(Intent.EXTRA_REPLACING);Notification notification PackageInstallerService.buildSuccessNotification(context,context.getResources().getString(update ? R.string.package_updated_device_owner :R.string.package_installed_device_owner),basePackageName,userId);if (notification ! null) {NotificationManager notificationManager (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);notificationManager.notify(basePackageName,SystemMessageProto.SystemMessage.NOTE_PACKAGE_STATE,notification);}}final Intent fillIn new Intent();fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);fillIn.putExtra(PackageInstaller.EXTRA_STATUS,PackageManager.installStatusToPublicStatus(returnCode));fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,PackageManager.installStatusToString(returnCode, msg));fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);if (extras ! null) {final String existing extras.getString(PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);if (!TextUtils.isEmpty(existing)) {fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);}}try {target.sendIntent(context, 0, fillIn, null, null);} catch (IntentSender.SendIntentException ignored) {}}这里就是发送了BROADCAST_ACTION广播咱们再看看安装进程中的接收者的处理。 安装进程中的接收者的处理是在EventResultPersister中的onEventReceived()中代码如下 void onEventReceived(NonNull Context context, NonNull Intent intent) {int status intent.getIntExtra(PackageInstaller.EXTRA_STATUS, 0);if (status PackageInstaller.STATUS_PENDING_USER_ACTION) {context.startActivity(intent.getParcelableExtra(Intent.EXTRA_INTENT));return;}int id intent.getIntExtra(EXTRA_ID, 0);String statusMessage intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);int legacyStatus intent.getIntExtra(PackageInstaller.EXTRA_LEGACY_STATUS, 0);EventResultObserver observerToCall null;synchronized (mLock) {int numObservers mObservers.size();for (int i 0; i numObservers; i) {if (mObservers.keyAt(i) id) {observerToCall mObservers.valueAt(i);mObservers.removeAt(i);break;}}if (observerToCall ! null) {observerToCall.onResult(status, legacyStatus, statusMessage);} else {mResults.put(id, new EventResult(status, legacyStatus, statusMessage));writeState();}}}注册的回调在成员变量mObservers它是SparseArray类型。接收到广播之后通过参数id来找到对应的回调函数就可以回调对应的函数了。 再看一下它的注册回调也是在InstallInstalling Activity中如下 mInstallId InstallEventReceiver.addObserver(this, EventResultPersister.GENERATE_NEW_ID,this::launchFinishBasedOnResult)所以最后会调用launchFinishBasedOnResult(int statusCode, int legacyStatus, String statusMessage)方法再显示对应的界面。详见Android 安装过程一 界面跳转。
总结 安装这个过程还是挺复杂的最主要的是它将之分成4个阶段准备、浏览、协调、提交。每个步骤中都有好多代码并且代码中处理不是只针对普通应用的安装它是包括其他形式安装的处理该文章主要是有关普通应用的安装还是结合了前面文章的例子将所有的流程过了一遍其中的相关细节还没有深究留待后续继续琢磨。