理解包管理机制和PMS

一.概述

包管理机制:包指的是apk,jar和so等文件,他们被加载到Android内存中,由一个包转换成可执行的代码,需要一个机制来进行包的加载、解析和管理等操作,这就是包管理机制。

PackageManagerService(PMS):包管理机制的核心类。

PackageInstaller:安装器,用于apk安装的类。

 

二.PackageInstaller的初始化

1.PackageManager简介

PMS对应的管理类,PackageManager提供以下一些功能:

①.获取一个应用程序的所有信息(ApplicationInfo)。

②.获取四大组件的信息。

③.获取permission的相关信息。

④.获取包的信息。

⑤.安装、卸载APK。

2.APK的文件结构和安装方式

文件结构:

assert:存放的原生资源文件,通过AssertManager类访问。

lib:存放库文件。

MATA-INF:保存应用的签名信息,签名信息可以验证apk文件的完整性。

res:存放资源文件。res除了raw子目录,其他子目录都参与编译,这些子目录的资源可以通过编译出来的R类在代码中访问。

AndroidManifest.xml:用来声明应用程序的包名称、版本、组件和权限等数据。APK中的AndroidManifest.xml经过压缩,可以通过AXMLPrinter2工具解开。

classes.dex:java源码编译后生成的java字节码文件。

resource.arsc:编译后的二进制资源文件。

APK主要有以下四种安装方式

①.通过adb命令安装,adb命令包括adb push/install。

②.用户下载了APK,通过系统安装器PackageInstaller安装该APK。PackageInstaller的系统内置的应用程序,用于安装和卸载应用程序。

③.系统开机时安装系统应用。

④.通过电脑或者手机上的应用商店自动安装。

这四种方式最终都是由PMS来进行处理的,与此前的调用链是不同的,这里介绍第二种方式。

3.寻找PackageInstaller入口

Android 7.0之前,通过下面代码来安装指定路径中的APK。

Intent intent = new Intent(Intent.ACTION_VIEW);

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

intent.setDataAndType(Uri.parse("file://"+path),"application/vnd.android.package-archive");

context.startActivity(intent);

7.0之后受StrictMode API政策禁止应用程序将file://Uri暴露给另一个应用程序。所以如下是Android 7.0及更高版本调用下面代码:

Intent intent = new Intent(Intent.ACTION_VIEW);

intent.setDataAndType(xxxxx,"application/vnd.android.package-archive");

能匹配的Activity为InstallStart,Android 7.0能隐式匹配Activity为PackageInstallerActivity。

InstallStart经过onCreate方法跳转到InstallStaging activity,

然后InstallStaging的onResume方法启动异步任务AsynTask,

然后AsynTask在doInBackground方法中,将packageUri的内容写入mStagedFile中,如果写入成功则再onPostExcute方法中跳转到PackageInstallerActivity中,和Android 7.0一致。

4.PackageInstallerActivity解析

从功能上来说PackageInstallerActivity才是应用安装器PackageInstaller的真正入口Activity。

PackageInstallerActivity中大致流程:

PackageInstallerActivity的onCreate方法--------->processPackageUri(解析uri)---------->checkIfAllowedAndInitiateInstall(判断apk来源)--------->initiateInstall(初始化安装)------->startInstallConfirm(安装确认界面)

onCreate方法:初始化安装需要的各个对象,例如:

类名描述
PackageManager用于向应用程序进程提供一些功能,最终由PMS来实现这些功能
IPackageManager一个AIDL的接口,用于和PMS进行跨进程通信的
AppOpsManager用于权限动态检测,从Android 4.3开始被引入
PackageInstaller提供安装、升级和删除应用程序的功能
UserManager用于多用户管理

processPackageUri方法:对package协议和file协议进行解析,不是这两种协议则关闭PackageInstallerActivity并且返回false。根据file协议继续往下走根据packageUri创建一个File,然后PackageParser的parsePackage方法解析file,得到包信息然后封装成PackageInfo

checkIfAllowedAndInitiateInstall:判断是否允许安装未知来源apk或者判断是否是未知来源apk,如果是true则调用initiateInstall方法,否则调用handleUnknownSources方法处理未知来源apk。

initiateInstall:根据PackageInfo得到包名然后根据包名获得应用信息ApplicationInfo,初始化安装的确认界面startInstallConfirm

startInstallConfirm:创建AppSecurityPermission,根据PackageInfo提取apk的权限信息,然后将权限信息展示在界面。

5.PackageInstaller的初始化过程

①.根据Uri的Scheme协议不同跳转不同界面,android 7.0以上跳转到InstallStart,以下跳转到PackageInstallerActivity。

