PackageManagerService啟動原始碼分析

kc專欄發表於2015-05-06


瞭解了Android系統的啟動過程的讀者應該知道,Android的所有Java服務都是通過SystemServer程式啟動的,並且駐留在SystemServer程式中。SystemServer程式在啟動時,通過建立一個ServerThread執行緒來啟動所有服務,本文主要介紹Android服務中PackageManagerService服務啟動過程。首先介紹一些PackageManagerService服務下的相關類關係圖:


SystemServer程式的ServerThread執行緒中,執行以下程式碼啟動PackageManagerService服務:

  1. // 通過讀取屬性來判斷執行核心應用  
  2. String cryptState = SystemProperties.get("vold.decrypt");  
  3. boolean onlyCore = false;  
  4. if (ENCRYPTING_STATE.equals(cryptState)) {  
  5.     Slog.w(TAG, "Detected encryption in progress - only parsing core apps");  
  6.     onlyCore = true;  
  7. else if (ENCRYPTED_STATE.equals(cryptState)) {  
  8.     Slog.w(TAG, "Device encrypted - only parsing core apps");  
  9.     onlyCore = true;  
  10. }  
  11. //啟動PackageManagerService  
  12. pm = PackageManagerService.main(context,  
  13.         factoryTest != SystemServer.FACTORY_TEST_OFF,  
  14.         onlyCore);  
  15. boolean firstBoot = false;  
  16. //判斷PackageManagerService是否是第一次啟動,SystemServer程式被殺後會被重啟  
  17. try {  
  18.     firstBoot = pm.isFirstBoot();  
  19. catch (RemoteException e) {  
  20. }  
  21. //PackageManagerService執行dex優化  
  22. ...  
  23. try {  
  24.     pm.performBootDexOpt();  
  25. catch (Throwable e) {  
  26.     reportWtf("performing boot dexopt", e);  
  27. }  
// 通過讀取屬性來判斷執行核心應用
String cryptState = SystemProperties.get("vold.decrypt");
boolean onlyCore = false;
if (ENCRYPTING_STATE.equals(cryptState)) {
	Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
	onlyCore = true;
} else if (ENCRYPTED_STATE.equals(cryptState)) {
	Slog.w(TAG, "Device encrypted - only parsing core apps");
	onlyCore = true;
}
//啟動PackageManagerService
pm = PackageManagerService.main(context,
		factoryTest != SystemServer.FACTORY_TEST_OFF,
		onlyCore);
boolean firstBoot = false;
//判斷PackageManagerService是否是第一次啟動,SystemServer程式被殺後會被重啟
try {
	firstBoot = pm.isFirstBoot();
} catch (RemoteException e) {
}
//PackageManagerService執行dex優化
...
try {
	pm.performBootDexOpt();
} catch (Throwable e) {
	reportWtf("performing boot dexopt", e);
}

首先啟動PackageManagerService,然後判斷該服務是否是第一次啟動,接著執行dex優化。

  1. public static final IPackageManager main(Context context, boolean factoryTest,  
  2.         boolean onlyCore) {  
  3.     //構造PackageManagerService服務物件  
  4.     PackageManagerService m = new PackageManagerService(context, factoryTest, onlyCore);  
  5.     //註冊PackageManagerService服務  
  6.     ServiceManager.addService("package", m);  
  7.     return m;  
  8. }  
public static final IPackageManager main(Context context, boolean factoryTest,
		boolean onlyCore) {
	//構造PackageManagerService服務物件
	PackageManagerService m = new PackageManagerService(context, factoryTest, onlyCore);
	//註冊PackageManagerService服務
	ServiceManager.addService("package", m);
	return m;
}

啟動過程比較簡單,就是構造一個PackageManagerService物件,然後將該服務物件註冊到ServiceManger程式中,關於服務註冊過程請檢視Android服務註冊完整過程原始碼分析。PackageManagerService物件構造過程非常複雜,構造過程分幾個階段.

  1. //PackageManagerService啟動開始  
  2. EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,SystemClock.uptimeMillis());  
  3. //SDK版本檢查  
  4. if (mSdkVersion <= 0) {  
  5.     Slog.w(TAG, "**** ro.build.version.sdk not set!");  
  6. }  
  7. //讀取開機啟動模式  
  8. String mode = SystemProperties.get("ro.bootmode""mode");  
  9. engModeEnable = "engtest".equals(mode)?true:false;  
  10. Slog.i(TAG, "engModeEnable: " + engModeEnable + " ,mode:"+mode);  
  11. mContext = context;  
  12. mFactoryTest = factoryTest;//開機模式  
  13. mOnlyCore = onlyCore;//是否對包做dex優化  
  14. //如果編譯版本為eng,則不需要dex優化  
  15. mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));  
  16. //建立顯示尺寸資訊  
  17. mMetrics = new DisplayMetrics();  
  18. //儲存系統執行過程中的設定資訊  
  19. mSettings = new Settings();  
  20. /*建立SharedUserSetting物件並新增到Settings的成員變數mSharedUsers中,在Android系統中,多個package通過設定sharedUserId屬性可以執行在同一個程式,共享同一個UID*/  
  21. mSettings.addSharedUserLPw("android.uid.system",Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM);  
  22. mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ApplicationInfo.FLAG_SYSTEM);  
  23. mSettings.addSharedUserLPw("android.uid.log", LOG_UID, ApplicationInfo.FLAG_SYSTEM);  
  24. mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, ApplicationInfo.FLAG_SYSTEM);  
  25. String separateProcesses = SystemProperties.get("debug.separate_processes");  
  26. if (separateProcesses != null && separateProcesses.length() > 0) {  
  27.     if ("*".equals(separateProcesses)) {  
  28.         mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;  
  29.         mSeparateProcesses = null;  
  30.         Slog.w(TAG, "Running with debug.separate_processes: * (ALL)");  
  31.     } else {  
  32.         mDefParseFlags = 0;  
  33.         mSeparateProcesses = separateProcesses.split(",");  
  34.         Slog.w(TAG, "Running with debug.separate_processes: "  
  35.                 + separateProcesses);  
  36.     }  
  37. else {  
  38.     mDefParseFlags = 0;  
  39.     mSeparateProcesses = null;  
  40. }  
  41. mPreInstallDir = new File("/system/preloadapp");  
  42. //建立應用安裝器  
  43. mInstaller = new Installer();  
  44. //獲取螢幕尺寸大小  
  45. WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);  
  46. Display d = wm.getDefaultDisplay();  
  47. d.getMetrics(mMetrics);  
  48. synchronized (mInstallLock) {  
  49. // writer  
  50. synchronized (mPackages) {  
  51.     //啟動訊息處理執行緒  
  52.     mHandlerThread.start();  
  53.     //為訊息處理執行緒建立一個訊息分發handler  
  54.     mHandler = new PackageHandler(mHandlerThread.getLooper());  
  55.     // dataDir =/data/  
  56.     File dataDir = Environment.getDataDirectory();  
  57.     // mAppDataDir = /data/data  
  58.     mAppDataDir = new File(dataDir, "data");  
  59.     // mAsecInternalPath = /data/app-asec  
  60.     mAsecInternalPath = new File(dataDir, "app-asec").getPath();  
  61.     // mUserAppDataDir = /data/user  
  62.     mUserAppDataDir = new File(dataDir, "user");  
  63.     // mDrmAppPrivateInstallDir = /data/app-private  
  64.     mDrmAppPrivateInstallDir = new File(dataDir, "app-private");  
  65.     sUserManager = new UserManager(mInstaller, mUserAppDataDir);  
  66.     //讀取並解析/etc/permissions下的XML檔案  
  67.     readPermissions();  
  68.     mRestoredSettings = mSettings.readLPw(getUsers());  
//PackageManagerService啟動開始
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,SystemClock.uptimeMillis());
//SDK版本檢查
if (mSdkVersion <= 0) {
	Slog.w(TAG, "**** ro.build.version.sdk not set!");
}
//讀取開機啟動模式
String mode = SystemProperties.get("ro.bootmode", "mode");
engModeEnable = "engtest".equals(mode)?true:false;
Slog.i(TAG, "engModeEnable: " + engModeEnable + " ,mode:"+mode);
mContext = context;
mFactoryTest = factoryTest;//開機模式
mOnlyCore = onlyCore;//是否對包做dex優化
//如果編譯版本為eng,則不需要dex優化
mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
//建立顯示尺寸資訊
mMetrics = new DisplayMetrics();
//儲存系統執行過程中的設定資訊
mSettings = new Settings();
/*建立SharedUserSetting物件並新增到Settings的成員變數mSharedUsers中,在Android系統中,多個package通過設定sharedUserId屬性可以執行在同一個程式,共享同一個UID*/
mSettings.addSharedUserLPw("android.uid.system",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);
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;
}
mPreInstallDir = new File("/system/preloadapp");
//建立應用安裝器
mInstaller = new Installer();
//獲取螢幕尺寸大小
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
d.getMetrics(mMetrics);
synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
	//啟動訊息處理執行緒
	mHandlerThread.start();
	//為訊息處理執行緒建立一個訊息分發handler
	mHandler = new PackageHandler(mHandlerThread.getLooper());
	// dataDir =/data/
	File dataDir = Environment.getDataDirectory();
	// mAppDataDir = /data/data
	mAppDataDir = new File(dataDir, "data");
	// mAsecInternalPath = /data/app-asec
	mAsecInternalPath = new File(dataDir, "app-asec").getPath();
	// mUserAppDataDir = /data/user
	mUserAppDataDir = new File(dataDir, "user");
	// mDrmAppPrivateInstallDir = /data/app-private
	mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
	sUserManager = new UserManager(mInstaller, mUserAppDataDir);
	//讀取並解析/etc/permissions下的XML檔案
	readPermissions();
	mRestoredSettings = mSettings.readLPw(getUsers());
