APK的安装过程分析

Package管理服务PackageManagerService在安装一个应用程序的过程中,会对这个应用程序的配置文件AndroidManifest.xml进行解析,以便可以获得它的安装信息。

Android系统中每一个应用程序都有一个Linux用户ID,一个应用程序除了拥有一个linux用户ID之外,还可以拥有若干个Linux用户组ID,以便可以在系统中获得更多的资源访问权限,如读取联系人信息、使用摄像头等权限。

PMS在安装一个应用程序时,如果发现它没有与其他应用程序共享同一个Linux用户ID,那么就会为它分配一个唯一的Linux用户ID,以便它可以在系统中获得合适的运行权限。如果发现它申请了一个特定的资源访问权限,那么就会为它分配一个相应的Linux用户组ID。

分析应用程序的安装过程,主要是关注它的组件信息的解析过程,以及Linux用户ID和Linux用户组ID的分配过程。

System进程在启动时,会调用PMS类的静态成员函数main方法将系统的PMS启动起来。由于PMS在启动过程中会对系统中的应用程序进行安装,因此,接下来就从PMS类的main方法开始分析应用程序的安装过程:

[java]  view plain  copy
  1. public static PackageManagerService main(Context context, Installer installer,  
  2.         boolean factoryTest, boolean onlyCore) {  
  3.     // 实例化PMS  
  4.     PackageManagerService m = new PackageManagerService(context, installer,  
  5.             factoryTest, onlyCore);  
  6.     // 把PMS添加到ServiceManager中  
  7.     ServiceManager.addService("package", m);  
  8.     return m;  
  9. }  


PMS的构造方法完成的主要功能是,扫描android系统中几个目标文件夹中的apk文件,从而建立合适的数据结构以管理诸如Package信息、四大组件信息、权限信息等各种信息。PMS的工作流程相对简单,复杂的是其中用于保存各种信息的数据结构和它们之间的关系,以及影响最终结果的策略控制。

由于代码量较大,采用分段的方法进行分析。

1.扫描目标文件夹之前的准备工作

先看下时序图:

[java]  view plain  copy
  1. final int mSdkVersion = Build.VERSION.SDK_INT;  
  2. final Context mContext;  
  3. final boolean mFactoryTest;  
  4. final boolean mOnlyCore;  
  5. final boolean mLazyDexOpt;  
  6. final DisplayMetrics mMetrics;  
  7. final Settings mSettings;  
  8. // Keys are String (package name), values are Package.  This also serves  
  9. // as the lock for the global state.  Methods that must be called with  
  10. // this lock held have the prefix "LP".  
  11. @GuardedBy("mPackages")  
  12. final ArrayMap<String, PackageParser.Package> mPackages =  
  13.         new ArrayMap<String, PackageParser.Package>();  
  14. private static final int RADIO_UID = Process.PHONE_UID;  
  15. private static final int LOG_UID = Process.LOG_UID;  
  16. private static final int NFC_UID = Process.NFC_UID;  
  17. private static final int BLUETOOTH_UID = Process.BLUETOOTH_UID;  
  18. private static final int SHELL_UID = Process.SHELL_UID;  
  19.   
  20. public PackageManagerService(Context context, Installer installer,  
  21.         boolean factoryTest, boolean onlyCore) {  
  22.   
  23.     // 编译的SDK版本,若没有定义则APK就无法知道自己运行在Android的哪个版本上  
  24.     if (mSdkVersion <= 0) {  
  25.         Slog.w(TAG, "**** ro.build.version.sdk not set!");  
  26.     }  
  27.   
  28.     mContext = context;  
  29.     // 是否运行在工厂模式下  
  30.     mFactoryTest = factoryTest;  
  31.     // 用于判断是否只扫描系统目录  
  32.     mOnlyCore = onlyCore;  
  33.     // 如果此系统是eng版本,则扫描Package后,不对其做dex优化  
  34.     mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));  
  35.     // 用于存储与显示屏相关的一些属性,如屏幕的宽高、分辨率等信息  
  36.     mMetrics = new DisplayMetrics();  
  37.     // Settings是用来管理应用程序的安装信息的  
  38.     mSettings = new Settings(mPackages);  
  39.     // 添加共享用户  
  40.     mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,  
  41.             ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);  
  42.     mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,  
  43.             ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);  
  44.     mSettings.addSharedUserLPw("android.uid.log", LOG_UID,  
  45.             ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);  
  46.     mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,  
  47.             ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);  
  48.     mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,  
  49.             ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);  
  50.     mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,  
  51.             ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);  
  52.     . . .  
  53. }  


刚进入构造函数就会遇到第一个较为复杂的数据结构Settings以及它的addSharedUserLPw方法。先看Settings类的构造方法,主要是创建相关的文件夹并设置文件夹的读写权限:

[java]  view plain  copy
  1. Settings(Object lock) {  
  2.     // Environment.getDataDirectory()获取到的是/data目录  
  3.     this(Environment.getDataDirectory(), lock);  
  4. }  
  5.   
  6. private final Object mLock;  
  7. private final RuntimePermissionPersistence mRuntimePermissionsPersistence;  
  8. private final File mSystemDir;  
  9. private final File mSettingsFilename;  
  10. private final File mBackupSettingsFilename;  
  11. private final File mPackageListFilename;  
  12. private final File mStoppedPackagesFilename;  
  13. private final File mBackupStoppedPackagesFilename;  
  14.   
  15. Settings(File dataDir, Object lock) {  
  16.     mLock = lock;  
  17.   
  18.     mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);  
  19.   
  20.     mSystemDir = new File(dataDir, "system");  
  21.     // 创建/data/system文件夹  
  22.     mSystemDir.mkdirs();  
  23.     // 设置/data/system文件夹的读写权限  
  24.     FileUtils.setPermissions(mSystemDir.toString(),  
  25.             FileUtils.S_IRWXU|FileUtils.S_IRWXG  
  26.             |FileUtils.S_IROTH|FileUtils.S_IXOTH,  
  27.             -1, -1);  
  28.     mSettingsFilename = new File(mSystemDir, "packages.xml");  
  29.     mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");  
  30.     mPackageListFilename = new File(mSystemDir, "packages.list");  
  31.     FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);  
  32.   
  33.     // Deprecated: Needed for migration  
  34.     mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");  
  35.     mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");  
  36. }  


Settings的构造方法会在data目录下创建system目录,用来保存多个系统文件。主要有:

packages.xml:记录系统中所有安装的应用信息,包括基本信息、签名和权限。

packages-backup.xml:packages.xml文件的备份。写文件之前会先备份,写成功后再删除掉备份文件,如果写的时候出现问题,则重启后再读取这两个文件时,如果发现备份文件存在,就会使用备份文件的内容,因为原文件可能已经损坏了。

packages.list:保存普通应用的数据目录和uid等信息。

packages-stopped.xml:记录系统中被强制停止运行的应用信息。系统在强制停止某个应用时,会将应用的信息记录在该文件中。

packages-stopped-backup.xml:packages-stopped.xml文件的备份文件。