②.InstallStart将content协议的Uri转换成file协议,然后跳转到PackageInstallerActivity。

③.PackageInstallerActivity分别对package协议和file协议的Uri进行处理,如果是file协议,则会解析apk文件得到包信息PackageInfo。

④.PackageInstallerActivity会对未知来源的apk进行处理,如果是允许未知来源或者不是未知来源的apk则进入安装确认界面。如果不允许就会到handleUnknownSources方法,可能到设置界面或者弹出对话框。

 

三.PackageInstaller安装APK过程

1.PackageInstaller中的处理

onClick方法-------->startInstall--------->跳转到InstallInstalling activity-------->onCreate-------->onResume-------->异步任务AsynTask--------->IPackageInstallerSession的commit方法跨进程---------->java框架层PackageInstallerSession

onClick方法分别对点击事件确认和取消做处理,取消就finish当前界面,确认按钮判断mSessionId是否为-1,是-1调用starInstall方法

InstallInstalling主要是用于向包管理器发送包信息并处理包管理的回调。

onCreate方法中得到mInstallId(安装事件id),注册监听回调,PackageInstallerService的createSession方法创建mSessionId

onResume方法根据mSessionId获得sessionInfo,sessionInfo不为null并且不是活跃的则调用异步任务,异步任务将APK信息通过I/O流写入PackageInstaller.Session中,调用mSession.commit方法

2.Java框架层的处理

PackageInstallerSession的commit方法-------->commitLocked---------->mPm的installStage方法跨进程----------->PMS

 

四.PMS处理APK的安装过程

1.PackageHandler处理安装消息

PMS的installStage-------->PackageHandler的doHandleMessage(INIT_COPY)------->doHandleMessage(MCS_BOUND)--------->HandlerParams的startCopy

doHandleMessage(INIT_COPY)方法:绑定DefaultContainerService服务(此服务用于检查和复制可移动文件的,耗时,所以在新的进程),绑定成功调用doHandleMessage(MCS_BOUND)

doHandleMessage(MCS_BOUND)方法:将安装队列中轮询调用startCopy方法

2.复制APK过程

handlerParams的startCopy------>InstallParams的handleStartCopy------->FileInstallArgs的doCopyApk------->IMediaContainerService的copyPackage------->DefaultContainerService的copyPackage

startCopy:尝试安装次数大于4次则放弃这个安装请求并发送MCS_GIVE_UP消息将此次请求从安装请求队列mPendingInstalls中移除,正常调用到handleStartCopy方法

handleStartCopy:跨进程调用轻量级解析APK信息,确定安装位置InstallArgs(是抽象类),实现类FileInstallArgs(data分区)、AsecInstallArgs(sd卡)、MoveInstallArgs(处理安装后apk的移动逻辑)

此处调用的是FileInstallArgs的doCopyApk方法:创建临时目录,跨进程调用copyPackage复制方法,将APK复制到临时目录

3.PMS处理APK安装

HandlerParams的startCopy方法-------->InstallParams的handleReturnCode方法-------->PMS的processPendingInstall方法--------->installPackageTracedLI-------->installPackageLI------->installNewPackageLIF

processPendingInstall:检测安装环境是否可靠,可靠进行下一步,不可靠清除复制的APK并删除相关目录与文件。

installPackageLI:

①.创建PackageParser,解析APK。

②.APK是否存在,是否替换安装。

③.是否在Setting中存在安装APK的信息,如果存在说明此前安装过此APK,需要校检APK的签名信息,确保进行替换安装是安全的。

④.重命名临时文件。将临时文件夹替换成包名的形式

⑤.系统App的更新安装会有两个限制:1.不能再SD卡进行替换安装,2.另一个是系统App不能被Instant App替换

⑥.根据replace进行区分是替换安装还是安装新的apk,此处安装新的apk则是installNewPackageLIF方法,替换安装是replacePackageLIF方法

installNewPackageLIF:

①.扫描APK,将APK信息存储在PackageParser.Package类型的newPackage中,一个Package的信息包括一个base APK及0或多个split APK。

②.更新APK对应的Setting信息,用于保存所有包的动态设置。

③.如果安装成功,就为新安装的应用程序准备数据,如果安装失败,删除APK

4.PMS处理APK安装的步骤

①.PackageInstaller安装APK时会将APK的信息交由PMS来处理,PMS通过PackageHandler发送消息来驱动apk的复制和安装。

②.PMS发送INIT_COPY和MCS_BOUND类型消息绑定DefaultContainerService完成复制APK工作。

③.复制完成apk,开始安装APK的流程,包括安装前的检查、安装APK和安装后的收尾工作。

 

五.PMS的创建过程

