包管理服務( 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類中進行統一管理。
歡迎轉載,轉載時請尊重原創註明出處。