[java]  view plain  copy
  1. final ArrayMap<String, SharedUserSetting> mSharedUsers = new ArrayMap<String, SharedUserSetting>();  
  2.   
  3. // 添加共享用户  
  4. SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {  
  5.     // 根据key从map中获取值  
  6.     SharedUserSetting s = mSharedUsers.get(name);  
  7.     // 如果值不为null并且保存的uid和传递过来的一致,就直接返回结果。uid不一致则返回null  
  8.     if (s != null) {  
  9.         if (s.userId == uid) {  
  10.             return s;  
  11.         }  
  12.         PackageManagerService.reportSettingsProblem(Log.ERROR,  
  13.                 "Adding duplicate shared user, keeping first: " + name);  
  14.         return null;  
  15.     }  
  16.     // 若s为null,则根据传递过来的参数新创建对象  
  17.     s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);  
  18.     s.userId = uid;  
  19.     // 在系统中保存值为uid的Linux用户ID,成功返回true  
  20.     if (addUserIdLPw(uid, s, name)) {  
  21.         // 保存到map中  
  22.         mSharedUsers.put(name, s);  
  23.         return s;  
  24.     }  
  25.     return null;  
  26. }  
  27.   
  28. private final ArrayList<Object> mUserIds = new ArrayList<Object>();  
  29. private final SparseArray<Object> mOtherUserIds = new SparseArray<Object>();  
  30.   
  31. private boolean addUserIdLPw(int uid, Object obj, Object name) {  
  32.     // LAST_APPLICATION_UID = 19999  
  33.     if (uid > Process.LAST_APPLICATION_UID) {  
  34.         return false;  
  35.     }  
  36.   
  37.     // FIRST_APPLICATION_UID = 10000  
  38.     if (uid >= Process.FIRST_APPLICATION_UID) {  
  39.         // 获取数组的长度  
  40.         int N = mUserIds.size();  
  41.         // 计算目标索引值  
  42.         final int index = uid - Process.FIRST_APPLICATION_UID;  
  43.         // 如果目标索引值大于数组长度,则在数组索引值之前的位置都添加null的元素  
  44.         while (index >= N) {  
  45.             mUserIds.add(null);  
  46.             N++;  
  47.         }  
  48.         // 如果数组的目标索引值位置有不为null的值,说明已经添加过  
  49.         if (mUserIds.get(index) != null) {  
  50.             PackageManagerService.reportSettingsProblem(Log.ERROR,  
  51.                     "Adding duplicate user id: " + uid  
  52.                     + " name=" + name);  
  53.             return false;  
  54.         }  
  55.         // 把值放在数组的目标索引位置  
  56.         mUserIds.set(index, obj);  
  57.     } else {  
  58.         // 如果uid < 10000,则把对应的值保存在mOtherUserIds变量中  
  59.         if (mOtherUserIds.get(uid) != null) {  
  60.             PackageManagerService.reportSettingsProblem(Log.ERROR,  
  61.                     "Adding duplicate shared id: " + uid  
  62.                             + " name=" + name);  
  63.             return false;  
  64.         }  
  65.         mOtherUserIds.put(uid, obj);  
  66.     }  
  67.     return true;  
  68. }  


至此,对Settings的分析就告一段落了。下面继续分析PMS的构造方法:

[java]  view plain  copy
  1. private static final long WATCHDOG_TIMEOUT = 1000*60*10;   
  2.   
  3. public PackageManagerService(Context context, Installer installer,  
  4.         boolean factoryTest, boolean onlyCore) {  
  5.   
  6.     . . .  
  7.   
  8.     // 应用安装器  
  9.     mInstaller = installer;  
  10.     // 实例化类优化器  
  11.     mPackageDexOptimizer = new PackageDexOptimizer(this);  
  12.     mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());  
  13.   
  14.     mOnPermissionChangeListeners = new OnPermissionChangeListeners(  
  15.             FgThread.get().getLooper());  
  16.   
  17.     // 获取当前显示屏信息  
  18.     getDefaultDisplayMetrics(context, mMetrics);  
  19.   
  20.     // 获取系统的初始化变量  
  21.     SystemConfig systemConfig = SystemConfig.getInstance();  
  22.     mGlobalGids = systemConfig.getGlobalGids();  
  23.     mSystemPermissions = systemConfig.getSystemPermissions();  
  24.     mAvailableFeatures = systemConfig.getAvailableFeatures();  
  25.   
  26.     // 创建一个HandlerThread子类的实例,主要处理应用的安装和卸载  
  27.     mHandlerThread = new ServiceThread(TAG,  
  28.             Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);  
  29.     mHandlerThread.start();  
  30.     // 以mHandlerThread线程的looper创建的Handler实例,该Handler运行在mHandlerThread线程  
  31.     mHandler = new PackageHandler(mHandlerThread.getLooper());  
  32.     // 把mHandler加入到watchdog中  
  33.     Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);  
  34.   
  35.     // /data目录  
  36.     File dataDir = Environment.getDataDirectory();  
  37.     // /data/data目录  
  38.     mAppDataDir = new File(dataDir, "data");  
  39.     // /data/app目录,保存的是用户自己安装的app  
  40.     mAppInstallDir = new File(dataDir, "app");  
  41.     mAppLib32InstallDir = new File(dataDir, "app-lib");  
  42.     mAsecInternalPath = new File(dataDir, "app-asec").getPath();  
  43.     mUserAppDataDir = new File(dataDir, "user");  
  44.     // /data/app-parivate目录,保存的是受DRM保护的私有app  
  45.     mDrmAppPrivateInstallDir = new File(dataDir, "app-private");  
  46.     mRegionalizationAppInstallDir = new File(dataDir, "app-regional");  
  47.   
  48.     // 实例化用户管理服务,多用户时使用  
  49.     sUserManager = new UserManagerService(context, this,  
  50.             mInstallLock, mPackages);  
  51.   
  52.     // 通过systemConfig获取系统中定义的权限,这些权限保存在/system/etc/permissions目录下的文件中  
  53.     ArrayMap<String, SystemConfig.PermissionEntry> permConfig  
  54.             = systemConfig.getPermissions();  
  55.     for (int i=0; i<permConfig.size(); i++) {  
  56.         SystemConfig.PermissionEntry perm = permConfig.valueAt(i);  
  57.         // 根据权限名获取基本权限信息  
  58.         BasePermission bp = mSettings.mPermissions.get(perm.name);  
  59.         if (bp == null) {  
  60.             bp = new BasePermission(perm.name, "android", BasePermission.TYPE_BUILTIN);  
  61.             // 如果基本权限信息为null,则根据权限名创建它并保存到mSettings.mPermissions中  
  62.             mSettings.mPermissions.put(perm.name, bp);  
  63.         }  
  64.         if (perm.gids != null) {  
  65.             bp.setGids(perm.gids, perm.perUser);  
  66.         }  
  67.     }  
  68.   
  69.     // 通过systemConfig获取系统的共享库列表,并保存在mSharedLibraries中  
  70.     ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();  
  71.     for (int i=0; i<libConfig.size(); i++) {  
  72.         mSharedLibraries.put(libConfig.keyAt(i),  
  73.                 new SharedLibraryEntry(libConfig.valueAt(i), null));  
  74.     }  
  75.   
  76.     // 解析SELinux的策略文件  
  77.     mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();  
  78.   
  79.     // 恢复上一次的应用程序安装信息,扫描package.xml文件  
  80.     mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),  
  81.             mSdkVersion, mOnlyCore);  
  82.   
  83.     // 这里获取的customResolverActivity为空字符串  
  84.     String customResolverActivity = Resources.getSystem().getString(  
  85.             R.string.config_customResolverActivity);  
  86.     if (TextUtils.isEmpty(customResolverActivity)) {  
  87.         customResolverActivity = null;  
  88.     } else {  
  89.         mCustomResolverComponentName = ComponentName.unflattenFromString(  
  90.                 customResolverActivity);  
  91.     }  
  92.     . . .  
  93.   
  94. }  


下面分析下SystemConfig类的方法:

