了解了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); }
首先啟動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; }
啟動過程比較簡單,就是構造一個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());
函數首先創建一個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對象的構造過程很簡單,就是創建一些目錄和文件。首先創建/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; }
函數首先根據字符串名稱從成員變量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; }
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;
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");
首先創建Installer對象,用於訪問installd服務進程,完成一些apk安裝,卸載,優化工作。然后通過WindowManager得到屏幕尺寸信息,接着啟動一個名為PackageManager的消息線程,該線程是PackageManagerService的工作線程,mHandlerThread線程是一個帶消息循環的工作線程,在定義該線程對象的時候就已經創建
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); } }
這里暫時不介紹doHandleMessage函數,在介紹特定消息時,在來分析該函數對各種消息的處理過程。PackageManagerService的線程模型如下:
最后就是創建一些安裝目錄:
/system/preloadapp
/data/data
/data/app-asec
/data/user
/data/data
/data/app-private
創建用戶管理對象UserManager:
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(); }
構造過程比較簡單,就是創建幾個目錄和幾個文件:
/data/system/users
/data/system/users/0
/data/system/users/userlist.xml
然后通過函數readUserList讀取用戶列表,這里不在介紹該函數的實現,該函數就是從userlist.xml文件中讀取用戶信息,保存到UserManager的成員變量mUsers中。
讀取權限配置信息:
//讀取並解析/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); }
在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; }
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; }
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); } }
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); }
讀取安裝包信息
/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) { ; } ... }
接下來檢測並優化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(); } } } }
接着掃描系統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();
監控並掃描以下三個系統包安裝目錄:
/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; }
監控並掃描以下三個數據目錄:
/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();
至此,PackageManagerService就構造完成了,構造過程認為繁重,Apk文件掃描解析耗費比較長的時間,這是導致開機速度慢的原因。
@閱讀原文http://www.cnblogs.com/keanuyaoo/p/3306406.html