PackageManagerService类作用分析

程序包管理

程序包管理主要有三个内容:

  • 提供一个能够根据intent匹配到具体的Activity、Provider、Service。即可以把intent转化为可以被java类加载器识别的Component

  • 进行权限检查

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

    以上三个功能主要在PackageManagerService类中。以后简称PMS。

包管理概述

​ 框架可以分成三层,是应用程序层、PMS服务层、数据文件层

应用程序层

  • 通过contextImpl.getPackageManager()获取,饭后PackageManager对象。

PMS服务层

  • 和AMS、WMS一样运行在SystemServer进程。PMS运行时,使用了两个目录下的XML文件保存相关包管理信息
  • 第一个目录用于permission的管理,定义了系统中的所有权限。位于/system/etc/permissions
  • 第二个目录用于保存所有按照程序的基本信息,程序使用了那些系统权限等,类似于系统的注册表
  • PMS启动时候,会从这两个目录中解析相关的XML文件信息,建立信息树。应用程序可以从这个信息树中查询所有需要的程序包信息。

数据文件层

一般分为三个部分

  • 程序文件,所有系统程序保存在/system/app目录下,所有的第三方程序保存在/data/app目录下。安装时候会把apk包移动到data/app目录下,并且按照包名命名,如com.android.hello.android-1.apk当在此安装时候,数字1会变为2,再安装有变回1,有点像乒乓机制。
  • framework库文件。文件存放于、system/framework目录下。库文件类型是apk或者jar。系统开机后,虚拟机会加载这些库文件。在PMS启动时候,这写还没被转化为dex文件,则PMS会把它们转为dex文件,并存到/data/dalvik-cache目录下
  • 应用程序使用的数据文件。应用程序一般用三种存储方式:参数存储、数据库存储、文件存储。这些文件一般保存在/data/data/xxx目录下,xxx代表包名。

packages.xml文件格式

last-platform-version标签

记录了系统最后一次的版八号,一般和相应的SDK版八号相同。

permissions标签

保存了系统中所有权限列表,包括framework定义的权限以及应用程序自定义的权限

  • name:权限名称,系统权限一般用andorid.permission开头,应用程序一般包名开头。权限名称必须全局唯一
  • package:权限所在的包名,Framework对应的包名为android
  • protection:保护等级,分别为普通、危险、签名、签名或系统。

cert标签

cert代表certifacation,即“证书”,一个应用程序一般只包含一个证书。cert包含两个属性,分别是index和key

  • index:在PMS中保存了所用证书,每个证书对应一个索引,index表示的就是索引。
  • key:该属性不是必须的,如果index已存在,key可以没有。而如果index是首次出现,则key的值必须指定,值为2390个16进制值,来源于对apk进行签名的证书文件。

sigs标签

即signature,签名。一个应用程序只能有一个签名,一个签名可以包含多个证书。签名标签有一个属性count,即该签名中包含多少个证书,sigs标签中必须包含count个cert子标签。用来表示具体的证书。

perms标签

即permission,权限。一个应用程序可以申请多个权限,perms标签中包含了所有的权限列表。和permissions不同,这个表示的是一个应用程序需要的权限。那个表示的是整个系统中所有的权限。

package标签

该标签包含了一个应用程序包的相关信息,package的标签属性包括如下几种:

  • name:程序包名
  • codePath:程序包所在路径,比如/system/app/Mms.apk/data/app/com.hallo.android.Test-a.apk
  • nativeLibraryPath:该程序使用的native库文件路径。一般情况下native库文件会被安装到程序数据文件路径下的lib子目录中,比如/data/data/com.hello.android.Test/lib
  • flags:用于标识应用程序类型,类型在Application.java中定义,包括FLAG_SYSTEM、FLAG_DEBUGGABLE、FLAG_PERSISTENT等
  • it、ut:分别代表"首次安装时间 install time"和"最后升级时间update time"
  • ft、ts:含义相同,代表最后一次修改该记录的时间,一般情况下,这个时间等于ut标签值
  • installStatus属性:仅在packages-backup.xml文件中存在,值一般为false,当值为true是,该属性一般不会再写到该文件中
  • userId、sharedUserId:应用程序对应的linux用户id值、应用程序共享的Linux用户id。这两个属性互斥
  • installer:安装器名称。一般指应用程序调用PackageManager的installPackage()函数时,参数installPackageName的值。

shared-user标签

系统为每一个应用程序分配了一个Linux用户ID,一些native进程的用户id从1000开始,比如shell进程、log进程、Phone进程等。java应用程序对应的用户id从10000开始。从用户角度讲,一个应用程序实际上就是一个用户id。

share-user标签定义了共享用户id对应的签名和权限,他和package标签的含义本质是相同的。share-user的属性包括nameuserId,其意义和package标签的属性相同,包含的子标签也和package相同,包括sigsperms标签。

包管理服务启动过程

PMS本身是一个Service,他与WMS、AMS等重要的系统服务运行在同一个进程——系统进程中。当SystemService启动时候,它也会启动,启动方法如以下代码所示:

public static final IPackageManager main(Context context,boolean factoryTest){
    PackageManagerService m = new packageManagerService(Context,factoryTest);
    ServiceManager.addService("package",m);
    return m;
}

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