[java]  view plain  copy
  1. static SystemConfig sInstance;  
  2.   
  3. public static SystemConfig getInstance() {  
  4.     synchronized (SystemConfig.class) {  
  5.         if (sInstance == null) {  
  6.             sInstance = new SystemConfig();  
  7.         }  
  8.         return sInstance;  
  9.     }  
  10. }  
  11.   
  12. SystemConfig() {  
  13.     // Read configuration from system  
  14.     // Environment.getRootDirectory()获取到的是/system目录  
  15.     readPermissions(Environment.buildPath(  
  16.             Environment.getRootDirectory(), "etc""sysconfig"), false);  
  17.     // Read configuration from the old permissions dir  
  18.     readPermissions(Environment.buildPath(  
  19.             Environment.getRootDirectory(), "etc""permissions"), false);  
  20.     // Only read features from OEM config  
  21.     readPermissions(Environment.buildPath(  
  22.             Environment.getOemDirectory(), "etc""sysconfig"), true);  
  23.     readPermissions(Environment.buildPath(  
  24.             Environment.getOemDirectory(), "etc""permissions"), true);  
  25. }  
  26.   
  27. void readPermissions(File libraryDir, boolean onlyFeatures) {  
  28.     // Read permissions from given directory.  
  29.     if (!libraryDir.exists() || !libraryDir.isDirectory()) {  
  30.         if (!onlyFeatures) {  
  31.             Slog.w(TAG, "No directory " + libraryDir + ", skipping");  
  32.         }  
  33.         return;  
  34.     }  
  35.     if (!libraryDir.canRead()) {  
  36.         Slog.w(TAG, "Directory " + libraryDir + " cannot be read");  
  37.         return;  
  38.     }  
  39.   
  40.     // 遍历目标文件夹下所有的.xml文件  
  41.     File platformFile = null;  
  42.     for (File f : libraryDir.listFiles()) {  
  43.         // 最后解析platform.xml文件  
  44.         if (f.getPath().endsWith("etc/permissions/platform.xml")) {  
  45.             platformFile = f;  
  46.             continue;  
  47.         }  
  48.   
  49.         if (!f.getPath().endsWith(".xml")) {  
  50.             Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");  
  51.             continue;  
  52.         }  
  53.         if (!f.canRead()) {  
  54.             Slog.w(TAG, "Permissions library file " + f + " cannot be read");  
  55.             continue;  
  56.         }  
  57.   
  58.         // 解析xml文件,保存到相应的变量中  
  59.         readPermissionsFromXml(f, onlyFeatures);  
  60.     }  
  61.   
  62.     // 最后解析platform.xml文件,该文件的优先级最高  
  63.     if (platformFile != null) {  
  64.         readPermissionsFromXml(platformFile, onlyFeatures);  
  65.     }  
  66. }  
  67.   
  68.   
  69. public int[] getGlobalGids() {  
  70.     // 该变量保存xml中group标签定义的gid  
  71.     return mGlobalGids;  
  72. }  
  73.   
  74. public SparseArray<ArraySet<String>> getSystemPermissions() {  
  75.     // uid为索引,存储一个字符串集合,用于描述指定UID所拥有的权限。解析assign-permission标签而来  
  76.     return mSystemPermissions;  
  77. }  
  78.   
  79. public ArrayMap<String, String> getSharedLibraries() {  
  80.     // 解析library标签而来,key为库的名字,value为库文件的位置  
  81.     return mSharedLibraries;  
  82. }  
  83.   
  84. public ArrayMap<String, FeatureInfo> getAvailableFeatures() {  
  85.     // 解析feature标签而来。key为feature的字符串描述,value为FeatureInfo对象  
  86.     return mAvailableFeatures;  
  87. }  
  88.   
  89. public ArrayMap<String, PermissionEntry> getPermissions() {  
  90.     // 解析permission标签而来,key为权限名,value为PermissionEntry对象。  
  91.     return mPermissions;  
  92. }  


Android系统每次启动时,都会重新安装一遍系统中的应用程序,但是有些应用程序信息每次安装都是需要保持一致的,如应用程序的Linux用户ID等。否则应用程序每次在系统重启后表现可能不一致。因此PMS每次在安装完成应用程序之后,都需要将它们的信息保存下来,以便下次安装时可以恢复回来。恢复上一次的应用程序安装信息是通过Settings类的readLPw方法实现的。下面就分析下该方法扫描packages.xml文件或其备份文件的过程:

