PackageManagerService啟動及初始化流程
PackageManagerService也是有ServerThread啟動的,執行在system_process程序。
我們先來看下PackageManagerService是怎麼啟動的:
PackageManagerService的啟動需要四個引數,context上下文環境資訊由ActivityManagerService獲取,installer是一個安裝器,是對install程式的一個封裝,在new一個Installer之後會呼叫ping命令測試是否能連線的上install的服務端。
再來看一下PackageManagerService的初始化流程:
相關程式碼:
public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START, SystemClock.uptimeMillis()); if (mSdkVersion <= 0) { Slog.w(TAG, "**** ro.build.version.sdk not set!"); } mContext = context; mFactoryTest = factoryTest; mOnlyCore = onlyCore; mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type")); mMetrics = new DisplayMetrics(); mSettings = new Settings(context);//新建一個Settings結構 mSettings.addSharedUserLPw("android.uid.system", //新增一些使用者id Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM); mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ApplicationInfo.FLAG_SYSTEM); mSettings.addSharedUserLPw("android.uid.log", LOG_UID, ApplicationInfo.FLAG_SYSTEM); mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, ApplicationInfo.FLAG_SYSTEM); mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID, ApplicationInfo.FLAG_SYSTEM); String separateProcesses = SystemProperties.get("debug.separate_processes"); if (separateProcesses != null && separateProcesses.length() > 0) { if ("*".equals(separateProcesses)) { mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES; mSeparateProcesses = null; Slog.w(TAG, "Running with debug.separate_processes: * (ALL)"); } else { mDefParseFlags = 0; mSeparateProcesses = separateProcesses.split(","); Slog.w(TAG, "Running with debug.separate_processes: " + separateProcesses); } } else { mDefParseFlags = 0; mSeparateProcesses = null; } mInstaller = installer;//在ServerThread中建立,呼叫了其中的ping測試是否連上 WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);//獲取WINDOW_SERVICE Display d = wm.getDefaultDisplay();//獲取顯示引數 d.getMetrics(mMetrics); synchronized (mInstallLock) { // writer synchronized (mPackages) { mHandlerThread.start();//啟動訊息處理迴圈 mHandler = new PackageHandler(mHandlerThread.getLooper());//PackageHandler封裝了對訊息的處理 File dataDir = Environment.getDataDirectory();///data mAppDataDir = new File(dataDir, "data");//待檢測目錄/data/data mAppInstallDir = new File(dataDir, "app");///data/app mAppLibInstallDir = new File(dataDir, "app-lib");///data/app-lib mAsecInternalPath = new File(dataDir, "app-asec").getPath();///data/app-asec mUserAppDataDir = new File(dataDir, "user");///data/user mDrmAppPrivateInstallDir = new File(dataDir, "app-private");///data/app-private sUserManager = new UserManagerService(context, this, mInstallLock, mPackages);//建立一個UserManagerService readPermissions();//讀取許可權配置檔案中的資訊,儲存到全域性變數 mRestoredSettings = mSettings.readLPw(sUserManager.getUsers(false)); long startTime = SystemClock.uptimeMillis(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, startTime); // Set flag to monitor and not change apk file paths when // scanning install directories. int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;//設定掃描模式 if (mNoDexOpt) { Slog.w(TAG, "Running ENG build: no pre-dexopt!"); scanMode |= SCAN_NO_DEX; } final HashSet<String> libFiles = new HashSet<String>(); mFrameworkDir = new File(Environment.getRootDirectory(), "framework");///system/framework mDalvikCacheDir = new File(dataDir, "dalvik-cache");///data/dalvik-cache boolean didDexOpt = false; /** * Out of paranoia, ensure that everything in the boot class * path has been dexed. */ String bootClassPath = System.getProperty("java.boot.class.path");//所有在bootClassPath目錄的類已經優化了 if (bootClassPath != null) {//確保 boot路徑的class都被優化了 String[] paths = splitString(bootClassPath, ':'); for (int i=0; i<paths.length; i++) { try { if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) {//需要優化? libFiles.add(paths[i]); mInstaller.dexopt(paths[i], Process.SYSTEM_UID, true); didDexOpt = true; } } catch (FileNotFoundException e) { Slog.w(TAG, "Boot class path not found: " + paths[i]); } catch (IOException e) { Slog.w(TAG, "Cannot dexopt " + paths[i] + "; is it an APK or JAR? " + e.getMessage()); } } } else { Slog.w(TAG, "No BOOTCLASSPATH found!"); } /** * Also ensure all external libraries have had dexopt run on them. */ if (mSharedLibraries.size() > 0) {//確保 外部庫也被 優化 Iterator<String> libs = mSharedLibraries.values().iterator(); while (libs.hasNext()) { String lib = libs.next(); try { if (dalvik.system.DexFile.isDexOptNeeded(lib)) { libFiles.add(lib); mInstaller.dexopt(lib, Process.SYSTEM_UID, true); didDexOpt = true; } } catch (FileNotFoundException e) { Slog.w(TAG, "Library not found: " + lib); } catch (IOException e) { Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? " + e.getMessage()); } } } // Gross hack for now: we know this file doesn't contain any // code, so don't dexopt it to avoid the resulting log spew. libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");//framework-res.apk沒有包含程式碼,不需要優化 /** * And there are a number of commands implemented in Java, which * we currently need to do the dexopt on so that they can be * run from a non-root shell. */ String[] frameworkFiles = mFrameworkDir.list(); if (frameworkFiles != null) { for (int i=0; i<frameworkFiles.length; i++) {//優化/system/framework目錄下的檔案 File libPath = new File(mFrameworkDir, frameworkFiles[i]); String path = libPath.getPath(); // Skip the file if we alrady did it. if (libFiles.contains(path)) {//已經包含過,包含過的都優化了 continue; } // Skip the file if it is not a type we want to dexopt. if (!path.endsWith(".apk") && !path.endsWith(".jar")) {//跳過不符合條件的 continue; } try { if (dalvik.system.DexFile.isDexOptNeeded(path)) {//需要優化 mInstaller.dexopt(path, Process.SYSTEM_UID, true); didDexOpt = true; } } catch (FileNotFoundException e) { Slog.w(TAG, "Jar not found: " + path); } catch (IOException e) { Slog.w(TAG, "Exception reading jar: " + path, e); } } } if (didDexOpt) { // If we had to do a dexopt of one of the previous // things, then something on the system has changed. // Consider this significant, and wipe away all other // existing dexopt files to ensure we don't leave any // dangling around. String[] files = mDalvikCacheDir.list(); if (files != null) { for (int i=0; i<files.length; i++) { String fn = files[i]; if (fn.startsWith("data@app@") || fn.startsWith("data@app-private@")) { Slog.i(TAG, "Pruning dalvik file: " + fn); (new File(mDalvikCacheDir, fn)).delete(); } } } } // Find base frameworks (resource packages without code). mFrameworkInstallObserver = new AppDirObserver(//建立一個監察器監視/system/framework mFrameworkDir.getPath(), OBSERVER_EVENTS, true); mFrameworkInstallObserver.startWatching(); scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM//掃描該目錄下的所有apk,進行安裝 | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode | SCAN_NO_DEX, 0);//currentTime 為 0 SCAN_NO_DEX // Collect all system packages. mSystemAppDir = new File(Environment.getRootDirectory(), "app"); mSystemInstallObserver = new AppDirObserver(//監視/system/app mSystemAppDir.getPath(), OBSERVER_EVENTS, true); mSystemInstallObserver.startWatching(); scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM //掃描該目錄下的所有apk,進行安裝 | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0); // Collect all vendor packages. mVendorAppDir = new File("/vendor/app"); mVendorInstallObserver = new AppDirObserver(//監視/vendor/app mVendorAppDir.getPath(), OBSERVER_EVENTS, true); mVendorInstallObserver.startWatching(); scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM //掃描該目錄下的所有apk,進行安裝 | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0); if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands"); mInstaller.moveFiles(); // Prune any system packages that no longer exist.//去除不存在的系統packages final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>(); if (!mOnlyCore) { Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator(); while (psit.hasNext()) { PackageSetting ps = psit.next(); /* * If this is not a system app, it can't be a * disable system app. */ if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {//系統app continue; } /* * If the package is scanned, it's not erased. */ final PackageParser.Package scannedPkg = mPackages.get(ps.name); if (scannedPkg != null) { /* * If the system app is both scanned and in the * disabled packages list, then it must have been * added via OTA. Remove it from the currently * scanned package so the previously user-installed * application can be scanned. *///如果系統app剛被掃描並且在disabled列表,則它肯定是通過ota新增的,從當前掃描的package中移除它,所以以前使用者安裝的可以被掃描到 if (mSettings.isDisabledSystemPackageLPr(ps.name)) { Slog.i(TAG, "Expecting better updatd system app for " + ps.name + "; removing system app"); removePackageLI(ps, true); } continue; } if (!mSettings.isDisabledSystemPackageLPr(ps.name)) { psit.remove(); String msg = "System package " + ps.name + " no longer exists; wiping its data"; reportSettingsProblem(Log.WARN, msg); removeDataDirsLI(ps.name); } else { final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name); if (disabledPs.codePath == null || !disabledPs.codePath.exists()) { possiblyDeletedUpdatedSystemApps.add(ps.name); } } } } //look for any incomplete package installations未安裝完全的package ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr(); //clean up list for(int i = 0; i < deletePkgsList.size(); i++) { //clean up here cleanupInstallFailedPackage(deletePkgsList.get(i));//移除安裝失敗的package } //delete tmp files deleteTempPackageFiles();//移除臨時檔案 if (!mOnlyCore) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis()); mAppInstallObserver = new AppDirObserver( mAppInstallDir.getPath(), OBSERVER_EVENTS, false); mAppInstallObserver.startWatching();//監控/data/app目錄 scanDirLI(mAppInstallDir, 0, scanMode, 0);//掃描該目錄下的package mDrmAppInstallObserver = new AppDirObserver( //DRM,英文全稱Digital Rights Management, 可以翻譯為:內容數字版權加密保護技術 mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false); mDrmAppInstallObserver.startWatching();//監控/data/app-private目錄 scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,//掃描該目錄下的package scanMode, 0); /** * Remove disable package settings for any updated system * apps that were removed via an OTA. If they're not a * previously-updated app, remove them completely. * Otherwise, just revoke their system-level permissions. */ for (String deletedAppName : possiblyDeletedUpdatedSystemApps) { PackageParser.Package deletedPkg = mPackages.get(deletedAppName); mSettings.removeDisabledSystemPackageLPw(deletedAppName); String msg; if (deletedPkg == null) { msg = "Updated system package " + deletedAppName + " no longer exists; wiping its data"; removeDataDirsLI(deletedAppName); } else { msg = "Updated system app + " + deletedAppName + " no longer present; removing system privileges for " + deletedAppName; deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM; PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName); deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM; } reportSettingsProblem(Log.WARN, msg); } } else { mAppInstallObserver = null; mDrmAppInstallObserver = null; } EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, SystemClock.uptimeMillis()); Slog.i(TAG, "Time to scan packages: " + ((SystemClock.uptimeMillis()-startTime)/1000f) + " seconds"); // If the platform SDK has changed since the last time we booted, // we need to re-grant app permission to catch any new ones that // appear. This is really a hack, and means that apps can in some // cases get permissions that the user didn't initially explicitly // allow... it would be nice to have some better way to handle // this situation. final boolean regrantPermissions = mSettings.mInternalSdkPlatform != mSdkVersion; if (regrantPermissions) Slog.i(TAG, "Platform changed from " + mSettings.mInternalSdkPlatform + " to " + mSdkVersion + "; regranting permissions for internal storage"); mSettings.mInternalSdkPlatform = mSdkVersion; updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL //賦予package相應請求的許可權 | (regrantPermissions ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL) : 0)); // can downgrade to reader mSettings.writeLPr();//寫/data/system/packages.xml EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis()); // Now after opening every single application zip, make sure they // are all flushed. Not really needed, but keeps things nice and // tidy. Runtime.getRuntime().gc(); mRequiredVerifierPackage = getRequiredVerifierLPr(); } // synchronized (mPackages) } // synchronized (mInstallLock) }
PackageManagerService的初始化工作都是在它的建構函式中完成的,主要完成一下任務:
1、 新增一些使用者id,如system、phone等;
2、 建立並啟動PackageHandler訊息迴圈,用於處理apk安裝請求如adbinstall packageinstaller安裝apk時就會發送訊息;
3、 解析/system/etc/permission下的xml檔案,主要是platform.xml,建立permission和gid之間的關係,可以指定一個許可權與幾個組對應,當一個apk被授予這個許可權時它也同時屬於這幾個組,readPermission(parser, perm);給一些底層使用者分配一些許可權,如shell授予各種permission,把一個許可權賦予一個uid,當apk使用這個uid執行時,就具備了這個許可權系統增加的一些應用需要link的擴充套件的jar庫,系統每增加一個硬體,都要新增相應的featrue,將解析結果放入mAvailableFeatures;
4、 檢查/data/system/packages.xml是否存在,裡面記錄了系統的ppermission,以及每個apk的name,codePath,flags,ts,version,userid等,這些資訊主要是通過apk安裝的時候解析AndroidManifest.xml獲取到的,解析完apk後將更新資訊寫入這個檔案並儲存到flash,下次開機直接從裡面讀取相關資訊新增到記憶體相關列表中,當有apk安裝,升級,刪除時會更新這個檔案;
5、 檢查BootClassPath,mSharedLibraries及/system/framework下的jar是否需要dexopt,需要則通過dexopt進行優化,這裡面主要是呼叫mInstaller.dexopt進行相應的優化;
6、 建立java 層的installer 與c 層的installd 的socket 聯接,使得在上層的install,remove,dexopt等功能最終由installd在底層實現;
7、 啟動AppDirObserver執行緒往中監測/system/framework,/system/app,/data/app/data/app-private目錄的事件,主要監聽add和remove事件,對於目錄監聽底層通過innotify機制實現,inotify是一種檔案系統的變化通知機制如檔案增加、刪除等事件可以立刻讓使用者態得知,它為使用者態監視檔案系統的變化提供了強大的支援,當有add event時呼叫scanPackageLI(File,int,int)處理,當有remove event時呼叫removePackageLI處理;
8、 呼叫scanDirLI啟動apk解析,解析目錄包括:/system/framework、/system/app、/vendor/app、/data/app、/data/app-private;
9、 移除臨時檔案;
10、 賦予package相應請求的許可權;
11、 將解析出的Package的相關資訊儲存到相關全域性變數,還有檔案。
下面來分析前面每一步大概都做了些什麼:
一、新增使用者:
新增使用者呼叫的是Settings的addSharedUserLPw
SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags) {
SharedUserSetting s = mSharedUsers.get(name);
if (s != null) {
if (s.userId == uid) {
return s;
}
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Adding duplicate shared user, keeping first: " + name);
return null;
}
s = new SharedUserSetting(name, pkgFlags);//新建一個SharedUserSetting結構
s.userId = uid;
if (addUserIdLPw(uid, s, name)) {//儲存到mUserIds或mOtherUserIds
mSharedUsers.put(name, s);//新增到mSharedUsers
return s;
}
return null;
}
首先檢查mSharedUsers中是否有這個使用者,沒有的話則新建一個SharedUserSetting,呼叫addUserIdLPw儲存到mUserIds或mOtherUserIds,並新增到mSharedUsers。
private boolean addUserIdLPw(int uid, Object obj, Object name) {
if (uid > Process.LAST_APPLICATION_UID) {//大於應用程式最大pid
return false;
}
if (uid >= Process.FIRST_APPLICATION_UID) {//uid大於應用程式id的起始值
int N = mUserIds.size();
final int index = uid - Process.FIRST_APPLICATION_UID;
while (index >= N) {//先新增元素,後面設定值
mUserIds.add(null);
N++;
}
if (mUserIds.get(index) != null) {
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Adding duplicate user id: " + uid
+ " name=" + name);
return false;
}
mUserIds.set(index, obj);//把該uid和對應的PackageSetting儲存
} else {//系統使用者
if (mOtherUserIds.get(uid) != null) {
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Adding duplicate shared id: " + uid
+ " name=" + name);
return false;
}
mOtherUserIds.put(uid, obj);//新增到mOtherUserIds
}
return true;
}
二、建立並啟動PackageHandler訊息迴圈
PackageHandler用來處理安裝apk等過程中的各種訊息,後面降到apk安裝的時候會涉及到。
這個比較簡單,主要就新建一個PackageHandler,用來處理訊息。
三、解析/system/etc/permission下的xml檔案
主要是讀取並解析/etc/permissions的xml檔案,如我的平板上面:
看一下讀取的流程:
相關程式碼:
void readPermissions() {//從/etc/permission讀取許可權配置資訊
// Read permissions from .../etc/permission directory.
File libraryDir = new File(Environment.getRootDirectory(), "etc/permissions");
if (!libraryDir.exists() || !libraryDir.isDirectory()) {
Slog.w(TAG, "No directory " + libraryDir + ", skipping");
return;
}
if (!libraryDir.canRead()) {
Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
return;
}
// Iterate over the files in the directory and scan .xml files
for (File f : libraryDir.listFiles()) {
// We'll read platform.xml last
if (f.getPath().endsWith("etc/permissions/platform.xml")) {
continue;
}
if (!f.getPath().endsWith(".xml")) {
Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
continue;
}
if (!f.canRead()) {
Slog.w(TAG, "Permissions library file " + f + " cannot be read");
continue;
}
readPermissionsFromXml(f);
}
// Read permissions from .../etc/permissions/platform.xml last so it will take precedence
final File permFile = new File(Environment.getRootDirectory(),
"etc/permissions/platform.xml");//最後讀取
readPermissionsFromXml(permFile);
}
readPermissions先讀取除platform.xml的其他檔案,並呼叫readPermissionsFromXml進行解析,繼續看一下readPermissionsFromXml
private void readPermissionsFromXml(File permFile) {
FileReader permReader = null;
try {
permReader = new FileReader(permFile);
} catch (FileNotFoundException e) {
Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
return;
}
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(permReader);
XmlUtils.beginDocument(parser, "permissions");
while (true) {
XmlUtils.nextElement(parser);
if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
break;
}
String name = parser.getName();
if ("group".equals(name)) {
String gidStr = parser.getAttributeValue(null, "gid");
if (gidStr != null) {
int gid = Integer.parseInt(gidStr);
mGlobalGids = appendInt(mGlobalGids, gid);//儲存到mGlobalGids
} else {
Slog.w(TAG, "<group> without gid at "
+ parser.getPositionDescription());
}
XmlUtils.skipCurrentTag(parser);
continue;
} else if ("permission".equals(name)) {//定義了許可權和組id(gid)的關係,該組擁有什麼許可權
String perm = parser.getAttributeValue(null, "name");//許可權地名字
if (perm == null) {
Slog.w(TAG, "<permission> without name at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
perm = perm.intern();
readPermission(parser, perm);//進一步解析,解析結果儲存到 mSettings.mPermissions
} else if ("assign-permission".equals(name)) {//那一個uid都擁有什麼許可權(把什麼許可權賦予哪個uid)
String perm = parser.getAttributeValue(null, "name");//獲取許可權名
if (perm == null) {
Slog.w(TAG, "<assign-permission> without name at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
String uidStr = parser.getAttributeValue(null, "uid");//獲取使用者名稱
if (uidStr == null) {
Slog.w(TAG, "<assign-permission> without uid at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
int uid = Process.getUidForName(uidStr);//該使用者名稱對應的uid
if (uid < 0) {
Slog.w(TAG, "<assign-permission> with unknown uid \""
+ uidStr + "\" at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
perm = perm.intern();
HashSet<String> perms = mSystemPermissions.get(uid);//從mSystemPermissions查詢是否已為該uid分配許可權
if (perms == null) {
perms = new HashSet<String>();
mSystemPermissions.put(uid, perms);//新增到mSystemPermissions
}
perms.add(perm);//新增 該許可權
XmlUtils.skipCurrentTag(parser);
} else if ("library".equals(name)) {//系統共享庫
String lname = parser.getAttributeValue(null, "name");
String lfile = parser.getAttributeValue(null, "file");
if (lname == null) {
Slog.w(TAG, "<library> without name at "
+ parser.getPositionDescription());
} else if (lfile == null) {
Slog.w(TAG, "<library> without file at "
+ parser.getPositionDescription());
} else {
//Log.i(TAG, "Got library " + lname + " in " + lfile);
mSharedLibraries.put(lname, lfile);//新增到mSharedLibraries
}
XmlUtils.skipCurrentTag(parser);
continue;
} else if ("feature".equals(name)) {//系統特徵 (桌布等)
String fname = parser.getAttributeValue(null, "name");
if (fname == null) {
Slog.w(TAG, "<feature> without name at "
+ parser.getPositionDescription());
} else {
//Log.i(TAG, "Got feature " + fname);
FeatureInfo fi = new FeatureInfo();
fi.name = fname;
mAvailableFeatures.put(fname, fi);//新增到mAvailableFeatures
}
XmlUtils.skipCurrentTag(parser);
continue;
} else {
XmlUtils.skipCurrentTag(parser);
continue;
}
}
permReader.close();
} catch (XmlPullParserException e) {
Slog.w(TAG, "Got execption parsing permissions.", e);
} catch (IOException e) {
Slog.w(TAG, "Got execption parsing permissions.", e);
}
}
readPermissionsFromXml主要是:
1、讀取permission name新增到mSettings.mPermissions
2、讀取gid新增到mSettings.mPermissions
readPermissionsFromXml:
permission
a、讀取permission name新增到mSettings.mPermissions
b、讀取gid新增到mSettings.mPermissions
assign-permission
a、設定相應uid所具有的許可權,儲存到mSystemPermissions
library
a、.jar包儲存到mSharedLibraries
feature
a、 硬體相關資訊儲存到mAvailableFeatures
我們來看一下platform.xml:
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- This file is used to define the mappings between lower-level system
user and group IDs and the higher-level permission names managed
by the platform.
Be VERY careful when editing this file! Mistakes made here can open
big security holes.
-->
<permissions>
<!-- ================================================================== -->
<!-- ================================================================== -->
<!-- ================================================================== -->
<!-- The following tags are associating low-level group IDs with
permission names. By specifying such a mapping, you are saying
that any application process granted the given permission will
also be running with the given group ID attached to its process,
so it can perform any filesystem (read, write, execute) operations
allowed for that group. -->
<permission name="android.permission.BLUETOOTH_ADMIN" >
<group gid="net_bt_admin" />
</permission>
<permission name="android.permission.BLUETOOTH" >
<group gid="net_bt" />
</permission>
<permission name="android.permission.BLUETOOTH_STACK" >
<group gid="net_bt_stack" />
</permission>
<permission name="android.permission.NET_TUNNELING" >
<group gid="vpn" />
</permission>
<permission name="android.permission.INTERNET" >
<group gid="inet" />
</permission>
<permission name="android.permission.CAMERA" >
<group gid="camera" />
</permission>
<permission name="android.permission.READ_LOGS" >
<group gid="log" />
</permission>
<permission name="android.permission.READ_EXTERNAL_STORAGE" >
<group gid="sdcard_r" />
</permission>
<permission name="android.permission.WRITE_EXTERNAL_STORAGE" >
<group gid="sdcard_rw" />
</permission>
<permission name="android.permission.WRITE_MEDIA_STORAGE" >
<group gid="media_rw" />
</permission>
<permission name="android.permission.ACCESS_MTP" >
<group gid="mtp" />
</permission>
<permission name="android.permission.NET_ADMIN" >
<group gid="net_admin" />
</permission>
<!-- The group that /cache belongs to, linked to the permission
set on the applications that can access /cache -->
<permission name="android.permission.ACCESS_CACHE_FILESYSTEM" >
<group gid="cache" />
</permission>
<!-- RW permissions to any system resources owned by group 'diag'.
This is for carrier and manufacture diagnostics tools that must be
installable from the framework. Be careful. -->
<permission name="android.permission.DIAGNOSTIC" >
<group gid="input" />
<group gid="diag" />
</permission>
<!-- Group that can read detailed network usage statistics -->
<permission name="android.permission.READ_NETWORK_USAGE_HISTORY">
<group gid="net_bw_stats" />
</permission>
<!-- Group that can modify how network statistics are accounted -->
<permission name="android.permission.MODIFY_NETWORK_ACCOUNTING">
<group gid="net_bw_acct" />
</permission>
<!-- ================================================================== -->
<!-- ================================================================== -->
<!-- ================================================================== -->
<!-- The following tags are assigning high-level permissions to specific
user IDs. These are used to allow specific core system users to
perform the given operations with the higher-level framework. For
example, we give a wide variety of permissions to the shell user
since that is the user the adb shell runs under and developers and
others should have a fairly open environment in which to
interact with the system. -->
<!-- Standard permissions granted to the shell. -->
<assign-permission name="android.permission.WRITE_EXTERNAL_STORAGE" uid="shell" />
<assign-permission name="android.permission.SEND_SMS" uid="shell" />
<assign-permission name="android.permission.CALL_PHONE" uid="shell" />
<assign-permission name="android.permission.READ_CONTACTS" uid="shell" />
<assign-permission name="android.permission.WRITE_CONTACTS" uid="shell" />
<assign-permission name="android.permission.READ_CALENDAR" uid="shell" />
<assign-permission name="android.permission.WRITE_CALENDAR" uid="shell" />
<assign-permission name="android.permission.READ_USER_DICTIONARY" uid="shell" />
<assign-permission name="android.permission.WRITE_USER_DICTIONARY" uid="shell" />
<assign-permission name="android.permission.ACCESS_FINE_LOCATION" uid="shell" />
<assign-permission name="android.permission.ACCESS_COARSE_LOCATION" uid="shell" />
<assign-permission name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" uid="shell" />
<assign-permission name="android.permission.ACCESS_NETWORK_STATE" uid="shell" />
<assign-permission name="android.permission.ACCESS_WIFI_STATE" uid="shell" />
<assign-permission name="android.permission.BLUETOOTH" uid="shell" />
<!-- System tool permissions granted to the shell. -->
<assign-permission name="android.permission.GET_TASKS" uid="shell" />
<assign-permission name="android.permission.CHANGE_CONFIGURATION" uid="shell" />
<assign-permission name="android.permission.REORDER_TASKS" uid="shell" />
<assign-permission name="android.permission.SET_ANIMATION_SCALE" uid="shell" />
<assign-permission name="android.permission.SET_PREFERRED_APPLICATIONS" uid="shell" />
<assign-permission name="android.permission.WRITE_SETTINGS" uid="shell" />
<assign-permission name="android.permission.WRITE_SECURE_SETTINGS" uid="shell" />
<assign-permission name="android.permission.BROADCAST_STICKY" uid="shell" />
<!-- Development tool permissions granted to the shell. -->
<assign-permission name="android.permission.SET_DEBUG_APP" uid="shell" />
<assign-permission name="android.permission.SET_PROCESS_LIMIT" uid="shell" />
<assign-permission name="android.permission.SET_ALWAYS_FINISH" uid="shell" />
<assign-permission name="android.permission.DUMP" uid="shell" />
<assign-permission name="android.permission.SIGNAL_PERSISTENT_PROCESSES" uid="shell" />
<assign-permission name="android.permission.KILL_BACKGROUND_PROCESSES" uid="shell" />
<!-- Internal permissions granted to the shell. -->
<assign-permission name="android.permission.FORCE_BACK" uid="shell" />
<assign-permission name="android.permission.BATTERY_STATS" uid="shell" />
<assign-permission name="android.permission.INTERNAL_SYSTEM_WINDOW" uid="shell" />
<assign-permission name="android.permission.INJECT_EVENTS" uid="shell" />
<assign-permission name="android.permission.RETRIEVE_WINDOW_CONTENT" uid="shell" />
<assign-permission name="android.permission.SET_ACTIVITY_WATCHER" uid="shell" />
<assign-permission name="android.permission.READ_INPUT_STATE" uid="shell" />
<assign-permission name="android.permission.SET_ORIENTATION" uid="shell" />
<assign-permission name="android.permission.INSTALL_PACKAGES" uid="shell" />
<assign-permission name="android.permission.CLEAR_APP_USER_DATA" uid="shell" />
<assign-permission name="android.permission.DELETE_CACHE_FILES" uid="shell" />
<assign-permission name="android.permission.DELETE_PACKAGES" uid="shell" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="shell" />
<assign-permission name="android.permission.READ_FRAME_BUFFER" uid="shell" />
<assign-permission name="android.permission.DEVICE_POWER" uid="shell" />
<assign-permission name="android.permission.INSTALL_LOCATION_PROVIDER" uid="shell" />
<assign-permission name="android.permission.BACKUP" uid="shell" />
<assign-permission name="android.permission.FORCE_STOP_PACKAGES" uid="shell" />
<assign-permission name="android.permission.STOP_APP_SWITCHES" uid="shell" />
<assign-permission name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY" uid="shell" />
<assign-permission name="android.permission.GRANT_REVOKE_PERMISSIONS" uid="shell" />
<assign-permission name="android.permission.SET_KEYBOARD_LAYOUT" uid="shell" />
<assign-permission name="android.permission.GET_DETAILED_TASKS" uid="shell" />
<assign-permission name="android.permission.SET_SCREEN_COMPATIBILITY" uid="shell" />
<assign-permission name="android.permission.READ_EXTERNAL_STORAGE" uid="shell" />
<assign-permission name="android.permission.WRITE_EXTERNAL_STORAGE" uid="shell" />
<assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="shell" />
<assign-permission name="android.permission.INTERACT_ACROSS_USERS_FULL" uid="shell" />
<assign-permission name="android.permission.MANAGE_USERS" uid="shell" />
<assign-permission name="android.permission.BLUETOOTH_STACK" uid="shell" />
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
<assign-permission name="android.permission.ACCESS_DRM" uid="media" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />
<assign-permission name="android.permission.WAKE_LOCK" uid="media" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />
<!-- This is a list of all the libraries available for application
code to link against. -->
<library name="android.test.runner"
file="/system/framework/android.test.runner.jar" />
<library name="javax.obex"
file="/system/framework/javax.obex.jar"/>
</permissions>
這個檔案是模擬器上的,/etc/permissions下的其他檔案還有定義該硬體的特性等。
四、解析系統已經安裝的包
檢查/data/system/packages.xml是否存在,第一次開機的時候該檔案不存在,而以後每次系統如果有apk變動如新apk安裝、刪除、更新等,都會將相關資訊記錄到該檔案。這個會一定程度加快系統的啟動速度,但影響不大,先看一下流程圖:
這裡把有關setting相關的流程都畫出來的,apk資訊的讀取是通過readLPw來完成的。
boolean readLPw(List<UserInfo> users) {//packages-backup.xml存在則從它讀取,不存在在從packages.xml讀取
FileInputStream str = null;
if (mBackupSettingsFilename.exists()) {///data/system/packages-backup.xml存在
try {
str = new FileInputStream(mBackupSettingsFilename);
mReadMessages.append("Reading from backup settings file\n");
PackageManagerService.reportSettingsProblem(Log.INFO,
"Need to read from backup settings file");
if (mSettingsFilename.exists()) {///data/system/packages.xml也存在 則刪除它
// If both the backup and setutings file exist, we
// ignore the settings since it might have been
// corrupted.
Slog.w(PackageManagerService.TAG, "Cleaning up settings file "
+ mSettingsFilename);
mSettingsFilename.delete();
}
} catch (java.io.IOException e) {
// We'll try for the normal settings file.
}
}
mPendingPackages.clear();
mPastSignatures.clear();
try {
if (str == null) {///data/system/packages-backup.xml不存在
if (!mSettingsFilename.exists()) {//packages.xml不存在則返回
mReadMessages.append("No settings file found\n");
PackageManagerService.reportSettingsProblem(Log.INFO,
"No settings file; creating initial state");
readDefaultPreferredAppsLPw(0);
return false;
}
str = new FileInputStream(mSettingsFilename);//獲取一個輸入流/data/system/packages.xml
}
XmlPullParser parser = Xml.newPullParser();//新建一個xml解析器
parser.setInput(str, null);//設定解析器的輸入流
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG
&& type != XmlPullParser.END_DOCUMENT) {
;
}
if (type != XmlPullParser.START_TAG) {
mReadMessages.append("No start tag found in settings file\n");
PackageManagerService.reportSettingsProblem(Log.WARN,
"No start tag found in package manager settings");
Log.wtf(PackageManagerService.TAG,
"No start tag found in package manager settings");
return false;
}
int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (tagName.equals("package")) {//解析系統中存在的package,以及該包的一些相關資訊
readPackageLPw(parser);
} else if (tagName.equals("permissions")) {//解析系統定義了哪些許可權,由那個包定義的,構建BasePermission結構都新增到mPermissions
readPermissionsLPw(mPermissions, parser);
} else if (tagName.equals("permission-trees")) {
readPermissionsLPw(mPermissionTrees, parser);
} else if (tagName.equals("shared-user")) {//解析系統中可被使用者共享的一些uid所擁有的許可權
readSharedUserLPw(parser);
} else if (tagName.equals("preferred-packages")) {
// no longer used.
} else if (tagName.equals("preferred-activities")) {
// Upgrading from old single-user implementation;
// these are the preferred activities for user 0.
readPreferredActivitiesLPw(parser, 0);
} else if (tagName.equals("updated-package")) {//更新的apk
readDisabledSysPackageLPw(parser);
} else if (tagName.equals("cleaning-package")) {//刪除的apk
String name = parser.getAttributeValue(null, ATTR_NAME);
String userStr = parser.getAttributeValue(null, ATTR_USER);
String codeStr = parser.getAttributeValue(null, ATTR_CODE);
if (name != null) {
int userId = 0;
boolean andCode = true;
try {
if (userStr != null) {
userId = Integer.parseInt(userStr);
}
} catch (NumberFormatException e) {
}
if (codeStr != null) {
andCode = Boolean.parseBoolean(codeStr);
}
addPackageToCleanLPw(new PackageCleanItem(userId, name, andCode));
}
} else if (tagName.equals("renamed-package")) {//重新命名的apk
String nname = parser.getAttributeValue(null, "new");
String oname = parser.getAttributeValue(null, "old");
if (nname != null && oname != null) {
mRenamedPackages.put(nname, oname);
}
} else if (tagName.equals("last-platform-version")) {
mInternalSdkPlatform = mExternalSdkPlatform = 0;
try {
String internal = parser.getAttributeValue(null, "internal");//內部版本號
if (internal != null) {
mInternalSdkPlatform = Integer.parseInt(internal);
}
String external = parser.getAttributeValue(null, "external");//外部版本號
if (external != null) {
mExternalSdkPlatform = Integer.parseInt(external);
}
} catch (NumberFormatException e) {
}
} else if (tagName.equals("verifier")) {
final String deviceIdentity = parser.getAttributeValue(null, "device");
try {
mVerifierDeviceIdentity = VerifierDeviceIdentity.parse(deviceIdentity);
} catch (IllegalArgumentException e) {
Slog.w(PackageManagerService.TAG, "Discard invalid verifier device id: "
+ e.getMessage());
}
} else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) {
final String enforcement = parser.getAttributeValue(null, ATTR_ENFORCEMENT);
mReadExternalStorageEnforced = "1".equals(enforcement);
} else {
Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "
+ parser.getName());
XmlUtils.skipCurrentTag(parser);
}
}
str.close();
} catch (XmlPullParserException e) {
mReadMessages.append("Error reading: " + e.toString());
PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
Log.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);
} catch (java.io.IOException e) {
mReadMessages.append("Error reading: " + e.toString());
PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
Log.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);
}
final int N = mPendingPackages.size();//共享了uid的package
for (int i = 0; i < N; i++) {
final PendingPackage pp = mPendingPackages.get(i);//獲取PendingPackage結構
Object idObj = getUserIdLPr(pp.sharedId);//獲取被共享的uid的SharedUserSetting結構
if (idObj != null && idObj instanceof SharedUserSetting) {
PackageSetting p = getPackageLPw(pp.name, null, pp.realName, //新建一個PackageSetting結構
(SharedUserSetting) idObj, pp.codePath, pp.resourcePath,
pp.nativeLibraryPathString, pp.versionCode, pp.pkgFlags,
null, true /* add */, false /* allowInstall */); //add標誌為true,需要新增到mPackages
if (p == null) {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Unable to create application package for " + pp.name);
continue;
}
p.copyFrom(pp);//重新賦值該package的一些資訊(在前面解析的)
} else if (idObj != null) {
String msg = "Bad package setting: package " + pp.name + " has shared uid "
+ pp.sharedId + " that is not a shared uid\n";
mReadMessages.append(msg);
PackageManagerService.reportSettingsProblem(Log.ERROR, msg);
} else {
String msg = "Bad package setting: package " + pp.name + " has shared uid "
+ pp.sharedId + " that is not defined\n";
mReadMessages.append(msg);
PackageManagerService.reportSettingsProblem(Log.ERROR, msg);
}
}
mPendingPackages.clear();//所以的都處理完了,清空
if (mBackupStoppedPackagesFilename.exists()///data/system/packages-stopped-backup.xml
|| mStoppedPackagesFilename.exists()) { ///data/system/packages-stopped.xml
// Read old file
readStoppedLPw();
mBackupStoppedPackagesFilename.delete();
mStoppedPackagesFilename.delete();
// Migrate to new file format
writePackageRestrictionsLPr(0);
} else {
if (users == null) {
readPackageRestrictionsLPr(0);
} else {
for (UserInfo user : users) {
readPackageRestrictionsLPr(user.id);//讀取該user的限制
}
}
}
/*
* Make sure all the updated system packages have their shared users
* associated with them.
*///確保所有已更新的系統packages有他們的共享使用者關聯他們
final Iterator<PackageSetting> disabledIt = mDisabledSysPackages.values().iterator();
while (disabledIt.hasNext()) {
final PackageSetting disabledPs = disabledIt.next();
final Object id = getUserIdLPr(disabledPs.appId);
if (id != null && id instanceof SharedUserSetting) {
disabledPs.sharedUser = (SharedUserSetting) id;
}
}
mReadMessages.append("Read completed successfully: " + mPackages.size() + " packages, "
+ mSharedUsers.size() + " shared uids\n");
return true;
}
解析/data/system/packages.xml,看一下模擬器的已經啟動一次後的這個檔案
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<packages>
<last-platform-version internal="17" external="17" />
<permission-trees />
<permissions>
<item name="android.permission.CHANGE_WIFI_MULTICAST_STATE" package="android" protection="1" />
<item name="android.permission.WRITE_CALL_LOG" package="android" protection="1" />
<item name="android.permission.CLEAR_APP_CACHE" package="android" protection="1" />
<item name="android.permission.AUTHENTICATE_ACCOUNTS" package="android" protection="1" />
<item name="android.permission.ACCESS_WIMAX_STATE" package="android" />
<item name="android.permission.ASEC_ACCESS" package="android" protection="2" />
<item name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS" package="android" protection="1" />
<item name="android.permission.INTERNAL_SYSTEM_WINDOW" package="android" protection="2" />
<item name="android.permission.ACCESS_ALL_EXTERNAL_STORAGE" package="android" protection="2" />
<item name="android.permission.ACCESS_MOCK_LOCATION" package="android" protection="1" />
<item name="android.permission.ACCESS_NETWORK_STATE" package="android" />
<item name="android.permission.CHANGE_BACKGROUND_DATA_SETTING" package="android" protection="2" />
<item name="android.permission.GET_DETAILED_TASKS" package="android" protection="2" />
<item name="android.permission.MOVE_PACKAGE" package="android" protection="18" />
<item name="android.permission.FORCE_STOP_PACKAGES" package="android" protection="2" />
<item name="com.android.launcher.permission.UNINSTALL_SHORTCUT" package="com.android.launcher" protection="1" />
<item name="android.permission.DISABLE_KEYGUARD" package="android" protection="1" />
<item name="android.permission.READ_SYNC_STATS" package="android" />
<item name="android.permission.CONTROL_WIFI_DISPLAY" package="android" protection="2" />
<item name="android.permission.GLOBAL_SEARCH_CONTROL" package="android" protection="2" />
<item name="android.permission.READ_INPUT_STATE" package="android" protection="2" />
<item name="android.permission.WRITE_DREAM_STATE" package="android" protection="2" />
<item name="android.permission.START_ANY_ACTIVITY" package="android" protection="2" />
<item name="android.permission.REBOOT" package="android" protection="18" />
<item name="android.permission.BROADCAST_WAP_PUSH" package="android" protection="2" />
<item name="android.permission.WRITE_SMS" package="android" protection="1" />
<item name="android.permission.FILTER_EVENTS" package="android" protection="2" />
<item name="android.permission.STATUS_BAR" package="android" protection="18" />
<item name="android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED" package="com.android.providers.downloads" protection="18" />
<item name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" package="android" protection="18" />
<item name="android.permission.GLOBAL_SEARCH" package="android" protection="18" />
<item name="android.permission.STOP_APP_SWITCHES" package="android" protection="18" />
<item name="android.permission.BIND_VPN_SERVICE" package="android" protection="2" />
<item name="android.permission.MANAGE_APP_TOKENS" package="android" protection="2" />
<item name="android.permission.SET_KEYBOARD_LAYOUT" package="android" protection="2" />
<item name="android.permission.RETRIEVE_WINDOW_INFO" package="android" protection="2" />
<item name="android.permission.ASEC_CREATE" package="android" protection="2" />
<item name="android.permission.RECEIVE_EMERGENCY_BROADCAST" package="android" protection="18" />
<item name="android.permission.BIND_PACKAGE_VERIFIER" package="android" protection="2" />
<item name="android.permission.BATTERY_STATS" package="android" protection="1" />
<item name="android.permission.READ_PROFILE" package="android" protection="1" />
<item name="android.permission.COPY_PROTECTED_DATA" package="android" protection="2" />
<item name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" package="android" protection="1" />
<item name="android.permission.ASEC_RENAME" package="android" protection="2" />
<item name="com.android.alarm.permission.SET_ALARM" package="android" />
<item name="android.permission.MOUNT_FORMAT_FILESYSTEMS" package="android" protection="18" />
<item name="android.permission.SIGNAL_PERSISTENT_PROCESSES" package="android" protection="50" />
<item name="android.permission.MASTER_CLEAR" package="android" protection="18" />
<item name="android.permission.REMOTE_AUDIO_PLAYBACK" package="android" protection="2" />
<item name="android.permission.READ_CONTACTS" package="android" protection="1" />
<item name="android.permission.GET_ACCOUNTS" package="android" />
<item name="android.permission.RESTART_PACKAGES" package="android" />
<item name="android.permission.MANAGE_USERS" package="android" protection="18" />
<item name="android.permission.SEND_SMS_NO_CONFIRMATION" package="android" protection="18" />
<item name="android.permission.SUBSCRIBED_FEEDS_READ" package="android" />
<item name="android.permission.WAKE_LOCK" package="android" />
<item name="android.permission.RECEIVE_WAP_PUSH" package="android" protection="1" />
<item name="com.android.voicemail.permission.ADD_VOICEMAIL" package="android" protection="1" />
<item name="android.permission.INJECT_EVENTS" package="android" protection="2" />
<item name="android.permission.ACCOUNT_MANAGER" package="androi