包管理器
包管理器 (Package Manager) 是实际管理应用安装、移除和更新的 API。
APK 安装过程
Android 应用安装过程如下:

当您安装 APK 文件时,包管理器解析 APK 并显示确认信息。当您按下"确定"按钮时,包管理器调用
PackageInstaller
进行交互式安装包。PackageInstaller 提供用户界面来管理包。PackageInstaller 调用
InstallAppProgress
活动来接收来自用户的指令。InstallAppProgress 请求
包管理器服务
安装包。包管理器服务使用
installd
守护进程安装包,该进程通过/dev/socket/installd
套接字接收请求,并以 root 权限执行一系列步骤来安装 APK。整个安装过程如下:将包添加到安装队列。
确定包安装的适当位置(系统应用为
/system/app/
,第三方应用为/data/app/
)。将 APK 复制到给定目录。
确定应用的 UID。
请求
installd
守护进程。在
/data/data/
中创建应用目录并设置权限。将 DEX 代码提取到缓存目录
/data/dalvik-cache/
。更新
packages.list
和packages.xml
文件。使用
Intent.ACTION_PACKAGE_ADDED
或Intent.ACTION_PACKAGE_REPLACED
向系统广播
应用安装成功。
数据存储
包管理器将应用信息存储在位于 /data/system
的三个文件中:
packages.xml
包含权限和包列表:packages.list
是一个简单的文本文件,包含包名、用户 ID、标志和数据目录。packages-stoped.xml
包含具有停止状态的包列表(停止状态的应用无法接收任何广播)。
packages.list
packages.list
文件为系统上安装的所有应用包含类似这样的内容:
com.android.packageinstaller 10025 0 /data/data/com.android.packageinstaller platform 1028,3003,2001
该行分为 6 列,包含关于应用的信息:
com.android.packageinstaller
是应用的包名,它是AndroidManifest.xml
中<manifest>
元素的package
属性的内容。10025
是应用使用的userId
;如果在AndroidManifext.xml
中未指定android:sharedUserId
属性,系统将自动为应用分配一个userId
。0
表示应用是否处于调试模式,由AndroidManifext.xml
中的android:debuggable
指定。/data/data/com.android.packageinstaller
是应用的数据存储路径,通常是一个像/data/data/<package_name>
的文件夹。platform
是应用的seinfo
信息;这应该与 SEAndroid 机制相关(不太清楚,其值似乎有platform
和default
)。1028,3003,2001
是应用所属的用户组;如果应用不属于任何组,这里的值是None
。
packages.xml
packages.xml
文件具有以下结构:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<packages>
<version ... />
<version ... />
<permissions>
<item name="xxxx" package="xxx" protection="xx" />
... ...
</permissions>
<package xxx>
...
</package>
...
<shared-user xxx>
...
</shared-user>
...
<keyset-settings version="1">
...
</keyset-settings>
</packages>
packages.xml
文件中的主要信息分为以下部分:
权限块包含系统中所有定义的权限信息。
包块包含系统中所有已安装应用的详细信息。
共享用户块包含所有系统定义的共享用户信息。
密钥集设置块包含已安装应用签名的公钥信息。
权限块
<permissions>
<item name="android.permission.REAL_GET_TASKS" package="android" protection="18" />
<item name="android.permission.REMOTE_AUDIO_PLAYBACK" package="android" protection="2" />
...
</permissions>
它定义了系统中所有声明的权限信息,每个项目块代表一个权限:
Name 表示权限的名称。
Package 表示声明权限的包
Protection 表示权限的级别,如 normal、dangerous 等。
包块
包块包含每个应用的详细信息。
<package name="com.tencent.qqmusictv" codePath="/data/app/qqmusictv" nativeLibraryPath="/data/app/qqmusictv/lib" primaryCpuAbi="armeabi" publicFlags="941112933" privateFlags="0" ft="15f00a383c8" it="15f00a383c8" ut="15f00a383c8" version="134" userId="10044">
<sigs count="1">
<cert index="6" key="30820247308201b0a003020..." />
</sigs>
<perms>
<item name="android.permission.WRITE_SETTINGS" granted="true" flags="0" />
...
</perms>
<proper-signing-keyset identifier="7" />
</package>
<package>
元素的属性:
name 表示包名。
codePath 表示此 APK 文件存储的位置。
nativeLibraryPath 表示应用使用的
xxx.so
库的位置。primaryCpuAbi 表示应用运行在哪个 abi 架构上。
publicFlags 和 privateFlags 是根据
AndroidManifest.xml
中的设置生成的,例如:android:multiarch
。ft 表示 APK 文件最后更改的时间。
it 表示应用首次安装的时间。
ut 表示应用最后更新的时间。
version 是关于应用版本号的信息,是
AndroidManifest.xml
中配置的android:versionCode
。userId 是分配给应用的用户 ID;如果有
shareUserId
,则SharedUserId
出现在这里。
<sigs>
元素的属性:
count 表示应用有多少个签名(某些应用可能由多个证书签名)。
<cert>
元素的属性:
index 表示应用使用的证书的序列号;当系统发现新证书时,数字将增加 1。
key 是应用使用的证书内容的 ASCII 码值;如果包管理器服务在扫描 APK 时检测到使用了先前已知的证书,则
key
值将不存在;具有相同索引的包,表示它们使用相同的签名。
<perms>
块是应用拥有的权限。对于普通应用,这些权限写在 AndroidManifest.xml
中。对于那些使用相同 userId
的应用,这里的权限是所有使用相同 userId
的应用的权限总和。granted
表示是否已允许此权限。
<proper-signing-keyset>
的 identifier
属性是密钥集中标识符的值。它用于指示应用使用哪个公钥。
共享用户块
<shared-user name="android.uid.system" userId="1000">
<sigs count="1">
<cert index="1" />
</sigs>
<perms>
<item name="android.permission.REAL_GET_TASKS" granted="true" flags="0" />
<item name="android.permission.ACCESS_CACHE_FILESYSTEM" granted="true" flags="0" />
... ...
<item name="android.permission.DELETE_PACKAGES" granted="true" flags="0" />
</perms>
</shared-user>
<shared-user>
元素的属性:
name 表示此共享用户的名称。
userId 表示系统中用户的编号。
<sigs>
元素的含义在这里和包块中相同。
<perms>
表示此用户拥有的权限。在启动时扫描 APK 文件时,所有使用相同 userId
的应用的权限被收集并放置在这里。最后,这些权限将被发送到那些使用相同 userId
的应用。最终结果是系统中具有相同 userId
的应用具有相同的权限。
密钥集设置块
<keyset-settings version="1">
<keys>
<public-key identifier="1" value="MIIBIjANBgkqhki..." />
...
</keys>
<keysets>
<keyset identifier="1">
<key-id identifier="1" />
</keyset>
...
</keysets>
<lastIssuedKeyId value="9" />
<lastIssuedKeySetId value="9" />
</keyset-settings>
<keyset-settings>
块收集所有应用签名的公钥信息,并与包块中的信息相关联。<keys>
块中<public-key>
的value
属性的值是从 APK 包中的签名文件中提取的公钥。<keysets>
块包含许多密钥集。每个密钥集都有一个带标识符的数字。<key-id>
的identifier
属性对应于上面<keys>
中<public-key>
标识符的值。lastIssuedKeyId
和lastIssuedKeySetId
表示最新公钥被取到的集合编号。
参考资料
最后更新于