[java]  view plain  copy
  1. // 读取应用程序的安装信息  
  2. boolean readLPw(PackageManagerService service, List<UserInfo> users, int sdkVersion,  
  3.         boolean onlyCore) {  
  4.     FileInputStream str = null;  
  5.     // 先检查/data/system/packages-backup.xml文件是否存在,  
  6.     // 如果存在就将它的内容作为上一次的应用程序安装信息  
  7.     if (mBackupSettingsFilename.exists()) {  
  8.         try {  
  9.             str = new FileInputStream(mBackupSettingsFilename);  
  10.             mReadMessages.append("Reading from backup settings file\n");  
  11.             PackageManagerService.reportSettingsProblem(Log.INFO,  
  12.                     "Need to read from backup settings file");  
  13.             if (mSettingsFilename.exists()) {  
  14.                 // 备份文件和原文件都存在时,原文件可能已经损坏了,故这里要删除掉原文件  
  15.                 Slog.w(PackageManagerService.TAG, "Cleaning up settings file "  
  16.                         + mSettingsFilename);  
  17.                 mSettingsFilename.delete();  
  18.             }  
  19.         } catch (java.io.IOException e) {  
  20.             // We'll try for the normal settings file.  
  21.         }  
  22.     }  
  23.   
  24.     mPendingPackages.clear();  
  25.     mPastSignatures.clear();  
  26.     mKeySetRefs.clear();  
  27.   
  28.     try {  
  29.         // 如果str为null,说明没有读取备份文件,下面要读取原文件  
  30.         if (str == null) {  
  31.             if (!mSettingsFilename.exists()) {  
  32.                 mReadMessages.append("No settings file found\n");  
  33.                 PackageManagerService.reportSettingsProblem(Log.INFO,  
  34.                         "No settings file; creating initial state");  
  35.                 // 如果原文件不存在,根据默认值创建版本信息。  
  36.                 findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL);  
  37.                 findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL);  
  38.                 return false;  
  39.             }  
  40.             str = new FileInputStream(mSettingsFilename);  
  41.         }  
  42.         // 创建解析器  
  43.         XmlPullParser parser = Xml.newPullParser();  
  44.         parser.setInput(str, StandardCharsets.UTF_8.name());  
  45.   
  46.         int type;  
  47.         while ((type = parser.next()) != XmlPullParser.START_TAG  
  48.                 && type != XmlPullParser.END_DOCUMENT) {  
  49.             ;  
  50.         }  
  51.   
  52.         if (type != XmlPullParser.START_TAG) {  
  53.             mReadMessages.append("No start tag found in settings file\n");  
  54.             PackageManagerService.reportSettingsProblem(Log.WARN,  
  55.                     "No start tag found in package manager settings");  
  56.             Slog.wtf(PackageManagerService.TAG,  
  57.                     "No start tag found in package manager settings");  
  58.             return false;  
  59.         }  
  60.   
  61.         int outerDepth = parser.getDepth();  
  62.         // 开始解析xml文件  
  63.         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT  
  64.                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {  
  65.             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {  
  66.                 continue;  
  67.             }  
  68.   
  69.             String tagName = parser.getName();  
  70.             if (tagName.equals("package")) {  
  71.                 // 解析标签为package的元素,一个应用一个package标签.  
  72.                 // 获取上一次安装这个应用程序时所分配给它的Linux用户ID  
  73.                 readPackageLPw(parser);  
  74.             } else if (tagName.equals("permissions")) {  
  75.                 // 解析系统定义了哪些权限,由哪个包定义  
  76.                 readPermissionsLPw(mPermissions, parser);  
  77.             } else if (tagName.equals("permission-trees")) {  
  78.                 readPermissionsLPw(mPermissionTrees, parser);  
  79.             } else if (tagName.equals("shared-user")) {  
  80.                 // shared-user标签是以sharedUserId的名字为name属性,然后为它分配一个userId赋值给userId属性。  
  81.                 // 其他应用用到该sharedUserId的,userId都是shared-user标签中的userId属性值  
  82.                 // 解析上一次应用程序安装信息中的共享Linux用户信息  
  83.                 readSharedUserLPw(parser);  
  84.             }  
  85.             . . .  
  86.             else {  
  87.                 Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "  
  88.                         + parser.getName());  
  89.                 XmlUtils.skipCurrentTag(parser);  
  90.             }  
  91.         }  
  92.   
  93.         str.close();  
  94.   
  95.     } catch (XmlPullParserException e) {  
  96.         mReadMessages.append("Error reading: " + e.toString());  
  97.         PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);  
  98.         Slog.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);  
  99.   
  100.     } catch (java.io.IOException e) {  
  101.         mReadMessages.append("Error reading: " + e.toString());  
  102.         PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);  
  103.         Slog.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);  
  104.     }  
  105.   
  106.     . . .  
  107.       
  108.     // 先看readPackageLPw方法再往下面看  
  109.     final int N = mPendingPackages.size();  
  110.   
  111.     // 循环遍历mPendingPackages中的PendingPackage对象,以便为它们所描述的应用程序保存上一次安装时所使用的Linux用户ID  
  112.     for (int i = 0; i < N; i++) {  
  113.         final PendingPackage pp = mPendingPackages.get(i);  
  114.         // 根据uid获取对应的对象,如果在mUserIds或mOtherUserIds中存在一个与userId对应的Object对象,  
  115.         // 且该对象是SharedUserSetting的类型,则说明pp所描述的应用程序上一次所使用的Linux用户ID是有效的  
  116.         Object idObj = getUserIdLPr(pp.sharedId);  
  117.         if (idObj != null && idObj instanceof SharedUserSetting) {  
  118.             // 为该应用程序分配一个Linux用户ID  
  119.             PackageSetting p = getPackageLPw(pp.name, null, pp.realName,  
  120.                     (SharedUserSetting) idObj, pp.codePath, pp.resourcePath,  
  121.                     pp.legacyNativeLibraryPathString, pp.primaryCpuAbiString,  
  122.                     pp.secondaryCpuAbiString, pp.versionCode, pp.pkgFlags, pp.pkgPrivateFlags,  
  123.                     nulltrue /* add */false /* allowInstall */);  
  124.             if (p == null) {  
  125.                 PackageManagerService.reportSettingsProblem(Log.WARN,  
  126.                         "Unable to create application package for " + pp.name);  
  127.                 continue;  
  128.             }  
  129.             p.copyFrom(pp);  
  130.         } else if (idObj != null) {  
  131.             String msg = "Bad package setting: package " + pp.name + " has shared uid "  
  132.                     + pp.sharedId + " that is not a shared uid\n";  
  133.             mReadMessages.append(msg);  
  134.             PackageManagerService.reportSettingsProblem(Log.ERROR, msg);  
  135.         } else {  
  136.             String msg = "Bad package setting: package " + pp.name + " has shared uid "  
  137.                     + pp.sharedId + " that is not defined\n";  
  138.             mReadMessages.append(msg);  
  139.             PackageManagerService.reportSettingsProblem(Log.ERROR, msg);  
  140.         }  
  141.     }  
  142.     mPendingPackages.clear();  
  143.     . . .  
  144.   
  145.     mReadMessages.append("Read completed successfully: " + mPackages.size() + " packages, "  
  146.             + mSharedUsers.size() + " shared uids\n");  
  147.   
  148.     return true;  
  149. }  
  150.   
  151. private static final String ATTR_NAME = "name";  
  152. // 解析标签为package的元素,可以获取到上一次安装这个应用程序时所分配给它的Linux用户ID  
  153. private void readPackageLPw(XmlPullParser parser) throws XmlPullParserException, IOException {  
  154.     String name = null;  
  155.     String idStr = null;  
  156.     String sharedIdStr = null;  
  157.     . . .  
  158.     try {  
  159.         // 应用程序的包名  
  160.         name = parser.getAttributeValue(null, ATTR_NAME);  
  161.         // 应用程序所使用的独立Linux用户ID  
  162.         idStr = parser.getAttributeValue(null"userId");  
  163.         // 应用程序所使用的共享Linux用户ID  
  164.         sharedIdStr = parser.getAttributeValue(null"sharedUserId");  
  165.         . . .  
  166.   
  167.         int userId = idStr != null ? Integer.parseInt(idStr) : 0;  
  168.         . . .  
  169.         if (name == null) {  
  170.             // 安装的应用程序包名不能为null,否则上报错误信息  
  171.             PackageManagerService.reportSettingsProblem(Log.WARN,  
  172.                     "Error in package manager settings: <package> has no name at "  
  173.                             + parser.getPositionDescription());  
  174.         }  
  175.         . . .  
  176.         else if (userId > 0) {  
  177.             // 检查该应用是否被分配了一个独立的uid,如果是就在系统中保存值为userId的Linux用户ID  
  178.             packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),  
  179.                     new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString,  
  180.                     secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags,  
  181.                     pkgPrivateFlags);  
  182.             . . .  
  183.         } else if (sharedIdStr != null) {  
  184.             // 如果sharedIdStr不为null,说明安装该应用时PMS给它分配了一个共享的uid。此时不能马上保存该uid,  
  185.             // 因为这个uid不属于它自己所有,等解析完shared-user节点之后,再为它保存上一次所使用的Linux用户ID  
  186.             userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;  
  187.             if (userId > 0) {  
  188.                 // 创建PendingPackage对象并保存在mPendingPackages中,用来描述一个Linux用户ID还未确定的应用程序  
  189.                 packageSetting = new PendingPackage(name.intern(), realName, new File(  
  190.                         codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr,  
  191.                         primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,  
  192.                         userId, versionCode, pkgFlags, pkgPrivateFlags);  
  193.                 . . .  
  194.                 mPendingPackages.add((PendingPackage) packageSetting);  
  195.                 . . .  
  196.             }  
  197.             . . .  
  198.         } else {  
  199.             PackageManagerService.reportSettingsProblem(Log.WARN,  
  200.                     "Error in package manager settings: package " + name + " has bad userId "  
  201.                             + idStr + " at " + parser.getPositionDescription());  
  202.         }  
  203.     } catch (NumberFormatException e) {  
  204.         PackageManagerService.reportSettingsProblem(Log.WARN,  
  205.                 "Error in package manager settings: package " + name + " has bad userId "  
  206.                         + idStr + " at " + parser.getPositionDescription());  
  207.     }  
  208. }  
  209.   
  210. // 在系统中保存值为userId的Linux用户ID  
  211. // 在PMS中,每一个应用程序的安装信息都是使用一个PackageSetting对象来描述的。这些对象保存在mPackages中。  
  212. PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,  
  213.         String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,  
  214.         String cpuAbiOverrideString, int uid, int vc, int pkgFlags, int pkgPrivateFlags) {  
  215.     // 根据包名获取应用程序的安装信息  
  216.     PackageSetting p = mPackages.get(name);  
  217.     if (p != null) {  
  218.         // 如果应用程序的安装信息不为null,并且uid和目标uid相同则说明PMS已经为该应用程序分配过uid了  
  219.         if (p.appId == uid) {  
  220.             return p;  
  221.         }  
  222.         PackageManagerService.reportSettingsProblem(Log.ERROR,  
  223.                 "Adding duplicate package, keeping first: " + name);  
  224.         return null;  
  225.     }  
  226.     // 如果mPackages中不存在与该包名对应的PackageSetting对象,则为该应用程序分配一个参数uid所描述的Linux用户ID  
  227.     p = new PackageSetting(name, realName, codePath, resourcePath,  
  228.             legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,  
  229.             cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags);  
  230.     p.appId = uid;  
  231.     // 在系统中保存保存值为uid的Linux用户ID  
  232.     if (addUserIdLPw(uid, p, name)) {  
  233.         mPackages.put(name, p);  
  234.         return p;  
  235.     }  
  236.     return null;  
  237. }  
  238.   
  239. // 解析上一次的应用程序安装信息中的共享Linux用户信息  
  240. private void readSharedUserLPw(XmlPullParser parser) throws XmlPullParserException,IOException {  
  241.     String name = null;  
  242.     String idStr = null;  
  243.     int pkgFlags = 0;  
  244.     int pkgPrivateFlags = 0;  
  245.     SharedUserSetting su = null;  
  246.     try {  
  247.         // 获取sharedUserId的名字  
  248.         name = parser.getAttributeValue(null, ATTR_NAME);  
  249.         // 所有共享该sharedUserId名字的应用程序uid  
  250.         idStr = parser.getAttributeValue(null"userId");  
  251.         int userId = idStr != null ? Integer.parseInt(idStr) : 0;  
  252.         // system属性用来描述这个共享uid是分配给一个系统类型的应用程序使用的还是分配给一个用户类型的应用程序使用的。  
  253.         if ("true".equals(parser.getAttributeValue(null"system"))) {  
  254.             pkgFlags |= ApplicationInfo.FLAG_SYSTEM;  
  255.         }  
  256.         if (name == null) {  
  257.             PackageManagerService.reportSettingsProblem(Log.WARN,  
  258.                     "Error in package manager settings: <shared-user> has no name at "  
  259.                             + parser.getPositionDescription());  
  260.         } else if (userId == 0) {  
  261.             PackageManagerService.reportSettingsProblem(Log.WARN,  
  262.                     "Error in package manager settings: shared-user " + name  
  263.                             + " has bad userId " + idStr + " at "  
  264.                             + parser.getPositionDescription());  
  265.         } else {  
  266.             // 调用addSharedUserLPw方法在系统中为名称为name的共享Linux用户保存一个值为userId的Linux用户  
  267.             if ((su = addSharedUserLPw(name.intern(), userId, pkgFlags, pkgPrivateFlags))  
  268.                     == null) {  
  269.                 PackageManagerService  
  270.                         .reportSettingsProblem(Log.ERROR, "Occurred while parsing settings at "  
  271.                                 + parser.getPositionDescription());  
  272.             }  
  273.         }  
  274.     } catch (NumberFormatException e) {  
  275.         PackageManagerService.reportSettingsProblem(Log.WARN,  
  276.                 "Error in package manager settings: package " + name + " has bad userId "  
  277.                         + idStr + " at " + parser.getPositionDescription());  
  278.     }  
  279.   
  280.     . . .  
  281. }  
  282.   
  283. // 在系统中为名称为name的共享Linux用户保存一个值为userId的Linux用户  
  284. // 在PMS中,每一个共享Linux用户都是使用一个SharedUserSetting对象来描述的。这些对象保存在mSharedUsers中。  
  285. SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {  
  286.     // 根据包名获取共享应用程序的安装信息,如果存在并且userId等于参数uid的值,则说明PMS已经为该应用程序分配过uid了  
  287.     SharedUserSetting s = mSharedUsers.get(name);  
  288.     if (s != null) {  
  289.         if (s.userId == uid) {  
  290.             return s;  
  291.         }  
  292.         PackageManagerService.reportSettingsProblem(Log.ERROR,  
  293.                 "Adding duplicate shared user, keeping first: " + name);  
  294.         return null;  
  295.     }  
  296.     // 如果mSharedUsers中不存在与该包名对应的SharedUserSetting对象,则为该应用程序分配一个参数uid所描述的Linux用户ID  
  297.     s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);  
  298.     s.userId = uid;  
  299.     // 在系统中保存保存值为uid的Linux用户ID  
  300.     if (addUserIdLPw(uid, s, name)) {  
  301.         mSharedUsers.put(name, s);  
  302.         return s;  
  303.     }  
  304.     return null;  
  305. }  
  306.   
  307. // 为应用程序分配一个Linux用户ID  
  308. private PackageSetting getPackageLPw(String name, PackageSetting origPackage,  
  309.         String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,  
  310.         String legacyNativeLibraryPathString, String primaryCpuAbiString,  
  311.         String secondaryCpuAbiString, int vc, int pkgFlags, int pkgPrivateFlags,  
  312.         UserHandle installUser, boolean add, boolean allowInstall) {  
  313.     // 根据name从mPackages中获取PackageSetting对象  
  314.     PackageSetting p = mPackages.get(name);  
  315.     UserManagerService userManager = UserManagerService.getInstance();  
  316.     if (p != null) {  
  317.         . . .  
  318.   
  319.         // 判断已经存在的p对象的sharedUser是否和传递来的一致,若不一致说明对象p已不能描述应用的安装信息,需要重新分配  
  320.         if (p.sharedUser != sharedUser) {  
  321.             PackageManagerService.reportSettingsProblem(Log.WARN,  
  322.                     "Package " + name + " shared user changed from "  
  323.                     + (p.sharedUser != null ? p.sharedUser.name : "<nothing>")  
  324.                     + " to "  
  325.                     + (sharedUser != null ? sharedUser.name : "<nothing>")  
  326.                     + "; replacing with new");  
  327.             p = null;  
  328.         } else {  
  329.             // 判断当前分配的应用是否是系统应用/私有特权应用  
  330.             p.pkgFlags |= pkgFlags & ApplicationInfo.FLAG_SYSTEM;  
  331.             p.pkgPrivateFlags |= pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;  
  332.         }  
  333.     }  
  334.     // p为null说明要重新分配Linux用户ID  
  335.     if (p == null) {  
  336.         if (origPackage != null) {  
  337.             // origPackage不为null说明该应用程序在系统中有一个旧版本  
  338.             // 根据旧版本的应用程序创建一个新的PackageSetting对象  
  339.             p = new PackageSetting(origPackage.name, name, codePath, resourcePath,  
  340.                     legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,  
  341.                     null /* cpuAbiOverrideString */, vc, pkgFlags, pkgPrivateFlags);  
  342.             . . .  
  343.             // 把旧安装包的userId分配给该应用程序  
  344.             p.appId = origPackage.appId;  
  345.             . . .  
  346.         } else {  
  347.             // origPackage为null,说明该应用是一个新安装的应用程序  
  348.             // 根据传递过来的参数新建一个PackageSetting对象  
  349.             p = new PackageSetting(name, realName, codePath, resourcePath,  
  350.                     legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,  
  351.                     null /* cpuAbiOverrideString */, vc, pkgFlags, pkgPrivateFlags);  
  352.             p.setTimeStamp(codePath.lastModified());  
  353.             p.sharedUser = sharedUser;  
  354.             // 如果该应用不是系统应用,则新安装后是停止运行状态  
  355.             if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {  
  356.                 List<UserInfo> users = getAllUsers();  
  357.                 final int installUserId = installUser != null ? installUser.getIdentifier() : 0;  
  358.                 if (users != null && allowInstall) {  
  359.                     for (UserInfo user : users) {  
  360.                         final boolean installed = installUser == null  
  361.                                 || (installUserId == UserHandle.USER_ALL  
  362.                                     && !isAdbInstallDisallowed(userManager, user.id))  
  363.                                 || installUserId == user.id;  
  364.                         // 设置该应用是停止运行状态  
  365.                         p.setUserState(user.id, COMPONENT_ENABLED_STATE_DEFAULT,  
  366.                                 installed,  
  367.                                 true// stopped,  
  368.                                 true// notLaunched  
  369.                                 false// hidden  
  370.                                 nullnullnull,  
  371.                                 false// blockUninstall  
  372.                                 INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);  
  373.                         writePackageRestrictionsLPr(user.id);  
  374.                     }  
  375.                 }  
  376.             }  
  377.             if (sharedUser != null) {  
  378.                 // 如果sharedUser不为null,说明该新安装应用程序设置了sharedUserId属性,  
  379.                 // 则把sharedUserId的userId分配给该应用  
  380.                 p.appId = sharedUser.userId;  
  381.             } else {  
  382.                 // 如果该新安装应用程序没有设置sharedUserId属性,则需要为该应用程序分配新的Linux用户ID  
  383.                   
  384.                 // 根据name值从已经禁用的系统应用程序列表中获取PackageSetting对象  
  385.                 PackageSetting dis = mDisabledSysPackages.get(name);  
  386.                 if (dis != null) {  
  387.                     // 如果dis不为null,说明该应用程序是一个已经禁用的系统应用,此时  
  388.                     // 只需用把它原来的userId分配给它即可  
  389.                     . . .  
  390.                     // 把原来的userId分配给该应用程序  
  391.                     p.appId = dis.appId;  
  392.                     . . .  
  393.                     // 在系统中保存保存值为uid的Linux用户ID  
  394.                     addUserIdLPw(p.appId, p, name);  
  395.                 } else {  
  396.                     // 如果dis为null,说明需要为该新安装应用程序新分配一个Linux用户ID  
  397.                     p.appId = newUserIdLPw(p);  
  398.                 }  
  399.             }  
  400.         }  
  401.         if (p.appId < 0) {  
  402.             PackageManagerService.reportSettingsProblem(Log.WARN,  
  403.                     "Package " + name + " could not be assigned a valid uid");  
  404.             return null;  
  405.         }  
  406.         if (add) {  
  407.             // 调用addPackageSettingLPw方法把p保存到mPackages中,  
  408.             // 表示它所描述的应用程序已经成功地安装在系统中了  
  409.             addPackageSettingLPw(p, name, sharedUser);  
  410.         }  
  411.     } else {  
  412.         // p不为null说明不需要重新分配Linux用户ID  
  413.         if (installUser != null && allowInstall) {  
  414.             // The caller has explicitly specified the user they want this  
  415.             // package installed for, and the package already exists.  
  416.             // Make sure it conforms to the new request.  
  417.             List<UserInfo> users = getAllUsers();  
  418.             if (users != null) {  
  419.                 for (UserInfo user : users) {  
  420.                     if ((installUser.getIdentifier() == UserHandle.USER_ALL  
  421.                                 && !isAdbInstallDisallowed(userManager, user.id))  
  422.                             || installUser.getIdentifier() == user.id) {  
  423.                         boolean installed = p.getInstalled(user.id);  
  424.                         if (!installed) {  
  425.                             p.setInstalled(true, user.id);  
  426.                             writePackageRestrictionsLPr(user.id);  
  427.                         }  
  428.                     }  
  429.                 }  
  430.             }  
  431.         }  
  432.     }  
  433.     return p;  
  434. }  
  435.   
  436. // 为该新安装应用程序新分配一个Linux用户ID  
  437. private int newUserIdLPw(Object obj) {  
  438.     // 获取之前已经分配出去的Linux用户ID的数量  
  439.     final int N = mUserIds.size();  
  440.     for (int i = mFirstAvailableUid; i < N; i++) {  
  441.         // 如果第i个对象值为null,说明值为Process.FIRST_APPLICATION_UID + i  
  442.         // 的Linux用户ID还未分配出去,这里就将该值分配给新安装的应用程序使用  
  443.         if (mUserIds.get(i) == null) {  
  444.             mUserIds.set(i, obj);  
  445.             return Process.FIRST_APPLICATION_UID + i;  
  446.         }  
  447.     }  
  448.   
  449.     // 如果已经没有值可分配时,则返回-1  
  450.     if (N > (Process.LAST_APPLICATION_UID-Process.FIRST_APPLICATION_UID)) {  
  451.         return -1;  
  452.     }  
  453.   
  454.     mUserIds.add(obj);  
  455.     // 如果不能在mUserIds中找到空闲的Linux用户ID,且没有超过分配限制,则把  
  456.     // Process.FIRST_APPLICATION_UID + N分配给新安装应用程序使用  
  457.     return Process.FIRST_APPLICATION_UID + N;  
  458. }  