函式首先建立一個Settings物件,用來儲存一些設定資訊,然後呼叫addSharedUserLPw向Settings類的成員變數mSharedUsers中新增SharedUserSetting物件,在Android系統中,通過設定android:sharedUserId="android.uid.system"屬性可以為應用程式指定UID,SharedUserSetting物件儲存同一共享程式UID的所有包資訊,Settings物件用於管理Android系統執行過程中的一些設定資訊,Settings的成員變數mSharedUsers以鍵值對的方式儲存UID對應的SharedUserSetting物件。在Android系統中,可以通過在AndroidManifest.xml檔案中設定sharedUserId屬性來設定多個APK執行在同一個程式中。PackageManagerService的任務就是構造一些資料結構來儲存所有APK的配置資訊,關於Settings類之間的關係圖如下:


PackageSignatures來用來描述Android應用程式安裝包的簽名資訊,GrantedPermissions類用於描述應用APK的許可權資訊。Settings類的成員變數mSharedUsers是一個HashMap,用鍵值對的形式儲存所有的SharedUserSetting物件,SharedUserSetting物件用於記錄共享同一程式的所有APK資訊,該類的成員變數packages的型別為PackageSetting,用來儲存所有共享同一UID的包資訊,而成員變數userId則是記錄多個APK共享的UID。首先介紹Settings物件的構造過程:

  1. Settings() {  
  2.     //呼叫另外一個有參建構函式  
  3.     this(Environment.getDataDirectory());  
  4. }  
  5.   
  6. Settings(File dataDir) {  
  7.     //建立/data/system/目錄  
  8.     mSystemDir = new File(dataDir, "system");  
  9.     mSystemDir.mkdirs();  
  10.     //設定/data/system目錄的許可權  
  11.     FileUtils.setPermissions(mSystemDir.toString(),  
  12.             FileUtils.S_IRWXU|FileUtils.S_IRWXG  
  13.             |FileUtils.S_IROTH|FileUtils.S_IXOTH,  
  14.             -1, -1);  
  15.     //mSettingsFilename=/data/system/packages.xml  
  16.     mSettingsFilename = new File(mSystemDir, "packages.xml");  
  17.     //mBackupSettingsFilename=/data/system/packages-backup.xml  
  18.     mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");  
  19.     //mPackageListFilename=/data/system/packages.list  
  20.     mPackageListFilename = new File(mSystemDir, "packages.list");  
  21.     // Deprecated: Needed for migration  
  22.     //mStoppedPackagesFilename = /data/system/packages-stopped.xml  
  23.     mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");  
  24.     //mStoppedPackagesFilename = /data/system/packages-stopped-backup.xml  
  25.     mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");  
  26. }  
Settings() {
	//呼叫另外一個有參建構函式
	this(Environment.getDataDirectory());
}

Settings(File dataDir) {
	//建立/data/system/目錄
	mSystemDir = new File(dataDir, "system");
	mSystemDir.mkdirs();
	//設定/data/system目錄的許可權
	FileUtils.setPermissions(mSystemDir.toString(),
			FileUtils.S_IRWXU|FileUtils.S_IRWXG
			|FileUtils.S_IROTH|FileUtils.S_IXOTH,
			-1, -1);
	//mSettingsFilename=/data/system/packages.xml
	mSettingsFilename = new File(mSystemDir, "packages.xml");
	//mBackupSettingsFilename=/data/system/packages-backup.xml
	mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
	//mPackageListFilename=/data/system/packages.list
	mPackageListFilename = new File(mSystemDir, "packages.list");
	// Deprecated: Needed for migration
	//mStoppedPackagesFilename = /data/system/packages-stopped.xml
	mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
	//mStoppedPackagesFilename = /data/system/packages-stopped-backup.xml
	mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
}

Settings物件的構造過程很簡單,就是建立一些目錄和檔案。首先建立/data/system/目錄,然後分別建立以下四個檔案:

/data/system/packages.xml

/data/system/packages-backup.xml

/data/system/packages.list

/data/system/packages-stopped.xml

/data/system/packages-stopped-backup.xml

Settings通過addSharedUserLPw函式新增向mSharedUsers預先新增SharedUserSetting物件

  1. SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags) {  
  2.     //根據程式UID對應的名稱從成員變數mSharedUsers中查詢對應的SharedUserSetting物件  
  3.     SharedUserSetting s = mSharedUsers.get(name);  
  4.     //返回查詢到的結果  
  5.     if (s != null) {  
  6.         if (s.userId == uid) {  
  7.             return s;  
  8.         }  
  9.         PackageManagerService.reportSettingsProblem(Log.ERROR,  
  10.                 "Adding duplicate shared user, keeping first: " + name);  
  11.         return null;  
  12.     }  
  13.     //沒有查詢到對應的SharedUserSetting物件,則建立一個新的SharedUserSetting物件。  
  14.     s = new SharedUserSetting(name, pkgFlags);  
  15.     s.userId = uid;  
  16.     //新增到成員變數mUserIds,mOtherUserIds中,這兩個變數主要是加快查詢速度  
  17.     if (addUserIdLPw(uid, s, name)) {  
  18.         //新增到mSharedUsers表中  
  19.         mSharedUsers.put(name, s);  
  20.         return s;  
  21.     }  
  22.     return null;  
  23. }  
SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags) {
	//根據程式UID對應的名稱從成員變數mSharedUsers中查詢對應的SharedUserSetting物件
	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;
	}
	//沒有查詢到對應的SharedUserSetting物件,則建立一個新的SharedUserSetting物件。
	s = new SharedUserSetting(name, pkgFlags);
	s.userId = uid;
	//新增到成員變數mUserIds,mOtherUserIds中,這兩個變數主要是加快查詢速度
	if (addUserIdLPw(uid, s, name)) {
		//新增到mSharedUsers表中
		mSharedUsers.put(name, s);
		return s;
	}
	return null;
}