1.SystemServer处理部分

SystemServer的main方法--------->run方法-------->startBootstrapServices启动引导服务-------->PMS构造方法------>是否第一次启动PMS

2.PMS构造方法

PMS构造方法大致分为五个阶段:开始阶段、扫描系统阶段、扫描Data分区阶段、扫描结束阶段、准备阶段。

①.开始阶段

开始阶段创建了很多关键的对象:

mSettings:用于保存所有包的动态设置,比如:sharedUserId(进程共享id)

mInstaller:是继承SystemService的系统服务,和PMS、AMS一样。PMS很多操作是Installer完成的,比如apk的安装和卸载。

systemConfig:用于得到全局系统的配置信息,比如系统的权限。

mPackageDexOptimizer:Dex优化工具类。

mHandler(PackageHandler类型):PMS通过PackageHandler驱动APK的复制和安装工作。

Watchdog主要两个用途:1.定时检测系统关键服务(AMS和WMS等)是否发生死锁。2.定时检测线程的消息队列是否长时间处于工作状态。如果出现上述问题,则Watchdog会将日志保存起来,必要时会杀掉自己所在进程,也就是SystemServer进程。

sUserManager(UserManagerService类型):多用户管理服务。

关键代码:

两次加锁,一次是安装apk的锁,一次是更新apk的锁。

创建data分区

解析packages.xml等文件信息保存到Settings对应字段中,包括基本信息、签名和权限。如果有安装信息则不是首次安装

②.扫描系统阶段

主要工作:

1.创建/system子目录,比如/system/framework、/system/app等。

2.扫描系统文件,比如:/vendor/overlay、/system/framework和/system/app等目录下的文件。

3.对扫描到的系统文件进行后续处理。主要是对升级后的app的各种情况做操作。

③.扫描Data分区阶段

主要工作:

1.扫描/data/app和/data/app-private目录下的文件

2.移除残留的app信息和移除不属于系统的权限信息

3.解析参数并将数据添加到mSetting的mPackages中

④.扫描结束阶段

主要工作:

1.如果当前平台的SDK版本和上次启动时的SDK版本不同,则重新更新apk的授权。

2.如果是第一次启动或者是Android M升级后的第一次启动,则需要初始化所有用户定义的默认首选App。

3.OTA升级后第一次启动,会清除代码缓存目录。

4.把Setting的内容保存到packages.xml中,这样以后PMS再创建时会读到此前保存的Settings的内容。

⑤.准备阶段

主要工作:

1.创建PackageInstallerService用于管理安装会话的服务,它会为每次安装过程分配一个sessionId。

2.进行一次垃圾回收。

3.将PackageManagerInternalImpl(PackageManager的本地服务)添加到LocalServices中,LocalServices用于存储运行在当前进程中的本地服务。

 

六.APK解析过程

1.引入PackageParser

需要一个工具类将包转换为内存中的数据结构,这个工具就是包解析器PackageParser

在installPackageLI中创建PackageParser

2.PackageParser解析APK

Android 5.0引入了Split APK机制,解决65536上线及安装包越来越大等问题。

引入后apk有两种分类:

Single APK:完成的APK安装文件,即base APK。Android称其为Monolithic

Mutiple APK:在一个文件目录中安装文件,其内部有多个被拆分的APK,这些APK由一个base APK和一个或多个split APK组成。Android称其为Cluster

解析过程:parsePackage-------->parseClusterPackage------>parseBaseApk------->parseBaseApk------>parseBaseApkCommon------->parseBaseApplication

parsePackage:如果是目录则说明apk种类为Mutiple APK,调用parseClusterPackage解析,反之是Single APK,调用parseMonolithicPackage解析。

parseClusterPackage:轻量级解析目录内容,是否是核心应用,调用parseBaseApk解析base APK,调用parseSplitApk解析split APK。

parseBaseApk:获取volumeUuid,用于标识解析后的package。

parseBaseApk:创建Package对象,提取attrs_manifest.xml中的属性值,最后调用parseBaseApkCommon解析AndroidManifest中各个标签。

parseBaseApplication:解析application标签,包括四大组件等等。

3.Package的数据结构

①.Package中有许多组件,比如:Activity,Provider和Permission等,他们都继承基类Component

②.每个组件都包含一个info,比如ActivityInfo,是Activity的数据。

③.四大组件的标签内可能含有<intent-filter>,用来过滤Intent信息,因此需要IntentInfo来保存组件的Intent信息,组件基类Component依赖IntentInfo。IntentInfo有三个子类,即ActivityIntentInfo、ServiceIntentInfo、ProviderIntentInfo,不同组件依赖不同的IntentInfo。

 

 

 

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页