到这里,扫描目标文件夹之前的准备工作就介绍完了。主要是扫描并解析xml文件将上一次的应用程序安装信息恢复完成。

2.扫描目标文件夹

先看下时序图:

下面主要是扫描系统中的apk文件了。继续分析PMS的构造方法:

[java]  view plain  copy
  1. private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";  
  2.   
  3. public PackageManagerService(Context context, Installer installer,  
  4.         boolean factoryTest, boolean onlyCore) {  
  5.   
  6.     . . .  
  7.     // 记录开始扫描的时间  
  8.     long startTime = SystemClock.uptimeMillis();  
  9.   
  10.     // 初始化扫描参数  
  11.     final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING | SCAN_INITIAL;  
  12.   
  13.     // /system/framework目录保存的应用程序是资源型的。资源型的应用程序是用来打包资源文件的,不包含有执行代码  
  14.     File frameworkDir = new File(Environment.getRootDirectory(), "framework");  
  15.     . . .  
  16.     // Collect vendor overlay packages.  
  17.     // (Do this before scanning any apps.)  
  18.     // 收集供应商提供的覆盖应用程序  
  19.     File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);  
  20.     scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM  
  21.             | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);  
  22.   
  23.     // Find base frameworks (resource packages without code).  
  24.     scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM  
  25.             | PackageParser.PARSE_IS_SYSTEM_DIR  
  26.             | PackageParser.PARSE_IS_PRIVILEGED,  
  27.             scanFlags | SCAN_NO_DEX, 0);  
  28.   
  29.     // Collected privileged system packages./system/priv-app系统自带应用程序  
  30.     final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");  
  31.     scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM  
  32.             | PackageParser.PARSE_IS_SYSTEM_DIR  
  33.             | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);  
  34.   
  35.     // Collect ordinary system packages./system/app目录保存的是系统自带的应用程序  
  36.     final File systemAppDir = new File(Environment.getRootDirectory(), "app");  
  37.     scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM  
  38.             | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);  
  39.   
  40.     // Collect all vendor packages.供应商提供的应用程序  
  41.     File vendorAppDir = new File("/vendor/app");  
  42.     try {  
  43.         vendorAppDir = vendorAppDir.getCanonicalFile();  
  44.     } catch (IOException e) {  
  45.         // failed to look up canonical path, continue with original one  
  46.     }  
  47.     scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM  
  48.             | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);  
  49.     if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");  
  50.     mInstaller.moveFiles();  
  51.   
  52.     // 删除各种无效安装包  
  53.       
  54.     if (!mOnlyCore) {  
  55.         EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,  
  56.                 SystemClock.uptimeMillis());  
  57.         scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);  
  58.   
  59.         scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,  
  60.                 scanFlags | SCAN_REQUIRE_KNOWN, 0);  
  61.         . . .  
  62.   
  63.     }  
  64.   
  65.     // Now that we know all the packages we are keeping,  
  66.     // read and update their last usage times.  
  67.     mPackageUsage.readLP();// 更新各安装包的上次使用时间  
  68.   
  69.     EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,  
  70.             SystemClock.uptimeMillis());  
  71.     // 输出扫描用的时间  
  72.     Slog.i(TAG, "Time to scan packages: "  
  73.             + ((SystemClock.uptimeMillis()-startTime)/1000f)  
  74.             + " seconds");  
  75.     . . .  
  76. }  