函式首先根據字串名稱從成員變數mSharedUsers雜湊表中查詢對應的SharedUserSetting物件,如果表中不存在對應的SharedUserSetting物件,則建立一個新的SharedUserSetting物件,並初始化該物件的域,然後根據UID的大小通過函式addUserIdLPw新增到mUserIds或mOtherUserIds中,同時以鍵值對的形式儲存在mSharedUsers中。

  1. private boolean addUserIdLPw(int uid, Object obj, Object name) {  
  2.     //判斷新增的UID是否大於19999  
  3.     if (uid > Process.LAST_APPLICATION_UID) {  
  4.         return false;  
  5.     }  
  6.     //判斷新增的UID是否大於等於10000  
  7.     if (uid >= Process.FIRST_APPLICATION_UID) {  
  8.         //計算在陣列中的索引為uid-10000  
  9.         int N = mUserIds.size();  
  10.         final int index = uid - Process.FIRST_APPLICATION_UID;  
  11.         while (index >= N) {  
  12.             mUserIds.add(null);  
  13.             N++;  
  14.         }  
  15.         if (mUserIds.get(index) != null) {  
  16.             PackageManagerService.reportSettingsProblem(Log.ERROR,  
  17.                     "Adding duplicate user id: " + uid  
  18.                     + " name=" + name);  
  19.             return false;  
  20.         }  
  21.         //新增的SharedUserSetting物件到mUserIds動態陣列中  
  22.         mUserIds.set(index, obj);  
  23.     } else {//將UID小於1000,則將SharedUserSetting物件新增到mOtherUserIds陣列中  
  24.         if (mOtherUserIds.get(uid) != null) {  
  25.             PackageManagerService.reportSettingsProblem(Log.ERROR,  
  26.                     "Adding duplicate shared id: " + uid  
  27.                     + " name=" + name);  
  28.             return false;  
  29.         }  
  30.         mOtherUserIds.put(uid, obj);  
  31.     }  
  32.     return true;  
  33. }  
private boolean addUserIdLPw(int uid, Object obj, Object name) {
	//判斷新增的UID是否大於19999
	if (uid > Process.LAST_APPLICATION_UID) {
		return false;
	}
	//判斷新增的UID是否大於等於10000
	if (uid >= Process.FIRST_APPLICATION_UID) {
		//計算在陣列中的索引為uid-10000
		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;
		}
		//新增的SharedUserSetting物件到mUserIds動態陣列中
		mUserIds.set(index, obj);
	} else {//將UID小於1000,則將SharedUserSetting物件新增到mOtherUserIds陣列中
		if (mOtherUserIds.get(uid) != null) {
			PackageManagerService.reportSettingsProblem(Log.ERROR,
					"Adding duplicate shared id: " + uid
					+ " name=" + name);
			return false;
		}
		mOtherUserIds.put(uid, obj);
	}
	return true;
}

Android定義了應用程式的UID範圍,對於非系統應用,UID介於10001999之間,而對於系統應用,UID小於1000

  1. public static final int SYSTEM_UID = 1000;  
  2. public static final int PHONE_UID = 1001;  
  3. public static final int SHELL_UID = 2000;  
  4. public static final int LOG_UID = 1007;  
  5. public static final int WIFI_UID = 1010;  
  6. public static final int MEDIA_UID = 1013;  
  7. public static final int DRM_UID = 1019;  
  8. public static final int SDCARD_RW_GID = 1015;  
  9. public static final int VPN_UID = 1016;  
  10. public static final int NFC_UID = 1027;  
  11. public static final int MEDIA_RW_GID = 1023;  
  12. //應用程式UID範圍  
  13. public static final int FIRST_APPLICATION_UID = 10000;  
  14. public static final int LAST_APPLICATION_UID = 19999;  
  15. //fully isolated sandboxed processes UID範圍  
  16. public static final int FIRST_ISOLATED_UID = 99000;  
  17. public static final int LAST_ISOLATED_UID = 99999;  
public static final int SYSTEM_UID = 1000;
public static final int PHONE_UID = 1001;
public static final int SHELL_UID = 2000;
public static final int LOG_UID = 1007;
public static final int WIFI_UID = 1010;
public static final int MEDIA_UID = 1013;
public static final int DRM_UID = 1019;
public static final int SDCARD_RW_GID = 1015;
public static final int VPN_UID = 1016;
public static final int NFC_UID = 1027;
public static final int MEDIA_RW_GID = 1023;
//應用程式UID範圍
public static final int FIRST_APPLICATION_UID = 10000;
public static final int LAST_APPLICATION_UID = 19999;
//fully isolated sandboxed processes UID範圍
public static final int FIRST_ISOLATED_UID = 99000;
public static final int LAST_ISOLATED_UID = 99999;

addUserIdLPw函式將UID介於10001999之間的SharedUserSetting物件新增到mUserIds陣列中,通過UID來索引陣列元素。



UID小於1000SharedUserSetting儲存到陣列mOtherUserIds中。回到PackageManagerService的建構函式中,通過Settings的addSharedUserLPw函式向mSharedUsers,mUserIds,mOtherUserIds陣列新增了4個特定程式的SharedUserSetting物件。


  1. mPreInstallDir = new File("/system/preloadapp");  
  2. //建立應用安裝器  
  3. mInstaller = new Installer();  
  4. //獲取螢幕尺寸大小  
  5. WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);  
  6. Display d = wm.getDefaultDisplay();  
  7. d.getMetrics(mMetrics);  
  8. synchronized (mInstallLock) {  
  9. // writer  
  10. synchronized (mPackages) {  
  11.     //啟動訊息處理執行緒  
  12.     mHandlerThread.start();  
  13.     //為訊息處理執行緒建立一個訊息分發handler  
  14.     mHandler = new PackageHandler(mHandlerThread.getLooper());  
  15.     // dataDir =/data/  
  16.     File dataDir = Environment.getDataDirectory();  
  17.     // mAppDataDir = /data/data  
  18.     mAppDataDir = new File(dataDir, "data");  
  19.     // mAsecInternalPath = /data/app-asec  
  20.     mAsecInternalPath = new File(dataDir, "app-asec").getPath();  
  21.     // mUserAppDataDir = /data/user  
  22.     mUserAppDataDir = new File(dataDir, "user");  
  23.     // mDrmAppPrivateInstallDir = /data/app-private  
  24.     mDrmAppPrivateInstallDir = new File(dataDir, "app-private");  
mPreInstallDir = new File("/system/preloadapp");
//建立應用安裝器
mInstaller = new Installer();
//獲取螢幕尺寸大小
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
d.getMetrics(mMetrics);
synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
	//啟動訊息處理執行緒
	mHandlerThread.start();
	//為訊息處理執行緒建立一個訊息分發handler
	mHandler = new PackageHandler(mHandlerThread.getLooper());
	// dataDir =/data/
	File dataDir = Environment.getDataDirectory();
	// mAppDataDir = /data/data
	mAppDataDir = new File(dataDir, "data");
	// mAsecInternalPath = /data/app-asec
	mAsecInternalPath = new File(dataDir, "app-asec").getPath();
	// mUserAppDataDir = /data/user
	mUserAppDataDir = new File(dataDir, "user");
	// mDrmAppPrivateInstallDir = /data/app-private
	mDrmAppPrivateInstallDir = new File(dataDir, "app-private");

首先建立Installer物件,用於訪問installd服務程式,完成一些apk安裝,解除安裝,優化工作。然後通過WindowManager得到螢幕尺寸資訊,接著啟動一個名為PackageManager的訊息執行緒,該執行緒是PackageManagerService的工作執行緒,mHandlerThread執行緒是一個帶訊息迴圈的工作執行緒,在定義該執行緒物件的時候就已經建立

  1. final HandlerThread mHandlerThread = new HandlerThread("PackageManager",Process.THREAD_PRIORITY_BACKGROUND);  
final HandlerThread mHandlerThread = new HandlerThread("PackageManager",Process.THREAD_PRIORITY_BACKGROUND);

同時為該訊息執行緒建立了一個訊息分發器PackageHandler物件,通過該handler物件可以往PackageManager執行緒傳送訊息,PackageManager執行緒通過訊息迴圈處理髮送進來的訊息,訊息處理過程如下:

  1. public void handleMessage(Message msg) {  
  2.     try {  
  3.         //直接呼叫doHandleMessage函式來處理各種訊息  
  4.         doHandleMessage(msg);  
  5.     } finally {  
  6.         Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
  7.     }  
  8. }  
public void handleMessage(Message msg) {
	try {
		//直接呼叫doHandleMessage函式來處理各種訊息
		doHandleMessage(msg);
	} finally {
		Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
	}
}

這裡暫時不介紹doHandleMessage函式,在介紹特定訊息時,在來分析該函式對各種訊息的處理過程。PackageManagerService的執行緒模型如下:




最後就是建立一些安裝目錄:

/system/preloadapp

/data/data

/data/app-asec

/data/user

/data/data

/data/app-private

建立使用者管理物件UserManager:

  1. sUserManager = new UserManager(mInstaller, mUserAppDataDir);  
sUserManager = new UserManager(mInstaller, mUserAppDataDir);

構造了一個UserManager,引數一為應用程式安裝器Installer,引數二為使用者安裝目錄/data/user

  1. public UserManager(Installer installer, File baseUserPath) {  
  2.     this(Environment.getDataDirectory(), baseUserPath);  
  3.     mInstaller = installer;  
  4.   }  
  5.     
  6.   UserManager(File dataDir, File baseUserPath) {  
  7.     // mUsersDir=/data/system/users  
  8.     mUsersDir = new File(dataDir, USER_INFO_DIR);  
  9.     mUsersDir.mkdirs();  
  10.     // userZeroDir=/data/system/users/0  
  11.     File userZeroDir = new File(mUsersDir, "0");  
  12.     userZeroDir.mkdirs();  
  13.     //mBaseUserPath=/data/user  
  14.     mBaseUserPath = baseUserPath;  
  15.     FileUtils.setPermissions(mUsersDir.toString(),  
  16.                    FileUtils.S_IRWXU|FileUtils.S_IRWXG  
  17.             |FileUtils.S_IROTH|FileUtils.S_IXOTH,  
  18.             -1, -1);  
  19.     // mUserListFile=/data/system/users/userlist.xml  
  20.     mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);  
  21.     readUserList();  
  22. }  
public UserManager(Installer installer, File baseUserPath) {
	this(Environment.getDataDirectory(), baseUserPath);
	mInstaller = installer;
  }
  
  UserManager(File dataDir, File baseUserPath) {
  	// mUsersDir=/data/system/users
	mUsersDir = new File(dataDir, USER_INFO_DIR);
	mUsersDir.mkdirs();
  	// userZeroDir=/data/system/users/0
	File userZeroDir = new File(mUsersDir, "0");
	userZeroDir.mkdirs();
	//mBaseUserPath=/data/user
	mBaseUserPath = baseUserPath;
	FileUtils.setPermissions(mUsersDir.toString(),
				   FileUtils.S_IRWXU|FileUtils.S_IRWXG
			|FileUtils.S_IROTH|FileUtils.S_IXOTH,
			-1, -1);
	// mUserListFile=/data/system/users/userlist.xml
	mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);
	readUserList();
}

