(OK) Android PackageManagerService分析一:PMS的启动


http://blog.csdn.net/lilian0118/article/details/24455019


从这一章开始,我们来分析Android的PackageManagerService,后面简称PMS。PMS用来管理所有的package信息,包括安装、卸载、更新以及解析AndroidManifest.xml以组织相应的数据结构,这些数据结构将会被PMS、ActivityMangerService等等service和application使用到。PMS有几个比较重要的命令可以用于我们debug中:

adb shell dumpsys package   (dump出系统中所有的application信息)

adb shell dumpsys package “com.android.contacts" p  (dump出系统中特定包名的application信息)


首先来看SystemServer中PMS的构造以及注册:

  1.     pm = PackageManagerService.main(context, installer,  
  2.             factoryTest != SystemServer.FACTORY_TEST_OFF,  
  3.             onlyCore);  
  4.   
  5.     try {  
  6.         firstBoot = pm.isFirstBoot();  
  7.     } catch (RemoteException e) {  
  8.     }  
  9.   
  10. try {  
  11.     pm.performBootDexOpt();  
  12. catch (Throwable e) {  
  13.     reportWtf("performing boot dexopt", e);  
  14. }  
  15.   
  16. try {  
  17.     pm.systemReady();  
  18. catch (Throwable e) {  
  19.     reportWtf("making Package Manager Service ready", e);  
  20. }  

首先来看PMS的main方法:
  1. public static final IPackageManager main(Context context, Installer installer,  
  2.         boolean factoryTest, boolean onlyCore) {  
  3.     PackageManagerService m = new PackageManagerService(context, installer,  
  4.             factoryTest, onlyCore);  
  5.     ServiceManager.addService("package", m);  
  6.     return m;  
  7. }  

首先构造一个PMS对象,然后调用ServiceManager的addService注册这个服务。构造函数的第二个参数是一个Installer对象,用于和Installd通信使用,我们后面分析Installd再来介绍;第三个参数factoryTest为出厂测试,默认为false;第四个参数onlyCore与vold相关,我们以后再分析,这里也为false。PMS的构造函数比较长,我们首先来看一下大概的流程图,然后我们分段来分析代码:




  1. public PackageManagerService(Context context, Installer installer,  
  2.         boolean factoryTest, boolean onlyCore) {  
  3.   
  4.     mContext = context;  
  5.     mFactoryTest = factoryTest;  
  6.     mOnlyCore = onlyCore;  
  7.     mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));  
  8.     mMetrics = new DisplayMetrics();  
  9.     mSettings = new Settings(context);  
  10.     mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,  
  11.             ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);  
  12.     mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,  
  13.             ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);  
  14.     mSettings.addSharedUserLPw("android.uid.log", LOG_UID,  
  15.             ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);  
  16.     mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,  
  17.             ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);  
  18.     mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,  
  19.             ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);  
  20.     mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,  
  21.             ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);  

上面首先做一个变量的赋值,然后取出"ro.build.type"属性值,build版本分为user和eng两种,一种是面向user,一种是用于engineer debug版,这里假设mNoDexOpt为false。然后构造一个Settings对象,Settings是Android的全局管理者,用于协助PMS保存所有的安装包信息,PMS和Settings之间的类图关系如下:



来看一下Settings的构造函数:

  1. Settings(Context context) {  
  2.     this(context, Environment.getDataDirectory());  
  3. }  
  4.   
  5. Settings(Context context, File dataDir) {  
  6.     mContext = context;  
  7.     mSystemDir = new File(dataDir, "system");  
  8.     mSystemDir.mkdirs();  
  9.     FileUtils.setPermissions(mSystemDir.toString(),  
  10.             FileUtils.S_IRWXU|FileUtils.S_IRWXG  
  11.             |FileUtils.S_IROTH|FileUtils.S_IXOTH,  
  12.             -1, -1);  
  13.     mSettingsFilename = new File(mSystemDir, "packages.xml");  
  14.     mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");  
  15.     mPackageListFilename = new File(mSystemDir, "packages.list");  
  16.     FileUtils.setPermissions(mPackageListFilename, 0660, SYSTEM_UID, PACKAGE_INFO_GID);  
  17.   
  18.     mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");  
  19.     mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");  
  20. }  

Environment.getDataDirectory()返回/data目录,然后创建/data/system/目录,并设置它的权限,并在/data/system目录中创建mSettingsFilename、mBackupSettingsFilename、mPackageListFilename、mStoppedPackagesFilename和mBackupStoppedPackagesFilename几个文件。packages.xml就是保存了系统所有的Package信息,packages-backup.xml是packages.xml的备份,防止在写packages.xml突然断电等问题。回到PMS的构造函数,调用addSharedUserLPw将几种SharedUserId的名字和它对应的UID对应写到Settings当中。关于SharedUserId的使用,我们在后面介绍APK的安装过程中再来分析。这里先简单看一下Process中提供的UID列表:

  1. public static final int SYSTEM_UID = 1000;  
  2. public static final int PHONE_UID = 1001;  
  3. public static final int SHELL_UID = 2000;  
  4. public static final int LOG_UID = 1007;  
  5. public static final int WIFI_UID = 1010;  
  6. public static final int MEDIA_UID = 1013;  
  7. public static final int DRM_UID = 1019;  
  8. public static final int VPN_UID = 1016;  
  9. public static final int NFC_UID = 1027;  
  10. public static final int BLUETOOTH_UID = 1002;  
  11. public static final int MEDIA_RW_GID = 1023;  
  12. public static final int PACKAGE_INFO_GID = 1032;  
  13. public static final int FIRST_APPLICATION_UID = 10000;  
  14. public static final int LAST_APPLICATION_UID = 19999;  

上面定义了一系列的UID,其中applicantion的uid从10000开始到19999结束。来看addSharedUserLPw函数的实现:
  1. SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags) {  
  2.     SharedUserSetting s = mSharedUsers.get(name);  
  3.     if (s != null) {  
  4.         if (s.userId == uid) {  
  5.             return s;  
  6.         }  
  7.         PackageManagerService.reportSettingsProblem(Log.ERROR,  
  8.                 "Adding duplicate shared user, keeping first: " + name);  
  9.         return null;  
  10.     }  
  11.     s = new SharedUserSetting(name, pkgFlags);  
  12.     s.userId = uid;  
  13.     if (addUserIdLPw(uid, s, name)) {  
  14.         mSharedUsers.put(name, s);  
  15.         return s;  
  16.     }  
  17.     return null;  
  18. }  
  19.   
  20. private boolean addUserIdLPw(int uid, Object obj, Object name) {  
  21.     if (uid > Process.LAST_APPLICATION_UID) {  
  22.         return false;  
  23.     }  
  24.   
  25.     if (uid >= Process.FIRST_APPLICATION_UID) {  
  26.         int N = mUserIds.size();  
  27.         final int index = uid - Process.FIRST_APPLICATION_UID;  
  28.         while (index >= N) {  
  29.             mUserIds.add(null);  
  30.             N++;  
  31.         }  
  32.         if (mUserIds.get(index) != null) {  
  33.             PackageManagerService.reportSettingsProblem(Log.ERROR,  
  34.                     "Adding duplicate user id: " + uid  
  35.                     + " name=" + name);  
  36.             return false;  
  37.         }  
  38.         mUserIds.set(index, obj);  
  39.     } else {  
  40.         if (mOtherUserIds.get(uid) != null) {  
  41.             PackageManagerService.reportSettingsProblem(Log.ERROR,  
  42.                     "Adding duplicate shared id: " + uid  
  43.                     + " name=" + name);  
  44.             return false;  
  45.         }  
  46.         mOtherUserIds.put(uid, obj);  
  47.     }  
  48.     return true;  
  49. }  