上面这段代码主要是扫描系统中各相关目录下的apk文件。

[java]  view plain  copy
  1. // 扫描给定目录下的apk文件  
  2. private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {  
  3.     final File[] files = dir.listFiles();  
  4.     if (ArrayUtils.isEmpty(files)) {  
  5.         Log.d(TAG, "No files in app dir " + dir);  
  6.         return;  
  7.     }  
  8.   
  9.     Log.d(TAG, "start scanDirLI:"+dir);  
  10.     // 使用多线程提高扫描速度  
  11.     int iMultitaskNum = SystemProperties.getInt("persist.pm.multitask"6);  
  12.     Log.d(TAG, "max thread:" + iMultitaskNum);  
  13.     final MultiTaskDealer dealer = (iMultitaskNum > 1) ? MultiTaskDealer.startDealer(  
  14.             MultiTaskDealer.PACKAGEMANAGER_SCANER, iMultitaskNum) : null;  
  15.   
  16.     for (File file : files) {  
  17.         final boolean isPackage = (isApkFile(file) || file.isDirectory())  
  18.                 && !PackageInstallerService.isStageName(file.getName());  
  19.         if (!isPackage) {  
  20.             continue;  
  21.         }  
  22.   
  23.         final File ref_file = file;  
  24.         final int ref_parseFlags = parseFlags;  
  25.         final int ref_scanFlags = scanFlags;  
  26.         final long ref_currentTime = currentTime;  
  27.         Runnable scanTask = new Runnable() {  
  28.             public void run() {  
  29.                 try {  
  30.                     // 解析apk文件  
  31.                     scanPackageLI(ref_file, ref_parseFlags | PackageParser.PARSE_MUST_BE_APK,  
  32.                             ref_scanFlags, ref_currentTime, null);  
  33.                 } catch (PackageManagerException e) {  
  34.                     Slog.w(TAG, "Failed to parse " + ref_file + ": " + e.getMessage());  
  35.   
  36.                     // 解析失败则删除无效的apk文件  
  37.                     if ((ref_parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&  
  38.                             e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {  
  39.                         logCriticalInfo(Log.WARN, "Deleting invalid package at " + ref_file);  
  40.                         if (ref_file.isDirectory()) {  
  41.                             mInstaller.rmPackageDir(ref_file.getAbsolutePath());  
  42.                         } else {  
  43.                             ref_file.delete();  
  44.                         }  
  45.                     }  
  46.                 }  
  47.             }  
  48.         };  
  49.   
  50.         if (dealer != null)  
  51.             dealer.addTask(scanTask);  
  52.         else  
  53.             scanTask.run();  
  54.     }  
  55.   
  56.     if (dealer != null)  
  57.         dealer.waitAll();  
  58.     Log.d(TAG, "end scanDirLI:"+dir);  
  59. }  
  60.   
  61. // 解析apk文件  
  62. private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,  
  63.         long currentTime, UserHandle user) throws PackageManagerException {  
  64.     if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);  
  65.     parseFlags |= mDefParseFlags;  
  66.     PackageParser pp = new PackageParser();  
  67.     . . .  
  68.   
  69.     final PackageParser.Package pkg;  
  70.     try {  
  71.         // 解析apk文件后返回一个PackageParser.Package对象  
  72.         pkg = pp.parsePackage(scanFile, parseFlags);  
  73.     } catch (PackageParserException e) {  
  74.         throw PackageManagerException.from(e);  
  75.     }  
  76.     . . .  
  77.   
  78.     // Set application objects path explicitly.  
  79.     pkg.applicationInfo.volumeUuid = pkg.volumeUuid;  
  80.     pkg.applicationInfo.setCodePath(pkg.codePath);  
  81.     pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);  
  82.     pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);  
  83.     pkg.applicationInfo.setResourcePath(resourcePath);  
  84.     pkg.applicationInfo.setBaseResourcePath(baseResourcePath);  
  85.     pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);  
  86.   
  87.     // 对刚解析apk文件返回的pkg对象所描述的apk文件进行安装,以便获取它的组件信息,以及为它分配Linux用户ID等。  
  88.     PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags  
  89.             | SCAN_UPDATE_SIGNATURE, currentTime, user);  
  90.   
  91.     return scannedPkg;  
  92. }  


