现在的位置: 首页 > 综合 > 正文

第九篇 ANDROID包管理服务机制–解释器模式

2013年08月23日 ⁄ 综合 ⁄ 共 6012字 ⁄ 字号 评论关闭

       包管理服务( PackageManagerService)ANDROID的系统服务之一,主要功能实现应用包的解析、安装、更新、移动、卸载等服务。

        系统类图如下:

         

        PackageManagerService主要通过InstallerUserManagerAppDirObserverSettingsDefaultContainerServicePackageHelperNativeLibraryHelperPackageHandlerPackageParser等类实现相应的功能。

        Installer类与本地服务installd建立LocalSocket连接,借助installd实现包的installremovedexopt等功能。

        UserManager类实现与用户相关的用户数据和包的安装、创建和管理,包括用户及用户数据的创建、删除。

        AppDirObserver实现对/system/framework,/system/app /vendor/app/data/app/data/app-private等目录的addremove事件的监听,实现包的动态安装和卸载。

        Settings类实现data/system/目录下的包安装信息相关的文件的读取和管理(创建、更新等),解析和读取如下packages.xml"packages-backup.xml""packages.list""packages-stopped.xml""packages-stopped-backup.xml"
 XML
文件。

        packages.xm是在解析apk时由 writeLP()创建的,里面记录了系统的permissions以及每个apkname
,codePath, pkgFlags, timeStamp, versionCode,uesrid
等信息,这些信息主要通过apk AndroidManifest.xml解析获取,解析完apk后将更新信息写入这个文件并保存到flash,下次开机直接从里面读取相关信息添加到内存相关列表中。当有apk升级,安装或删除时会更新这个文件。

        packages.list记录了如下数据:pkgNameuserIddebugFlagdataPath(包的数据路径)。

        packages-stopped.xml记录处于停止状态的包的信息,主要包括包名、notLaunched状态等信息。

      
DefaultContainerService
是一个应用服务,具体负责实现APK等相关资源文件在内部或外部存储器上的存储工作。       DefaultContainerService
服务中提供了一个IMediaContainerService.Stub桩对象。PackageManagerService包管理服务在PackageHandler对象接收到应用安装消息后首先与该服务建立连接(通过BINDSERVICE)。在服务建立连接后onServiceConnected回调被调用,在onServiceConnected回调函数中根据参数传进来的IMediaContainerService.Stub的对象引用创建一个远程代理对象。以后PackageManagerService服务通过该代理对象访问DefaultContainerService服务。

        PackageHelper是提供包安装用到的 MountServiceAPI方法的帮助类。

        NativeLibraryHelper是提供APK包含的库文件安装、删除、空间大小计算等方法的帮助类。

        PackageHandler实现包处理相关的消息的处理,如apk安装请求消息,如adb install等。PackageHandler运行在独立的线程。

        PackageHandler对象对应用包的处理请求使用了模板和命令模式,把要处理的请求作为对象通过消息传递给处理函数;包的安装、移动及获得包的大小消息请求分别打包为InstallParamsMoveParamsMeasureParams对象,三个类都继承自HandlerParams超类,HandlerParams超类中定义了一个模板函数startCopy,模板函数startCopy中使用的三个函数在超类中没有实现,是虚函数,具体实现的功能由具体类确定;如虚函数handleStartCopy对于InstallParams类实现的是包的安装工作,对于MoveParams类实现的是包的移动工作,而MeasureParams类中的handleStartCopy函数实现的是包的测量工作。

        InstallParamsMoveParamsMeasureParams三个类中提供了对应的观察者接口IPackageInstallObserverIPackageMoveObserverIPackageStatsObserver,三个接口在PackageManagerService的客户端对象调用PackageManagerService服务的包的安装、移动及获得包的大小等相关API时作为参数传进来,并在InstallParamsMoveParamsMeasureParams三个对象实例化时赋值给对应的观察者接口。因此三个观察者接口指向的对象实际是客户端提供的观察者对象(桩对象)的远程代理对象,InstallParamsMoveParamsMeasureParams三个对象通过对应的观察者接口向远端客户端发送通知。采用的模式是代理模式和观察者模式的复合模式。

       POST_INSTALL消息的处理也采用了命令设计模式,把请求的参数打包为PostInstallData对象,PostInstallData对象中包括InstallArgsPackageInstalledInfo对象,InstallArgs是一个虚类,提供copyApk等接口,接口的具体实现在其具体类FileInstallArgsSdInstallArgs中完成。

       PackageParser实现应用包的解析功能,主要是解析每个apkAndroidManifest.xml文件,处理asset/res等资源文件,建立起每个apk的配置结构信息。PackageParser是其它类功能实现的基础,是包管理服务最重要的一个类。PackageParser类在实现应用包的解析时采用了解释器模式,对于应用包中的每种语法结构都创建了对应的类,来分别搜集应用包中的相应信息。类结构图如下:

       

       图中除了ResourcesXmlPullParser两个类外其余的类都是PackageParser类的内部类,应用包的每个语法结构的对应类都派生自componet类或属于componet类的内部成员,Package类(一个包一个Package对象)是一个聚合类,把解析出来的一个应用包中的componet聚合到Package类中进行统一管理,PackageParser类将解析出的每个componet及其它信息添加到Package中。

         ResourcesXmlPullParser两个类负责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文件中解析出被解析包的VersionCodeVersionNameinstallLocation等全局属性信息;然后根据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的子类ComponentInfoPackageInfo类一个容器类,应用包中解析出的信息都被聚合到PackageInfo类中进行统一管理。

                          欢迎转载,转载时请尊重原创注明出处。

抱歉!评论已关闭.