mSharedUsers是一个HashMap,保存着所有的name和SharedUserSetting的映射关系。这里先调用addUserIdLPw将uid和SharedUserSetting添加到mOtherUserIds中,然后将name和SharedUserSetting添加到mSharedUsers中方便以后查找。接着来看PMS的构造函数:
  1. mInstaller = installer;  
  2.   
  3. WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);  
  4. Display d = wm.getDefaultDisplay();  
  5. d.getMetrics(mMetrics);  
  6.   
  7. synchronized (mInstallLock) {  
  8. // writer  
  9. synchronized (mPackages) {  
  10.     mHandlerThread.start();  
  11.     mHandler = new PackageHandler(mHandlerThread.getLooper());  
  12.     Watchdog.getInstance().addThread(mHandler, mHandlerThread.getName(),  
  13.             WATCHDOG_TIMEOUT);  
  14.   
  15.     File dataDir = Environment.getDataDirectory();  
  16.     mAppDataDir = new File(dataDir, "data");  
  17.     mAppInstallDir = new File(dataDir, "app");  
  18.     mAppLibInstallDir = new File(dataDir, "app-lib");  
  19.     mAsecInternalPath = new File(dataDir, "app-asec").getPath();  
  20.     mUserAppDataDir = new File(dataDir, "user");  
  21.     mDrmAppPrivateInstallDir = new File(dataDir, "app-private");  
  22.   
  23.     sUserManager = new UserManagerService(context, this,  
  24.             mInstallLock, mPackages);  
  25.   
  26.     readPermissions();  

上面首先获得显示屏的相关信息并保存在mMetrics中。然后启动“PackageManager”的HandleThread并绑定到PackageHandler上,这就是最后处理所有的跨进程消息的handler。接着调用readPermissions()来处理系统的permissions相关的文件。在/etc/permissions的文件大多来源于代码中的framworks/native/data/etc,这些文件的作用是表明系统支持的feature有哪些,例如是否支持蓝牙、wifi、P2P等。文件目录如下:

  1. android.hardware.bluetooth.xml
  2. android.hardware.bluetooth_le.xml
  3. android.hardware.camera.autofocus.xml
  4. android.hardware.camera.flash-autofocus.xml
  5. android.hardware.camera.front.xml
  6. android.hardware.camera.xml
  1. android.software.sip.xml
  2. com.android.nfc_extras.xml
  3. com.nxp.mifare.xml
  4. handheld_core_hardware.xml

这里的文件内容很简单,例如android.hardware.bluetooth.xml的内容如下:
  1. <permissions>  
  2.     <feature name="android.hardware.bluetooth" />  
  3. </permissions>  

在/etc/permissions中有一个platform.xml,它是来源于frameworks/base/data/etc/中,其中的内容大致如下:
  1. <permissions>  
  2.   
  3.     <permission name="android.permission.BLUETOOTH_ADMIN" >  
  4.         <group gid="net_bt_admin" />  
  5.     </permission>  
  6.   
  7.     <permission name="android.permission.BLUETOOTH" >  
  8.         <group gid="net_bt" />  
  9.     </permission>  
  10.   
  11.     <permission name="android.permission.BLUETOOTH_STACK" >  
  12.         <group gid="net_bt_stack" />  
  13.     </permission>  
  14.   
  15.     <permission name="android.permission.NET_TUNNELING" >  
  16.         <group gid="vpn" />  
  17.     </permission>  
  18.   
  19.     <permission name="android.permission.INTERNET" >  
  20.         <group gid="inet" />  
  21.     </permission>  
  22.   
  23.     <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />  
  24.     <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />  
  25.     <assign-permission name="android.permission.WAKE_LOCK" uid="media" />  
  26.     <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="media" />  
  27.     <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="media" />  
  28.   
  29.     <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />  
  30.   
  31.   
  32.     <library name="android.test.runner"  
  33.             file="/system/framework/android.test.runner.jar" />  
  34.     <library name="javax.obex"  
  35.             file="/system/framework/javax.obex.jar"/>  

现在来看readPermissions()的实现:
  1. void readPermissions() {  
  2.     File libraryDir = new File(Environment.getRootDirectory(), "etc/permissions");  
  3.     if (!libraryDir.exists() || !libraryDir.isDirectory()) {  
  4.         Slog.w(TAG, "No directory " + libraryDir + ", skipping");  
  5.         return;  
  6.     }  
  7.     if (!libraryDir.canRead()) {  
  8.         Slog.w(TAG, "Directory " + libraryDir + " cannot be read");  
  9.         return;  
  10.     }  
  11.   
  12.     for (File f : libraryDir.listFiles()) {  
  13.         if (f.getPath().endsWith("etc/permissions/platform.xml")) {  
  14.             continue;  
  15.         }  
  16.   
  17.         if (!f.getPath().endsWith(".xml")) {  
  18.             Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");  
  19.             continue;  
  20.         }  
  21.         if (!f.canRead()) {  
  22.             Slog.w(TAG, "Permissions library file " + f + " cannot be read");  
  23.             continue;  
  24.         }  
  25.   
  26.         readPermissionsFromXml(f);  
  27.     }  
  28.   
  29.     // Read permissions from .../etc/permissions/platform.xml last so it will take precedence  
  30.     final File permFile = new File(Environment.getRootDirectory(),  
  31.             "etc/permissions/platform.xml");  
  32.     readPermissionsFromXml(permFile);  
  33. }  

首先不断的读出/etc/permissions下面的文件,并依此处理除了platform.xml以外的其它xml文件,并最后处理platform.xml文件,来看readPermissionsFromXml()的实现,这个函数比较长,我们主要看处理feature、permission、assign-permission和library的代码:
  1. private void readPermissionsFromXml(File permFile) {  
  2.         FileReader permReader = null;  
  3.         try {  
  4.             permReader = new FileReader(permFile);  
  5.         } catch (FileNotFoundException e) {  
  6.         }  
  7.   
  8.         try {  
  9.             XmlPullParser parser = Xml.newPullParser();  
  10.             parser.setInput(permReader);  
  11.   
  12.             XmlUtils.beginDocument(parser, "permissions");  
  13.   
  14.             while (true) {  
  15.                 XmlUtils.nextElement(parser);  
  16.                 if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {  
  17.                     break;  
  18.                 }  
  19.   
  20.                 String name = parser.getName();  
  21.                 if ("group".equals(name)) {  
  22.   
  23.                 } else if ("permission".equals(name)) {  
  24.                     String perm = parser.getAttributeValue(null"name");  
  25.                     if (perm == null) {  
  26.                         Slog.w(TAG, "<permission> without name at "  
  27.                                 + parser.getPositionDescription());  
  28.                         XmlUtils.skipCurrentTag(parser);  
  29.                         continue;  
  30.                     }  
  31.                     perm = perm.intern();  
  32.                     readPermission(parser, perm);  
  33.   
  34.                 } else if ("assign-permission".equals(name)) {  
  35.                     String perm = parser.getAttributeValue(null"name");  
  36.                     String uidStr = parser.getAttributeValue(null"uid");  
  37.                     if (uidStr == null) {  
  38.                         Slog.w(TAG, "<assign-permission> without uid at "  
  39.                                 + parser.getPositionDescription());  
  40.                         XmlUtils.skipCurrentTag(parser);  
  41.                         continue;  
  42.                     }  
  43.                     int uid = Process.getUidForName(uidStr);  
  44.                     perm = perm.intern();  
  45.                     HashSet<String> perms = mSystemPermissions.get(uid);  
  46.                     if (perms == null) {  
  47.                         perms = new HashSet<String>();  
  48.                         mSystemPermissions.put(uid, perms);  
  49.                     }  
  50.                     perms.add(perm);  
  51.                     XmlUtils.skipCurrentTag(parser);  
  52.   
  53.                 } else if ("library".equals(name)) {  
  54.                     String lname = parser.getAttributeValue(null"name");  
  55.                     String lfile = parser.getAttributeValue(null"file");  
  56.                     if (lname == null) {  
  57.   
  58.                     } else if (lfile == null) {  
  59.   
  60.                     } else {  
  61.                         mSharedLibraries.put(lname, new SharedLibraryEntry(lfile, null));  
  62.                     }  
  63.                     XmlUtils.skipCurrentTag(parser);  
  64.                     continue;  
  65.   
  66.                 } else if ("feature".equals(name)) {  
  67.                     String fname = parser.getAttributeValue(null"name");  
  68.                     if (fname == null) {  
  69.   
  70.                     } else {  
  71.                         FeatureInfo fi = new FeatureInfo();  
  72.                         fi.name = fname;  
  73.                         mAvailableFeatures.put(fname, fi);  
  74.                     }  
  75.                     XmlUtils.skipCurrentTag(parser);  
  76.                     continue;  
  77.   
  78.                 } else {  
  79.                     XmlUtils.skipCurrentTag(parser);  
  80.                     continue;  
  81.                 }  
  82.   
  83.             }  
  84.             permReader.close();  
  85.         } catch (XmlPullParserException e) {  
  86.             Slog.w(TAG, "Got execption parsing permissions.", e);  
  87.         } catch (IOException e) {  
  88.             Slog.w(TAG, "Got execption parsing permissions.", e);  
  89.         }  
  90.     }  

首先来看处理feature这个tag的代码,在fname中保存feature的名字,然后创建一个FeatureInfo,并把fname和FeatureInfo保存到mAvailableFeatures这个HashMap中。接着来看处理permission tag,首先读出permission的name,然后调用readPermission去处理后面的group信息:
  1. void readPermission(XmlPullParser parser, String name)  
  2.         throws IOException, XmlPullParserException {  
  3.   
  4.     name = name.intern();  
  5.   
  6.     BasePermission bp = mSettings.mPermissions.get(name);  
  7.     if (bp == null) {  
  8.         bp = new BasePermission(name, null, BasePermission.TYPE_BUILTIN);  
  9.         mSettings.mPermissions.put(name, bp);  
  10.     }  
  11.     int outerDepth = parser.getDepth();  
  12.     int type;  
  13.     while ((type=parser.next()) != XmlPullParser.END_DOCUMENT  
  14.            && (type != XmlPullParser.END_TAG  
  15.                    || parser.getDepth() > outerDepth)) {  
  16.         if (type == XmlPullParser.END_TAG  
  17.                 || type == XmlPullParser.TEXT) {  
  18.             continue;  
  19.         }  
  20.   
  21.         String tagName = parser.getName();  
  22.         if ("group".equals(tagName)) {  
  23.             String gidStr = parser.getAttributeValue(null"gid");  
  24.             if (gidStr != null) {  
  25.                 int gid = Process.getGidForName(gidStr);  
  26.                 bp.gids = appendInt(bp.gids, gid);  
  27.             } else {  
  28.                 Slog.w(TAG, "<group> without gid at "  
  29.                         + parser.getPositionDescription());  
  30.             }  
  31.         }  
  32.         XmlUtils.skipCurrentTag(parser);  
  33.     }  
  34. }  

在readPermission中首先构造BasePermission对象,并把name和BasePermission一起添加到Settings的mPermissions这个HashMap中。Android管理权限的机制其实就是对应相应的permission,用一个gid号来描述,当一个应用程序请求这个permission的时候,就把这个gid号添加到对应的application中去。Process.getGidForName方法通过JNI调用getgrnam系统函数去获取相应的组名称所对应的gid号,并把它添加到BasePermission对象的gids数组中。再来看处理assign-permission这个tag的代码,首先读出permission的名字和uid,保存在perm和uidStr中,Process.getUidForName方法通过JNI调用getpwnam系统函数获取相应的用户名所对应的uid号,并把刚解析的permission名添加到HashSet当中,最后把上面的uid和hashset添加到mSystemPermissions这个数组中。最后来看处理library这个tag的代码,这里把解析处理的library名字和路径保存在mSharedLibraries这个hashMap中。再回到PMS的构造函数中,接着往下来看:
  1. mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),  
  2.         mSdkVersion, mOnlyCore);  
  3.   
  4. String customResolverActivity = Resources.getSystem().getString(  
  5.         R.string.config_customResolverActivity);  
  6. if (TextUtils.isEmpty(customResolverActivity)) {  
  7.     customResolverActivity = null;  
  8. else {  
  9.     mCustomResolverComponentName = ComponentName.unflattenFromString(  
  10.             customResolverActivity);  
  11. }  
  12.   
  13. long startTime = SystemClock.uptimeMillis();  
  14.   
  15. int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;  
  16. if (mNoDexOpt) {  
  17.     Slog.w(TAG, "Running ENG build: no pre-dexopt!");  
  18.     scanMode |= SCAN_NO_DEX;  
  19. }  
  20.   
  21. final HashSet<String> alreadyDexOpted = new HashSet<String>();  
  22.   
  23. String bootClassPath = System.getProperty("java.boot.class.path");  
  24. if (bootClassPath != null) {  
  25.     String[] paths = splitString(bootClassPath, ':');  
  26.     for (int i=0; i<paths.length; i++) {  
  27.         alreadyDexOpted.add(paths[i]);  
  28.     }  
  29. else {  
  30.     Slog.w(TAG, "No BOOTCLASSPATH found!");  
  31. }  
  32.   
  33. boolean didDexOpt = false;  
  34.   
  35. if (mSharedLibraries.size() > 0) {  
  36.     Iterator<SharedLibraryEntry> libs = mSharedLibraries.values().iterator();  
  37.     while (libs.hasNext()) {  
  38.         String lib = libs.next().path;  
  39.         if (lib == null) {  
  40.             continue;  
  41.         }  
  42.         try {  
  43.             if (dalvik.system.DexFile.isDexOptNeeded(lib)) {  
  44.                 alreadyDexOpted.add(lib);  
  45.                 mInstaller.dexopt(lib, Process.SYSTEM_UID, true);  
  46.                 didDexOpt = true;  
  47.             }  
  48.         } catch (FileNotFoundException e) {  
  49.             Slog.w(TAG, "Library not found: " + lib);  
  50.         } catch (IOException e) {  
  51.             Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "  
  52.                     + e.getMessage());  
  53.         }  
  54.     }  
  55. }  


这里首先调用Settings的readLPw函数去解析packages.xml和packages-backup.xml保存的安装列表信息,并把解析的pakcages信息添加到相应的数据结构中,这里我们先假设这是第一次开机,所有packages.xml和packages-backup.xml文件都还不存在。所以Settings的readLPw函数会直接返回。接着把boot class path里面的文件添加到alreadyDexOpted这个HashSet中,因为它们在zygote启动时已经进过Dex优化了。接着扫描mSharedLibraries中的文件,这些文件是在解析platfrom.xml中的library tag添加进来的,如果它们需要做dex优化,则调用Installd的的dexopt方法,关于installd的调用流程,我们后面在安装apk的时候再来分析。接着来看PMS的构造函数:

  1. File frameworkDir = new File(Environment.getRootDirectory(), "framework");  
  2. alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");  
  3.   
  4. alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar");  
  5.   
  6. String[] frameworkFiles = frameworkDir.list();  
  7. if (frameworkFiles != null) {  
  8.     for (int i=0; i<frameworkFiles.length; i++) {  
  9.         File libPath = new File(frameworkDir, frameworkFiles[i]);  
  10.         String path = libPath.getPath();  
  11.         if (alreadyDexOpted.contains(path)) {  
  12.             continue;  
  13.         }  
  14.         if (!path.endsWith(".apk") && !path.endsWith(".jar")) {  
  15.             continue;  
  16.         }  
  17.         try {  
  18.             if (dalvik.system.DexFile.isDexOptNeeded(path)) {  
  19.                 mInstaller.dexopt(path, Process.SYSTEM_UID, true);  
  20.                 didDexOpt = true;  
  21.             }  
  22.         } catch (FileNotFoundException e) {  
  23.             Slog.w(TAG, "Jar not found: " + path);  
  24.         } catch (IOException e) {  
  25.             Slog.w(TAG, "Exception reading jar: " + path, e);  
  26.         }  
  27.     }  
  28. }  
  29.   
  30. if (didDexOpt) {  
  31.     File dalvikCacheDir = new File(dataDir, "dalvik-cache");  
  32.   
  33.     String[] files = dalvikCacheDir.list();  
  34.     if (files != null) {  
  35.         for (int i=0; i<files.length; i++) {  
  36.             String fn = files[i];  
  37.             if (fn.startsWith("data@app@")  
  38.                     || fn.startsWith("data@app-private@")) {  
  39.                 Slog.i(TAG, "Pruning dalvik file: " + fn);  
  40.                 (new File(dalvikCacheDir, fn)).delete();  
  41.             }  
  42.         }  
  43.     }  
  44. }  

这里扫描所有的/system/framework下面除framework-res以外的apk和jar包(因为framework-res只有resource文件),然后依次对它们做Dex优化。在上面如果有对文件做过Dex优化,就要去删除dalvi-cache下面所有的dex文件,以防止cache文件和现在的文件不相符。接着来看PMS的构造函数:
  1. mFrameworkInstallObserver = new AppDirObserver(  
  2.     frameworkDir.getPath(), OBSERVER_EVENTS, truefalse);  
  3. mFrameworkInstallObserver.startWatching();  
  4. scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM  
  5.         | PackageParser.PARSE_IS_SYSTEM_DIR  
  6.         | PackageParser.PARSE_IS_PRIVILEGED,  
  7.         scanMode | SCAN_NO_DEX, 0);  
  8.   
  9. // Collected privileged system packages.  
  10. File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");  
  11. mPrivilegedInstallObserver = new AppDirObserver(  
  12.         privilegedAppDir.getPath(), OBSERVER_EVENTS, truetrue);  
  13. mPrivilegedInstallObserver.startWatching();  
  14.     scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM  
  15.             | PackageParser.PARSE_IS_SYSTEM_DIR  
  16.             | PackageParser.PARSE_IS_PRIVILEGED, scanMode, 0);  
  17.   
  18. // Collect ordinary system packages.  
  19. File systemAppDir = new File(Environment.getRootDirectory(), "app");  
  20. mSystemInstallObserver = new AppDirObserver(  
  21.     systemAppDir.getPath(), OBSERVER_EVENTS, truefalse);  
  22. mSystemInstallObserver.startWatching();  
  23. scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM  
  24.         | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);  
  25.   
  26. // Collect all vendor packages.  
  27. File vendorAppDir = new File("/vendor/app");  
  28. mVendorInstallObserver = new AppDirObserver(  
  29.     vendorAppDir.getPath(), OBSERVER_EVENTS, truefalse);  
  30. mVendorInstallObserver.startWatching();  
  31. scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM  
  32.         | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);  
  33.   
  34. if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");  
  35. mInstaller.moveFiles();  