接下来先看PackageParser类的parsePackage方法:

[java]  view plain  copy
  1. // 解析apk文件  
  2. public Package parsePackage(File packageFile, int flags) throws PackageParserException {  
  3.     if (packageFile.isDirectory()) {  
  4.         // 解析文件夹下的所有apk文件  
  5.         return parseClusterPackage(packageFile, flags);  
  6.     } else {  
  7.         // 解析独立apk文件  
  8.         return parseMonolithicPackage(packageFile, flags);  
  9.     }  
  10. }  
  11.   
  12. // 解析独立apk文件  
  13. public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {  
  14.     if (mOnlyCoreApps) {  
  15.         // 根据传递来的参数生成一个PackageLite对象,并对它进行是否为核心应用判断,若不是则抛异常  
  16.         final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);  
  17.         if (!lite.coreApp) {  
  18.             throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,  
  19.                     "Not a coreApp: " + apkFile);  
  20.         }  
  21.     }  
  22.   
  23.     final AssetManager assets = new AssetManager();  
  24.     try {  
  25.         // 解析apk文件  
  26.         final Package pkg = parseBaseApk(apkFile, assets, flags);  
  27.         pkg.codePath = apkFile.getAbsolutePath();  
  28.         return pkg;  
  29.     } finally {  
  30.         IoUtils.closeQuietly(assets);  
  31.     }  
  32. }  
  33.   
  34. private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";  
  35. // 解析apk文件  
  36. private Package parseBaseApk(File apkFile, AssetManager assets, int flags)  
  37.         throws PackageParserException {  
  38.     . . .  
  39.   
  40.     Resources res = null;  
  41.     XmlResourceParser parser = null;  
  42.     try {  
  43.          res = new Resources(assets, mMetrics, null);  
  44.   
  45.         assets.setConfiguration(00null0000000000000,  
  46.                 Build.VERSION.RESOURCES_SDK_INT);  
  47.         parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);  
  48.   
  49.         final String[] outError = new String[1];  
  50.         // 解析AndroidManifest.xml文件  
  51.         final Package pkg = parseBaseApk(res, parser, flags, outError);  
  52.         if (pkg == null) {  
  53.             throw new PackageParserException(mParseError,  
  54.                     apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);  
  55.         }  
  56.         . . .  
  57.         return pkg;  
  58.   
  59.     } catch (PackageParserException e) {  
  60.         throw e;  
  61.     } catch (Exception e) {  
  62.         throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,  
  63.                 "Failed to read manifest from " + apkPath, e);  
  64.     } finally {  
  65.         IoUtils.closeQuietly(parser);  
  66.     }  
  67. }  
  68.   
  69. // 解析AndroidManifest.xml文件  
  70. private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,  
  71.         String[] outError) throws XmlPullParserException, IOException {  
  72.     . . .  
  73.     try {  
  74.         // 解析apk的包名  
  75.         Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs, flags);  
  76.         pkgName = packageSplit.first;  
  77.         splitName = packageSplit.second;  
  78.     } catch (PackageParserException e) {  
  79.         mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;  
  80.         return null;  
  81.     }  
  82.   
  83.     final Package pkg = new Package(pkgName);  
  84.     boolean foundApp = false;  
  85.   
  86.     // 解析apk的版本号、versionName、等  
  87.     . . .  
  88.     // 解析manifest标签中的android:sharedUserId属性  
  89.     String str = sa.getNonConfigurationString(  
  90.             com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);  
  91.     if (str != null && str.length() > 0) {  
  92.         . . .  
  93.          // 把该属性值赋值给mSharedUserId  
  94.         pkg.mSharedUserId = str.intern();  
  95.         . . .  
  96.     }  
  97.     . . .  
  98.     sa.recycle();  
  99.     . . .  
  100.   
  101.     // 循环解析manifest的各个子标签  
  102.     while ((type = parser.next()) != XmlPullParser.END_DOCUMENT  
  103.             && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {  
  104.         if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {  
  105.             continue;  
  106.         }  
  107.   
  108.         String tagName = parser.getName();  
  109.         if (tagName.equals("application")) {  
  110.             . . .  
  111.             // 解析application标签,该标签用来描述与应用程序组件相关的信息  
  112.             if (!parseBaseApplication(pkg, res, parser, attrs, flags, outError)) {  
  113.                 return null;  
  114.             }  
  115.         } else if (tagName.equals("uses-permission")) {  
  116.             // 解析uses-permission标签,一个标签对应一个资源访问权限  
  117.             if (!parseUsesPermission(pkg, res, parser, attrs)) {  
  118.                 return null;  
  119.             }  
  120.         }  
  121.         . . .  
  122.         else {  
  123.             Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()  
  124.                     + " at " + mArchiveSourcePath + " "  
  125.                     + parser.getPositionDescription());  
  126.             XmlUtils.skipCurrentTag(parser);  
  127.             continue;  
  128.         }  
  129.     }  
  130.     . . .  
  131.     return pkg;  
  132. }  
  133.   
  134. // 解析application标签  
  135. private boolean parseBaseApplication(Package owner, Resources res,  
  136.         XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)  
  137.     throws XmlPullParserException, IOException {  
  138.     // 解析application标签的基本信息,图标、应用名等  
  139.     . . .  
  140.   
  141.   
  142.     final int innerDepth = parser.getDepth();  
  143.     int type;  
  144.     // 解析application的子标签  
  145.     while ((type = parser.next()) != XmlPullParser.END_DOCUMENT  
  146.             && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {  
  147.         if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {  
  148.             continue;  
  149.         }  
  150.   
  151.         String tagName = parser.getName();  
  152.         // 解析四大组件的标签,把相应配置信息都存放在owner的相应列表中  
  153.         if (tagName.equals("activity")) {  
  154.             Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false,  
  155.                     owner.baseHardwareAccelerated);  
  156.             . . .  
  157.             owner.activities.add(a);  
  158.         } else if (tagName.equals("receiver")) {  
  159.             Activity a = parseActivity(owner, res, parser, attrs, flags, outError, truefalse);  
  160.             . . .  
  161.             owner.receivers.add(a);  
  162.         } else if (tagName.equals("service")) {  
  163.             Service s = parseService(owner, res, parser, attrs, flags, outError);  
  164.             . . .  
  165.             owner.services.add(s);  
  166.         } else if (tagName.equals("provider")) {  
  167.             Provider p = parseProvider(owner, res, parser, attrs, flags, outError);  
  168.             . . .  
  169.             owner.providers.add(p);  
  170.         }  
  171.         . . .  
  172.         else {  
  173.             . . .  
  174.         }  
  175.     }  
  176.     . . .  
  177.     return true;  
  178. }  


