包管理服务( PackageManagerService)是ANDROID的系统服务之一,主要功能实现应用包的解析、安装、更新、移动、卸载等服务。
系统类图如下:
PackageManagerService主要通过Installer、UserManager、AppDirObserver、Settings、DefaultContainerService、PackageHelper、NativeLibraryHelper、PackageHandler、PackageParser等类实现相应的功能。
Installer类与本地服务installd建立LocalSocket连接,借助installd实现包的install、remove、dexopt等功能。
UserManager类实现与用户相关的用户数据和包的安装、创建和管理,包括用户及用户数据的创建、删除。
AppDirObserver实现对/system/framework,/system/app、 /vendor/app、/data/app、/data/app-private等目录的add和remove事件的监听,实现包的动态安装和卸载。
Settings类实现data/system/目录下的包安装信息相关的文件的读取和管理(创建、更新等),解析和读取如下packages.xml、"packages-backup.xml"、"packages.list"、"packages-stopped.xml"、"packages-stopped-backup.xml" XML文件。
packages.xm是在解析apk时由 writeLP()创建的,里面记录了系统的permissions以及每个apk的name ,codePath, pkgFlags, timeStamp, versionCode,uesrid等信息,这些信息主要通过apk的 AndroidManifest.xml解析获取,解析完apk后将更新信息写入这个文件并保存到flash,下次开机直接从里面读取相关信息添加到内存相关列表中。当有apk升级,安装或删除时会更新这个文件。
packages.list记录了如下数据:pkgName,userId,debugFlag,dataPath(包的数据路径)。
packages-stopped.xml记录处于停止状态的包的信息,主要包括包名、notLaunched状态等信息。
DefaultContainerService是一个应用服务,具体负责实现APK等相关资源文件在内部或外部存储器上的存储工作。 DefaultContainerService服务中提供了一个IMediaContainerService.Stub桩对象。PackageManagerService包管理服务在PackageHandler对象接收到应用安装消息后首先与该服务建立连接(通过BINDSERVICE)。在服务建立连接后onServiceConnected回调被调用,在onServiceConnected回调函数中根据参数传进来的IMediaContainerService.Stub的对象引用创建一个远程代理对象。以后PackageManagerService服务通过该代理对象访问DefaultContainerService服务。
PackageHelper是提供包安装用到的 MountService的API方法的帮助类。
NativeLibraryHelper是提供APK包含的库文件安装、删除、空间大小计算等方法的帮助类。
PackageHandler实现包处理相关的消息的处理,如apk安装请求消息,如adb install等。PackageHandler运行在独立的线程。
PackageHandler对象对应用包的处理请求使用了模板和命令模式,把要处理的请求作为对象通过消息传递给处理函数;包的安装、移动及获得包的大小消息请求分别打包为InstallParams、MoveParams、MeasureParams对象,三个类都继承自HandlerParams超类,HandlerParams超类中定义了一个模板函数startCopy,模板函数startCopy中使用的三个函数在超类中没有实现,是虚函数,具体实现的功能由具体类确定;如虚函数handleStartCopy对于InstallParams类实现的是包的安装工作,对于MoveParams类实现的是包的移动工作,而MeasureParams类中的handleStartCopy函数实现的是包的测量工作。
InstallParams、MoveParams、MeasureParams三个类中提供了对应的观察者接口IPackageInstallObserver、IPackageMoveObserver、IPackageStatsObserver,三个接口在PackageManagerService的客户端对象调用PackageManagerService服务的包的安装、移动及获得包的大小等相关API时作为参数传进来,并在InstallParams、MoveParams、MeasureParams三个对象实例化时赋值给对应的观察者接口。因此三个观察者接口指向的对象实际是客户端提供的观察者对象(桩对象)的远程代理对象,InstallParams、MoveParams、MeasureParams三个对象通过对应的观察者接口向远端客户端发送通知。采用的模式是代理模式和观察者模式的复合模式。
POST_INSTALL消息的处理也采用了命令设计模式,把请求的参数打包为PostInstallData对象,PostInstallData对象中包括InstallArgs和PackageInstalledInfo对象,InstallArgs是一个虚类,提供copyApk等接口,接口的具体实现在其具体类FileInstallArgs和SdInstallArgs中完成。
PackageParser实现应用包的解析功能,主要是解析每个apk的AndroidManifest.xml文件,处理asset/res等资源文件,建立起每个apk的配置结构信息。PackageParser是其它类功能实现的基础,是包管理服务最重要的一个类。PackageParser类在实现应用包的解析时采用了解释器模式,对于应用包中的每种语法结构都创建了对应的类,来分别搜集应用包中的相应信息。类结构图如下:
图中除了Resources及XmlPullParser两个类外其余的类都是PackageParser类的内部类,应用包的每个语法结构的对应类都派生自componet类或属于componet类的内部成员,Package类(一个包一个Package对象)是一个聚合类,把解析出来的一个应用包中的componet聚合到Package类中进行统一管理,PackageParser类将解析出的每个componet及其它信息添加到Package中。
Resources及XmlPullParser两个类负责XML资源读取的工作。
整个解析流程:
1、 在PackageManagerService服务的构造函数中调用scanDirLI函数对如下FrameworkDir(/system/framework)、SystemAppDir(/system/app)、VendorAppDir(/vendor/app)、AppInstallDir(/data/app)、DrmAppPrivateInstallDir(/data/app-private)五个目录下的APK文件进行扫描;
2、 scanDirLI函数对扫描目录下的每个APK文件调用scanPackageLI(file, flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime)函数对每个APK文件进行解析,返回包含解析信息的PackageParser.Package对象。scanDirLI函数在解析失败后还删除解析的无效APK文件;
3、 在函数scanPackageLI中首先实例化一个PackageParser对象,接着调用PackageParser对象的parsePackage(scanFile,scanPath, mMetrics, parseFlags)函数对待解析文件进行解析;
4、 在parsePackage函数中对文件进行一些判断后,先实例化一个AssetManager对象,并调用AssetManager对象的addAssetPath函数把被解析文件的路径添加到AssetManager对象,添加成功后实例化一个Resources对象,然后调用AssetManager对象的openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME)函数打开一个解析AndroidManifest.xml文件的XML解析器,接着调用parsePackage(res, parser, flags, errorText)函数开始具体解析工作;
5、 parsePackage函数先调用parsePackageName函数解析出包名,接着根据包名实例化一个Package对象,接着从AndroidManifest.xml文件中解析出被解析包的VersionCode、VersionName、installLocation等全局属性信息;然后根据XML文件的标签循环解析XML文件包含的其它组成部分,对于tagName名称为application标签时调用parseApplication函数解析该application标签下包含的组件等信息(只能对一个application标签进行解析);对于tagName名称为"permission-group"时调用parsePermissionGroup函数进行解析;对于tagName名称为"permission"时调用parsePermission函数进行解析;对于tagName名称为"permission-tree"时调用parsePermissionTree函数进行解析;对于tagName名称为"permission-tree"时调用parsePermissionTree函数进行解析;对于tagName名称为"instrumentation"时调用parseInstrumentation函数进行解析;并解析或跳过其它标签,如"uses-feature"、"uses-configuration"、"uses-sdk"、"supports-screens"等标签,获得应用包的其它属性;
6、 在parseApplication函数中首先解析出应用标签下的包含的应用属性信息,然后根据XML文件的标签循环解析应用标签下包含的其它组件;对于"activity"标签调用parseActivity函数进行解析,并返回一个Activity对象,添加到Package对象的activities列表中;对于"receiver"标签也调用parseActivity函数进行解析,返回一个Activity对象,添加到Package对象的receivers列表中;对于"service"标签调用parseService函数进行解析,并返回一个Service对象,添加到Package对象的services列表中;对于"provider"标签调用parseProvider函数进行解析,并返回一个Provider对象,添加到Package对象的providers列表中;对于"activity-alias"标签调用parseActivityAlias函数进行解析,并返回一个Activity对象,添加到Package对象的activities列表中;对于"meta-data"标签调用parseMetaData函数进行解析,解析出应用的MetaData;解析或跳过其它标签,如"uses-library"、"uses-package"等标签;
7、 在parseActivity函数中先实例化一个ParseComponentArgs对象和ActivityInfo对象,再实例化Activity对象(实例化的ParseComponentArgs对象和ActivityInfo对象作为参数传给Activity对象的构造函数),然后解析"activity"标签包含的各种属性信息并赋值给Activity对象的内部ActivityInfo对象的相应属性;然后根据XML文件的标签循环解析"activity"标签下包含的其它部分,对于"intent-filter"标签先实例化一个ActivityIntentInfo对象,并调用parseIntent解析"intent-filter"部分,解析出的信息放在作为参数传给parseIntent函数的ActivityIntentInfo对象中,解析后把包含解析信息的ActivityIntentInfo对象添加到Activity对象的intents列表中;对于"meta-data"标签调用parseMetaData函数进行解析,解析出Activity对应的MetaData,并跳过其它标签;标签循环解析完成后返回已包含解析信息的Activity对象;
8、 对于其它组件进行同样过程的解析过程。
componet类的每个派生类内部都有一个对应的info对象,具体指向每个componet包含的信息,具体类图如下:
每个componet的信息类都派生自PackageInfo类和PackageItemInfo的子类ComponentInfo,PackageInfo类一个容器类,应用包中解析出的信息都被聚合到PackageInfo类中进行统一管理。
上一篇 版权所有,转载时请尊重原创显要处注明链接,谢谢!
下一篇