Android程序包管理机制解析和PMS启动流程分析

程序包管理包含三个部分内容:

  • 提供一个能够根据intent匹配到具体的Activity、Provider、Service。即当应用程序调用startActivity(intent)时,能够把参数中指定的intent转换成一个具体的包含了程序包名称及具体Componment名称的信息,以便Java类加载器加载具体的Componment。

  • 进行权限检查。即当应用程序调用某个需要一定权限的函数时,系统判断调用者是否具备该权限,从而保证系统的安全。

  • 提供安装、删除应用程序的接口

一、包管理概述:

该框架分为三层,分别为程序应用层、Pms服务层及数据文件层

  1. 应用程序层

​ 应用程序需要使用包管理服务时,调用ContextImpl类的getPackageManager()函数返回一个 ApplicationPackageManager对象,它继承自PackageManager抽象类,参数传入Pms,Apm类调用各种pms的类方法。

  1. Pms服务层

    和Ams、Wms等其他系统服务一样,包管理服务运行于SystemServer进程。Pms服务运行时,使用如下

    xml文件保存相关的包管理信息。

​ 第一个目录是“/system/etc/permissions”,该目录所有文件用于pemission的管理,包括两件事情,一是定义系统中都包含哪些user-permission,应用可以在androidManifest.xml中使用。二是该目录还定义了一个platform.xml文件,为一些特别的uid和gid分配一些默认权限。

​ 第二个目录是“/data/system/packages.xml",该文件保存了所有安装程序的基本包信息,有点像系统的注册表,比如包名称、安装包路径和程序使用了哪些系统权限等等。看下packages.xml的内部信息

<packages>
    <last-platform-version internal="19" external="19" />
    <permission-trees />
    <permissions>
        <item name="android.permission.CHANGE_WIFI_MULTICAST_STATE" package="android" protection="1" />
        <item name="android.permission.WRITE_CALL_LOG" package="android" protection="1" />
        <item name="android.permission.CLEAR_APP_CACHE" package="android" protection="1" />
        <item name="android.permission.AUTHENTICATE_ACCOUNTS" package="android" protection="1" />
        <item name="android.permission.ACCESS_WIMAX_STATE" package="android" />
        <item name="android.permission.ASEC_ACCESS" package="android" protection="2" />
        ....
             <item name="android.permission.VIBRATE" package="android" />
        <item name="android.permission.READ_CELL_BROADCASTS" package="android" protection="1" />
    </permissions>
    <package name="com.myapp" codePath="/data/app/com.myapp-2.apk" nativeLibraryPath="/data/app-lib/com.myapp-2" flags="4767302" ft="15e3b437430" it="15e37659f09" ut="15e3b4378f4" version="1" userId="10043">
        <sigs count="1">
            <cert index="0" key="308201dd30820146020101300d06092a864886f70d010105050030373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b3009060355040613025553301e170d3137303833313...7d6c66ce" />
        </sigs>
        <perms />
        <signing-keyset identifier="1" />
    </package>

<last-platform-version>:internal是内部存储区程序被更新前的系统版本号,external是外部存储区程序更新前的系统版本号,两者一般相同。

<permissions>:保存系统所有的权限列表,包括name、package、protection

<sigs>: 签名信息

<perms>应用程序申请的权限列表

<package> 包括一个程序包相关的信息,如程序名称、程序包路径、程序使用native库文件路径、等

  1. 数据文件层

​ Android程序由相关的程序文件组成,这些程序文件可以分为三个部分。

  • 程序文件,所有系统程序保存在/system/app下,所有第三方应用程序保存在/data/app目录下,对于非系统程序,安装前可以放在任意地方,但安装后,Pms会把APK文件放到/data/app目录下,并且文件名称以包名进行命名。/data/davik-cache目录下保存了程序执行代码,当程序运行前,Pms会从APK文件中提取出代码文件也就是dex文件,并将该文件存储在该目录下,以便以后能快速运行该程序。

  • framework库文件,这些文件保存在/system/framework目录下,系统开机时davik虚拟机会加载这些库文件,在pms启动时,将这些文件转换成dex文件,并保存到/data/dalvik-cache目录下。

  • 应用程序使用的数据文件。分别为sharepreference存储、数据库存储和文件存储,前两种文件一般会保存在/data/data/xxx/目录下,xxx代表程序包名,文件存储可以保存在内置存储或者外置存储的任意位置。

