android文件校验
① Android生成APK后目录中META-INF目录文件解析
Android开发环境对每一个需要Release的APK都会进行签名,在APK文件被安装时,Android系统会对APK的签名信息进行比对,以此来判断程序的完整性,最终确定APK是否可以正常安装使用,一定程度上达到安全的目的。
给一个APK文件的后缀名从.apk改为.zip或者.rar,然后利用解压工具进行解压,我们会在META-INF目录下看到四个文件: MANIFEST.MF、CERT.SF、INDEX.LIST、CERT.RSA
MANIFEST.MF(摘要文件): 程序遍历APK包中的所有文件,对非文件夹非签名文件的文件,逐个用SHA1生成摘要信息,再用Base64进行编码。如果APK包的文件被修改,在APK安装校验时,被修改的文件与MANIFEST.MF的校验信息不同,程序将无法正常安装。
CERT.SF(对摘要文件的签名文件): 对于生成的MANIFEST.MF文件利用SHA1-RSA算法对开发者的私钥进行签名。在安装时只有公共密钥才能对其解密。解密之后将其与未加密的摘要信息进行比对,如果相符则文件没有被修改。
INDEX.LIST APK索引文件目录
CERT.RSA 保存公钥、加密算法等信息。
在APK进行安装时,可以通过MANIFEST.MF文件开始的环环相扣来保证APK的安全性。但这些文件或者密钥如果被攻击者得到或者被攻击者通过某些技术手段攻破,则Android操作系统无法验证其安全性。
② Android启动优化概述
Android启动应用, 按 官方说法 分为冷启动, 温启动和热启动.
具体的定义可以看官方文档, 简单地说
一般我们只需要关注冷启动即可.
要想启动快, 硬件性能必然有影响, 在硬件一定的前提下, 我们要尽量 降低启动应用时CPU的负载 , 让CPU有更多的算力投入到启动流程中:
在做好一些基本原则后, 接着看具体的流程优化点
在应用进程创建后, 首先必然是加载类, 此时一些静态变量就会初始化了, 因此我们应该
类加载完毕后就是创建 Application 实例了, 因此我们应该
之后会先创建 ContentProvider 和执行 ContentProvider.onCreate() , 因此我们应该
跟接着就会执行 Application.onCreate() 等方法, 因此我们应该
接着就进入 Activity 环节.
同样第一步会是创建实例, 因此我们应该
在 Activity 进程生命周期后, 第一步就是渲染(inflate)布局, 我们应该
在应用启动的瞬间, 系统服务会先展示一个空白窗口, 等待应用第一帧绘制完毕后, 再从该窗口切换到应用, 如果启动耗时较长, 就会明显看到白屏, 对于这一点, 常见的操作有
可以使用IdleHandler, 在主线程空闲时再执行某些不重要的操作
实际上异步初始化只是不阻塞主线程, 但是子线程一样会占用CPU资源, 让主线程的执行时间变少, 所以不应该盲目地将所有工作放到子线程.
优化做到最后, 就是在系统流程上做文章了
原理是将启动时加载的类放到主dex,提升了这些类的内聚,让更多的类满足pre-verify的条件,在安装时就做了校验和优化,以减少首次加载的耗时,从而优化冷启动耗时。
Redex 初探与 Interdex:Andorid 冷启动优化
应用启动过程中会从apk压缩包中读取文件, 该优化的原理是利用Linux中的Pagecache机制, 让启动过程会用到的文件尽可能进入缓存中, 减少磁盘IO次数
支付宝 App 构建优化解析:通过安装包重排布优化 Android 端启动性能
在Dalvik VM(Android5.0以前)加载类的时候会有一个类校验过程, 它需要校验方法的每一个指令, 是一个比较耗时的过程, 可以通过Hook去掉类加载过程中的类验证过程. 不过对于ART(Android5.0之后)来说, 这个过程在安装时已经做了, 所以用处不大.
不进入冷启动, 就不用优化了~
这个Android Studio自带的工具, 可以看到启动过程中详细的方法执行流程, 但是采集数据本身会影响方法执行, 所以不能准确判断每个方法的耗时, 但是仍可以判断哪个方法相对来说耗时.
这个工具的好处是可以自定义事件, 可以指定需要采集的数据集, 可以看到线程间的状态等.
启动优化的一个关键点在于定义启动结束的点, 以及如何测量启动时间.
在Android4.4以上, 系统进程会提供一个类似 ActivityManager: Displayed ***: +3s534ms 的日志, 表示从启动进程到首次绘制完毕所用的时间.
应用可以在任何时候调用该方法, 触发系统打印类似 system_process I/ActivityManager: Fully drawn {package}/.MainActivity: +1s54ms 的日志
应用可以通过 ViewTreeObserver 来监听绘制前回调来判断第一帧的绘制时机, 或者直接在控件树的末尾加一个简单的View, 它 onDraw 调用时即表示页面(差不多)绘制完毕.
应用启动过程可以参考 Android Vitals Series' Articles 系列文章