漫画Android:APK是怎样安装的?
APK的安装过程可以概括为以下几个主要阶段:
- 解析 (Parsing):系统检查APK文件的完整性和合法性。
- 验证 (Verification):校验APK的数字签名,确保应用未被篡改。
- 提取 (Extraction):将APK中的内容解压到设备存储。
- 优化 (Optimization):对DEX文件进行优化,生成ODEX或ART格式。
- 安装 (Installation):将应用注册到系统,创建数据目录,并关联权限。
通俗地讲,你可以把APK的安装过程想象成一个App从“搬家”到“安家落户”的全过程:
I. 准备阶段:
打包(APK文件): App的开发者把App的所有东西都打包成一个APK“行李箱”。
下载(获取APK): 用户把这个“行李箱”下载到手机。
II. 安装阶段:App“住”进手机
A. 检查(解析、验证): 手机检查这个“行李箱”是否安全、里面有什么东西、需要哪些“通行证”(权限)。
B. 搬家(提取、优化): 手机把“行李箱”里的东西都拿出来,放到一个专门的“新家”里,并且把一些东西“摆放”好,方便快速使用。
C. 登记(安装注册到系统): 手机把这个“新住户”的信息登记到“户口本”上,让所有人都知道手机里多了一个新成员。
III. 完成阶段:App“就绪”,可以运行了
之后就是 入住(显示图标、首次运行): 用户就可以看到这个App的“门牌号”(图标),并且可以打开它,正式开始使用了!
其中「准备阶段」自不必说,我们详细讲讲「安装阶段」!
详细步骤解析
1. 解析 (Parsing)
当你点击一个APK文件时,系统首先会启动一个PackageManagerService (PMS) 的组件来处理这个安装请求。
- 入口点: 通常是
PackageInstaller
(用户界面)或PackageManager
的installPackage()
方法被调用。 - 文件检查: PMS会首先对APK文件进行基本的合法性检查,例如:
- 它是不是一个合法的ZIP文件?
- 文件后缀是不是
.apk
? - 文件头部信息是否正确?
- Manifest文件解析: 这是解析阶段最重要的部分。PMS会读取APK内部的
AndroidManifest.xml
文件。这个文件是应用的“身份证”,它包含了应用的所有核心信息:- 包名 (Package Name): 唯一标识应用的字符串,例如
com.tencent.mm
(微信)。 - 版本号 (Version Code / Version Name): 应用的版本信息。
- 组件信息: 包含Activity、Service、BroadcastReceiver、ContentProvider等四大组件的声明。
- 权限 (Permissions): 应用请求的各种权限,例如访问网络、读取联系人等。
- 最低/目标SDK版本: 应用兼容的Android版本范围。
- 签名信息: 用于后续的验证。
- 包名 (Package Name): 唯一标识应用的字符串,例如
- 冲突检测: PMS会检查新安装的APK的包名是否与设备上已安装的应用包名冲突。如果冲突且不是更新,安装将会失败。
2. 验证 (Verification)
解析完成后,进入安全至关重要的验证阶段。
- 数字签名验证: 这是Android安全机制的核心。APK文件在打包时会使用开发者的私钥进行数字签名。PMS会做以下几件事:
- 提取签名: 从APK中的
META-INF
目录下提取签名文件(例如CERT.RSA
、CERT.SF
)。 - 校验完整性: 使用公钥验证APK中所有文件的哈希值,确保APK在传输或存储过程中没有被篡改。如果任何一个文件被修改,签名验证都会失败。
- 签名一致性: 如果是应用更新,PMS会检查新APK的签名是否与已安装应用的签名一致。不一致则安装失败(除非是系统应用)。这防止了恶意应用冒充正版应用进行更新。
- 提取签名: 从APK中的
- 病毒扫描 (可选): 如果设备安装了安全软件,并且系统启用了“验证应用”功能,那么在签名验证之后,可能会调用第三方安全软件对APK进行病毒扫描。
- SELinux上下文分配: 在这个阶段,系统还会根据应用的包名和权限,为其分配一个SELinux (Security-Enhanced Linux) 上下文。SELinux是Android底层的强制访问控制机制,它决定了应用可以访问哪些文件、进程和系统资源。
3. 提取 (Extraction)
验证通过后,系统开始将APK文件中的内容解压并放置到设备存储中。
- 目标目录: Android系统会为每个应用分配一个独立的存储空间,通常在
/data/app/
目录下,例如/data/app/com.szsl.myapp/
。这个目录通常包含:- Base APK: 实际的APK文件本身。
- Library目录: 包含应用的
.so
库(C/C++原生代码编译成的动态链接库),例如lib/arm64
。 - ODEX/ART文件 (如果有): 优化后的DEX文件。
- 权限设置: 系统会为这些解压出来的文件和目录设置严格的文件系统权限,确保只有应用本身和系统可以访问它们。
4. 优化 (Optimization)
这是一个非常重要的阶段,它关系到应用的启动速度和运行效率。
- DEX文件: Android应用的代码是用Java编写的,编译后会生成
.class
文件,然后通过DX工具转换成.dex
(Dalvik Executable)文件。一个APK可以包含多个DEX文件。 - ART (Android Runtime) 优化:
- Android 5.0 (Lollipop) 之前 (Dalvik虚拟机): 采用JIT (Just-In-Time) 编译。安装时会生成
.odex
(Optimized Dalvik Executable)文件。这个文件是DEX文件的优化版本,它包含了对DEX文件进行预校验和优化后的字节码,可以加速应用的加载。 - Android 5.0 (Lollipop) 及之后 (ART虚拟机): ART采用AOT (Ahead-Of-Time) 编译。在安装时,系统会使用
dex2oat
工具将DEX文件编译成设备的本地机器码(ELF格式)。这些本地机器码文件通常存储在/data/app/包名/oat/
目录下。- 好处: AOT编译使得应用在运行时无需进行JIT编译,从而大大提高了应用的启动速度和运行性能。这也是为什么首次安装应用后,系统会显示“正在优化应用”或“正在安装应用”的进度条,这个过程会消耗一定时间。
- Android 5.0 (Lollipop) 之前 (Dalvik虚拟机): 采用JIT (Just-In-Time) 编译。安装时会生成
- Profile-Guided Compilation (PGO): 从Android N (7.0) 开始,ART还引入了PGO。在应用首次运行后,ART会收集应用的运行数据,并在后台再次对DEX文件进行优化,生成更高效的本地机器码。这进一步提升了应用的性能。
5. 安装 (Installation)
这是整个过程的最后阶段,系统将应用注册到它的内部数据库,并为应用分配UID和GID。
- 包信息注册: PMS会将应用的详细信息(包名、版本、权限、组件、签名等)注册到系统内部的
packages.xml
(旧版本)或数据库(新版本)中。这个数据库是系统管理所有已安装应用的核心。 - 创建数据目录: 系统会为应用创建私有的数据目录,通常在
/data/data/包名/
下。这个目录是应用存储其私有数据(数据库、SharedPreferences、缓存文件、内部存储文件等)的地方,其他应用无法直接访问。 - UID/GID分配: 每个安装的应用都会被分配一个独立的Linux用户ID (UID) 和组ID (GID)。这是Android沙箱机制的基础。每个应用都在自己的进程中运行,并且拥有独立的UID/GID,从而实现了进程隔离。
- 权限关联: 系统将应用请求的权限与分配的UID/GID关联起来。当应用尝试执行某个需要权限的操作时,系统会检查其UID/GID是否拥有相应的权限。
- 桌面快捷方式 (可选): 如果应用声明了
android.intent.category.LAUNCHER
的Activity,系统可能会通知桌面启动器(Launcher)为应用创建快捷方式。 - 广播通知: 安装完成后,系统会发送
ACTION_PACKAGE_ADDED
等广播,通知其他对应用安装感兴趣的系统组件或第三方应用(例如,桌面启动器、应用商店等)。