#1 安装方式

  • 1 安装系统APK和预制APK时,通过PMS的构造函数中安装,即第一次开机时安装应用,没有安装界面。
  • 2 网络下载安装,通过应用商店等,即调用PackageManager.installPackages(),有安装界面。
  • 3 通过adb工具安装,没有安装界面,它通过启动pm脚本的形式,然后调用com.android.commands.pm.Pm类,之后调用到PMS.installStage()完成安装。
  • 4 安装本地apk,有安装界面,由PackageInstaller系统应用安装。

    上述几种方式均通过PackageInstallObserver来监听安装是否成功。

#2 安装流程分析

2.1 首次安装

首次安装即系统第一次开机时安装应用,包括系统应用和预制应用,其最主要过程在PMS构造函数中,

整个过程关键步骤大致为上述15步,与应用安装相关实际上就是扫描和安装两步。方法调用时序图如图1所示。

[图1 PMS安装应用时序图]

  • 1 向动态设置中添加系统默认的共享ID(system、phone、log、nfc、bluetooth、shell、se等)。
  • 2 初始化成员变量,如Installer、PackageDexOptimizer、DexManager、ArtManagerService、MoveCallbacks、OnPermissionChangeListeners等,并获取系统配置。
  • 3 启动一个服务类线程。
  • 4 初始化用户管理服务
  • 5 将权限配置传入包管理器
  • 6 清除代码路径不存在的孤立包
  • 7 将系统应用权限从安装态升级为运行时
  • 8 在扫描应用前,手机供应商的覆盖安装包(/overlay)
  • 9 扫描应用目录,依次为特权系统目录 priv-app、普通目录 app、供应商系统目录 vendor/app等
  • 10 解析存储管理器
  • 11 如果是第一次开机,需要初始化用户的默认偏好应用
  • 12 在启动时,为用户准备好存储空间,因为SystemUI等启动不能等待用户
  • 13 安装应用,完成后检查webview,默认浏览器等。
  • 14 启动PackageInstallerService
  • 15 向系统组件暴露私有服务

    下面我们结合代码做详细分析
  1. 判断应用包是否已安装,如果包名存在于uninstalled_deapp.xml中或者已安装,则直接返回null。

2.2 下载安装

下载安装可分为两部分:拷贝应用和安装应用。拷贝过程的函数调用时序图如图2所示。

【图2 下载安装应用程序时序图】

frameworks层的入口函数为PackageManager.installPackage,由应用市场APP调用,然后调用PMS.installPackageAsUser,然后发送消息INIT_COPY、MCS_BOUND开始复制,调用HandlerParams.startCopy。这个方法主要分两部分,一部分是拷贝应用的执行程序,另一部分是创建应用的数据目录,拷贝部分由handleStartCopy完成。之后调用handlerReturnCode来处理创建数据目录。拷贝部分会调用DefaultContainerService来完成,该服务为那些可能位于可删除空间上的文件提供检查和拷贝功能。当底层设置被移除时,这样设计可以防止系统进程保留打开的文件时,不被内核杀死。

handleStartcopy实现在PMS内部类InstallParams中,它的功能是调用远程方法获取包信息和安装位置,如有必要则给与默认车辆覆盖安装位置,然后基于安装位置创建安装参数。下面我们结合关键代码做进一步分析。

