关于pm命令安装,其copy过程与下载安装不同,但安装过程却与下载过程是相同的,这里不做重复分析。

拷贝过程流程图

 pm的入口在com.android.commands.pm.Pm类,那么这是如何调用到这个类的呢,这是adb命令通过adbd守护进程调用到/system/bin/pm这个脚本,其脚本源码如下:

base=/system
export CLASSPATh-$base/framework/pm.jar
exec app_process $base/bin.com.android.commands.pm.Pm "$@"

Pm类通过脚本启动,执行顺序是main->run->runInstall,然后提交session。

public static void main(String[] args) {int exitCode = 1;try {exitCode = new Pm().run(args);} catch (Exception e) {Log.e(TAG, "Error", e);System.err.println("Error: " + e);if (e instanceof RemoteException) {System.err.println(PM_NOT_RUNNING_ERR);}}System.exit(exitCode);
}
 public int run(String[] args) throws RemoteException {boolean validCommand = false;if (args.length < 1) {return showUsage();}mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE));mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE));mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));if (mPm == null) {System.err.println(PM_NOT_RUNNING_ERR);return 1;}mInstaller = mPm.getPackageInstaller();mArgs = args;String op = args[0];mNextArg = 1;//......//安装if ("install".equals(op)) {return runInstall();}if ("uninstall".equals(op)) {return runUninstall();}//.....
}

Pm.runInstall中首先是创建session,然后提交session,代码如下。

 private int runInstall() throws RemoteException {long startedTime = SystemClock.elapsedRealtime();//创建安装参数final InstallParams params = makeInstallParams();//app路径final String inPath = nextArg();if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {File file = new File(inPath);if (file.isFile()) {try {//轻量级解析ApkLite baseApk = PackageParser.parseApkLite(file, 0);PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,null, null);params.sessionParams.setSize(PackageHelper.calculateInstalledSize(pkgLite, false,params.sessionParams.abiOverride));} catch (PackageParserException | IOException e) {System.err.println("Error: Failed to parse APK file: " + e);return 1;}} else {System.err.println("Error: Can't open non-file: " + inPath);return 1;}}//创建一个session idfinal int sessionId = doCreateSession(params.sessionParams,params.installerPackageName, params.userId);try {//copy文件if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {return 1;}//提交sessionPair<String, Integer> status = doCommitSession(sessionId, false /*logSuccess*/);if (status.second != PackageInstaller.STATUS_SUCCESS) {return 1;}return 0;} finally {try {mInstaller.abandonSession(sessionId);} catch (Exception ignore) {}}
}

接下来看doCommitSession,根据id创建PackageInstallerSession的客户端调用commit

//PM.commit
private Pair<String, Integer> doCommitSession(int sessionId, boolean logSuccess)throws RemoteException {PackageInstaller.Session session = null;try {//根据session id  创建sessionsession = new PackageInstaller.Session(mInstaller.openSession(sessionId));final LocalIntentReceiver receiver = new LocalIntentReceiver();//跨进程提交会调用PackageInstallerSession.commitsession.commit(receiver.getIntentSender());final Intent result = receiver.getResult();final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,PackageInstaller.STATUS_FAILURE);return new Pair<>(result.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME), status);} finally {IoUtils.closeQuietly(session);}
}

commit 内部发一个消息,然后调用commitLocked

//PackageInstallerSession.commit
@Override
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {Preconditions.checkNotNull(statusReceiver);final boolean wasSealed;synchronized (mLock) {//.....mCommitted = true;mHandler.obtainMessage(MSG_COMMIT).sendToTarget();}}private final Handler.Callback mHandlerCallback = new Handler.Callback() {@Overridepublic boolean handleMessage(Message msg) {switch (msg.what) {case MSG_COMMIT:synchronized (mLock) {try {//内部调用commitLockedcommitLocked();} catch (PackageManagerException e) {final String completeMsg = ExceptionUtils.getCompleteMessage(e);destroyInternal();dispatchSessionFinished(e.error, completeMsg, null);}}break;}return true;}//PackageInstallerSession.commitLocked
private void commitLocked()throws PackageManagerException {// Unpack native librariesextractNativeLibraries(mResolvedStageDir, params.abiOverride);// Container is ready to go, let's seal it up!if (stageCid != null) {finalizeAndFixContainer(stageCid);}//.......mRelinquished = true;//调用PMS的installStagemPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,mInstallerPackageName, mInstallerUid, user, mCertificates);
}

回到了PMS.installStage

void installStage(String packageName, File stagedDir, String stagedCid,IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,String installerPackageName, int installerUid, UserHandle user,Certificate[][] certificates) {final VerificationInfo verificationInfo = new VerificationInfo(sessionParams.originatingUri, sessionParams.referrerUri,sessionParams.originatingUid, installerUid);final OriginInfo origin;if (stagedDir != null) {origin = OriginInfo.fromStagedFile(stagedDir);} else {origin = OriginInfo.fromStagedContainer(stagedCid);}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, certificates, installReason);params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));msg.obj = params;//发送INIT_COPYmHandler.sendMessage(msg);
}

