关于frameworks:MASA-Framework-DDD设计2

Clean Architecture国内对于Clean Architecture的翻译很多,洁净/整洁/清晰。但无论哪一种都阐明了它简洁、清晰的个性。 晚期它长这样 看到这张图的同学可能会对另外一张图有印象 洋葱架构(Onion) 当初长这样 看起来如同是亲戚,它们确实也有着千头万绪的关系 剖析Clean Architecture这部分次要是依据explicit architecture文章的了解整顿的,有翻译也有本人理解消化的。如有错漏欢送斧正,谢谢三大构建块用户界面基础设施利用外围 控制流用户界面利用外围基础设施利用外围用户界面 工具左右两侧造成鲜明对比,动机不同 HTTP/CLI:通知利用要做什么SMS/Mailing Server/Search Engine...:利用通知它们要做什么 链接工具和交付机制到利用外围将工具连贯到应用程序外围的代码单元称为适配器(端口和适配器架构)。 通知咱们的应用程序做某事的适配器称为主适配器或被动适配器,而咱们的应用程序通知咱们做某事的适配器称为从适配器或被动适配器。 端口这些适配器为了适应利用外围的一个十分特定的入口点,即端口。端口只不过是工具如何应用应用程序外围或利用外围如何应用它的标准。 你能够看作是接口和DTO主适配器或被动适配器主适配器或被动适配器围绕一个端口并应用它来通知利用外围该做什么。 咱们的被动适配器是Controller或Console Commands,它们在其构造函数中注入了一些对象,该对象的类实现了Controller或Console Commands所需的接口(端口)。 端口能够是控制器须要的服务接口或存储库接口,而后将 Service、Repository 或 Query 的具体实现注入并在 Controller 中应用。 或者,端口能够是Command Bus或Query Bus的接口。在这种状况下,将Command Bus或Query Bus的具体实现注入到Controller中,而后Controller结构Command或Query并将其传递给相干Bus。 注:这里其实提到了CQRS 从适配器或被动适配器与围绕在端口四周的被动适配器不同,从适配器实现一个端口、一个接口,而后在须要端口的任何中央注入利用外围。 能够了解为是右侧是合乎利用外围的须要的接口或者对象,而左侧则是包装用例的传播机制,如HTTP/CLI等 假如咱们有一个须要长久化数据的需要: 咱们创立一个长久化接口(在左侧端口四周),有一个保留数据的办法和一个通过ID删除数据的办法基础设施中提供一个实现类,通过IoC注入这个接口和对应的实现类在须要长久化数据的类的构造函数中注入一个长久化接口如果有一天咱们须要从SQL Server换到MongoDb,只须要替换步骤2中的实现类和注入新的实现类即可IoC与上图相比,仅仅是多了一个蓝色的箭头从内部直插入利用外围外部。在下面例子中有提到通过IoC的作用这里就不再反复了。 至此,咱们统一在解说利用外围的外围,而利用外围是咱们架构设计的重点。 利用外围组织洋葱架构采纳 DDD 分层并将它们合并到端口和适配器架构中。这些层旨在为业务逻辑带来一些组织,即端口和适配器“六边形”的外部,就像在端口和适配器中一样,依赖方向是朝向核心的。 应用层用例(Use Case)是咱们的利用中的一个或多个用户界面触发的流程(业务逻辑)。用户界面能够是终端用户界面也能够是治理界面,或者控制台界面和API。 用例在应用层定义,由DDD和洋葱架构提供,它能够蕴含端口,ORM接口,搜索引擎接口,音讯接口等,也能够是CQRS解决Handlers的中央,发送邮件,调用第三方API等。 应用服务/Command Handler蕴含用例的业务逻辑,作用是: 应用Repository查找一个或多个实体通知这些实体做一些畛域逻辑应用Repository长久化这些实体,保留数据更改Command Handler能够有两种不同的应用形式: 蕴含执行用例的实在业务逻辑作为架构中的中间件,接管Command并触发应用服务中的逻辑 畛域层畛域内的对象除了有对象自身的属性外,还能够操作该对象外部的属性,这是特定于域自身的,并且独立于触发该逻辑的业务流程,它们是独立的,齐全不晓得应用层。 畛域服务有时咱们会遇到一些波及不同实体的畛域逻辑,无论是否雷同,该畛域逻辑不属于实体自身,它没有间接责任。 那咱们能够应用畛域服务来承载这部分逻辑,可能有人会感觉那能够放应用层,但畛域逻辑在其余用例中就不能重用了。畛域逻辑应该在畛域外部,不要回升到应用层。 畛域服务能够应用其余畛域服务,或者其余畛域对象畛域模型在最核心,依赖于它之外的任何货色,是畛域模型,它蕴含代表畛域中某些事物的业务对象。至于如何定义畛域模型能够参考第一篇。 组件组件与利用外围内所有的层穿插,从外贯通到外部。例如身份验证、受权、计费、用户、评论或账户,但它们仍然与畛域无关。 像受权和身份验证这样的限界上下文应该被视为暗藏在某种端口前面的内部工具。 解耦组件具备齐全解耦的组件意味着一个组件不间接理解任何另一个组件。换句话说,它可能没有接口,所以咱们须要一些新的架构构造。 比方事件、最终一致性、服务发现等。当你往这条路上走的时候,你就开始脱离单体了。 这里Dapr或者是个不错的抉择,它蕴含了这些性能,对Dapr感兴趣的能够看之前的手把手教你学Dapr系列MASA Framework解决方案联合DDD和Clean Architecture以及MASA Framework的个性,咱们将在MASA.BuildingBlocks中以接口的模式定义标准,在MASA.Contrib中对接口进行实现。 ...

February 23, 2022 · 1 min · jiezi

借助URLOS快速安装beego-web框架

简介beego是一个快速开发Go应用的http框架,go 语言方面技术大牛。beego可以用来快速开发API、Web、后端服务等各种应用,是一个RESTFul的框架。 今天我们介绍一种更快速的安装方法,那就是通过URLOS一键安装beego。urlos是什么? URLOS是一个云主机管理软件,基于Docker容器技术打包和运行应用,包含负载均衡和故障转移等高级功能,可自动识别机器和云应用的故障并将云应用转移至可用的机器上,单机故障并不影响业务开展。 你可以使用以下命令安装URLOS: curl -LO www.urlos.com/iu && sh iu在此不讨论URLOS的使用方法,感兴趣的朋友请自行搜索,我们直接来看URLOS如何快速安装beego: 安装流程1.登录URLOS系统后台,在应用市场中搜索“beego”,找到之后,直接点击安装按钮 2.填写服务名称、选择运行节点、服务端口、选择智能部署 3.填写域名:www.aaa.com(这里填写自己的域名) 4.设置SFTP选择“上传与下载”选项卡,开启SFTP上传下载并填写SFTP端口、SFTP密码; 然后点击“提交”按钮,等待部署完成; 部署完成后,网站已经成功跑起来了! 上传网站代码用ssh或者sftp客户端登录。 网站根目录是:/mounts/beego001/data/www/web(由于本次教程的服务名称为beego001,实际操作中根据你填写的服务名称自动创建) 如果要更新网站,上传网站文件到网站根目录后,重新部署一下就好了:

July 10, 2019 · 1 min · jiezi

mybatis处理枚举类

mybatis自带对枚举的处理类org.apache.ibatis.type.EnumOrdinalTypeHandler<E> :该类实现了枚举类型和Integer类型的相互转换。但是给转换仅仅是将对应的枚举转换为其索引位置,也就是"ordinal()"方法获取到的值。对应自定义的int值,该类无能为力。 org.apache.ibatis.type.EnumTypeHandler<E>:该类实现了枚举类型和String类型的相互转换。对于想将枚举在数据库中存储为对应的int值的情况,该类没办法实现。 基于以上mybatis提供的两个枚举处理类的能力有限,因此只能自己定义对枚举的转换了。 自定义mybatis的枚举处理类EnumValueTypeHandler该类需要继承org.apache.ibatis.type.BaseTypeHandler<E>,然后在重定义的方法中实现自有逻辑。 import java.sql.CallableStatement;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import org.apache.ibatis.type.MappedTypes;import org.apache.ibatis.type.BaseTypeHandler;import org.apache.ibatis.type.JdbcType;/** * 处理实现了{@link EsnBaseEnum}接口的枚举类 * @author followtry * @time 2016年8月16日 下午8:06:49 * @since 2016年8月16日 下午8:06:49 */ //在 xml 中添加该 TypeHandler 时需要使用该注解@MappedTypes(value = { QcListTypeEnum.class, SellingQcBizTypeEnum.class})public class EnumValueTypeHandler<E extends EsnBaseEnum> extends BaseTypeHandler<E> { private Class<E> type; private final E[] enums; public EnumValueTypeHandler(Class<E> type) { if (type == null) { throw new IllegalArgumentException("Type argument cannot be null"); } this.type = type; this.enums = type.getEnumConstants(); if (this.enums == null) { throw new IllegalArgumentException(type.getSimpleName() + " does not represent an enum type."); } } @Override public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException { //获取非空的枚举的int值并设置到statement中 ps.setInt(i, parameter.getValue()); } @Override public E getNullableResult(ResultSet rs, String columnName) throws SQLException { int i = rs.getInt(columnName); if (rs.wasNull()) { return null; } else { try { return getEnumByValue(i); } catch (Exception ex) { throw new IllegalArgumentException( "Cannot convert " + i + " to " + type.getSimpleName() + " by ordinal value.", ex); } } } /** * 通过枚举类型的int值,获取到对应的枚举类型 * @author jingzz * @param i */ protected E getEnumByValue(int i) { for (E e : enums) { if (e.getValue() == i) { return e; } } return null; } @Override public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException { int i = rs.getInt(columnIndex); if (rs.wasNull()) { return null; } else { try { return getEnumByValue(i); } catch (Exception ex) { throw new IllegalArgumentException( "Cannot convert " + i + " to " + type.getSimpleName() + " by ordinal value.", ex); } } } @Override public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { int i = cs.getInt(columnIndex); if (cs.wasNull()) { return null; } else { try { return getEnumByValue(i); } catch (Exception ex) { throw new IllegalArgumentException( "Cannot convert " + i + " to " + type.getSimpleName() + " by ordinal value.", ex); } } }}该处理器是处理继承了EsnBaseEnum接口的枚举类,因为该接口中定义了获取自定义int值的方法。 ...

May 13, 2019 · 3 min · jiezi

Android 8.1 源码_核心篇 -- 深入研究 PMS 系列(6)之 APK 安装流程(PMS)