構造過程比較簡單,就是建立幾個目錄和幾個檔案:

/data/system/users

/data/system/users/0

/data/system/users/userlist.xml

然後通過函式readUserList讀取使用者列表,這裡不在介紹該函式的實現,該函式就是從userlist.xml檔案中讀取使用者資訊,儲存到UserManager的成員變數mUsers中。

讀取許可權配置資訊:
  1. //讀取並解析/etc/permissions下的XML檔案  
  2. readPermissions();  
//讀取並解析/etc/permissions下的XML檔案
readPermissions();

函式首先呼叫readPermissions掃描讀取並解析/etc/permissions資料夾下的XML檔案,並將解析的資料儲存到PackageManagerService的成員變數中



  1. void readPermissions() {  
  2.     // Read permissions from .../etc/permission directory.  
  3.     File libraryDir = new File(Environment.getRootDirectory(), "etc/permissions");  
  4.     if (!libraryDir.exists() || !libraryDir.isDirectory()) {  
  5.         Slog.w(TAG, "No directory " + libraryDir + ", skipping");  
  6.         return;  
  7.     }  
  8.     if (!libraryDir.canRead()) {  
  9.         Slog.w(TAG, "Directory " + libraryDir + " cannot be read");  
  10.         return;  
  11.     }  
  12.     // 迴圈讀取etc/permissions目錄下的XML檔案  
  13.     for (File f : libraryDir.listFiles()) {  
  14.         // 跳過platform.xml檔案,最後讀取該檔案  
  15.         if (f.getPath().endsWith("etc/permissions/platform.xml")) {  
  16.             continue;  
  17.         }  
  18.         if (!f.getPath().endsWith(".xml")) {  
  19.             Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");  
  20.             continue;  
  21.         }  
  22.         if (!f.canRead()) {  
  23.             Slog.w(TAG, "Permissions library file " + f + " cannot be read");  
  24.             continue;  
  25.         }  
  26.         readPermissionsFromXml(f);  
  27.     }  
  28.     // Read permissions from .../etc/permissions/platform.xml last so it will take precedence  
  29.     final File permFile = new File(Environment.getRootDirectory(),"etc/permissions/platform.xml");  
  30.     readPermissionsFromXml(permFile);  
  31. }  
void readPermissions() {
	// 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;
	}
	// 迴圈讀取etc/permissions目錄下的XML檔案
	for (File f : libraryDir.listFiles()) {
		// 跳過platform.xml檔案,最後讀取該檔案
		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);
}
在etc/permissions目錄下儲存了一下配置檔案


這些檔案在編譯的時候直接從frameworks指定目錄下拷貝過來的,在特定product編譯目錄下的base.mk檔案中的配置如下:


函式readPermissionsFromXml使用PULL方式解析這些XML檔案,下面分別介紹各個標籤的解析過程。

feature標籤用來描述裝置應該支援的硬體特性。解析過程如下:

  1. else if ("feature".equals(name)) {  
  2.     //讀取熟悉name的值  
  3.     String fname = parser.getAttributeValue(null"name");  
  4.     if (fname == null) {  
  5.         Slog.w(TAG, "<feature> without name at "+ parser.getPositionDescription());  
  6.     } else {  
  7.         //建立一個FeatureInfo物件  
  8.         FeatureInfo fi = new FeatureInfo();  
  9.         fi.name = fname;  
  10.         //mAvailableFeatures是PackageManagerService的成員變數,以HashMap的方式儲存硬體支援的特性  
  11.         mAvailableFeatures.put(fname, fi);  
  12.     }  
  13.     XmlUtils.skipCurrentTag(parser);  
  14.     continue;  
  15. }  
else if ("feature".equals(name)) {
	//讀取熟悉name的值
	String fname = parser.getAttributeValue(null, "name");
	if (fname == null) {
		Slog.w(TAG, "<feature> without name at "+ parser.getPositionDescription());
	} else {
		//建立一個FeatureInfo物件
		FeatureInfo fi = new FeatureInfo();
		fi.name = fname;
		//mAvailableFeatures是PackageManagerService的成員變數,以HashMap的方式儲存硬體支援的特性
		mAvailableFeatures.put(fname, fi);
	}
	XmlUtils.skipCurrentTag(parser);
	continue;
}

library用於指定系統庫,當應用程式執行時,系統會為程式載入一些必要庫。該標籤的解析過程如下:

  1. else if ("library".equals(name)) {  
  2.     //讀取屬性name的值  
  3.     String lname = parser.getAttributeValue(null"name");  
  4.     //讀取屬性file的值  
  5.     String lfile = parser.getAttributeValue(null"file");  
  6.     if (lname == null) {  
  7.         Slog.w(TAG, "<library> without name at "+ parser.getPositionDescription());  
  8.     } else if (lfile == null) {  
  9.         Slog.w(TAG, "<library> without file at "+ parser.getPositionDescription());  
  10.     } else {  
  11.         //mSharedLibraries是PackageManagerService的成員變數,以HashMap的形式儲存程式執行庫  
  12.         mSharedLibraries.put(lname, lfile);  
  13.     }  
  14.     XmlUtils.skipCurrentTag(parser);  
  15.     continue;  
  16. }  
else if ("library".equals(name)) {
	//讀取屬性name的值
	String lname = parser.getAttributeValue(null, "name");
	//讀取屬性file的值
	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 {
		//mSharedLibraries是PackageManagerService的成員變數,以HashMap的形式儲存程式執行庫
		mSharedLibraries.put(lname, lfile);
	}
	XmlUtils.skipCurrentTag(parser);
	continue;
}