到这里,PMS就解析完一个应用程序了,下面调用PMS类的scanPackageLI方法以便可以获得前面所解析的应用程序的组件配置信息,以及为这个应用程序分配Linux用户ID:

[java]  view plain  copy
  1. // 获得前面所解析的应用程序的组件配置信息,以及为这个应用程序分配Linux用户ID  
  2. private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags,  
  3.         int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {  
  4.     boolean success = false;  
  5.     try {  
  6.         final PackageParser.Package res = scanPackageDirtyLI(pkg, parseFlags, scanFlags,  
  7.                 currentTime, user);  
  8.         success = true;  
  9.         return res;  
  10.     } finally {  
  11.         if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {  
  12.             removeDataDirsLI(pkg.volumeUuid, pkg.packageName);  
  13.         }  
  14.     }  
  15. }  
  16.   
  17. // 获得前面所解析的应用程序的组件配置信息,以及为这个应用程序分配Linux用户ID  
  18. private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags,  
  19.         int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {  
  20.     final File scanFile = new File(pkg.codePath);  
  21.     . . .  
  22.   
  23.     SharedUserSetting suid = null;  
  24.     PackageSetting pkgSetting = null;  
  25.   
  26.     // 为参数pkg所描述的应用程序分配Linux用户ID  
  27.     // writer  
  28.     synchronized (mPackages) {  
  29.         if (pkg.mSharedUserId != null) {  
  30.             // 如果该应用有sharedUserId属性,则从mSettings中获取要为它分配的共享uid  
  31.             suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 00true);  
  32.             // 判断该共享uid是否合法  
  33.             . . .  
  34.         }  
  35.         . . .  
  36.   
  37.         // 为应用程序分配一个Linux用户ID  
  38.         pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,  
  39.                 destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,  
  40.                 pkg.applicationInfo.primaryCpuAbi,  
  41.                 pkg.applicationInfo.secondaryCpuAbi,  
  42.                 pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,  
  43.                 user, false);  
  44.         . . .  
  45.     }  
  46.     . . .  
  47.   
  48.     // writer  
  49.     synchronized (mPackages) {  
  50.         . . .  
  51.         // 把pkg所指向的一个Package对象保存在mSettings中  
  52.         mPackages.put(pkg.applicationInfo.packageName, pkg);  
  53.         . . .  
  54.   
  55.         // 把参数pkg所描述的应用程序的Content Provider组件配置信息保存在mProviders中  
  56.         int N = pkg.providers.size();  
  57.         StringBuilder r = null;  
  58.         int i;  
  59.         for (i=0; i<N; i++) {  
  60.             PackageParser.Provider p = pkg.providers.get(i);  
  61.             p.info.processName = fixProcessName(pkg.applicationInfo.processName,  
  62.                     p.info.processName, pkg.applicationInfo.uid);  
  63.             mProviders.addProvider(p);  
  64.             . . .  
  65.         }  
  66.   
  67.         // 把参数pkg所描述的应用程序的Service组件配置信息保存在mServices中  
  68.         N = pkg.services.size();  
  69.         r = null;  
  70.         for (i=0; i<N; i++) {  
  71.             PackageParser.Service s = pkg.services.get(i);  
  72.             s.info.processName = fixProcessName(pkg.applicationInfo.processName,  
  73.                     s.info.processName, pkg.applicationInfo.uid);  
  74.             mServices.addService(s);  
  75.             . . .  
  76.         }  
  77.   
  78.         // 把参数pkg所描述的应用程序的广播接收者组件配置信息保存在mReceivers中  
  79.         N = pkg.receivers.size();  
  80.         r = null;  
  81.         for (i=0; i<N; i++) {  
  82.             PackageParser.Activity a = pkg.receivers.get(i);  
  83.             a.info.processName = fixProcessName(pkg.applicationInfo.processName,  
  84.                     a.info.processName, pkg.applicationInfo.uid);  
  85.             mReceivers.addActivity(a, "receiver");  
  86.             . . .  
  87.         }  
  88.   
  89.         // 把参数pkg所描述的应用程序的Activity组件配置信息保存在mActivities中  
  90.         N = pkg.activities.size();  
  91.         r = null;  
  92.         for (i=0; i<N; i++) {  
  93.             PackageParser.Activity a = pkg.activities.get(i);  
  94.             a.info.processName = fixProcessName(pkg.applicationInfo.processName,  
  95.                     a.info.processName, pkg.applicationInfo.uid);  
  96.             mActivities.addActivity(a, "activity");  
  97.             . . .  
  98.         }  
  99.   
  100.         . . .  
  101.     }  
  102.   
  103.     return pkg;  
  104. }  


通过调用getPackageLPw方法为该应用程序分配uid后,一个应用程序就成功地安装到系统中了。到这里PMS构造方法的扫描目标文件夹的工作就完成了。

3.扫描之后的工作

先看下时序图:

当系统安装完所有应用程序后,PMS的构造方法就会调用updatePermissionsLPw方法为前面所安装的应用程序分配Linux用户组ID,即授予它们所申请的资源访问权限,以及调用Settings类的writeLPr方法将这些应用程序的安装信息保持到本地文件中:

[java]  view plain  copy
  1. public PackageManagerService(Context context, Installer installer,  
  2.         boolean factoryTest, boolean onlyCore) {  
  3.   
  4.     . . .  
  5.     // 为申请了特定的资源访问权限的应用程序分配相应的Linux用户组ID  
  6.     updatePermissionsLPw(nullnull, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags);  
  7.     . . .  
  8.       
  9.     // 将前面获取到的应用程序安装信息保存在本地的一个配置文件中,以便下一次再安装这些应用程序时  
  10.     // 可以将需要保持一致的应用程序信息恢复回来  
  11.     mSettings.writeLPr();  
  12.     . . .  
  13.     // Now after opening every single application zip, make sure they  
  14.     // are all flushed.  Not really needed, but keeps things nice and  
  15.     // tidy.  
  16.     Runtime.getRuntime().gc();  
  17.   
  18.     // Expose private service for system components to use.  
  19.     LocalServices.addService(PackageManagerInternal.classnew PackageManagerInternalImpl());  
  20.   
  21.   
  22.     // are all flushed.  Not really needed, but keeps things nice and  
  23.     // tidy.  
  24.     Runtime.getRuntime().gc();  
  25.   
  26.     // Expose private service for system components to use.  
  27.     LocalServices.addService(PackageManagerInternal.classnew PackageManagerInternalImpl());  
  28.   
  29. }  
  30.   
  31. // 为前面所安装的应用程序分配Linux用户组ID  
  32. private void updatePermissionsLPw(String changingPkg,  
  33.         PackageParser.Package pkgInfo, String replaceVolumeUuid, int flags) {  
  34.     . . .  
  35.   
  36.     // Now update the permissions for all packages, in particular  bold">new PackageManagerInternalImpl());  
  37.   
  38. }  
  39.   
  40. // 为前面所安装的应用程序分配Linux用户组ID  
  41. private void updatePermissionsLPw(String changingPkg,  
  42.         PackageParser.Package pkgInfo, String replaceVolumeUuid, int flags) {  
  43.     . . .  
  44.   
  45.     // Now update the permissions for all packages, in particular  
  46.     // replace the granted permissions of the system packages.  
  47.     if ((flags&UPDATE_PERMISSIONS_ALL) != 0) {  
  48.         for (PackageParser.Package pkg : mPackages.values()) {  
  49.             if}