首先是拷贝应用过程

  • 1 PMS.installPackageAsUser的功能主要是:根据uid确定installFlags,并校验权限,并构造InstallParam,然后发送INIT_COPY消息。
  1. @Override
  2. public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
  3. int installFlags, String installerPackageName, int userId) {
  4. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
  5. final int callingUid = Binder.getCallingUid();
  6. enforceCrossUserPermission(callingUid, userId,
  7. true /* requireFullPermission */, true /* checkShell */, "installPackageAsUser");
  8. if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
  9. try {
  10. if (observer != null) {
  11. observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);
  12. }
  13. } catch (RemoteException re) {
  14. }
  15. return;
  16. }
  17. if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
  18. installFlags |= PackageManager.INSTALL_FROM_ADB;
  19. } else {
  20. // Caller holds INSTALL_PACKAGES permission, so we're less strict
  21. // about installerPackageName.
  22. installFlags &= ~PackageManager.INSTALL_FROM_ADB;
  23. installFlags &= ~PackageManager.INSTALL_ALL_USERS;
  24. }
  25. UserHandle user;
  26. if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
  27. user = UserHandle.ALL;
  28. } else {
  29. user = new UserHandle(userId);
  30. }
  31. // Only system components can circumvent runtime permissions when installing.
  32. if ((installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
  33. && mContext.checkCallingOrSelfPermission(Manifest.permission
  34. .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
  35. throw new SecurityException("You need the "
  36. + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
  37. + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
  38. }
  39. if ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
  40. || (installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
  41. throw new IllegalArgumentException(
  42. "New installs into ASEC containers no longer supported");
  43. }
  44. final File originFile = new File(originPath);
  45. final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
  46. final Message msg = mHandler.obtainMessage(INIT_COPY);
  47. final VerificationInfo verificationInfo = new VerificationInfo(
  48. null /*originatingUri*/, null /*referrer*/, -1 /*originatingUid*/, callingUid);
  49. final InstallParams params = new InstallParams(origin, null /*moveInfo*/, observer,
  50. installFlags, installerPackageName, null /*volumeUuid*/, verificationInfo, user,
  51. null /*packageAbiOverride*/, null /*grantedPermissions*/,
  52. null /*certificates*/, PackageManager.INSTALL_REASON_UNKNOWN);
  53. params.setTraceMethod("installAsUser").setTraceCookie(System.identityHashCode(params));
  54. msg.obj = params;
  55. Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installAsUser",
  56. System.identityHashCode(msg.obj));
  57. Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
  58. System.identityHashCode(msg.obj));
  59. mHandler.sendMessage(msg);
  60. }
  • 2 之后根据Handler.doHandleMessage调用到InstallParams.handleStartCopy方法,首先检查文件和cid是否已生成,如生成则设置installFlags。
  1. // [InstallParams.handleStartCopy]
  2. if (origin.staged) {
  3. if (origin.file != null) {
  4. installFlags |= PackageManager.INSTALL_INTERNAL;
  5. installFlags &= ~PackageManager.INSTALL_EXTERNAL;
  6. } else if (origin.cid != null) {
  7. installFlags |= PackageManager.INSTALL_EXTERNAL;
  8. installFlags &= ~PackageManager.INSTALL_INTERNAL;
  9. } else {
  10. throw new IllegalStateException("Invalid stage location");
  11. }
  12. }
  • 3 然后检查空间大小,如果空间不够则释放无用空间。
  1. // [InstallParams.handleStartCopy]
  2. if (!origin.staged && pkgLite.recommendedInstallLocation
  3. == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
  4. // TODO: focus freeing disk space on the target device
  5. final StorageManager storage = StorageManager.from(mContext);
  6. final long lowThreshold = storage.getStorageLowBytes(
  7. Environment.getDataDirectory());
  8. final long sizeBytes = mContainerService.calculateInstalledSize(
  9. origin.resolvedPath, isForwardLocked(), packageAbiOverride);
  10. try {
  11. mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
  12. pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
  13. installFlags, packageAbiOverride);
  14. } catch (InstallerException e) {
  15. Slog.w(TAG, "Failed to free cache", e);
  16. }
  17. if (pkgLite.recommendedInstallLocation
  18. == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
  19. pkgLite.recommendedInstallLocation
  20. = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
  21. }
  22. }
  • 4 覆盖原有安装位置的文件,并根据返回结果来确定函数的返回值,并设置installFlags。
  1. // [InstallParams.handleStartCopy]
  2. // Override with defaults if needed.
  3. loc = installLocationPolicy(pkgLite);
  4. if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
  5. ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
  6. } else if (!onSd && !onInt) {
  7. // Override install location with flags
  8. if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
  9. // Set the flag to install on external media.
  10. installFlags |= PackageManager.INSTALL_EXTERNAL;
  11. installFlags &= ~PackageManager.INSTALL_INTERNAL;
  12. } else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {
  13. if (DEBUG_EPHEMERAL) {
  14. Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
  15. }
  16. installFlags |= PackageManager.INSTALL_INSTANT_APP;
  17. installFlags &= ~(PackageManager.INSTALL_EXTERNAL
  18. |PackageManager.INSTALL_INTERNAL);
  19. } else {
  20. // Make sure the flag for installing on external
  21. // media is unset
  22. installFlags |= PackageManager.INSTALL_INTERNAL;
  23. installFlags &= ~PackageManager.INSTALL_EXTERNAL;
  24. }
  25. }
  • 5 确定是否有任何已安装的包验证器,如有,则延迟检测。主要分三步:首先新建一个验证Intent,然后设置相关的信息,之后获取验证器列表,最后向每个验证器发送验证Intent。
  1. // [InstallParams.handleStartCopy]
  2. final Intent verification = new Intent( //构造验证Intent
  3. Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
  4. // ......
  5. final PackageVerificationState verificationState = new PackageVerificationState(
  6. requiredUid, args);
  7. mPendingVerification.append(verificationId, verificationState);
  8. // 获取验证器列表
  9. final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
  10. receivers, verificationState);
  11. DeviceIdleController.LocalService idleController = getDeviceIdleController();
  12. final long idleDuration = getVerificationTimeout();
  13. /*
  14. * If any sufficient verifiers were listed in the package
  15. * manifest, attempt to ask them.
  16. */
  17. if (sufficientVerifiers != null) {
  18. final int N = sufficientVerifiers.size();
  19. if (N == 0) {
  20. Slog.i(TAG, "Additional verifiers required, but none installed.");
  21. ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
  22. } else {
  23. for (int i = 0; i < N; i++) {
  24. final ComponentName verifierComponent = sufficientVerifiers.get(i);
  25. idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
  26. verifierComponent.getPackageName(), idleDuration,
  27. verifierUser.getIdentifier(), false, "package verifier");
  28. // 向每个验证器发送验证Intent
  29. final Intent sufficientIntent = new Intent(verification);
  30. sufficientIntent.setComponent(verifierComponent);
  31. mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);
  32. }
  33. }
  34. }
  • 6 向验证器客户端发送intent,只有当验证成功之后才会开启copy工作。如果没有任何验证器则直接拷贝。

下面为安装过程入口是PMS.processPendingInstall方法,调用时序图如图3