发送完Handler消息后就与下载安装过程相同了。请参考:Android PackageManagerService(二)下载安装详解

Android PackageManagerService(三)pm命令安装流程详解相关推荐

  1. 《MySQL安装流程详解》及《MySQL安装一直失败,重新安装显示已安装》

    <MySQL安装流程详解>及<MySQL安装一直失败,重新安装显示已安装> 本文由博主经过查阅网上资料整理总结后编写,如存在错误或不恰当之处请留言以便更正,内容仅供大家参考学习 ...

  2. (03)_k8s之flannel三种模型安装部署详解

    flannel三种模型安装部署详解 yht_1990关注[2020-10-04 12:13:47](javascript:

  3. Android apk用pm命令安装apk碰到问题汇总

    Android P(API 28 - Andorid 9.0)之前安装 apk: $ adb shell pm install -r xxx.apk 串口下面: # pm install -r xxx ...

  4. PMS启动 APK 安装流程详解

    文章目录 概述 相关类说明 PMS 服务启动 应用程序(APK)安装 有界面安装 无界面安装 APK 安装原理 概述 PackageManagerService(以下简称 PMS)是一个常用的系统服务 ...

  5. android系统加载主题的流程,详解Android布局加载流程源码

    一.首先看布局层次 看这么几张图 我们会发现DecorView里面包裹的内容可能会随着不同的情况而变化,但是在Decor之前的层次关系都是固定的.即Activity包裹PhoneWindow,Phon ...

  6. Android SDK 和虚拟器 安装过程详解

    一.安装Android SDK Android SDK(Software Development Kit,软件开发工具包)提供了 Android API 库和开发工具构建,测试和调试应用程序.Andr ...

  7. 工业以太网交换机的安装流程详解

    工业以太网交换机是应用于工业控制领域的以太网交换机设备,所以设备的安装调试是很重要的一环,那么,我们在安装工业交换机的过程中需要注意什么呢?工业以太网交换机的安装流程是什么呢?接下来我们就跟随飞畅科技 ...

  8. linux genymotion安装教程,最火Android模拟神器Genymotion之安装过程详解

    上文介绍了Genymotion的运行要求,接下来,就该介绍Genymotion的安装需求了,大家肯定会想,安装过程是不是很麻烦啊,别担心,安装过程只需要简单的几步,只需要在Genymotion页面进行 ...

  9. Android 11---WMS之横竖屏切换流程详解之一

    本文以Activity.setRequestedOrientation为入口梳理下横竖屏切换的详细流程.     代码均是基于最新的11.0版本. 第一篇主要讲了横竖屏切换时的准备操作: 更新方向,执 ...

  10. Android App Bundles相关概念及开发流程详解

    本文会根据官网的介绍,结合自己的一些理解,来阐述Android App Bundles的相关概念和开发流程. 主要参考文章如下. https://developer.android.com/guide ...

最新文章

  1. 【开源方案共享】VDO-SLAM:基于视觉的动态SLAM感知系统
  2. Google 开源 AdaNet:快速灵活的轻量级 AutoML 框架
  3. Quartz教程三:Job与JobDetail介绍
  4. [react] 在React中怎么将参数传递给事件?
  5. java configuration_关于JAVA 中的Configuration类
  6. LeetCode 1760. 袋子里最少数目的球(二分查找)
  7. mysql 10048 linux_解决Can't connect to MySQL server on 'localhost' (10048)
  8. php管理nginx虚拟主机shell脚本
  9. 检验密码强度的JS类(from thin's blog)
  10. Services in Kubernetes
  11. STM32的位带操作
  12. Mybatis框架(复杂动态SQL),一对一,一对多,多对多
  13. 网站/APP 流量分析、用户访问分析
  14. TCP 和 UDP 区别及使用场景(详细)
  15. nfc卡模式与标准模式_全功能NFC是什么意思?点对点/读写卡/卡模拟三种模式介绍...
  16. 【UCOSii源码解析】事件控制块
  17. 作用域和作用域链的理解
  18. No valid crumb was included in the request 问题定位与解决
  19. three.js 相对坐标的设置
  20. 共享Excel编辑的一些资源

热门文章

  1. 宾馆酒店如何对客人进行实名认证登记?
  2. 基于ELMO Composer的MAXON RE40电机增益调节
  3. 通信原理 简易蒙特卡洛仿真法仿真无码间干扰基带系统误码率的matlab实现
  4. 三菱PLC c语言梯形图,三菱plc梯形图实例详解
  5. snagit 注册码
  6. 行政地名、行政区划名、地名分类(矢量数据)
  7. Froala编辑器使用经历
  8. Linux的shell脚本教程(一)
  9. 自学测试的看过来:【全网最全超大型软件测试从零开始学习攻略】
  10. 机器学习正则化线性回归(调参技巧(matlab))