这里首先会/system/framework、/system/priv-app、/system/app、/vendor/app四个目录建立AppDirObserver去监听它们的add、delete等操作,AppDirObserver是继承于FileObserver,它的底层是通过linux内核的inotify机制实现的。接着调用scanDirLI去扫描上面的四个目录。我们来看一下AppDirObserver的架构:


接着来看scanDirLI的代码:

  1. private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {  
  2.     String[] files = dir.list();  
  3.   
  4.     int i;  
  5.     for (i=0; i<files.length; i++) {  
  6.         File file = new File(dir, files[i]);  
  7.         if (!isPackageFilename(files[i])) {  
  8.   
  9.             continue;  
  10.         }  
  11.         PackageParser.Package pkg = scanPackageLI(file,  
  12.                 flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null);  
  13.   
  14.         if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&  
  15.                 mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {  
  16.   
  17.             Slog.w(TAG, "Cleaning up failed install of " + file);  
  18.             file.delete();  
  19.         }  
  20.     }  
  21. }  

scanDirLI调用scanPackageLI依次扫描并解析上面四个目录的目录下所有的apk文件:
  1. private PackageParser.Package scanPackageLI(File scanFile,  
  2.         int parseFlags, int scanMode, long currentTime, UserHandle user) {  
  3.     mLastScanError = PackageManager.INSTALL_SUCCEEDED;  
  4.     String scanPath = scanFile.getPath();  
  5.   
  6.     parseFlags |= mDefParseFlags;  
  7.     PackageParser pp = new PackageParser(scanPath);  
  8.   
  9.     //首先解析出一个Package对象  
  10.     final PackageParser.Package pkg = pp.parsePackage(scanFile,  
  11.             scanPath, mMetrics, parseFlags);  
  12.   
  13.     PackageSetting ps = null;  
  14.     PackageSetting updatedPkg;  
  15.   
  16.     synchronized (mPackages) {  
  17.   
  18.         String oldName = mSettings.mRenamedPackages.get(pkg.packageName);  
  19.         if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {  
  20.   
  21.             ps = mSettings.peekPackageLPr(oldName);  
  22.         }  
  23.         if (ps == null) {  
  24.             ps = mSettings.peekPackageLPr(pkg.packageName);  
  25.         }  
  26.   
  27.         updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);  
  28.         if (DEBUG_INSTALL && updatedPkg != null) Slog.d(TAG, "updatedPkg = " + updatedPkg);  
  29.     }  
  30.   
  31.     if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {  
  32.         //与update app相关的  
  33.     }  
  34.   
  35.     if (updatedPkg != null) {  
  36.         parseFlags |= PackageParser.PARSE_IS_SYSTEM;  
  37.     }  
  38.   
  39.     if (!collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)) {  
  40.         Slog.w(TAG, "Failed verifying certificates for package:" + pkg.packageName);  
  41.         return null;  
  42.     }  
  43.   
  44.     //处理system与非system的app同名的问题  
  45.     boolean shouldHideSystemApp = false;  
  46.     if (updatedPkg == null && ps != null  
  47.             && (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) {  
  48.   
  49.         if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures)  
  50.                 != PackageManager.SIGNATURE_MATCH) {  
  51.             if (DEBUG_INSTALL) Slog.d(TAG, "Signature mismatch!");  
  52.             deletePackageLI(pkg.packageName, nulltruenullnull0nullfalse);  
  53.             ps = null;  
  54.         } else {  
  55.   
  56.             if (pkg.mVersionCode < ps.versionCode) {  
  57.                 shouldHideSystemApp = true;  
  58.             } else {  
  59.                 InstallArgs args = createInstallArgs(packageFlagsToInstallFlags(ps),  
  60.                         ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString);  
  61.                 synchronized (mInstallLock) {  
  62.                     args.cleanUpResourcesLI();  
  63.                 }  
  64.             }  
  65.         }  
  66.     }  
  67.   
  68.     if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {  
  69.         if (ps != null && !ps.codePath.equals(ps.resourcePath)) {  
  70.             parseFlags |= PackageParser.PARSE_FORWARD_LOCK;  
  71.         }  
  72.     }  
  73.   
  74.     String codePath = null;  
  75.     String resPath = null;  
  76.     if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0) {  
  77.         if (ps != null && ps.resourcePathString != null) {  
  78.             resPath = ps.resourcePathString;  
  79.         } else {  
  80.   
  81.         }  
  82.     } else {  
  83.         resPath = pkg.mScanPath;  
  84.     }  
  85.   
  86.     codePath = pkg.mScanPath;  
  87.     setApplicationInfoPaths(pkg, codePath, resPath);  
  88.       
  89.     //  
  90.     PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode  
  91.             | SCAN_UPDATE_SIGNATURE, currentTime, user);  
  92.               
  93.     if (shouldHideSystemApp) {  
  94.         synchronized (mPackages) {  
  95.             grantPermissionsLPw(pkg, true);  
  96.             mSettings.disableSystemPackageLPw(pkg.packageName);  
  97.         }  
  98.     }  
  99.   
  100.     return scannedPkg;  
  101. }  