【图3 下载安装-安装过程图】

  • 1 首先启动一个新线程,然后设置安装信息,处理安装参数,开始安装,并发送关于安装状态的广播,然后处理安装完的事情,比如打印错误信息,清除临时文件等。
  1. private void processPendingInstall(final InstallArgs args, final int currentStatus) {
  2. // Queue up an async operation since the package installation may take a little while.
  3. mHandler.post(new Runnable() {
  4. public void run() {
  5. mHandler.removeCallbacks(this);
  6. // Result object to be returned
  7. PackageInstalledInfo res = new PackageInstalledInfo();
  8. res.setReturnCode(currentStatus);
  9. res.uid = -1;
  10. res.pkg = null;
  11. res.removedInfo = null;
  12. if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
  13. args.doPreInstall(res.returnCode);
  14. synchronized (mInstallLock) {
  15. installPackageTracedLI(args, res);
  16. }
  17. args.doPostInstall(res.returnCode, res.uid);
  18. //......
  19. }
  • 2 installPackageTracedLI是安装过程的核心方法,然后调用installPackageLI.首先检查安装包的完整性并解析安装包。
  1. //[PMS.installPackageLI]
  2. // 完整性校验
  3. if (instantApp && (forwardLocked || onExternal)) {
  4. Slog.i(TAG, "Incompatible ephemeral install; fwdLocked=" + forwardLocked
  5. + " external=" + onExternal);
  6. res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
  7. return;
  8. }
  9. // 检索包设置,并解析应用
  10. final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
  11. | PackageParser.PARSE_ENFORCE_CODE
  12. | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
  13. | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0)
  14. | (instantApp ? PackageParser.PARSE_IS_EPHEMERAL : 0)
  15. | (forceSdk ? PackageParser.PARSE_FORCE_SDK : 0);
  16. PackageParser pp = new PackageParser();
  17. pp.setSeparateProcesses(mSeparateProcesses);
  18. pp.setDisplayMetrics(mMetrics);
  19. pp.setCallback(mPackageParserCallback);
  20. Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
  21. final PackageParser.Package pkg;
  22. try {
  23. //解析安装包
  24. pkg = pp.parsePackage(tmpPackageFile, parseFlags);
  25. DexMetadataHelper.validatePackageDexMetadata(pkg);
  26. } catch (PackageParserException e) {
  27. res.setError("Failed parse during installPackageLI", e);
  28. return;
  29. } finally {
  30. Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
  31. }
  • 3 检查SDK版本和沙箱版本,同时检查是否有静态共享库,如有则需要放在内部存储中。
  1. //[PMS.installPackageLI]
  2. //检查SDK版本和沙箱版本
  3. if (instantApp && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
  4. Slog.w(TAG, "Instant app package " + pkg.packageName + " does not target O");
  5. res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
  6. "Instant app package must target O");
  7. return;
  8. }
  9. if (instantApp && pkg.applicationInfo.targetSandboxVersion != 2) {
  10. Slog.w(TAG, "Instant app package " + pkg.packageName
  11. + " does not target targetSandboxVersion 2");
  12. res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
  13. "Instant app package must use targetSanboxVersion 2");
  14. return;
  15. }
  16. //检查是否有静态共享库
  17. if (pkg.applicationInfo.isStaticSharedLibrary()) {
  18. // Static shared libraries have synthetic package names
  19. renameStaticSharedLibraryPackage(pkg);
  20. // No static shared libs on external storage
  21. if (onExternal) {
  22. Slog.i(TAG, "Static shared libs can only be installed on internal storage.");
  23. res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
  24. "Packages declaring static-shared libs cannot be updated");
  25. return;
  26. }
  27. }
  • 4 检查是否有子安装包,如有则子安装包也需要检测。
  1. //[PMS.installPackageLI]
  2. // If we are installing a clustered package add results for the children
  3. if (pkg.childPackages != null) {
  4. synchronized (mPackages) {
  5. final int childCount = pkg.childPackages.size();
  6. for (int i = 0; i < childCount; i++) {
  7. PackageParser.Package childPkg = pkg.childPackages.get(i);
  8. PackageInstalledInfo childRes = new PackageInstalledInfo();
  9. childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
  10. childRes.pkg = childPkg;
  11. childRes.name = childPkg.packageName;
  12. PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
  13. if (childPs != null) {
  14. childRes.origUsers = childPs.queryInstalledUsers(
  15. sUserManager.getUserIds(), true);
  16. }
  17. if ((mPackages.containsKey(childPkg.packageName))) {
  18. childRes.removedInfo = new PackageRemovedInfo(this);
  19. childRes.removedInfo.removedPackage = childPkg.packageName;
  20. childRes.removedInfo.installerPackageName = childPs.installerPackageName;
  21. }
  22. if (res.addedChildPackages == null) {
  23. res.addedChildPackages = new ArrayMap<>();
  24. }
  25. res.addedChildPackages.put(childPkg.packageName, childRes);
  26. }
  27. }
  28. }
  • 5 检查安装包是否已存在,如已存在则需要检查旧的父包、沙箱、sdk等是否已为空,否则会报错。
  • 6 校验安装包签名
  1. //[PMS.installPackageLI]
  2. PackageSetting signatureCheckPs = ps;
  3. if (pkg.applicationInfo.isStaticSharedLibrary()) {
  4. SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg);
  5. if (libraryEntry != null) {
  6. signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk);
  7. }
  8. }
  9. // Quick sanity check that we're signed correctly if updating;
  10. // we'll check this again later when scanning, but we want to
  11. // bail early here before tripping over redefined permissions.
  12. if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) {
  13. if (!checkUpgradeKeySetLP(signatureCheckPs, pkg)) {
  14. res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
  15. + pkg.packageName + " upgrade keys do not match the "
  16. + "previously installed version");
  17. return;
  18. }
  19. } else {
  20. try {
  21. verifySignaturesLP(signatureCheckPs, pkg);
  22. } catch (PackageManagerException e) {
  23. res.setError(e.error, e.getMessage());
  24. return;
  25. }
  26. }
  • 7 设置相关的全向,包括生成权限、移植权限等
  • 8 如果这是一个系统应用,则检查是否在外部存储上或是是否被其他应用替换等
  1. //[PMS.installPackageLI]
  2. if (systemApp) {
  3. if (onExternal) {
  4. // Abort update; system app can't be replaced with app on sdcard
  5. res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
  6. "Cannot install updates to system apps on sdcard");
  7. return;
  8. } else if (instantApp) {
  9. // Abort update; system app can't be replaced with an instant app
  10. res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
  11. "Cannot update a system app with an instant app");
  12. return;
  13. }
  14. }
  • 9 生成安装包Abi(Application binary interface,应用二进制接口,描述应用程序和操作系统之间或其他应用程序的低级接口)
  1. //[PMS.installPackageLI]
  2. try {
  3. String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
  4. args.abiOverride : pkg.cpuAbiOverride);
  5. final boolean extractNativeLibs = !pkg.isLibrary();
  6. derivePackageAbi(pkg, new File(pkg.codePath), abiOverride,
  7. extractNativeLibs, mAppLib32InstallDir);
  8. } catch (PackageManagerException pme) {
  9. Slog.e(TAG, "Error deriving application ABI", pme);
  10. res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
  11. return;
  12. }
  • 10更新共享库
  1. //[PMS.installPackageLI]
  2. synchronized (mPackages) {
  3. try {
  4. updateSharedLibrariesLPr(pkg, null);
  5. } catch (PackageManagerException e) {
  6. Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
  7. }
  8. }
  • 11如有必要,优化dex文件
  1. //[PMS.installPackageLI]
  2. final boolean performDexopt = (res.returnCode == PackageManager.INSTALL_SUCCEEDED)
  3. && !forwardLocked
  4. && !pkg.applicationInfo.isExternalAsec()
  5. && (!instantApp || Global.getInt(mContext.getContentResolver(),
  6. Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
  7. && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
  8. if (performDexopt) {
  9. Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
  10. // Do not run PackageDexOptimizer through the local performDexOpt
  11. // method because `pkg` may not be in `mPackages` yet.
  12. //
  13. // Also, don't fail application installs if the dexopt step fails.
  14. DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,
  15. REASON_INSTALL,
  16. DexoptOptions.DEXOPT_BOOT_COMPLETE |
  17. DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
  18. mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
  19. null /* instructionSets */,
  20. getOrCreateCompilerPackageStats(pkg),
  21. mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
  22. dexoptOptions);
  23. Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
  24. }
  • 12替换安装,则直接安装新包,这里应用时生成应用数据目录。ps:替换安装:其主要过程为更新设置,清除原有的某些APP数据,重新生成相关的app数据目录等步骤,同事要区分系统应用替换和非系统应用替换。而安装新包:则直接更新设置,生成APP数据即可。
  1. try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
  2. "installPackageLI")) {
  3. if (replace) {
  4. if (pkg.applicationInfo.isStaticSharedLibrary()) {
  5. // Static libs have a synthetic package name containing the version
  6. // and cannot be updated as an update would get a new package name,
  7. // unless this is the exact same version code which is useful for
  8. // development.
  9. PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
  10. if (existingPkg != null && existingPkg.mVersionCode != pkg.mVersionCode) {
  11. res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring "
  12. + "static-shared libs cannot be updated");
  13. return;
  14. }
  15. }
  16. replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
  17. installerPackageName, res, args.installReason);
  18. } else {
  19. installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
  20. args.user, installerPackageName, volumeUuid, res, args.installReason);
  21. }
  22. }
  • 13 如果是安装一个不存在的包,则调用PMS.installNewPackageLIF方法。首先会检查是否有重复的包名,并更新设置,然后根据安装的结果,如果安装失败则删除安装过程中产生的文件。
  1. private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags,
  2. int scanFlags, UserHandle user, String installerPackageName, String volumeUuid,
  3. PackageInstalledInfo res, int installReason) {
  4. Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage");
  5. // Remember this for later, in case we need to rollback this install
  6. String pkgName = pkg.packageName;
  7. if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
  8. synchronized(mPackages) {
  9. final String renamedPackage = mSettings.getRenamedPackageLPr(pkgName);
  10. if (renamedPackage != null) {
  11. // 如果已有相同包名的应用,则报错
  12. res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
  13. + " without first uninstalling package running as "
  14. + renamedPackage);
  15. return;
  16. }
  17. if (mPackages.containsKey(pkgName)) {
  18. // Don't allow installation over an existing package with the same name.
  19. res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
  20. + " without first uninstalling.");
  21. return;
  22. }
  23. }
  24. try {
  25. PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags, System.currentTimeMillis(), user);
  26. updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason);
  27. if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
  28. prepareAppDataAfterInstallLIF(newPackage);
  29. } else {
  30. // Remove package from internal structures, but keep around any
  31. // data that might have already existed
  32. deletePackageLIF(pkgName, UserHandle.ALL, false, null,
  33. PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
  34. }
  35. } catch (PackageManagerException e) {
  36. res.setError("Package couldn't be installed in " + pkg.codePath, e);
  37. }
  38. Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
  39. }
  • 14 然后为已安装的应用准备数据目录,其依次的顺序是

    • PMS.prepareAppDataAfterInstallLIF
    • PMS.prepareAppDataLIF
    • PMS.prepareAppDataLeafLIF
    • Installer.createAppData

