PackageManagerService 源码扫描安装包分析

平台:android 8.0 源码


本文分析的问题:
apk的安装有如下四种方式:

  • apk随着PMS的启动而安装(本文)
  • adb install安装
  • ODM内置商店静默安装
  • 拷贝apk到手机,界面安装

这四种方式在代码里的实现其实就是如下两种:

  • PMS调用scanDirLI扫描安装(本文分析的方式)
  • 直接或间接调用installPackageAsUser安装

在systemserver的分析过程中,在startBootstrapServices()中启动PMS是通过调用PackageManagerService.main()启动了PMS服务的,本文接着从这开始分析.
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

  1. public static PackageManagerService main(Context context, Installer installer,
  2. boolean factoryTest, boolean onlyCore) {
  3. // Self-check for initial settings.
  4. PackageManagerServiceCompilerMapping.checkProperties();
  5. PackageManagerService m = new PackageManagerService(context, installer,
  6. factoryTest, onlyCore);
  7. m.enableSystemUserPackages();
  8. ServiceManager.addService("package", m);
  9. return m;
  10. }

上面的main()方法比较简单,重点就是创建了PackageManagerService对象,并且把它加入到ServiceManager中,本文的重点就是分析PackageManagerService对象的创建. 在这其中会涉及到在同一个包下面的其他.java类,比较核心的有:Settings.java, 接着分析PackageManagerService.java的构造方法,该方法相当的长,分段进行分析

  1. public PackageManagerService(Context context, Installer installer,
  2. boolean factoryTest, boolean onlyCore) {
  3. LockGuard.installLock(mPackages, LockGuard.INDEX_PACKAGES);
  4. Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "create package manager");
  5. EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
  6. SystemClock.uptimeMillis());
  7. /// M: Add for Mtprof tool.
  8. mMTPROFDisable = false;
  9. addBootEvent("Android:PackageManagerService_Start");
  10. //mSdkVersion标示SDK版本,让apk知道自己运行在哪个版本
  11. if (mSdkVersion <= 0) {
  12. Slog.w(TAG, "**** ro.build.version.sdk not set!");
  13. }
  14. mContext = context;
  15. //标示了CTA表示在产品要在国内买,需要过CTA,类似CTS
  16. /// M: CTA requirement - permission control
  17. mPermissionReviewRequired = CtaUtils.isCtaSupported() ? true :
  18. context.getResources().getBoolean(R.bool.config_permissionReviewRequired);
  19. ///@}
  20. //是否运行在工厂模式下
  21. mFactoryTest = factoryTest;
  22. //判断是否只扫描系统目录,这个在后面多次用到
  23. mOnlyCore = onlyCore;
  24. //获取手机分辨率信息
  25. mMetrics = new DisplayMetrics();
  26. //mPackages是一个map集合存放packagesetting对象,是全局变量.PMS中的每一个应用程序的安装信息都是使用一个packagesetting对象进行描述
  27. //Settings类是用来管理应用程序的安装信息的
  28. mSettings = new Settings(mPackages);

由于这个Settings类比较重要,接下来分析Settings的构造方法,Settings的构造函数主要用于创建一些目录和文件,并配置相应的权限. frameworks/base/services/core/java/com/android/server/pm/Settings.java

  1. Settings(Object lock) {
  2. //Environment.getDataDirectory()获取的是/data目录
  3. this(Environment.getDataDirectory(), lock);
  4. }
  5. Settings(File dataDir, Object lock) {
  6. mLock = lock;
  7. mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);
  8. //目录指向为/data/system
  9. mSystemDir = new File(dataDir, "system");
  10. //创建前面指向好的目录
  11. mSystemDir.mkdirs();
  12. FileUtils.setPermissions(mSystemDir.toString(),
  13. FileUtils.S_IRWXU|FileUtils.S_IRWXG
  14. |FileUtils.S_IROTH|FileUtils.S_IXOTH,
  15. -1, -1);
  16. //packages.xml和packages-backup.xml为一组,用于描述系统所安装的Package信息,其中packages-backup.xml是packages.xml的备份
  17. //PKMS写把数据写到backup文件中,信息全部写成功后在改名为非backup文件,以防止在写文件的过程中出错,导致信息丢失
  18. mSettingsFilename = new File(mSystemDir, "packages.xml");
  19. mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
  20. //packages.list保存中所有安装apk的信息
  21. mPackageListFilename = new File(mSystemDir, "packages.list");
  22. FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);
  23. final File kernelDir = new File("/config/sdcardfs");
  24. mKernelMappingFilename = kernelDir.exists() ? kernelDir : null;
  25. //packages-stopped.xml用于描述系统中强行停止运行的package信息,backup也是备份文件
  26. // Deprecated: Needed for migration
  27. mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
  28. mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
  29. }

回到frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java,继续分析PackageManagerService的构造方法:

  1. //设置系统的shareuserid,这个是在manifest.xml中设置,拥有相同shareuserid的app将会共享权限.
  2. //shareuserid属性设置为"android.uid.system"那么说明是系统app
  3. mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
  4. ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
  5. mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
  6. ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
  7. mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
  8. ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
  9. mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
  10. ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
  11. mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
  12. ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
  13. mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
  14. ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);

用到了Settings类的方法:addSharedUserLPw,作用是添加共享用户:

  1. //name和uid一一对应,例如:"android.uid.system":Process.SYSTEM_UID(1000)
  2. // "android.uid.phone" :RADIO_UID(Process.PHONE_UID, 1001)
  3. // 在PMS中,每一个共享Linux用户都是使用一个SharedUserSetting对象来描述的。这些对象保存在mSharedUsers中
  4. SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
  5. //依据key(这里其实就是包名)值,从mSharedUsers对象中获取对应的SharedUserSetting对象.
  6. SharedUserSetting s = mSharedUsers.get(name);
  7. if (s != null) {//如果在mSharedUsers里面存在给的包名对应的SharedUserSetting对象
  8. if (s.userId == uid) {//并且userId=uid,说明PMS已经为该应用程序分配过了uid
  9. return s;
  10. }
  11. PackageManagerService.reportSettingsProblem(Log.ERROR,
  12. "Adding duplicate shared user, keeping first: " + name);
  13. return null;
  14. }
  15. // 如果mSharedUsers中不存在与该包名对应的SharedUserSetting对象,则为该应用程序分配一个参数uid所描述的Linux用户ID
  16. s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
  17. s.userId = uid;
  18. // 在系统中保存值为uid的Linux用户ID,成功返回true
  19. if (addUserIdLPw(uid, s, name)) {
  20. //将新new的SharedUserSetting对象添加到mSharedUsers中
  21. mSharedUsers.put(name, s);
  22. return s;
  23. }
  24. return null;
  25. }

在系统保存值为uid的Linux用户ID,使用到了addUserIdLPw方法:

  1. private boolean addUserIdLPw(int uid, Object obj, Object name) {
  2. if (uid > Process.LAST_APPLICATION_UID) {//大于19999说明是一个非法的uid,超出了uid的上线
  3. return false;
  4. }
  5. if (uid >= Process.FIRST_APPLICATION_UID) {//大于等于10000普通apk的uid,保存在mUserIds中
  6. //计算数组长度
  7. int N = mUserIds.size();
  8. //计算索引值
  9. final int index = uid - Process.FIRST_APPLICATION_UID;
  10. while (index >= N) {//索引值大于数组长度,在N到index之间的位置都填上null
  11. mUserIds.add(null);
  12. N++;
  13. }
  14. // 如果数组的目标索引值位置有不为null的值,说明已经添加过
  15. if (mUserIds.get(index) != null) {
  16. PackageManagerService.reportSettingsProblem(Log.ERROR,
  17. "Adding duplicate user id: " + uid
  18. + " name=" + name);
  19. return false;
  20. }
  21. //没有添加过,则在索引位置填上obj
  22. mUserIds.set(index, obj);
  23. } else {//小于10000,系统apk使用的uid,保存在mOtherUserIds中
  24. if (mOtherUserIds.get(uid) != null) {
  25. PackageManagerService.reportSettingsProblem(Log.ERROR,
  26. "Adding duplicate shared id: " + uid
  27. + " name=" + name);
  28. return false;
  29. }
  30. mOtherUserIds.put(uid, obj);
  31. }
  32. return true;
  33. }

PMS在创建了Settings之后会,调用一系列的addSharedUserLPw方法,形成下图的结构:
1 如图所示,PKMS将根据参数构建出SharedUserSettings对象,可以通过两个维度来引用创建出的对象,即名称和uid。 在Settings中mSharedUsers是一个map对象,利用名称作为索引管理SharedUserSettings对象。 Settings中的mOtherUserIds和mUserIds,均是利用userId作为索引管理SharedUserSettings对象。不同的是mOtherUserIds是SparseArray, 以系统uid作为键值;mUserIds是ArrayList,普通APK的uid为ArrayList的下标。
接着分析一下这个SharedUserSettings:

  1. //重点看这一个方法
  2. void addPackage(PackageSetting packageSetting) {
  3. if (packages.add(packageSetting)) {//SharedUserSettings保存着一个packages集合用来存储packageSetting<-存储一个应用的安装信息
  4. setFlags(this.pkgFlags | packageSetting.pkgFlags);
  5. setPrivateFlags(this.pkgPrivateFlags | packageSetting.pkgPrivateFlags);
  6. }
  7. }

回到frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java,继续分析PackageManagerService的构造方法:

  1. // 应用安装器,构造函数传入的InstallerService,与底层Installd通信,installer由SystemServer构造
  2. mInstaller = installer;
  3. // 实例化优化器,PackageDexOptimizer用于辅助进行dex优化
  4. mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
  5. "*dexopt*");
  6. //在pm/dex/包下,用于记录dex文件使用情况的记录在/data/system/package-dex-usage.list中
  7. mDexManager = new DexManager(this, mPackageDexOptimizer, installer, mInstallLock);
  8. //定义一些回调函数
  9. mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
  10. //定义权限更改监听器
  11. mOnPermissionChangeListeners = new OnPermissionChangeListeners(
  12. FgThread.get().getLooper());
  13. //获取默认显示屏信息
  14. getDefaultDisplayMetrics(context, mMetrics);
  15. Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "get system config");
  16. //获得SystemConfig对象,通过该对象获取系统配置
  17. SystemConfig systemConfig = SystemConfig.getInstance();

