?????PKMS啟動詳解(四)之Android包資訊體和決議器(上)
Android PackageManagerService系列博客目錄:
PKMS啟動詳解系列博客概要
PKMS啟動詳解(一)之整體流程分析
PKMS啟動詳解(二)之怎么通過packages.xml對已安裝應用資訊進行持久化管理?
PKMS啟動詳解(三)之BOOT_PROGRESS_PMS_START流程分析
PKMS啟動詳解(四)之Android包資訊體和決議器(上)
本篇博客撰寫思路總結和關鍵點說明:
為了更加方便的讀者閱讀博客,通過導讀思維圖的形式將本博客的關鍵點列舉出來,從而方便讀者取舍和閱讀!
引言
??通過前面博客PKMS啟動詳解(三)之BOOT_PROGRESS_PMS_START流程分析以及更前面系列博客的耕耘,我們對PKMS啟動流程有了一個整體的概括和圖譜,并且經過BOOT_PROGRESS_PMS_START啟動階段一戰PKMS通過Settings資料結構類完成了對已安裝應用資訊的加載和管控,并且也同時借助SystemConfig資料結構類完成了對Android相關系統配置資訊完成了相關的加載和管控,
按照代碼邏輯的發展,PKMS要開始對系統應用路徑進行相關掃描然后決議應用安裝包了,但是這里我們先不急于進行這一階段的原始碼分析,因為我覺得這里有必要站在Android系統設計者的角度出發先來看看Android的設計者是通過什么策略對Android安裝包進行管理,或者說是通過什么資料結構來管控Android安裝包的(即apk應用的),只要我們掌握了Android設計者對應用包管理的設計思路,我想對于PKMS掃描應用安裝目錄的相關邏輯處理應該就是手到擒來的事情了,
注意:本篇的介紹是基于Android 7.xx平臺為基礎的(并且為了書寫簡便后續PackageManagerService統一簡稱為PKMS),其中涉及的代碼路徑如下:
--- frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
--- frameworks/base/core/java/android/content/pm/
PackageParser.java
ComponentInfo.java
PermissionGroupInfo.java
ApplicationInfo.java
PermissionInfo.java
PackageInfo.java
ActivityInfo.java
ServiceInfo.java
ProviderInfo.java
PermissionGroupInfo.java
PackageItemInfo.java
這里必須鄭重申明,鄭重申明,鄭重申明!
后續的前三個章節的博客絕大部分是基于博客Android包管理機制而來(加上自己的一些理解和思考),為啥我要冒著說抄襲的罪名也要把它放上來!因為他寫的太好了,忍不住的把他放了進來,他的博客真的不錯,這里不是打廣告或者吹捧,他的有些博客確實寫的很好,必須承認,值得我們學習!
一.站在上帝角度理解Android包管機制
讓我們一起開啟上帝視角看看Android的設計者是怎么設計Android的包管理機制的,學會了它我們就成了站在上帝上面的人了,
??有人的地方就有江湖,小到家庭,大到國家每一個社會群落都有管理機制,牽涉到管理那么就繞不開其中的三個要素:被管理者、管理者以及管理機制的運轉,在Android的世界中,有一處群落叫“包管理”,要研究Android的包管理機制,同樣可以從以下幾個角度來思考:
- 被管理的物件是什么?
- 管理者的職能是什么?
- 管理機制是如何運轉的?
所謂Android包,其實就是一種檔案格式,譬如APK包、JAR包等,在Android中存活著很多包,所有的應用程式都是APK包,很多構成Android運行環境的都是JAR包,還有一些以so為后綴的庫檔案,包管理者很重要的一個職能就是識別不同的包,統一維護這些包的資訊,當有一個包進入或離開Android世界,都需要向包管理者申報,其他管理部門要獲取包的具體資訊,也都需要向包管理者申請,
如同社會是由人與人的協作形成,不同的包之間也需要進行協作,既然有協作,自然就有協作的規范,一個包可以干什么,不可以干什么,都需要有一個明確的范圍界定,這就是包管理中的權限設計,涉及到的內容非常廣泛,Linux的UGO(User Group Other)和ACL(Access Control List,訪問控制串列)權限管理、數字簽名與驗證、Android授權機制、Selinux,都是包管理中權限設計的組成部分,
Android的世界就如同一個井然有序的人類社會,除了包管理部門,還有其他各種管理部門,譬如電源管理、視窗管理、活動管理等等,大家不僅各司其職,而且也有交流往來,從APK的安裝到Activity的顯示這么一個看似簡單的程序,卻需要大量管理部門參與進來,不斷地進行資料決議、封裝、傳遞、呈現,內部機理十分復雜,
對于上述三者關系中的管理者和被管理者,讀者朋友肯定能很歡快的回答出來是PKMS和Android包,但是對于其中涉及的管理機制估計沒有深入過PKMS的讀者就很難回答上一二了!
這個沒有關系,不熟悉才有學習的必要嗎!在接下來的章節中,我們將會重點分析Android包的管理機制,
二.Android包形態的簡介
對于PKMS機制中被管理者Android包,這里就介紹上了,
??Android中的APK和JAR包都以靜態檔案的形式分布在不同的硬體磁區,包管理者面臨的第一個任務就是將這些靜態的檔案轉化成記憶體的資料結構,這樣才能將其管理起來,Android中最重要的包管理物件就是APK,APK可以包含so檔案,負責將靜態檔案轉換記憶體中資料結構的工具就是PackageParser,包決議器(這里終于扣住我們要的主題了),
Android L(5.0)以后,支持APK拆分,即一個APK可以分割成很多部分,位于相同的目錄下,每一個部分都是一個單獨的APK檔案,所有的APK檔案具備相同的簽名,在APK決議程序中,會將拆分的APK重新組合成記憶體中的一個Package,對于一個完整的APK,Android稱其為Monolithic;對于拆分后的APK,Android稱其為Cluster,
在Android L(5.0)以前,APK檔案都是直接位于app或priv-app目錄下,譬如短彩信APK的目錄就是/system/priv-app/Mms.apk;到了Android L(5.0)之后,多了一級目錄結構,譬如短彩信APK的目錄是/system/priv-app/Mms/Mms.apk,這是Android為了支持APK拆分而做的改動,如果要將短彩信APK進行拆分,那所有被拆出來的APK都位于/system/priv-app/Mms/即可,這樣在包決議時,就會變成以Cluster的方式決議目錄,
一個包在記憶體中的資料結構就是Package,那么,Package有一些什么屬性?是怎么從APK檔案中獲取資料的呢? 這就涉及到包決議器的作業原理,Android的包管理者PKMS正是通過包管理決議器對Android包進行管理的!
2.1 Android包內部結構簡介
??通過前面的介紹我們可以Android包的核心各種APK檔案(對于jar包,這里我們不重點討論),因為Android包管理機制的核心就是對Android包通過包管理決議器對其進行管理,所以這里我們非常有必要了解一下APK的內部構造,我們以zip檔案的形式對APK展開看看其內部結構如下:
并且它的目錄結構每個核心檔案/目錄功能如下:
| APK內部檔案或目錄 | 作用 |
|---|---|
| META-INF/ | 也就是一個 manifest ,從 java jar 檔案引入的描述包資訊的目錄 |
| res/ | 資源檔案目錄 |
| libs/ | 如果存在的話,存放的是 ndk 編出來的 so 庫 |
| AndroidManifest.xml | Android程式全域組態檔 |
| classes.dex | dalvik 位元組碼 |
| resources.ars | 編譯后的二進制資源檔案 |
三.Android包管理機制設計思路
??通過前面的章節我們對于Android包的管理者,以及被管理者Android包都有了一個初步的認識!那么將管理者和被管理者關聯起來的就只有通過管理機制了,而這里的管理機制就是通過Android的包決議器了,
3.1 包決議器(PackageParse)設計思路
??通過為了先讓讀者對被管理物件有一個初步的認識,我們先把一個包最終在記憶體中的資料結構拎出來,其實生成這個資料結構,需要包管理者進行大量的調度作業,調度中心是PMS,包決議的程序也都是由PMS驅動的,在分析包決議程序之前,我們先上包決議的結果:
這個類圖,示意了一個包最終在記憶體中的資料結構Package,它包含很多屬性,部分屬性還是包決議器中的子資料結構,我們可以從設計的角度來理解這個類圖:
-
一個包中有很多組件,為此設計了一個高層的基類Component,所有具體的組件都是Component的子類,什么是組件呢?AndroidManifest.xml檔案中所定義的的一些標簽,就是組件,譬如<activity>,<service>,<provider>,<permission>等,這些標簽分別對應到包決議器中的一個資料結構,它們各自有自身的屬性,
-
諸如<activity>,<service>標簽,都可以配置<intent-filter>,來過濾其可以接收的Intent,這些資訊也需要在包決議器中體現出來,為此組件Component依賴于IntentInfo這個資料結構,每一個具體的組件所依賴的IntentInfo不同,所以Component和IntentInfo之間的依賴關系采用了橋接(Bridge)這種設計模式,通過泛型的手段實作,
-
各種組件最終聚合到Package這個資料結構中,形成了最終包決議器的輸出,當然,在決議的程序中,還有利用了一些資料結構來優化設計,PackageLite和ApkLite就是一些很簡單的資料封裝,
要得到以上的資料結構,包決議器PackageParser功不可沒,從接收一個靜態的檔案(File型別)開始,會經過一個漫長的包決議程序,直到生成最終的Package:
parsePackages(File file...)
└── parseClusterPackage(File packageDir...)
└── parseClusterPackageLite(File packageDir...)
| └── parseApkLite(File apkFile...)
| └── parseApkLite(String codePath...)
└── parseBaseApk()
└── parseBaseApplication()
| └── parseActivity()
| └── parseService()
| └── ...
└── parseInstrumentation()
└── ...
這些方法的具體邏輯本文不予分析,僅把關鍵的流程捋出來:
- PackageParser.parsePackages()是包決議器的入口方法,它首先會判定給定的輸入是否為一個目錄,如果是目錄,則以為著目錄下可能存在多個拆分后的APK,這就需要以Cluster的方式進行決議;如果僅僅是一個APK檔案,就以Monolithic的方式決議;
- 決議APK,需要先得到一個中間資料結構PacakgeLite,包名、版本、拆分包等資訊都會保存在這個資料結構中;由于一個包可能有多個拆分的APK,所以PackageLite可能關聯到多個APK,每一個APK都對應到ApkLite這個資料結構,也是一些基本資訊的封裝,之所以以Lite為后綴命名,是因為這兩個資料結構都比較輕量,只保存APK中很少資訊;
- 一個APK真正的資訊都寫在AndroidManifest.xml這個檔案中,PackageParser.parseBaseApk()這個方法就是用來決議該檔案,其決議程序與AndroidManifest.xml的檔案結構一一對應,譬如先決議<application>標簽的內容,然后決議其下的<activity>,<service>等標簽,由于AndroidManifest.xml檔案的結構非常復雜,所以該方法邏輯也非常龐大,讀者們可以自行分析原始碼,
至此,包決議器PackageParser就將一個靜態的檔案,轉換成了記憶體中的資料結構Package,它包含了一個包的所有資訊,如包名、包路徑、權限、四大組件等,其資料來源主要就是AndroidManifest.xml檔案,
3.2 Android包資訊體設計思路
??包決議器從靜態檔案中獲取的資料,很多都是需要用于跨行程傳遞的,譬如初次啟動Activity時,就需要把包資訊從系統行程傳遞到應用行程,先完成應用行程的啟動,在包決議器的類圖中,我們看到Activity、Service、Provider、Permission、Instrumentaion這些類都有一個共同的特征:都具備info這個屬性,其實這些類的結構非常簡單,就是對info的一次封裝,info這個結構體才是真正的包資料,筆者暫且稱之為“包資訊體”:
所有的info都實作了Parcelable介面,意圖很明顯,info是可以進行跨行程傳遞的,不同組件的info型別是不同的,除了實作了Parcelable介面,它們之間又構成了一個龐大的資料結構,把這些具體的info型別展開,就是以下的類圖:
可以看到,這個類圖與PackageParser中的類圖在結構上很相似,我們依舊是從設計的角度來理解這個類圖:
-
PackageItemInfo作為包每一項資訊的高層基類:
- 針對permission,permission,instrumentation等,分別為其設計了一個類,都繼承自PackageItemInfo
- 針對activity,service,provider等四大組件,在PackageItemInfo之下又多設計了一層:ComponentInfo作為四大組件的基類
- ApplicationInfo也是包資訊中的一項,但與四大組件緊密相連,四大組件肯定都屬于某個Application,所以ComponentInfo與Application存在依賴關系,繼而,具體到每個組件都與Application存在依賴關系
-
所有的包資訊都聚合到PackageInfo這個類中,PackageInfo就是一個包向外提供的所有資訊,其實除了上圖列出來的類,還有一些類沒有示意出來,譬如ConfigurationInfo,FeatureInfo,它們都可以對應到AndroidManifest.xml中的標簽,
這些結構體中的資料,都是在包決議器時初始化的,譬如Activity依賴于ActivityInfo,在決議Activity時,就會創建一個ActivityInfo物件,把<activity>所定義的資料全都填充到ActivityInfo中,讀者可以思考一下PackageParser中的Activity與此處的ActivityInfo的分開設計的目的和好處是什么?
關于此處我們需要重點注意如下幾點
1、上述針對activity,service,provider等四大組件,并不是我們通常意義上的Activity.java類,這里指代的是PackageParser的內部類千萬不要搞混淆了,
2.并且在后續的分析中,我們會見到很多類,類的命名方式還有點相似,初讀代碼的時候,很容易陷入各個類之間復雜的關系網之中,不得不說,包在記憶體中的資料結構是比較龐大的,因為它蘊含的資訊大多了,
3.3 關于包決議器和包資訊體小結
??前面牛逼的博主已經為我們從整體方向和高層次的視角概括了Android包管理機制中核心的包決議器和包資訊體的設計思路,不知道讀者有沒有get到其本質,這里為了使讀者能更加的對上述二者有深層次的認識,這里我加上自己對上述二者的理解,
- PackageParser包決議器
對于它,我們可以理解為它是PKMS在安裝,掃描應用程序中一個必不可少的工具類,它負責決議安裝包,將決議的安裝包資訊用來添加資料結構類Package!然后Package有許多的成員變數又分別指向安裝包中各個構成,譬如Service,Activity等,而這些類都有一個共同的特征:都具備info這個屬性,而這個屬性就是我們的包資訊體相關的資料結構,并且PackageParser是害羞的,它是一個hide類不能被外部使用,從而決定了它只能負責相關的決議,確不會拋頭露面對外提供介面 - 包資訊體
通過PackageParser決議完Android包后,在PKMS中就會有它相關的資料記錄,而此時第三方應用就可以通過public PackageInfo getPackageInfo(String packageName, int flags, int userId)獲取已經安裝應用相關安裝包的資訊,如果說包決議器是隊內的,那么包資訊體就是對外的,
理解了上述二者之間的聯系,我想讀者在后續的分析中就會游刃有余了,
四.從原始碼角度出發理解Android包資訊體設計思路
前面的章節,前人為我們高瞻遠矚的指明了道路的方向!但是如果不自己切身實踐,就領會不到他們的意圖和角度了,所以在后續章節中我們從原始碼角度出發來領悟,參透一下!
按照正常的邏輯,我們應該先從原始碼角度分析包決議器(PackageParse)的實作,但是這里為了排版和篇幅的原因,先從原始碼角度出發理解Android包資訊體設計理念,后面再來分析PackageParse的實作,
??通過前面的章節3.2我們知道了包決議器從靜態檔案中獲取的資料,很多都是需要用于跨行程傳遞的,譬如初次啟動Activity時,就需要把包資訊從系統行程傳遞到應用行程,先完成應用行程的啟動,在包決議器的類圖中,我們看到Activity、Service、Provider、Permission、Instrumentaion這些類都有一個共同的特征:都具備info這個屬性,其實這些類的結構非常簡單,就是對info的一次封裝,info這個結構體才是真正的包資料,筆者暫且稱之為“包資訊體”,這里我們就先從最外層的PackageItemInfo開始分析起!
4.1 PackageItemInfo類
對于PackageItemInfo我們將從如下幾個方面來發起攻擊:
- PackageItemInfo類概述
- PackageItemInfo類重要成員變數和方法
- PackageItemInfo在Android包設計中的使用
好了,啥也不說了,先干為敬!
4.1.1 PackageItemInfo類概述
通常看人看臉,而看Android原始碼通常是看設定著對它的概述了,我們這里看下Android設計者對它的概述定義如下:
// 【 PackageItemInfo.java 】
/**
* Base class containing information common to all package items held by
* the package manager. This provides a very common basic set of attributes:
* a label, icon, and meta-data. This class is not intended
* to be used by itself; it is simply here to share common definitions
* between all items returned by the package manager. As such, it does not
* itself implement Parcelable, but does provide convenience methods to assist
* in the implementation of Parcelable in subclasses.
*/
/**
PackageItemInfo, 代表一個應用包內所有組件項以及通用資訊的基類,該類提供最基本的屬性集,
如: label, icon, meta-data等,并且一般不會直接使用該類,它設計之初就是為了包內其它基本
組件項提供統一的基本定義,它沒有實作介面Parcelable, 但它提供了傳Parcel型的建構式,
以及writeToParcel()方法給它的子類來實作PackageItemInfo內部這部分的成員的Parcel化,
*/
public class PackageItemInfo {
...
}
英文比較好的先生們,女士們應該比較好容易理解上面的概述(英文不好的同仁們,就只能接收我蹩腳的中文翻譯了,勿見怪)!上述對于PackageItemInfo一句話歸納總結就是它是作為"包每一項資訊的高層基類",用來被繼承實作的,
這里我們需要知道的是PackageItemInfo直接子類,有如下幾個:
4.1.2 PackageItemInfo類主要成員變數
通常一個資料基類,最最重要的就是它的成員變數了,我們先睹為快,看看PackageItemInfo的廬山真面目!
// 【 PackageItemInfo.java 】
public class PackageItemInfo {
/*
表示包組件項的名稱,從"android:name"屬性得到
注意是組件項的名稱,而不是Android包的名稱
*/
public String name;
// 該組件項所在Android包的包名
public String packageName;
/*
指向該組件項的標簽,為String型的資源id,
從"android:label"屬性得到,如不設定則為0.
*/
public int labelRes;
/**
* The string provided in the AndroidManifest file, if any. You
* probably don't want to use this. You probably want
* {@link PackageManager#getApplicationLabel}
*/
// 這個應該指向的是Application對應的Label
public CharSequence nonLocalizedLabel;
/*
指向該組件項的圖示,drawable型的資源id,
從"android:icon"屬性得到,如不設定則為0.
*/
public int icon;
/*
指向該組件項的橫幅,drawable型的資源id,
從"android:banner"屬性得到,如不設定則為0.
*/
public int banner;
/*
指定該組件項的logo,drawable型的資源id,比應用圖示要大,
ActionBar可以設定是否顯示logo, 從"android:banner"屬性得到,如不設定則為0
*/
public int logo;
/*
對應AndroidManifest中的<meta-data>標簽,
只有<activity>, <activity-alias>, <service>, <receiver>, <application>
標簽中可能包含<meta-data>子標簽,
*/
public Bundle metaData;
// 表示是否顯示用戶icon
public int showUserIcon;
...
}
上述資訊填充的來源通常是AndroidManifest.xml檔案下對應組件標簽下的子標簽,這個讀者了解一下即可,
4.1.3 PackageItemInfo類主要方法
對于一個資料型別的基類,通常它的方法是用來提供獲取/設定成員變數資訊的,這里的PackageItemInfo是不是也遵循這一套路呢,這里我們透過原始碼來看實質,如下:
// 【 PackageItemInfo.java 】
public class PackageItemInfo {
// 各種花式構造方法
public PackageItemInfo();
public PackageItemInfo(PackageItemInfo orig);
protected PackageItemInfo(Parcel source);
/*
顧名思義,回傳該組件項的標簽,優先級依次為:nonLocalizedLabel, labelRes, name, packageName.
*/
public CharSequence loadLabel(PackageManager pm);
/*
回傳該組件項的圖示,通過ApplicationPackageManager的loadItemIcon()方法獲取icon對應的Drawable.
*/
public Drawable loadIcon(PackageManager pm)
/*
回傳該組件項的橫幅,通過ApplicationPackageManager的getDrawable()
方法獲取banner對應的Drawable, 如果banner為0, 回傳loadDefaultBanner()的結果.
*/
public Drawable loadBanner(PackageManager pm)
/*
回傳該組件項的大圖示,通過ApplicationPackageManager的getDrawable()
方法獲取logo對應的Drawable, 如果logo為0, 回傳loadDefaultLogo()的結果.
*/
public Drawable loadLogo(PackageManager pm)
/*
回傳該組件的默認圖示,通過ApplicationPackageManager的getDefaultActivityIcon()方法,
回傳的結果是com.android.internal.R.drawable.sym_def_app_icon對應的Drawable.
*/
public Drawable loadDefaultIcon(PackageManager pm)
// 回傳null
protected Drawable loadDefaultBanner(PackageManager pm)
// 回傳null
protected Drawable loadDefaultLogo(PackageManager pm)
/*
找到metaData中對應為name的資源id, 通過ApplicationPackageManager的getXml()方法,
回傳該id對應的XmlResourceParser.
*/
public XmlResourceParser loadXmlMetaData(PackageManager pm, String name)
// 回傳null
protected ApplicationInfo getApplicationInfo()
// 為PackageItemInfo的子類Parcel化提供基類部分的成員的寫入
public void writeToParcel(Parcel dest, int parcelableFlags)
}
看來PackageItemInfo也被拜托老套路啊!
4.1.4 PackageItemInfo在Android包管理中的使用
通過搜尋發現在決議Android包的程序中只有PackageParser.parsePackageItemInfo方法會以out引數的形式獲取PackageItemInfo的資訊,其定義如下:
// 【 PackageParser.java 】
private static boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
String[] outError, String tag, TypedArray sa, boolean nameRequired,
int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes);
這里可以看到parsePackageItemInfo方法是PackageParser的私有方法,也是唯一的引數有PackageItemInfo的方法,它在PackageParser中三個地方被呼叫,分別用于決議標簽 <permission-group>生成 PermissionGroupInfo, 決議 <permission>生成PermissionInfo, 決議<permission-tree>生成PermissionInfo,
所以可以看到PackageItemInfo類在Android包管理機制中只有極少部分時候被直接使用,更多的是它的子類、間接子類,不過它定義了組件的共同特征,為研究其它組件資訊提供基礎,組件資訊均是public的,外部直接用該類實體來參考賦值,并且我們通過前面總結可知它的直接子類是ComponentInfo, ApplicationInfo,這個我們會在后面繼續介紹,
4.1.5 PackageItemInfo類小結
至此PackageItemInfo類我們就介紹完畢了,對于它在Android包管理中的定位和功能我們也應該心里大概有譜了,還是一句話總結它定義了Android包組件的共同特性,是用來被繼承和實作的,最后附上它的類圖,如下:
4.2 ComponentInfo類
PackageItemInfo分析完畢,我們來說說其子類ComponentInfo,老規矩,我們將從如下幾個方面來發起攻擊:
- ComponentInfo類概述
- ComponentInfo類重要成員變數和方法
- ComponentInfo在Android包設計中的使用
好了,啥也不說了,先干為敬!
4.2.1 ComponentInfo概述
多余的文字我也給省了,直接看設計者對它的定義:
// 【 ComponentInfo.java 】
/**
* Base class containing information common to all application components
* ({@link ActivityInfo}, {@link ServiceInfo}). This class is not intended
* to be used by itself; it is simply here to share common definitions
* between all application components. As such, it does not itself
* implement Parcelable, but does provide convenience methods to assist
* in the implementation of Parcelable in subclasses.
*/
/*
ComponentInfo, 代表一個應用內組件(如ActivityInfo, ServiceInfo, ProviderInfo)通用資訊的基類,
一般不會直接使用該類,它設計是為了不同應用的組件共享統一的定義,它沒有實作介面Parcelable,
但它提供了傳Parcel型的建構式,以及writeToParcel()方法給它的子類來實作ComponentInfo內部這部分的成員的Parcel化
*/
public class ComponentInfo extends PackageItemInfo {
...
}
對于ComponentInfo我用一句話概括總結就是它是對PackageItemInfo的具象化,它是ActivityInfo, ServiceInfo, ProviderInfo基類,用來抽象化Android包組件中上述資訊,
ComponentInfo的直接子類有且僅有上述三個!
4.2.2 ComponentInfo類主要成員變數和方法
前面感覺介紹PackageItemInfo有點太啰嗦了,這里我們就不對ComponentInfo過度的展開了,只查看其成員變數,方法基本是對成員變數的操作,
直接上原始碼,來看看ComponentInfo類的真面目!
// 【 ComponentInfo.java 】
public class ComponentInfo extends PackageItemInfo {
/*
表示該組件所在的包的application資訊,從<application>標簽獲取
*/
public ApplicationInfo applicationInfo;
/*
該組件所運行的行程名,string型,從"android:process"屬性得到,
如不設定則為applicationInfo.processName.
*/
public String processName;
/*
該組件的描述,string型的資源id,從"android:description"屬性得到,如不設定則為0
*/
public int descriptionRes;
/*
表明當前組件能否被實體化,boolean型,從"android:enabled"屬性得到,
如果它所在的ApplicationInfo中enabled為false, 則這處的設定無效
*/
public boolean enabled = true;
/*
表明當前組件能否被其它Application的組件啟動,boolean型,從"android:exported"屬性得到,
如果當前組件沒有一個<intent-filter>則它默認為false(沒有任何<intent-filter>表明要用組件的準確名稱來啟動),
exported=false表明當前組件只能被當前應用內組件啟動,或有相同UID的應用,
*/
public boolean exported = false;
...
}
4.2.3 ComponentInfo在Android包管理中的使用
通過搜尋發現在決議Android包的程序中只有PackageParser.Component內部類會以out引數的形式獲取ComponentInfo的資訊,其定義如下:
// 【 PackageParser.java 】
public static class Component<II extends IntentInfo> {
public Component(final ParseComponentArgs args, final ComponentInfo outInfo) {
}
}
這里可以看到PackageParser中的組件基類Component,它的一個建構式會傳入ComponentInfo的類, 內部對它的成員進行賦值,
4.2.4 ComponentInfo類小結
至此ComponentInfo類我們就介紹完畢了,對于它在Android包管理中的定位和功能我們也應該心里大概有譜了,還是一句話總結,它是PackageItemInfo基類的具象化,用來表述Android包組件Service,Activity,Provider資訊的,最后附上它的類圖,如下:
4.3 ApplicationInfo類
ApplicationInfo分析完畢,我們來說說其子類ApplicationInfo,老規矩,我們將從如下幾個方面來發起攻擊:
- ApplicationInfo類概述
- ApplicationInfo類重要成員變數和方法
- ApplicationInfo在Android包設計中的使用
好了,啥也不說了,先干為敬!
4.3.1 ApplicationInfo類概述
多余的文字我也給省了,直接看設計者對它的定義:
/**
* Information you can retrieve about a particular application. This
* corresponds to information collected from the AndroidManifest.xml's
* <application> tag.
*/
/*
通過它可以得到一個應用基本資訊,這些資訊是T通過決議應用的AndroidManifest.xml
的<application>標簽獲取的
*/
public class ApplicationInfo extends PackageItemInfo implements Parcelable {
...
}
對于ApplicationInfo我用一句話概括總結,就是它是對PackageItemInfo的具象化,它是Android包中AndroidManifest.xml中標簽的資料實體化類,
4.3.2 ApplicationInfo類主要成員和方法
直接上原始碼,來看看ComponentInfo類的真面目!
// 【 ApplicationInfo.java 】
public class ApplicationInfo extends PackageItemInfo implements Parcelable {
/*
當前應用所有Activity的默認task密切性,從”android:taskAffinity“屬性得到
*
public String taskAffinity;
/*
可選項,訪問當前應用所有組件需要宣告的權限,從”android:permission“屬性得到
*/
public String permission;
/*
從”android:process“屬性得到,表明應用運行的行程名,或不設定則默認為應用包名
*/
public String processName;
/*
從”android:class“屬性得到,應用實作的Application類的類名
如果不設定則使用默認的名稱""
*/
public String className;
/ *
對Application組件的描述,從”android:description“屬性得到,若不設定則為0
*/
public int descriptionRes;
/*
指向應用的主題,從”android:theme“屬性得到,,若不設定則為0
*/
public int theme;
/*
從”android:manageSpaceActivity“屬性得到,用于指定一個Activity來管理資料,
它最侄訓出現在設定->應用程式管理中,默認為按鈕為”清除資料”,指定此屬性后,
該按鈕可點擊跳轉到該Activity, 讓用戶選擇性清除哪些資料,若不設定則為null.
*/
public String manageSpaceActivityName;
/*
從”android:backupAgent“屬性得到,Android原生的備份引擎BackupManagerService在應用端的實作類,
是backupAgent的子類,默認不會由系統備份,若”android:allowBackup“值為false, 則該屬性設定無效,
*/
public String backupAgentName;
/*
可選項,注明應用是否支持自動備份,
*/
public int fullBackupContent = 0;
/*
為應用內所有Activity設定的默認UI選項,可選值為"none", "splitActionBarWhenNarrow",
*/
public int uiOptions = 0;
/*
flag標志位,常見的有android:debuggable和android:persistent等配置選項
*/
public int flags = 0;
/*
來自SELinux策略中seinfo標簽,這個值一般在設定應用行程的SELinux安全背景關系時有用
*/
public String seinfo;
// 應用的資料目錄
public String dataDir;
// JNI本地庫存放路徑
public String nativeLibraryDir;
...
// 構造方法
public ApplicationInfo(...);
public void writeToParcel(Parcel dest, int parcelableFlags);
// 通過return this回傳當前ApplicationInfo實體
protected ApplicationInfo getApplicationInfo();
// 判斷當前應用是否為系統應用,flags與ApplicationInfo.FLAG_SYSTEM按位與不等于0則回傳true
public boolean isSystemApp()
這里可以看到ApplicationInfo類的成員變數和方法還是比較多的,這里就不展開了!讀者可以在具體使用的時候結合原始碼一起查看,最好是對照AndroidManifest.xml檔案!
4.3.3 ApplicationInfo在Android包管理中的使用
關于此處ApplicationInfo在Android包管理中使用的情況,比較復雜,總之它會通過PackageParser決議Android包的程序中被賦值,這個在后面的博客中再細說,
4.4 包資訊體牽涉的其它類
包資訊體其它相關的類PermissionInfo,InstrumentationInfo,PermissionGroupInfo,PackageInfo這里就不過多展開了,感興趣的讀者可以自行分析,總之我們可以認為PackageInfo是包資訊體主根,而PermissionInfo,InstrumentationInfo,PermissionGroupInfo,PackageInfo等都是它的字根是對PackageInfo的填充而已,
總結
??好了,到這里PackageManagerService啟動詳解(四)之Android包資訊體和決議器(上)分析就告一段落了,在本篇博客中我們重點闡述了如下知識點:
- Android包管理機制中的Android包資訊體設計思想和原始碼邏輯
- Android包管理機制中的Android包決議器設計思想
但是由于篇幅和包決議器原始碼邏輯過于繁瑣,就將其留到下一個章節進行相關的分析了,
好了,各位青山不改綠水長流,各位江湖見!當然各位讀者的點贊和關注是我寫作路上前進的最大動力了,如果有啥不對或者不爽的也可以踩一踩也無妨!
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/267152.html
標籤:其他
上一篇:龐雜技術要點匯總檔案分享(1)
下一篇:Unity 檔案操作及各路徑總結