这个方法是PMS与Installer交互的接口函数,这里的数据目录是CE类型。

  1. private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
  2. if (DEBUG_APP_DATA) {
  3. Slog.v(TAG, "prepareAppData for " + pkg.packageName + " u" + userId + " 0x"
  4. + Integer.toHexString(flags));
  5. }
  6. final String volumeUuid = pkg.volumeUuid;
  7. final String packageName = pkg.packageName;
  8. final ApplicationInfo app = pkg.applicationInfo;
  9. final int appId = UserHandle.getAppId(app.uid);
  10. Preconditions.checkNotNull(app.seInfo);
  11. long ceDataInode = -1;
  12. try {
  13. // 调用Installd守护进程的入口
  14. ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
  15. appId, app.seInfo, app.targetSdkVersion);
  16. } catch (InstallerException e) {
  17. //......
  18. }
  19. // Prepare the application profiles.
  20. mArtManagerService.prepareAppProfiles(pkg, userId);
  21. if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {
  22. // TODO: mark this structure as dirty so we persist it!
  23. synchronized (mPackages) {
  24. final PackageSetting ps = mSettings.mPackages.get(packageName);
  25. if (ps != null) {
  26. ps.setCeDataInode(ceDataInode, userId);
  27. }
  28. }
  29. }
  30. prepareAppDataContentsLeafLIF(pkg, userId, flags);
  31. }
  • 15 如果是替换应用,一般情况是应用更新,或者是重新安装。它的主要过程包括:验证签名,如是系统更新则还需要校验hash值,检查共享ID的更改情况,不允许完整更新,更新已被删除数据,最后根据应用是否是系统应用来判断接下去的操作。
  1. private void replacePackageLIF(PackageParser.Package pkg, final int policyFlags, int scanFlags,
  2. UserHandle user, String installerPackageName, PackageInstalledInfo res,
  3. int installReason) {
  4. final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
  5. final PackageParser.Package oldPackage;
  6. final PackageSetting ps;
  7. final String pkgName = pkg.packageName;
  8. final int[] allUsers;
  9. final int[] installedUsers;
  10. // ......
  11. boolean sysPkg = (isSystemApp(oldPackage));
  12. if (sysPkg) {
  13. // Set the system/privileged flags as needed
  14. final boolean privileged =
  15. (oldPackage.applicationInfo.privateFlags
  16. & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
  17. final int systemPolicyFlags = policyFlags
  18. | PackageParser.PARSE_IS_SYSTEM
  19. | (privileged ? PackageParser.PARSE_IS_PRIVILEGED : 0);
  20. replaceSystemPackageLIF(oldPackage, pkg, systemPolicyFlags, scanFlags,
  21. user, allUsers, installerPackageName, res, installReason);
  22. } else {
  23. replaceNonSystemPackageLIF(oldPackage, pkg, policyFlags, scanFlags,
  24. user, allUsers, installerPackageName, res, installReason);
  25. }
  26. }
  • 16 最后这两个方法均会调用到PMS.prepareAppDataLeafLIF。
  • 17 安装完成后,更新设置,更新安装锁等。

2.3 adb安装

关于adb安装,其copy过程与下载安装不同,但安装过程却与下载过程是相同的,这里不做重复分析,需要注意的是adb安装是不能替换安装的,具体原因?

拷贝过程

其调用时序图如图4 所示。

【图4 adb安装-copy过程时序图】

  • 1 adb的入口在com.android.commands.pm.Pm类,那么这是如何调用到这个类的呢,这是adb命令通过adbd守护进程调用到/system/bin/pm这个脚本,其脚本源码如下:
  1. base=/system
  2. export CLASSPATh-$base/framework/pm.jar
  3. exec app_process $base/bin.com.android.commands.pm.Pm "$@"
  • 2 Pm类通过脚本启动,执行顺序是main->run->runInstall,然后提交session。
  1. public static void main(String[] args) {
  2. int exitCode = 1;
  3. try {
  4. exitCode = new Pm().run(args);
  5. } catch (Exception e) {
  6. Log.e(TAG, "Error", e);
  7. System.err.println("Error: " + e);
  8. if (e instanceof RemoteException) {
  9. System.err.println(PM_NOT_RUNNING_ERR);
  10. }
  11. }
  12. System.exit(exitCode);
  13. }
  14. public int run(String[] args) throws RemoteException {
  15. boolean validCommand = false;
  16. if (args.length < 1) {
  17. return showUsage();
  18. }
  19. mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE));
  20. mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE));
  21. mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
  22. if (mPm == null) {
  23. System.err.println(PM_NOT_RUNNING_ERR);
  24. return 1;
  25. }
  26. mInstaller = mPm.getPackageInstaller();
  27. mArgs = args;
  28. String op = args[0];
  29. mNextArg = 1;
  30. //......
  31. if ("install".equals(op)) {
  32. return runInstall();
  33. }
  34. //......
  35. }
  • 3 Pm.runInstall中首先是创建session,然后提交session,代码如下。
  1. private int runInstall() throws RemoteException {
  2. long startedTime = SystemClock.elapsedRealtime();
  3. final InstallParams params = makeInstallParams();
  4. final String inPath = nextArg();
  5. if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {
  6. File file = new File(inPath);
  7. if (file.isFile()) {
  8. try {
  9. ApkLite baseApk = PackageParser.parseApkLite(file, 0);
  10. PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
  11. null, null);
  12. params.sessionParams.setSize(
  13. PackageHelper.calculateInstalledSize(pkgLite, false,
  14. params.sessionParams.abiOverride));
  15. } catch (PackageParserException | IOException e) {
  16. System.err.println("Error: Failed to parse APK file: " + e);
  17. return 1;
  18. }
  19. } else {
  20. System.err.println("Error: Can't open non-file: " + inPath);
  21. return 1;
  22. }
  23. }
  24. final int sessionId = doCreateSession(params.sessionParams,
  25. params.installerPackageName, params.userId);
  26. try {
  27. if (inPath == null && params.sessionParams.sizeBytes == -1) {
  28. System.err.println("Error: must either specify a package size or an APK file");
  29. return 1;
  30. }
  31. if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
  32. false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
  33. return 1;
  34. }
  35. Pair<String, Integer> status = doCommitSession(sessionId, false /*logSuccess*/);
  36. if (status.second != PackageInstaller.STATUS_SUCCESS) {
  37. return 1;
  38. }
  39. Log.i(TAG, "Package " + status.first + " installed in " + (SystemClock.elapsedRealtime()
  40. - startedTime) + " ms");
  41. System.out.println("Success");
  42. return 0;
  43. } finally {
  44. try {
  45. mInstaller.abandonSession(sessionId);
  46. } catch (Exception ignore) {
  47. }
  48. }
  49. }
  • 4 这里Pm相当于客户端,接受session的服务端在PackageInstallerSession中,这里利用AIDL来完成传输,其调用过程为:

    • Pm.doCommitSession
    • PackageInstaller.Session.commit
    • IPackageInstallerSession.commit
    • PackageInstallerSession.commit
    • Handler.Callback.handleMessage
    • PackageInstallerSession.commitLock
    • PMS.installStage