由于SystemConfig是一个比较重要的类,下面的代码多次使用,进行详细分析. frameworks/base/core/java/com/android/server/SystemConfig.java

  1. static SystemConfig sInstance;
  2. //SystemConfig是单例模式
  3. public static SystemConfig getInstance() {
  4. synchronized (SystemConfig.class) {
  5. if (sInstance == null) {
  6. sInstance = new SystemConfig();
  7. }
  8. return sInstance;
  9. }
  10. }
  11. SystemConfig() {//从不少目录读取权限,可能有些目录不存在,但是/system一定存在
  12. //Environment.getRootDirectory()获取到的是/system目录,从/system目录读取权限
  13. // Read configuration from system
  14. readPermissions(Environment.buildPath(
  15. Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);
  16. // Read configuration from the old permissions dir
  17. readPermissions(Environment.buildPath(
  18. Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
  19. //从/vendor目录下读取权限
  20. // Allow Vendor to customize system configs around libs, features, permissions and apps
  21. int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS |
  22. ALLOW_APP_CONFIGS;
  23. readPermissions(Environment.buildPath(
  24. Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
  25. readPermissions(Environment.buildPath(
  26. Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
  27. //从/odm目录读取权限
  28. // Allow ODM to customize system configs around libs, features and apps
  29. int odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS;
  30. readPermissions(Environment.buildPath(
  31. Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
  32. readPermissions(Environment.buildPath(
  33. Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);
  34. //从/oem目录读取权限
  35. // Only allow OEM to customize features
  36. readPermissions(Environment.buildPath(
  37. Environment.getOemDirectory(), "etc", "sysconfig"), ALLOW_FEATURES);
  38. readPermissions(Environment.buildPath(
  39. Environment.getOemDirectory(), "etc", "permissions"), ALLOW_FEATURES);
  40. }
  41. //接着看readPermissions方法的实现
  42. void readPermissions(File libraryDir, int permissionFlag) {
  43. //检测是否存在,是否可读
  44. // Read permissions from given directory.
  45. if (!libraryDir.exists() || !libraryDir.isDirectory()) {
  46. if (permissionFlag == ALLOW_ALL) {
  47. Slog.w(TAG, "No directory " + libraryDir + ", skipping");
  48. }
  49. return;
  50. }
  51. if (!libraryDir.canRead()) {
  52. Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
  53. return;
  54. }
  55. // 遍历目标文件夹下所有的.xml文件
  56. // Iterate over the files in the directory and scan .xml files
  57. File platformFile = null;
  58. for (File f : libraryDir.listFiles()) {
  59. // 最后解析platform.xml文件
  60. // We'll read platform.xml last
  61. if (f.getPath().endsWith("etc/permissions/platform.xml")) {
  62. platformFile = f;
  63. continue;
  64. }
  65. if (!f.getPath().endsWith(".xml")) {
  66. Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
  67. continue;
  68. }
  69. if (!f.canRead()) {
  70. Slog.w(TAG, "Permissions library file " + f + " cannot be read");
  71. continue;
  72. }
  73. //将可读取的xml进行读取
  74. readPermissionsFromXml(f, permissionFlag);//下面详解readPermissionsFromXml方法
  75. }
  76. // 最后解析platform.xml文件,该文件的优先级最高
  77. // Read platform permissions last so it will take precedence
  78. if (platformFile != null) {
  79. readPermissionsFromXml(platformFile, permissionFlag);
  80. }
  81. }

readPermissions就是从指定目录下,读取xml中的配置的权限信息.将xml文件转换成对应的数据结构.eg:/system/etc/permissions/platform.xml. 看一下platform.xml里面的主要标签:

  • permission和group字段用于建立Linux层GID和Android层permission字段之间的映射关系;
  • assign-permission用于向指定的uid赋予相应的权限;
  • library字段用于可链接的指定系统库;
  • allow-in-power-save-except-idle用于指定进程在省电模式下(非Idle)仍可上网;
  • backup-transport-whitelisted-service用于指定服务具有传输备份数据的权利;

上面这些标签是用readPermissionsFromXml方法解析的.在readPermissions方法中两次调用到了readPermissionsFromXml,该方法是SystemConfig的核心方法.源码:

  1. private void readPermissionsFromXml(File permFile, int permissionFlag) {
  2. FileReader permReader = null;
  3. try {
  4. //利用file构造fileReader
  5. permReader = new FileReader(permFile);
  6. } catch (FileNotFoundException e) {
  7. Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
  8. return;
  9. }
  10. //读取系统属性"ro.config.low_ram",如果该属性为true,不会加载指定notLowRam的feature属性
  11. final boolean lowRam = ActivityManager.isLowRamDeviceStatic();
  12. try {
  13. //创建xml解析器
  14. XmlPullParser parser = Xml.newPullParser();
  15. //给解析器输入FileReader读取的内容
  16. parser.setInput(permReader);
  17. //寻找解析的起点
  18. int type;
  19. while ((type=parser.next()) != parser.START_TAG
  20. && type != parser.END_DOCUMENT) {
  21. ;
  22. }
  23. if (type != parser.START_TAG) {
  24. throw new XmlPullParserException("No start tag found");
  25. }
  26. if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) {
  27. throw new XmlPullParserException("Unexpected start tag in " + permFile
  28. + ": found " + parser.getName() + ", expected 'permissions' or 'config'");
  29. }
  30. //根据SystemConfig构造方法中设置的flag,决定当前目录下,从xml文件中解析内容的范围
  31. boolean allowAll = permissionFlag == ALLOW_ALL;
  32. boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0;
  33. boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0;
  34. boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0;
  35. boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0;
  36. boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS) != 0;
  37. while (true) {
  38. XmlUtils.nextElement(parser);
  39. //解析完成退出
  40. if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
  41. break;
  42. }
  43. String name = parser.getName();
  44. //解析group标签
  45. if ("group".equals(name) && allowAll) {
  46. //以字符串的形式获取属性值,如果获取的属性值是一个int,那么就要进行转换
  47. String gidStr = parser.getAttributeValue(null, "gid");
  48. if (gidStr != null) {
  49. //将Gid字符串转化成整形,保存到mGlobalGids中
  50. int gid = android.os.Process.getGidForName(gidStr);
  51. mGlobalGids = appendInt(mGlobalGids, gid);
  52. } else {
  53. Slog.w(TAG, "<group> without gid in " + permFile + " at "
  54. + parser.getPositionDescription());
  55. }
  56. XmlUtils.skipCurrentTag(parser);
  57. continue;
  58. } else if ("permission".equals(name) && allowPermissions) {//解析permission标签
  59. String perm = parser.getAttributeValue(null, "name");
  60. if (perm == null) {
  61. Slog.w(TAG, "<permission> without name in " + permFile + " at "
  62. + parser.getPositionDescription());
  63. XmlUtils.skipCurrentTag(parser);
  64. continue;
  65. }
  66. perm = perm.intern();
  67. //调用readPermission解析permission标签,注意不是readPermissions方法!!!
  68. readPermission(parser, perm);
  69. } else if ("assign-permission".equals(name) && allowPermissions) {//解析assign-permission标签,记录uid分配的权限,最终记录到mSystemPermissions
  70. //获取权限名称
  71. String perm = parser.getAttributeValue(null, "name");
  72. if (perm == null) {
  73. Slog.w(TAG, "<assign-permission> without name in " + permFile + " at "
  74. + parser.getPositionDescription());
  75. XmlUtils.skipCurrentTag(parser);
  76. continue;
  77. }
  78. //获取该权限的uid的值
  79. String uidStr = parser.getAttributeValue(null, "uid");
  80. if (uidStr == null) {
  81. Slog.w(TAG, "<assign-permission> without uid in " + permFile + " at "
  82. + parser.getPositionDescription());
  83. XmlUtils.skipCurrentTag(parser);
  84. continue;
  85. }
  86. //将uid从string转换成int
  87. int uid = Process.getUidForName(uidStr);
  88. if (uid < 0) {
  89. Slog.w(TAG, "<assign-permission> with unknown uid \""
  90. + uidStr + " in " + permFile + " at "
  91. + parser.getPositionDescription());
  92. XmlUtils.skipCurrentTag(parser);
  93. continue;
  94. }
  95. //使用了字符串池,intern()是String类的方法
  96. perm = perm.intern();
  97. //从系统获取该uid已经拥有的权限
  98. ArraySet<String> perms = mSystemPermissions.get(uid);
  99. //如果该uid之前没有添加过权限,创建一个,并将添加到mSystemPermissions中
  100. if (perms == null) {
  101. perms = new ArraySet<String>();
  102. mSystemPermissions.put(uid, perms);//保存着以uid为key的权限映射表,是一个稀疏数组
  103. }
  104. //将uid新增的权限,加入到它的ArraySet
  105. perms.add(perm);
  106. XmlUtils.skipCurrentTag(parser);
  107. } else if ("library".equals(name) && allowLibs) {//解析library标签,最终记录到mSharedLibraries
  108. String lname = parser.getAttributeValue(null, "name");
  109. String lfile = parser.getAttributeValue(null, "file");
  110. if (lname == null) {
  111. Slog.w(TAG, "<library> without name in " + permFile + " at "
  112. + parser.getPositionDescription());
  113. } else if (lfile == null) {
  114. Slog.w(TAG, "<library> without file in " + permFile + " at "
  115. + parser.getPositionDescription());
  116. } else {
  117. //Log.i(TAG, "Got library " + lname + " in " + lfile);
  118. //将解析好的library标签的内容添加到mSharedLibraries,是一个map集合
  119. mSharedLibraries.put(lname, lfile);
  120. }
  121. XmlUtils.skipCurrentTag(parser);
  122. continue;
  123. } else if ("feature".equals(name) && allowFeatures) {//解析feature标签
  124. String fname = parser.getAttributeValue(null, "name");
  125. int fversion = XmlUtils.readIntAttribute(parser, "version", 0);
  126. boolean allowed;
  127. if (!lowRam) {//如果是低内存就不解析
  128. allowed = true;
  129. } else {
  130. String notLowRam = parser.getAttributeValue(null, "notLowRam");
  131. allowed = !"true".equals(notLowRam);
  132. }
  133. if (fname == null) {
  134. Slog.w(TAG, "<feature> without name in " + permFile + " at "
  135. + parser.getPositionDescription());
  136. } else if (allowed) {
  137. //将feature构造成featureInfo,加入到mAvailableFeatures对象中,该方法在SystemConfig中
  138. addFeature(fname, fversion);
  139. }
  140. XmlUtils.skipCurrentTag(parser);
  141. continue;
  142. } else if ("unavailable-feature".equals(name) && allowFeatures) {//mUnavailableFeatures保存不支持的feature
  143. String fname = parser.getAttributeValue(null, "name");
  144. if (fname == null) {
  145. Slog.w(TAG, "<unavailable-feature> without name in " + permFile + " at "
  146. + parser.getPositionDescription());
  147. } else {
  148. mUnavailableFeatures.add(fname);
  149. }
  150. XmlUtils.skipCurrentTag(parser);
  151. continue;
  152. } else if ("allow-in-power-save-except-idle".equals(name) && allowAll) {//保存省电模式下,可以使用网络的应用
  153. String pkgname = parser.getAttributeValue(null, "package");
  154. if (pkgname == null) {
  155. Slog.w(TAG, "<allow-in-power-save-except-idle> without package in "
  156. + permFile + " at " + parser.getPositionDescription());
  157. } else {
  158. //保存在mAllowInPowerSaveExceptIdle中
  159. mAllowInPowerSaveExceptIdle.add(pkgname);
  160. }
  161. XmlUtils.skipCurrentTag(parser);
  162. continue;
  163. } else if ("allow-in-power-save".equals(name) && allowAll) {
  164. //mAllowInPowerSave与mAllowInPowerSaveExceptIdle类似,权限更高
  165. //这与Android M新特性Doze and App Standby模式有关
  166. //DeviceIdleController用于判断设备是否进入Idle状态,进入Idle状态时,mAllowInPowerSaveExceptIdle中的应用要被禁掉
  167. //但mAllowInPowerSave中的应用仍可运行
  168. String pkgname = parser.getAttributeValue(null, "package");
  169. if (pkgname == null) {
  170. Slog.w(TAG, "<allow-in-power-save> without package in " + permFile + " at "
  171. + parser.getPositionDescription());
  172. } else {
  173. mAllowInPowerSave.add(pkgname);
  174. }
  175. XmlUtils.skipCurrentTag(parser);
  176. continue;
  177. } else if ("allow-in-data-usage-save".equals(name) && allowAll) {
  178. //mAllowInDataUsageSave保存此标签对应的packageName
  179. //貌似android 7新增了一个节省数据流量的能力,有此标签的应用在节省数据流量时,仍可访问网络
  180. String pkgname = parser.getAttributeValue(null, "package");
  181. if (pkgname == null) {
  182. Slog.w(TAG, "<allow-in-data-usage-save> without package in " + permFile
  183. + " at " + parser.getPositionDescription());
  184. } else {
  185. mAllowInDataUsageSave.add(pkgname);
  186. }
  187. XmlUtils.skipCurrentTag(parser);
  188. continue;
  189. } else if ("allow-unthrottled-location".equals(name) && allowAll) {
  190. String pkgname = parser.getAttributeValue(null, "package");
  191. if (pkgname == null) {
  192. Slog.w(TAG, "<allow-unthrottled-location> without package in "
  193. + permFile + " at " + parser.getPositionDescription());
  194. } else {
  195. mAllowUnthrottledLocation.add(pkgname);
  196. }
  197. XmlUtils.skipCurrentTag(parser);
  198. continue;
  199. } else if ("allow-implicit-broadcast".equals(name) && allowAll) {
  200. String action = parser.getAttributeValue(null, "action");
  201. if (action == null) {
  202. Slog.w(TAG, "<allow-implicit-broadcast> without action in " + permFile
  203. + " at " + parser.getPositionDescription());
  204. } else {
  205. mAllowImplicitBroadcasts.add(action);
  206. }
  207. XmlUtils.skipCurrentTag(parser);
  208. continue;
  209. } else if ("app-link".equals(name) && allowAppConfigs) {
  210. String pkgname = parser.getAttributeValue(null, "package");
  211. if (pkgname == null) {
  212. Slog.w(TAG, "<app-link> without package in " + permFile + " at "
  213. + parser.getPositionDescription());
  214. } else {
  215. mLinkedApps.add(pkgname);
  216. }
  217. XmlUtils.skipCurrentTag(parser);
  218. } else if ("system-user-whitelisted-app".equals(name) && allowAppConfigs) {
  219. //mSystemUserWhitelistedApps保存此标签对应的packageName
  220. //指定以system user权限运行的app
  221. String pkgname = parser.getAttributeValue(null, "package");
  222. if (pkgname == null) {
  223. Slog.w(TAG, "<system-user-whitelisted-app> without package in " + permFile
  224. + " at " + parser.getPositionDescription());
  225. } else {
  226. mSystemUserWhitelistedApps.add(pkgname);
  227. }
  228. XmlUtils.skipCurrentTag(parser);
  229. } else if ("system-user-blacklisted-app".equals(name) && allowAppConfigs) {
  230. //mSystemUserBlacklistedApp保存此标签对应的packageName
  231. //指定在system user权限下,不应该运行的app
  232. String pkgname = parser.getAttributeValue(null, "package");
  233. if (pkgname == null) {
  234. Slog.w(TAG, "<system-user-blacklisted-app without package in " + permFile
  235. + " at " + parser.getPositionDescription());
  236. } else {
  237. mSystemUserBlacklistedApps.add(pkgname);
  238. }
  239. XmlUtils.skipCurrentTag(parser);
  240. } else if ("default-enabled-vr-app".equals(name) && allowAppConfigs) {
  241. //mDefaultVrComponents保存此标签对应的packageName
  242. //指定默认运行在VR模式下的components
  243. String pkgname = parser.getAttributeValue(null, "package");
  244. String clsname = parser.getAttributeValue(null, "class");
  245. if (pkgname == null) {
  246. Slog.w(TAG, "<default-enabled-vr-app without package in " + permFile
  247. + " at " + parser.getPositionDescription());
  248. } else if (clsname == null) {
  249. Slog.w(TAG, "<default-enabled-vr-app without class in " + permFile
  250. + " at " + parser.getPositionDescription());
  251. } else {
  252. mDefaultVrComponents.add(new ComponentName(pkgname, clsname));
  253. }
  254. XmlUtils.skipCurrentTag(parser);
  255. } else if ("backup-transport-whitelisted-service".equals(name) && allowFeatures) {
  256. //mBackupTransportWhitelist保存此标签对应的packageName
  257. //保存能够传输备份数据的服务
  258. String serviceName = parser.getAttributeValue(null, "service");
  259. if (serviceName == null) {
  260. Slog.w(TAG, "<backup-transport-whitelisted-service> without service in "
  261. + permFile + " at " + parser.getPositionDescription());
  262. } else {
  263. ComponentName cn = ComponentName.unflattenFromString(serviceName);
  264. if (cn == null) {
  265. Slog.w(TAG,
  266. "<backup-transport-whitelisted-service> with invalid service name "
  267. + serviceName + " in "+ permFile
  268. + " at " + parser.getPositionDescription());
  269. } else {
  270. mBackupTransportWhitelist.add(cn);
  271. }
  272. }
  273. XmlUtils.skipCurrentTag(parser);
  274. } else if ("disabled-until-used-preinstalled-carrier-associated-app".equals(name)
  275. && allowAppConfigs) {
  276. String pkgname = parser.getAttributeValue(null, "package");
  277. String carrierPkgname = parser.getAttributeValue(null, "carrierAppPackage");
  278. if (pkgname == null || carrierPkgname == null) {
  279. Slog.w(TAG, "<disabled-until-used-preinstalled-carrier-associated-app"
  280. + " without package or carrierAppPackage in " + permFile + " at "
  281. + parser.getPositionDescription());
  282. } else {
  283. List<String> associatedPkgs =
  284. mDisabledUntilUsedPreinstalledCarrierAssociatedApps.get(
  285. carrierPkgname);
  286. if (associatedPkgs == null) {
  287. associatedPkgs = new ArrayList<>();
  288. mDisabledUntilUsedPreinstalledCarrierAssociatedApps.put(
  289. carrierPkgname, associatedPkgs);
  290. }
  291. associatedPkgs.add(pkgname);
  292. }
  293. XmlUtils.skipCurrentTag(parser);
  294. } else if ("privapp-permissions".equals(name) && allowPrivappPermissions) {
  295. readPrivAppPermissions(parser);
  296. } else {
  297. XmlUtils.skipCurrentTag(parser);
  298. continue;
  299. }
  300. }
  301. } catch (XmlPullParserException e) {
  302. Slog.w(TAG, "Got exception parsing permissions.", e);
  303. } catch (IOException e) {
  304. Slog.w(TAG, "Got exception parsing permissions.", e);
  305. } finally {
  306. IoUtils.closeQuietly(permReader);
  307. }
  308. //对相关的feature加密
  309. // Some devices can be field-converted to FBE, so offer to splice in
  310. // those features if not already defined by the static config
  311. if (StorageManager.isFileEncryptedNativeOnly()) {
  312. addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION, 0);
  313. addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, 0);
  314. }
  315. //移除mUnavailableFeatures中记录的不支持的feature
  316. for (String featureName : mUnavailableFeatures) {
  317. removeFeature(featureName);
  318. }
  319. }

回到frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java,继续分析PackageManagerService的构造方法:

  1. mGlobalGids = systemConfig.getGlobalGids();
  2. mSystemPermissions = systemConfig.getSystemPermissions();
  3. mAvailableFeatures = systemConfig.getAvailableFeatures();
  4. Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

分别调用SystemConfig类的getGlobalGids(),getSystemPermissions(),getAvailableFeatures()方法:

  1. public int[] getGlobalGids() {
  2. return mGlobalGids;
  3. }
  4. public SparseArray<ArraySet<String>> getSystemPermissions() {
  5. return mSystemPermissions;
  6. }
  7. public ArrayMap<String, FeatureInfo> getAvailableFeatures() {
  8. return mAvailableFeatures;
  9. }

可以看出这三个方法只是将readPermissionsFromXml方法中解析xml文件得到的数据结构获取出来.PMS调用SystemConfig的作用就是解析xml. 回到frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java,继续分析PackageManagerService的构造方法:

  1. //mHandlerThread将负责Apk的安装和卸载
  2. mHandlerThread = new ServiceThread(TAG,
  3. Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
  4. mHandlerThread.start();
  5. //PackageHandler、ProcessLoggingHandler共用ServiceThread
  6. // 以mHandlerThread线程的looper创建的Handler实例,该Handler运行在mHandlerThread线程
  7. // 该消息循环用于处理apk的安装请求
  8. mHandler = new PackageHandler(mHandlerThread.getLooper());
  9. mProcessLoggingHandler = new ProcessLoggingHandler();
  10. //Watchdog监控ServiceThread是否长时间阻塞
  11. Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
  12. mDefaultPermissionPolicy = new DefaultPermissionGrantPolicy(this);
  13. mInstantAppRegistry = new InstantAppRegistry(this);
  14. //在/data目录下创建一系列的目录
  15. File dataDir = Environment.getDataDirectory();//获取的是/data目录
  16. mAppInstallDir = new File(dataDir, "app");//data/app保存用户自己的app
  17. mAppLib32InstallDir = new File(dataDir, "app-lib");
  18. mAsecInternalPath = new File(dataDir, "app-asec").getPath();
  19. mDrmAppPrivateInstallDir = new File(dataDir, "app-private");// /data/app-parivate目录,保存的是受DRM保护的私有app
  20. //实例化多用户管理服务,用于管理多用户
  21. sUserManager = new UserManagerService(context, this,
  22. new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
  23. //取出SystemConfig中的mPermissions
  24. //向包管理器中传播权限配置。
  25. // Propagate permission configuration in to package manager.
  26. ArrayMap<String, SystemConfig.PermissionEntry> permConfig
  27. = systemConfig.getPermissions();
  28. //从SystemConfig中的mPermissions获取信息,存储到mSettings.mPermissions中
  29. for (int i=0; i<permConfig.size(); i++) {
  30. SystemConfig.PermissionEntry perm = permConfig.valueAt(i);
  31. // 根据权限名获取基本权限信息
  32. BasePermission bp = mSettings.mPermissions.get(perm.name);
  33. if (bp == null) {
  34. bp = new BasePermission(perm.name, "android", BasePermission.TYPE_BUILTIN);
  35. mSettings.mPermissions.put(perm.name, bp);
  36. }
  37. if (perm.gids != null) {
  38. bp.setGids(perm.gids, perm.perUser);
  39. }
  40. }
  41. //取出systemConfig对象中的链接库信息,保存到PKMS中
  42. ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();
  43. final int builtInLibCount = libConfig.size();
  44. for (int i = 0; i < builtInLibCount; i++) {
  45. String name = libConfig.keyAt(i);
  46. String path = libConfig.valueAt(i);
  47. addSharedLibraryLPw(path, null, name, SharedLibraryInfo.VERSION_UNDEFINED,
  48. SharedLibraryInfo.TYPE_BUILTIN, PLATFORM_PACKAGE_NAME, 0);
  49. }
  50. // 解析SELinux的策略文件
  51. mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
  52. Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "read user settings");
  53. //mFirstBoot用于判断机器是否时第一次开机,这里的readLPw恢复上一次的应用程序安装信息,扫描package.xml文件,如果没有该文件判断为第一次开机
  54. mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
  55. Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

Android系统每次启动时,都会重新安装一遍系统中的应用程序,但是有些应用程序信息每次安装都是需要保持一致的, 如应用程序的Linux用户ID等。否则应用程序每次在系统重启后表现可能不一致。因此PMS每次在安装完成应用程序之后, 都需要将它们的信息保存下来,以便下次安装时可以恢复回来。恢复上一次的应用程序安装信息是通过Settings类的readLPw方法实现的。 重点分析Settings类的方法readLPw:
进入frameworks/base/services/core/java/com/android/server/pm/Settings.java

  1. boolean readLPw(@NonNull List<UserInfo> users) {
  2. FileInputStream str = null;
  3. // 先检查/data/system/packages-backup.xml文件是否存在,
  4. // 如果存在就将它的内容作为上一次的应用程序安装信息
  5. if (mBackupSettingsFilename.exists()) {
  6. try {
  7. str = new FileInputStream(mBackupSettingsFilename);
  8. mReadMessages.append("Reading from backup settings file\n");
  9. PackageManagerService.reportSettingsProblem(Log.INFO,
  10. "Need to read from backup settings file");
  11. if (mSettingsFilename.exists()) {
  12. // If both the backup and settings file exist, we
  13. // ignore the settings since it might have been
  14. // corrupted.
  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. mPendingPackages.clear();
  24. mPastSignatures.clear();
  25. mKeySetRefs.clear();
  26. mInstallerPackages.clear();
  27. try {
  28. if (str == null) {
  29. if (!mSettingsFilename.exists()) {
  30. mReadMessages.append("No settings file found\n");
  31. PackageManagerService.reportSettingsProblem(Log.INFO,
  32. "No settings file; creating initial state");
  33. // It's enough to just touch version details to create them
  34. // with default values
  35. // 如果原文件不存在,根据默认值创建版本信息。
  36. findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL).forceCurrent();
  37. findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL).forceCurrent();
  38. return false;
  39. }
  40. str = new FileInputStream(mSettingsFilename);
  41. }
  42. XmlPullParser parser = Xml.newPullParser();
  43. parser.setInput(str, StandardCharsets.UTF_8.name());
  44. int type;
  45. while ((type = parser.next()) != XmlPullParser.START_TAG
  46. && type != XmlPullParser.END_DOCUMENT) {
  47. ;
  48. }
  49. if (type != XmlPullParser.START_TAG) {
  50. mReadMessages.append("No start tag found in settings file\n");
  51. PackageManagerService.reportSettingsProblem(Log.WARN,
  52. "No start tag found in package manager settings");
  53. Slog.wtf(PackageManagerService.TAG,
  54. "No start tag found in package manager settings");
  55. /// M: Create version info when packages.xml is corrupt
  56. findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL);
  57. findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL);
  58. return false;
  59. }
  60. int outerDepth = parser.getDepth();
  61. //开始解析
  62. while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
  63. && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
  64. if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
  65. continue;
  66. }
  67. String tagName = parser.getName();
  68. if (tagName.equals("package")) {
  69. // 解析标签为package的元素,一个应用一个package标签.
  70. // 获取上一次安装这个应用程序时所分配给它的Linux用户ID
  71. readPackageLPw(parser);//1
  72. } else if (tagName.equals("permissions")) {
  73. // 解析系统定义了哪些权限,由哪个包定义
  74. readPermissionsLPw(mPermissions, parser);
  75. } else if (tagName.equals("permission-trees")) {
  76. readPermissionsLPw(mPermissionTrees, parser);
  77. } else if (tagName.equals("shared-user")) {
  78. // shared-user标签是以sharedUserId的名字为name属性,然后为它分配一个userId赋值给userId属性。
  79. // 其他应用用到该sharedUserId的,userId都是shared-user标签中的userId属性值
  80. // 解析上一次应用程序安装信息中的共享Linux用户信息
  81. // 就是前面在Settings类中addSharedUserLPw方法写信息,最终保存在mSharedUsers中
  82. readSharedUserLPw(parser);//解析上一次应用程序安装信息中的共享linux用户信息
  83. } else if (tagName.equals("preferred-packages")) {
  84. ......
  85. str.close();
  86. } catch (XmlPullParserException e) {
  87. ......

分析readPackageLPw方法:

  1. private void readPackageLPw(XmlPullParser parser) throws XmlPullParserException, IOException {
  2. //定义变量
  3. ......
  4. try {
  5. //获取应用程序包名,Linux用户Id,sharedUserId等信息,将前面定义的变量初始化
  6. name = parser.getAttributeValue(null, ATTR_NAME);
  7. realName = parser.getAttributeValue(null, "realName");
  8. idStr = parser.getAttributeValue(null, "userId");
  9. uidError = parser.getAttributeValue(null, "uidError");
  10. sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
  11. codePathStr = parser.getAttributeValue(null, "codePath");
  12. resourcePathStr = parser.getAttributeValue(null, "resourcePath");
  13. //初始化变量,并且做相应的合法性判断,eg:==NULL?
  14. .....
  15. } else if (userId > 0) {
  16. //packageSetting用于保存一个应用程序的的安装信息,使用addPackageLPw将以上app的安装信息封装成packageSetting对象保存在mPackages中
  17. packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),//addPackageLPw源码分析
  18. new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString,
  19. secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags,
  20. pkgPrivateFlags, flagsEx, parentPackageName, null /*childPackageNames*/,
  21. null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/);
  22. //对返回的packageSetting对象进行合法性判断
  23. if (PackageManagerService.DEBUG_SETTINGS)
  24. Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId="
  25. + userId + " pkg=" + packageSetting);
  26. if (packageSetting == null) {
  27. PackageManagerService.reportSettingsProblem(Log.ERROR, "Failure adding uid "
  28. + userId + " while parsing settings at "
  29. + parser.getPositionDescription());
  30. } else {
  31. packageSetting.setTimeStamp(timeStamp);
  32. packageSetting.firstInstallTime = firstInstallTime;
  33. packageSetting.lastUpdateTime = lastUpdateTime;
  34. }

进入addPackageLPw方法:

  1. // 在系统中保存值为userId的Linux用户ID
  2. // 在PMS中,每一个应用程序的安装信息都是使用一个PackageSetting对象来描述的。这些对象保存在mPackages中。
  3. PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
  4. String legacyNativeLibraryPathString, String primaryCpuAbiString,
  5. String secondaryCpuAbiString, String cpuAbiOverrideString, int uid, int vc, int
  6. pkgFlags, int pkgPrivateFlags, int flagsEx, String parentPackageName,
  7. List<String> childPackageNames, String[] usesStaticLibraries,
  8. int[] usesStaticLibraryNames) {
  9. PackageSetting p = mPackages.get(name);
  10. if (p != null) {//判断一下mPackages是否已经有了
  11. if (p.appId == uid) {
  12. return p;//在mPackages应经存在,直接将mPackages里的PackageSetting对象直接返回
  13. }
  14. PackageManagerService.reportSettingsProblem(Log.ERROR,
  15. "Adding duplicate package, keeping first: " + name);
  16. return null;
  17. }
  18. //mPackages里面没有,依据传入的信息,new一个PackageSetting对象,并且添加到mPackages中,并将该对象返回
  19. /// M: [FlagExt] Add flagsEx
  20. p = new PackageSetting(name, realName, codePath, resourcePath,
  21. legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
  22. cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags, flagsEx, parentPackageName,
  23. childPackageNames, 0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames);
  24. p.appId = uid;
  25. if (addUserIdLPw(uid, p, name)) {//addUserIdLPw是在系统中保存值为uid的Linux用户Id,该方法在前面分析过
  26. mPackages.put(name, p);
  27. return p;
  28. }
  29. return null;
  30. }

回到readPackageLPw方法,继续分析:

  1. } else if (sharedIdStr != null) {
  2. // 如果sharedIdStr不为null,说明安装该应用时PMS给它分配了一个共享的uid。此时不能马上保存该uid,
  3. // 因为这个uid不属于它自己所有,而是所有shareuserId了该uid的app共享.所以等解析完shared-user节点之后,再为它保存上一次所使用的Linux用户ID
  4. if (sharedUserId > 0) {
  5. /// M: [FlagExt] Add flagsEx
  6. packageSetting = new PackageSetting(name.intern(), realName, new File(
  7. codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr,
  8. primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
  9. versionCode, pkgFlags, pkgPrivateFlags, flagsEx, parentPackageName,
  10. null /*childPackageNames*/, sharedUserId,
  11. null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/);
  12. packageSetting.setTimeStamp(timeStamp);
  13. packageSetting.firstInstallTime = firstInstallTime;
  14. packageSetting.lastUpdateTime = lastUpdateTime;
  15. //将是shareuserId的应用信息,先暂时保存在mPendingPackages中
  16. mPendingPackages.add(packageSetting);
  17. if (PackageManagerService.DEBUG_SETTINGS)
  18. Log.i(PackageManagerService.TAG, "Reading package " + name
  19. + ": sharedUserId=" + sharedUserId + " pkg=" + packageSetting);
  20. } else {
  21. PackageManagerService.reportSettingsProblem(Log.WARN,
  22. "Error in package manager settings: package " + name
  23. + " has bad sharedId " + sharedIdStr + " at "
  24. + parser.getPositionDescription());
  25. }
  26. } else {
  27. PackageManagerService.reportSettingsProblem(Log.WARN,
  28. "Error in package manager settings: package " + name + " has bad userId "
  29. + idStr + " at " + parser.getPositionDescription());
  30. }
  31. } catch (NumberFormatException e) {
  32. PackageManagerService.reportSettingsProblem(Log.WARN,
  33. "Error in package manager settings: package " + name + " has bad userId "
  34. + idStr + " at " + parser.getPositionDescription());
  35. }
  36. if (packageSetting != null) {
  37. packageSetting.uidError = "true".equals(uidError);
  38. packageSetting.installerPackageName = installerPackageName;
  39. packageSetting.isOrphaned = "true".equals(isOrphaned);
  40. packageSetting.volumeUuid = volumeUuid;
  41. packageSetting.categoryHint = categoryHint;
  42. packageSetting.legacyNativeLibraryPathString = legacyNativeLibraryPathStr;
  43. packageSetting.primaryCpuAbiString = primaryCpuAbiString;
  44. packageSetting.secondaryCpuAbiString = secondaryCpuAbiString;
  45. packageSetting.updateAvailable = "true".equals(updateAvailable);
  46. // Handle legacy string here for single-user mode
  47. final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
  48. if (enabledStr != null) {
  49. try {
  50. packageSetting.setEnabled(Integer.parseInt(enabledStr), 0 /* userId */, null);
  51. } catch (NumberFormatException e) {
  52. if (enabledStr.equalsIgnoreCase("true")) {
  53. packageSetting.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 0, null);
  54. } else if (enabledStr.equalsIgnoreCase("false")) {
  55. packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0, null);
  56. } else if (enabledStr.equalsIgnoreCase("default")) {
  57. packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0, null);
  58. } else {
  59. PackageManagerService.reportSettingsProblem(Log.WARN,
  60. "Error in package manager settings: package " + name
  61. + " has bad enabled value: " + idStr + " at "
  62. + parser.getPositionDescription());
  63. }
  64. }
  65. } else {
  66. packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0, null);
  67. }
  68. if (installerPackageName != null) {
  69. mInstallerPackages.add(installerPackageName);
  70. }
  71. final String installStatusStr = parser.getAttributeValue(null, "installStatus");
  72. if (installStatusStr != null) {
  73. if (installStatusStr.equalsIgnoreCase("false")) {
  74. packageSetting.installStatus = PackageSettingBase.PKG_INSTALL_INCOMPLETE;
  75. } else {
  76. packageSetting.installStatus = PackageSettingBase.PKG_INSTALL_COMPLETE;
  77. }
  78. }
  79. int outerDepth = parser.getDepth();
  80. int type;
  81. while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
  82. && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
  83. if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
  84. continue;
  85. }
  86. String tagName = parser.getName();
  87. // Legacy
  88. if (tagName.equals(TAG_DISABLED_COMPONENTS)) {
  89. readDisabledComponentsLPw(packageSetting, parser, 0);
  90. } else if (tagName.equals(TAG_ENABLED_COMPONENTS)) {
  91. readEnabledComponentsLPw(packageSetting, parser, 0);
  92. } else if (tagName.equals("sigs")) {
  93. packageSetting.signatures.readXml(parser, mPastSignatures);
  94. } else if (tagName.equals(TAG_PERMISSIONS)) {
  95. readInstallPermissionsLPr(parser,
  96. packageSetting.getPermissionsState());
  97. packageSetting.installPermissionsFixed = true;
  98. } else if (tagName.equals("proper-signing-keyset")) {
  99. long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
  100. Integer refCt = mKeySetRefs.get(id);
  101. if (refCt != null) {
  102. mKeySetRefs.put(id, refCt + 1);
  103. } else {
  104. mKeySetRefs.put(id, 1);
  105. }
  106. packageSetting.keySetData.setProperSigningKeySet(id);
  107. } else if (tagName.equals("signing-keyset")) {
  108. // from v1 of keysetmanagerservice - no longer used
  109. } else if (tagName.equals("upgrade-keyset")) {
  110. long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
  111. packageSetting.keySetData.addUpgradeKeySetById(id);
  112. } else if (tagName.equals("defined-keyset")) {
  113. long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
  114. String alias = parser.getAttributeValue(null, "alias");
  115. Integer refCt = mKeySetRefs.get(id);
  116. if (refCt != null) {
  117. mKeySetRefs.put(id, refCt + 1);
  118. } else {
  119. mKeySetRefs.put(id, 1);
  120. }
  121. packageSetting.keySetData.addDefinedKeySet(id, alias);
  122. } else if (tagName.equals(TAG_DOMAIN_VERIFICATION)) {
  123. readDomainVerificationLPw(parser, packageSetting);
  124. } else if (tagName.equals(TAG_CHILD_PACKAGE)) {
  125. String childPackageName = parser.getAttributeValue(null, ATTR_NAME);
  126. if (packageSetting.childPackageNames == null) {
  127. packageSetting.childPackageNames = new ArrayList<>();
  128. }
  129. packageSetting.childPackageNames.add(childPackageName);
  130. } else {
  131. PackageManagerService.reportSettingsProblem(Log.WARN,
  132. "Unknown element under <package>: " + parser.getName());
  133. XmlUtils.skipCurrentTag(parser);
  134. }
  135. }
  136. } else {
  137. XmlUtils.skipCurrentTag(parser);
  138. }
  139. }

