PackageManagerService啟動原始碼分析
瞭解了Android系統的啟動過程的讀者應該知道,Android的所有Java服務都是通過SystemServer程式啟動的,並且駐留在SystemServer程式中。SystemServer程式在啟動時,通過建立一個ServerThread執行緒來啟動所有服務,本文主要介紹Android服務中PackageManagerService服務啟動過程。首先介紹一些PackageManagerService服務下的相關類關係圖:
在SystemServer程式的ServerThread執行緒中,執行以下程式碼啟動PackageManagerService服務:
- // 通過讀取屬性來判斷執行核心應用
- 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);
- }
// 通過讀取屬性來判斷執行核心應用
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優化。
- 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;
- }
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物件構造過程非常複雜,構造過程分幾個階段.
- //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());
//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物件的構造過程:
- 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() {
//呼叫另外一個有參建構函式
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物件
- 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;
- }
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中。
- 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;
- }
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介於1000到1999之間,而對於系統應用,UID小於1000
- 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;
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介於1000到1999之間的SharedUserSetting物件新增到mUserIds陣列中,通過UID來索引陣列元素。
UID小於1000的SharedUserSetting儲存到陣列mOtherUserIds中。回到PackageManagerService的建構函式中,通過Settings的addSharedUserLPw函式向mSharedUsers,mUserIds,mOtherUserIds陣列新增了4個特定程式的SharedUserSetting物件。
- 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");
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執行緒是一個帶訊息迴圈的工作執行緒,在定義該執行緒物件的時候就已經建立
- final HandlerThread mHandlerThread = new HandlerThread("PackageManager",Process.THREAD_PRIORITY_BACKGROUND);
final HandlerThread mHandlerThread = new HandlerThread("PackageManager",Process.THREAD_PRIORITY_BACKGROUND);
同時為該訊息執行緒建立了一個訊息分發器PackageHandler物件,通過該handler物件可以往PackageManager執行緒傳送訊息,PackageManager執行緒通過訊息迴圈處理髮送進來的訊息,訊息處理過程如下:
- public void handleMessage(Message msg) {
- try {
- //直接呼叫doHandleMessage函式來處理各種訊息
- doHandleMessage(msg);
- } finally {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- }
- }
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:
- sUserManager = new UserManager(mInstaller, mUserAppDataDir);
sUserManager = new UserManager(mInstaller, mUserAppDataDir);
構造了一個UserManager,引數一為應用程式安裝器Installer,引數二為使用者安裝目錄/data/user
- 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();
- }
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中。
讀取許可權配置資訊:- //讀取並解析/etc/permissions下的XML檔案
- readPermissions();
//讀取並解析/etc/permissions下的XML檔案
readPermissions();
函式首先呼叫readPermissions掃描讀取並解析/etc/permissions資料夾下的XML檔案,並將解析的資料儲存到PackageManagerService的成員變數中
- 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);
- }
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標籤用來描述裝置應該支援的硬體特性。解析過程如下:
- 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;
- }
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用於指定系統庫,當應用程式執行時,系統會為程式載入一些必要庫。該標籤的解析過程如下:
- 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;
- }
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層之間的許可權對映關係。
- 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);
- }
- }
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中- 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);
- }
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檔案是上一次執行過程中建立的。
- 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) {
- ;
- }
- ...
- }
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如下:
- 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();
- }
- }
- }
- }
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資訊
- 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();
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資訊- 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;
- }
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/
最後進入結尾階段,將掃描到的資訊儲存到檔案中。- 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();
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檔案掃描解析耗費比較長的時間,這是導致開機速度慢的原因。
相關文章
- 【Android原始碼】PackageManagerService 淺析Android原始碼Package
- Flutter啟動流程原始碼分析Flutter原始碼
- apiserver原始碼分析——啟動流程APIServer原始碼
- Activity啟動流程原始碼分析原始碼
- Tomcat原始碼分析--啟動流程Tomcat原始碼
- JobTracker啟動流程原始碼級分析原始碼
- TOMCAT原始碼分析(啟動框架)Tomcat原始碼框架
- ThinkPHP6.0 原始碼分析之啟動分析PHP原始碼
- 以太坊原始碼分析(39)geth啟動流程分析原始碼
- RocketMQ中Producer的啟動原始碼分析MQ原始碼
- Android Activity啟動流程原始碼分析Android原始碼
- Spring啟動過程——原始碼分析Spring原始碼
- Flutter app啟動flutter端原始碼分析FlutterAPP原始碼
- jetty啟動web專案原始碼分析JettyWeb原始碼
- Android原始碼分析:Activity啟動流程Android原始碼
- Netty啟動流程及原始碼分析Netty原始碼
- APK安裝流程詳解6——PackageManagerService啟動前奏APKPackage
- Android 8.0 原始碼分析 (五) Service 啟動Android原始碼
- RocketMQ中Broker的啟動原始碼分析(一)MQ原始碼
- Android 8.0 原始碼分析 (四) Activity 啟動Android原始碼
- Spring Boot原始碼分析-啟動過程Spring Boot原始碼
- Netty NioEventLoop 啟動過程原始碼分析NettyOOP原始碼
- Spring MVC 啟動過程原始碼分析SpringMVC原始碼
- Apache Flink原始碼分析---JobManager啟動流程Apache原始碼
- spark core原始碼分析2 master啟動流程Spark原始碼AST
- spark core原始碼分析4 worker啟動流程Spark原始碼
- containerd 原始碼分析:啟動註冊流程AI原始碼
- SpringBoot啟動程式碼和自動裝配原始碼分析Spring Boot原始碼
- Android 8.0 原始碼分析 (六) BroadcastReceiver 啟動Android原始碼AST
- Android 8.0 原始碼分析 (一) SystemServer 程式啟動Android原始碼Server
- Netty原始碼分析(三):客戶端啟動Netty原始碼客戶端
- Netty原始碼分析(二):服務端啟動Netty原始碼服務端
- RocketMQ中PullConsumer的啟動原始碼分析MQ原始碼
- Giraph原始碼分析(二)—啟動Master/Worker服務原始碼AST
- Scrapy原始碼閱讀分析_2_啟動流程原始碼
- Android系統原始碼分析–Service啟動流程Android原始碼
- Egg.js 原始碼分析-專案啟動JS原始碼
- Sharding-JDBC 原始碼之啟動流程分析JDBC原始碼