0%

Android-Apk安装的流程(前章)

感悟

最近自己又去阅读了Android源码,感觉以前有些困惑清晰了不少。
android源码庞大而复杂,一个源文件文件少则都是几千行代码。抓住核心很重要,那么多API的调用链根本记不完,不能一窥全貌,就只能迷失在森林之中,其实重要的是去梳理流程,搞清楚这个模块的设计初衷是为了什么,如果让你自己来你会怎么设计,如何写出高质量的代码。
思维上的提高才是本质上的进步!!!

摘要

APK安装的方式其实有很多种,网上也有很多好的文章,不过学会才是最重要的,做出我们自己的总结。
从2021 年 8 月起 新应用需要使用 Android App Bundle 才能在 Google Play 中发布(Android ABB),在加上国内华为也支持了该ABB形式文件上架应用,后面也兴会成为主流。

关于相关的 Android App Bundle的知识可以点击这里🏷)

APK安装的方式

本章节只讲大致流程,代码流程我们后面再慢慢梳理

  • 安装方式
  • 1.系统应用和预制应用的安装
  • 2.通过商店
  • 3.Adb
  • 4.通过SD卡

🏷 科普

Android科普

安装目录的基本知识

既然是APK安装,有输入点就有输出点,所以就会有对应的目录,每个不同的目录存放这对应的文件。

目录 含义
/system/app 系统自带的应用程序,获得 root 权限才能删除
/data/app 第三方应用apk文件.安装时把apk文件复制到此目录
/data/anr 存放anr信息(/data/anr/traces.txt用于存放app ANR信息)
/data/data 应用程序数据
/data/data/${package_name} 特定应用程序数据目录
/data/data/${package_name}/cache 临时文件,系统会自动清理
/data/data/${package_name}/databases 数据库
/data/data/${package_name}/files 一般文件
/data/data/${package_name}/shared_pres SharedPreference
/data/data/${package_name}/lib so文件
/data/dalvik-cache 存放odex文件.将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,ART模式的可执行文件格式为.aot,启动ART时,系统会执行dex文件转换至aot文件)
/data/system/packages.list 类似于Window的注册表,该文件是解析apk时由writeLP()创建的。记录了系统的permissons,以及解析apk的AndroidManifest获取的应用name,codePath,flag,ts,version,userid等信息。解析完apk后将更新信息写入这个文件并保存到flash,下次开机的时候直接从里面读取相关信息并添加到内存相关列表中.当有apk升级,安装或删除时会更新这个文件。
/data/system/packages.xml 指定应用的默认存储位置/data/data/com.xx.xx/package.xml中包含了该应用申请的权限,签名和代码所在的位置等信息系,并且两者都有同一个userld.
/data/user/0 软链接,指向/data/data
/data/user_de/0/${package_name} 设备存储保护区,在快速启动模式可以访问这个文件夹
/proc/cpuinfo cpu信息
/proc/smaps 内存占用信息
/sdcard 软链接,最终指向/storage/emulated/0【跟Android版本和ROM版本有关】
/storage/emulated/0 外部存储的根目录
/storage/emulated/0/Android/data/${package_name} 应用的额外数据
/system/app 系统应用apk文件
/system/lib 系统应用so库
————————————————

在/data/data/包名目录下,每个app都有自己的目录,目录名就是应用程序在AndroidManifest.xml文件中定义的包。每个应用程序的代码,对自己的目录是有绝对的控制权限的。在每个目录下,一般有如下几个子目录(结合上面的表格):

databases : 存放数据库
cache : 存放缓存数据
files : 存放应用程序自己控制的文件
lib : 存放使用的包

Linux科普

为什么这里需要了解Linux的知识点,
Linux进程有两个ID,一个就是用户ID,为每个用户的唯一标识符;
另一个是组ID,为用户组的唯一标识符

当你在手机点击一个APK之后,APK中的AndroidManifest.xml会被解析,在手机root之后,或者用模拟器打开根目录 /data/system/ ,我们获得超级权限之后,可以在查看目前手机在系统已经注册的app,解析的内容会被存储到 /data/system/packages.xml/data/system/packages.list 中。我们打开packages.list和packages.xml,我们已Apk的包名为索引,可以看到对应的内容。

