android基于linux所以当设备上电后,初期嘚启动流程跟linux系统并无二致uboot引导,接着载入kernel代码加载各种驱动,结束后启动第一个用户级进程init,init接着解析init.rc后按照配置启动各种linux后囼进程。
整个linux系统底层已经Ready后接着要干嘛,当然是启动android引导进程装载android运行环境所需的代码和资源。
Android的引导进程是Zygote我们可以在init.rc中找到她,Zygote运行后会创建davlik虚拟机,加载framework.jar等代码和资源;Zygote是所有android进程的父进程这里的android进程是指需要共享dalvik虚拟机的进程。Zygote初始化结束后会fork出她嘚第一个子进程system_server,即android的核心服务进程很多轻量级的service都跑在这个进程中,这些轻量级的服务当中包含了本章所要详细描述的package怎么使用Manager
PMS,顧名思义一个负责安装包管理的服务,它在systemserver起来后被创建并完成初始化它是整个android的基础,如果PMS出问题了那整个android运行会乱掉。
本文将會简单介绍PMS的整个实现原理由于本人水平有限,文中肯定会存在描述不准确或者错误的地方欢迎指正!
1:APK文件结构概述
Android的安装包叫apk(android package怎麼使用),在介绍怎么管理它之前肯定要先了解它的内部结构,要不在后续看PMS的相关代码时会一头雾水。
APK文件就是一个zip压缩文件用解壓缩软件可以看到其内部结构如下:
1) META-INF文件夹主要包含APK内所有文件的摘要清单,清单签名数据和公钥证书
我们如果将APK文件解压接着查看内蔀文件内容,会发现除了assets目录下的其他所有XML文件都会被转换成二进制文件,android在打包的时候做了什么这么做的目的是什么?
Android资源ID是一个4芓节的无符号整数最高字节表示package怎么使用ID,次高字节表示TypeID最低两字节表示EntryID;所以,当我们拿到资源ID时我们就知道资源所属包,以及對应的资源类型和入口ID所有的资源ID最终都生成到R.java。
有了资源ID当然不够资源ID对应的数据是什么?所以还需要资源索引描述表这样才可鉯通过资源ID,快速的找到最匹配的资源数据;
所有分配的资源ID都会被按照指定的数据结构重新组织并连同资源数据保存到resources.arsc中
resources.arsc是android资源数据嘚核心,有了它程序在运行时,就可以根据当前的各种环境比如language,screensize等等来快速定位最匹配的资源;同时由于资源数据的ID化又可以保證资源数据最大可能的复用,从而减少APK的大小
试想下,如果对AndroidManifest和各种布局文件如果都是通过纯文本解析,那效率肯定是无法接受的還有一点,文件中的各种关联数据的值如何获取比如drawable,string等等在上面已经描述过,resources.arsc包含了所有数据的ID和对应值所以我们只需要根据xml内蔀数据,重新定义数据结构并将xml各种值元素的key和value替换成resources.arsc中对应的id值,接着将结构化数据存储到同名文件中即可这就是我们再在包后看箌的二进制数据。
接着介绍程序启动后如何读取资源数据比如我们要根据layout ID读取对应的layout文件
2) 通过资源ID的次高位字节,得到资源类型为layout從而在app资源描述表中快速定位到layout类型的数据结构
3) 根据app当前的硬件或系统信息(language,screensize等)在layout类型的数据结构中,快速的匹配到最佳资源从而拿到资源路径
4) 根据资源路径,获取布局文件数据
5) 根据布局文件数据生成AttributeSet,接着根据AttributeSet的解析节点信息和对应属性ID从app资源描述表,获取AttributeSet中当前节点下对应属性的值
android默认提供了AssetManager来实现上述功能,不过我们实际开发中更多的是使用Resource来获取资源数据,Resource基于AssetManager重新封装提供叻更加易用的接口并对指定操作做特殊处理,比如drawableResource会添加缓存处理等。
下面简单介绍几个跟PMS相关的:
通过R.attr数组读取相当于把要读取的屬性ID直接写入代码中,扩展性和维护性都比较差所以建议使用第二种方式。
通过使用styleable就使目标属性集合可配置,从而提高程序的扩展性
Android应用在打包之后在正式发布前,需要对其签名签名的目的主要有两个:
1)保护APK数据的完整性
2)作为APK的身份验证
下面简单介绍下签名嘚原理以及APK解析时的相关验证代码。
1.2.1 消息摘要加解密,数字签名数字证书
下面的名词解释相关内容大部分都摘自网络
消息摘要算法是使用一个Hash函数对任意长度的输入数据进行处理,输出固定长度的数 据输出数据称为消息摘要。无法从消息摘要倒推出消息内容常用的消息摘要算法是 MD5 和 SHA-1。
公钥加密算法又称为非对称密钥加密算法因为它包含一个公钥-私钥对,称为key pair即 key pair = private key +public key。从功能上说两个key作用相同,用┅个key加密的消息只能用另一个key解密,反之亦然
数字签名就是将原始数据的信息摘要用private key加密后,和原始数据一起发送给接收方;
接收方收到签名数据后先使用public key进行解密,拿到信息摘要;接着用收到的原始数据生成信息摘要并与解密后的信息摘要做对比,如果一致数據完整性验证通过, 否则验证失败说明数据被修改了。
由于无法通过publickey推导出private key通过数字签名就可以确保发送数据额完整,再则private key只有发送鍺知道这样又可以确保数据是由private key的拥有者发送的。
数字签名存在一个问题那就是数据接收方如何获取publickey?预先把public key给接 收方或者直接和数芓签名一起发送给接收方这么做在通常情况下,肯定是没问题的但是 在如下两种情况下,会存在安全性问题:
1:预先把publickey 给接收方如果有人在接收方不知情的情况下,更换了public key然后再截取发送过来的数据并替换成自己的,这样接收方和发送方在不知情的情况下,数据巳经被人调包了
2:publickey连同数字签名一起发送给接收方,如果有人截取发送的数据将数据,数字签名和public key都替换掉这样也会产生数据调包嘚问题。
所以要解决上面安全性问题,核心就是保证发送者的publickey不被调换
数字证书因此而生,数字证书是指由权威机构CA认证发行的主偠包含拥有者的相关信 息和public key;所以上述发送者,只需要去CA提供自己的相关信息和publickey做认证加密,通过后CA会给其一本数字证书;后续发送鍺发送数据时,将数据用private key加密后随同数字证书一起发出,就ok了
APK在使用SignApk进行签名后,会在META-INF目录下生成如下文件:
到这里很多人可以会囿疑问,为什么要产生CERT.SF这个摘要文件好像没啥必要啊,直接用MANIFEST.MF不就可以了;细细的思考下好像的确是这么回事,但是我们还是要相信Google這么做是有原因的有可能是为了APK校验时效率更高?异或是为了留个口子便于后续扩展,这里就不做深究咱们继续往下走