scanPackageLI首先调用PackageParser的parsePackage去解析扫描的文件,注意这里有两个parsePackage函数,但它们的参数不同,我们来看以File为第一个参数的parsePackage方法:

  1. public Package parsePackage(File sourceFile, String destCodePath,  
  2.         DisplayMetrics metrics, int flags) {  
  3.     mParseError = PackageManager.INSTALL_SUCCEEDED;  
  4.   
  5.     mArchiveSourcePath = sourceFile.getPath();  
  6.   
  7.     XmlResourceParser parser = null;  
  8.     AssetManager assmgr = null;  
  9.     Resources res = null;  
  10.     boolean assetError = true;  
  11.     try {  
  12.         assmgr = new AssetManager();  
  13.         int cookie = assmgr.addAssetPath(mArchiveSourcePath);  
  14.         if (cookie != 0) {  
  15.             res = new Resources(assmgr, metrics, null);  
  16.             assmgr.setConfiguration(00null0000000000000,  
  17.                     Build.VERSION.RESOURCES_SDK_INT);  
  18.             parser = assmgr.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);  
  19.             assetError = false;  
  20.         } else {  
  21.             Slog.w(TAG, "Failed adding asset path:"+mArchiveSourcePath);  
  22.         }  
  23.     } catch (Exception e) {  
  24.         Slog.w(TAG, "Unable to read AndroidManifest.xml of "  
  25.                 + mArchiveSourcePath, e);  
  26.     }  
  27.     if (assetError) {  
  28.         if (assmgr != null) assmgr.close();  
  29.         mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;  
  30.         return null;  
  31.     }  
  32.     String[] errorText = new String[1];  
  33.     Package pkg = null;  
  34.     Exception errorException = null;  
  35.     try {  
  36.         // XXXX todo: need to figure out correct configuration.  
  37.         pkg = parsePackage(res, parser, flags, errorText);  
  38.     } catch (Exception e) {  
  39.         errorException = e;  
  40.         mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;  
  41.     }  
  42.   
  43.     parser.close();  
  44.     assmgr.close();  
  45.   
  46.     pkg.mPath = destCodePath;  
  47.     pkg.mScanPath = mArchiveSourcePath;  
  48.     pkg.mSignatures = null;  
  49.   
  50.     return pkg;  
  51. }  

首先从apk文件中打开AndroidManifest.xml文件,然后调用以Resources为第一个参数的parsePackage方法,这个函数比较长,主要就是解析AndroidManifest.xml文件,建立一个Package对象,大概类图如下。最后设置Package对象的mPath和mScanPath为当前APK所在的全路径名。




