声明
- 以Android手机用户角度来看,安装各式各样的APP,基本就是从应用市场上 “搜索->下载->安装” 三连。而对Android系统来说,这就是个大工程了,因为对Android系统来说APK是“外来户”,如何安装它、有限制地支持它的运行、如何防着它干坏事等问题就来了。
- 写此专栏的起因是为了给客户在定制的Android系统中实现 大型APK快速安装的功能。
- 本专栏就来从Android系统的角度来分析下APK的整个生命周期(安装-运行-卸载),包含对APK的静态/动态分析、PackageManagerService、pm命令、PackageInstaller、Installd
- 此篇代码基于LineageOS 14.1(Android 7.1.1),参考一些博客和书籍,不方便逐一列出,仅供学习、知识分享。
1 APK的文件结构
Android 应用均是以 APK 文件格式进行发布和安装的。APK 文件同时包含应用程序的代码和资源,包括应用程序的 manifest 文件。它们还可以包含一个代码签名文件。APK 文件格式是 JavaJAR 的一种扩展格式,当然也是广为流行的 ZIP 文件格式的扩展格式,可以使用 ZIP 格式的压缩工具对其进行解压。如下是一个典型 APK 文件解压后的内容:
pedro@x86:$ tree -L 2
.
├── AndroidManifest.xml APP属性定义文件
├── classes2.dex Java源码编译后的代码文件
├── classes.dex
├── asserts 声音、字体、网页....资源
├── lib 应用中调用到的库
│ ├── armeabi
│ ├── arm64-v8a
├── META-INF APK的签名文件(*.RSA、*.SF、*.MF 文件)
│ ├── androidx.activity_activity.version
│ ├── ...省略...
│ ├── androidx.viewpager2_viewpager2.version
│ ├── androidx.viewpager_viewpager.version
│ ├── CERT.RSA
│ ├── CERT.SF
│ ├── com
│ └── MANIFEST.MF
├── res APP中使用到的资源目录
│ ├── anim 动画资源
│ ├── animator
│ ├── animator-v21
│ ├── anim-v21
│ ├── color 颜色资源
│ ├── color-v23
│ ├── drawable 可绘制的图片资源
│ ├── drawable-hdpi-v4
│ ├── drawable-ldrtl-hdpi-v17
│ ├── drawable-ldrtl-mdpi-v17
│ ├── drawable-ldrtl-xhdpi-v17
│ ├── drawable-ldrtl-xxhdpi-v17
│ ├── drawable-ldrtl-xxxhdpi-v17
│ ├── drawable-mdpi-v4
│ ├── drawable-v21
│ ├── drawable-v23
│ ├── drawable-v24
│ ├── drawable-watch-v20
│ ├── drawable-xhdpi-v4
│ ├── drawable-xxhdpi-v4
│ ├── drawable-xxxhdpi-v4
│ ├── interpolator
│ ├── interpolator-v21
│ ├── layout 页面布局文件
│ ├── layout-land
│ ├── layout-sw600dp-v13
│ ├── layout-v21
│ ├── layout-v26
│ ├── layout-watch-v20
│ ├── mipmap-anydpi-v26
│ ├── mipmap-hdpi-v4
│ ├── mipmap-mdpi-v4
│ ├── mipmap-xhdpi-v4
│ ├── mipmap-xxhdpi-v4
│ ├── mipmap-xxxhdpi-v4
│ └── xml 应用属性配置文件
└── resources.arsc 编译后的资源文件,如 strings.xml
APK 中的 AndroidManifest.xml 文件中注册着 APK 所有的重要信息(四大组件、包名、META等),通过分析AndroidManifest.xml 更有助于我们了解整个应用的架构。APK 解压后的几个重要文件,classes.dex 文件、AndroidManifest.xml文件、so 文件(c/c++代码文件,存在JNI的情况下会有此文件 )、resources.arsc ( 资源文件)。
2 APP的种类
Android 应用程序开发使用 Java 语言,若还使用 NDK 的话还需要 C/C++ 进行JNI调用。目前,市面上也存在着多种 Android 应用开发的语言。比如:PhoneaGap 提供使用 HTML5+JavaScript 进行开发,Cocos2dX 也是提供 C/C++ 语言进行跨平台开发等。
目前主流应用程序开发方式大体分为3类(如下图所示):
- Web App (网页 App )
- Hybrid App (混合App)
- Native App(原生App)。
2.1 原生 APP
基于 Google 的 SDK 使用 Java 语言或 C/C++语言进行开发,称为Native App。Native App 指的是原生程序,一般依托于操作系统,有很强的交互,是一个完整的App,可拓展性强,需要用户下载安装使用。
- 优点:打造完美的用户体验;性能稳定;操作速度快,上手流畅;访问本地资源(通讯录,相册);设计出色的动效,转场;拥有系统级别的贴心通知或提醒;用户留存率高。
- 缺点:分发成本高(不同平台有不同的开发语言和界面适配);维护成本高(例如一款 App 已更新至V4 版本,但仍有用户在使用 V2、V3版本,需要更多的开发人员维护之前的版本 );更新缓慢,根据不同平台,提交-审核-上线等不同的流程,需要经过的流程较复杂。
2.2 Web APP
采用 Html5 语言写的 App,不需要下载安装,类似于现在所说的轻应用,是生存在浏览器中的应用,可以理解为触屏版的网页应用。当然,也有些应用是将网页再通过Android SDK打包成APK文件的形式上传到市场上的。主要开发方式就是使用的HTML5+JavaScript,使用 WebView 作为本地接口进行开发,其架构如下图所示。
- 优点:开发成本低;更新快;更新无需通知用户,不需要手动升级;能够跨多个平台和终端。因为开发与使用成本都比较低,所以很多巨头公司都推出了自己的 WebApp 搭建平台,又称为轻应用。
- 缺点:临时性的人口,无法获取系统级别的通知、提醒、动效等用户留存率低,设计受限制诸多,体验较差。
2.3 混合 APP
半原生半 Web 的混合类App,需要下载安装,看上去类似 Native App,但只有很少的 UI WebView,访问的内容是 Web。常见的有新闻类App、视频类 App,普遍采取的是Native的框架、Web 的内容。
Hybrid App 也包括使用其他语言(C#、JavaScript)进行开发的 App。使用第三方语言进行开发的原理基本都是将其编译为 so 文件,再通过JNI的方式调用其逻辑。
3 Android 代码签名
Android 为何需要代码签名? 原因通常是:为了 完整性 和 可靠性。在执行任何第三方程序之前,你希望确保该程序没有被篡改(完整性),并且该程序确实由它所声称的创建者所创建(可靠性)。AOSP 的 build/ 目录中包含一个叫 signapk 的Android专用工具。
Android 代码签名机制是基于Java JAR 签名机制,所以它跟许多代码签名方案一样,使用公钥加密和 X.509 证书。实际上,代码签名证书必须由一个信任平台 CA 颁发。虽然有很多颁发证书的 CA,然而仍然很难获取一个受所有目标设备信任的证书。Android 非常简单地解决了这个问题:它不关心证书的内容和签发者。因此你的证书不需要必须由 CA 颁发,实际上所有 Android 里使用的代码签名,均是自签名的。
签名验证过程,既验证代码是否被篡改,同时又验证签名确实由所预期的密钥生成但是存在一个问题,代码签名不能直接解决代码签名者(软件发布者)能否被信任的问题。通常建立信任关系的方法是,要求代码签名者持有数字证书,并且将其附加到被签名的代码中去。验证者决定是否信任,可以基于一种信任模型(例如 PKI或信任网),或者具体案例具体对待。
代码签名的另一个问题是,它不能解决被签名的代码是否确定是安全的。
4 DEX文件
Dex文件是Android上的可执行文件,由Java 虚拟机JVM编译后再由 Android 中的虚拟机 Dalvik 所编译后而成。
5 so文件
Android平台的底层就是 Linux 系统,而 Linux 系统原本就是使用 C/C++语言的。只是Android在上面使用了一个 Dalvik/ART 虚拟机才使得应用程序的开发使用 Java语言。虚拟机 Dalvik/ART 本身支持JNI编程方式。
NDK(Native Development Kit) 就是为了 “Java+C” 开发而提出来的工具库,使得在使用 C/C++ 开发时能够保证程序的兼容性、调试性与调用 API 的方便性。使用 NDK 进行应用程序开发也能够避免掉 Java 中的一些不足:
目的 | 说明 |
---|---|
代码的保护 | APK中的Java代码很容易被反编译、阅读和篡改,而对C/C++开发出来 so库进行反汇编难度较大 |
可以方便地使用现存的开源库 | 大部分现存的开源库(OpenCV、OpenGL等)都是用 C/C++代码编写的 |
提高程序的执行效率 | 将要求高性能的应用逻辑使用 C开发,从而提高应用程序的执行效率 |
便于移植 | 用 C/C++写的 so 库可以方便地在其他的入式平台上再次使用 |
6 APK逆向工程
APK的逆向破解也是个大学问,我工作不涉及这个,所以就不研究了。