提供一个能够根据intent匹配到具体的Activity、Provider、Service。即当应用程序调用startActivity(intent)时,能够把参数中指定的intent转换成一个具体的包含了程序包名称及具体Componment名称的信息,以便Java类加载器加载具体的Componment。
进行权限检查。即当应用程序调用某个需要一定权限的函数时,系统判断调用者是否具备该权限,从而保证系统的安全。
提供安装、删除应用程序的接口
该框架分为三层,分别为程序应用层、Pms服务层及数据文件层
应用程序层:
应用程序需要使用包管理服务时,调用ContextImpl类的getPackageManager()函数返回一个 ApplicationPackageManager对象,它继承自PackageManager抽象类,参数传入Pms,Apm类调用各种pms的类方法。
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>
数据文件层
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
HashMap
ArrayList
ArrayMap
Pms类中重要变量
ArrayMap
final Settings mSettings:Settings类
final SparseArray
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()函数时,其内部就是通过以上四个变量查询相关的目标对象信息的。
创建一个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文件。
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信息。