- 作者:老汪软件技巧
- 发表时间:2024-08-31 00:02
- 浏览量:
Android Framework 包管理主要体现在以下几个部分:
1、系统启动过程中 PKMS(PackageManagerService) 对系统配置文件进行读取,如 packages.xml 文件等,然后对外提供 APP 信息查询接口(IPackageManager);
2、提供 apk/apex 的安装、更新、卸载等操作 api 接口(IPackageInstaller),apex 是谷歌提供的类似 apk 的系统更新模块;
3、应用运行过程中对系统权限的检查;
Android Framework 包管理框架大体如下图:
应用层
应用层需要获取某个安装包的信息或者安装应用时,需要获取 PKMS 的实例,PKMS 是在系统启动的时候注册到 ServiceManager 中,应用通过 Context 的 getPackageManager 接口获取 PKMS 实例,实际返回的是一个 ApplicationPackageManager 对象,它实现了 PackageManager 抽象接口,并且内部有个远程接口 IPackageManager 的代理对象 mPM,通过这个对象可以访问 PKMS 层的接口;
mPM 有个方法 getPackageInstaller 可以返回远程接口 IPackageInstaller 的代理对象 PackageInstallerService,此对象可以用于应用的安装、卸载、更新等操作。
PKMS 服务层
PKMS 是在 SystemServer 进程启动过程中启动的,它还初始化了一个 PackageInstallerService 服务,用于应用的安装、卸载、更新等操作,这些操作最终是通过 binder 和系统层的 installd 系统服务进行通信,PKMS 可以被应用层调用,获得应用的信息,其内部有三个文件目录保存相关包管理信息:
PKMS 启动的时候会从这三个文件目录中解析相关的 XML 文件,从而建立庞大的信息树,应用程序可以间接的从这个信息树中查询所需的程序包信息;
1、/data/system/packages.list
用于记录系统中所有应用的一些基本信息,包括应用名称、uid、gid、数据存放路径等信息,
com.android.tvsettings 1000 0 /data/user/0/com.android.tvsettings platform:privapp:targetSdkVersion=22 2001,1077,1065,3002,3003,3001,3007,1007 0 28
com.android.providers.tv 10007 0 /data/user/0/com.android.providers.tv default:privapp:targetSdkVersion=30 none 0 30
2、/system/etc/permissions
该目录下的文件主要用于权限的管理,包含两件事:
3、/data/system/packages.xml
此文件记录了系统的所有权限信息,所有安装应用的基本信息,所有 sharedUserId 信息以及应用打包时的签名信息等:
'1.0' encoding='utf-8' standalone='yes' ?>
// 存储了当前设备的基本信息:包括 SDK 版本,database 版本,以及指纹等信息
<version sdkVersion="30" databaseVersion="3" fingerprint="EPSON/sti6291d101/sti6291d101:11/RD2A.211001.1020/2.1.20231113.1020:userdebug/release-keys" />
<version volumeUuid="primary_physical" sdkVersion="30" databaseVersion="3" fingerprint="EPSON/sti6291d101/sti6291d101:11/RD2A.211001.1020/2.1.20231113.1020:userdebug/release-keys" />
// 代表了一组权限信息
<permission-trees />
// 表示系统中所有的权限信息,package:该权限归属于某个应用,
// android 表示归属系统,protection:当前权限的级别,如 normal 或 dangerous 等
<permissions>
<item name="com.android.permission.WHITELIST_BLUETOOTH_DEVICE" package="com.android.bluetooth" protection="2" />
<item name="android.permission.BLUETOOTH" package="android" />
<item name="android.permission.BLUETOOTH_PRIVILEGED" package="android" protection="18" />
permissions>
// 表示应用信息,name:包名;codePath:代码放置的路径;
// nativeLibraryPath:APK 的 so 库存放路径;
// primaryCpuAbi:app 以哪种 abi 架构运行,是 armabi 还是 armabi-v7a、x86等;
// ft:apk 文件上次被更改的时间;it:app 第一次安装的时间;
// ut:app 上次被更新时间,它的值好像一直和 ft 相同, ota 或 app 重装之后,
// 这里的 ft 和 ut 可能会改变;
// version:版本号,也就是 versioncode 信息;
// userId:为 app 分配的 user id, 如果有使用 sharedUserId,
// 这里出现的是 sharedUserId;
<package name="com.android.tvsettings" codePath="/system/priv-app/Viewlib" nativeLibraryPath="/system/priv-app/Viewlib/lib" primaryCpuAbi="armeabi" publicFlags="805879365" privateFlags="-1940910072" ft="11e8f7d4c00" it="11e8f7d4c00" ut="11e8f7d4c00" version="28" sharedUserId="1000" isOrphaned="true">
// 签名信息,count:app 有多少个签名信息;
// cert:index 表示 app 使用的证书的序号,
// key 是 app 使用的证书内容的 ascii 码值;
<sigs count="1" schemeVersion="3">
<cert index="0" key="..." />
sigs>
// 当前 app 申请的权限信息
<perms>
<item name="android.permission.BLUETOOTH" granted="true" flags="0" />
<item name="android.permission.INTERNET" granted="true" flags="0" />
<item name="com.ktcp.launcher.provider" granted="true" flags="0" />
perms>
// 应用使用的公钥信息的 ID,对应下面的 keysets 节点中的公钥信息
<proper-signing-keyset identifier="2" />
package>
// 表示一个 shared user 的属性信息,声明了相同 sharedUserId 应用得到 userId 是固定一样的
<shared-user name="android.uid.system" userId="1000">
<sigs count="1" schemeVersion="3">
<cert index="0" />
sigs>
<perms>
<item name="android.permission.BLUETOOTH" granted="true" flags="0" />
<item name="android.permission.INTERNET" granted="true" flags="0" />
<item name="com.ktcp.launcher.provider" granted="true" flags="0" />
perms>
shared-user>
// 所有应用对应的公钥信息
<keyset-settings version="1">
<keys>
// value:从 apk 包里的签名文件里提取出来的公钥的值
<public-key identifier="1" value="MIIBIDANBgkqhkiG9w0BAQE..." />
keys>
// keysets 中包含了很多 keyset, 每个 keyset 都有一个编号用 identifier 表示
<keysets>
<keyset identifier="1">
// key-id 里的 identifier 和上面 keys 中 public-key 的 identifier 的值相对应
<key-id identifier="1" />
keyset>
keysets>
// 最近一次使用的公钥编号
<lastIssuedKeyId value="17" />
<lastIssuedKeySetId value="17" />
keyset-settings>
从文件中可以看出每个节点会有多个相同节点,说明这些节点并不是唯一的,所以写入到内存中也是一个集合的形式存在,可以看到 packages.xml 文件在系统启动过程中起着一个非常重要的作用,主要体现在对应用清单配置以及应用的权限把控方面;
文件系统层
除了前面提到的系统包配置文件,还有应用安装的文件系统,包括第三方应用以及系统应用。所有的系统应用保存在 /system/app 目录下,所有的第三方应用保存在 /data/app 目录下。
/data/dalvik-cache 目录保存程序执行代码,当 Android 启动时,Dalvik VM 监视所有的程序(APK 文件)和框架,并且为他们创建一个依存关系树,Dalvik VM 通过这个依存关系树为每个程序优化代码并存储在 Dalvik 缓存中,这样所有程序在运行时都会使用优化过的代码。
/data/data 是应用的私有目录,其他应用对此是没有访问权限的,/sdcard/Android/data 属于应用的外部存储目录。
/system/framework 存储了系统运行的各种 jar 包,framework-res.apk 则存储了 framework 需要的各种资源文件。
installd 系统服务层
installd 系统服务主要用来运行 APK 的安装和卸载、dex 优化等工作,PKMS 收到应用安装任务时,会把最终任务提交给 installd 进行处理。
installd 进程拥有 root 权限,而 PKMS 只拥有系统权限,installd 进程在 6.0 之前使用 Socket 通信,之后使用 Binder 通信。