packages.list

1
com.game.dalan2.s3 10130 1 /data/user/0/com.game.dalan2.s3 default 3003

packages.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
<package name="com.game.dalan2.s3" codePath="/data/app/com.game.dalan2.s3-1" nativeLibraryPath="/data/app/com.game.dalan2.s3-1/lib" primaryCpuAbi="x86" publicFlags="940097350" privateFlags="0" ft="17b8267bd90" it="17b586694ad" ut="17b8267cb67" version="1" userId="10130">
<sigs count="1">
<cert index="9" key="忽略" />
</sigs>
<perms>
<item name="android.permission.MODIFY_AUDIO_SETTINGS" granted="true" flags="0" />
<item name="android.permission.CHANGE_NETWORK_STATE" granted="true" flags="0" />
<item name="android.permission.INTERNET" granted="true" flags="0" />
<item name="android.permission.ACCESS_NETWORK_STATE" granted="true" flags="0" />
<item name="android.permission.ACCESS_WIFI_STATE" granted="true" flags="0" />
</perms>
<proper-signing-keyset identifier="147" />
</package>

packages.list中指名了该应用默认存储的位置
packages.xml中包含了该应用申请的权限、签名和代码所在位置等信息,并且两者都有一个userId为10060。

之所以每个应用都有一个userId,是因为Android在系统设计上把每个应用当作Linux系统上的一个用户对待,这样就可以利用已有的Linux上用户管理机制来设计Android应用,比如应用目录,应用权限,应用进程管理等。

这个解析的过程也可以理解为在APK在系统的注册。

相关知识点可以查看这里 Stack Overflow

Apk安装的流程

这里大致只讲流程,详细的代码我们后面再一一罗列出来:
简单来说分为四步:

1)将APK的信息通过IO流的形式写入到PackageInstaller.Session中。

2)调用PackageInstaller.Session的commit方法,将APK的信息交由PKMS处理。

3)拷贝APK

4)最后进行安装

Android十万个为什么

什么是覆盖安装 ?

无论在国内还是出海国外上架海外游戏App,我们在每次上架新版本的时候,都是需要versionCode+1,用户再通过商店渠道再把 versioncode+1的apk覆盖掉原先的apk,这个过程就是覆盖安装,。
不过还是有前置条件:
1.包名跟旧的一致
2.签名跟原来的一致
3.组件不冲突

更详细的内容看这张表:

正常安装 覆盖安装 DES MORE
删除旧版本APK之后重新进行安装 (不删除之前的旧版本包,直接安装)
SQLite的数据也会被删除 SQLite的数据不会丢失
shared_prefs中的数据会被删除 shared_prefs中的数据不会丢失
4.4之前的版本不会比较apk的Version_code

部分手机在APK安装成功后提示清除安装包,要清除安装包的是在哪里?

首先要清除对应的安装包,就得知道安装包的目录是在哪,计算机的世界有入口就有出口。
我们这里在做一些知识的扩展:
现在部分手机的App是具有分享Apk的功能,也就是传输本机上的apk,比如说QQ,还有一些第三方的软件具备之类的功能。手机安装app时,会在根目录和外存储器合生成文件夹。反过来说,你删除app的时候,这些对应生成文件夹也会被系统删除。根目录会放置app的安装包,而且统一命名为base.apk,还有一些重要的app用户数据。(你想查看,前提是开启root)
外存储器就是你能看到的文件夹,里面放置可操作的文件,例如保存的图片,视频。所以即使你安装app后删除安装包,也是删除了外存储器的安装包,QQ传输app安装包就是传输根目录的安装包。

Android目录扫盲

关于存储的目录,我们后面额外再开一张新的文章,android对于目录和权限其实做了不少的修改。
接下来这段是很多Code的误区

1
Environment.getExternalStorageDirectory()

实际上是获取的手机自带的sd卡,这个自带的sd卡你在手机的文件管理应用里看,显示的中文名是“内部存储”,这个“内部存储”实际上就是手机自带的sd卡,也就是ExternalStorage