Android的ActivityManagerService(簡稱AMS)的源碼分析
Android的PackageManagerService10.0源碼解讀(AndroidManifest.xml解析)
Android判斷Activity是否在AndroidManifest.xml裏面註冊(源碼分析)
Android的PackageManagerService10.0源碼解讀
PackageManagerService 簡稱 PKMS
PKMS簡介
PackageManagerService(簡稱 PKMS),是 Android 系統中核心服務之一,負責應用程序的安 裝,卸載,信息查詢,等工作。
Android系統啓動時,會啓動(應用程序管理服務器PKMS),此服務負責掃描系統中特定的目錄,尋找裏面的APK格式的文件,並對這些文件進行解析,然後得到應用程序相關信息,最後完成應用程序的安裝。
PKMS在安裝應用過程中, 會全面解析應用程序的AndroidManifest.xml文件, 來得到Activity,
Service, BroadcastReceiver, ContextProvider 等信息, 在結合PKMS服務就可以在OS中正常的使用應用程序了。
在Android系統中, 系統啓動時由SystemServer啓動PKMS服務, 啓動該服務後會執行應用程序的安裝過程。
PKMS主要作用
PKMS 與 AMS 一樣,也是Android系統核心服務之一
1.解析AndroidNanifest.xml清單文件,解析清單文件中的所有節點信息
2.掃描.apk文件,安裝系統應用,安裝本地應用等
3.管理本地應用,主要有, 安裝,卸載,應用信息查詢 等
源碼路徑在 /frameworks/base/core/java/android/ 和 /frameworks/base/services/java/com/android/
PKMS角色
客戶端可通過Context.getPackageManager()獲得ApplicationPackageManager對象, 而
mPM指向的是Proxy代理,當調用到mPM.方法後,將會調用到IPackageManager的Proxy代理方法,然後通過Binder機制中的mRemote與服務端PackageManagerService通信 並調用到PackageManagerService的方法。
簡單來說:PKMS是屬於Binder機制的服務端角色.
PKMS的啓動
PKMS啓動過程描述:
SystemServer啓動PKMS: 先是在SystemServer.startBootstrapServices()函數中啓動PKMS服務,再調用startOtherServices()函數中對dex優化,磁盤管理功能,讓PKMS進入systemReady狀態。
第一步:啓動Installer服務
SystemServer.startBootstrapServices()
Installer installer = mSystemServiceManager.startService(Installer.class);
第二步:獲取手機是否加密
String cryptState = VoldProperties.decrypt().orElse("");
第三步:調用PKMS的main方法,實列化
PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest);
t.traceEnd(); // "create package manager"
m.installWhitelistedSystemPackages();
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
第四步:
如果設備沒有加密,直接操作,管理A/B OTA dexopting
SystemServer啓動服務,使核心服務處於ready狀態,startOtherServices
if(!mOnlyCore)
{
boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt", false);
OtaDexoptService.main(mSystemContext, mPackageManagerService);
}
第五步:
如果設備沒有加密,執行performDexOptUpgrade完成dex優化, PKMS.updatePackagesIfNeeded()
mPackageManagerService.updatePackagesIfNeeded();
第六步:
執行performFstrimIfNeeded(),完成磁盤維護,
第七步:
執行systemReady(),PKMS準備就緒
主要是PKMS的main()方法
(1) 檢查Package編譯相關係統屬性
(2) 調用PackageManagerService構造方法
(3) 啓用部分應用服務於多用戶場景
(4) 在ServiceManager中註冊”package”和”package_native”。
public static PackageManagerService main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
// (1)檢查Package編譯相關係統屬性
PackageManagerServiceCompilerMapping.checkProperties();
// (2)調用PackageManagerService構造方法,
PackageManagerService m = new PackageManagerService(context, installer, factoryTest, onlyCore);
//(3)啓用部分應用服務於多用戶場景
m.enableSystemUserPackages();
//(4)往ServiceManager中註冊”package”和”package_native”。
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
return m;
}
public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore)
PKMS的構造函數主要作用,具體可以看源碼
(1) 構造 DisplayMetrics ,保存分辨率等相關信息;
(2) 創建Installer對象,與installd交互;
(3) 創建mPermissionManager對象,進行權限管理;
(4) 構造Settings類,保存安裝包信息,清除路徑不存在的孤立應用,主要涉及/data/system/目錄的packages.xml,packages-backup.xml,packages.list,packages-stopped.xml,packagesstopped�backup.xml等文件。
(5) 構造PackageDexOptimizer及DexManager類,處理dex優化;
(6) 創建SystemConfig實例,獲取系統配置信息,配置共享lib庫;
(7) 創建PackageManager的handler線程,循環處理外部安裝相關消息。
APK的掃描
主要是PKMS構造方法,總結一下:
第一步:掃描APK,解析AndroidManifest.xml文件,得到清單文件各個標籤內容
第二步:解析清單文件到的信息由 Package 保存。從該類的成員變量可看出,和 Android 四大組件相關的信息分別由 activites、receivers、providers、services 保存,由於一個 APK 可聲明多個組件,因此activites 和 receivers等均聲明爲 ArrayList。
這下我們就知道了何時解析了AndroidManifest.xml文件,以及裏面的四大組件信息。
簡要說下APK的安裝
安裝步驟一: 把Apk的信息通過IO流的形式寫入到PackageInstaller.Session中
安裝步驟二: 調用PackageInstaller.Session的commit方法, 把Apk的信息交給PKMS處理
安裝步驟三: 進行Apk的Copy操作, 進行安裝
我們看到的安裝界面其實是入PackageInstallerActivity這個。
安裝的原理:
PKMS權限掃描
PackageManagerService執行systemReady()時,通過SystemConfig的readPermissionsFromXml()來掃描讀取/system/etc/permissions中的xml文件,包括platform.xml和系統支持的各種硬件模塊的feature主要工作:
[圖片上傳失敗...(image-cd0e9f-1624121551347)]
void readPermissions(File libraryDir, int permissionFlag) {
...
// Iterate over the files in the directory and scan .xml files
File platformFile = null;
for (File f : libraryDir.listFiles()) {
if (!f.isFile()) {
continue;
}
// 最後讀取platform.xml
if (f.getPath().endsWith("etc/permissions/platform.xml")) {
platformFile = f; continue; }
...
readPermissionsFromXml(f, permissionFlag);
}
// Read platform permissions last so it will take precedence
if (platformFile != null) {
readPermissionsFromXml(platformFile, permissionFlag);
}
}
解析xml的標籤節點,存入mGlobalGids、mPermissions、mSystemPermissions等成員變量中,供其他進行調用.
看下/system/etc/permissions/platform.xml的內容
<? xml version = "1.0" encoding="utf-8"?>
<permissions>
<permission name="android.permission.BLUETOOTH_ADMIN">
<group gid="net_bt_admin"/>
</permission>
<permission name="android.permission.INTERNET">
<group gid="inet"/>
</permission>
<permission name="android.permission.READ_LOGS">
<group gid="log"/>
</permission>...
<assign-permission name = "android.permission.MODIFY_AUDIO_SETTINGS" uid="media"/>
<assign- permission name = "android.permission.ACCESS_SURFACE_FLINGER" uid="media"/>
<assign- permission name = "android.permission.WAKE_LOCK"uid="media"/>
...
<split-permission name="android.permission.ACCESS_FINE_LOCATION">
<new-permission name="android.permission.ACCESS_COARSE_LOCATION" />
</split-permission>
<library name="android.test.base" file="/system/framework/android.test.base.jar" />
</permissions>
總結:權限掃描,掃描/system/etc/permissions中的xml,存入相應的結構體中,供之後權限管理使用
以上是PackageManagerService的主要源碼解析,當然還有很多細節沒有說到,看源碼先看主線,再去看看支線,可以對着源碼和這篇文章一起看看,能夠更加清晰明瞭。