group標籤用於建立Android層與Linux層之間的許可權對映關係。

  1. else if ("permission".equals(name)) {  
  2.     //讀取屬性name的值  
  3.     String perm = parser.getAttributeValue(null"name");  
  4.     if (perm == null) {  
  5.         Slog.w(TAG, "<permission> without name at "+ parser.getPositionDescription());  
  6.         XmlUtils.skipCurrentTag(parser);  
  7.         continue;  
  8.     }  
  9.     perm = perm.intern();  
  10.     readPermission(parser, perm);  
  11. }   
  12.   
  13. void readPermission(XmlPullParser parser, String name)  
  14.         throws IOException, XmlPullParserException {  
  15.     name = name.intern();  
  16.     //根據name在mSettings.mPermissions表中查詢對應的BasePermission物件  
  17.     BasePermission bp = mSettings.mPermissions.get(name);  
  18.     //如果不存在,則建立一個新的BasePermission物件,並儲存到mSettings.mPermissions中  
  19.     if (bp == null) {  
  20.         bp = new BasePermission(name, null, BasePermission.TYPE_BUILTIN);  
  21.         mSettings.mPermissions.put(name, bp);  
  22.     }  
  23.     int outerDepth = parser.getDepth();  
  24.     int type;  
  25.     while ((type=parser.next()) != XmlPullParser.END_DOCUMENT  
  26.            && (type != XmlPullParser.END_TAG  
  27.                    || parser.getDepth() > outerDepth)) {  
  28.         if (type == XmlPullParser.END_TAG  
  29.                 || type == XmlPullParser.TEXT) {  
  30.             continue;  
  31.         }  
  32.         String tagName = parser.getName();  
  33.         //讀取標籤group的屬性gid值  
  34.         if ("group".equals(tagName)) {  
  35.             String gidStr = parser.getAttributeValue(null"gid");  
  36.             if (gidStr != null) {  
  37.                 //根據gid字串,找到對應的gid數值  
  38.                 int gid = Process.getGidForName(gidStr);  
  39.                 //設定BasePermission物件的gid值  
  40.                 bp.gids = appendInt(bp.gids, gid);  
  41.             } else {  
  42.                 Slog.w(TAG, "<group> without gid at "+ parser.getPositionDescription());  
  43.             }  
  44.         }  
  45.         XmlUtils.skipCurrentTag(parser);  
  46.     }  
  47. }  
else if ("permission".equals(name)) {
	//讀取屬性name的值
	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);
} 

void readPermission(XmlPullParser parser, String name)
		throws IOException, XmlPullParserException {
	name = name.intern();
	//根據name在mSettings.mPermissions表中查詢對應的BasePermission物件
	BasePermission bp = mSettings.mPermissions.get(name);
	//如果不存在,則建立一個新的BasePermission物件,並儲存到mSettings.mPermissions中
	if (bp == null) {
		bp = new BasePermission(name, null, BasePermission.TYPE_BUILTIN);
		mSettings.mPermissions.put(name, bp);
	}
	int outerDepth = parser.getDepth();
	int type;
	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();
		//讀取標籤group的屬性gid值
		if ("group".equals(tagName)) {
			String gidStr = parser.getAttributeValue(null, "gid");
			if (gidStr != null) {
				//根據gid字串,找到對應的gid數值
				int gid = Process.getGidForName(gidStr);
				//設定BasePermission物件的gid值
				bp.gids = appendInt(bp.gids, gid);
			} else {
				Slog.w(TAG, "<group> without gid at "+ parser.getPositionDescription());
			}
		}
		XmlUtils.skipCurrentTag(parser);
	}
}
assign-permission標籤將解析到的內容儲存到mSettings.mPermissions中
  1. else if ("assign-permission".equals(name)) {  
  2.      //讀取屬性name的值  
  3.     String perm = parser.getAttributeValue(null"name");  
  4.     if (perm == null) {  
  5.         Slog.w(TAG, "<assign-permission> without name at "+ parser.getPositionDescription());  
  6.         XmlUtils.skipCurrentTag(parser);  
  7.         continue;  
  8.     }  
  9.     //讀取屬性uid的值  
  10.     String uidStr = parser.getAttributeValue(null"uid");  
  11.     if (uidStr == null) {  
  12.         Slog.w(TAG, "<assign-permission> without uid at "+ parser.getPositionDescription());  
  13.         XmlUtils.skipCurrentTag(parser);  
  14.         continue;  
  15.     }  
  16.     //根據屬性uid字串轉換為uid數值  
  17.     int uid = Process.getUidForName(uidStr);  
  18.     if (uid < 0) {  
  19.         Slog.w(TAG, "<assign-permission> with unknown uid \""+ uidStr + "\" at "+ parser.getPositionDescription());  
  20.         XmlUtils.skipCurrentTag(parser);  
  21.         continue;  
  22.     }  
  23.     //儲存到mSystemPermissions表中  
  24.     perm = perm.intern();  
  25.     HashSet<String> perms = mSystemPermissions.get(uid);  
  26.     if (perms == null) {  
  27.         perms = new HashSet<String>();  
  28.         mSystemPermissions.put(uid, perms);  
  29.     }  
  30.     perms.add(perm);  
  31.     XmlUtils.skipCurrentTag(parser);  
  32. }   
else if ("assign-permission".equals(name)) {
	 //讀取屬性name的值
	String perm = parser.getAttributeValue(null, "name");
	if (perm == null) {
		Slog.w(TAG, "<assign-permission> without name at "+ parser.getPositionDescription());
		XmlUtils.skipCurrentTag(parser);
		continue;
	}
	//讀取屬性uid的值
	String uidStr = parser.getAttributeValue(null, "uid");
	if (uidStr == null) {
		Slog.w(TAG, "<assign-permission> without uid at "+ parser.getPositionDescription());
		XmlUtils.skipCurrentTag(parser);
		continue;
	}
	//根據屬性uid字串轉換為uid數值
	int uid = Process.getUidForName(uidStr);
	if (uid < 0) {
		Slog.w(TAG, "<assign-permission> with unknown uid \""+ uidStr + "\" at "+ parser.getPositionDescription());
		XmlUtils.skipCurrentTag(parser);
		continue;
	}
	//儲存到mSystemPermissions表中
	perm = perm.intern();
	HashSet<String> perms = mSystemPermissions.get(uid);
	if (perms == null) {
		perms = new HashSet<String>();
		mSystemPermissions.put(uid, perms);
	}
	perms.add(perm);
	XmlUtils.skipCurrentTag(parser);
} 

讀取安裝包資訊

/data/system/packages.xml檔案用於記錄系統中所安裝的Package資訊;/data/system/packages-backup.xml檔案是/data/packages.xml檔案的備份。在PackageManagerService掃描完目標資料夾後會建立該檔案,當系統進行程式安裝解除安裝時會更新該檔案。
/data/system/packages-stopped.xml檔案用於記錄系統中強制停止執行的Package資訊。/data/system/packages-stopped-backup.xml是/data/packages-stopped.xml檔案的備份。在強制停止某個應用時,會將應用相關資訊記錄到該檔案中。
/data/system/packages.list儲存系統中存在的所有非系統自帶的APK資訊,即UID大於1000的apk。


