| 
 | 
 
 
今天無意間找到這個文章,看了一下,寫得還是不錯的,轉載下,後面繼續學習。 
 
原文鏈接:http://blog.csdn.net/yangwen123/article/details/9464779 
 
瞭解了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介於10000到19999之間,而對於系統應用,UID小於10000- 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對象。
 
- <img src="http://www.tshopping.com.tw/forum.php?mod=image&aid=181194&size=300x300&key=0558a77bc94df9c2&nocache=yes&type=fixnone" border="0" aid="attachimg_181194" alt="">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掃瞄讀取並解析/etc/permissions文件夾下的XML文件,並將解析的數據保存到PackageManagerService的成員變量中 
 
- <img src="http://www.tshopping.com.tw/forum.php?mod=image&aid=181196&size=300x300&key=0bbd8668da995653&nocache=yes&type=fixnone" border="0" aid="attachimg_181196" alt="">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如下: 
 
- <img src="http://www.tshopping.com.tw/forum.php?mod=image&aid=181203&size=300x300&key=d53ac82dbd66612c&nocache=yes&type=fixnone" border="0" aid="attachimg_181203" alt="">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;
 
 - }
 
 
  複製代碼 i監控並掃瞄以下三個數據目錄: 
/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://blog.csdn.net/zhao_3546/article/details/12028271 
 
 |   
 
 
 
 |