二、包管理服务的启动过程

当SystemServer进程启动时,其初始化函数中会启动各种具体的服务进程,包括Ams、Wms和Pms等,Pms服务是从静态函数中创建的

public static PackageManagerService main(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) {
    // Self-check for initial settings.
    PackageManagerServiceCompilerMapping.checkProperties();

    PackageManagerService m = new PackageManagerService(context, installer,
            factoryTest, onlyCore);
    m.enableSystemUserPackages();
    ServiceManager.addService("package", m);
    return m;
}

main()函数创建一个pms的实例,然后添加到serviceManager中,应用程序可以使用Context类的getSystemService()获取pms服务的Binder接口,并调用pms所提供相应的服务。

pms实际的启动过程就是该类构造函数的各种初始化的过程,在介绍流程之前,需要先理解各主要功能之间的关系,因为启动过程实际上就是读取相关XML文件的信息,并把这些信息存放到相关的类成员变量之中。

Settings类作为包管理服务相关的主要类,基本上包含了包管理所需的全部信息,该类主要包含几类变量:

  • File mSettingFilename:配置文件名称,指的就是packages.xml

  • File mBackupSettingFilename:配置文件有一个backup文件,该文件用于系统意外关机后和原始配置文件进行对比,以检查系统的完整性。

  • File mPackageListFilename:指的就是packages.list文件,保存了所有应用程序列表

com.android.provision 1000 0 /data/data/com.android.provision platform 1028,1015,3002,3001,1023,3003
com.android.providers.media 10004 0 /data/data/com.android.providers.media media 1028,1015,1023,1024,2001,3003,3007
com.android.pacprocessor 10029 0 /data/data/com.android.pacprocessor platform 3003
com.maxtropy.android.doublepad 10097 1 /data/data/com.maxtropy.android.doublepad default 3002,3001,3003,1028,1015

第一项表示应用程序包名称,第二项表示该应用程序Linux用户id,第三项数字1表示应用程序可以被debug,0表示不能被debug,第四项表示应用程序数据文件目录

  • HashMap<String,PackageSetting> mPackages:在Pms启动后,该变量被填充为包管理信息,这些信息来源于package.xml。注意该变量和pms中定义的mPakcages变量的区别,前者是从package,xml读取的记录信息,而后者是直接扫描程序目录下所有的APK文件生成的,后者类型是packageParser.Package。

  • HashMap<String,PackageSetting> mDisabledPackages:记录不是通过标准卸载方法删除的应用程序列表。

  • ArrayList<Signature> mPastSignatures:保存所有的签名

  • ArrayMap<String, BasePermission> mPermissions :保存了所有的权限