我们以Mms这个应用的Manifest文件来看分析解析后的结果,首先来看Mms的AndroidManifest.xml文件(这里只截取了一部分)

  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  2.         package="com.android.mms">  
  3.     <original-package android:name="com.android.mms" />  
  4.     <uses-permission android:name="android.permission.RECEIVE_MMS" />  
  5.     <uses-permission android:name="android.permission.SEND_SMS" />  
  6.     <!-- System apps can access the  receiver through intent-->  
  7.     <permission android:name="android.permission.MMS_SEND_OUTBOX_MSG"  
  8.                 android:protectionLevel="signatureOrSystem"  
  9.                 android:label="@string/label_mms_send_outbox_msg"  
  10.                 android:description="@string/desc_mms_send_outbox_msg"/>  
  11.     <application android:name="MmsApp"  
  12.             android:label="@string/app_label"  
  13.             android:icon="@mipmap/ic_launcher_smsmms"  
  14.             android:taskAffinity="android.task.mms"  
  15.             android:allowTaskReparenting="true">  
  16.         <activity android:name=".ui.ConversationList"  
  17.                   android:label="@string/app_label"  
  18.                   android:configChanges="orientation|screenSize|keyboardHidden"  
  19.                   android:theme="@style/MmsHoloTheme"  
  20.                   android:uiOptions="splitActionBarWhenNarrow"  
  21.                   android:launchMode="singleTop">  
  22.             <intent-filter>  
  23.                 <action android:name="android.intent.action.MAIN" />  
  24.                 <category android:name="android.intent.category.LAUNCHER" />  
  25.                 <category android:name="android.intent.category.DEFAULT" />  
  26.                 <category android:name="android.intent.category.APP_MESSAGING" />  
  27.             </intent-filter>  
  28.             <intent-filter>  
  29.                 <action android:name="android.intent.action.MAIN" />  
  30.                 <category android:name="android.intent.category.DEFAULT" />  
  31.                 <data android:mimeType="vnd.android.cursor.dir/mms" />  
  32.             </intent-filter>  
  33.             <intent-filter>  
  34.                 <action android:name="android.intent.action.MAIN" />  
  35.                 <category android:name="android.intent.category.DEFAULT" />  
  36.                 <data android:mimeType="vnd.android-dir/mms-sms" />  
  37.             </intent-filter>  
  38.         </activity>  
  39.         <activity android:name=".ui.ComposeMessageActivity"  
  40.                   android:configChanges="orientation|screenSize|keyboardHidden"  
  41.                   android:windowSoftInputMode="stateHidden|adjustResize"  
  42.                   android:theme="@style/MmsHoloTheme"  
  43.                   android:parentActivityName=".ui.ConversationList"  
  44.                   android:launchMode="singleTop" >  
  45.             <intent-filter>  
  46.                 <action android:name="android.intent.action.VIEW" />  
  47.                 <category android:name="android.intent.category.DEFAULT" />  
  48.                 <data android:mimeType="vnd.android-dir/mms-sms" />  
  49.             </intent-filter>  
  50.             <intent-filter>  
  51.                 <action android:name="android.intent.action.VIEW" />  
  52.                 <action android:name="android.intent.action.SENDTO" />  
  53.                 <category android:name="android.intent.category.DEFAULT" />  
  54.                 <category android:name="android.intent.category.BROWSABLE" />  
  55.                 <data android:scheme="sms" />  
  56.                 <data android:scheme="smsto" />  
  57.             </intent-filter>  
  58.             <intent-filter>  
  59.                 <action android:name="android.intent.action.VIEW" />  
  60.                 <action android:name="android.intent.action.SENDTO" />  
  61.                 <category android:name="android.intent.category.DEFAULT" />  
  62.                 <category android:name="android.intent.category.BROWSABLE" />  
  63.                 <data android:scheme="mms" />  
  64.                 <data android:scheme="mmsto" />  
  65.             </intent-filter>  
  66.            <intent-filter>  
  67.                <action android:name="android.intent.action.SEND" />  
  68.                <category android:name="android.intent.category.DEFAULT" />  
  69.                <data android:mimeType="image/*" />  
  70.            </intent-filter>  
  71.            <intent-filter>  
  72.                <action android:name="android.intent.action.SEND" />  
  73.                <category android:name="android.intent.category.DEFAULT" />  
  74.                <data android:mimeType="text/plain" />  
  75.            </intent-filter>  
  76.            <intent-filter>  
  77.                <action android:name="android.intent.action.SEND_MULTIPLE" />  
  78.                <category android:name="android.intent.category.DEFAULT" />  
  79.                <data android:mimeType="image/*" />  
  80.            </intent-filter>  
  81.         </activity>  
  82.         <receiver android:name=".transaction.PushReceiver"  
  83.             android:permission="android.permission.BROADCAST_WAP_PUSH">  
  84.             <intent-filter>  
  85.                 <action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />  
  86.                 <data android:mimeType="application/vnd.wap.mms-message" />  
  87.             </intent-filter>  
  88.         </receiver>  
  89.         <receiver android:name=".transaction.SmsReceiver">  
  90.             <intent-filter>  
  91.                 <action android:name="android.intent.action.BOOT_COMPLETED" />  
  92.             </intent-filter>  
  93.             <intent-filter>  
  94.                 <action android:name="com.android.mms.transaction.MESSAGE_SENT" />  
  95.                 <!-- TODO Do a better data match here. -->  
  96.                 <data android:scheme="content" />  
  97.             </intent-filter>  
  98.             <intent-filter>  
  99.                 <action android:name="android.intent.action.SEND_MESSAGE" />  
  100.             </intent-filter>  
  101.         </receiver>  
  102.         <provider android:name="SuggestionsProvider"  
  103.             android:exported="true"  
  104.             android:readPermission="android.permission.READ_SMS"  
  105.             android:authorities="com.android.mms.SuggestionsProvider" >  
  106.             <path-permission  
  107.                     android:pathPrefix="/search_suggest_query"  
  108.                     android:readPermission="android.permission.GLOBAL_SEARCH" />  
  109.             <path-permission  
  110.                     android:pathPrefix="/search_suggest_shortcut"  
  111.                     android:readPermission="android.permission.GLOBAL_SEARCH" />  
  112.         </provider>  
  113.         <service android:name=".ui.NoConfirmationSendService"  
  114.                  android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"  
  115.                  android:exported="true" >  
  116.             <intent-filter>  
  117.                 <action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />  
  118.                 <category android:name="android.intent.category.DEFAULT" />  
  119.                 <data android:scheme="sms" />  
  120.                 <data android:scheme="smsto" />  
  121.             </intent-filter>  
  122.         </service>  
  123.     </application>  
  124. </manifest>  

上面的AndroidManifest.xml文件中定义了2个Activity,2个receiver,1个service和1个provider,我们来看进过parsePackage得到的Package对象如下:



接着回到scanPackageLI方法,解析完AndroidManifest.xml文件后,再来检查是否是更新的APK,如果更新的APK版本比以前的版本还有低,则直接返回;如果更新的APK版本比以前的版本高,则去删除之前的APK以及resource文件。若不是更新APK,并且当前package是系统app,但之前安装了非系统的app,这里首先比较签名,如果签名不一致,则直接删除当前package;若签名文件一致,则首先比较当前package和之前的版本号,如果当前版本号比较新,则直接删除之前的APK以及resource文件。最后调用scanPackageLI方法让把当前package的信息归入到PMS中的数据结构:

  1. private PackageParser.Package scanPackageLI(PackageParser.Package pkg,  
  2.         int parseFlags, int scanMode, long currentTime, UserHandle user) {  
  3.     File scanFile = new File(pkg.mScanPath);  
  4.     mScanningPath = scanFile;  
  5.   
  6.     if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {  
  7.         pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;  
  8.     }  
  9.   
  10.     if ((parseFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {  
  11.         pkg.applicationInfo.flags |= ApplicationInfo.FLAG_PRIVILEGED;  
  12.     }  
  13.   
  14.     if (mCustomResolverComponentName != null &&  
  15.             mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) {  
  16.         setUpCustomResolverActivity(pkg);  
  17.     }  
  18.   
  19.     if (pkg.packageName.equals("android")) {  
  20.         synchronized (mPackages) {  
  21.             if (mAndroidApplication != null) {  
  22.                 mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;  
  23.                 return null;  
  24.             }  
  25.   
  26.             mPlatformPackage = pkg;  
  27.             pkg.mVersionCode = mSdkVersion;  
  28.             mAndroidApplication = pkg.applicationInfo;  
  29.   
  30.             if (!mResolverReplaced) {  
  31.                 mResolveActivity.applicationInfo = mAndroidApplication;  
  32.                 mResolveActivity.name = ResolverActivity.class.getName();  
  33.                 mResolveActivity.packageName = mAndroidApplication.packageName;  
  34.                 mResolveActivity.processName = "system:ui";  
  35.                 mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;  
  36.                 mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;  
  37.                 mResolveActivity.theme = com.android.internal.R.style.Theme_Holo_Dialog_Alert;  
  38.                 mResolveActivity.exported = true;  
  39.                 mResolveActivity.enabled = true;  
  40.                 mResolveInfo.activityInfo = mResolveActivity;  
  41.                 mResolveInfo.priority = 0;  
  42.                 mResolveInfo.preferredOrder = 0;  
  43.                 mResolveInfo.match = 0;  
  44.                 mResolveComponentName = new ComponentName(  
  45.                         mAndroidApplication.packageName, mResolveActivity.name);  
  46.             }  
  47.         }  
  48.     }  
  49.   
  50.     File destCodeFile = new File(pkg.applicationInfo.sourceDir);  
  51.     File destResourceFile = new File(pkg.applicationInfo.publicSourceDir);  
  52.   
  53.     SharedUserSetting suid = null;  
  54.     PackageSetting pkgSetting = null;  
  55.   
  56.     if (!isSystemApp(pkg)) {  
  57.         // Only system apps can use these features.  
  58.         pkg.mOriginalPackages = null;  
  59.         pkg.mRealPackage = null;  
  60.         pkg.mAdoptPermissions = null;  
  61.     }  
  62.   
  63.     // writer  
  64.     synchronized (mPackages) {  
  65.         if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {  
  66.             if (!updateSharedLibrariesLPw(pkg, null)) {  
  67.                 return null;  
  68.             }  
  69.         }  
  70.   
  71.         if (pkg.mSharedUserId != null) {  
  72.             suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0true);  
  73.             if (suid == null) {  
  74.                 Slog.w(TAG, "Creating application package " + pkg.packageName  
  75.                         + " for shared user failed");  
  76.                 mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;  
  77.                 return null;  
  78.             }  
  79.             if (DEBUG_PACKAGE_SCANNING) {  
  80.                 if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)  
  81.                     Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid=" + suid.userId  
  82.                             + "): packages=" + suid.packages);  
  83.             }  
  84.         }  
  85.           

这里的mCustomResolverComponentName默认是空,采用framework是本身的ResolverActivity去解析intent。mAndroidApplication在Android系统中只有一个这样的application,就是framework-res.apk,它的packageName是"android"。然后在mResolveActivity和mResolveInfo保存ResolverActivity的信息,ResolverActivity用于在启动Activity的时候,如果有多个activity符合条件,弹出对话框给用户选择,这部分我们在以后分析AcitivityManagerService的时候再来分析。如果在Manifest中指定了ShareUserId,则首先获取一个关联的SharedUserSetting对象:

  1. SharedUserSetting getSharedUserLPw(String name,  
  2.         int pkgFlags, boolean create) {  
  3.     SharedUserSetting s = mSharedUsers.get(name);  
  4.     if (s == null) {  
  5.         if (!create) {  
  6.             return null;  
  7.         }  
  8.         s = new SharedUserSetting(name, pkgFlags);  
  9.         s.userId = newUserIdLPw(s);  
  10.         Log.i(PackageManagerService.TAG, "New shared user " + name + ": id=" + s.userId);  
  11.         // < 0 means we couldn't assign a userid; fall out and return  
  12.         // s, which is currently null  
  13.         if (s.userId >= 0) {  
  14.             mSharedUsers.put(name, s);  
  15.         }  
  16.     }  
  17.   
  18.     return s;  
  19. }  

在开始PMS的构造函数里面我们知道,系统会首先添加一系列的sysem的user id到mSharedUsers,所以如果能够从mSharedUsers获得到就直接返回;如果不能,则首先构造一个SharedUserSetting,并指派一个没有使用的APPLICATION UID,当然APPLICATION UID的值是在FIRST_APPLICATION_UID到LAST_APPLICATION_UID之间。最后把创建的SharedUserSetting添加到mSharedUsers和mUserIds数组当中。接着来看scanPackageLI函数:
  1. PackageSetting origPackage = null;  
  2. String realName = null;  
  3. if (pkg.mOriginalPackages != null) {  
  4.  //关于应用命名和更新的代码  
  5. }  
  6.   
  7. pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,  
  8.         destResourceFile, pkg.applicationInfo.nativeLibraryDir,  
  9.         pkg.applicationInfo.flags, user, false);  
  10. if (pkgSetting == null) {  
  11.     Slog.w(TAG, "Creating application package " + pkg.packageName + " failed");  
  12.     mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;  
  13.     return null;  
  14. }  
  15.   
  16. if (pkgSetting.origPackage != null) {  
  17.     pkg.setPackageName(origPackage.name);  
  18.       
  19.     String msg = "New package " + pkgSetting.realName  
  20.             + " renamed to replace old package " + pkgSetting.name;  
  21.     reportSettingsProblem(Log.WARN, msg);  
  22.       
  23.     mTransferedPackages.add(origPackage.name);  
  24.       
  25.     pkgSetting.origPackage = null;  
  26. }  
  27.   
  28. if (realName != null) {  
  29.     mTransferedPackages.add(pkg.packageName);  
  30. }  
  31.   
  32. if (mSettings.isDisabledSystemPackageLPr(pkg.packageName)) {  
  33.     pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;  
  34. }  
  35.   
  36. if (mFoundPolicyFile) {  
  37.     SELinuxMMAC.assignSeinfoValue(pkg);  
  38. }  
  39.   
  40. pkg.applicationInfo.uid = pkgSetting.appId;  
  41. pkg.mExtras = pkgSetting;  
  42.   
  43. if (!verifySignaturesLP(pkgSetting, pkg)) {  
  44.     if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {  
  45.         return null;  
  46.     }  
  47.     pkgSetting.signatures.mSignatures = pkg.mSignatures;  
  48.     if (pkgSetting.sharedUser != null) {  
  49.         if (compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,  
  50.                 pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {  
  51.             Log.w(TAG, "Signature mismatch for shared user : " + pkgSetting.sharedUser);  
  52.             mLastScanError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;  
  53.             return null;  
  54.         }  
  55.     }  
  56.     String msg = "System package " + pkg.packageName  
  57.             + " signature changed; retaining data.";  
  58.     reportSettingsProblem(Log.WARN, msg);  
  59. }  

关于应用程序改名和更新的代码我们这里先忽略,首先来看构造PackageSetting的方法:

  1. PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,  
  2.         String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,  
  3.         String nativeLibraryPathString, int pkgFlags, UserHandle user, boolean add) {  
  4.     final String name = pkg.packageName;  
  5.     PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath,  
  6.             resourcePath, nativeLibraryPathString, pkg.mVersionCode, pkgFlags,  
  7.             user, add, true /* allowInstall */);  
  8.     return p;  
  9. }  
  10.   
  11. private PackageSetting getPackageLPw(String name, PackageSetting origPackage,  
  12.         String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,  
  13.         String nativeLibraryPathString, int vc, int pkgFlags,  
  14.         UserHandle installUser, boolean add, boolean allowInstall) {  
  15.     PackageSetting p = mPackages.get(name);  
  16.     if (p != null) {  
  17.       //更新apk相关  
  18.     }  
  19.     if (p == null) {  
  20.         if (origPackage != null) {  
  21.              //更新apk相关  
  22.         } else {  
  23.             p = new PackageSetting(name, realName, codePath, resourcePath,  
  24.                     nativeLibraryPathString, vc, pkgFlags);  
  25.             p.setTimeStamp(codePath.lastModified());  
  26.             p.sharedUser = sharedUser;  
  27.             if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {  
  28.                 List<UserInfo> users = getAllUsers();  
  29.                 if (users != null && allowInstall) {  
  30.                      //多用户的部分  
  31.                     }  
  32.                 }  
  33.             }  
  34.             if (sharedUser != null) {  
  35.                 p.appId = sharedUser.userId;  
  36.             } else {  
  37.                //更新系统apk相关  
  38.         }  
  39.   
  40.         if (add) {  
  41.             // Finish adding new package by adding it and updating shared  
  42.             // user preferences  
  43.             addPackageSettingLPw(p, name, sharedUser);  
  44.         }  
  45.     } else {  
  46.         //多用户的部分  
  47.     }  
  48.     return p;  
  49. }  