以上关于session传递过程暂不分析,下面我们来详细看下installStage方法。

  • 5 installStage方法主要功能就是构造InstallParam对象,并发送INIT_COPY。
  1. void installStage(String packageName, File stagedDir, String stagedCid,
  2. IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
  3. String installerPackageName, int installerUid, UserHandle user,
  4. Certificate[][] certificates) {
  5. if (DEBUG_EPHEMERAL) {
  6. if ((sessionParams.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
  7. Slog.d(TAG, "Ephemeral install of " + packageName);
  8. }
  9. }
  10. final VerificationInfo verificationInfo = new VerificationInfo(
  11. sessionParams.originatingUri, sessionParams.referrerUri,
  12. sessionParams.originatingUid, installerUid);
  13. final OriginInfo origin;
  14. if (stagedDir != null) {
  15. origin = OriginInfo.fromStagedFile(stagedDir);
  16. } else {
  17. origin = OriginInfo.fromStagedContainer(stagedCid);
  18. }
  19. final Message msg = mHandler.obtainMessage(INIT_COPY);
  20. final int installReason = fixUpInstallReason(installerPackageName, installerUid,
  21. sessionParams.installReason);
  22. final InstallParams params = new InstallParams(origin, null, observer,
  23. sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
  24. verificationInfo, user, sessionParams.abiOverride,
  25. sessionParams.grantedRuntimePermissions, certificates, installReason);
  26. params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
  27. msg.obj = params;
  28. Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
  29. System.identityHashCode(msg.obj));
  30. Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
  31. System.identityHashCode(msg.obj));
  32. mHandler.sendMessage(msg);
  33. }
  • 6 发送完Handler消息后就与下载安装过程相同了。

