• 作者:老汪软件技巧
  • 发表时间: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 通信。