关于PackageSetting结构可以看文章最开始的类图。在新建一个PackageSetting对象后,首先将得到的系统的uid值赋给applicationInfo.uid ,这就是当前APK以后运行时的UID了。然后就做数字签名验证,这里主要是对于更新APK来做验证。在做完数字签名验证后,还需要检查当前APK是否提供providers与系统已有的providers冲突,如果冲突,则提示安装失败。接着来看scanPackageLI函数:
  1. synchronized (mPackages) {  
  2.     // We don't expect installation to fail beyond this point,  
  3.     if ((scanMode&SCAN_MONITOR) != 0) {  
  4.         mAppDirs.put(pkg.mPath, pkg);  
  5.     }  
  6.     // Add the new setting to mSettings  
  7.     mSettings.insertPackageSettingLPw(pkgSetting, pkg);  
  8.     // Add the new setting to mPackages  
  9.     mPackages.put(pkg.applicationInfo.packageName, pkg);  
  10.     // Make sure we don't accidentally delete its data.  
  11.     final Iterator<PackageCleanItem> iter = mSettings.mPackagesToBeCleaned.iterator();  
  12.     while (iter.hasNext()) {  
  13.         PackageCleanItem item = iter.next();  
  14.         if (pkgName.equals(item.packageName)) {  
  15.             iter.remove();  
  16.         }  
  17.     }  
  18.   
  19.     // Take care of first install / last update times.  
  20.     if (currentTime != 0) {  
  21.         if (pkgSetting.firstInstallTime == 0) {  
  22.             pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime;  
  23.         } else if ((scanMode&SCAN_UPDATE_TIME) != 0) {  
  24.             pkgSetting.lastUpdateTime = currentTime;  
  25.         }  
  26.     } else if (pkgSetting.firstInstallTime == 0) {  
  27.         // We need *something*.  Take time time stamp of the file.  
  28.         pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = scanFileTime;  
  29.     } else if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {  
  30.         if (scanFileTime != pkgSetting.timeStamp) {  
  31.             // A package on the system image has changed; consider this  
  32.             // to be an update.  
  33.             pkgSetting.lastUpdateTime = scanFileTime;  
  34.         }  
  35.     }  
  36.   
  37.     // Add the package's KeySets to the global KeySetManager  
  38.     KeySetManager ksm = mSettings.mKeySetManager;  
  39.     try {  
  40.         ksm.addSigningKeySetToPackage(pkg.packageName, pkg.mSigningKeys);  
  41.         if (pkg.mKeySetMapping != null) {  
  42.             for (Map.Entry<String, Set<PublicKey>> entry : pkg.mKeySetMapping.entrySet()) {  
  43.                 if (entry.getValue() != null) {  
  44.                     ksm.addDefinedKeySetToPackage(pkg.packageName,  
  45.                         entry.getValue(), entry.getKey());  
  46.                 }  
  47.             }  
  48.         }  
  49.     } catch (NullPointerException e) {  
  50.         Slog.e(TAG, "Could not add KeySet to " + pkg.packageName, e);  
  51.     } catch (IllegalArgumentException e) {  
  52.         Slog.e(TAG, "Could not add KeySet to malformed package" + pkg.packageName, e);  
  53.     }  

首先调用Settings的insertPackageSettingLPw将pkgSetting对象加入到Settings中的mPackages这个HashMap中。在insertPackageSettingLPw方法中,首先将Package中的一些信息赋予给PackageSetting,然后调用addPackageSettingLPw方法将PackageSetting对象添加到mPackages中,并将PackageSetting加入到SharedUserSetting中的packages这个HashSet中。接着将pkg对象加入到PMS的mPackages这个HashMap中,保存在mPackages中信息会被后面很多地方使用到。最后对apk的安装或者更新时间做相应的更新。接着来看scanPackageLI函数:
  1.         int N = pkg.providers.size();  
  2.         StringBuilder r = null;  
  3.         int i;  
  4.         for (i=0; i<N; i++) {  
  5.             PackageParser.Provider p = pkg.providers.get(i);  
  6.             p.info.processName = fixProcessName(pkg.applicationInfo.processName,  
  7.                     p.info.processName, pkg.applicationInfo.uid);  
  8.             mProviders.addProvider(p);  
  9.             p.syncable = p.info.isSyncable;  
  10.             if (p.info.authority != null) {  
  11.                 String names[] = p.info.authority.split(";");  
  12.                 p.info.authority = null;  
  13.                 for (int j = 0; j < names.length; j++) {  
  14.                     if (j == 1 && p.syncable) {  
  15.                         p = new PackageParser.Provider(p);  
  16.                         p.syncable = false;  
  17.                     }  
  18.                     if (!mProvidersByAuthority.containsKey(names[j])) {  
  19.                         mProvidersByAuthority.put(names[j], p);  
  20.                         if (p.info.authority == null) {  
  21.                             p.info.authority = names[j];  
  22.                         } else {  
  23.                             p.info.authority = p.info.authority + ";" + names[j];  
  24.                         }  
  25.                     } else {  
  26.                         PackageParser.Provider other = mProvidersByAuthority.get(names[j]);  
  27.                     }  
  28.                 }  
  29.             }  
  30.             if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {  
  31.                 if (r == null) {  
  32.                     r = new StringBuilder(256);  
  33.                 } else {  
  34.                     r.append(' ');  
  35.                 }  
  36.                 r.append(p.info.name);  
  37.             }  
  38.         }  
  39.         if (r != null) {  
  40.             if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Providers: " + r);  
  41.         }  
  42.   
  43.         N = pkg.services.size();  
  44.         r = null;  
  45.         for (i=0; i<N; i++) {  
  46.             PackageParser.Service s = pkg.services.get(i);  
  47.             s.info.processName = fixProcessName(pkg.applicationInfo.processName,  
  48.                     s.info.processName, pkg.applicationInfo.uid);  
  49.             mServices.addService(s);  
  50.             if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {  
  51.                 if (r == null) {  
  52.                     r = new StringBuilder(256);  
  53.                 } else {  
  54.                     r.append(' ');  
  55.                 }  
  56.                 r.append(s.info.name);  
  57.             }  
  58.         }  
  59.         if (r != null) {  
  60.             if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Services: " + r);  
  61.         }  
  62.   
  63.         N = pkg.receivers.size();  
  64.         r = null;  
  65.         for (i=0; i<N; i++) {  
  66.             PackageParser.Activity a = pkg.receivers.get(i);  
  67.             a.info.processName = fixProcessName(pkg.applicationInfo.processName,  
  68.                     a.info.processName, pkg.applicationInfo.uid);  
  69.             mReceivers.addActivity(a, "receiver");  
  70.             if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {  
  71.                 if (r == null) {  
  72.                     r = new StringBuilder(256);  
  73.                 } else {  
  74.                     r.append(' ');  
  75.                 }  
  76.                 r.append(a.info.name);  
  77.             }  
  78.         }  
  79.         if (r != null) {  
  80.             if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Receivers: " + r);  
  81.         }  
  82.   
  83.         N = pkg.activities.size();  
  84.         r = null;  
  85.         for (i=0; i<N; i++) {  
  86.             PackageParser.Activity a = pkg.activities.get(i);  
  87.             a.info.processName = fixProcessName(pkg.applicationInfo.processName,  
  88.                     a.info.processName, pkg.applicationInfo.uid);  
  89.             mActivities.addActivity(a, "activity");  
  90.             if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {  
  91.                 if (r == null) {  
  92.                     r = new StringBuilder(256);  
  93.                 } else {  
  94.                     r.append(' ');  
  95.                 }  
  96.                 r.append(a.info.name);  
  97.             }  
  98.         }  
  99.         if (r != null) {  
  100.             if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Activities: " + r);  
  101.         }  
  102.   
  103.         N = pkg.permissionGroups.size();  
  104.         r = null;  
  105.         for (i=0; i<N; i++) {  
  106.             PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);  
  107.             PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name);  
  108.             if (cur == null) {  
  109.                 mPermissionGroups.put(pg.info.name, pg);  
  110.                 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {  
  111.                     if (r == null) {  
  112.                         r = new StringBuilder(256);  
  113.                     } else {  
  114.                         r.append(' ');  
  115.                     }  
  116.                     r.append(pg.info.name);  
  117.                 }  
  118.             } else {  
  119.                 Slog.w(TAG, "Permission group " + pg.info.name + " from package "  
  120.                         + pg.info.packageName + " ignored: original from "  
  121.                         + cur.info.packageName);  
  122.                 if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {  
  123.                     if (r == null) {  
  124.                         r = new StringBuilder(256);  
  125.                     } else {  
  126.                         r.append(' ');  
  127.                     }  
  128.                     r.append("DUP:");  
  129.                     r.append(pg.info.name);  
  130.                 }  
  131.             }  
  132.         }  
  133.         if (r != null) {  
  134.             if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Permission Groups: " + r);  
  135.         }  
  136.   
  137.         N = pkg.permissions.size();  
  138.         r = null;  
  139.         for (i=0; i<N; i++) {  
  140.             PackageParser.Permission p = pkg.permissions.get(i);  
  141.             HashMap<String, BasePermission> permissionMap =  
  142.                     p.tree ? mSettings.mPermissionTrees  
  143.                     : mSettings.mPermissions;  
  144.             p.group = mPermissionGroups.get(p.info.group);  
  145.             if (p.info.group == null || p.group != null) {  
  146.                 BasePermission bp = permissionMap.get(p.info.name);  
  147.                 if (bp == null) {  
  148.                     bp = new BasePermission(p.info.name, p.info.packageName,  
  149.                             BasePermission.TYPE_NORMAL);  
  150.                     permissionMap.put(p.info.name, bp);  
  151.                 }  
  152.                 if (bp.perm == null) {  
  153.                     if (bp.sourcePackage != null  
  154.                             && !bp.sourcePackage.equals(p.info.packageName)) {  
  155.                         if (isSystemApp(p.owner)) {  
  156.                             Slog.i(TAG, "New decl " + p.owner + " of permission  "  
  157.                                     + p.info.name + " is system");  
  158.                             bp.sourcePackage = null;  
  159.                         }  
  160.                     }  
  161.                     if (bp.sourcePackage == null  
  162.                             || bp.sourcePackage.equals(p.info.packageName)) {  
  163.                         BasePermission tree = findPermissionTreeLP(p.info.name);  
  164.                         if (tree == null  
  165.                                 || tree.sourcePackage.equals(p.info.packageName)) {  
  166.                             bp.packageSetting = pkgSetting;  
  167.                             bp.perm = p;  
  168.                             bp.uid = pkg.applicationInfo.uid;  
  169.                             if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {  
  170.                                 if (r == null) {  
  171.                                     r = new StringBuilder(256);  
  172.                                 } else {  
  173.                                     r.append(' ');  
  174.                                 }  
  175.                                 r.append(p.info.name);  
  176.                             }  
  177.                         } else {  
  178.   
  179.                         }  
  180.                     } else {  
  181.   
  182.                     }  
  183.                 } else if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {  
  184.                     if (r == null) {  
  185.                         r = new StringBuilder(256);  
  186.                     } else {  
  187.                         r.append(' ');  
  188.                     }  
  189.                     r.append("DUP:");  
  190.                     r.append(p.info.name);  
  191.                 }  
  192.                 if (bp.perm == p) {  
  193.                     bp.protectionLevel = p.info.protectionLevel;  
  194.                 }  
  195.             } else {  
  196.   
  197.             }  
  198.         }  
  199.         if (r != null) {  
  200.             if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Permissions: " + r);  
  201.         }  
  202.   
  203.         N = pkg.instrumentation.size();  
  204.         r = null;  
  205.         for (i=0; i<N; i++) {  
  206.             PackageParser.Instrumentation a = pkg.instrumentation.get(i);  
  207.             a.info.packageName = pkg.applicationInfo.packageName;  
  208.             a.info.sourceDir = pkg.applicationInfo.sourceDir;  
  209.             a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir;  
  210.             a.info.dataDir = pkg.applicationInfo.dataDir;  
  211.             a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;  
  212.             mInstrumentation.put(a.getComponentName(), a);  
  213.             if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {  
  214.                 if (r == null) {  
  215.                     r = new StringBuilder(256);  
  216.                 } else {  
  217.                     r.append(' ');  
  218.                 }  
  219.                 r.append(a.info.name);  
  220.             }  
  221.         }  
  222.         if (r != null) {  
  223.             if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Instrumentation: " + r);  
  224.         }  
  225.   
  226.         if (pkg.protectedBroadcasts != null) {  
  227.             N = pkg.protectedBroadcasts.size();  
  228.             for (i=0; i<N; i++) {  
  229.                 mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i));  
  230.             }  
  231.         }  
  232.   
  233.         pkgSetting.setTimeStamp(scanFileTime);  
  234.     }  
  235.   
  236.     return pkg;  
  237. }  