2.4 本地安装

本地安装参与对象包括PackageInstaller应用,PMS两部分。下面我们就来分析下PackageInstaller是如何调用到PMS中的。函数调用时序图如图5所示。

【图5 本地安装前提调用时序图】

  • 1 点击文件管理器中的apk文件时,会调用到FolderFragment类的openFile方法,然后调用startActivitySafety方法启动PackageInstallerActivity。
  1. private void openFile(File f) {
  2. final Uri fileUri = Uri.fromFile(f);
  3. final Intent intent = new Intent();
  4. intent.setAction(android.content.Intent.ACTION_VIEW);
  5. intent.putExtra(Intent.EXTRA_TITLE, f.getName());
  6. intent.putExtra(EXTRA_ALL_VIDEO_FOLDER, true);
  7. Uri contentUri = null;
  8. String type = getMIMEType(f);
  9. //......
  10. if (contentUri != null) {
  11. intent.setDataAndType(contentUri, type);
  12. } else {
  13. intent.setDataAndType(fileUri, type);
  14. }
  15. try {
  16. startActivitySafely(intent);
  17. }
  18. //......
  19. }
  • 2 如下为PackageInstallerActivity.onCreate方法源码,其主要过程初始化各个服务的成员变量如PMS,校验session,并加载UI界面,然用户确定是否安装。
  1. //[PackageInstallerActivity.java]
  2. protected void onCreate(Bundle icicle) {
  3. super.onCreate(icicle);
  4. if (icicle != null) {
  5. mAllowUnknownSources = icicle.getBoolean(ALLOW_UNKNOWN_SOURCES_KEY);
  6. }
  7. //初始化各个关键参数
  8. mPm = getPackageManager();
  9. mIpm = AppGlobals.getPackageManager();
  10. mAppOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
  11. mInstaller = mPm.getPackageInstaller();
  12. mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
  13. final Intent intent = getIntent();
  14. mCallingPackage = intent.getStringExtra(EXTRA_CALLING_PACKAGE);
  15. mSourceInfo = intent.getParcelableExtra(EXTRA_ORIGINAL_SOURCE_INFO);
  16. mOriginatingUid = intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID,
  17. PackageInstaller.SessionParams.UID_UNKNOWN);
  18. mOriginatingPackage = (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN)
  19. ? getPackageNameForUid(mOriginatingUid) : null;
  20. final Uri packageUri;
  21. //校验session
  22. if (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(intent.getAction())) {
  23. final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);
  24. final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId);
  25. if (info == null || !info.sealed || info.resolvedBaseCodePath == null) {
  26. Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring");
  27. finish();
  28. return;
  29. }
  30. mSessionId = sessionId;
  31. packageUri = Uri.fromFile(new File(info.resolvedBaseCodePath));
  32. mOriginatingURI = null;
  33. mReferrerURI = null;
  34. } else {
  35. mSessionId = -1;
  36. packageUri = intent.getData();
  37. mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
  38. mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
  39. }
  40. // if there's nothing to do, quietly slip into the ether
  41. if (packageUri == null) {
  42. Log.w(TAG, "Unspecified source");
  43. setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI);
  44. finish();
  45. return;
  46. }
  47. if (DeviceUtils.isWear(this)) {
  48. showDialogInner(DLG_NOT_SUPPORTED_ON_WEAR);
  49. return;
  50. }
  51. boolean wasSetUp = processPackageUri(packageUri);
  52. if (!wasSetUp) {
  53. return;
  54. }
  55. // 加载UI界面
  56. bindUi(R.layout.install_confirm, false);
  57. checkIfAllowedAndInitiateInstall();
  58. }
  • 3 当用户点击安装按钮时,响应函数为PackageInstallerActivity.onClick方法,
  1. //[PackageInstallerActivity.java]
  2. public void onClick(View v) {
  3. if (v == mOk) {
  4. if (mOk.isEnabled()) {
  5. if (mOkCanInstall || mScrollView == null) {
  6. if (mSessionId != -1) {
  7. mInstaller.setPermissionsResult(mSessionId, true);
  8. finish();
  9. } else {
  10. startInstall();
  11. }
  12. } else {
  13. mScrollView.pageScroll(View.FOCUS_DOWN);
  14. }
  15. }
  16. } else if (v == mCancel) {
  17. // Cancel and finish
  18. setResult(RESULT_CANCELED);
  19. if (mSessionId != -1) {
  20. mInstaller.setPermissionsResult(mSessionId, false);
  21. }
  22. finish();
  23. }
  24. }
  • 4 之后调用 PackageInstallerActivity.startInstall方法,构造Intent,然后启动InstallInstalling,并销毁PackageInstallerActivity。
  1. private void startInstall() {
  2. // Start subactivity to actually install the application
  3. Intent newIntent = new Intent();
  4. newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
  5. mPkgInfo.applicationInfo);
  6. newIntent.setData(mPackageURI);
  7. newIntent.setClass(this, InstallInstalling.class);
  8. String installerPackageName = getIntent().getStringExtra(
  9. Intent.EXTRA_INSTALLER_PACKAGE_NAME);
  10. if (mOriginatingURI != null) {
  11. newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
  12. }
  13. if (mReferrerURI != null) {
  14. newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
  15. }
  16. if (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
  17. newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
  18. }
  19. if (installerPackageName != null) {
  20. newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
  21. installerPackageName);
  22. }
  23. if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
  24. newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
  25. newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
  26. }
  27. if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
  28. startActivity(newIntent);
  29. finish();
  30. }
  • 5 之后启动InstallInstalling,因为Activity中的默认成员方法的执行顺序是onCreate->onStart->onResume...其中onCreate的方法中主要过程包括:

    • 1 获取待安装应用信息
    • 2 根据应用安装与否决定如何调用方法
    • 3 如果已存在,则直接调用PackageManager.installExistingPackage
    • 4 如果不存在则构造session
    • 5 之后则为安装事件广播添加一个监测
  1. @Override
  2. protected void onCreate(@Nullable Bundle savedInstanceState) {
  3. super.onCreate(savedInstanceState);
  4. setContentView(R.layout.install_installing);
  5. // 获取待安装应用信息
  6. ApplicationInfo appInfo = getIntent()
  7. .getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
  8. mPackageURI = getIntent().getData();
  9. // 如果应用已存在,则使用这条路径安装
  10. if ("package".equals(mPackageURI.getScheme())) {
  11. try {
  12. getPackageManager().installExistingPackage(appInfo.packageName);
  13. launchSuccess();
  14. } catch (PackageManager.NameNotFoundException e) {
  15. launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
  16. }
  17. } else { //否则使用session提交安装应用
  18. final File sourceFile = new File(mPackageURI.getPath());
  19. PackageUtil.initSnippetForNewApp(this, PackageUtil.getAppSnippet(this, appInfo,
  20. sourceFile), R.id.app_snippet);
  21. // 如果session已存在,则获取sessionId等数据
  22. if (savedInstanceState != null) {
  23. mSessionId = savedInstanceState.getInt(SESSION_ID);
  24. mInstallId = savedInstanceState.getInt(INSTALL_ID);
  25. // Reregister for result; might instantly call back if result was delivered while
  26. // activity was destroyed
  27. try {
  28. InstallEventReceiver.addObserver(this, mInstallId,
  29. this::launchFinishBasedOnResult);
  30. } catch (EventResultPersister.OutOfIdsException e) {
  31. // Does not happen
  32. }
  33. } else { // 否则创建session
  34. PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
  35. PackageInstaller.SessionParams.MODE_FULL_INSTALL);
  36. // ......
  37. try {
  38. mInstallId = InstallEventReceiver
  39. .addObserver(this, EventResultPersister.GENERATE_NEW_ID,
  40. this::launchFinishBasedOnResult);
  41. } catch (EventResultPersister.OutOfIdsException e) {
  42. launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
  43. }
  44. //创建session
  45. try {
  46. mSessionId = getPackageManager().getPackageInstaller().createSession(params);
  47. } catch (IOException e) {
  48. launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
  49. }
  50. }
  51. //......
  52. mSessionCallback = new InstallSessionCallback();
  53. }
  54. }
  • 6 InstallInstalling.onStart中注册回调函数,然后onResume中执行AsyncTask。
  1. @Override
  2. protected void onResume() {
  3. super.onResume();
  4. // This is the first onResume in a single life of the activity
  5. if (mInstallingTask == null) {
  6. PackageInstaller installer = getPackageManager().getPackageInstaller();
  7. PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);
  8. //如果session非空,则执行AsyncTask
  9. if (sessionInfo != null && !sessionInfo.isActive()) {
  10. mInstallingTask = new InstallingAsyncTask();
  11. mInstallingTask.execute();
  12. } else {
  13. // we will receive a broadcast when the install is finished
  14. mCancelButton.setEnabled(false);
  15. setFinishOnTouchOutside(false);
  16. }
  17. }
  18. }
  • 7 AsyncTask是Android提供的一种轻量级的异步类,执行过程可以表示为5个阶段。

    • 1 准备执行,onPreExecute()
    • 2 正在后台执行,doInBackgroud()
    • 3 进度更新,onProcessUpdate()
    • 4 完成后台任务,onPostExecute()
    • 5 取消任务,onCacelled()