开篇核心源码关键类路径PackageInstallerSession.javaframeworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.javaPackageManagerService.javaframeworks/base/services/core/java/com/android/server/pm/PackageManagerService.java前言在本系列上一篇文章 【深入研究 PackageManagerService 系列(5)之 PackageInstaller - APK 安装流程】 中,我们了解了 PackageInstaller 安装 APK 的流程,最后会将 APK 的信息交由 PMS 处理。那么 PMS 是如何处理的?这就是我们这篇文章需要分析的。PackageHandlercommitLocked在前一篇文章末尾,我们讲过 commitLocked 方法,我们回顾下: private final PackageManagerService mPm; private void commitLocked() throws PackageManagerException { … … /** * commitLocked 方法很长,我们主要关注这一行代码 * 调用 PackageManagerService 的 installStage 方法 * 这样安装 APK 的代码逻辑就进入了 PackageManagerService 中 / mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params, mInstallerPackageName, mInstallerUid, user, mCertificates); }installStage正式进入 PMS 源码分析流程,我们看看 installStage 方法: void installStage(String packageName, File stagedDir, String stagedCid, IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams, String installerPackageName, int installerUid, UserHandle user, Certificate[][] certificates) { … … // 创建类型为 INIT_COPY 的消息 final Message msg = mHandler.obtainMessage(INIT_COPY); final int installReason = fixUpInstallReason(installerPackageName, installerUid, sessionParams.installReason); // 创建 InstallParams,它对应于包的安装数据 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; … … // 将 InstallParams 通过消息发送出去 mHandler.sendMessage(msg); }handleMessage因为 PackageHandler 继承 Handler ,所以我们来看下 PackageHandler 的 HandlerMessage 方法: public void handleMessage(Message msg) { try { doHandleMessage(msg); } finally { // 设置了线程的优先级为后台线程 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } }INIT_COPY接下来看下 INIT_COPY 消息的处理流程: class PackageHandler extends Handler { private boolean mBound = false; final ArrayList<HandlerParams> mPendingInstalls = new ArrayList<HandlerParams>(); … … // 用于处理各个类型的消息 void doHandleMessage(Message msg) { switch (msg.what) { case INIT_COPY: { // 取出 InstallParams HandlerParams params = (HandlerParams) msg.obj; // idx 为当前需要安装的 APK 个数,mPendingInstalls 里面保存所有需要安装的 APK 解析出来的 HandlerParams 参数 int idx = mPendingInstalls.size(); if (DEBUG_INSTALL) Slog.i(TAG, “init_copy idx=” + idx + “: " + params); // mBound 用于标识是否绑定了服务(DefaultContainerService), // 如果已经绑定了,则 mBound 为true,如果是第一次调用 mBound 为 false,默认值为 false。 if (!mBound) { Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, “bindingMCS”, System.identityHashCode(mHandler)); // 如果没有绑定服务,重新绑定,connectToService 方法内部如果绑定成功会将 mBound 置为 true if (!connectToService()) { Slog.e(TAG, “Failed to bind to media container service”); params.serviceError(); Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, “bindingMCS”, System.identityHashCode(mHandler)); if (params.traceMethod != null) { Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod, params.traceCookie); } // 绑定服务失败则 return return; } else { // 绑定服务成功,将请求添加到 ArrayList 类型的 mPendingInstalls 中,等待处理 mPendingInstalls.add(idx, params); } } else { // 已经绑定服务 mPendingInstalls.add(idx, params); if (idx == 0) { // 如果是第一个安装请求,则直接发送事件 MCS_BOUND 触发处理流程 mHandler.sendEmptyMessage(MCS_BOUND); } } break; } … … }connectToService假设我们是第一次走流程,还没有绑定服务,则会调用 connectToService() 方法,我们看下流程: class PackageHandler extends Handler { private boolean connectToService() { if (DEBUG_SD_INSTALL) Log.i(TAG, “Trying to bind to” + " DefaultContainerService”); Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); /* * bindServiceAsUser 方法会传入 mDefContainerConn, * bindServiceAsUser 方法的处理逻辑和我们调用 bindService 是类似的, * 服务建立连接后,会调用 onServiceConnected / if (mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); // 如果绑定 DefaultContainerService 成功,mBound 会置为 ture mBound = true; return true; } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); return false; }这里可以看到 bind 到了一个 service ,这个 service 的 ComponentName 是 “DEFAULT_CONTAINER_COMPONENT” 这个常量,那我们就来看下这个 ComponentName。 static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName( DEFAULT_CONTAINER_PACKAGE, “com.android.defcontainer.DefaultContainerService”);所以我们知道 bind 的 service 是 DefaultContainerService 。绑定 DefaultContainerService 之后,设定进程的优先级为 THREAD_PRIORITY_DEFAULT。然后等 bindServiceAsUser 这个方法执行完则又把线程的优先级设为 THREAD_PRIORITY_BACKGROUND。我们这边要重点提到一个 mDefContainerConn 变量,研究一下: final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();这下我们知道了 mDefContainerConn 的类型是 DefaultContainerConnection ,那我们来看下 DefaultContainerConnection 这个类。DefaultContainerConnection // DefaultContainerConnection 实现了 ServiceConnection,所以在连接成功的时候会调用 onServiceConnected 方法 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)); // 发送了 MCS_BOUND 类型的消息 mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs)); } public void onServiceDisconnected(ComponentName name) { if (DEBUG_SD_INSTALL) Log.i(TAG, “onServiceDisconnected”); } }上文我们提及到 mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM) 方法,其实就是"绑定" DefaultContainerService。我们知道 bind 一个 Service ,其中负责通信的 ServiceConnection,而本方法中负责通信的就是 mDefContainerConn。所以一旦绑定成功会执行 mDefContainerConn 的 onServiceConnected 方法。而现实是当绑定成功后在 onServiceConnected 中将一个 IBinder 转换成了一个 IMediaContainerService。这个就是 onServiceConnected 回调函数中根据参数传进来的 IMediaContainerService.Stub 的对象引用创建的一个远程代理对象,后面 PacakgeManagerServic 通过该代理对象访问 DefaultContainerService 服务。我们简单梳理一下以上代码所做的工作: ✨ mBound 用于标识是否绑定了 DefaultContainerService,默认值为 false。 ✨ DefaultContainerService 是用于检查和复制可移动文件的服务,这是一个比较耗时的操作,因此 DefaultContainerService 没有和 PMS 运行在同一进程中,它运行在 com.android.defcontainer 进程,通过 IMediaContainerService 和 PMS 进行 IPC 通信。彼此之间的 IPC 通信如下图所示: ✨ connectToService 方法用来绑定 DefaultContainerService。 ✨ mHandler.sendEmptyMessage(MCS_BOUND):发送 MCS_BOUND 类型的消息,触发处理第一个安装请求。不知道你是否发现,有两个发送 MCS_BOUND 类型消息的方法:// PackageHandler.doHandleMessage(已绑定服务)mHandler.sendEmptyMessage(MCS_BOUND); // 不带参数// DefaultContainerConnection(未绑定服务 - 绑定服务)mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs)); // 带参数MCS_BOUND 分析不带参数case MCS_BOUND: { if (DEBUG_INSTALL) Slog.i(TAG, “mcs_bound”); // 不带参数,则此条件不满足 if (msg.obj != null) { mContainerService = (IMediaContainerService) msg.obj; Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, “bindingMCS”, System.identityHashCode(mHandler)); } // 走这边的逻辑 if (mContainerService == null) { // 服务没有绑定,则走这边,但是之前我们讲解过,发送 MCS_BOUND 时,已经绑定了服务,这显然是不正常的 if (!mBound) { // Something seriously wrong since we are not bound and we are not // waiting for connection. Bail out. Slog.e(TAG, “Cannot bind to media container service”); for (HandlerParams params : mPendingInstalls) { // 负责处理服务发生错误的情况 params.serviceError(); Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, “queueInstall”, System.identityHashCode(params)); if (params.traceMethod != null) { Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod, params.traceCookie); } return; } // 绑定失败,清空安装请求队列 mPendingInstalls.clear(); } else { // 继续等待绑定服务 Slog.w(TAG, “Waiting to connect to media container service”); } } else if (mPendingInstalls.size() > 0) { … … } else { // Should never happen ideally. Slog.w(TAG, “Empty queue”); } break;}带参数case MCS_BOUND: { if (DEBUG_INSTALL) Slog.i(TAG, “mcs_bound”); if (msg.obj != null) { mContainerService = (IMediaContainerService) msg.obj; Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, “bindingMCS”, System.identityHashCode(mHandler)); } // 带参数,此条件不满足 if (mContainerService == null) { … … // 走这边的逻辑,安装请求队列不为空 } else if (mPendingInstalls.size() > 0) { // 得到安装请求队列第一个请求 HandlerParams HandlerParams params = mPendingInstalls.get(0); if (params != null) { Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, “queueInstall”, System.identityHashCode(params)); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, “startCopy”); // 如果 HandlerParams 不为 null 就会调用 HandlerParams 的 startCopy 方法,用于开始复制 APK 的流程 if (params.startCopy()) { if (DEBUG_SD_INSTALL) Log.i(TAG, “Checking for more work or unbind…”); // 如果 APK 安装成功,删除本次安装请求 if (mPendingInstalls.size() > 0) { mPendingInstalls.remove(0); } if (mPendingInstalls.size() == 0) { if (mBound) { // 如果没有安装请求了,发送解绑服务的请求 if (DEBUG_SD_INSTALL) Log.i(TAG, “Posting delayed MCS_UNBIND”); removeMessages(MCS_UNBIND); Message ubmsg = obtainMessage(MCS_UNBIND); sendMessageDelayed(ubmsg, 10000); } } else { if (DEBUG_SD_INSTALL) Log.i(TAG, “Posting MCS_BOUND for next work”); // 如果还有其他的安装请求,接着发送 MCS_BOUND 消息继续处理剩余的安装请求 mHandler.sendEmptyMessage(MCS_BOUND); } } Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } // 如果安装请求数不大于 0 就会打印 “Empty queue” } else { // Should never happen ideally. Slog.w(TAG, “Empty queue”); } break;}上面的流程其实很简单,我们根据是否传入了 ims 这个参数,走两条流程,核心的方法就是最终的 startCopy()。复制 APK上面我们提过,Copy APK 的操作是调用 HandlerParams 的 startCopy 方法。HandlerParams 是 PMS 中的抽象类,它的实现类为 PMS 的内部类 InstallParams。startCopy private abstract class HandlerParams { private static final int MAX_RETRIES = 4; /* * Number of times startCopy() has been attempted and had a non-fatal * error. / private int mRetries = 0; … … final boolean startCopy() { boolean res; try { if (DEBUG_INSTALL) Slog.i(TAG, “startCopy " + mUser + “: " + this); /* * mRetries 用于记录 startCopy 方法调用的次数,调用 startCopy 方法时会先自动加 1 * startCopy 方法尝试的次数超过了 4 次,就放弃这个安装请求 / if (++mRetries > MAX_RETRIES) { Slog.w(TAG, “Failed to invoke remote methods on default container service. Giving up”); // 发送 MCS_GIVE_UP 类型消息,将第一个安装请求(本次安装请求)从安装请求队列 mPendingInstalls 中移除掉 mHandler.sendEmptyMessage(MCS_GIVE_UP); handleServiceError(); return false; } else { handleStartCopy(); // ???? ???? ???? 重点方法 ???? ???? ???? res = true; } } catch (RemoteException e) { if (DEBUG_INSTALL) Slog.i(TAG, “Posting install MCS_RECONNECT”); mHandler.sendEmptyMessage(MCS_RECONNECT); res = false; } // 调用 handleReturnCode 抽象方法,这个方法会在 handleStartCopy 执行完拷贝相关行为之后,根据 handleStartCopy 做进一步的处理,主要返回状态码 handleReturnCode(); return res; } … … abstract void handleStartCopy() throws RemoteException; abstract void handleServiceError(); abstract void handleReturnCode(); }这边我们还是简单的看一下 MCS_GIVE_UP 和 MCS_RECONNECT 两种 message 的处理流程,逻辑相当简单:MCS_RECONNECT case MCS_RECONNECT: { if (DEBUG_INSTALL) Slog.i(TAG, “mcs_reconnect”); if (mPendingInstalls.size() > 0) { if (mBound) { disconnectService(); } if (!connectToService()) { Slog.e(TAG, “Failed to bind to media container service”); for (HandlerParams params : mPendingInstalls) { // Indicate service bind error params.serviceError(); Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, “queueInstall”, System.identityHashCode(params)); } mPendingInstalls.clear(); } } break; }判断安装请求队列 mPendingInstalls 是否还有元素,如果有元素先断开绑定,则再次重新调用 connectToService 方法,我们知道 connectToService() 内部会再次执行绑定 DefaultContainerService,而在绑定成功后会再次发送一个 what 值为 MCS_BOUND 的 Message,从而又回到了 startCopy 里面。MCS_GIVE_UP case MCS_GIVE_UP: { if (DEBUG_INSTALL) Slog.i(TAG, “mcs_giveup too many retries”); HandlerParams params = mPendingInstalls.remove(0); Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, “queueInstall”, System.identityHashCode(params)); break; }直接删除了安装请求队列 mPendingInstalls 里面下标为 0 的元素,即取消本次安装请求。handleStartCopy我们发现 handleStartCopy 也是一个抽象的方法,那么它在哪实现?前面我们说过:HandlerParams 是 PMS 中的抽象类,它的实现类为 PMS 的内部类 InstallParams。 class InstallParams extends HandlerParams { / * Invoke remote method to get package information and install * location values. Override install location based on default * policy if needed and then create install arguments based * on the install location. / public void handleStartCopy() throws RemoteException { int ret = PackageManager.INSTALL_SUCCEEDED; … … /* * 确定 APK 的安装位置 * onSd: 安装到 SD 卡 * onInt: 内部存储即 Data 分区 * ephemeral:安装到临时存储 / 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; // APK 不能同时安装在 SD 卡和 Data 分区 if (onInt && onSd) { // Check if both bits are set. Slog.w(TAG, “Conflicting flags specified for installing on both internal and external”); ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; // 安装标志冲突,Instant Apps 不能安装到 SD 卡中 } else if (onSd && ephemeral) { Slog.w(TAG, “Conflicting flags specified for installing ephemeral on external”); ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; } else { /* * 获取 APK 的少量的信息 * 通过 IMediaContainerService 跨进程调用 DefaultContainerService 的 getMinimalPackageInfo 方法, * 该方法轻量解析 APK 并得到 APK 的少量信息, * 轻量解析的原因是这里不需要得到 APK 的全部信息,APK 的少量信息会封装到 PackageInfoLite 中。 / pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags, packageAbiOverride); if (DEBUG_EPHEMERAL && ephemeral) { Slog.v(TAG, “pkgLite for install: " + pkgLite); } … .. } if (ret == PackageManager.INSTALL_SUCCEEDED) { // 判断安装的位置 int loc = pkgLite.recommendedInstallLocation; if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) { ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) { … … } else { installFlags = sPmsExt.customizeInstallPkgFlags(installFlags, pkgLite, mSettings.mPackages, getUser()); loc = installLocationPolicy(pkgLite); … … } } /* * 根据 InstallParams 创建 InstallArgs 对象 * InstallArgs 是一个抽象类,定义了 APK 的安装逻辑,比如"复制"和"重命名” APK 等 * * abstract int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException; * * InstallArgs 有 3 个子类,都被定义在 PMS 中: * FileInstallArgs:用于处理安装到非 ASEC 的存储空间的 APK ,也就是内部存储空间(Data分区) * AsecInstallArgs:用于处理安装到 ASEC 中(mnt/asec)即 SD 卡中的 APK * MoveInstallArgs:用于处理已安装 APK 的移动的逻辑 / final InstallArgs args = createInstallArgs(this); mArgs = args; if (ret == PackageManager.INSTALL_SUCCEEDED) { … … if (!origin.existing && requiredUid != -1 && isVerificationEnabled( verifierUser.getIdentifier(), installFlags, installerUid)) { … … } else { // 对 APK 进行检查后就会调用 InstallArgs 的 copyApk 方法进行安装 ret = args.copyApk(mContainerService, true); } } mRet = ret; } … … }FileInstallArgsOK,我们知道 InstallParams 有三个子类,不同的 InstallArgs 子类会有着不同的处理,那我们现在以 FileInstallArgs 为例跟踪学习一下具体的流程:copyApk /* * Logic to handle installation of non-ASEC applications, including copying * and renaming logic. / class FileInstallArgs extends InstallArgs { private File codeFile; … … int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, “copyApk”); try { return doCopyApk(imcs, temp); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } }doCopyApk调用了 doCopyApk 方法: private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException { … … try { final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; // 用于创建临时存储目录,比如 /data/app/vmdl18300388.tmp ,其中 18300388 是安装的 sessionId 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; /* * 通过 IMediaContainerService 跨进程调用 DefaultContainerService 的 copyPackage 方法, * 这个方法会在 DefaultContainerService 所在的进程中将 APK 复制到临时存储目录, * 比如 /data/app/vmdl18300388.tmp/base.apk 。 / ret = imcs.copyPackage(origin.file.getAbsolutePath(), target); // 真正的文件拷贝 … … return ret; }安装 APKhandleReturnCode我们回到 APK 的复制调用链的头部方法:HandlerParams 的 startCopy 方法,在最后 调用了 handleReturnCode 方法,进行 APK 的安装。 private abstract class HandlerParams { private static final int MAX_RETRIES = 4; private int mRetries = 0; … … final boolean startCopy() { boolean res; try { if (++mRetries > MAX_RETRIES) { … … } else { handleStartCopy(); res = true; } } catch (RemoteException e) { … … } // 处理复制 APK 后的安装 APK 逻辑 handleReturnCode(); // ???? ???? ???? ???? ???? ???? return res; } … … abstract void handleReturnCode(); }handleReturnCode 也是一个抽象方法,那么在哪里实现?同样,它的实现在 InstallParams 中。 @Override void handleReturnCode() { // If mArgs is null, then MCS couldn’t be reached. When it // reconnects, it will try again to install. At that point, this // will succeed. if (mArgs != null) { // “装载代码"的入口是 processPendingInstall(InstallArgs,int) 方法 processPendingInstall(mArgs, mRet); } }我们发现调用了 processPendingInstall 方法,继续跟!processPendingInstall 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) { /* * 安装前处理 * 用于检查 APK 的状态的,在安装前确保安装环境的可靠,如果不可靠会清除复制的 APK 文件 args.doPreInstall(res.returnCode); synchronized (mInstallLock) { installPackageTracedLI(args, res); // ???? ???? ???? ???? ???? ???? } /** * 安装后收尾 * 用于处理安装后的收尾操作,如果安装不成功,删除掉安装相关的目录与文件 args.doPostInstall(res.returnCode, res.uid); } … … } }); }installPackageTracedLI private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) { try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, “installPackage”); installPackageLI(args, res); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } }installPackageLI private void installPackageLI(InstallArgs args, PackageInstalledInfo res) { … … PackageParser pp = new PackageParser(); pp.setSeparateProcesses(mSeparateProcesses); pp.setDisplayMetrics(mMetrics); pp.setCallback(mPackageParserCallback); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, “parsePackage”); final PackageParser.Package pkg; try { // 解析 APK pkg = pp.parsePackage(tmpPackageFile, parseFlags); } catch (PackageParserException e) { res.setError(“Failed parse during installPackageLI”, e); return; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } … … // Get rid of all references to package scan path via parser. pp = null; String oldCodePath = null; boolean systemApp = false; synchronized (mPackages) { // 检查 APK 是否存在 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; // 设置标志位表示是替换安装 replace = true; if (DEBUG_INSTALL) Slog.d(TAG, “Replacing existing renamed package: oldName=” + oldName + " pkgName=” + pkgName); } … … } PackageSetting ps = mSettings.mPackages.get(pkgName); // 查看 Settings 中是否存有要安装的 APK 的信息,如果有就获取签名信息 if (ps != null) { if (DEBUG_INSTALL) Slog.d(TAG, “Existing package: " + ps); PackageSetting signatureCheckPs = ps; if (pkg.applicationInfo.isStaticSharedLibrary()) { SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg); if (libraryEntry != null) { signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk); } } // 检查签名的正确性 if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) { if (!checkUpgradeKeySetLP(signatureCheckPs, pkg)) { res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, “Package " + pkg.packageName + " upgrade keys do not match the " + “previously installed version”); return; } } … … } int N = pkg.permissions.size(); for (int i = N-1; i >= 0; i–) { // 遍历每个权限,对权限进行处理 PackageParser.Permission perm = pkg.permissions.get(i); BasePermission bp = mSettings.mPermissions.get(perm.info.name); … … } } if (systemApp || sPmsExt.isOperatorApp(mPackages, mSettings.mPackages, pkgName)) { if (onExternal) { // 系统APP不能在SD卡上替换安装 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; } if (!instantApp) { startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg); } else { if (DEBUG_DOMAIN_VERIFICATION) { Slog.d(TAG, “Not verifying instant app install for app links: " + pkgName); } } try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags, “installPackageLI”)) { if (replace) { // 替换安装 if (pkg.applicationInfo.isStaticSharedLibrary()) { PackageParser.Package existingPkg = mPackages.get(pkg.packageName); if (existingPkg != null && existingPkg.mVersionCode != pkg.mVersionCode) { res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, “Packages declaring " + “static-shared libs cannot be updated”); return; } } replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user, installerPackageName, res, args.installReason); } else { // 安装新的 APK installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES, args.user, installerPackageName, volumeUuid, res, args.installReason); } } // 更新应用程序所属的用户 synchronized (mPackages) { final PackageSetting ps = mSettings.mPackages.get(pkgName); if (ps != null) { res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true); ps.setUpdateAvailable(false /updateAvailable/); } … … } }installPackageLI 方法的代码很长,这里截取主要的部分,主要做了几件事: ✨ 1、创建 PackageParser 解析 APK 。 ✨ 2、检查 APK 是否存在,如果存在就获取此前没被改名前的包名,赋值给 PackageParser.Package 类型的 pkg ,将标志位 replace 置为 true 表示是替换安装。 ✨ 3、如果 Settings 中保存有要安装的 APK 的信息,说明此前安装过该 APK ,则需要校验 APK 的签名信息,确保安全的进行替换。 ✨ 4、将临时文件重新命名,比如前面提到的 /data/app/vmdl18300388.tmp/base.apk ,重命名为 /data/app/包名-1/base.apk 。这个新命名的包名会带上一个数字后缀 1,每次升级一个已有的 App ,这个数字会不断的累加。 ✨ 5、系统 APP 的更新安装会有两个限制,一个是系统 APP 不能在 SD 卡上替换安装,另一个是系统 APP 不能被 Instant App 替换。 ✨ 6、根据 replace 来做区分,如果是替换安装就会调用 replacePackageLIF 方法,其方法内部还会对系统 APP 和非系统 APP 进行区分处理,如果是新安装 APK 会调用 installNewPackageLIF 方法。installNewPackageLIF我们以安装新 APK 为例,查看 installNewPackageLIF 的源码: /* * Install a non-existing package. / private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags, int scanFlags, UserHandle user, String installerPackageName, String volumeUuid, PackageInstalledInfo res, int installReason) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, “installNewPackage”); … … try { // 扫描 APK PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, 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); }installNewPackageLIF 主要做了以下 3 件事: ✨ 1、扫描 APK,将 APK 的信息存储在 PackageParser.Package 类型的 newPackage 中,一个 Package 的信息包含了 1 个 base APK 以及 0 个或者多个 split APK 。 ✨ 2、更新该 APK 对应的 Settings 信息,Settings 用于保存所有包的动态设置。 ✨ 3、如果安装成功就为新安装的应用程序准备数据,安装失败就删除APK。scanPackageTracedLI调用 scanPackageTracedLI() 进行安装 : public PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, “scanPackage [” + scanFile.toString() + “]”); try { return scanPackageLI(scanFile, parseFlags, scanFlags, currentTime, user); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } }scanPackageLI - 01scanPackageTracedLI() 调用了 scanPackageLI() 方法: /* * Scans a package and returns the newly parsed package. * Returns {@code null} in case of errors and the error code is stored in mLastScanError */ private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { if (DEBUG_INSTALL) Slog.d(TAG, “Parsing: " + scanFile); PackageParser pp = new PackageParser(); pp.setSeparateProcesses(mSeparateProcesses); pp.setOnlyCoreApps(mOnlyCore); pp.setDisplayMetrics(mMetrics); pp.setCallback(mPackageParserCallback); … … return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user); }scanPackageLI - 02 private PackageParser.Package scanPackageLI(PackageParser.Package pkg, final int policyFlags, int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException { boolean success = false; try { // scanPackageDirtyLI 实际安装 package 的方法 final PackageParser.Package res = scanPackageDirtyLI(pkg, policyFlags, scanFlags, currentTime, user); success = true; return res; } finally { if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) { // DELETE_DATA_ON_FAILURES is only used by frozen paths destroyAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE); destroyAppProfilesLIF(pkg, UserHandle.USER_ALL); } } }总结本文主要讲解了 PMS 是如何处理 APK 安装的流程,主要有几个步骤: ✨ PackageInstaller 安装 APK 时会将 APK 的信息交由 PMS 处理,PMS 通过向 PackageHandler 发送消息来驱动 APK 的复制和安装工作。 ✨ PMS 发送 INIT_COPY 和 MCS_BOUND 类型的消息,控制 PackageHandler 来绑定 DefaultContainerService ,完成复制 APK 等工作。 ✨ 复制 APK 完成后,会开始进行安装 APK 的流程,包括安装前的检查、安装 APK 和安装后的收尾工作。参考 01. http://liuwangshu.cn/framewor... 02. https://www.jianshu.com/p/c43… ...

November 30, 2018 · 13 min · jiezi

Android 8.1 源码_核心篇 -- 深入研究 PackageManagerService 系列(2)

开篇核心源码关键类路径SystemServer.javaframeworks/base/services/java/com/android/server/SystemServer.javaPackageManagerService.javaframeworks/base/services/core/java/com/android/server/pm/PackageManagerService.javaProcess.javaframeworks/base/core/java/android/os/Process.javaSystemConfig.javaframeworks/base/core/java/com/android/server/SystemConfig.javaSettings.javaframeworks/base/services/core/java/com/android/server/pm/Settings.java简介PackageManagerService(PMS)是 SystemServer 启动后的第一个核心服务,也是 Android 系统中最常用的服务之一。它负责系统中 Package 的管理,应用程序的安装、卸载、信息查询等。如果你是面向 Android 系统开发的工程师,基础概念我也不需要再多赘述,我们直接跟源码。构造函数分析 - 扫描PackagePMS 构造函数第二阶段的工作就是扫描系统中的 APK 了。由于需要逐个扫描文件,因此手机上装的程序越多,PMS 的工作量就越大,系统启动速度也就越慢,这就是为什么你的手机启动速度有快慢的原因。系统库的 dex 优化接着上面的 PMS 构造函数继续分析源码: public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { … … // DEX 优化 mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context, “dexopt”); mDexManager = new DexManager(this, mPackageDexOptimizer, installer, mInstallLock); synchronized (mPackages) { mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, true /allowIo/); mHandlerThread.start(); mHandler = new PackageHandler(mHandlerThread.getLooper()); mProcessLoggingHandler = new ProcessLoggingHandler(); Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT); mDefaultPermissionPolicy = new DefaultPermissionGrantPolicy(this); mInstantAppRegistry = new InstantAppRegistry(this); // 为 data/ 目录下的某些子目录生成File实例 File dataDir = Environment.getDataDirectory(); // data/app 存放第三方应用 mAppInstallDir = new File(dataDir, “app”); mAppLib32InstallDir = new File(dataDir, “app-lib”); mAsecInternalPath = new File(dataDir, “app-asec”).getPath(); // data/app-private 存放 drm 保护的应用 mDrmAppPrivateInstallDir = new File(dataDir, “app-private”); sUserManager = new UserManagerService(context, this, new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages); // 获取 SystemConfig 中解析到的 <permission> 标签标识的 permission 信息,保存到 Settings::mPermissions ArrayMap<String, SystemConfig.PermissionEntry> permConfig = systemConfig.getPermissions(); for (int i=0; i<permConfig.size(); i++) { SystemConfig.PermissionEntry perm = permConfig.valueAt(i); BasePermission bp = mSettings.mPermissions.get(perm.name); if (bp == null) { bp = new BasePermission(perm.name, “android”, BasePermission.TYPE_BUILTIN); mSettings.mPermissions.put(perm.name, bp); } if (perm.gids != null) { bp.setGids(perm.gids, perm.perUser); } } // 得到除 framework 之外的系统中的共享库列表,从 SystemConfig 获取解析到的数据 ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries(); final int builtInLibCount = libConfig.size(); for (int i = 0; i < builtInLibCount; i++) { String name = libConfig.keyAt(i); String path = libConfig.valueAt(i); addSharedLibraryLPw(path, null, name, SharedLibraryInfo.VERSION_UNDEFINED, SharedLibraryInfo.TYPE_BUILTIN, PLATFORM_PACKAGE_NAME, 0); } mFoundPolicyFile = SELinuxMMAC.readInstallPolicy(); // 读取packages.xml的内容,并对mSettings::mPackages等成员进行赋值;packages.xml文件中的内容是上一次扫描apk目录的结果; // 当前这一次扫描的结果是保存在PackageManagerService::mPackages列表中; // 对比上次扫描的结果来检查本次扫描到的应用中是否有被升级包覆盖的系统应用,如果有则从PackageManagerService::mPackages中移除; // 这样,PackageManagerService::mPackages的记录就和mSettings::mPackages的一致了; // 系统最终会将本次apk扫描的结果重新写入packages.xml中 mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false)); // Clean up orphaned packages for which the code path doesn’t exist // and they are an update to a system app - caused by bug/32321269 final int packageSettingCount = mSettings.mPackages.size(); // 清理那些代码路径不存在的异常 package for (int i = packageSettingCount - 1; i >= 0; i–) { PackageSetting ps = mSettings.mPackages.valueAt(i); if (!isExternal(ps) && (ps.codePath == null || !ps.codePath.exists()) && mSettings.getDisabledSystemPkgLPr(ps.name) != null) { mSettings.mPackages.removeAt(i); mSettings.enableSystemPackageLPw(ps.name); } } if (mFirstBoot) { requestCopyPreoptedFiles(); } // 设置模块来代替 framework-res.apk 中缺省的 ResolverActivity String customResolverActivity = Resources.getSystem().getString( R.string.config_customResolverActivity); if (TextUtils.isEmpty(customResolverActivity)) { customResolverActivity = null; } else { mCustomResolverComponentName = ComponentName.unflattenFromString( customResolverActivity); } long startTime = SystemClock.uptimeMillis(); // 记录扫描开始的时间 // 需要系统提前加载的一些 jar final String bootClassPath = System.getenv(“BOOTCLASSPATH”); final String systemServerClassPath = System.getenv(“SYSTEMSERVERCLASSPATH”); if (bootClassPath == null) { Slog.w(TAG, “No BOOTCLASSPATH found!”); } if (systemServerClassPath == null) { Slog.w(TAG, “No SYSTEMSERVERCLASSPATH found!”); }扫描系统 Package清空 cache 文件后,PMS 终于进入重点段了。接下来看 PMS 第二阶段工作的核心内容,即扫描 Package,相关代码如下:// PackageManagerService.java // 定义 frameworkDir 指向 /system/frameworks 目录 File frameworkDir = new File(Environment.getRootDirectory(), “framework”); final VersionInfo ver = mSettings.getInternalVersion(); mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint); // when upgrading from pre-M, promote system app permissions from install to runtime mPromoteSystemApps = mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1; // When upgrading from pre-N, we need to handle package extraction like first boot, // as there is no profiling data available. mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N; mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1; // save off the names of pre-existing system packages prior to scanning; we don’t // want to automatically grant runtime permissions for new system apps // 是否需要提升权限 if (mPromoteSystemApps) { Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator(); while (pkgSettingIter.hasNext()) { PackageSetting ps = pkgSettingIter.next(); if (isSystemApp(ps)) { // 遍历Settings::mPackages集合,将系统APP加入到PackageManagerService::mExistingSystemPackages mExistingSystemPackages.add(ps.name); } } } mCacheDir = preparePackageParserCache(mIsUpgrade); // 定义扫描参数 int scanFlags = SCAN_BOOTING | SCAN_INITIAL; if (mIsUpgrade || mFirstBoot) { scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE; } // 先扫描 /vendor/overlay 目录 scanDirTracedLI(new File(VENDOR_OVERLAY_DIR), mDefParseFlags | PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0); // 调用 scanDirTracedLI 函数扫描 /system/frameworks 目录 scanDirTracedLI(frameworkDir, mDefParseFlags | PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_IS_PRIVILEGED, scanFlags | SCAN_NO_DEX, 0); // Collected privileged system packages. final File privilegedAppDir = new File(Environment.getRootDirectory(), “priv-app”); // 扫描 /system/priv-app 下的 package scanDirTracedLI(privilegedAppDir, mDefParseFlags | PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0); // Collect ordinary system packages. final File systemAppDir = new File(Environment.getRootDirectory(), “app”); // 扫描 /system/app 下的 package scanDirTracedLI(systemAppDir, mDefParseFlags | PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0); // Collect all vendor packages. File vendorAppDir = new File("/vendor/app"); try { vendorAppDir = vendorAppDir.getCanonicalFile(); } catch (IOException e) { // failed to look up canonical path, continue with original one } // 扫描 /vendor/app 下的 package scanDirTracedLI(vendorAppDir, mDefParseFlags | PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0); // Collect all OEM packages. final File oemAppDir = new File(Environment.getOemDirectory(), “app”); // 扫描 OEM 的 Package scanDirTracedLI(oemAppDir, mDefParseFlags | PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);由以上代码可知,PMS 将扫描以下几个目录(仅列出重点): ✨ /system/frameworks :该目录中的文件都是系统库,例如:framework.jar、services.jar、framework-res.apk。不过 scanDirTracedLI 只扫描 APK 文件,所以 framework-res.apk 是该目录中唯一“受宠”的文件。 ✨ /system/app :该目录下全是默认的系统应用。例如:Browser.apk、SettingsProvider.apk 等。 ✨ /vendor/app :该目录中的文件由厂商提供,即全是厂商特定的 APK 文件,目前市面上的厂商都把自己的应用放在 /system/app 目录下。scanDirTracedLIPMS 调用 scanDirTracedLI 函数进行扫描,下面分析此函数: public void scanDirTracedLI(File dir, final int parseFlags, int scanFlags, long currentTime) { try { scanDirLI(dir, parseFlags, scanFlags, currentTime); // 调用 scanDirLI 函数 } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } }我们可以看出,实际是调用了 scanDirLI 函数进行扫描工作!scanDirLI下面的重点就是来关注 scanDirLI 函数了: private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) { // 列举该目录下的文件 final File[] files = dir.listFiles(); if (ArrayUtils.isEmpty(files)) { Log.d(TAG, “No files in app dir " + dir); return; } ParallelPackageParser parallelPackageParser = new ParallelPackageParser( mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir, mParallelPackageParserCallback); int fileCount = 0; for (File file : files) { final boolean isPackage = (isApkFile(file) || file.isDirectory()) && !PackageInstallerService.isStageName(file.getName()); if (!isPackage) { // Ignore entries which are not packages continue; } parallelPackageParser.submit(file, parseFlags); fileCount++; } // Process results one by one for (; fileCount > 0; fileCount–) { ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take(); Throwable throwable = parseResult.throwable; int errorCode = PackageManager.INSTALL_SUCCEEDED; if (throwable == null) { // Static shared libraries have synthetic package names if (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) { renameStaticSharedLibraryPackage(parseResult.pkg); } try { if (errorCode == PackageManager.INSTALL_SUCCEEDED) { // 调用 scanPackageLI 函数扫描一个特定的文件,返回值是 PackageParser 的内部类 Package,该类的实例代表一个 APK 文件,所以它就是和 APK 文件对应的数据结构 scanPackageLI(parseResult.pkg, parseResult.scanFile, parseFlags, scanFlags, currentTime, null); } … … } // Delete invalid userdata apps if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 && errorCode == PackageManager.INSTALL_FAILED_INVALID_APK) { // 非系统 Package 扫描失败,删除文件 removeCodePathLI(parseResult.scanFile); } } parallelPackageParser.close(); }scanPackageLI - 01PMS 中有三处 scanPackageLI,我们后面会一一分析到,先来看第一个也是最先碰到的 sanPackageLI 函数。 private PackageParser.Package scanPackageLI(PackageParser.Package pkg, File scanFile, final int policyFlags, int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException { if ((scanFlags & SCAN_CHECK_ONLY) == 0) { if (pkg.childPackages != null && pkg.childPackages.size() > 0) { scanFlags |= SCAN_CHECK_ONLY; } } else { scanFlags &= ~SCAN_CHECK_ONLY; } // Scan the parent PackageParser.Package scannedPkg = scanPackageInternalLI(pkg, scanFile, policyFlags, scanFlags, currentTime, user); // Scan the children final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; for (int i = 0; i < childCount; i++) { PackageParser.Package childPackage = pkg.childPackages.get(i); scanPackageInternalLI(childPackage, scanFile, policyFlags, scanFlags, currentTime, user); } if ((scanFlags & SCAN_CHECK_ONLY) != 0) { return scanPackageLI(pkg, scanFile, policyFlags, scanFlags, currentTime, user); } return scannedPkg; }scanPackageInternalLI调用 scanPackageInternalLI(): private PackageParser.Package scanPackageInternalLI(PackageParser.Package pkg, File scanFile, int policyFlags, int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException { PackageSetting ps = null; PackageSetting updatedPkg; // 判断系统 APP 是否需要更新 synchronized (mPackages) { // 查看是否已经有该安装包,通过 mSetting 查找 String oldName = mSettings.getRenamedPackageLPr(pkg.packageName); if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) { // 如果存在同一个包名的老的安装包,且已经改回原始名称了 ps = mSettings.getPackageLPr(oldName); } // 如果没有原始包,则使用真实包名 if (ps == null) { ps = mSettings.getPackageLPr(pkg.packageName); } // 查这个包是否是一个隐藏或者可以更新的系统包 updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName); // If this is a package we don’t know about on the system partition, we // may need to remove disabled child packages on the system partition // or may need to not add child packages if the parent apk is updated // on the data partition and no longer defines this child package. if ((policyFlags & PackageParser.PARSE_IS_SYSTEM) != 0) { // If this is a parent package for an updated system app and this system // app got an OTA update which no longer defines some of the child packages // we have to prune them from the disabled system packages. PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName); if (disabledPs != null) { final int scannedChildCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; final int disabledChildCount = disabledPs.childPackageNames != null ? disabledPs.childPackageNames.size() : 0; for (int i = 0; i < disabledChildCount; i++) { String disabledChildPackageName = disabledPs.childPackageNames.get(i); boolean disabledPackageAvailable = false; for (int j = 0; j < scannedChildCount; j++) { PackageParser.Package childPkg = pkg.childPackages.get(j); if (childPkg.packageName.equals(disabledChildPackageName)) { disabledPackageAvailable = true; break; } } if (!disabledPackageAvailable) { mSettings.removeDisabledSystemPackageLPw(disabledChildPackageName); } } } } } … … // Note that we invoke the following method only if we are about to unpack an application // 调用第二个 scanPackageLI 函数 PackageParser.Package scannedPkg = scanPackageLI(pkg, policyFlags, scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user); … … }scanPackageLI - 02 private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { // 创建一个 PackageParser 对象,用于解析包 PackageParser pp = new PackageParser(); // 设置 PackageParse 的三个属性 pp.setSeparateProcesses(mSeparateProcesses); pp.setOnlyCoreApps(mOnlyCore); pp.setDisplayMetrics(mMetrics); pp.setCallback(mPackageParserCallback); // 判断扫描模式 if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) { parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY; } // 解析APK获取对应PackageParser.Package对象 pkg final PackageParser.Package pkg; // 调用 PackageParser 的 parsePackage 函数解析 APK 文件 try { // ???? ???? ???? ???? ???? ???? 真正的解析 pkg = pp.parsePackage(scanFile, parseFlags); } catch (PackageParserException e) { throw PackageManagerException.from(e); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } // Static shared libraries have synthetic package names if (pkg.applicationInfo.isStaticSharedLibrary()) { renameStaticSharedLibraryPackage(pkg); } return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user); }PackageParserPackageParser 主要负责 APK 文件的解析,即解析 APK 文件中的 AndroidManifest.xml。这边我们要重点分析 PackageParser 类!!!官方解释Android 安装一个 APK 的时候首先会解析 APK,而解析 APK 则需要用到一个工具类,这个工具类就是 PackageParser。/** * Parser for package files (APKs) on disk. This supports apps packaged either * as a single “monolithic” APK, or apps packaged as a “cluster” of multiple * APKs in a single directory. * <p> * Apps packaged as multiple APKs always consist of a single “base” APK (with a * {@code null} split name) and zero or more “split” APKs (with unique split * names). Any subset of those split APKs are a valid install, as long as the * following constraints are met: * <ul> * <li>All APKs must have the exact same package name, version code, and signing * certificates. * <li>All APKs must have unique split names. * <li>All installations must contain a single base APK. * </ul> * * @hide /public class PackageParser {解释如下:解析磁盘上的APK安装包文件。它既能解析一个"单一"APK文件,也能解析一个"集群"APK文件(即一个APK文件里面包含多个APK文件)。一个"集群"APK有一个"基准"APK(base APK)组成和其他一些"分割"APK(“split” APKs)构成,其中这些"分割"APK用一些数字来分割。这些"分割"APK的必须都是有效的安装,同时必须满足下面的几个条件: ✨ 所有的APK必须具有完全相同的软件包名称,版本代码和签名证书 ✨ 所有的APK必须具有唯一的拆分名称 ✨ 所有安装必须包含一个单一的APK。解析步骤所以我们知道PackageParse类,它主要用来解析手机上的APK文件(支持Single APK和MultipleAPK),解析一个APK主要是分为两个步骤: ✨ 1、将APK解析成Package:即解析APK文件为Package对象的过程。 ✨ 2、将Package转化为PackageInfo:即由Package对象生成PackageInfo的过程。我们接下来看看 parsePackage 方法。parsePackage /* * Parse the package at the given location. Automatically detects if the * package is a monolithic style (single APK file) or cluster style * (directory of APKs). * <p> * This performs sanity checking on cluster style packages, such as * requiring identical package name and version codes, a single base APK, * and unique split names. * <p> * Note that this <em>does not</em> perform signature verification; that * must be done separately in {@link #collectCertificates(Package, int)}. * * If {@code useCaches} is true, the package parser might return a cached * result from a previous parse of the same {@code packageFile} with the same * {@code flags}. Note that this method does not check whether {@code packageFile} * has changed since the last parse, it’s up to callers to do so. * * @see #parsePackageLite(File, int) / public Package parsePackage(File packageFile, int flags) throws PackageParserException { return parsePackage(packageFile, flags, false / useCaches /); } public Package parsePackage(File packageFile, int flags, boolean useCaches) throws PackageParserException { Package parsed = useCaches ? getCachedResult(packageFile, flags) : null; if (parsed != null) { return parsed; } long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0; if (packageFile.isDirectory()) { // 集群APK parsed = parseClusterPackage(packageFile, flags); // 获得一个 XML 资源解析对象 } else { // 单一APK parsed = parseMonolithicPackage(packageFile, flags); // 获得一个 XML 资源解析对象 } long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0; cacheResult(packageFile, flags, parsed); if (LOG_PARSE_TIMINGS) { parseTime = cacheTime - parseTime; cacheTime = SystemClock.uptimeMillis() - cacheTime; if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) { Slog.i(TAG, “Parse times for ‘” + packageFile + “’: parse=” + parseTime + “ms, update_cache=” + cacheTime + " ms”); } } return parsed; }parseMonolithicPackage这边我们以单一APK为例去跟踪源码流程: /* * Parse the given APK file, treating it as as a single monolithic package. * <p> * Note that this <em>does not</em> perform signature verification; that * must be done separately in {@link #collectCertificates(Package, int)}. * * @deprecated external callers should move to * {@link #parsePackage(File, int)}. Eventually this method will * be marked private. */ @Deprecated public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException { final AssetManager assets = newConfiguredAssetManager(); // ???? ???? ???? ???? ???? ???? 重点分析 final PackageLite lite = parseMonolithicPackageLite(apkFile, flags); if (mOnlyCoreApps) { if (!lite.coreApp) { throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, “Not a coreApp: " + apkFile); } } try { // ???? ???? ???? ???? ???? ???? 重点分析 // 调用parseBaseApk()方法解析一个apk并生成一个Package对象 final Package pkg = parseBaseApk(apkFile, assets, flags); pkg.setCodePath(apkFile.getAbsolutePath()); pkg.setUse32bitAbi(lite.use32bitAbi); return pkg; } finally { IoUtils.closeQuietly(assets); } }【说明】:未分析完,由于篇幅字数限制,剩下代码的分析见【Android 8.1 源码_核心篇 – 深入研究 PackageManagerService 系列(3)】 ...

October 26, 2018 · 10 min · jiezi

Android 8.1 源码_核心篇 -- 深入研究 PackageManagerService 系列(3)

开篇核心源码关键类路径SystemServer.javaframeworks/base/services/java/com/android/server/SystemServer.javaPackageManagerService.javaframeworks/base/services/core/java/com/android/server/pm/PackageManagerService.javaProcess.javaframeworks/base/core/java/android/os/Process.javaSystemConfig.javaframeworks/base/core/java/com/android/server/SystemConfig.javaSettings.javaframeworks/base/services/core/java/com/android/server/pm/Settings.java简介PackageManagerService(PMS)是 SystemServer 启动后的第一个核心服务,也是 Android 系统中最常用的服务之一。它负责系统中 Package 的管理,应用程序的安装、卸载、信息查询等。如果你是面向 Android 系统开发的工程师,基础概念我也不需要再多赘述,我们直接跟源码。PackageParserparseMonolithicPackageLite private static PackageLite parseMonolithicPackageLite(File packageFile, int flags) throws PackageParserException { final ApkLite baseApk = parseApkLite(packageFile, flags); final String packagePath = packageFile.getAbsolutePath(); return new PackageLite(packagePath, baseApk, null, null, null, null, null, null); }这个方法就是调用parseApkLite()方法来获取一个ApkLite对象,然后用这个ApkLite对象构造一个PackageLite对象。parseApkLite-01 /** * Utility method that retrieves lightweight details about a single APK * file, including package name, split name, and install location. * * @param apkFile path to a single APK * @param flags optional parse flags, such as * {@link #PARSE_COLLECT_CERTIFICATES} / public static ApkLite parseApkLite(File apkFile, int flags) throws PackageParserException { final String apkPath = apkFile.getAbsolutePath(); // 创建 AssetManager 对象 AssetManager assets = null; XmlResourceParser parser = null; try { assets = newConfiguredAssetManager(); int cookie = assets.addAssetPath(apkPath); if (cookie == 0) { throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, “Failed to parse " + apkPath); } final DisplayMetrics metrics = new DisplayMetrics(); metrics.setToDefaults(); parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); final Signature[] signatures; final Certificate[][] certificates; // 设置签名 if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) { // TODO: factor signature related items out of Package object final Package tempPkg = new Package((String) null); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, “collectCertificates”); try { collectCertificates(tempPkg, apkFile, flags); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } signatures = tempPkg.mSignatures; certificates = tempPkg.mCertificates; } else { signatures = null; certificates = null; } final AttributeSet attrs = parser; return parseApkLite(apkPath, parser, attrs, signatures, certificates); } catch (XmlPullParserException | IOException | RuntimeException e) { Slog.w(TAG, “Failed to parse " + apkPath, e); throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, “Failed to parse " + apkPath, e); } finally { // 关闭资源管理器与解析器 IoUtils.closeQuietly(parser); IoUtils.closeQuietly(assets); } }parseApkLite-02 private static ApkLite parseApkLite(String codePath, XmlPullParser parser, AttributeSet attrs, Signature[] signatures, Certificate[][] certificates) throws IOException, XmlPullParserException, PackageParserException { // 调用了parsePackageSplitNames()方法来获取packageSplit final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs); int installLocation = PARSE_DEFAULT_INSTALL_LOCATION; int versionCode = 0; int revisionCode = 0; boolean coreApp = false; boolean debuggable = false; boolean multiArch = false; boolean use32bitAbi = false; boolean extractNativeLibs = true; boolean isolatedSplits = false; boolean isFeatureSplit = false; String configForSplit = null; String usesSplitName = null; // 遍历属性,并获取相应的值 for (int i = 0; i < attrs.getAttributeCount(); i++) { final String attr = attrs.getAttributeName(i); if (attr.equals(“installLocation”)) { installLocation = attrs.getAttributeIntValue(i, PARSE_DEFAULT_INSTALL_LOCATION); } else if (attr.equals(“versionCode”)) { versionCode = attrs.getAttributeIntValue(i, 0); } else if (attr.equals(“revisionCode”)) { revisionCode = attrs.getAttributeIntValue(i, 0); } else if (attr.equals(“coreApp”)) { coreApp = attrs.getAttributeBooleanValue(i, false); } else if (attr.equals(“isolatedSplits”)) { isolatedSplits = attrs.getAttributeBooleanValue(i, false); } else if (attr.equals(“configForSplit”)) { configForSplit = attrs.getAttributeValue(i); } else if (attr.equals(“isFeatureSplit”)) { isFeatureSplit = attrs.getAttributeBooleanValue(i, false); } } // Only search the tree when the tag is directly below <manifest> int type; final int searchDepth = parser.getDepth() + 1; final List<VerifierInfo> verifiers = new ArrayList<VerifierInfo>(); // private static final String TAG_PACKAGE_VERIFIER = “package-verifier” // 继续解析package-verifier节点 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } if (parser.getDepth() != searchDepth) { continue; } if (TAG_PACKAGE_VERIFIER.equals(parser.getName())) { final VerifierInfo verifier = parseVerifier(attrs); if (verifier != null) { verifiers.add(verifier); } } else if (TAG_APPLICATION.equals(parser.getName())) { for (int i = 0; i < attrs.getAttributeCount(); ++i) { final String attr = attrs.getAttributeName(i); if (“debuggable”.equals(attr)) { debuggable = attrs.getAttributeBooleanValue(i, false); } if (“multiArch”.equals(attr)) { multiArch = attrs.getAttributeBooleanValue(i, false); } if (“use32bitAbi”.equals(attr)) { use32bitAbi = attrs.getAttributeBooleanValue(i, false); } if (“extractNativeLibs”.equals(attr)) { extractNativeLibs = attrs.getAttributeBooleanValue(i, true); } } } else if (TAG_USES_SPLIT.equals(parser.getName())) { if (usesSplitName != null) { Slog.w(TAG, “Only one <uses-split> permitted. Ignoring others.”); continue; } usesSplitName = attrs.getAttributeValue(ANDROID_RESOURCES, “name”); if (usesSplitName == null) { throw new PackageParserException( PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, “<uses-split> tag requires ‘android:name’ attribute”); } } } //利用解析出来的数据去构造一个ApkLite对象 return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit, configForSplit, usesSplitName, versionCode, revisionCode, installLocation, verifiers, signatures, certificates, coreApp, debuggable, multiArch, use32bitAbi, extractNativeLibs, isolatedSplits); }parsePackageSplitNames// 这个方法主要是解析manifest private static Pair<String, String> parsePackageSplitNames(XmlPullParser parser, AttributeSet attrs) throws IOException, XmlPullParserException, PackageParserException { int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { } if (type != XmlPullParser.START_TAG) { throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, “No start tag found”); } if (!parser.getName().equals(TAG_MANIFEST)) { throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, “No <manifest> tag”); } final String packageName = attrs.getAttributeValue(null, “package”); if (!“android”.equals(packageName)) { // 这个方法主要就是检测是否是数字、字母、下划线和点分隔符,这也是取包名的规则, // 比如是字母数字下划线加点分隔符,否则都不是合法的应用包名。并且合法的包名至少包含一个点分隔符。 final String error = validateName(packageName, true, true); if (error != null) { throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, “Invalid manifest package: " + error); } } String splitName = attrs.getAttributeValue(null, “split”); if (splitName != null) { if (splitName.length() == 0) { splitName = null; } else { final String error = validateName(splitName, false, false); if (error != null) { throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, “Invalid manifest split: " + error); } } } return Pair.create(packageName.intern(), (splitName != null) ? splitName.intern() : splitName); }parseBaseApk private Package parseBaseApk(File apkFile, AssetManager assets, int flags) throws PackageParserException { final String apkPath = apkFile.getAbsolutePath(); String volumeUuid = null; if (apkPath.startsWith(MNT_EXPAND)) { final int end = apkPath.indexOf(’/’, MNT_EXPAND.length()); volumeUuid = apkPath.substring(MNT_EXPAND.length(), end); } mParseError = PackageManager.INSTALL_SUCCEEDED; mArchiveSourcePath = apkFile.getAbsolutePath(); if (DEBUG_JAR) Slog.d(TAG, “Scanning base APK: " + apkPath); final int cookie = loadApkIntoAssetManager(assets, apkPath, flags); Resources res = null; XmlResourceParser parser = null; try { res = new Resources(assets, mMetrics, null); parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); final String[] outError = new String[1]; final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError); if (pkg == null) { throw new PackageParserException(mParseError, apkPath + " (at " + parser.getPositionDescription() + “): " + outError[0]); } pkg.setVolumeUuid(volumeUuid); pkg.setApplicationVolumeUuid(volumeUuid); pkg.setBaseCodePath(apkPath); pkg.setSignatures(null); return pkg; } catch (PackageParserException e) { throw e; } catch (Exception e) { throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, “Failed to read manifest from " + apkPath, e); } finally { IoUtils.closeQuietly(parser); } }parseBaseApk private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException, IOException { final String splitName; final String pkgName; try { Pair<String, String> packageSplit = parsePackageSplitNames(parser, parser); pkgName = packageSplit.first; splitName = packageSplit.second; if (!TextUtils.isEmpty(splitName)) { outError[0] = “Expected base APK, but found split " + splitName; mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; return null; } } catch (PackageParserException e) { mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; return null; } if (mCallback != null) { String[] overlayPaths = mCallback.getOverlayPaths(pkgName, apkPath); if (overlayPaths != null && overlayPaths.length > 0) { for (String overlayPath : overlayPaths) { res.getAssets().addOverlayPath(overlayPath); } } } // 用包名构造一个Package final Package pkg = new Package(pkgName); // 获取资源数组 TypedArray sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifest); // 初始化pkg的属性mVersionCode、baseRevisionCode和mVersionName pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger( com.android.internal.R.styleable.AndroidManifest_versionCode, 0); pkg.baseRevisionCode = sa.getInteger( com.android.internal.R.styleable.AndroidManifest_revisionCode, 0); pkg.mVersionName = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifest_versionName, 0); if (pkg.mVersionName != null) { pkg.mVersionName = pkg.mVersionName.intern(); } // 判断是不是核心app pkg.coreApp = parser.getAttributeBooleanValue(null, “coreApp”, false); sa.recycle(); // 解析AndroidManifest下面的每一个节点 return parseBaseApkCommon(pkg, null, res, parser, flags, outError); }parseBaseApkCommon private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res, XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException, IOException { … … / Set the global “forward lock” flag / if ((flags & PARSE_FORWARD_LOCK) != 0) { pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK; } / Set the global “on SD card” flag / // 是否要安装在SD卡上 if ((flags & PARSE_EXTERNAL_STORAGE) != 0) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE; } // Resource boolean are -1, so 1 means we don’t know the value. int supportsSmallScreens = 1; int supportsNormalScreens = 1; int supportsLargeScreens = 1; int supportsXLargeScreens = 1; int resizeable = 1; int anyDensity = 1; int outerDepth = parser.getDepth(); while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } … … // 解析<application> 标签 if (tagName.equals(TAG_APPLICATION)) { if (foundApp) { if (RIGID_PARSER) { outError[0] = “<manifest> has more than one <application>”; mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; } else { Slog.w(TAG, “<manifest> has more than one <application>”); XmlUtils.skipCurrentTag(parser); continue; } } foundApp = true; if (!parseBaseApplication(pkg, res, parser, flags, outError)) { return null; } // 解析<overlay> 标签 } else if (tagName.equals(TAG_OVERLAY)) { sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestResourceOverlay); pkg.mOverlayTarget = sa.getString( com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage); pkg.mOverlayPriority = sa.getInt( com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority, 0); pkg.mIsStaticOverlay = sa.getBoolean( com.android.internal.R.styleable.AndroidManifestResourceOverlay_isStatic, false); final String propName = sa.getString( com.android.internal.R.styleable .AndroidManifestResourceOverlay_requiredSystemPropertyName); final String propValue = sa.getString( com.android.internal.R.styleable .AndroidManifestResourceOverlay_requiredSystemPropertyValue); sa.recycle(); if (pkg.mOverlayTarget == null) { outError[0] = “<overlay> does not specify a target package”; mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; } if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) { outError[0] = “<overlay> priority must be between 0 and 9999”; mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; } // check to see if overlay should be excluded based on system property condition if (!checkOverlayRequiredSystemProperty(propName, propValue)) { Slog.i(TAG, “Skipping target and overlay pair " + pkg.mOverlayTarget + " and " + pkg.baseCodePath+ “: overlay ignored due to required system property: " + propName + " with value: " + propValue); return null; } XmlUtils.skipCurrentTag(parser); // 解析<key-sets> 标签 } else if (tagName.equals(TAG_KEY_SETS)) { if (!parseKeySets(pkg, res, parser, outError)) { return null; } // 解析<permission-group> 标签 } else if (tagName.equals(TAG_PERMISSION_GROUP)) { if (!parsePermissionGroup(pkg, flags, res, parser, outError)) { return null; } // 解析<permission> 标签 } else if (tagName.equals(TAG_PERMISSION)) { if (!parsePermission(pkg, res, parser, outError)) { return null; } // 解析<permission-tree> 标签 } else if (tagName.equals(TAG_PERMISSION_TREE)) { if (!parsePermissionTree(pkg, res, parser, outError)) { return null; } // 解析<uses-permission> 标签 } else if (tagName.equals(TAG_USES_PERMISSION)) { if (!parseUsesPermission(pkg, res, parser)) { return null; } // 解析<uses-permission-sdk-m> 标签或者 <uses-permission-sdk-23> 标签 } else if (tagName.equals(TAG_USES_PERMISSION_SDK_M) || tagName.equals(TAG_USES_PERMISSION_SDK_23)) { if (!parseUsesPermission(pkg, res, parser)) { return null; } // 解析<uses-configuration>标签 } else if (tagName.equals(TAG_USES_CONFIGURATION)) { ConfigurationInfo cPref = new ConfigurationInfo(); sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestUsesConfiguration); cPref.reqTouchScreen = sa.getInt( com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen, Configuration.TOUCHSCREEN_UNDEFINED); cPref.reqKeyboardType = sa.getInt( com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType, Configuration.KEYBOARD_UNDEFINED); if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard, false)) { cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD; } cPref.reqNavigation = sa.getInt( com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation, Configuration.NAVIGATION_UNDEFINED); if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav, false)) { cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV; } sa.recycle(); pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref); XmlUtils.skipCurrentTag(parser); // 解析<uses-feature>标签 } else if (tagName.equals(TAG_USES_FEATURE)) { FeatureInfo fi = parseUsesFeature(res, parser); pkg.reqFeatures = ArrayUtils.add(pkg.reqFeatures, fi); if (fi.name == null) { ConfigurationInfo cPref = new ConfigurationInfo(); cPref.reqGlEsVersion = fi.reqGlEsVersion; pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref); } XmlUtils.skipCurrentTag(parser); // 解析<feature-group>标签 } else if (tagName.equals(TAG_FEATURE_GROUP)) { FeatureGroupInfo group = new FeatureGroupInfo(); ArrayList<FeatureInfo> features = null; final int innerDepth = parser.getDepth(); while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } final String innerTagName = parser.getName(); if (innerTagName.equals(“uses-feature”)) { FeatureInfo featureInfo = parseUsesFeature(res, parser); // FeatureGroups are stricter and mandate that // any <uses-feature> declared are mandatory. featureInfo.flags |= FeatureInfo.FLAG_REQUIRED; features = ArrayUtils.add(features, featureInfo); } else { Slog.w(TAG, “Unknown element under <feature-group>: " + innerTagName + " at " + mArchiveSourcePath + " " + parser.getPositionDescription()); } XmlUtils.skipCurrentTag(parser); } if (features != null) { group.features = new FeatureInfo[features.size()]; group.features = features.toArray(group.features); } pkg.featureGroups = ArrayUtils.add(pkg.featureGroups, group); // 解析<uses-sdk>标签 } else if (tagName.equals(TAG_USES_SDK)) { if (SDK_VERSION > 0) { sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestUsesSdk); int minVers = 1; String minCode = null; int targetVers = 0; String targetCode = null; TypedValue val = sa.peekValue( com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion); if (val != null) { if (val.type == TypedValue.TYPE_STRING && val.string != null) { targetCode = minCode = val.string.toString(); } else { // If it’s not a string, it’s an integer. targetVers = minVers = val.data; } } val = sa.peekValue( com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion); if (val != null) { if (val.type == TypedValue.TYPE_STRING && val.string != null) { targetCode = val.string.toString(); if (minCode == null) { minCode = targetCode; } } else { // If it’s not a string, it’s an integer. targetVers = val.data; } } sa.recycle(); final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers, minCode, SDK_VERSION, SDK_CODENAMES, outError); if (minSdkVersion < 0) { mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; return null; } final int targetSdkVersion = PackageParser.computeTargetSdkVersion(targetVers, targetCode, SDK_VERSION, SDK_CODENAMES, outError); if (targetSdkVersion < 0) { mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; return null; } pkg.applicationInfo.minSdkVersion = minSdkVersion; pkg.applicationInfo.targetSdkVersion = targetSdkVersion; } XmlUtils.skipCurrentTag(parser); // 解析<supports-screens>标签 } else if (tagName.equals(TAG_SUPPORT_SCREENS)) { sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestSupportsScreens); pkg.applicationInfo.requiresSmallestWidthDp = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp, 0); pkg.applicationInfo.compatibleWidthLimitDp = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp, 0); pkg.applicationInfo.largestWidthLimitDp = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp, 0); // This is a trick to get a boolean and still able to detect // if a value was actually set. supportsSmallScreens = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_smallScreens, supportsSmallScreens); supportsNormalScreens = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_normalScreens, supportsNormalScreens); supportsLargeScreens = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens, supportsLargeScreens); supportsXLargeScreens = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_xlargeScreens, supportsXLargeScreens); resizeable = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_resizeable, resizeable); anyDensity = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_anyDensity, anyDensity); sa.recycle(); XmlUtils.skipCurrentTag(parser); // 解析<protected-broadcast>标签 } else if (tagName.equals(TAG_PROTECTED_BROADCAST)) { sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestProtectedBroadcast); // Note: don’t allow this value to be a reference to a resource // that may change. String name = sa.getNonResourceString( com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name); sa.recycle(); if (name != null && (flags&PARSE_IS_SYSTEM) != 0) { if (pkg.protectedBroadcasts == null) { pkg.protectedBroadcasts = new ArrayList<String>(); } if (!pkg.protectedBroadcasts.contains(name)) { pkg.protectedBroadcasts.add(name.intern()); } } XmlUtils.skipCurrentTag(parser); // 解析<instrumentation>标签 } else if (tagName.equals(TAG_INSTRUMENTATION)) { if (parseInstrumentation(pkg, res, parser, outError) == null) { return null; } // 解析<original-package>标签 } else if (tagName.equals(TAG_ORIGINAL_PACKAGE)) { sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestOriginalPackage); String orig =sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0); if (!pkg.packageName.equals(orig)) { if (pkg.mOriginalPackages == null) { pkg.mOriginalPackages = new ArrayList<String>(); pkg.mRealPackage = pkg.packageName; } pkg.mOriginalPackages.add(orig); } sa.recycle(); XmlUtils.skipCurrentTag(parser); // 解析<adopt-permissions>标签 } else if (tagName.equals(TAG_ADOPT_PERMISSIONS)) { sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestOriginalPackage); String name = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0); sa.recycle(); if (name != null) { if (pkg.mAdoptPermissions == null) { pkg.mAdoptPermissions = new ArrayList<String>(); } pkg.mAdoptPermissions.add(name); } XmlUtils.skipCurrentTag(parser); // 解析<uses-gl-texture>标签 } else if (tagName.equals(TAG_USES_GL_TEXTURE)) { // Just skip this tag XmlUtils.skipCurrentTag(parser); continue; // 解析<compatible-screens>标签 } else if (tagName.equals(TAG_COMPATIBLE_SCREENS)) { // Just skip this tag XmlUtils.skipCurrentTag(parser); continue; // 解析<supports-input>标签 } else if (tagName.equals(TAG_SUPPORTS_INPUT)) {// XmlUtils.skipCurrentTag(parser); continue; // 解析<eat-comment>标签 } else if (tagName.equals(TAG_EAT_COMMENT)) { // Just skip this tag XmlUtils.skipCurrentTag(parser); continue; } else if (tagName.equals(TAG_PACKAGE)) { if (!MULTI_PACKAGE_APK_ENABLED) { XmlUtils.skipCurrentTag(parser); continue; } if (!parseBaseApkChild(pkg, res, parser, flags, outError)) { // If parsing a child failed the error is already set return null; } } else if (tagName.equals(TAG_RESTRICT_UPDATE)) { if ((flags & PARSE_IS_SYSTEM_DIR) != 0) { sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestRestrictUpdate); final String hash = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestRestrictUpdate_hash, 0); sa.recycle(); pkg.restrictUpdateHash = null; if (hash != null) { final int hashLength = hash.length(); final byte[] hashBytes = new byte[hashLength / 2]; for (int i = 0; i < hashLength; i += 2){ hashBytes[i/2] = (byte) ((Character.digit(hash.charAt(i), 16) << 4) + Character.digit(hash.charAt(i + 1), 16)); } pkg.restrictUpdateHash = hashBytes; } } XmlUtils.skipCurrentTag(parser); } else if (RIGID_PARSER) { outError[0] = “Bad element under <manifest>: " + parser.getName(); mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; } else { Slog.w(TAG, “Unknown element under <manifest>: " + parser.getName() + " at " + mArchiveSourcePath + " " + parser.getPositionDescription()); XmlUtils.skipCurrentTag(parser); continue; } }parseBaseApplication private boolean parseBaseApplication(Package owner, Resources res, XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException, IOException { // 获取ApplicationInfo对象ai final ApplicationInfo ai = owner.applicationInfo; // 获取包名 final String pkgName = owner.applicationInfo.packageName; // 从资源里面获取AndroidManifest的数组 TypedArray sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestApplication); if (!parsePackageItemInfo(owner, ai, outError, “<application>”, sa, false /nameRequired/, com.android.internal.R.styleable.AndroidManifestApplication_name, com.android.internal.R.styleable.AndroidManifestApplication_label, com.android.internal.R.styleable.AndroidManifestApplication_icon, com.android.internal.R.styleable.AndroidManifestApplication_roundIcon, com.android.internal.R.styleable.AndroidManifestApplication_logo, com.android.internal.R.styleable.AndroidManifestApplication_banner)) { sa.recycle(); mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return false; } if (ai.name != null) { ai.className = ai.name; } // 在AndroidManifest里面是否设置了android:manageSpaceActivity属性, // 如果设置了则manageSpaceActivity不为空,没有设置manageSpaceActivity为空 String manageSpaceActivity = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity, Configuration.NATIVE_CONFIG_VERSION); if (manageSpaceActivity != null) { // 如果设置了,则添加类名 ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity, outError); } // 是否设置了androidMannifest.xml文件中android:allowBackup属性; boolean allowBackup = sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true); // 如果设置了允许备份 if (allowBackup) { ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; // backupAgent, killAfterRestore, fullBackupContent, backupInForeground, // and restoreAnyVersion are only relevant if backup is possible for the // given application. // 获取backupAgent,如果在AndroidManifest里面设置了android:backupAgent属性, // 则backupAgent不为空,否则backupAgent为空 String backupAgent = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestApplication_backupAgent, Configuration.NATIVE_CONFIG_VERSION); // 设置了backupAgent,这构建类名 if (backupAgent != null) { ai.backupAgentName = buildClassName(pkgName, backupAgent, outError); if (DEBUG_BACKUP) { Slog.v(TAG, “android:backupAgent = " + ai.backupAgentName + " from " + pkgName + “+” + backupAgent); } if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore, true)) { ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE; } if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_restoreAnyVersion, false)) { ai.flags |= ApplicationInfo.FLAG_RESTORE_ANY_VERSION; } if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_fullBackupOnly, false)) { ai.flags |= ApplicationInfo.FLAG_FULL_BACKUP_ONLY; } if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_backupInForeground, false)) { ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND; } } TypedValue v = sa.peekValue( com.android.internal.R.styleable.AndroidManifestApplication_fullBackupContent); if (v != null && (ai.fullBackupContent = v.resourceId) == 0) { if (DEBUG_BACKUP) { Slog.v(TAG, “fullBackupContent specified as boolean=” + (v.data == 0 ? “false” : “true”)); } // “false” => -1, “true” => 0 ai.fullBackupContent = (v.data == 0 ? -1 : 0); } if (DEBUG_BACKUP) { Slog.v(TAG, “fullBackupContent=” + ai.fullBackupContent + " for " + pkgName); } } ai.theme = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_theme, 0); ai.descriptionRes = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_description, 0); if ((flags&PARSE_IS_SYSTEM) != 0) { if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_persistent, false)) { // Check if persistence is based on a feature being present final String requiredFeature = sa.getNonResourceString( com.android.internal.R.styleable. AndroidManifestApplication_persistentWhenFeatureAvailable); if (requiredFeature == null || mCallback.hasFeature(requiredFeature)) { ai.flags |= ApplicationInfo.FLAG_PERSISTENT; } } } if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_requiredForAllUsers, false)) { owner.mRequiredForAllUsers = true; } String restrictedAccountType = sa.getString(com.android.internal.R.styleable .AndroidManifestApplication_restrictedAccountType); if (restrictedAccountType != null && restrictedAccountType.length() > 0) { owner.mRestrictedAccountType = restrictedAccountType; } String requiredAccountType = sa.getString(com.android.internal.R.styleable .AndroidManifestApplication_requiredAccountType); if (requiredAccountType != null && requiredAccountType.length() > 0) { owner.mRequiredAccountType = requiredAccountType; } if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_debuggable, false)) { ai.flags |= ApplicationInfo.FLAG_DEBUGGABLE; } if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_vmSafeMode, false)) { ai.flags |= ApplicationInfo.FLAG_VM_SAFE_MODE; } owner.baseHardwareAccelerated = sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_hardwareAccelerated, owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH); if (owner.baseHardwareAccelerated) { ai.flags |= ApplicationInfo.FLAG_HARDWARE_ACCELERATED; } if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_hasCode, true)) { ai.flags |= ApplicationInfo.FLAG_HAS_CODE; } if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting, false)) { ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING; } if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData, true)) { ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA; } // The parent package controls installation, hence specify test only installs. if (owner.parentPackage == null) { if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_testOnly, false)) { ai.flags |= ApplicationInfo.FLAG_TEST_ONLY; } } if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_largeHeap, false)) { ai.flags |= ApplicationInfo.FLAG_LARGE_HEAP; } if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_usesCleartextTraffic, true)) { ai.flags |= ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC; } if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_supportsRtl, false / default is no RTL support*/)) { ai.flags |= ApplicationInfo.FLAG_SUPPORTS_RTL; } if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_multiArch, false)) { ai.flags |= ApplicationInfo.FLAG_MULTIARCH; } if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs, true)) { ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS; } if (sa.getBoolean( R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage, false)) { ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE; } if (sa.getBoolean( R.styleable.AndroidManifestApplication_directBootAware, false)) { ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE; } if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) { if (sa.getBoolean(R.styleable.AndroidManifestApplication_resizeableActivity, true)) { ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE; } else { ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE; } } else if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) { ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; } ai.maxAspectRatio = sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0); ai.networkSecurityConfigRes = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_networkSecurityConfig, 0); ai.category = sa.getInt( com.android.internal.R.styleable.AndroidManifestApplication_appCategory, ApplicationInfo.CATEGORY_UNDEFINED); String str; str = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestApplication_permission, 0); ai.permission = (str != null && str.length() > 0) ? str.intern() : null; if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { str = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity, Configuration.NATIVE_CONFIG_VERSION); } else { // Some older apps have been seen to use a resource reference // here that on older builds was ignored (with a warning). We // need to continue to do this for them so they don’t break. str = sa.getNonResourceString( com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity); } ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName, str, outError); if (outError[0] == null) { CharSequence pname; if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { pname = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestApplication_process, Configuration.NATIVE_CONFIG_VERSION); } else { // Some older apps have been seen to use a resource reference // here that on older builds was ignored (with a warning). We // need to continue to do this for them so they don’t break. pname = sa.getNonResourceString( com.android.internal.R.styleable.AndroidManifestApplication_process); } ai.processName = buildProcessName(ai.packageName, null, pname, flags, mSeparateProcesses, outError); ai.enabled = sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_enabled, true); if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_isGame, false)) { ai.flags |= ApplicationInfo.FLAG_IS_GAME; } if (false) { if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState, false)) { ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE; // A heavy-weight application can not be in a custom process. // We can do direct compare because we intern all strings. if (ai.processName != null && ai.processName != ai.packageName) { outError[0] = “cantSaveState applications can not use custom processes”; } } } } ai.uiOptions = sa.getInt( com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0); ai.classLoaderName = sa.getString( com.android.internal.R.styleable.AndroidManifestApplication_classLoader); if (ai.classLoaderName != null && !ClassLoaderFactory.isValidClassLoaderName(ai.classLoaderName)) { outError[0] = “Invalid class loader name: " + ai.classLoaderName; } sa.recycle(); if (outError[0] != null) { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return false; } final int innerDepth = parser.getDepth(); // IMPORTANT: These must only be cached for a single <application> to avoid components // getting added to the wrong package. final CachedComponentArgs cachedArgs = new CachedComponentArgs(); int type; // 开始解析 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } String tagName = parser.getName(); // 解析activity if (tagName.equals(“activity”)) { Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false, owner.baseHardwareAccelerated); if (a == null) { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return false; } owner.activities.add(a); // 解析receiver } else if (tagName.equals(“receiver”)) { Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, true, false); if (a == null) { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return false; } owner.receivers.add(a); // 解析service } else if (tagName.equals(“service”)) { Service s = parseService(owner, res, parser, flags, outError, cachedArgs); if (s == null) { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return false; } owner.services.add(s); // 解析provider } else if (tagName.equals(“provider”)) { Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs); if (p == null) { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return false; } owner.providers.add(p); … … } else { if (!RIGID_PARSER) { Slog.w(TAG, “Unknown element under <application>: " + tagName + " at " + mArchiveSourcePath + " " + parser.getPositionDescription()); XmlUtils.skipCurrentTag(parser); continue; } else { outError[0] = “Bad element under <application>: " + tagName; mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return false; } } } // Must be ran after the entire {@link ApplicationInfo} has been fully processed and after // every activity info has had a chance to set it from its attributes. setMaxAspectRatio(owner); PackageBackwardCompatibility.modifySharedLibraries(owner); // 检查IntentFilter之一是否包含DEFAULT / VIEW和HTTP / HTTPS数据URI if (hasDomainURLs(owner)) { owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS; } else { owner.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS; } return true; }其实这个方法就是解析了application节点下的所有信息,比如activity、service、receiver、provider、library、users-librayry等信息,同时将解析后的每一个属性生成相应的对象,添加到传入的package里面,这些信息最后都会在PackageManagerService中用到。扫描非系统 Package if (!mOnlyCore) { // mOnlyCore 用于控制是否扫描非系统 Package // do this first before mucking with mPackages for the “expecting better” case final Iterator<PackageParser.Package> pkgIterator = mPackages.values().iterator(); while (pkgIterator.hasNext()) { final PackageParser.Package pkg = pkgIterator.next(); if (pkg.isStub) { stubSystemApps.add(pkg.packageName); } } final Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator(); while (psit.hasNext()) { PackageSetting ps = psit.next(); /* * If this is not a system app, it can’t be a * disable system app. / if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) { /// M: Operator apps are belong to system domain, therefore, need prune. /// We should also consider OTA from old version without mtkFlag if (sPmsExt.isNotOperatorApp(ps)) continue; } / * If the package is scanned, it’s not erased. / final PackageParser.Package scannedPkg = mPackages.get(ps.name); if (scannedPkg != null) { / * If the system app is both scanned and in the * disabled packages list, then it must have been * added via OTA. Remove it from the currently * scanned package so the previously user-installed * application can be scanned. / if (mSettings.isDisabledSystemPackageLPr(ps.name)) { logCriticalInfo(Log.WARN, “Expecting better updated system app for " + ps.name + “; removing system app. Last known codePath=” + ps.codePathString + “, installStatus=” + ps.installStatus + “, versionCode=” + ps.versionCode + “; scanned versionCode=” + scannedPkg.mVersionCode); removePackageLI(scannedPkg, true); mExpectingBetter.put(ps.name, ps.codePath); } continue; } if (!mSettings.isDisabledSystemPackageLPr(ps.name)) { psit.remove(); logCriticalInfo(Log.WARN, “System package " + ps.name + " no longer exists; it’s data will be wiped”); // Actual deletion of code and data will be handled by later // reconciliation step } else { // we still have a disabled system package, but, it still might have // been removed. check the code path still exists and check there’s // still a package. the latter can happen if an OTA keeps the same // code path, but, changes the package name. final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name); if (disabledPs.codePath == null || !disabledPs.codePath.exists() || disabledPs.pkg == null) { possiblyDeletedUpdatedSystemApps.add(ps.name); } } } } if (!mOnlyCore) { scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0); scanDirTracedLI(mDrmAppPrivateInstallDir, mDefParseFlags | PackageParser.PARSE_FORWARD_LOCK, scanFlags | SCAN_REQUIRE_KNOWN, 0); // Remove disable package settings for updated system apps that were // removed via an OTA. If the update is no longer present, remove the // app completely. Otherwise, revoke their system privileges. for (String deletedAppName : possiblyDeletedUpdatedSystemApps) { PackageParser.Package deletedPkg = mPackages.get(deletedAppName); mSettings.removeDisabledSystemPackageLPw(deletedAppName); final String msg; if (deletedPkg == null) { // should have found an update, but, we didn’t; remove everything msg = “Updated system package " + deletedAppName + " no longer exists; removing its data”; // Actual deletion of code and data will be handled by later // reconciliation step } else { // found an update; revoke system privileges msg = “Updated system package + " + deletedAppName + " no longer exists; revoking system privileges”; // Don’t do anything if a stub is removed from the system image. If // we were to remove the uncompressed version from the /data partition, // this is where it’d be done. final PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName); deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM; deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM; /// M: [Operator] Revoke operator permissions for the original operator sPmsExt.clearExtFlags(deletedPkg, deletedPs); } logCriticalInfo(Log.WARN, msg); } / * Make sure all system apps that we expected to appear on * the userdata partition actually showed up. If they never * appeared, crawl back and revive the system version. */ for (int i = 0; i < mExpectingBetter.size(); i++) { final String packageName = mExpectingBetter.keyAt(i); if (!mPackages.containsKey(packageName)) { final File scanFile = mExpectingBetter.valueAt(i); logCriticalInfo(Log.WARN, “Expected better " + packageName + " but never showed up; reverting to system”); int reparseFlags = mDefParseFlags; if (FileUtils.contains(privilegedAppDir, scanFile)) { reparseFlags = PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_IS_PRIVILEGED; } else if (FileUtils.contains(systemAppDir, scanFile)) { reparseFlags = PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR; } else if (FileUtils.contains(vendorAppDir, scanFile)) { reparseFlags = PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR; } else if (FileUtils.contains(oemAppDir, scanFile)) { reparseFlags = PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR; } else { Slog.e(TAG, “Ignoring unexpected fallback path " + scanFile); continue; } mSettings.enableSystemPackageLPw(packageName); try { scanPackageTracedLI(scanFile, reparseFlags, scanFlags, 0, null); } catch (PackageManagerException e) { Slog.e(TAG, “Failed to parse original system package: " + e.getMessage()); } } } // Uncompress and install any stubbed system applications. // This must be done last to ensure all stubs are replaced or disabled. decompressSystemApplications(stubSystemApps, scanFlags); final int cachedNonSystemApps = PackageParser.sCachedPackageReadCount.get() - cachedSystemApps; final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime; final int dataPackagesCount = mPackages.size() - systemPackagesCount; Slog.i(TAG, “Finished scanning non-system apps. Time: " + dataScanTime + " ms, packageCount: " + dataPackagesCount + " , timePerPackage: " + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount) + " , cached: " + cachedNonSystemApps); if (mIsUpgrade && dataPackagesCount > 0) { MetricsLogger.histogram(null, “ota_package_manager_data_app_avg_scan_time”, ((int) dataScanTime) / dataPackagesCount); } }构造函数分析 - 扫尾工作这部分任务比较简单,就是将第二阶段手机的信息再集中整理一次,可自行研究。总结第二阶段分析就此结束! ...

October 26, 2018 · 20 min · jiezi