上面的代码比较长,但功能却比较简单,就是将前面从AndroidManifest里面Parse出来的providers、services、receivers、activities、permissionGroups、permissions和instrumentation添加到PMS的相应数据结构中。providers保存在ProviderIntentResolver对象中;services保存在ServiceIntentResolver对象中;receivers和activities保存在ActivityIntentResolver中;permissionGroups、permissions和permissions保存在HashMap中。ProviderIntentResolver、ServiceIntentResolver和ActivityIntentResolver都是继承于IntentResolver,它们的类图关系如下:


到这里,我们就把scanDirLI介绍完了,依次扫描完/system/framework、/system/priv-app、/system/app、/vendor/app这四个目录下面所有的APK文件,并解析成一个个Package对象,并把他们加入到PMS和Settings中的一些数据结构中。接着回到PMS的构造函数来分析:

  1. final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();  
  2. if (!mOnlyCore) {  
  3.     Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();  
  4.     while (psit.hasNext()) {  
  5.         PackageSetting ps = psit.next();  
  6.         if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {  
  7.             continue;  
  8.         }  
  9.   
  10.         final PackageParser.Package scannedPkg = mPackages.get(ps.name);  
  11.         if (scannedPkg != null) {  
  12.             if (mSettings.isDisabledSystemPackageLPr(ps.name)) {  
  13.                 Slog.i(TAG, "Expecting better updatd system app for " + ps.name  
  14.                         + "; removing system app");  
  15.                 removePackageLI(ps, true);  
  16.             }  
  17.   
  18.             continue;  
  19.         }  
  20.   
  21.         if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {  
  22.             psit.remove();  
  23.             String msg = "System package " + ps.name  
  24.                     + " no longer exists; wiping its data";  
  25.             reportSettingsProblem(Log.WARN, msg);  
  26.             removeDataDirsLI(ps.name);  
  27.         } else {  
  28.             final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);  
  29.             if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {  
  30.                 possiblyDeletedUpdatedSystemApps.add(ps.name);  
  31.             }  
  32.         }  
  33.     }  
  34. }  