此处重写了方法onPostExecute方法,源码如下。

  1. @Override
  2. protected void onPostExecute(PackageInstaller.Session session) {
  3. if (session != null) {
  4. Intent broadcastIntent = new Intent(BROADCAST_ACTION);
  5. broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
  6. broadcastIntent.setPackage(
  7. getPackageManager().getPermissionControllerPackageName());
  8. broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);
  9. PendingIntent pendingIntent = PendingIntent.getBroadcast(
  10. InstallInstalling.this,
  11. mInstallId,
  12. broadcastIntent,
  13. PendingIntent.FLAG_UPDATE_CURRENT);
  14. //提交session
  15. session.commit(pendingIntent.getIntentSender());
  16. mCancelButton.setEnabled(false);
  17. setFinishOnTouchOutside(false);
  18. } else {
  19. getPackageManager().getPackageInstaller().abandonSession(mSessionId);
  20. if (!isCancelled()) {
  21. launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);
  22. }
  23. }
  24. }
  • 8 session对象传输顺序为:

    • 1 PackageInstaller.Session.commit
    • 2 IPackageInstallerSession.commit
    • 3 PackageInstallerSession.commit
    • 4 Handler.Callback.handleMessage
    • 5 PackageInstallerSession.commitLock
    • 6 PMS.installStage

      这里是不是似曾相识,这一步跟Adb安装的第4步几乎相同,之后就调用installStage方法完成安装。