回到readLPw继续分析:

  1. // If the build is setup to drop runtime permissions
  2. // on update drop the files before loading them.
  3. if (PackageManagerService.CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE) {
  4. final VersionInfo internal = getInternalVersion();
  5. if (!Build.FINGERPRINT.equals(internal.fingerprint)) {
  6. for (UserInfo user : users) {
  7. mRuntimePermissionsPersistence.deleteUserRuntimePermissionsFile(user.id);
  8. }
  9. }
  10. }
  11. //在readPackageLPw方法中将shareuserId的app安装信息都暂时的保存在mPendingPackages,现在进行处理
  12. final int N = mPendingPackages.size();
  13. for (int i = 0; i < N; i++) {
  14. final PackageSetting p = mPendingPackages.get(i);
  15. final int sharedUserId = p.getSharedUserId();
  16. // 根据uid获取对应的对象,如果在mUserIds或mOtherUserIds中存在一个与userId对应的Object对象,
  17. // 且该对象是SharedUserSetting的类型,则说明pp所描述的应用程序上一次所使用的Linux用户ID是有效的
  18. final Object idObj = getUserIdLPr(sharedUserId);
  19. //每一个共享Linux用户Id都是使用SharedUserSetting对象来描述,并且保存在mSharedUsers中
  20. if (idObj instanceof SharedUserSetting) {
  21. final SharedUserSetting sharedUser = (SharedUserSetting) idObj;
  22. p.sharedUser = sharedUser;
  23. p.appId = sharedUser.userId;
  24. //addPackageSettingLPw将PackageSetting对象p添加到mPackages,把sharedUser赋给p.sharedUser保存
  25. addPackageSettingLPw(p, sharedUser);
  26. } else if (idObj != null) {
  27. String msg = "Bad package setting: package " + p.name + " has shared uid "
  28. + sharedUserId + " that is not a shared uid\n";
  29. mReadMessages.append(msg);
  30. PackageManagerService.reportSettingsProblem(Log.ERROR, msg);
  31. } else {
  32. String msg = "Bad package setting: package " + p.name + " has shared uid "
  33. + sharedUserId + " that is not defined\n";
  34. mReadMessages.append(msg);
  35. PackageManagerService.reportSettingsProblem(Log.ERROR, msg);
  36. }
  37. }
  38. mPendingPackages.clear();
  39. if (mBackupStoppedPackagesFilename.exists()
  40. || mStoppedPackagesFilename.exists()) {
  41. // Read old file
  42. readStoppedLPw();
  43. mBackupStoppedPackagesFilename.delete();
  44. mStoppedPackagesFilename.delete();
  45. // Migrate to new file format
  46. writePackageRestrictionsLPr(UserHandle.USER_SYSTEM);
  47. } else {
  48. for (UserInfo user : users) {
  49. readPackageRestrictionsLPr(user.id);
  50. }
  51. }
  52. for (UserInfo user : users) {
  53. mRuntimePermissionsPersistence.readStateForUserSyncLPr(user.id);
  54. }
  55. /*
  56. * Make sure all the updated system packages have their shared users
  57. * associated with them.
  58. */
  59. final Iterator<PackageSetting> disabledIt = mDisabledSysPackages.values().iterator();
  60. while (disabledIt.hasNext()) {
  61. final PackageSetting disabledPs = disabledIt.next();
  62. final Object id = getUserIdLPr(disabledPs.appId);
  63. if (id != null && id instanceof SharedUserSetting) {
  64. disabledPs.sharedUser = (SharedUserSetting) id;
  65. }
  66. }
  67. mReadMessages.append("Read completed successfully: " + mPackages.size() + " packages, "
  68. + mSharedUsers.size() + " shared uids\n");
  69. writeKernelMappingLPr();
  70. return true;
  71. }