上面的代码主要是处理在mSettings中保存了的System app,但在在刚刚的scanDirLI并没有找到对应的APK,这里分三种情况:一是在mSettings中有保存,刚刚的scanDirLI也有找到,这里判断它是否被disable的APK,如果是,说明这个apk是通过OTA升级后更新了的,所以清除相应的数据结构;二是在mSettings中有保存,但刚刚的scanDirLI没有找到对应的APK,并且不是被disable的APK就直接删除相应的数据结构;三是在mSettings中有保存,但刚刚的scanDirLI没有找到对应的APK,并且是被disable的APK,就通过查看它的codePath是否存在来判断它是否有可能被更新或者删除,并添加到possiblyDeletedUpdatedSystemApps链表里。接着来看PMS的构造函数:
  1. ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();  
  2. for(int i = 0; i < deletePkgsList.size(); i++) {  
  3.     //clean up here  
  4.     cleanupInstallFailedPackage(deletePkgsList.get(i));  
  5. }  
  6.   
  7. deleteTempPackageFiles();  
  8. mSettings.pruneSharedUsersLPw();  
  9.   
  10. if (!mOnlyCore) {  
  11.     EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,  
  12.             SystemClock.uptimeMillis());  
  13.     mAppInstallObserver = new AppDirObserver(  
  14.         mAppInstallDir.getPath(), OBSERVER_EVENTS, falsefalse);  
  15.     mAppInstallObserver.startWatching();  
  16.     scanDirLI(mAppInstallDir, 0, scanMode, 0);  
  17.   
  18.     mDrmAppInstallObserver = new AppDirObserver(  
  19.         mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, falsefalse);  
  20.     mDrmAppInstallObserver.startWatching();  
  21.     scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,  
  22.             scanMode, 0);  
  23.   
  24.     for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {  
  25.         PackageParser.Package deletedPkg = mPackages.get(deletedAppName);  
  26.         mSettings.removeDisabledSystemPackageLPw(deletedAppName);  
  27.   
  28.         String msg;  
  29.         if (deletedPkg == null) {  
  30.             msg = "Updated system package " + deletedAppName  
  31.                     + " no longer exists; wiping its data";  
  32.             removeDataDirsLI(deletedAppName);  
  33.         } else {  
  34.             msg = "Updated system app + " + deletedAppName  
  35.                     + " no longer present; removing system privileges for "  
  36.                     + deletedAppName;  
  37.   
  38.             deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;  
  39.   
  40.             PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);  
  41.             deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;  
  42.         }  
  43.         reportSettingsProblem(Log.WARN, msg);  
  44.     }  
  45. else {  
  46.     mAppInstallObserver = null;  
  47.     mDrmAppInstallObserver = null;  
  48. }  

首先去删除安装不完整的APK文件及其数据,然后清除安装的temp文件,并清除在mSharedUsers没有被使用的ShareUserSettins。接着去扫描/data/app和/data/app-private两个目录中的所有APK文件,并建立对应的FileObserver。最后处理通过OTA更新或者删除的APK文件。来看PMS构造函数的最后一部分:

  1.         updateAllSharedLibrariesLPw();  
  2.   
  3.         final boolean regrantPermissions = mSettings.mInternalSdkPlatform  
  4.                 != mSdkVersion;  
  5.         if (regrantPermissions) Slog.i(TAG, "Platform changed from "  
  6.                 + mSettings.mInternalSdkPlatform + " to " + mSdkVersion  
  7.                 + "; regranting permissions for internal storage");  
  8.         mSettings.mInternalSdkPlatform = mSdkVersion;  
  9.           
  10.         updatePermissionsLPw(nullnull, UPDATE_PERMISSIONS_ALL  
  11.                 | (regrantPermissions  
  12.                         ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)  
  13.                         : 0));  
  14.   
  15.         if (!mRestoredSettings && !onlyCore) {  
  16.             mSettings.readDefaultPreferredAppsLPw(this0);  
  17.         }  
  18.   
  19.         mSettings.writeLPr();  
  20.   
  21.         Runtime.getRuntime().gc();  
  22.     } // synchronized (mPackages)  
  23.     } // synchronized (mInstallLock)  
  24. }  

这一部分的代码量虽然很少,却做了比较多的事情,首先调用updateAllSharedLibrariesLPw为所有需要使用ShareLibrary的package找到对应的ShareLibrary路径,并把这些路径保存在package的usesLibraryFiles数组中。接着调用updatePermissionsLPw为需要使用权限的APK分配对应的权限:
  1. private void updatePermissionsLPw(String changingPkg,  
  2.         PackageParser.Package pkgInfo, int flags) {  
  3.     Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator();  
  4.     while (it.hasNext()) {  
  5.         final BasePermission bp = it.next();  
  6.         if (bp.packageSetting == null) {  
  7.             bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);  
  8.         }  
  9.     }  
  10.   
  11.     it = mSettings.mPermissions.values().iterator();  
  12.     while (it.hasNext()) {  
  13.         final BasePermission bp = it.next();  
  14.         if (bp.type == BasePermission.TYPE_DYNAMIC) {  
  15.             if (bp.packageSetting == null && bp.pendingInfo != null) {  
  16.                 final BasePermission tree = findPermissionTreeLP(bp.name);  
  17.                 if (tree != null && tree.perm != null) {  
  18.                     bp.packageSetting = tree.packageSetting;  
  19.                     bp.perm = new PackageParser.Permission(tree.perm.owner,  
  20.                             new PermissionInfo(bp.pendingInfo));  
  21.                     bp.perm.info.packageName = tree.perm.info.packageName;  
  22.                     bp.perm.info.name = bp.name;  
  23.                     bp.uid = tree.uid;  
  24.                 }  
  25.             }  
  26.         }  
  27.         if (bp.packageSetting == null) {  
  28.             bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);  
  29.         }  
  30.         if (bp.packageSetting == null) {  
  31.             Slog.w(TAG, "Removing dangling permission: " + bp.name  
  32.                     + " from package " + bp.sourcePackage);  
  33.             it.remove();  
  34.         } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {  
  35.             if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {  
  36.                 Slog.i(TAG, "Removing old permission: " + bp.name  
  37.                         + " from package " + bp.sourcePackage);  
  38.                 flags |= UPDATE_PERMISSIONS_ALL;  
  39.                 it.remove();  
  40.             }  
  41.         }  
  42.     }  
  43.   
  44.     if ((flags&UPDATE_PERMISSIONS_ALL) != 0) {  
  45.         for (PackageParser.Package pkg : mPackages.values()) {  
  46.             if (pkg != pkgInfo) {  
  47.                 grantPermissionsLPw(pkg, (flags&UPDATE_PERMISSIONS_REPLACE_ALL) != 0);  
  48.             }  
  49.         }  
  50.     }  
  51. }  

updatePermissionsLPw中首先对mPermissionTrees和mPermissions两个Map中的permission的一些信息进行赋值,然后调用grantPermissionsLPw为每个package分配权限,Android分配权限其实就是分配对应的gid号。在grantPermissionsLPw有一系列的判断条件,如果请求分配的权限被允许,就会将对应的gid号码加入到GrantedPermissions的gids数组当中。回到PMS的构造函数函数,最后调用readDefaultPreferredAppsLPw去设置对于处理Intent默认的Activity信息,关于这部分,我们在ActivityMangerService中再来介绍。在PMS构造函数的最后调用mSettings.writeLPr将所有的package、permission、ShareUserID等信息全部写到/data/system/packages.xml中。到这里PMS的构造函数就介绍完了。
posted @ 2016-12-07 21:04  张同光  阅读(313)  评论(0编辑  收藏  举报