Android PackageManagerService(三)pm命令安装流程详解
关于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命令安装流程详解相关推荐
- 《MySQL安装流程详解》及《MySQL安装一直失败,重新安装显示已安装》
<MySQL安装流程详解>及<MySQL安装一直失败,重新安装显示已安装> 本文由博主经过查阅网上资料整理总结后编写,如存在错误或不恰当之处请留言以便更正,内容仅供大家参考学习 ...
- (03)_k8s之flannel三种模型安装部署详解
flannel三种模型安装部署详解 yht_1990关注[2020-10-04 12:13:47](javascript:
- Android apk用pm命令安装apk碰到问题汇总
Android P(API 28 - Andorid 9.0)之前安装 apk: $ adb shell pm install -r xxx.apk 串口下面: # pm install -r xxx ...
- PMS启动 APK 安装流程详解
文章目录 概述 相关类说明 PMS 服务启动 应用程序(APK)安装 有界面安装 无界面安装 APK 安装原理 概述 PackageManagerService(以下简称 PMS)是一个常用的系统服务 ...
- android系统加载主题的流程,详解Android布局加载流程源码
一.首先看布局层次 看这么几张图 我们会发现DecorView里面包裹的内容可能会随着不同的情况而变化,但是在Decor之前的层次关系都是固定的.即Activity包裹PhoneWindow,Phon ...
- Android SDK 和虚拟器 安装过程详解
一.安装Android SDK Android SDK(Software Development Kit,软件开发工具包)提供了 Android API 库和开发工具构建,测试和调试应用程序.Andr ...
- 工业以太网交换机的安装流程详解
工业以太网交换机是应用于工业控制领域的以太网交换机设备,所以设备的安装调试是很重要的一环,那么,我们在安装工业交换机的过程中需要注意什么呢?工业以太网交换机的安装流程是什么呢?接下来我们就跟随飞畅科技 ...
- linux genymotion安装教程,最火Android模拟神器Genymotion之安装过程详解
上文介绍了Genymotion的运行要求,接下来,就该介绍Genymotion的安装需求了,大家肯定会想,安装过程是不是很麻烦啊,别担心,安装过程只需要简单的几步,只需要在Genymotion页面进行 ...
- Android 11---WMS之横竖屏切换流程详解之一
本文以Activity.setRequestedOrientation为入口梳理下横竖屏切换的详细流程. 代码均是基于最新的11.0版本. 第一篇主要讲了横竖屏切换时的准备操作: 更新方向,执 ...
- Android App Bundles相关概念及开发流程详解
本文会根据官网的介绍,结合自己的一些理解,来阐述Android App Bundles的相关概念和开发流程. 主要参考文章如下. https://developer.android.com/guide ...
最新文章
- 【开源方案共享】VDO-SLAM:基于视觉的动态SLAM感知系统
- Google 开源 AdaNet:快速灵活的轻量级 AutoML 框架
- Quartz教程三:Job与JobDetail介绍
- [react] 在React中怎么将参数传递给事件?
- java configuration_关于JAVA 中的Configuration类
- LeetCode 1760. 袋子里最少数目的球(二分查找)
- mysql 10048 linux_解决Can't connect to MySQL server on 'localhost' (10048)
- php管理nginx虚拟主机shell脚本
- 检验密码强度的JS类(from thin's blog)
- Services in Kubernetes
- STM32的位带操作
- Mybatis框架(复杂动态SQL),一对一,一对多,多对多
- 网站/APP 流量分析、用户访问分析
- TCP 和 UDP 区别及使用场景(详细)
- nfc卡模式与标准模式_全功能NFC是什么意思?点对点/读写卡/卡模拟三种模式介绍...
- 【UCOSii源码解析】事件控制块
- 作用域和作用域链的理解
- No valid crumb was included in the request 问题定位与解决
- three.js 相对坐标的设置
- 共享Excel编辑的一些资源