Android包管理机制(三)PMS处理APK的安装

  • Android框架层
  • Android包管理机制
  • Android框架层

本文首发于微信公众号「刘望舒」

前言

在上一篇文章Android包管理机制(二)PackageInstaller安装APK中,我们学习了PackageInstaller是如何安装APK的,最后会将APK的信息交由PMS处理。那么PMS是如何处理的呢?这篇文章会给你答案。

1.PackageHandler处理安装消息

APK的信息交由PMS后,PMS通过向PackageHandler发送消息来驱动APK的复制和安装工作。 先来查看PackageHandler处理安装消息的调用时序图。

VeClRJ.png

接着上一篇文章的代码逻辑来查看PMS的installStage方法。 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

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 ... 6 final Message msg = mHandler.obtainMessage(INIT_COPY);//1 7 final int installReason = fixUpInstallReason(installerPackageName, installerUid, 8 sessionParams.installReason); 9 final InstallParams params = new InstallParams(origin, null, observer, 10 sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid, 11 verificationInfo, user, sessionParams.abiOverride, 12 sessionParams.grantedRuntimePermissions, certificates, installReason);//2 13 params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params)); 14 msg.obj = params; 15 ... 16 mHandler.sendMessage(msg);//3 17 }

注释2处创建InstallParams,它对应于包的安装数据。注释1处创建了类型为INIT_COPY的消息,在注释3处将InstallParams通过消息发送出去。

1.1 对INIT_COPY的消息的处理

处理INIT_COPY类型的消息的代码如下所示。 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#PackageHandler