當系統第一次開機時,這些檔案並不存在,而在以後的開機中,掃描到的這些XML檔案是上一次執行過程中建立的。

  1. boolean readLPw(List<UserInfo> users) {  
  2.     FileInputStream str = null;  
  3.     //如果/data/system/packages-backup.xml檔案存在  
  4.     if (mBackupSettingsFilename.exists()) {  
  5.         try {  
  6.             //讀取/data/system/packages-backup.xml檔案  
  7.             str = new FileInputStream(mBackupSettingsFilename);  
  8.             mReadMessages.append("Reading from backup settings file\n");  
  9.             PackageManagerService.reportSettingsProblem(Log.INFO,"Need to read from backup settings file");  
  10.             //當/data/system/packages.xml檔案的備份檔案存在時,刪除packages.xml檔案  
  11.             if (mSettingsFilename.exists()) {  
  12.                 Slog.w(PackageManagerService.TAG, "Cleaning up settings file "+ mSettingsFilename);  
  13.                 mSettingsFilename.delete();  
  14.             }  
  15.         } catch (java.io.IOException e) {  
  16.             // We'll try for the normal settings file.  
  17.         }  
  18.     }  
  19.     mPendingPackages.clear();  
  20.     mPastSignatures.clear();  
  21.     try {  
  22.         //如果/data/system/packages-backup.xml檔案為空  
  23.         if (str == null) {  
  24.             //同時/data/system/packages.xml檔案不存在  
  25.             if (!mSettingsFilename.exists()) {  
  26.                 mReadMessages.append("No settings file found\n");  
  27.                 PackageManagerService.reportSettingsProblem(Log.INFO,  
  28.                         "No settings file; creating initial state");  
  29.                 //讀取/etc/preferred-apps目錄下的xml檔案  
  30.                 readDefaultPreferredAppsLPw();  
  31.                 return false;  
  32.             }  
  33.             //如果packages.xml的備份檔案為空,讀取packages.xml檔案內容  
  34.             str = new FileInputStream(mSettingsFilename);  
  35.         }  
  36.         //解析檔案內容  
  37.         XmlPullParser parser = Xml.newPullParser();  
  38.         parser.setInput(str, null);  
  39.         int type;  
  40.         while ((type = parser.next()) != XmlPullParser.START_TAG  
  41.                 && type != XmlPullParser.END_DOCUMENT) {  
  42.             ;  
  43.         }  
  44.         ...  
  45. }  
boolean readLPw(List<UserInfo> users) {
	FileInputStream str = null;
	//如果/data/system/packages-backup.xml檔案存在
	if (mBackupSettingsFilename.exists()) {
		try {
			//讀取/data/system/packages-backup.xml檔案
			str = new FileInputStream(mBackupSettingsFilename);
			mReadMessages.append("Reading from backup settings file\n");
			PackageManagerService.reportSettingsProblem(Log.INFO,"Need to read from backup settings file");
			//當/data/system/packages.xml檔案的備份檔案存在時,刪除packages.xml檔案
			if (mSettingsFilename.exists()) {
				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 {
		//如果/data/system/packages-backup.xml檔案為空
		if (str == null) {
			//同時/data/system/packages.xml檔案不存在
			if (!mSettingsFilename.exists()) {
				mReadMessages.append("No settings file found\n");
				PackageManagerService.reportSettingsProblem(Log.INFO,
						"No settings file; creating initial state");
				//讀取/etc/preferred-apps目錄下的xml檔案
				readDefaultPreferredAppsLPw();
				return false;
			}
			//如果packages.xml的備份檔案為空,讀取packages.xml檔案內容
			str = new FileInputStream(mSettingsFilename);
		}
		//解析檔案內容
		XmlPullParser parser = Xml.newPullParser();
		parser.setInput(str, null);
		int type;
		while ((type = parser.next()) != XmlPullParser.START_TAG
				&& type != XmlPullParser.END_DOCUMENT) {
			;
		}
		...
}

接下來檢測並優化BOOTCLASSPATH環境變數指定的Java執行庫及platform.xml中配置的Java庫,同時優化/system/framework目錄下的Jar包和apk檔案,最後刪除/data/dalvik-cache目錄下的一些快取檔案。在init.rc中配置的BOOTCLASSPATH如下:

  1. long startTime = SystemClock.uptimeMillis();  
  2. EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,startTime);  
  3. // 設定掃描模式  
  4. int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;  
  5. if (mNoDexOpt) {  
  6.     Slog.w(TAG, "Running ENG build: no pre-dexopt!");  
  7.     scanMode |= SCAN_NO_DEX;  
  8. }  
  9. //儲存庫檔案路徑  
  10. final HashSet<String> libFiles = new HashSet<String>();  
  11. //mFrameworkDir = /framework/  
  12. mFrameworkDir = new File(Environment.getRootDirectory(), "framework");  
  13. //mDalvikCacheDir = /data/dalvik-cache/  
  14. mDalvikCacheDir = new File(dataDir, "dalvik-cache");  
  15. boolean didDexOpt = false;  
  16. //通過屬性的方式得到啟動Java啟動類庫的路徑,在init.rc中通過BOOTCLASSPATH環境變數的方式設定  
  17. String bootClassPath = System.getProperty("java.boot.class.path");  
  18. if (bootClassPath != null) {  
  19.     String[] paths = splitString(bootClassPath, ':');  
  20.     for (int i=0; i<paths.length; i++) {  
  21.         try {  
  22.             //判斷Jar包是否需要dex優化  
  23.             if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) {  
  24.                 //如果需要則新增到libFiles表中  
  25.                 libFiles.add(paths[i]);  
  26.                 //通過安裝器請求installd服務程式執行dex優化  
  27.                 mInstaller.dexopt(paths[i], Process.SYSTEM_UID, true);  
  28.                 didDexOpt = true;  
  29.             }  
  30.         } catch (FileNotFoundException e) {  
  31.             Slog.w(TAG, "Boot class path not found: " + paths[i]);  
  32.         } catch (IOException e) {  
  33.             Slog.w(TAG, "Cannot dexopt " + paths[i] + "; is it an APK or JAR? "  
  34.                     + e.getMessage());  
  35.         }  
  36.     }  
  37. else {  
  38.     Slog.w(TAG, "No BOOTCLASSPATH found!");  
  39. }  
  40. //在前面解析platfor.xml時,將一些額外的類庫路徑儲存到了mSharedLibraries變數中  
  41. if (mSharedLibraries.size() > 0) {  
  42.     //迴圈變數mSharedLibraries變數  
  43.     Iterator<String> libs = mSharedLibraries.values().iterator();  
  44.     while (libs.hasNext()) {  
  45.         String lib = libs.next();  
  46.         try {  
  47.             //判斷Jar包是否需要dex優化  
  48.             if (dalvik.system.DexFile.isDexOptNeeded(lib)) {  
  49.                 //如果需要則新增到libFiles表中  
  50.                 libFiles.add(lib);  
  51.                 //通過安裝器進行dex優化  
  52.                 mInstaller.dexopt(lib, Process.SYSTEM_UID, true);  
  53.                 didDexOpt = true;  
  54.             }  
  55.         } catch (FileNotFoundException e) {  
  56.             Slog.w(TAG, "Library not found: " + lib);  
  57.         } catch (IOException e) {  
  58.             Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "  
  59.                     + e.getMessage());  
  60.         }  
  61.     }  
  62. }  
  63. //將/system/frameworks/framework-res.apk新增到libFiles中  
  64. libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");  
  65. //列出/system/frameworks目錄下的檔案  
  66. String[] frameworkFiles = mFrameworkDir.list();  
  67. if (frameworkFiles != null) {  
  68.     //遍歷/system/frameworks目錄下的檔案  
  69.     for (int i=0; i<frameworkFiles.length; i++) {  
  70.         File libPath = new File(mFrameworkDir, frameworkFiles[i]);  
  71.         String path = libPath.getPath();  
  72.         //判斷libFiles中是否已經包含該檔案,如果包含則跳過  
  73.         if (libFiles.contains(path)) {  
  74.             continue;  
  75.         }  
  76.         //跳過不是apk或jar檔案  
  77.         if (!path.endsWith(".apk") && !path.endsWith(".jar")) {  
  78.             continue;  
  79.         }  
  80.         try {  
  81.             //判斷Jar包或apk是否需要dex優化  
  82.             if (dalvik.system.DexFile.isDexOptNeeded(path)) {  
  83.                 //通過安裝器進行dex優化  
  84.                 mInstaller.dexopt(path, Process.SYSTEM_UID, true);  
  85.                 didDexOpt = true;  
  86.             }  
  87.         } catch (FileNotFoundException e) {  
  88.             Slog.w(TAG, "Jar not found: " + path);  
  89.         } catch (IOException e) {  
  90.             Slog.w(TAG, "Exception reading jar: " + path, e);  
  91.         }  
  92.     }  
  93. }  
  94. //如果前面對某個檔案做過優化,只要優化了,didDexOpt就被設定為true  
  95. if (didDexOpt) {  
  96.     //遍歷/data/dalvik-cache目錄下的檔案  
  97.     String[] files = mDalvikCacheDir.list();  
  98.     if (files != null) {  
  99.         for (int i=0; i<files.length; i++) {  
  100.             String fn = files[i];  
  101.             //刪除檔名以"data@app@"和"data@app-private@"開頭的檔案  
  102.             if (fn.startsWith("data@app@")  
  103.                     || fn.startsWith("data@app-private@")) {  
  104.                 Slog.i(TAG, "Pruning dalvik file: " + fn);  
  105.                 (new File(mDalvikCacheDir, fn)).delete();  
  106.             }  
  107.         }  
  108.     }  
  109. }  
long startTime = SystemClock.uptimeMillis();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,startTime);
// 設定掃描模式
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 = /framework/
mFrameworkDir = new File(Environment.getRootDirectory(), "framework");
//mDalvikCacheDir = /data/dalvik-cache/
mDalvikCacheDir = new File(dataDir, "dalvik-cache");
boolean didDexOpt = false;
//通過屬性的方式得到啟動Java啟動類庫的路徑,在init.rc中通過BOOTCLASSPATH環境變數的方式設定
String bootClassPath = System.getProperty("java.boot.class.path");
if (bootClassPath != null) {
	String[] paths = splitString(bootClassPath, ':');
	for (int i=0; i<paths.length; i++) {
		try {
			//判斷Jar包是否需要dex優化
			if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) {
				//如果需要則新增到libFiles表中
				libFiles.add(paths[i]);
				//通過安裝器請求installd服務程式執行dex優化
				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!");
}
//在前面解析platfor.xml時,將一些額外的類庫路徑儲存到了mSharedLibraries變數中
if (mSharedLibraries.size() > 0) {
	//迴圈變數mSharedLibraries變數
	Iterator<String> libs = mSharedLibraries.values().iterator();
	while (libs.hasNext()) {
		String lib = libs.next();
		try {
			//判斷Jar包是否需要dex優化
			if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
				//如果需要則新增到libFiles表中
				libFiles.add(lib);
				//通過安裝器進行dex優化
				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());
		}
	}
}
//將/system/frameworks/framework-res.apk新增到libFiles中
libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");
//列出/system/frameworks目錄下的檔案
String[] frameworkFiles = mFrameworkDir.list();
if (frameworkFiles != null) {
	//遍歷/system/frameworks目錄下的檔案
	for (int i=0; i<frameworkFiles.length; i++) {
		File libPath = new File(mFrameworkDir, frameworkFiles[i]);
		String path = libPath.getPath();
		//判斷libFiles中是否已經包含該檔案,如果包含則跳過
		if (libFiles.contains(path)) {
			continue;
		}
		//跳過不是apk或jar檔案
		if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
			continue;
		}
		try {
			//判斷Jar包或apk是否需要dex優化
			if (dalvik.system.DexFile.isDexOptNeeded(path)) {
				//通過安裝器進行dex優化
				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);
		}
	}
}
//如果前面對某個檔案做過優化,只要優化了,didDexOpt就被設定為true
if (didDexOpt) {
	//遍歷/data/dalvik-cache目錄下的檔案
	String[] files = mDalvikCacheDir.list();
	if (files != null) {
		for (int i=0; i<files.length; i++) {
			String fn = files[i];
			//刪除檔名以"data@app@"和"data@app-private@"開頭的檔案
			if (fn.startsWith("data@app@")
					|| fn.startsWith("data@app-private@")) {
				Slog.i(TAG, "Pruning dalvik file: " + fn);
				(new File(mDalvikCacheDir, fn)).delete();
			}
		}
	}
}
接著掃描系統apk資訊

  1. mFlagInstall = false;  
  2. //建立資料夾監控物件,監視/system/framework目錄  
  3. mFrameworkInstallObserver = new AppDirObserver(mFrameworkDir.getPath(), OBSERVER_EVENTS, true);  
  4. mFrameworkInstallObserver.startWatching();  
  5. //掃描/system/framework目錄下的apk檔案,掃描模式設定為非優化模式  
  6. scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR,scanMode | SCAN_NO_DEX, 0);  
  7. //在工廠模式下,呼叫函式scanDirLIOnly只掃描特定的apk檔案  
  8. if(engModeEnable){  
  9.     //temp null  
  10.     mVendorAppDir = null;  
  11.     mDrmAppInstallObserver = null;  
  12.     mSystemAppDir = null;  
  13.     mAppInstallObserver = null;  
  14.     mSystemInstallObserver = null;  
  15.     mPreInstallObserver = null;  
  16.     mVendorInstallObserver = null;  
  17.     mAppInstallDir = null;  
  18.     Slog.i(TAG, " begin scan the apps !");  
  19.     scanDirLIOnly(PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);  
  20.     Slog.i(TAG, " end scan the apps !");  
  21.     engModeEnable = false;  
  22. }else{//正常模式下  
  23.     //建立資料夾監控物件,監視/system/app目錄  
  24.     mSystemAppDir = new File(Environment.getRootDirectory(), "app");  
  25.     mSystemInstallObserver = new AppDirObserver(  
  26.         mSystemAppDir.getPath(), OBSERVER_EVENTS, true);  
  27.     mSystemInstallObserver.startWatching();  
  28.     //掃描/system/app目錄  
  29.     scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);  
  30.     //建立資料夾監控物件,監視/vendor/app目錄  
  31.     mVendorAppDir = new File("/vendor/app");  
  32.     mVendorInstallObserver = new AppDirObserver(  
  33.         mVendorAppDir.getPath(), OBSERVER_EVENTS, true);  
  34.     mVendorInstallObserver.startWatching();  
  35.     //掃描/vendor/app目錄  
  36.     scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);  
  37.   
  38.     if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");  
  39.     mInstaller.moveFiles();  
  40.     // Prune any system packages that no longer exist.  
  41.     final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();  
  42.     if (!mOnlyCore) {  
  43.         //遍歷Settings的成員變數mPackages  
  44.         Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();  
  45.         while (psit.hasNext()) {  
  46.             PackageSetting ps = psit.next();  
  47.             //不是系統app  
  48.             if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {  
  49.                 continue;  
  50.             }  
  51.             //如果是系統app,同時已經被PackageManagerService掃描過了  
  52.             final PackageParser.Package scannedPkg = mPackages.get(ps.name);  
  53.             if (scannedPkg != null) {  
  54.                 //該apk包已不能使用  
  55.                 if (mSettings.isDisabledSystemPackageLPr(ps.name)) {  
  56.                     Slog.i(TAG, "Expecting better updatd system app for " + ps.name  
  57.                             + "; removing system app");  
  58.                     //移除該apk包資訊  
  59.                     removePackageLI(scannedPkg, true);  
  60.                 }  
  61.                 continue;  
  62.             }  
  63.             if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {  
  64.                 psit.remove();  
  65.                 String msg = "System package " + ps.name  
  66.                         + " no longer exists; wiping its data";  
  67.                 reportSettingsProblem(Log.WARN, msg);  
  68.                 mInstaller.remove(ps.name, 0);  
  69.                 sUserManager.removePackageForAllUsers(ps.name);  
  70.             } else {  
  71.                 final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);  
  72.                 if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {  
  73.                     possiblyDeletedUpdatedSystemApps.add(ps.name);  
  74.                 }  
  75.             }  
  76.         }  
  77.     }  
  78.     //mAppInstallDir = /data/app/  
  79.     mAppInstallDir = new File(dataDir, "app");  
  80.     //查詢未完成安裝的apk包  
  81.     ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();  
  82.     //清除未完成安裝包  
  83.     for(int i = 0; i < deletePkgsList.size(); i++) {  
  84.         //clean up here  
  85.         cleanupInstallFailedPackage(deletePkgsList.get(i));  
  86.     }  
  87.     //刪除臨時檔案  
  88.     deleteTempPackageFiles();  