经过上面的readLPw函数,将之前手机里面的安装信息都加载进来,接下来进入下一个阶段:开始扫描手机指定放apk的目录.
回到frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java,继续分析PackageManagerService的构造方法:

  1. // 记录开始扫描的时间
  2. long startTime = SystemClock.uptimeMillis();
  3. .....
  4. //获取目录:/system/framework/
  5. File frameworkDir = new File(Environment.getRootDirectory(), "framework");
  6. .....
  7. //初始化扫描参数
  8. // Set flag to monitor and not change apk file paths when
  9. // scanning install directories.
  10. int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
  11. if (mIsUpgrade || mFirstBoot) {
  12. scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
  13. }
  14. // Collect vendor overlay packages. (Do this before scanning any apps.)
  15. // For security and version matching reason, only consider
  16. // overlay packages if they reside in the right directory.
  17. scanDirTracedLI(new File(VENDOR_OVERLAY_DIR), mDefParseFlags//scanDirTracedLI详解其实调用还是scanDirLI,下来分析scanDirLI
  18. | PackageParser.PARSE_IS_SYSTEM
  19. | PackageParser.PARSE_IS_SYSTEM_DIR
  20. | PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
  21. //依次扫描放apk的目录
  22. ......

scanDirLI是用来扫描一个指定目录下的apk文件.接下来分析scanDirLI方法:

  1. private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
  2. final File[] files = dir.listFiles();
  3. if (ArrayUtils.isEmpty(files)) {
  4. Log.d(TAG, "No files in app dir " + dir);
  5. return;
  6. }
  7. /// M: Add for Mtprof tool.
  8. addBootEvent("Android:PMS_scan_data:" + dir.getPath().toString());
  9. //为了加快扫描速度,使用多线程进行扫描,启动多线程扫描来自QCOM平台
  10. int iMultitaskNum = SystemProperties.getInt("persist.pm.multitask", 6);
  11. final MultiTaskDealer dealer = (iMultitaskNum > 1) ? MultiTaskDealer.startDealer(
  12. MultiTaskDealer.PACKAGEMANAGER_SCANER, iMultitaskNum) : null;
  13. ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
  14. mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
  15. mParallelPackageParserCallback);
  16. // Submit files for parsing in parallel
  17. int fileCount = 0;
  18. for (File file : files) {
  19. // Added by zhongyang_lib for apk lib
  20. if(file == null){
  21. continue;
  22. }
  23. try{
  24. if(!file.getAbsolutePath().equals(file.getCanonicalPath()) && file.getName().endsWith(".so")) {
  25. //indicate file is a link file
  26. Log.i(TAG,"file: "+file.getAbsolutePath()+" is a link file: "+ file.getCanonicalPath());
  27. file = new File(file.getCanonicalPath());
  28. }
  29. }catch(IOException e){
  30. Log.e(TAG,"scan link file:"+file.getAbsolutePath()+" caused an exception",e);
  31. continue;
  32. }
  33. parallelPackageParser.submit(file, parseFlags);
  34. fileCount++;
  35. }
  36. // Process results one by one
  37. for (; fileCount > 0; fileCount--) {
  38. ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
  39. Throwable throwable = parseResult.throwable;
  40. int errorCode = PackageManager.INSTALL_SUCCEEDED;
  41. //merge from qcom platform by tian.pan@tcl.com for task5306252 start
  42. Runnable scanTask = new Runnable() {
  43. public void run() {
  44. int parserErrorCode = errorCode;
  45. if (throwable == null) {
  46. // Static shared libraries have synthetic package names
  47. if (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) {
  48. renameStaticSharedLibraryPackage(parseResult.pkg);
  49. }
  50. try {
  51. if (errorCode == PackageManager.INSTALL_SUCCEEDED) {
  52. //使用scanPackageLI解析apk文件
  53. scanPackageLI(parseResult.pkg, parseResult.scanFile, parseFlags, scanFlags,
  54. currentTime, null);
  55. }
  56. } catch (PackageManagerException e) {
  57. parserErrorCode = e.error;
  58. Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
  59. }
  60. } else if (throwable instanceof PackageParser.PackageParserException) {
  61. PackageParser.PackageParserException e = (PackageParser.PackageParserException)throwable;
  62. parserErrorCode = e.error;
  63. Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " + e.getMessage());
  64. } else {
  65. throw new IllegalStateException("Unexpected exception occurred while parsing "
  66. + parseResult.scanFile, throwable);
  67. }
  68. // Delete invalid userdata apps
  69. if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
  70. parserErrorCode == PackageManager.INSTALL_FAILED_INVALID_APK) {
  71. logCriticalInfo(Log.WARN, "Deleting invalid package at " + parseResult.scanFile);
  72. //删除无效的apk文件
  73. removeCodePathLI(parseResult.scanFile);
  74. }
  75. }
  76. };
  77. if (dealer != null) {
  78. dealer.addTask(scanTask);
  79. } else {
  80. scanTask.run();
  81. }
  82. }
  83. if (dealer != null) {
  84. dealer.waitAll();
  85. }
  86. //merge from qcom platform by tian.pan@tcl.com for task5306252 end
  87. parallelPackageParser.close();
  88. }