1 void doHandleMessage(Message msg) { 2 switch (msg.what) { 3 case INIT_COPY: { 4 HandlerParams params = (HandlerParams) msg.obj; 5 int idx = mPendingInstalls.size(); 6 if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params); 7 //mBound用于标识是否绑定了服务,默认值为false 8 if (!mBound) {//1 9 Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS", 10 System.identityHashCode(mHandler)); 11 //如果没有绑定服务,重新绑定,connectToService方法内部如果绑定成功会将mBound置为true 12 if (!connectToService()) {//2 13 Slog.e(TAG, "Failed to bind to media container service"); 14 params.serviceError(); 15 Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS", 16 System.identityHashCode(mHandler)); 17 if (params.traceMethod != null) { 18 Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod, 19 params.traceCookie); 20 } 21 //绑定服务失败则return 22 return; 23 } else { 24 //绑定服务成功,将请求添加到ArrayList类型的mPendingInstalls中,等待处理 25 mPendingInstalls.add(idx, params); 26 } 27 } else { 28 //已经绑定服务 29 mPendingInstalls.add(idx, params); 30 if (idx == 0) { 31 mHandler.sendEmptyMessage(MCS_BOUND);//3 32 } 33 } 34 break; 35 } 36 .... 37 } 38 } 39 }

PackageHandler继承自Handler,它被定义在PMS中,doHandleMessage方法用于处理各个类型的消息,来查看对INIT_COPY类型消息的处理。注释1处的mBound用于标识是否绑定了DefaultContainerService,默认值为false。DefaultContainerService是用于检查和复制可移动文件的服务,这是一个比较耗时的操作,因此DefaultContainerService没有和PMS运行在同一进程中,它运行在com.android.defcontainer进程,通过IMediaContainerService和PMS进行IPC通信,如下图所示。 VeCQG4.png

注释2处的connectToService方法用来绑定DefaultContainerService,注释3处发送MCS_BOUND类型的消息,触发处理第一个安装请求。 查看注释2处的connectToService方法: **frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#PackageHandler **

1 private boolean connectToService() { 2 if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" + 3 " DefaultContainerService"); 4 Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); 5 Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); 6 if (mContext.bindServiceAsUser(service, mDefContainerConn, 7 Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {//1 8 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 9 mBound = true;//2 10 return true; 11 } 12 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 13 return false; 14 }

注释2处如果绑定DefaultContainerService成功,mBound会置为ture 。注释1处的bindServiceAsUser方法会传入mDefContainerConn,bindServiceAsUser方法的处理逻辑和我们调用bindService是类似的,服务建立连接后,会调用onServiceConnected方法: **frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java **

1 class DefaultContainerConnection implements ServiceConnection { 2 public void onServiceConnected(ComponentName name, IBinder service) { 3 if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected"); 4 final IMediaContainerService imcs = IMediaContainerService.Stub 5 .asInterface(Binder.allowBlocking(service)); 6 mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, Object));//1 7 } 8 public void onServiceDisconnected(ComponentName name) { 9 if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected"); 10 } 11 }

注释1处发送了MCS_BOUND类型的消息,与PackageHandler.doHandleMessage方法的注释3处不同的是,这里发送消息带了Object类型的参数,这里会对这两种情况来进行讲解,一种是消息不带Object类型的参数,一种是消息带Object类型的参数。

1.2 对MCS_BOUND类型的消息的处理

消息不带Object类型的参数 查看对MCS_BOUND类型消息的处理:

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

1case MCS_BOUND: { 2 if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound"); 3 if (msg.obj != null) {//1 4 mContainerService = (IMediaContainerService) msg.obj;//2 5 Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS", 6 System.identityHashCode(mHandler)); 7 } 8 if (mContainerService == null) {//3 9 if (!mBound) {//4 10 Slog.e(TAG, "Cannot bind to media container service"); 11 for (HandlerParams params : mPendingInstalls) { 12 params.serviceError();//5 13 Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", 14 System.identityHashCode(params)); 15 if (params.traceMethod != null) { 16 Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, 17 params.traceMethod, params.traceCookie); 18 } 19 return; 20 } 21 //绑定失败,清空安装请求队列 22 mPendingInstalls.clear(); 23 } else { 24 //继续等待绑定服务 25 Slog.w(TAG, "Waiting to connect to media container service"); 26 } 27 } else if (mPendingInstalls.size() > 0) { 28 ... 29 else { 30 Slog.w(TAG, "Empty queue"); 31 } 32 break; 33 }

如果消息不带Object类型的参数,就无法满足注释1处的条件,注释2处的IMediaContainerService类型的mContainerService也无法被赋值,这样就满足了注释3处的条件。 如果满足注释4处的条件,说明还没有绑定服务,而此前已经在PackageHandler.doHandleMessage方法的注释2处调用绑定服务的方法了,这显然是不正常的,因此在注释5处负责处理服务发生错误的情况。如果不满足注释4处的条件,说明已经绑定服务了,就会打印出系统log,告知用户等待系统绑定服务。

消息带Object类型的参数 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

1case MCS_BOUND: { 2 if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound"); 3 if (msg.obj != null) { 4 ... 5 } 6 if (mContainerService == null) {//1 7 ... 8 } else if (mPendingInstalls.size() > 0) {//2 9 HandlerParams params = mPendingInstalls.get(0);//3 10 if (params != null) { 11 Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", 12 System.identityHashCode(params)); 13 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy"); 14 if (params.startCopy()) {//4 15 if (DEBUG_SD_INSTALL) Log.i(TAG, 16 "Checking for more work or unbind..."); 17 //如果APK安装成功,删除本次安装请求 18 if (mPendingInstalls.size() > 0) { 19 mPendingInstalls.remove(0); 20 } 21 if (mPendingInstalls.size() == 0) { 22 if (mBound) { 23 //如果没有安装请求了,发送解绑服务的请求 24 if (DEBUG_SD_INSTALL) Log.i(TAG, 25 "Posting delayed MCS_UNBIND"); 26 removeMessages(MCS_UNBIND); 27 Message ubmsg = obtainMessage(MCS_UNBIND); 28 sendMessageDelayed(ubmsg, 10000); 29 } 30 } else { 31 if (DEBUG_SD_INSTALL) Log.i(TAG, 32 "Posting MCS_BOUND for next work"); 33 //如果还有其他的安装请求,接着发送MCS_BOUND消息继续处理剩余的安装请求 34 mHandler.sendEmptyMessage(MCS_BOUND);//5 35 } 36 } 37 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 38 }else { 39 Slog.w(TAG, "Empty queue");//6 40 } 41 break; 42 }

如果MCS_BOUND类型消息带Object类型的参数就不会满足注释1处的条件,就会调用注释2处的判断,如果安装请求数不大于0就会打印出注释6处的log,说明安装请求队列是空的。安装完一个APK后,就会在注释5处发出MSC_BOUND消息,继续处理剩下的安装请求直到安装请求队列为空。 注释3处得到安装请求队列第一个请求HandlerParams ,如果HandlerParams 不为null就会调用注释4处的HandlerParams的startCopy方法,用于开始复制APK的流程。

2.复制APK

先来查看复制APK的时序图。

VeCuIU.png

HandlerParams是PMS中的抽象类,它的实现类为PMS的内部类InstallParams。HandlerParams的startCopy方法如下所示。 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#HandlerParams

1 final boolean startCopy() { 2 boolean res; 3 try { 4 if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this); 5 //startCopy方法尝试的次数,超过了4次,就放弃这个安装请求 6 if (++mRetries > MAX_RETRIES) {//1 7 Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); 8 mHandler.sendEmptyMessage(MCS_GIVE_UP);//2 9 handleServiceError(); 10 return false; 11 } else { 12 handleStartCopy();//3 13 res = true; 14 } 15 } catch (RemoteException e) { 16 if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT"); 17 mHandler.sendEmptyMessage(MCS_RECONNECT); 18 res = false; 19 } 20 handleReturnCode();//4 21 return res; 22 }

注释1处的mRetries用于记录startCopy方法调用的次数,调用startCopy方法时会先自动加1,如果次数大于4次就放弃这个安装请求:在注释2处发送MCS_GIVE_UP类型消息,将第一个安装请求(本次安装请求)从安装请求队列mPendingInstalls中移除掉。注释4处用于处理复制APK后的安装APK逻辑,第3小节中会再次提到它。注释3处调用了抽象方法handleStartCopy,它的实现在InstallParams中,如下所示。 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#InstallParams

1 public void handleStartCopy() throws RemoteException { 2 ... 3 //确定APK的安装位置。onSd:安装到SD卡, onInt:内部存储即Data分区,ephemeral:安装到临时存储(Instant Apps安装) 4 final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0; 5 final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0; 6 final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; 7 PackageInfoLite pkgLite = null; 8 if (onInt && onSd) { 9 // APK不能同时安装在SD卡和Data分区 10 Slog.w(TAG, "Conflicting flags specified for installing on both internal and external"); 11 ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; 12 //安装标志冲突,Instant Apps不能安装到SD卡中 13 } else if (onSd && ephemeral) { 14 Slog.w(TAG, "Conflicting flags specified for installing ephemeral on external"); 15 ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; 16 } else { 17 //获取APK的少量的信息 18 pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags, 19 packageAbiOverride);//1 20 if (DEBUG_EPHEMERAL && ephemeral) { 21 Slog.v(TAG, "pkgLite for install: " + pkgLite); 22 } 23 ... 24 if (ret == PackageManager.INSTALL_SUCCEEDED) { 25 //判断安装的位置 26 int loc = pkgLite.recommendedInstallLocation; 27 if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) { 28 ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; 29 } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) { 30 ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS; 31 } 32 ... 33 }else{ 34 loc = installLocationPolicy(pkgLite);//2 35 ... 36 } 37 } 38 //根据InstallParams创建InstallArgs对象 39 final InstallArgs args = createInstallArgs(this);//3 40 mArgs = args; 41 if (ret == PackageManager.INSTALL_SUCCEEDED) { 42 ... 43 if (!origin.existing && requiredUid != -1 44 && isVerificationEnabled( 45 verifierUser.getIdentifier(), installFlags, installerUid)) { 46 ... 47 } else{ 48 ret = args.copyApk(mContainerService, true);//4 49 } 50 } 51 mRet = ret; 52 } 53

handleStartCopy方法的代码很多,这里截取关键的部分。 注释1处通过IMediaContainerService跨进程调用DefaultContainerService的getMinimalPackageInfo方法,该方法轻量解析APK并得到APK的少量信息,轻量解析的原因是这里不需要得到APK的全部信息,APK的少量信息会封装到PackageInfoLite中。接着在注释2处确定APK的安装位置。注释3处创建了InstallArgs,InstallArgs 是一个抽象类,定义了APK的安装逻辑,比如复制和重命名APK等,它有3个子类,都被定义在PMS中,如下图所示。 VeCMiF.png 其中FileInstallArgs用于处理安装到非ASEC的存储空间的APK,也就是内部存储空间(Data分区),AsecInstallArgs用于处理安装到ASEC中(mnt/asec)即SD卡中的APK。MoveInstallArgs用于处理已安装APK的移动的逻辑。 对APK进行检查后就会在注释4处调用InstallArgs的copyApk方法进行安装。 不同的InstallArgs子类会有着不同的处理,这里以FileInstallArgs为例。FileInstallArgs的copyApk方法中会直接return FileInstallArgs的doCopyApk方法: frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#FileInstallArgs

1 private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException { 2 ... 3 try { 4 final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; 5 //创建临时文件存储目录 6 final File tempDir = 7 mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);//1 8 codeFile = tempDir; 9 resourceFile = tempDir; 10 } catch (IOException e) { 11 Slog.w(TAG, "Failed to create copy file: " + e); 12 return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; 13 } 14 ... 15 int ret = PackageManager.INSTALL_SUCCEEDED; 16 ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);//2 17 ... 18 return ret; 19 }

注释1处用于创建临时存储目录,比如/data/app/vmdl18300388.tmp,其中18300388是安装的sessionId。注释2处通过IMediaContainerService跨进程调用DefaultContainerService的copyPackage方法,这个方法会在DefaultContainerService所在的进程中将APK复制到临时存储目录,比如/data/app/vmdl18300388.tmp/base.apk。目前为止APK的复制工作就完成了,接着就是APK的安装过程了。

3.安装APK

照例先来查看安装APK的时序图。 VeCnaT.png 我们回到APK的复制调用链的头部方法:HandlerParams的startCopy方法,在注释4处会调用handleReturnCode方法,它的实现在InstallParams中,如下所示。 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

1 void handleReturnCode() { 2 if (mArgs != null) { 3 processPendingInstall(mArgs, mRet); 4 } 5} 6 7 private void processPendingInstall(final InstallArgs args, final int currentStatus) { 8 mHandler.post(new Runnable() { 9 public void run() { 10 mHandler.removeCallbacks(this); 11 PackageInstalledInfo res = new PackageInstalledInfo(); 12 res.setReturnCode(currentStatus); 13 res.uid = -1; 14 res.pkg = null; 15 res.removedInfo = null; 16 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { 17 //安装前处理 18 args.doPreInstall(res.returnCode);//1 19 synchronized (mInstallLock) { 20 installPackageTracedLI(args, res);//2 21 } 22 //安装后收尾 23 args.doPostInstall(res.returnCode, res.uid);//3 24 } 25 ... 26 } 27 }); 28 }

handleReturnCode方法中只调用了processPendingInstall方法,注释1处用于检查APK的状态的,在安装前确保安装环境的可靠,如果不可靠会清除复制的APK文件,注释3处用于处理安装后的收尾操作,如果安装不成功,删除掉安装相关的目录与文件。主要来看注释2处的installPackageTracedLI方法,其内部会调用PMS的installPackageLI方法。 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

1private void installPackageLI(InstallArgs args, PackageInstalledInfo res) { 2 ... 3 PackageParser pp = new PackageParser(); 4 pp.setSeparateProcesses(mSeparateProcesses); 5 pp.setDisplayMetrics(mMetrics); 6 pp.setCallback(mPackageParserCallback); 7 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage"); 8 final PackageParser.Package pkg; 9 try { 10 //解析APK 11 pkg = pp.parsePackage(tmpPackageFile, parseFlags);//1 12 } catch (PackageParserException e) { 13 res.setError("Failed parse during installPackageLI", e); 14 return; 15 } finally { 16 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 17 } 18 ... 19 pp = null; 20 String oldCodePath = null; 21 boolean systemApp = false; 22 synchronized (mPackages) { 23 // 检查APK是否存在 24 if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { 25 String oldName = mSettings.getRenamedPackageLPr(pkgName);//获取没被改名前的包名 26 if (pkg.mOriginalPackages != null 27 && pkg.mOriginalPackages.contains(oldName) 28 && mPackages.containsKey(oldName)) { 29 pkg.setPackageName(oldName);//2 30 pkgName = pkg.packageName; 31 replace = true;//设置标志位表示是替换安装 32 if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName=" 33 + oldName + " pkgName=" + pkgName); 34 } 35 ... 36 } 37 PackageSetting ps = mSettings.mPackages.get(pkgName); 38 //查看Settings中是否存有要安装的APK的信息,如果有就获取签名信息 39 if (ps != null) {//3 40 if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps); 41 PackageSetting signatureCheckPs = ps; 42 if (pkg.applicationInfo.isStaticSharedLibrary()) { 43 SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg); 44 if (libraryEntry != null) { 45 signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk); 46 } 47 } 48 //检查签名的正确性 49 if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) { 50 if (!checkUpgradeKeySetLP(signatureCheckPs, pkg)) { 51 res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " 52 + pkg.packageName + " upgrade keys do not match the " 53 + "previously installed version"); 54 return; 55 } 56 } 57 ... 58 } 59 60 int N = pkg.permissions.size(); 61 for (int i = N-1; i >= 0; i--) { 62 //遍历每个权限,对权限进行处理 63 PackageParser.Permission perm = pkg.permissions.get(i); 64 BasePermission bp = mSettings.mPermissions.get(perm.info.name); 65 66 } 67 } 68 } 69 if (systemApp) { 70 if (onExternal) { 71 //系统APP不能在SD卡上替换安装 72 res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION, 73 "Cannot install updates to system apps on sdcard"); 74 return; 75 } else if (instantApp) { 76 //系统APP不能被Instant App替换 77 res.setError(INSTALL_FAILED_INSTANT_APP_INVALID, 78 "Cannot update a system app with an instant app"); 79 return; 80 } 81 } 82 ... 83 //重命名临时文件 84 if (!args.doRename(res.returnCode, pkg, oldCodePath)) {//4 85 res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename"); 86 return; 87 } 88 89 startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg); 90 91 try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags, 92 "installPackageLI")) { 93 94 if (replace) {//5 95 //替换安装 96 ... 97 replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user, 98 installerPackageName, res, args.installReason); 99 } else { 100 //安装新的APK 101 installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES, 102 args.user, installerPackageName, volumeUuid, res, args.installReason); 103 } 104 } 105 106 synchronized (mPackages) { 107 final PackageSetting ps = mSettings.mPackages.get(pkgName); 108 if (ps != null) { 109 //更新应用程序所属的用户 110 res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true); 111 ps.setUpdateAvailable(false /*updateAvailable*/); 112 } 113 ... 114 } 115}

installPackageLI方法的代码有将近500行,这里截取主要的部分,主要做了几件事:

  1. 创建PackageParser解析APK。
  2. 检查APK是否存在,如果存在就获取此前没被改名前的包名并在注释1处赋值给PackageParser.Package类型的pkg,在注释3处将标志位replace置为true表示是替换安装。
  3. 注释3处,如果Settings中保存有要安装的APK的信息,说明此前安装过该APK,则需要校验APK的签名信息,确保安全的进行替换。
  4. 在注释4处将临时文件重新命名,比如前面提到的/data/app/vmdl18300388.tmp/base.apk,重命名为/data/app/包名-1/base.apk。这个新命名的包名会带上一个数字后缀1,每次升级一个已有的App,这个数字会不断的累加。
  5. 系统APP的更新安装会有两个限制,一个是系统APP不能在SD卡上替换安装,另一个是系统APP不能被Instant App替换。
  6. 注释5处根据replace来做区分,如果是替换安装就会调用replacePackageLIF方法,其方法内部还会对系统APP和非系统APP进行区分处理,如果是新安装APK会调用installNewPackageLIF方法。

这里我们以新安装APK为例,会调用PMS的installNewPackageLIF方法。 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

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 ... 5 try { 6 //扫描APK 7 PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags, 8 System.currentTimeMillis(), user); 9 //更新Settings信息 10 updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason); 11 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { 12 //安装成功后,为新安装的应用程序准备数据 13 prepareAppDataAfterInstallLIF(newPackage); 14 15 } else { 16 //安装失败则删除APK 17 deletePackageLIF(pkgName, UserHandle.ALL, false, null, 18 PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null); 19 } 20 } catch (PackageManagerException e) { 21 res.setError("Package couldn't be installed in " + pkg.codePath, e); 22 } 23 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 24 }

installNewPackageLIF主要做了以下3件事:

  1. 扫描APK,将APK的信息存储在PackageParser.Package类型的newPackage中,一个Package的信息包含了1个base APK以及0个或者多个split APK。
  2. 更新该APK对应的Settings信息,Settings用于保存所有包的动态设置。
  3. 如果安装成功就为新安装的应用程序准备数据,安装失败就删除APK。

安装APK的过程就讲到这里,就不再往下分析下去,有兴趣的同学可以接着深挖。

4.总结

本文主要讲解了PMS是如何处理APK安装的,主要有几个步骤:

  1. PackageInstaller安装APK时会将APK的信息交由PMS处理,PMS通过向PackageHandler发送消息来驱动APK的复制和安装工作。
  2. PMS发送INIT_COPY和MCS_BOUND类型的消息,控制PackageHandler来绑定DefaultContainerService,完成复制APK等工作。
  3. 复制APK完成后,会开始进行安装APK的流程,包括安装前的检查、安装APK和安装后的收尾工作。

参考资料 Android包管理机制 Android app安装过程分析(基于Nougat) 应用程序安装流程

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

Android系统启动流程(二)解析Zygote进程启动过程

上一篇文章我们分析了init进程的启动过程,启动过程中主要做了三件事,其中一件就是创建了Zygote进程,那么Zygote进程是什么,它做了哪些事呢?这篇文章会给你这些问题的答案。"tag:Android框架层Android系统启动categories:Android框架层本文首发于微信公众号「刘望舒」前言上一篇

Android输入系统(三)InputReader的加工类型和InputDispatcher的分发过程

Android框架层Android输入系统Android框架层本文首发于微信公众号「刘望舒」前言在上一篇文章中,我们学习了输入事件的处理,输入事件会交由InputDispatcher进行分发,那么InputDispatcher是如何进行分发的?这篇文章会给你答案。1.InputReader的加工类型在这篇文章中,我们知道InputReader会对原始

Android包管理机制(二)PackageInstaller安装APK

Android框架层Android包管理机制Android框架层本文首发于微信公众号「刘望舒」前言在本系列上一篇文章中我们学习了PackageInstaller是如何初始化的,这一篇文章我们接着学习PackageInstaller是如何安装APK的。本系列文章的源码基于Android8.0。1.PackageInstaller中的处理紧接着上一篇的内

Android包管理机制(一)PackageInstaller的初始化

Android框架层Android包管理机制Android框架层本文首发于微信公众号「刘望舒」前言包管理机制是Android中的重要机制,是应用开发和系统开发需要掌握的知识点之一。包指的是Apk、jar和so文件等等,它们被加载到Android内存中,由一个包转变成可执行的代码,这就需要一个机制来进行包的加载、解析、管理等操作,这就是包管理机制。包管理