#3 总结

安装应用的场景就是上述所示的PMS构造函数安装、adb安装、网络下载安装、本地安装。其最终的入口为PMS.prepareAppDataLeafLIF,然后调用Installer类完成安装,这里涉及到System_server到Installd守护进程的转移。

Android中应用安装分析的更多相关文章

  1. Android中AppWidget的分析与应用:AppWidgetProvider .

    from: http://blog.csdn.net/thl789/article/details/7887968 本文从开发AppWidgetProvider角度出发,看一个AppWidgetPrv ...

  2. Android 中图片压缩分析(上)

    作者: shawnzhao,QQ音乐技术团队一员 一.前言 在 Android 中进行图片压缩是非常常见的开发场景,主要的压缩方法有两种:其一是质量压缩,其二是下采样压缩. 前者是在不改变图片尺寸的情 ...

  3. android中SELINUX规则分析和语法简介【转】

    本文转载自:https://blog.csdn.net/LoongEmbedded/article/details/62430039 1. SELINUX是可以理解为一种Android上面的安全机制, ...

  4. android中SELINUX规则分析和语法简介

    1. SELINUX是可以理解为一种android上面的安全机制,是有美国国家安全局和一些公司设计的一个针对linux的安全加强系统我们可以通过配置SELINUX的相关policy,来定制自己的手机的 ...

  5. Android中Touch事件分析--解决HorizontalScrollView滑动和按钮事件触发问题

    之前写过关于HorizontalScrollView滑动和按钮事件触发问题,但是不能所有的情况,最近几天一直在想这个问题,今天有一个比较好的解决思路,最终应用在项目里面效果也很好,首先说明一下功能: ...

  6. Android中Parcel的分析以及使用

    简单点来说:Parcel就是一个存放读取数据的容器, Android系统中的binder进程间通信(IPC)就使用了Parcel类来进行客户端与服务端数据的交互,而且AIDL的数据也是通过Parcel ...

  7. Android中APK安装过程及原理解析

    [原文] 来自华为内部资料 应用安装是智能机的主要特点,即用户可以把各种应用(如游戏等)安装到手机上,并可以对其进行卸载等管理操作.APK是Android Package的缩写,即android安装包 ...

  8. Android中Context样式分析

    目录 1.样式定义以及使用 1.1.默认样式 1.2.样式定义及使用 1.3.当前样式下attr属性的获取 1.4.属性集合的定义与获取 2.Activity中Theme的初始化流程 2.1.系统调用 ...

  9. Android应用程序安装过程浅析

    我们知道在android中.安装应用是由PackageManager来管理的,可是我们发现PackageManager是一个抽象类.他的installPackage方法也没有详细的实现. 那在安装过程 ...

随机推荐

  1. jsp登陆

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"% ...

  2. android 代码覆盖率

    背景 项目使用的是small插件.一个app分为main和多个插件,为了统计插件的代码覆盖率. 1 修改插件 修改插件build.gradle buildTypes { release { ... } ...

  3. 【spring boot】【mybatis】spring boot中mybatis打印sql语句

    spring boot中mybatis打印sql语句,怎么打印出来?[参考:https://www.cnblogs.com/sxdcgaq8080/p/9100178.html] 在applicati ...

  4. 理解 VMWare的3种网络模型 z

    在说到VMware的网络模型之前,先说一下VMware的几个虚拟设备: ■ VMnet0:这是VMware用于虚拟桥接网络下的虚拟交换机: ■ VMnet1:这是VMware用于虚拟Host-Only ...

  5. 开源 java CMS - FreeCMS2.3会员我的留言

    原文地址:http://javaz.cn/site/javaz/site_study/info/2015/29631.html​ 项目地址:http://www.freeteam.cn/ 我的留言 从 ...

  6. centos7 mongodb3.2与3.4版本安装(转)

    一.安装环境及配置yum vi /etc/yum.repos.d/mongodb-org-3.2.repo [mongodb-org-3.2] name=MongoDB Repository base ...

  7. mysql 数据库设计(转)

    本规范适用于mysql 5.1或以上版本使用 数据库范式 第一范式(1NF)确保每列保持原子性 第一范式(1NF):数据库表的每一列都是不可分割的原子数据项,而不能是集合,数组,记录等非原子数据项. ...

  8. 【iOS开发-55】图片轮播案例:scrollView的分页、滚动栏、利用代理控制定时器和Page Control以及多线程问题

    案例: (1)用storyboard布局,这里用了三样东西. --UIScrollView就是我们准备存放滚动图片的容器. --Page Control就是控制页数的那几个小点点.能够设置有多少个点. ...

  9. 2017.7.14 使用case when和group by将多条数据合并成一行,并且根据某些列的合并值做条件判断来生成最终值

    参考来自:http://bbs.csdn.net/topics/390737006 1.效果演示 (1)不做处理 (2)合并多列,并对后四列的值做并集处理 2.SQL语句 (1)不做处理 SELECT ...

  10. javascript 冒泡排序算法

    <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...