Pms类中重要变量

  • ArrayMap<String, PackageParser.Package> mPackages :保存所有程序包信息,来源于扫描程序目录下所有程序文件

  • final Settings mSettings:Settings类

  • final SparseArray<ArraySet<String>> mSystemPermissions:系统所有的权限名称

  • final ActivityIntentResolver mReceivers

  • final ServiceIntentResolver mServices;

  • final ProviderIntentResolver mProviders

  • final ActivityIntentResolver mActivities

    以上四个变量用于进行Intent-Filter的匹配,并分别匹配到Activity、Receiver、Service、Providers对象,在pms初始化时会遍历程序目录下的全部程序,并从其包含的AndroidManifest.xml文件中提取出所有的intent-filter数据,并将其保存到以上的四个变量中,系统运行时,应用程序调用PackageManager的queryIntentxxx()函数时,其内部就是通过以上四个变量查询相关的目标对象信息的。

    三、PMS主体启动流程
  • 创建一个Settings对象,在该对象的构造函数时,给成员变量赋值

     Settings(File dataDir, Object lock) {
            mSettingsFilename = new File(mSystemDir, "packages.xml");
            mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
            mPackageListFilename = new File(mSystemDir, "packages.list");
            FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);
    
            final File kernelDir = new File("/config/sdcardfs");
            mKernelMappingFilename = kernelDir.exists() ? kernelDir : null;
    
            // Deprecated: Needed for migration
            mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
            mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
        }
  • 调用readPermission()函数,从/system/stc/permissions目录下读取全部的XML文件,该文件包含了系统中的所有的permission,这些属性值会保存在mSettings.mPermission中。

  • 调用mSettings.readLP()函数从/data/system/package.xml文件中所有应用程序中和包管理相关信息。这些信息将保存到mSetting.mPackages变量中。

  • 对java系统中的库文件进行dex转换,保存到davilk-cache目录中。

  • 调用scanDirLi扫描解析AndroidManifest.xml的所有应用程序文件,并将扫描结果保存到pms的mPackages变量中。

  • 为系统程序、framework程序和第三方程序目录创建FileObserver,它会检测目录中添加删除文件的事件,调用scanPackageLi()函数。

  • 调用scanPackageLI()函数,对所有的程序包进行扫描。第一是解析安装包中的AndroidManifest.xml文件,提取出其中包含的intent-filter信息和permission信息,保存到mActivites、mServices、mReceivers和mProvider列表中,第二是将安装包中的dex文件提取出来。

四、应用程序的安装和卸载

安装及卸载程序操作都是由Pms完成,安装程序的过程包括在程序目录下创建以包名称命名的程序文件、创建程序数据目录,以及把程序信息保存到相关的配置文件packages.xml中,卸载过程是相反的操作。

各主要功能类关系

HandlerParams是一个abstract类,该类有两个实现,分别是InstallParams和MoveParams。HandlerParams虚基类作用是进行程序文件的复制,比如安装一个hello.apk文件后,会将该apk文件复制到程序目录/data/app中,复制后文件名称为包名称。

InstallParams实现安装过程的复制,MoveParams实现移动的复制,比如讲安装好的程序从内部存储位置移动到外部存储位置。

1、应用程序的安装过程

应用程序首先调用PackageManager类的installPackage()函数开始,该函数间接调用Pms的installPackage()函数,安装时异步的,installPackage()函数内部发布一个异步消息,名称为INIT_COPY,进行文件复制。程序安装 对象是InstallParams,调用startCopy函数进行程序的复制,复制成功后会在data/app目录下多一个以包命名的APK文件。

程序安装的下一阶段是将APK中包含的包信息提取出来存放在packages.xml文件及mSetting.mPackages对象中。这个过程和Pms在启动时调用scanDirLI()过程相似。

2、应用程序的卸载过程

PackageManager中提供了deletePackage()函数用于卸载程序,该函数通过IPC调用到Pms的deletePackage()函数,继而调用到deletePackageX()。

调用deletePackageLI()开始删除程序

  • 删除程序文件,即/data/app目录下的APK文件

  • 删除Pms中的mSetting.mPackages变量及mPackages变量,以及其他相关变量中的关于该程序的包管理信息。

  • 发送一个广播消息,内容可能是删除,也可能是程序升级。

  • 删除程序文件本身,以及在davik-cache下的dex文件。

3、intent匹配框架

intent匹配主要是解决应用程序中没有明确指定Componment名称的情况,Pms在初始化时,会从所有应用程序的AndroidManifest.xml文件中读取Intent-filter的值,建立一个内部数据结构,通过PackageManager提供的queryXXX()分别查询不同的Componment的包信息。

以Actviity为例,Pms内部类ActivityIntentResolver的基类是IntentResolver,在Pms启动时调用scanDirLI函数,填充所有的Activity的intent-filter信息

intent匹配机制:

按照基本的匹配类型定义几个数据变量,比如action、scheme、mime等,每个数据变量保存所有只要满足本条件的Component信息,其结果是不同的变量中会包含相同的Component信息,当传入一个intent时,先将intent分解成这些基本的匹配条件,然后逐个用这些字段合前面的数据变量进行匹配,并最终找到不同数据变量匹配结果的交集,及为满足的component信息。

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值