各主要功能类的关系

包管理服务相关的主要类,作为PMS的内部类被定义。PMS的内部类Settings基本上包含了所有包管理所需的全部信息,主要包含几类变量:

  • 包属性信息
    • File mSettingsFilename:配置文件名称,指的就是packages.xml文件
    • File mBackupSettingFilename:配置文件可以有一个backup文件,该backup文件用于系统意外关机后原始配置文件进行对比,以检查系统的完整性。
    • File mPackageListFilename:指的就是packages.list文件,保存了所有应用程序列表,该文件中每一行对应一个应用程序
    • Hashmap mPackages:在PSM启动后,改变量被填充为包管理信息,这些信息来源于packages.xml
  • 用户ID相关信息
    • HashMap mSharedUsers:改变量保存了所有共享id的信息,来源于packages.xml中的shared-user标签
    • ArrayList mUserIds:所用用户ID
    • 权限管理相关信息
      • ArrayList mPastSignatures:保存了所有的签名
      • HashMap mPermissions:保存了所有的权限,该Map是从permission名称到permission信息的一个映射。
      • HashMap mPermissionTrees:对应packages.xml文件中的permission-tree标签,目前一直为空,没有被使用。
    • 删除信息
      • ArrayList mPackagesToBeCleaned:保存的是packages.xml中的cleaning-package标签中包含的package列表,该列表来源胡那些已经被卸载的应用程序。但其所办函的数据目录处于外部存储器而没有被删除。
    • PMS主体启动过程

      • 创建一个PMS.Settings,在该对象的构造函数中,将给裁员变量静态赋值
      • 调用mSettings.addSharedUserLP()添加四个共享用户ID
      • 创建一个Installer对象,该对象将辅助程序的安装。
      • 给以下几个数据文件路径静态赋值:
        • mAppDataDir,代表程序的数据目录,其值为/data/data
        • mSecureAppDataDir,所谓的解密数据区,目前无用,路径为/data/secure/data
        • mDrmAppPrivateInstallDir,所谓的DRM数据区,目前无用,路径为/data/app-private
      • 调用readPermission()函数,从/system/etc/permissions目录下读取全部的xml文件
      • 调用mSettings对象的readLP()函数从/data/system/packages.xml文件中读取所有应用程序中和包管理相关的信息,将其保存到mSettings.mPackages变量中。
      • 对java系统中的库文件进行dex提取(转换)
      • 创建FileObserver,用来检测目录中的添加、删除文件的时间,并当时间发生时执行相应的操作
      • 调用scanDirLI()扫描AndroidManifest文件,并将扫描结果保存到PMS中。
      • 删除已经不存在程序对应的数据记录。
      • 清除没有安装成功的数据记录
      • 调用deleteTempPackageFiles()删除/data/app目录下,一vmdl开头的.tmp结尾的文件
      • 如果系统升级,调用updatePermissionsLP()重新为应用程序赋予权限。
      • 调用mSettings.writeLP()mSettings.mPackages中的数据值重新写入packages.xml文件中

      readPermission()内部过程

      • 确保/system/etc/permissions目录的存在
      • 使用循环,读取该目录下每一个XML文件,并调用readPermissionFromXml()函数逐个解析。
      • 最后解析platform.xml文件

      mSettings.readLP()

      该函数会读取所有的安装包信息,主要读取的是packages.xml文件,读取过程可以分为以下几个步骤:

      • 判断backup文件是否存在,如果存在说明出现异常,那么进行错误记录,并删除pacages.xml文件,然后从backup文件中读取相关的包管理信息。
      • 解析xml文件中包含的各种标签。
      • 处理mPendingPackages列表中对应的包信息

      scanPackageLI()内部过程

      对程序包进行扫描,并知心程序的安装过程

      • 把原始的APK文件复制到相应的程序目录下,
      • 为程序创建相应的数据目录及提取dex文件,并修改程序包管理信息等。

      mSettings.writeLP()

      该函数作用失败mSettings.writeLP()的数据分别写入packages.xmlpackages.list文件中

      应用程序的安装和卸载

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

      应用程序安装过程

      • 调用PackageManager类的installPackage()函数开始,该函数间接调用PMSinstallPackage()函数。
      • 发送异步消息,启动文件复制流程,安装过程首先就是文件复制的过程
      • 文件复制是调用handleStartCopy()函数完成的,下面开一下具体的实现
        • 检查flags标识,确保参数没有冲突,比如不能同时安装到SD卡和内部存储中
        • pacageURIflags为参数,调用MCS服务的getMinimalPackageInfo(),询问MDS服务是否能够安装packageURI指定的程序。
        • 如果MCS认为可以安装packageURI指定的程序,则回调installLocationPolicy()
        • 调用InstallArgs类的coypApk()函数进行文件复制

      应用程序卸载过程

      • 卸载过程基本上就是安装过程的逆向操作。
      • 首先检查该程序是否有Admin管理。意义是告诉系统,哪些是被强制安装的,这类程序不可卸载
      • 调用deletPackageLI()开始删除程序,包括程序文件以及PMS的mSettings.mPackages变量及mPackages变量。以及其他相关变量中关于该程序的包管理信息
      • 发送广播消息报告删除成功

      你可能感兴趣的:(Activity深入分析)