上篇文章Apk安装之——点击安装确认页面的确认按钮,到将安装过程交给PMS的过程分析分析到apk安装的流程,交给了PMS,这篇文章继续分析,PMS是如何安装apk包的。首先调用PMS的installStage进行安装。下面看看这个方法:
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java void installStage(String packageName, File stagedDir, IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams, String installerPackageName, int installerUid, UserHandle user, PackageParser.SigningDetails signingDetails) { ... final VerificationInfo verificationInfo = new VerificationInfo( sessionParams.originatingUri, sessionParams.referrerUri, sessionParams.originatingUid, installerUid); final OriginInfo origin = OriginInfo.fromStagedFile(stagedDir); //关键代码 msg.what是INIT_COPY的消息 final Message msg = mHandler.obtainMessage(INIT_COPY); final int installReason = fixUpInstallReason(installerPackageName, installerUid, sessionParams.installReason); final InstallParams params = new InstallParams(origin, null, observer, sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid, verificationInfo, user, sessionParams.abiOverride, sessionParams.grantedRuntimePermissions, signingDetails, installReason); params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params)); //注意,这里的params是一个InstallParams类型的对象,赋值给了msg.obj msg.obj = params; ... //关键代码 发送一个msg.what是INIT_COPY的消息 mHandler.sendMessage(msg); }这个方法内部,会发送一个msg.what是INIT_COPY的消息,下面看PackageHandler对这个消息的处理
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java class PackageHandler extends Handler { ... private boolean connectToService() { if (DEBUG_INSTALL) Log.i(TAG, "Trying to bind to DefaultContainerService"); Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); if (mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); mBound = true; return true; } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); return false; } ... void doHandleMessage(Message msg) { switch (msg.what) { case INIT_COPY: { HandlerParams params = (HandlerParams) msg.obj; int idx = mPendingInstalls.size(); //mBound默认是false if (!mBound) { //关键代码1 发送连接DefaultContainerService的请求,这是system_server进程和com.android.defcontainer进程进行通信, if (!connectToService()) { params.serviceError(); ... //如果绑定DefaultContainerService失败,则return return; } else { //关键代码2 如果连接上DefaultContainerService,则将这个安装请求保存到这个mPendingInstalls这个List集合中 mPendingInstalls.add(idx, params); } } else { //如果已经绑定了DefaultContainerService,则将这个安装请求保存到这个mPendingInstalls这个List集合中 mPendingInstalls.add(idx, params); //如果是第一个安装请求,则发送绑定MCS_BOUND消息,在未给mPendingInstalls添加安装请求前,上面mPendingInstalls.size()的值是0, //当添加按章请求后,这是mPendingInstalls.size()的值是1,所以,这里idx==0,就是给第一个安装请求发送MCS_BOUND消息 if (idx == 0) { //关键代码3 mHandler.sendEmptyMessage(MCS_BOUND); } } break; ... } } final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection(); class DefaultContainerConnection implements ServiceConnection { public void onServiceConnected(ComponentName name, IBinder service) { if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected"); final IMediaContainerService imcs = IMediaContainerService.Stub .asInterface(Binder.allowBlocking(service)); //关键代码 这里发送msg.what为MCS_BOUND的消息是,msg.obj的值是imcs,其实就是DefaultContainerService在system_server的代理对象 mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs)); } public void onServiceDisconnected(ComponentName name) { if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected"); } }在INIT_COPY这个case中,如果本次安装时,没有其他安装请求,则mBound的值是false,这会执行到关键代码1处,调用connectToService()方法进行绑定DefaultContainerService的连接操作,这是个进程间通信的过程,是system_server进程和com.android.defcontainer进程进行通信。如果连接上DefaultContainerService,则将安装请求添加进mPendingInstalls这个集合中,如果连接失败,则return。如果本次安装时,已经有其他安装请求绑定DefaultContainerService服务了,则将这次安装请求添加进mPendingInstalls,并通过handler发送MCS_BOUND消息。注意发送MCS_BOUND消息时,msg.obj被赋值了,这个值是DefaultContainerService在system_server进程中的代理对象.下面看看handler对MCS_BOUND消息的处理:
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java class PackageHandler extends Handler { void doHandleMessage(Message msg) { switch (msg.what) { ... case MCS_BOUND: { if (msg.obj != null) { //关键代码1 如果msg.obj不为null,则给mContainerService赋值 mContainerService = (IMediaContainerService) msg.obj; ... } if (mContainerService == null) { //关键代码2 如果mContainerService为null if (!mBound) { //关键代码3 如果是连接上DefaultContainerService,mBound的值会true,如果这里的mBound的值为false,则安装过程出错了, for (HandlerParams params : mPendingInstalls) { // Indicate service bind error params.serviceError(); ... } //安装过程出错,清除这个mPendingInstalls集合 mPendingInstalls.clear(); } else { Slog.w(TAG, "Waiting to connect to media container service"); } } else if (mPendingInstalls.size() > 0) { //关键代码5 需要安装的请求的个数大于0 HandlerParams params = mPendingInstalls.get(0); if (params != null) { ... if (params.startCopy()) { //关键代码6 开始复制 ... if (mPendingInstalls.size() > 0) { //复制成功,则将本次安装请求重mPendingInstalls集合中移除 mPendingInstalls.remove(0); } if (mPendingInstalls.size() == 0) { // 如果安装请求的个数为0 if (mBound) { //如果需要安装的apk的个数为0,并且是绑定状态,则发送消息和ContainerService解绑 removeMessages(MCS_UNBIND); Message ubmsg = obtainMessage(MCS_UNBIND); sendMessageDelayed(ubmsg, 10000); } } else { // 接着处理下一个绑定ContainerService的请求 mHandler.sendEmptyMessage(MCS_BOUND); } } ... } } else { // Should never happen ideally. Slog.w(TAG, "Empty queue"); } break; ... } } }handler中处理MCS_BOUND消息的逻辑是,由于发送MCS_BOUND时msg.obj赋值过,导致关键代码1处成立,则执行关键代码5处的逻辑,这是就会执行关键代码6处的逻辑,在发送Init_copy消息时,msg.obj是InstallParams类型的对象,所以,这里mPendingInstalls中取出的就是InstallParams类型的对象,调用InstallParams类的startCopy方法进行复制工作。当复制成功后,会则将本次安装请求重mPendingInstalls集合中移除,如果需要安装的apk的个数为0,并且是绑定状态,则发送消息和ContainerService解绑,如果不为0,则继续处理下一个安装请求。这个方法中,还有另外的一个逻辑,这里也顺便阐述一下,如果关键代码1出的逻辑成立则执行关键代码2处的逻辑,关键代码2中逻辑是,如果当前状态是为绑定,则肯定是出错了,因为connectToServcie方法中如果连接成功,这个mBound这个值就复制为true了这里这个值如果是false,则if(!mBound)这个判断条件成立,这样安装过程肯定出错了,则将mPendingInstalls集合清除。正常情况下,这个mBound的值应该是true,所以不做处理。表示已经连接上了。下面接着分析,InstallParams类的startCopy方法是如何进行复制的:
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java final boolean startCopy() { boolean res; try { if (++mRetries > MAX_RETRIES) { Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); mHandler.sendEmptyMessage(MCS_GIVE_UP); handleServiceError(); return false; } else { // 关键代码1 handleStartCopy(); res = true; } } catch (RemoteException e) { if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT"); mHandler.sendEmptyMessage(MCS_RECONNECT); res = false; } //关键代码2 handleReturnCode(); return res; }InstallParams是继承自HandlerParams的startCopy()这个方法是HandlerParams的方法,这个方法内部,会判断安装重试的次数是否大于4次(MAX_RETRIES是个常量,值是4),如果大于4次,则发送放弃安装。如果不大于4次,则执行handleStartCopy()方法,下面看看这个方法的具体实现:
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java public void handleStartCopy() throws RemoteException { int ret = PackageManager.INSTALL_SUCCEEDED; // If we're already staged, we've firmly committed to an install location //如果是一个新的app,则staged为false if (origin.staged) { if (origin.file != null) { installFlags |= PackageManager.INSTALL_INTERNAL; installFlags &= ~PackageManager.INSTALL_EXTERNAL; } else { throw new IllegalStateException("Invalid stage location"); } } // 确定APK的安装位置,onSd表示安装到SD卡上, // onInt表示安装到内部存储,即Data分区 // ephemeral:安装到临时存储(Instant Apps安装) final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0; final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0; final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; PackageInfoLite pkgLite = null; if (onInt && onSd) { // 不能同时安装到sd卡和内部存储位置 Slog.w(TAG, "Conflicting flags specified for installing on both internal and external"); ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; } else if (onSd && ephemeral) { //flags冲突,不能在sd卡安装Instant app Slog.w(TAG, "Conflicting flags specified for installing ephemeral on external"); ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; } else { //获取apk的轻量信息 pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags, packageAbiOverride); if (!origin.staged && pkgLite.recommendedInstallLocation == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) { ... //省略这个判断内部的代码,这块的主要逻辑是判断,如果存储空间不足,则需要释放Cache的一些空间 } } if (ret == PackageManager.INSTALL_SUCCEEDED) { ... //省略这个判断内部的代码,这块的主要逻辑是判断安装的位置 } //创建InstallArgs对象,createInstallArgs方法内部返回的是FileInstallArgs类型的对象。FileInstallArgs是InstallArgs的子类 final InstallArgs args = createInstallArgs(this); mArgs = args; if (ret == PackageManager.INSTALL_SUCCEEDED) { ... if (!origin.existing && requiredUid != -1 && isVerificationEnabled( verifierUser.getIdentifier(), installFlags, installerUid)) { ... // 此处省略大段APK的检查逻辑。 } else { //调用FileInstallArgs类的copyApk方法 ret = args.copyApk(mContainerService, true); } } mRet = ret; }这个方法内部,根据安装方式,判断安装的位置是否冲突,在判断,安装的位置是否有足够的存储空间,如果没有,释放缓存空间,接着确定安装位置,在接着对apk进行检测,最后创建FileInstallArgs类型的对象,并调用其调用copyApk方法,copyApk方法中直接调用了doCopyApk方法,下面看看这个方法:
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException { ... try { final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; //创建临时文件 final File tempDir = mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral); codeFile = tempDir; resourceFile = tempDir; } catch (IOException e) { Slog.w(TAG, "Failed to create copy file: " + e); return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; } ... int ret = PackageManager.INSTALL_SUCCEEDED; //调用DefaultContainerService在system_server进程中的代理对象的copyPackage方法,这是进程间通信的过程, //跨进程调用DefaultContainerService进程中的copyPackage()函数 ret = imcs.copyPackage(origin.file.getAbsolutePath(), target); if (ret != PackageManager.INSTALL_SUCCEEDED) { return ret; } //复制Native库文件 final File libraryRoot = new File(codeFile, LIB_DIR_NAME); NativeLibraryHelper.Handle handle = null; try { handle = NativeLibraryHelper.Handle.create(codeFile); ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot, abiOverride); } catch (IOException e) { Slog.e(TAG, "Copying native libraries failed", e); ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; } finally { IoUtils.closeQuietly(handle); } return ret; }FileInstallArgs类的copyApk方法中,又会调用doCopyApk方法,在doCopyApk方法中,会创建一个临时路径,这里之所以创建临时目录,命名如/data/app/vmdl29300388.tmp,其中数字部分29300388在每一次安装过程都不同,是安装时的SessionId。由于PMS监控了/data/app目录,如果该目录下有后缀名为.apk的文件生成,便会触发PMS扫描,为了避免这种情况,安装APK时,先用了临时的文件名。 并跨进程调用DefaultContainerService的copyPackage方法完成apk的复制工作,然后复制Native库。完成了apk的复制工作后,apk就在data/app目录下,不过此时还是临时文件的,后续还需要重新命名。如果复制过程为出现异常,则返回INSTALL_SUCCEEDED(1)这个整数;否则,会返回对应的错误码。到这里,分析完了PMS H a n d l e r P a r a m s 类 的 的 s t a r t C o p y ( ) 中 的 h a n d l e S t a r t C o p y 方 法 的 处 理 逻 辑 , 下 面 继 续 看 P M S HandlerParams类的的startCopy()中的handleStartCopy方法的处理逻辑,下面继续看PMS HandlerParams类的的startCopy()中的handleStartCopy方法的处理逻辑,下面继续看PMSHandlerParams类的的startCopy()方法的后续对复制apk的结果的处理逻辑:
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java final boolean startCopy() { boolean res; try { if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this); if (++mRetries > MAX_RETRIES) { Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); mHandler.sendEmptyMessage(MCS_GIVE_UP); handleServiceError(); return false; } else { // 关键代码1 handleStartCopy(); res = true; } } catch (RemoteException e) { if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT"); mHandler.sendEmptyMessage(MCS_RECONNECT); res = false; } //关键代码2 handleReturnCode(); return res; }在关键代码2处,就是对复制apk后的返回结果的处理,下面看看这个handleReturnCode()方法的具体实现
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java @Override void handleReturnCode() { if (mArgs != null) { processPendingInstall(mArgs, mRet); } } private void processPendingInstall(final InstallArgs args, final int currentStatus) { mHandler.post(new Runnable() { public void run() { mHandler.removeCallbacks(this); PackageInstalledInfo res = new PackageInstalledInfo(); res.setReturnCode(currentStatus); res.uid = -1; res.pkg = null; res.removedInfo = null; if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { //安装前的准备工作,检查包状态,确保环境ok,如果环境不ok,那么会清理拷贝的文件 args.doPreInstall(res.returnCode); synchronized (mInstallLock) { //安装apk,调用installPackageTracedLI进行安装 installPackageTracedLI(args, res); } //安装完后的处理 args.doPostInstall(res.returnCode, res.uid); } ... if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) { IBackupManager bm = IBackupManager.Stub.asInterface( ServiceManager.getService(Context.BACKUP_SERVICE)); ... //这块省略的逻辑,是对apk的备份过程 } ... } }); }handleReturnCode方法内部,直接调用了processPendingInstall来处理具体的安装逻辑。processPendingInstall方法中,是将安装过程放在一个线程中的,这个方法内部,主要做了三件事,第一安装前的检查,检查安装环境是否正常,如果不正常,则清理复制的apk文件,如果安装环境正常,则进行进行安装工作,安装完后,处理一些收尾的事情。installPackageTracedLI方法内部直接调用了installPackageLI方法,下面具体看看这个方法的具体实现:
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java private void installPackageLI(InstallArgs args, PackageInstalledInfo res) { ... PackageParser pp = new PackageParser(); ... final PackageParser.Package pkg; try { //关键代码1 pkg = pp.parsePackage(tmpPackageFile, parseFlags); DexMetadataHelper.validatePackageDexMetadata(pkg); } catch (PackageParserException e) { res.setError("Failed parse during installPackageLI", e); return; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } ... try { //收集签名信息 if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) { pkg.setSigningDetails(args.signingDetails); } else { PackageParser.collectCertificates(pkg, false /* skipVerify */); } } catch (PackageParserException e) { res.setError("Failed collect during installPackageLI", e); return; } ... pp = null; String oldCodePath = null; boolean systemApp = false; synchronized (mPackages) { // 检查安装包是否存在 if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { String oldName = mSettings.getRenamedPackageLPr(pkgName); if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName) && mPackages.containsKey(oldName)) { pkg.setPackageName(oldName); pkgName = pkg.packageName; //替换安装,也就是升级app replace = true; } else if (mPackages.containsKey(pkgName)) { //替换安装,也就是升级app replace = true; if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName); } ... } //如果Settings中已经记录了待安装的APK信息,需要验证APK的签名 PackageSetting ps = mSettings.mPackages.get(pkgName); if (ps != null) { PackageSetting signatureCheckPs = ps; ... //省略的代码是 验证apk的签名信息 } int N = pkg.permissions.size(); for (int i = N-1; i >= 0; i--) { final PackageParser.Permission perm = pkg.permissions.get(i); final BasePermission bp = (BasePermission) mPermissionManager.getPermissionTEMP(perm.info.name); ... //省略的代码部分处理安装的apk中的权限的逻辑 } } if (systemApp) { if (onExternal) { //系统app不能被sd卡上的app替换,return res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION, "Cannot install updates to system apps on sdcard"); return; } else if (instantApp) { //系统app不能被instant app替换 res.setError(INSTALL_FAILED_INSTANT_APP_INVALID, "Cannot update a system app with an instant app"); return; } } ... //将之前的临时文件名重新命名 if (!args.doRename(res.returnCode, pkg, oldCodePath)) { res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename"); return; } ... try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags, "installPackageLI")) { if (replace) { if (pkg.applicationInfo.isStaticSharedLibrary()) { PackageParser.Package existingPkg = mPackages.get(pkg.packageName); if (existingPkg != null && existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) { res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring " + "static-shared libs cannot be updated"); return; } } //替换安装,也就是升级app replacePackageLIF(pkg, parseFlags, scanFlags, args.user, installerPackageName, res, args.installReason); } else { //安装一个新的app installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES, args.user, installerPackageName, volumeUuid, res, args.installReason); } } mArtManagerService.prepareAppProfiles(pkg, resolveUserIds(args.user.getIdentifier())); // 检查是否需要优化app中的dex文件,默认是不给instant app做dex优化的,只有满足下面4个条件,才做dex的优化 // 1) it is not forward locked. // 2) it is not on on an external ASEC container. // 3) it is not an instant app or if it is then dexopt is enabled via gservices. // 4) it is not debuggable. final boolean performDexopt = (res.returnCode == PackageManager.INSTALL_SUCCEEDED) && !forwardLocked && !pkg.applicationInfo.isExternalAsec() && (!instantApp || Global.getInt(mContext.getContentResolver(), Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0) && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0); if (performDexopt) { DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName, REASON_INSTALL, DexoptOptions.DEXOPT_BOOT_COMPLETE | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE); mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles, null /* instructionSets */, getOrCreateCompilerPackageStats(pkg), mDexManager.getPackageUseInfoOrDefault(pkg.packageName), dexoptOptions); } ... synchronized (mPackages) { final PackageSetting ps = mSettings.mPackages.get(pkgName); if (ps != null) { //更新APK的所属用户 res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true); ps.setUpdateAvailable(false /*updateAvailable*/); } ... } }这个方法内部,处理的逻辑还是很复杂的,下面列出主要的处理流程: 1.通过PackageParser的parsePackage方法对apk进行解析,具体的解析工作,很复杂,主要是解析apk文件中的manifest文件,并将manifest文件中的application标签,activity,service,broadcast,contentprovider,这四大组件,intentfileter等标签解析成对应的数据结构,比如activity标签就解析为Activity类,这里的这个Activity类不是我们平时开发时继承的Activity,这个Activity是继承Component类的,将这些解析的标签对应的数据保存到PackageParser$Package类的各个集合中。这里由于篇幅的原因,省略了这个解析过程的具体分析,但是读者一定要仔细去分析这个过程,如果做插件化开发,这个方法是很重要的,必须要了解。
2.收集apk中的签名信息和验证签名信息,如果是替换安装,则要和原来的apk的签名信息进行对比,主要是为了安全升级app
3.判断需要安装的apk的信息,是否有记录,如果有则是替换安装,如果没有,则是安装一个新的app
4.处理apk中的权限
5.将原来的临时文件重命名
6.如果是替换安装,则走具体的替换安装的逻辑,如果需要替换的是系统APP,则调用Settings$disableSystemPackageLPw来disable旧的APK;如果替换的是非系统APP,则调用deletePackageLI删除旧的APK。不管是更新系统还是非系统apk,都会先清除之前的packages信息,然后通过scanPackageTracedLI去安装apk,安装完后更新permissions和setting,最后通过writeLPr更新packages.xml.如果是一个安装一个新的app,则执行installNewPackageLIF方法,这个方法,后面会进行分析。
7.对满足条件的apk进行dex文件的优化处理
8.晚装完成后,更新apk所属的用户
下面下分析installNewPackageLIF方法:
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java private void installNewPackageLIF(PackageParser.Package pkg, final @ParseFlags int parseFlags, final @ScanFlags int scanFlags, UserHandle user, String installerPackageName, String volumeUuid, PackageInstalledInfo res, int installReason) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage"); // Remember this for later, in case we need to rollback this install String pkgName = pkg.packageName; synchronized(mPackages) { final String renamedPackage = mSettings.getRenamedPackageLPr(pkgName); if (renamedPackage != null) { // A package with the same name is already installed, though // it has been renamed to an older name. The package we // are trying to install should be installed as an update to // the existing one, but that has not been requested, so bail. res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName + " without first uninstalling package running as " + renamedPackage); return; } if (mPackages.containsKey(pkgName)) { // Don't allow installation over an existing package with the same name. res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName + " without first uninstalling."); return; } } try { //扫描apk PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags, scanFlags, System.currentTimeMillis(), user); //更新Settings中的信息 updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason); if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { //如果安装成功,则为新安装的应用准备数据 prepareAppDataAfterInstallLIF(newPackage); } else { // 安装失败,则删除apk deletePackageLIF(pkgName, UserHandle.ALL, false, null, PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null); } } catch (PackageManagerException e) { res.setError("Package couldn't be installed in " + pkg.codePath, e); } Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); }这个方法内部,通过调用scanPackageLI()函数,这样一来APK的各种信息都会记录在PMS中;描完以后,会调用updateSettingsLI()函数来更新APK的权限,设置安装状态等。如果安装成功,则为新安装的app准备数据,如果安装失败,则将apk删除。 以上便是PMS安装apk的过程,下面对这个过程进行总结:
总结:PMS处理apk的安装过程,是从installStage方法开始的,这个方法内部,会通过handler发送一个msg.what是INIT_COPY的消息,handler内部处理这个消息,发起apk文件的复制,这个工作是在com.android.defcontainer进程中进行的,但是复制apk文件时,会先判断是否绑定了DefaultContainerService这个服务,因为只有绑定了DefaultContainerService这个服务,才能和com.android.defcontainer进程进行通信,如果未绑定DefaultContainerService这个服务,则会发起绑定这个服务的请求,绑定完成后,调用InstallParams类的startCopy方法开始复制,这个方法内部会先判断安装的重试次数是否超过了4次,如果超过了,就放弃安装,如果未超过,就开始安装,安装的过程中,根据安装方式,判断安装的位置是否冲突,在判断,安装的位置是否有足够的存储空间,如果没有,释放缓存空间,接着确定安装位置,在接着对apk进行检测。接着会创建一个临时文件路径, 然后在通过进程间通信的方式,在com.android.defcontainer进程中进行apk文件的复制工作。然后复制Native库。完成了apk的复制工作后,apk就在data/app目录下,不过此时还是临时文件的,后续还需要重新命名。如果复制过程为出现异常,则返回INSTALL_SUCCEEDED(1)这个整数;否则,会返回对应的错误码。接着处理返回的复制结果,如果复制正常,则会进入到预安装,预安装这个步骤中,主要是检测包的状态,安装环境,比如sd卡的上的apk安装,如果在安装时,sd卡被拔出了或者sd卡上的文件不存了,所以这里要再次确认下安装的环境,如果安装环境不正常,则会清除复制的apk,如果安装环境正常,则进入实质的安装阶段,这个阶段,会解析apk,并将信息保存到PackageParser$Package类的成员变量中,在接着验证apk的签名信息,处理apk中的权限,接着将临时文件重命名,判断是安装一个新的app还是升级app,然后进行相应的安装和升级,如果安装过程中,安装失败,会删除apk,安装的本质是对apk中文件manifest文件进行解析,并将保存到PackageParser.Package中的信息赋值给Settings这个对象中,完成对Settings对象中对apk信息的更新。在接着是对满足一定条件的apk中的dex文件进行优化,完成安装后,更新apk所属的用户。
参考: 包管理机制分析
Android包管理机制(三)PMS处理APK的安装
应用程序安装流程