mFlagInstall = false;
//建立資料夾監控物件,監視/system/framework目錄
mFrameworkInstallObserver = new AppDirObserver(mFrameworkDir.getPath(), OBSERVER_EVENTS, true);
mFrameworkInstallObserver.startWatching();
//掃描/system/framework目錄下的apk檔案,掃描模式設定為非優化模式
scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR,scanMode | SCAN_NO_DEX, 0);
//在工廠模式下,呼叫函式scanDirLIOnly只掃描特定的apk檔案
if(engModeEnable){
	//temp null
	mVendorAppDir = null;
	mDrmAppInstallObserver = null;
	mSystemAppDir = null;
	mAppInstallObserver = null;
	mSystemInstallObserver = null;
	mPreInstallObserver = null;
	mVendorInstallObserver = null;
	mAppInstallDir = null;
	Slog.i(TAG, " begin scan the apps !");
	scanDirLIOnly(PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
	Slog.i(TAG, " end scan the apps !");
	engModeEnable = false;
}else{//正常模式下
	//建立資料夾監控物件,監視/system/app目錄
	mSystemAppDir = new File(Environment.getRootDirectory(), "app");
	mSystemInstallObserver = new AppDirObserver(
		mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
	mSystemInstallObserver.startWatching();
	//掃描/system/app目錄
	scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
	//建立資料夾監控物件,監視/vendor/app目錄
	mVendorAppDir = new File("/vendor/app");
	mVendorInstallObserver = new AppDirObserver(
		mVendorAppDir.getPath(), OBSERVER_EVENTS, true);
	mVendorInstallObserver.startWatching();
	//掃描/vendor/app目錄
	scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM| 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.
	final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
	if (!mOnlyCore) {
		//遍歷Settings的成員變數mPackages
		Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
		while (psit.hasNext()) {
			PackageSetting ps = psit.next();
			//不是系統app
			if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
				continue;
			}
			//如果是系統app,同時已經被PackageManagerService掃描過了
			final PackageParser.Package scannedPkg = mPackages.get(ps.name);
			if (scannedPkg != null) {
				//該apk包已不能使用
				if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
					Slog.i(TAG, "Expecting better updatd system app for " + ps.name
							+ "; removing system app");
					//移除該apk包資訊
					removePackageLI(scannedPkg, 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);
				mInstaller.remove(ps.name, 0);
				sUserManager.removePackageForAllUsers(ps.name);
			} else {
				final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
				if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
					possiblyDeletedUpdatedSystemApps.add(ps.name);
				}
			}
		}
	}
	//mAppInstallDir = /data/app/
	mAppInstallDir = new File(dataDir, "app");
	//查詢未完成安裝的apk包
	ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
	//清除未完成安裝包
	for(int i = 0; i < deletePkgsList.size(); i++) {
		//clean up here
		cleanupInstallFailedPackage(deletePkgsList.get(i));
	}
	//刪除臨時檔案
	deleteTempPackageFiles();

監控並掃描以下三個系統包安裝目錄:

/system/framework :該目錄下的檔案都是系統庫

/system/app :該目錄下是預設的系統應用

/vendor/app :該目錄下是廠商定製的應用

最後掃描非系統apk資訊

  1. if (!mOnlyCore) {  
  2.     //標識資料掃描開始  EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,SystemClock.uptimeMillis());  
  3.     //建立資料夾監控物件,監視/data/app/目錄  
  4.     mAppInstallObserver = new AppDirObserver(mAppInstallDir.getPath(), OBSERVER_EVENTS, false);  
  5.     mAppInstallObserver.startWatching();  
  6.     //掃描/data/app/目錄下的apk檔案  
  7.     scanDirLI(mAppInstallDir, 0, scanMode, 0);  
  8.     //建立資料夾監控物件,監視/system/preloadapp/目錄  
  9.     mPreInstallObserver = new AppDirObserver(mPreInstallDir.getPath(), OBSERVER_EVENTS, false);  
  10.     mPreInstallObserver.startWatching();  
  11.     //掃描/system/preloadapp/目錄下的apk檔案  
  12.     scanDirLI(mPreInstallDir, 0, scanMode, 0);  
  13.     //建立資料夾監控物件,監視/data/app-private/目錄  
  14.     mDrmAppInstallObserver = new AppDirObserver(mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);  
  15.     mDrmAppInstallObserver.startWatching();  
  16.     //掃描/data/app-private/目錄下的apk檔案  
  17.     scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,scanMode, 0);  
  18.     /** 
  19.      * Remove disable package settings for any updated system 
  20.      * apps that were removed via an OTA. If they're not a 
  21.      * previously-updated app, remove them completely. 
  22.      * Otherwise, just revoke their system-level permissions. 
  23.      */  
  24.     for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {  
  25.         PackageParser.Package deletedPkg = mPackages.get(deletedAppName);  
  26.         mSettings.removeDisabledSystemPackageLPw(deletedAppName);  
  27.         String msg;  
  28.         if (deletedPkg == null) {  
  29.             msg = "Updated system package " + deletedAppName+ " no longer exists; wiping its data";  
  30.             mInstaller.remove(deletedAppName, 0);  
  31.             sUserManager.removePackageForAllUsers(deletedAppName);  
  32.         } else {  
  33.             msg = "Updated system app + " + deletedAppName+ " no longer present; removing system privileges for "+ deletedAppName;  
  34.             deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;  
  35.             PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);  
  36.             deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;  
  37.         }  
  38.         reportSettingsProblem(Log.WARN, msg);  
  39.     }  
  40. else {  
  41.     mPreInstallObserver = null;  
  42.     mAppInstallObserver = null;  
  43.     mDrmAppInstallObserver = null;  
  44. }  