scanDirLI方法只是去扫描了指定的文件夹

  • /system/framework
  • /system/app
  • /vendor/app
  • /data/app
  • /data/app-private 然后并没有处理扫描到的apk文件,而是交给scanPackageLI去处理, 上面代码中使用到了一个核心的方法scanPackageLI,这个方法就是实现对apk文件进行解析和安装的文件.该方法有三个,参数对应的是6参数的,来看源码:

    1. /**
    2. * Scans a package and returns the newly parsed package.//返回的是刚刚解析的这个包.
    3. * @throws PackageManagerException on a parse error.
    4. */
    5. private PackageParser.Package scanPackageLI(PackageParser.Package pkg, File scanFile,
    6. final int policyFlags, int scanFlags, long currentTime, @Nullable UserHandle user)
    7. throws PackageManagerException {
    8. // If the package has children and this is the first dive in the function
    9. // we scan the package with the SCAN_CHECK_ONLY flag set to see whether all
    10. // packages (parent and children) would be successfully scanned before the
    11. // actual scan since scanning mutates internal state and we want to atomically
    12. // install the package and its children.
    13. // 从注释看,一个package里面可能存在多个需要解析的文件
    14. if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
    15. if (pkg.childPackages != null && pkg.childPackages.size() > 0) {
    16. scanFlags |= SCAN_CHECK_ONLY;
    17. }
    18. } else {
    19. scanFlags &= ~SCAN_CHECK_ONLY;
    20. }
    21. // Scan the parent
    22. //真正的解析工作是scanPackageInternalLI,返回的解析的包也是scanPackageInternalLI返回的
    23. PackageParser.Package scannedPkg = scanPackageInternalLI(pkg, scanFile, policyFlags,
    24. scanFlags, currentTime, user);
    25. // Scan the children
    26. final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
    27. for (int i = 0; i < childCount; i++) {
    28. PackageParser.Package childPackage = pkg.childPackages.get(i);
    29. scanPackageInternalLI(childPackage, scanFile, policyFlags, scanFlags,//是scanPackageInternalLI干活
    30. currentTime, user);
    31. }
    32. if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
    33. return scanPackageLI(pkg, scanFile, policyFlags, scanFlags, currentTime, user);
    34. }
    35. return scannedPkg;
    36. }

    OTA升级使用到scanPackageInternalLI,该方法作用就是比对新旧包,判断是否更换.分析scanPackageInternalLI的源码:

    1. /**
    2. * Scans a package and returns the newly parsed package.
    3. * @throws PackageManagerException on a parse error.
    4. */
    5. //scanPackageInternalLI方法是把扫描到的androidmainifest数据和之前在手机内扫描得到的数据做对比,然后进行对应操作。
    6. private PackageParser.Package scanPackageInternalLI(PackageParser.Package pkg, File scanFile,
    7. int policyFlags, int scanFlags, long currentTime, @Nullable UserHandle user)
    8. throws PackageManagerException {
    9. PackageSetting ps = null;
    10. PackageSetting updatedPkg;
    11. // reader
    12. synchronized (mPackages) {
    13. // 看是否是已知的包,并对其进行操作
    14. // Look to see if we already know about this package.
    15. String oldName = mSettings.getRenamedPackageLPr(pkg.packageName);
    16. if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
    17. // This package has been renamed to its original name. Let's
    18. // use that.
    19. ps = mSettings.getPackageLPr(oldName);
    20. }
    21. // If there was no original package, see one for the real package name.
    22. if (ps == null) {
    23. ps = mSettings.getPackageLPr(pkg.packageName);
    24. }
    25. // Check to see if this package could be hiding/updating a system
    26. // package. Must look for it either under the original or real
    27. // package name depending on our state.
    28. updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);
    29. if (DEBUG_INSTALL && updatedPkg != null) Slog.d(TAG, "updatedPkg = " + updatedPkg);
    30. // 非第一次启动 如果是一个已卸载的系统应用或者vendor app(厂商应用)则直接返回null
    31. /// M: Skip an uninstalled system or vendor app
    32. if (!isFirstBoot() && (isVendorApp(pkg) || isSystemApp(pkg))
    33. && ((updatedPkg != null)
    34. || (ps.getInstallStatus() == PackageSettingBase.PKG_INSTALL_INCOMPLETE))) {
    35. Slog.d(TAG, "Skip scanning " + scanFile.toString() + ", package " + updatedPkg +
    36. ", install status: " + ps.getInstallStatus());
    37. return null;
    38. } else if (ps == null && updatedPkg != null) {
    39. Slog.d(TAG, "Skip scanning uninstalled package: " + pkg.packageName);
    40. return null;
    41. }
    42. // If this is a package we don't know about on the system partition, we
    43. // may need to remove disabled child packages on the system partition
    44. // or may need to not add child packages if the parent apk is updated
    45. // on the data partition and no longer defines this child package.
    46. if ((policyFlags & PackageParser.PARSE_IS_SYSTEM) != 0) {
    47. // If this is a parent package for an updated system app and this system
    48. // app got an OTA update which no longer defines some of the child packages
    49. // we have to prune them from the disabled system packages.
    50. PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName);
    51. if (disabledPs != null) {//和OTA升级相关
    52. final int scannedChildCount = (pkg.childPackages != null)
    53. ? pkg.childPackages.size() : 0;
    54. final int disabledChildCount = disabledPs.childPackageNames != null
    55. ? disabledPs.childPackageNames.size() : 0;
    56. for (int i = 0; i < disabledChildCount; i++) {
    57. String disabledChildPackageName = disabledPs.childPackageNames.get(i);
    58. boolean disabledPackageAvailable = false;
    59. for (int j = 0; j < scannedChildCount; j++) {
    60. PackageParser.Package childPkg = pkg.childPackages.get(j);
    61. if (childPkg.packageName.equals(disabledChildPackageName)) {
    62. disabledPackageAvailable = true;
    63. break;
    64. }
    65. }
    66. if (!disabledPackageAvailable) {
    67. mSettings.removeDisabledSystemPackageLPw(disabledChildPackageName);
    68. }
    69. }
    70. }
    71. }
    72. }
    73. // 首先检查是否包含更新的系统包,包括vendor目录下
    74. final boolean isUpdatedPkg = updatedPkg != null;
    75. /// M: [Operator] Package in vendor folder should also be checked.
    76. final boolean isUpdatedSystemPkg = isUpdatedPkg
    77. && ((policyFlags & PackageParser.PARSE_IS_SYSTEM) != 0
    78. || (policyFlags & PackageParser.PARSE_IS_OPERATOR) != 0);
    79. boolean isUpdatedPkgBetter = false;
    80. // First check if this is a system package that may involve an update
    81. if (isUpdatedSystemPkg) {//是一个更新的系统包
    82. // If new package is not located in "/system/priv-app" (e.g. due to an OTA),
    83. // it needs to drop FLAG_PRIVILEGED.
    84. //如果新的包不在priv-app下,应该下调Flag
    85. if (locationIsPrivileged(scanFile)) {
    86. updatedPkg.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
    87. } else {
    88. updatedPkg.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
    89. }
    90. //如果扫描到的包路径发生了变化,根据已经存储的内容来判断该如何操作此app,记录下flag用于后面的使用
    91. if (ps != null && !ps.codePath.equals(scanFile)) {
    92. // The path has changed from what was last scanned... check the
    93. // version of the new path against what we have stored to determine
    94. // what to do.
    95. if (DEBUG_INSTALL) Slog.d(TAG, "Path changing from " + ps.codePath);
    96. ///M: [Operator] Allow vendor package downgrade.
    97. ///Always install the updated one on data partition.
    98. if (pkg.mVersionCode < ps.versionCode
    99. || ((policyFlags & PackageParser.PARSE_IS_OPERATOR) != 0)
    100. /// M: Removable system app support
    101. || isRemovableSysApp(pkg.packageName)) {
    102. // The system package has been updated and the code path does not match
    103. // Ignore entry. Skip it.
    104. if (DEBUG_INSTALL) Slog.i(TAG, "Package " + ps.name + " at " + scanFile
    105. + " ignored: updated version " + ps.versionCode
    106. + " better than this " + pkg.mVersionCode);
    107. if (!updatedPkg.codePath.equals(scanFile)) {
    108. Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg "
    109. + ps.name + " changing from " + updatedPkg.codePathString
    110. + " to " + scanFile);
    111. updatedPkg.codePath = scanFile;
    112. updatedPkg.codePathString = scanFile.toString();
    113. updatedPkg.resourcePath = scanFile;
    114. updatedPkg.resourcePathString = scanFile.toString();
    115. }
    116. updatedPkg.pkg = pkg;
    117. updatedPkg.versionCode = pkg.mVersionCode;
    118. // Update the disabled system child packages to point to the package too.
    119. final int childCount = updatedPkg.childPackageNames != null
    120. ? updatedPkg.childPackageNames.size() : 0;
    121. for (int i = 0; i < childCount; i++) {
    122. String childPackageName = updatedPkg.childPackageNames.get(i);
    123. PackageSetting updatedChildPkg = mSettings.getDisabledSystemPkgLPr(
    124. childPackageName);
    125. if (updatedChildPkg != null) {
    126. updatedChildPkg.pkg = pkg;
    127. updatedChildPkg.versionCode = pkg.mVersionCode;
    128. }
    129. }
    130. } else {// /system下的package比我们在/data目下pacakage好
    131. // The current app on the system partition is better than
    132. // what we have updated to on the data partition; switch
    133. // back to the system partition version.
    134. // At this point, its safely assumed that package installation for
    135. // apps in system partition will go through. If not there won't be a working
    136. // version of the app
    137. // writer
    138. synchronized (mPackages) {
    139. // Just remove the loaded entries from package lists.
    140. mPackages.remove(ps.name);
    141. }
    142. logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile
    143. + " reverting from " + ps.codePathString
    144. + ": new version " + pkg.mVersionCode
    145. + " better than installed " + ps.versionCode);
    146. InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
    147. ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
    148. synchronized (mInstallLock) {
    149. args.cleanUpResourcesLI();
    150. }
    151. synchronized (mPackages) {
    152. mSettings.enableSystemPackageLPw(ps.name);
    153. }
    154. isUpdatedPkgBetter = true;
    155. }
    156. }
    157. }
    158. String resourcePath = null;
    159. String baseResourcePath = null;
    160. if ((policyFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !isUpdatedPkgBetter) {
    161. if (ps != null && ps.resourcePathString != null) {
    162. resourcePath = ps.resourcePathString;
    163. baseResourcePath = ps.resourcePathString;
    164. } else {
    165. // Should not happen at all. Just log an error.
    166. Slog.e(TAG, "Resource path not set for package " + pkg.packageName);
    167. }
    168. } else {
    169. resourcePath = pkg.codePath;
    170. baseResourcePath = pkg.baseCodePath;
    171. }
    172. //精确的设置app的路径
    173. // Set application objects path explicitly.
    174. pkg.setApplicationVolumeUuid(pkg.volumeUuid);
    175. pkg.setApplicationInfoCodePath(pkg.codePath);
    176. pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
    177. pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
    178. pkg.setApplicationInfoResourcePath(resourcePath);
    179. pkg.setApplicationInfoBaseResourcePath(baseResourcePath);
    180. pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
    181. // throw an exception if we have an update to a system application, but, it's not more
    182. // recent than the package we've already scanned
    183. if (isUpdatedSystemPkg && !isUpdatedPkgBetter) {
    184. // Set CPU Abis to application info.
    185. if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) {
    186. final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, updatedPkg);
    187. derivePackageAbi(pkg, scanFile, cpuAbiOverride, false, mAppLib32InstallDir);
    188. } else {
    189. pkg.applicationInfo.primaryCpuAbi = updatedPkg.primaryCpuAbiString;
    190. pkg.applicationInfo.secondaryCpuAbi = updatedPkg.secondaryCpuAbiString;
    191. }
    192. throw new PackageManagerException(Log.WARN, "Package " + ps.name + " at "
    193. + scanFile + " ignored: updated version " + ps.versionCode
    194. + " better than this " + pkg.mVersionCode);
    195. }
    196. if (isUpdatedPkg) {
    197. // An updated system app will not have the PARSE_IS_SYSTEM flag set
    198. // initially
    199. /** M: [Operator] Only system app have system flag @{ */
    200. if (isSystemApp(updatedPkg)) {
    201. policyFlags |= PackageParser.PARSE_IS_SYSTEM;
    202. }
    203. /// M: [Operator] Add operator flags for updated vendor package
    204. /// We should consider an operator app with flag changed after OTA
    205. if ((isVendorApp(updatedPkg) || locationIsOperator(updatedPkg.codePath))
    206. && locationIsOperator(ps.codePath)) {
    207. policyFlags |= PackageParser.PARSE_IS_OPERATOR;
    208. }
    209. /** @} */
    210. // An updated privileged app will not have the PARSE_IS_PRIVILEGED
    211. // flag set initially
    212. if ((updatedPkg.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
    213. policyFlags |= PackageParser.PARSE_IS_PRIVILEGED;
    214. }
    215. }
    216. //扫描验证证书
    217. // Verify certificates against what was last scanned
    218. collectCertificatesLI(ps, pkg, scanFile, policyFlags);
    219. //一个新的system app,但有一个已安装的同名非系统app
    220. // 这里的代码是处理这样的情景:当系统更新后,可能更新包会多出一些system app出来,那么如果此时用户恰好安装了一个同包名的app.
    221. // 两者的签名还不一致,那么就删除扫描到的系统应用的信息。
    222. // 当两者签名一致时,如果扫描到的app版本更高,那么就删除安装的应用;如果扫描的app版本低,那么隐藏扫描到的系统应用。
    223. /*
    224. * A new system app appeared, but we already had a non-system one of the
    225. * same name installed earlier.
    226. */
    227. boolean shouldHideSystemApp = false;
    228. if (!isUpdatedPkg && ps != null
    229. && (policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) {
    230. /*
    231. * Check to make sure the signatures match first. If they don't,
    232. * wipe the installed application and its data.
    233. */
    234. //如果签名不同,擦除已安装应用和数据
    235. if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures)
    236. != PackageManager.SIGNATURE_MATCH) {
    237. logCriticalInfo(Log.WARN, "Package " + ps.name + " appeared on system, but"
    238. + " signatures don't match existing userdata copy; removing");
    239. try (PackageFreezer freezer = freezePackage(pkg.packageName,
    240. "scanPackageInternalLI")) {
    241. deletePackageLIF(pkg.packageName, null, true, null, 0, null, false, null);
    242. }
    243. ps = null;
    244. } else {//签名相同,继续判断
    245. /*
    246. * If the newly-added system app is an older version than the
    247. * already installed version, hide it. It will be scanned later
    248. * and re-added like an update.
    249. */
    250. if (pkg.mVersionCode <= ps.versionCode) {//新添加app更旧,则隐藏此app,后续会重新添加
    251. shouldHideSystemApp = true;
    252. logCriticalInfo(Log.INFO, "Package " + ps.name + " appeared at " + scanFile
    253. + " but new version " + pkg.mVersionCode + " better than installed "
    254. + ps.versionCode + "; hiding system");
    255. } else {//如果比已安装的app新,则保留app数据直接安装更新此system app
    256. /*
    257. * The newly found system app is a newer version that the
    258. * one previously installed. Simply remove the
    259. * already-installed application and replace it with our own
    260. * while keeping the application data.
    261. */
    262. logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile
    263. + " reverting from " + ps.codePathString + ": new version "
    264. + pkg.mVersionCode + " better than installed " + ps.versionCode);
    265. InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
    266. ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
    267. synchronized (mInstallLock) {
    268. args.cleanUpResourcesLI();
    269. }
    270. }
    271. }
    272. }
    273. // The apk is forward locked (not public) if its code and resources
    274. // are kept in different files. (except for app in either system or
    275. // vendor path).
    276. // TODO grab this value from PackageSettings
    277. //如果app中制定的资源在别的路径,则从PackageSettings中抓取
    278. if ((policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
    279. if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
    280. policyFlags |= PackageParser.PARSE_FORWARD_LOCK;
    281. }
    282. }
    283. final int userId = ((user == null) ? 0 : user.getIdentifier());
    284. if (ps != null && ps.getInstantApp(userId)) {
    285. scanFlags |= SCAN_AS_INSTANT_APP;
    286. }
    287. // Note that we invoke the following method only if we are about to unpack an application
    288. PackageParser.Package scannedPkg = scanPackageLI(pkg, policyFlags, scanFlags//这里是5参数的scanPackageLI方法,第一个参数是PackageParser.Package类型
    289. | SCAN_UPDATE_SIGNATURE, currentTime, user);
    290. /*
    291. * If the system app should be overridden by a previously installed
    292. * data, hide the system app now and let the /data/app scan pick it up
    293. * again.
    294. */
    295. if (shouldHideSystemApp) {//该package被隐藏
    296. synchronized (mPackages) {
    297. mSettings.disableSystemPackageLPw(pkg.packageName, true);
    298. }
    299. }
    300. return scannedPkg;
    301. }

    从上面的分析看出scanPackageInternalLI方法主要还是进行比对新旧package信息(主要是OTA升级带来的升级包),进行相关的参数判断,设置不同的参数,最后交给5参数的scanPackageLI方法, 从5参数的scanPackageLI方法开始才开始,所有合法性验证都通过,开始解析,安装这个package.:

    1. private PackageParser.Package scanPackageLI(PackageParser.Package pkg, final int policyFlags,
    2. int scanFlags, long currentTime, @Nullable UserHandle user)
    3. throws PackageManagerException {
    4. boolean success = false;
    5. try {//scanPackageDirtyLI是安装的核心函数,不论是开机扫描还是adb安装都会调用到该函数进行APK安装
    6. final PackageParser.Package res = scanPackageDirtyLI(pkg, policyFlags, scanFlags,
    7. currentTime, user);
    8. success = true;
    9. return res;
    10. } finally {
    11. if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
    12. // DELETE_DATA_ON_FAILURES is only used by frozen paths
    13. destroyAppDataLIF(pkg, UserHandle.USER_ALL,
    14. StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
    15. destroyAppProfilesLIF(pkg, UserHandle.USER_ALL);
    16. }
    17. }
    18. }

    快来看看这个scanPackageDirtyLI函数:
    ``` // 获得前面所解析的应用程序的组件配置信息,以及为这个应用程序分配Linux用户ID private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, final int policyFlags, final int scanFlags, long currentTime, @Nullable UserHandle user)

    1. throws PackageManagerException {

    if (DEBUG_PACKAGE_SCANNING) { if ((policyFlags & PackageParser.PARSE_CHATTY) != 0)

    1. Log.d(TAG, "Scanning package " + pkg.packageName);

    }

    applyPolicy(pkg, policyFlags);

    // Begin added by Xutao.Wu for Task5185134 on 2017/09/22 if (PackageManager.TCT_RETAILDEMO_PACKAGE_NAME.equals(pkg.packageName)){ if (DEBUG_INSTALL) Slog.w(TAG,”scanPackageDirtyLI, set retaildemo as SYSTEM PRIVILEGED”); pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; } // End added by Xutao.Wu for Task5185134 on 2017/09/22 // 方法的作用是判断给定的pkg是不是有效的 assertPackageIsValid(pkg, policyFlags, scanFlags);

    // Initialize package source and resource directories final File scanFile = new File(pkg.codePath); final File destCodeFile = new File(pkg.applicationInfo.getCodePath()); final File destResourceFile = new File(pkg.applicationInfo.getResourcePath());

    SharedUserSetting suid = null; PackageSetting pkgSetting = null;

    // Getting the package setting may have a side-effect, so if we // are only checking if scan would succeed, stash a copy of the // old setting to restore at the end. PackageSetting nonMutatedPs = null;

    // We keep references to the derived CPU Abis from settings in oder to reuse // them in the case where we’re not upgrading or booting for the first time. String primaryCpuAbiFromSettings = null; String secondaryCpuAbiFromSettings = null;

    // writer // 为参数pkg所描述的应用程序分配Linux用户ID synchronized (mPackages) { if (pkg.mSharedUserId != null) {// 如果该应用有sharedUserId属性,则从mSettings中获取要为它分配的共享uid

    1. // SIDE EFFECTS; may potentially allocate a new shared user
    2. suid = mSettings.getSharedUserLPw(
    3. pkg.mSharedUserId, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/);
    4. if (DEBUG_PACKAGE_SCANNING) {
    5. if ((policyFlags & PackageParser.PARSE_CHATTY) != 0)
    6. Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid=" + suid.userId
    7. + "): packages=" + suid.packages);
    8. }

    }

    // Check if we are renaming from an original package name. PackageSetting origPackage = null; String realName = null; if (pkg.mOriginalPackages != null) {

    1. // This package may need to be renamed to a previously
    2. // installed name. Let's check on that...
    3. final String renamed = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
    4. if (pkg.mOriginalPackages.contains(renamed)) {
    5. // This package had originally been installed as the
    6. // original name, and we have already taken care of
    7. // transitioning to the new one. Just update the new
    8. // one to continue using the old name.
    9. realName = pkg.mRealPackage;
    10. if (!pkg.packageName.equals(renamed)) {
    11. // Callers into this function may have already taken
    12. // care of renaming the package; only do it here if
    13. // it is not already done.
    14. pkg.setPackageName(renamed);
    15. }
    16. } else {
    17. for (int i=pkg.mOriginalPackages.size()-1; i>=0; i--) {
    18. if ((origPackage = mSettings.getPackageLPr(
    19. pkg.mOriginalPackages.get(i))) != null) {
    20. // We do have the package already installed under its
    21. // original name... should we use it?
    22. if (!verifyPackageUpdateLPr(origPackage, pkg)) {
    23. // New package is not compatible with original.
    24. origPackage = null;
    25. continue;
    26. } else if (origPackage.sharedUser != null) {
    27. // Make sure uid is compatible between packages.
    28. if (!origPackage.sharedUser.name.equals(pkg.mSharedUserId)) {
    29. Slog.w(TAG, "Unable to migrate data from " + origPackage.name
    30. + " to " + pkg.packageName + ": old uid "
    31. + origPackage.sharedUser.name
    32. + " differs from " + pkg.mSharedUserId);
    33. origPackage = null;
    34. continue;
    35. }
    36. // TODO: Add case when shared user id is added [b/28144775]
    37. } else {
    38. if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package "
    39. + pkg.packageName + " to old name " + origPackage.name);
    40. }
    41. break;
    42. }
    43. }
    44. }

    }

    if (mTransferedPackages.contains(pkg.packageName)) {

    1. Slog.w(TAG, "Package " + pkg.packageName
    2. + " was transferred to another, but its .apk remains");

    }

    // See comments in nonMutatedPs declaration if ((scanFlags & SCAN_CHECK_ONLY) != 0) {

    1. PackageSetting foundPs = mSettings.getPackageLPr(pkg.packageName);
    2. if (foundPs != null) {
    3. nonMutatedPs = new PackageSetting(foundPs);
    4. }

    }

    if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) == 0) {

    1. PackageSetting foundPs = mSettings.getPackageLPr(pkg.packageName);
    2. if (foundPs != null) {
    3. primaryCpuAbiFromSettings = foundPs.primaryCpuAbiString;
    4. secondaryCpuAbiFromSettings = foundPs.secondaryCpuAbiString;
    5. }

    }

    // 创建PackageSetting并设置 pkgSetting = mSettings.getPackageLPr(pkg.packageName); if (pkgSetting != null && pkgSetting.sharedUser != suid) {

    1. PackageManagerService.reportSettingsProblem(Log.WARN,
    2. "Package " + pkg.packageName + " shared user changed from "
    3. + (pkgSetting.sharedUser != null
    4. ? pkgSetting.sharedUser.name : "<nothing>")
    5. + " to "
    6. + (suid != null ? suid.name : "<nothing>")
    7. + "; replacing with new");
    8. pkgSetting = null;

    } final PackageSetting oldPkgSetting =

    1. pkgSetting == null ? null : new PackageSetting(pkgSetting);

    final PackageSetting disabledPkgSetting =

    1. mSettings.getDisabledSystemPkgLPr(pkg.packageName);

    String[] usesStaticLibraries = null; if (pkg.usesStaticLibraries != null) {

    1. usesStaticLibraries = new String[pkg.usesStaticLibraries.size()];
    2. pkg.usesStaticLibraries.toArray(usesStaticLibraries);

    }

    if (pkgSetting == null) {

    1. final String parentPackageName = (pkg.parentPackage != null)
    2. ? pkg.parentPackage.packageName : null;
    3. final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
    4. // REMOVE SharedUserSetting from method; update in a separate call
    5. pkgSetting = Settings.createNewSetting(pkg.packageName, origPackage,
    6. disabledPkgSetting, realName, suid, destCodeFile, destResourceFile,
    7. pkg.applicationInfo.nativeLibraryRootDir, pkg.applicationInfo.primaryCpuAbi,
    8. pkg.applicationInfo.secondaryCpuAbi, pkg.mVersionCode,
    9. pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
    10. /// M: [FlagExt] Add flagsEx
    11. pkg.applicationInfo.flagsEx, user,
    12. true /*allowInstall*/, instantApp, parentPackageName,
    13. pkg.getChildPackageNames(), UserManagerService.getInstance(),
    14. usesStaticLibraries, pkg.usesStaticLibrariesVersions);
    15. // SIDE EFFECTS; updates system state; move elsewhere
    16. if (origPackage != null) {
    17. mSettings.addRenamedPackageLPw(pkg.packageName, origPackage.name);
    18. }
    19. mSettings.addUserToSettingLPw(pkgSetting);

    } else {

    1. // REMOVE SharedUserSetting from method; update in a separate call.
    2. //
    3. // TODO(narayan): This update is bogus. nativeLibraryDir & primaryCpuAbi,
    4. // secondaryCpuAbi are not known at this point so we always update them
    5. // to null here, only to reset them at a later point.
    6. Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, suid, destCodeFile,
    7. pkg.applicationInfo.nativeLibraryDir, pkg.applicationInfo.primaryCpuAbi,
    8. pkg.applicationInfo.secondaryCpuAbi, pkg.applicationInfo.flags,
    9. pkg.applicationInfo.privateFlags, pkg.getChildPackageNames(),
    10. UserManagerService.getInstance(), usesStaticLibraries,
    11. pkg.usesStaticLibrariesVersions);

    } // SIDE EFFECTS; persists system state to files on disk; move elsewhere mSettings.writeUserRestrictionsLPw(pkgSetting, oldPkgSetting);

    // SIDE EFFECTS; modifies system state; move elsewhere if (pkgSetting.origPackage != null) {

    1. // If we are first transitioning from an original package,
    2. // fix up the new package's name now. We need to do this after
    3. // looking up the package under its new name, so getPackageLP
    4. // can take care of fiddling things correctly.
    5. pkg.setPackageName(origPackage.name);
    6. // File a report about this.
    7. String msg = "New package " + pkgSetting.realName
    8. + " renamed to replace old package " + pkgSetting.name;
    9. reportSettingsProblem(Log.WARN, msg);
    10. // Make a note of it.
    11. if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
    12. mTransferedPackages.add(origPackage.name);
    13. }
    14. // No longer need to retain this.
    15. pkgSetting.origPackage = null;

    }

    // SIDE EFFECTS; modifies system state; move elsewhere if ((scanFlags & SCAN_CHECK_ONLY) == 0 && realName != null) {

    1. // Make a note of it.
    2. mTransferedPackages.add(pkg.packageName);

    }

    if (mSettings.isDisabledSystemPackageLPr(pkg.packageName)) {

    1. /** M: [Operator] Operator package should not have FLAG_UPDATED_SYSTEM_APP @{ */
    2. PackageSetting oldPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName);
    3. if (oldPs != null && !isVendorApp(oldPs)) {
    4. pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
    5. }
    6. /** @} */

    }

    if ((scanFlags & SCAN_BOOTING) == 0

    1. && (policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
    2. // Check all shared libraries and map to their actual file path.
    3. // We only do this here for apps not on a system dir, because those
    4. // are the only ones that can fail an install due to this. We
    5. // will take care of the system apps by updating all of their
    6. // library paths after the scan is done. Also during the initial
    7. // scan don't update any libs as we do this wholesale after all
    8. // apps are scanned to avoid dependency based scanning.
    9. updateSharedLibrariesLPr(pkg, null);//创建共享库

    }

    if (mFoundPolicyFile) {

    1. SELinuxMMAC.assignSeInfoValue(pkg);//设置SELinux策略

    } pkg.applicationInfo.uid = pkgSetting.appId; pkg.mExtras = pkgSetting;

  1. // Static shared libs have same package with different versions where
  2. // we internally use a synthetic package name to allow multiple versions
  3. // of the same package, therefore we need to compare signatures against
  4. // the package setting for the latest library version.
  5. //验证签名信息的合法性
  6. PackageSetting signatureCheckPs = pkgSetting;
  7. if (pkg.applicationInfo.isStaticSharedLibrary()) {
  8. SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg);
  9. if (libraryEntry != null) {
  10. signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk);
  11. }
  12. }
  13. if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) {
  14. if (checkUpgradeKeySetLP(signatureCheckPs, pkg)) {
  15. // We just determined the app is signed correctly, so bring
  16. // over the latest parsed certs.
  17. pkgSetting.signatures.mSignatures = pkg.mSignatures;
  18. } else {
  19. if ((policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
  20. throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
  21. "Package " + pkg.packageName + " upgrade keys do not match the "
  22. + "previously installed version");
  23. } else {
  24. pkgSetting.signatures.mSignatures = pkg.mSignatures;
  25. String msg = "System package " + pkg.packageName
  26. + " signature changed; retaining data.";
  27. reportSettingsProblem(Log.WARN, msg);
  28. }
  29. }
  30. } else {
  31. try {
  32. // SIDE EFFECTS; compareSignaturesCompat() changes KeysetManagerService
  33. verifySignaturesLP(signatureCheckPs, pkg);
  34. // We just determined the app is signed correctly, so bring
  35. // over the latest parsed certs.
  36. pkgSetting.signatures.mSignatures = pkg.mSignatures;
  37. } catch (PackageManagerException e) {
  38. ///M: Add for operator APP.
  39. if ((policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0
  40. && (policyFlags & PackageParser.PARSE_IS_OPERATOR) == 0) {
  41. throw e;
  42. }
  43. // The signature has changed, but this package is in the system
  44. // image... let's recover!
  45. pkgSetting.signatures.mSignatures = pkg.mSignatures;
  46. // However... if this package is part of a shared user, but it
  47. // doesn't match the signature of the shared user, let's fail.
  48. // What this means is that you can't change the signatures
  49. // associated with an overall shared user, which doesn't seem all
  50. // that unreasonable.
  51. if (signatureCheckPs.sharedUser != null) {
  52. if (compareSignatures(signatureCheckPs.sharedUser.signatures.mSignatures,
  53. pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
  54. throw new PackageManagerException(
  55. INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
  56. "Signature mismatch for shared user: "
  57. + pkgSetting.sharedUser);
  58. }
  59. }
  60. // File a report about this.
  61. String msg = "System package " + pkg.packageName
  62. + " signature changed; retaining data.";
  63. reportSettingsProblem(Log.WARN, msg);
  64. }
  65. }
  66. if ((scanFlags & SCAN_CHECK_ONLY) == 0 && pkg.mAdoptPermissions != null) {
  67. // This package wants to adopt ownership of permissions from
  68. // another package.
  69. // 是否需要获取其他包的权限
  70. for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) {
  71. final String origName = pkg.mAdoptPermissions.get(i);
  72. final PackageSetting orig = mSettings.getPackageLPr(origName);
  73. if (orig != null) {
  74. if (verifyPackageUpdateLPr(orig, pkg)) {
  75. Slog.i(TAG, "Adopting permissions from " + origName + " to "
  76. + pkg.packageName);
  77. // SIDE EFFECTS; updates permissions system state; move elsewhere
  78. mSettings.transferPermissionsLPw(origName, pkg.packageName);
  79. }
  80. }
  81. }
  82. }
  83. }
  84. //确定进程名称
  85. pkg.applicationInfo.processName = fixProcessName(
  86. pkg.applicationInfo.packageName,
  87. pkg.applicationInfo.processName);
  88. if (pkg != mPlatformPackage) {
  89. // Get all of our default paths setup
  90. pkg.applicationInfo.initForUser(UserHandle.USER_SYSTEM);
  91. }
  92. final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting);
  93. if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
  94. if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) {
  95. Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
  96. final boolean extractNativeLibs = !pkg.isLibrary();
  97. derivePackageAbi(pkg, scanFile, cpuAbiOverride, extractNativeLibs,
  98. mAppLib32InstallDir);
  99. Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
  100. // Some system apps still use directory structure for native libraries
  101. // in which case we might end up not detecting abi solely based on apk
  102. // structure. Try to detect abi based on directory structure.
  103. if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
  104. pkg.applicationInfo.primaryCpuAbi == null) {
  105. setBundledAppAbisAndRoots(pkg, pkgSetting);
  106. setNativeLibraryPaths(pkg, mAppLib32InstallDir);
  107. }
  108. } else {
  109. // This is not a first boot or an upgrade, don't bother deriving the
  110. // ABI during the scan. Instead, trust the value that was stored in the
  111. // package setting.
  112. pkg.applicationInfo.primaryCpuAbi = primaryCpuAbiFromSettings;
  113. pkg.applicationInfo.secondaryCpuAbi = secondaryCpuAbiFromSettings;
  114. setNativeLibraryPaths(pkg, mAppLib32InstallDir);
  115. if (DEBUG_ABI_SELECTION) {
  116. Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
  117. pkg.packageName + " " + pkg.applicationInfo.primaryCpuAbi + ", " +
  118. pkg.applicationInfo.secondaryCpuAbi);
  119. }
  120. }
  121. } else {
  122. if ((scanFlags & SCAN_MOVE) != 0) {
  123. // We haven't run dex-opt for this move (since we've moved the compiled output too)
  124. // but we already have this packages package info in the PackageSetting. We just
  125. // use that and derive the native library path based on the new codepath.
  126. pkg.applicationInfo.primaryCpuAbi = pkgSetting.primaryCpuAbiString;
  127. pkg.applicationInfo.secondaryCpuAbi = pkgSetting.secondaryCpuAbiString;
  128. }
  129. // Set native library paths again. For moves, the path will be updated based on the
  130. // ABIs we've determined above. For non-moves, the path will be updated based on the
  131. // ABIs we determined during compilation, but the path will depend on the final
  132. // package path (after the rename away from the stage path).
  133. setNativeLibraryPaths(pkg, mAppLib32InstallDir);
  134. }
  135. // This is a special case for the "system" package, where the ABI is
  136. // dictated by the zygote configuration (and init.rc). We should keep track
  137. // of this ABI so that we can deal with "normal" applications that run under
  138. // the same UID correctly.
  139. if (mPlatformPackage == pkg) {
  140. pkg.applicationInfo.primaryCpuAbi = VMRuntime.getRuntime().is64Bit() ?
  141. Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
  142. }
  143. // If there's a mismatch between the abi-override in the package setting
  144. // and the abiOverride specified for the install. Warn about this because we
  145. // would've already compiled the app without taking the package setting into
  146. // account.
  147. if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) {
  148. if (cpuAbiOverride == null && pkgSetting.cpuAbiOverrideString != null) {
  149. Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride +
  150. " for package " + pkg.packageName);
  151. }
  152. }
  153. // CPU描述
  154. pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
  155. pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
  156. pkgSetting.cpuAbiOverrideString = cpuAbiOverride;
  157. // Copy the derived override back to the parsed package, so that we can
  158. // update the package settings accordingly.
  159. pkg.cpuAbiOverride = cpuAbiOverride;
  160. if (DEBUG_ABI_SELECTION) {
  161. Slog.d(TAG, "Resolved nativeLibraryRoot for " + pkg.applicationInfo.packageName
  162. + " to root=" + pkg.applicationInfo.nativeLibraryRootDir + ", isa="
  163. + pkg.applicationInfo.nativeLibraryRootRequiresIsa);
  164. }
  165. // Push the derived path down into PackageSettings so we know what to
  166. // clean up at uninstall time.
  167. pkgSetting.legacyNativeLibraryPathString = pkg.applicationInfo.nativeLibraryRootDir;
  168. if (DEBUG_ABI_SELECTION) {
  169. Slog.d(TAG, "Abis for package[" + pkg.packageName + "] are" +
  170. " primary=" + pkg.applicationInfo.primaryCpuAbi +
  171. " secondary=" + pkg.applicationInfo.secondaryCpuAbi);
  172. }
  173. // SIDE EFFECTS; removes DEX files from disk; move elsewhere
  174. if ((scanFlags & SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
  175. // We don't do this here during boot because we can do it all
  176. // at once after scanning all existing packages.
  177. //
  178. // We also do this *before* we perform dexopt on this package, so that
  179. // we can avoid redundant dexopts, and also to make sure we've got the
  180. // code and package path correct.
  181. adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages, pkg);
  182. }
  183. if (mFactoryTest && pkg.requestedPermissions.contains(
  184. android.Manifest.permission.FACTORY_TEST)) {
  185. pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
  186. }
  187. if (isSystemApp(pkg)) {
  188. pkgSetting.isOrphaned = true;
  189. }
  190. // 更新安装时间
  191. // Take care of first install / last update times.
  192. final long scanFileTime = getLastModifiedTime(pkg, scanFile);
  193. if (currentTime != 0) {
  194. if (pkgSetting.firstInstallTime == 0) {
  195. pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime;
  196. } else if ((scanFlags & SCAN_UPDATE_TIME) != 0) {
  197. pkgSetting.lastUpdateTime = currentTime;
  198. }
  199. } else if (pkgSetting.firstInstallTime == 0) {
  200. // We need *something*. Take time time stamp of the file.
  201. pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = scanFileTime;
  202. } else if ((policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
  203. if (scanFileTime != pkgSetting.timeStamp) {
  204. // A package on the system image has changed; consider this
  205. // to be an update.
  206. pkgSetting.lastUpdateTime = scanFileTime;
  207. }
  208. }
  209. pkgSetting.setTimeStamp(scanFileTime);
  210. if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
  211. if (nonMutatedPs != null) {
  212. synchronized (mPackages) {
  213. mSettings.mPackages.put(nonMutatedPs.name, nonMutatedPs);
  214. }
  215. }
  216. } else {
  217. final int userId = user == null ? 0 : user.getIdentifier();
  218. // Modify state for the given package setting
  219. // 该方法回设置很多东西包括services,providers,
  220. // 更新lib时杀掉依赖此lib的进程
  221. // 对framework-res.apk单独处理
  222. //更新设置apk的provider并更新到数据中
  223. // 广播接受者receivers,activities,permissionGroups,permissions,Instrumentation信息
  224. commitPackageSettings(pkg, pkgSetting, user, scanFlags
  225. (policyFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/);
  226. if (pkgSetting.getInstantApp(userId)) {
  227. mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId);
  228. }
  229. }
  230. return pkg;
  231. }

``` scanPackageDirtyLI流程总结如下:

  • framework-res.apk单独处理
  • 初始化代码路径和资源路径
  • 创建共享库
  • 验证签名信息的合法性
  • 验证新的包的Provider不会与现有包冲突
  • 是否需要获得其他包的权限
  • 确定进程名称
  • Lib库的更新设置操作等
  • 跟新Settings参数
  • 更新安装的时间
  • 四大组件、权限、Instrumentation、把解析的这些信息注册到PMS

当然上面有不少是在commitPackageSettings方法中实现的.
到此apk就安装完成了,在PackageManagerService的构造方法.接下来的方法就是使用一下两个方法把 // 为申请了特定的资源访问权限的应用程序分配相应的Linux用户组ID updatePermissionsLPw(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags); // 将前面获取到的应用程序安装信息保存在本地的一个配置文件中,以便下一次再安装这些应用程序时 // 可以将需要保持一致的应用程序信息恢复回来 mSettings.writeLPr();