if (!mOnlyCore) {
	//標識資料掃描開始	EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,SystemClock.uptimeMillis());
	//建立資料夾監控物件,監視/data/app/目錄
	mAppInstallObserver = new AppDirObserver(mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
	mAppInstallObserver.startWatching();
	//掃描/data/app/目錄下的apk檔案
	scanDirLI(mAppInstallDir, 0, scanMode, 0);
	//建立資料夾監控物件,監視/system/preloadapp/目錄
	mPreInstallObserver = new AppDirObserver(mPreInstallDir.getPath(), OBSERVER_EVENTS, false);
	mPreInstallObserver.startWatching();
	//掃描/system/preloadapp/目錄下的apk檔案
	scanDirLI(mPreInstallDir, 0, scanMode, 0);
	//建立資料夾監控物件,監視/data/app-private/目錄
	mDrmAppInstallObserver = new AppDirObserver(mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
	mDrmAppInstallObserver.startWatching();
	//掃描/data/app-private/目錄下的apk檔案
	scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,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";
			mInstaller.remove(deletedAppName, 0);
			sUserManager.removePackageForAllUsers(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 {
	mPreInstallObserver = null;
	mAppInstallObserver = null;
	mDrmAppInstallObserver = null;
}

監控並掃描以下三個資料目錄:

/data/app/

/system/preloadapp/

/data/app-private/

最後進入結尾階段,將掃描到的資訊儲存到檔案中。

  1. mFlagInstall = true;  
  2. EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,SystemClock.uptimeMillis());  
  3. final boolean regrantPermissions = mSettings.mInternalSdkPlatform != mSdkVersion;  
  4. mSettings.mInternalSdkPlatform = mSdkVersion;  
  5. updatePermissionsLPw(nullnull, UPDATE_PERMISSIONS_ALL | (regrantPermissions  
  6.                 ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL): 0));  
  7. ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();  
  8. for (PreferredActivity pa : mSettings.mPreferredActivities.filterSet()) {  
  9.     if (mActivities.mActivities.get(pa.mPref.mComponent) == null) {  
  10.         removed.add(pa);  
  11.     }  
  12. }  
  13. for (int i=0; i<removed.size(); i++) {  
  14.     PreferredActivity pa = removed.get(i);  
  15.     Slog.w(TAG, "Removing dangling preferred activity: "  
  16.             + pa.mPref.mComponent);  
  17.     mSettings.mPreferredActivities.removeFilter(pa);  
  18. }  
  19. // can downgrade to reader  
  20. mSettings.writeLPr();  
  21.   
  22. EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,SystemClock.uptimeMillis());  
  23. Runtime.getRuntime().gc();  
  24. mRequiredVerifierPackage = getRequiredVerifierLPr();  
mFlagInstall = true;
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,SystemClock.uptimeMillis());
final boolean regrantPermissions = mSettings.mInternalSdkPlatform != mSdkVersion;
mSettings.mInternalSdkPlatform = mSdkVersion;
updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL | (regrantPermissions
				? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL): 0));
ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();
for (PreferredActivity pa : mSettings.mPreferredActivities.filterSet()) {
	if (mActivities.mActivities.get(pa.mPref.mComponent) == null) {
		removed.add(pa);
	}
}
for (int i=0; i<removed.size(); i++) {
	PreferredActivity pa = removed.get(i);
	Slog.w(TAG, "Removing dangling preferred activity: "
			+ pa.mPref.mComponent);
	mSettings.mPreferredActivities.removeFilter(pa);
}
// can downgrade to reader
mSettings.writeLPr();

EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,SystemClock.uptimeMillis());
Runtime.getRuntime().gc();
mRequiredVerifierPackage = getRequiredVerifierLPr();

至此,PackageManagerService就構造完成了,構造過程認為繁重,Apk檔案掃描解析耗費比較長的時間,這是導致開機速度慢的原因。



相關文章