PackageManagerService啟動流程

本次源碼基于Android11分析

PKMS的啟動流程

packageManagerService作為系統(tǒng)的核心服務(wù),其作用是:對應(yīng)用進行安裝、卸載和信息查詢。此篇文章分析PKMS的啟動流程,其啟動流程大致如下:


關(guān)于PackageManagerService的類結(jié)構(gòu)關(guān)系如下圖所示:

PKMS的啟動

PKMS作為系統(tǒng)的核心服務(wù),也是從SystemServer進程中創(chuàng)建啟動的,在其startBootstrapServices、startOtherServices兩個方法中啟動PKMS的服務(wù)。

public final class SystemServer implements Dumpable {

  private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
      // 1. 啟動Installer服務(wù)
      Installer installer = mSystemServiceManager.startService(Installer.class);

      // 2. 獲取設(shè)備是否加密,加密則僅運行“核心”應(yīng)用程序。
      String cryptState = VoldProperties.decrypt().orElse("");
      if (ENCRYPTING_STATE.equals(cryptState)) {
          mOnlyCore = true;
      } else if (ENCRYPTED_STATE.equals(cryptState)) {
          mOnlyCore = true;
      }

      // 3. 調(diào)用PKMS.main ,實例化PKMS構(gòu)造 (重點)
      mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
              domainVerificationService, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF,
              mOnlyCore);

      // 4. 如果設(shè)備沒有加密,操作它。管理A/B OTA dexopting
      if (!mOnlyCore) {
          OtaDexoptService.main(mSystemContext, mPackageManagerService);
      }

  }

  private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
      if (!mOnlyCore) {
          // 5. dex優(yōu)化操作
          mPackageManagerService.updatePackagesIfNeeded();
      }

      // 6. 磁盤優(yōu)化維護操作
      mPackageManagerService.performFstrimIfNeeded();

      // 7. PKMS準(zhǔn)備就緒
      mPackageManagerService.systemReady();

  }
}

startBootstrapServices方法中關(guān)于PKMS主要做了四件事:

1.啟動Installer服務(wù)
2.獲取設(shè)備是否加密,加密則僅運行“核心”應(yīng)用程序。
3.調(diào)用PKMS.main ,實例化PKMS構(gòu)造 (重點)
4.如果設(shè)備沒有加密,操作它。管理A/B OTA dexopting
其中第三點:調(diào)用PKMS.main會創(chuàng)建PKMS實例,并調(diào)用PKMS的構(gòu)造函數(shù),這也是耗時比較久的地方,也是重點分析的地方

startOtherServices方法關(guān)于PKMS主要做了三件事:

1.dex優(yōu)化操作
2.磁盤優(yōu)化維護操作
3.PKMS準(zhǔn)備就緒
其中dex優(yōu)化操作也是比較耗時的操作

以上便是PKMS出生的啟動的地方,其中最主要的是調(diào)用PKMS.main方法:

public static PackageManagerService main(Context context, Installer installer,
                                           boolean factoryTest, boolean onlyCore) {
      // 檢查Package編譯相關(guān)系統(tǒng)屬性
      PackageManagerServiceCompilerMapping.checkProperties();
      .....
      //執(zhí)行pkms構(gòu)造方法
      PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest);
      //啟動部分應(yīng)用服務(wù)于多用戶場景
      m.installWhitelistedSystemPackages();
      //往ServiceManager中注冊"package"和"package_native"
      ServiceManager.addService("package", m);
      final PackageManagerNative pmn = m.new PackageManagerNative();
      ServiceManager.addService("package_native", pmn);
      return m;
  }

main()方法通過調(diào)用PackageManagerService的構(gòu)造函數(shù)創(chuàng)建實例,并把PKMS實例向ServiceManager中注冊。PKMS的構(gòu)造函數(shù)的代碼很長,通過下小節(jié)分析它。

PKMS的構(gòu)造函數(shù)

構(gòu)造函數(shù)分為五個階段,如下代碼簡易概括每個階段的重點執(zhí)行的事情:

public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
      ......
      // 階段一: 開始階段
      EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
              SystemClock.uptimeMillis());
      // 1. 構(gòu)造 DisplayMetrics,保存分辨率相關(guān)信息
      // 2. 創(chuàng)建Installer對象,與installd交互
      // 3. 創(chuàng)建mPermissionManager對象,進行權(quán)限管理
      // 4. 構(gòu)造Settings類,保存安裝包信息,清除路徑不存在的孤立應(yīng)用,主要涉及/data/system/目錄的packages.xml, packages-backup.xml,packages.list,packages-stopped.xml,packages-stopped-backup.xml等文件。
      // 5. 構(gòu)造PackageDexOptimizer及DexManager類,處理dex優(yōu)化
      // 6. 創(chuàng)建SystemConfig實例,獲取系統(tǒng)配置信息,配置共享lib庫
      // 7. 創(chuàng)建PackageManager的Handler線程,循環(huán)處理外部安裝相關(guān)消息。
      ......

      // 階段二:系統(tǒng)掃描階段
      EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
              startTime);
      // 1. 從init.rc中獲取環(huán)境變量BOOTCLASSPATH和SYSTEMSERVERCLASSPATH;
      // 2. 對于舊版本升級的情況,將安裝時獲取權(quán)限變更為運行時申請權(quán)限
      // 3. 掃描system/vendor/product/odm/oem等目錄的priv-app、app、overlay包
      // 4. 清除安裝時臨時文件以及其他不必要的信息。
      //掃描各個系統(tǒng)分區(qū)的的App
      //解析系統(tǒng)App信息
      //把解析結(jié)果存儲起來,存儲在PMS的相關(guān)屬性和mSettings里
      ......

      if (!mOnlyCore) {
          // 階段三: Data掃描階段
          EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                  SystemClock.uptimeMillis());

          // 1. 掃描/data/app下的App,也就是用戶安裝的App
          scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
                  packageParser, executorService);
      }
      ......

      // 階段四,掃描結(jié)束階段
      EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
              SystemClock.uptimeMillis());
      // 1.sdk版本變更,更新權(quán)限
      // 2.OTA升級后首次啟動,清除不必要的緩存數(shù)據(jù)
      // 3.權(quán)限等默認(rèn)項更新完后,清理相關(guān)數(shù)據(jù)
      // 4.更新package.xml
      ......

      // 階段五:就緒階段
      EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
              SystemClock.uptimeMillis());
      // 1. 創(chuàng)建PackageInstallerService對象
      // 2. GC回收內(nèi)存

  }

階段一:主要是解析了package.xml,獲取已經(jīng)安裝的App信息,存儲到Settings的mPackages中。并創(chuàng)建了工作線程和hanlder。
階段二:掃描解析系統(tǒng)App,并把系統(tǒng)App信息存儲在PKMS的相關(guān)屬性和mSettings里
階段三:對對/data/app路徑掃描,此路徑是用戶安裝的App
階段四:對SDK版本進行檢查更新,為系統(tǒng)核心服務(wù)準(zhǔn)備存儲空間、把更新后的信息寫回對應(yīng)的xml文件中。
階段五:初始化PackageInstallerService

其中階段三的掃描用戶安裝的app,是應(yīng)該重點關(guān)注的,其調(diào)用scanDirTracedLI方法對App進行掃描解析。

PKMS的掃描流程

PKMS會掃描如下路徑的App

// 系統(tǒng)App
/vendor/overlay
/product/overlay
/product_services/overlay
/odm/overlay
/oem/overlay
/system/framework
/system/priv-app
/system/app
/vendor/priv-app
/vendor/app
/odm/priv-app
/odm/app
/oem/app
/oem/priv-app
/product/priv-app
/product/app
/product_services/priv-app
/product_services/app
/product_services/priv-app
// 用戶App
/data/app

private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
                               long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
      Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
      try {
          // 調(diào)用scanDirLI
          scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService);
      } finally {
          Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
      }
  }

  private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
                         PackageParser2 packageParser, ExecutorService executorService) {
      final File[] files = scanDir.listFiles();
      if (ArrayUtils.isEmpty(files)) {
          Log.d(TAG, "No files in app dir " + scanDir);
          return;
      }

      if (DEBUG_PACKAGE_SCANNING) {
          Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags
                  + " flags=0x" + Integer.toHexString(parseFlags));
      }

      // ParallelPackageParser是一個隊列,收集系統(tǒng) apk 文件,
      // 然后從這個隊列里面一個個取出apk,調(diào)用PackageParser解析
      ParallelPackageParser parallelPackageParser =
              new ParallelPackageParser(packageParser, executorService);

      // Submit files for parsing in parallel
      int fileCount = 0;
      for (File file : files) {
          // 是 apk文件,或者是目錄
          final boolean isPackage = (isApkFile(file) || file.isDirectory())
                  && !PackageInstallerService.isStageName(file.getName());
          // 過濾掉非 apk 文件,如果不是則跳過繼續(xù)掃描
          if (!isPackage) {
              // Ignore entries which are not packages
              continue;
          }
          // 把 apk 信息存入ParallelPackageParser中的對象mQueue,
          // parsePackage()函數(shù)賦予給了隊列中的parsedPackage成員
          parallelPackageParser.submit(file, parseFlags);
          fileCount++;
      }

      // Process results one by one
      for (; fileCount > 0; fileCount--) {
          ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
          Throwable throwable = parseResult.throwable;
          int errorCode = PackageManager.INSTALL_SUCCEEDED;

          if (throwable == null) {
              // TODO(toddke): move lower in the scan chain
              // Static shared libraries have synthetic package names
              if (parseResult.parsedPackage.isStaticSharedLibrary()) {
                  renameStaticSharedLibraryPackage(parseResult.parsedPackage);
              }
              try {
                   // 更新mSettings中相關(guān)包的數(shù)據(jù)
                   // 把包的信息存儲到mPackages里面
                  addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
                          currentTime, null);
              } catch (PackageManagerException e) {
                  errorCode = e.error;
                  Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
              }
          } else if (throwable instanceof PackageParserException) {
              PackageParserException e = (PackageParserException)
                      throwable;
              errorCode = e.error;
              Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " + e.getMessage());
          } else {
              throw new IllegalStateException("Unexpected exception occurred while parsing "
                      + parseResult.scanFile, throwable);
          }

          if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0 && errorCode != INSTALL_SUCCEEDED) {
              mApexManager.reportErrorWithApkInApex(scanDir.getAbsolutePath());
          }

          // 如果是非系統(tǒng) apk 并且解析失敗
          if ((scanFlags & SCAN_AS_SYSTEM) == 0
                  && errorCode != PackageManager.INSTALL_SUCCEEDED) {
              logCriticalInfo(Log.WARN,
                      "Deleting invalid package at " + parseResult.scanFile);
              // 非系統(tǒng) Package 掃描失敗,刪除文件
              removeCodePathLI(parseResult.scanFile);
          }
      }
  }

scanDirLI方法:遍歷目錄下所有文件,如果文件不是Apk或目錄則不掃描,之后調(diào)用ParallelPackageParser.submit。如果非系統(tǒng)的App沒有解析失敗將被刪除。

   public void submit(File scanFile, int parseFlags) {
       mExecutorService.submit(() -> {
           ParseResult pr = new ParseResult();
           Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parallel parsePackage [" + scanFile + "]");
           try {
               pr.scanFile = scanFile;
               // 通過parsePackage()方法解析
               pr.parsedPackage = parsePackage(scanFile, parseFlags);
           } catch (Throwable e) {
               pr.throwable = e;
           } finally {
               Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
           }
           try {
               // 將ParseResult加入到mQueue隊列
               mQueue.put(pr);
           } catch (InterruptedException e) {
               Thread.currentThread().interrupt();
               // Propagate result to callers of take().
               // This is helpful to prevent main thread from getting stuck waiting on
               // ParallelPackageParser to finish in case of interruption
               mInterruptedInThread = Thread.currentThread().getName();
           }
       });
   }

   protected ParsedPackage parsePackage(File scanFile, int parseFlags)
           throws PackageParser.PackageParserException {
       // 調(diào)用 PackageParser2.parsePackage方法
       return mPackageParser.parsePackage(scanFile, parseFlags, true);
   }

通過PackageParser2.parsePackage解析Apk文件

   // PackageParser2
  public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
          throws PackageParserException {
      ......
      // 調(diào)用ParsingPackageUtils.parsePackage進行解析
      ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags);
      ......
      ParsedPackage parsed = (ParsedPackage) result.getResult().hideAsParsed();
      return parsed;
  }

  //ParsingPackageUtils
  public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile,
                                                  int flags)
          throws PackageParserException {
      // 如果是目錄,調(diào)用parseClusterPackage
      if (packageFile.isDirectory()) {
          return parseClusterPackage(input, packageFile, flags);
      } else {
          // 如果是apk,調(diào)用parseMonolithicPackage
          return parseMonolithicPackage(input, packageFile, flags);
      }
  }

如果是目錄調(diào)用parseClusterPackage方法,如果是apk文件調(diào)用parseMonolithicPackage方法

  private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
                                                          int flags) {
      // 獲取應(yīng)用目錄的PackageLite對象,這個對象分開保存了目錄下的核心應(yīng)用和非核心應(yīng)用的名稱
      ParseResult<PackageParser.PackageLite> liteResult =
              ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, 0);
      if (liteResult.isError()) {
          return input.error(liteResult);
      }

      final PackageParser.PackageLite lite = liteResult.getResult();
      // 如果lite中沒有核心應(yīng)用,退出
      if (mOnlyCoreApps && !lite.coreApp) {
          return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
                  "Not a coreApp: " + packageDir);
      }

      // Build the split dependency tree.
      SparseArray<int[]> splitDependencies = null;
      final SplitAssetLoader assetLoader;
      if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) {
          try {
              splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite);
              assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags);
          } catch (SplitAssetDependencyLoader.IllegalDependencyException e) {
              return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage());
          }
      } else {
          assetLoader = new DefaultSplitAssetLoader(lite, flags);
      }

      try {
          final AssetManager assets = assetLoader.getBaseAssetManager();
          final File baseApk = new File(lite.baseCodePath);
          // 對核心應(yīng)用進行解析
          ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk,
                  lite.codePath, assets, flags);
          if (result.isError()) {
              return input.error(result);
          }

          ParsingPackage pkg = result.getResult();
          if (!ArrayUtils.isEmpty(lite.splitNames)) {
              pkg.asSplit(
                      lite.splitNames,
                      lite.splitCodePaths,
                      lite.splitRevisionCodes,
                      splitDependencies
              );
              final int num = lite.splitNames.length;

              for (int i = 0; i < num; i++) {
                  final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
                  // 對非核心應(yīng)用的處理
                  parseSplitApk(input, pkg, i, splitAssets, flags);
              }
          }

          pkg.setUse32BitAbi(lite.use32bitAbi);
          return input.success(pkg);
      } catch (PackageParserException e) {
          return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                  "Failed to load assets: " + lite.baseCodePath, e);
      } finally {
          IoUtils.closeQuietly(assetLoader);
      }
  }


  private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
                                                             int flags) throws PackageParserException {
      ParseResult<PackageParser.PackageLite> liteResult =
              ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, flags);
      if (liteResult.isError()) {
          return input.error(liteResult);
      }

      final PackageParser.PackageLite lite = liteResult.getResult();
      if (mOnlyCoreApps && !lite.coreApp) {
          return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
                  "Not a coreApp: " + apkFile);
      }

      final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
      try {
          // 對核心應(yīng)用解析
          ParseResult<ParsingPackage> result = parseBaseApk(input,
                  apkFile,
                  apkFile.getCanonicalPath(),
                  assetLoader.getBaseAssetManager(), flags);
          if (result.isError()) {
              return input.error(result);
          }

          return input.success(result.getResult()
                  .setUse32BitAbi(lite.use32bitAbi));
      } catch (IOException e) {
          return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                  "Failed to get path: " + apkFile, e);
      } finally {
          IoUtils.closeQuietly(assetLoader);
      }
  }

無論文件是目錄還是apk,都會調(diào)用 parseBaseApk方法,從parseBaseApk方法開始解析AndroidManifest.xml文件

private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
                                                   String codePath, AssetManager assets, int flags) {
      final String apkPath = apkFile.getAbsolutePath();

      String volumeUuid = null;
      if (apkPath.startsWith(PackageParser.MNT_EXPAND)) {
          final int end = apkPath.indexOf('/', PackageParser.MNT_EXPAND.length());
          volumeUuid = apkPath.substring(PackageParser.MNT_EXPAND.length(), end);
      }

      if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);

      final int cookie = assets.findCookieForPath(apkPath);
      if (cookie == 0) {
          return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                  "Failed adding asset path: " + apkPath);
      }

      // assets.openXmlResourceParser(...)。獲得一個 XML 資源解析對象,
      try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
              PackageParser.ANDROID_MANIFEST_FILENAME)) {
          final Resources res = new Resources(assets, mDisplayMetrics, null);
          // 再調(diào)用重載函數(shù)parseBaseApk
          ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
                  parser, flags);
          if (result.isError()) {
              return input.error(result.getErrorCode(),
                      apkPath + " (at " + parser.getPositionDescription() + "): "
                              + result.getErrorMessage());
          }

          final ParsingPackage pkg = result.getResult();
          if (assets.containsAllocatedTable()) {
              final ParseResult<?> deferResult = input.deferError(
                      "Targeting R+ (version " + Build.VERSION_CODES.R + " and above) requires"
                              + " the resources.arsc of installed APKs to be stored uncompressed"
                              + " and aligned on a 4-byte boundary",
                      DeferredError.RESOURCES_ARSC_COMPRESSED);
              if (deferResult.isError()) {
                  return input.error(INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED,
                          deferResult.getErrorMessage());
              }
          }

          ApkAssets apkAssets = assets.getApkAssets()[0];
          if (apkAssets.definesOverlayable()) {
              SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers();
              int size = packageNames.size();
              for (int index = 0; index < size; index++) {
                  String packageName = packageNames.get(index);
                  Map<String, String> overlayableToActor = assets.getOverlayableMap(packageName);
                  if (overlayableToActor != null && !overlayableToActor.isEmpty()) {
                      for (String overlayable : overlayableToActor.keySet()) {
                          pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable));
                      }
                  }
              }
          }

          pkg.setVolumeUuid(volumeUuid);

          if ((flags & PackageParser.PARSE_COLLECT_CERTIFICATES) != 0) {
              pkg.setSigningDetails(getSigningDetails(pkg, false));
          } else {
              pkg.setSigningDetails(SigningDetails.UNKNOWN);
          }

          return input.success(pkg);
      } catch (Exception e) {
          return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                  "Failed to read manifest from " + apkPath, e);
      }
  }


  private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
                                                   String codePath, Resources res, XmlResourceParser parser, int flags)
          throws XmlPullParserException, IOException, PackageParserException {
      final String splitName;
      final String pkgName;

      ParseResult<Pair<String, String>> packageSplitResult =
              ApkLiteParseUtils.parsePackageSplitNames(input, parser, parser);
      if (packageSplitResult.isError()) {
          return input.error(packageSplitResult);
      }

      Pair<String, String> packageSplit = packageSplitResult.getResult();
      pkgName = packageSplit.first;
      splitName = packageSplit.second;

      if (!TextUtils.isEmpty(splitName)) {
          return input.error(
                  PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
                  "Expected base APK, but found split " + splitName
          );
      }

      // AndroidManifest
      final TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
      try {
          final boolean isCoreApp =
                  parser.getAttributeBooleanValue(null, "coreApp", false);
          final ParsingPackage pkg = mCallback.startParsingPackage(
                  pkgName, apkPath, codePath, manifestArray, isCoreApp);
          // 調(diào)用parseBaseApkTags()
          final ParseResult<ParsingPackage> result =
                  parseBaseApkTags(input, pkg, manifestArray, res, parser, flags);
          if (result.isError()) {
              return result;
          }

          return input.success(pkg);
      } finally {
          manifestArray.recycle();
      }
  }


  private ParseResult<ParsingPackage> parseBaseApkTags(ParseInput input, ParsingPackage pkg,
                                                       TypedArray sa, Resources res, XmlResourceParser parser, int flags)
          throws XmlPullParserException, IOException {
      ParseResult<ParsingPackage> sharedUserResult = parseSharedUser(input, pkg, sa);
      if (sharedUserResult.isError()) {
          return sharedUserResult;
      }

      pkg.setInstallLocation(anInteger(PackageParser.PARSE_DEFAULT_INSTALL_LOCATION,
              R.styleable.AndroidManifest_installLocation, sa))
              .setTargetSandboxVersion(anInteger(PackageParser.PARSE_DEFAULT_TARGET_SANDBOX,
                      R.styleable.AndroidManifest_targetSandboxVersion, sa))
              /* Set the global "on SD card" flag */
              .setExternalStorage((flags & PackageParser.PARSE_EXTERNAL_STORAGE) != 0);

      boolean foundApp = false;
      final int depth = parser.getDepth();
      int type;
      while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
              && (type != XmlPullParser.END_TAG
              || parser.getDepth() > depth)) {
          if (type != XmlPullParser.START_TAG) {
              continue;
          }

          String tagName = parser.getName();
          final ParseResult result;

          // TODO(b/135203078): Convert to instance methods to share variables
          // <application> has special logic, so it's handled outside the general method
          // 判斷是是否是Application標(biāo)簽
          if (PackageParser.TAG_APPLICATION.equals(tagName)) {
              if (foundApp) {
                  if (PackageParser.RIGID_PARSER) {
                      result = input.error("<manifest> has more than one <application>");
                  } else {
                      Slog.w(TAG, "<manifest> has more than one <application>");
                      result = input.success(null);
                  }
              } else {
                  foundApp = true;
                  // 是application標(biāo)簽,調(diào)用parseBaseApplication方法,解析application
                  result = parseBaseApplication(input, pkg, res, parser, flags);
              }
          } else {
              // 如果不是application標(biāo)簽,調(diào)用parseBaseApkTag方法,解析核心應(yīng)用的所有tag
              result = parseBaseApkTag(tagName, input, pkg, res, parser, flags);
          }

          if (result.isError()) {
              return input.error(result);
          }
      }

      if (!foundApp && ArrayUtils.size(pkg.getInstrumentations()) == 0) {
          ParseResult<?> deferResult = input.deferError(
                  "<manifest> does not contain an <application> or <instrumentation>",
                  DeferredError.MISSING_APP_TAG);
          if (deferResult.isError()) {
              return input.error(deferResult);
          }
      }

      if (!ParsedAttribution.isCombinationValid(pkg.getAttributions())) {
          return input.error(
                  INSTALL_PARSE_FAILED_BAD_MANIFEST,
                  "Combination <feature> tags are not valid"
          );
      }

      convertNewPermissions(pkg);

      convertSplitPermissions(pkg);

      // At this point we can check if an application is not supporting densities and hence
      // cannot be windowed / resized. Note that an SDK version of 0 is common for
      // pre-Doughnut applications.
      if (pkg.getTargetSdkVersion() < DONUT
              || (!pkg.isSupportsSmallScreens()
              && !pkg.isSupportsNormalScreens()
              && !pkg.isSupportsLargeScreens()
              && !pkg.isSupportsExtraLargeScreens()
              && !pkg.isResizeable()
              && !pkg.isAnyDensity())) {
          adjustPackageToBeUnresizeableAndUnpipable(pkg);
      }

      return input.success(pkg);
  }

  private ParseResult<ParsingPackage> parseBaseApplication(ParseInput input,
                                                           ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
          throws XmlPullParserException, IOException {

      ......
      while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
              && (type != XmlPullParser.END_TAG
              || parser.getDepth() > depth)) {
          if (type != XmlPullParser.START_TAG) {
              continue;
          }

          final ParseResult result;
          // 獲取 "application" 子標(biāo)簽的標(biāo)簽內(nèi)容
          String tagName = parser.getName();
          boolean isActivity = false;
          switch (tagName) {
              // 如果標(biāo)簽是 "activity"
              case "activity":
                  isActivity = true;
                  // fall-through
              case "receiver":
                  // 如果標(biāo)簽是 "receiver",獲取receiver信息
                  ParseResult<ParsedActivity> activityResult =
                          ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg,
                                  res, parser, flags, PackageParser.sUseRoundIcon, input);

                  if (activityResult.isSuccess()) {
                      ParsedActivity activity = activityResult.getResult();
                      if (isActivity) {
                          hasActivityOrder |= (activity.getOrder() != 0);
                          pkg.addActivity(activity);
                      } else {
                          hasReceiverOrder |= (activity.getOrder() != 0);
                          pkg.addReceiver(activity);
                      }
                  }

                  result = activityResult;
                  break;
              case "service":
                  // 解析 "service"
                  ParseResult<ParsedService> serviceResult =
                          ParsedServiceUtils.parseService(mSeparateProcesses, pkg, res, parser,
                                  flags, PackageParser.sUseRoundIcon, input);
                  if (serviceResult.isSuccess()) {
                      ParsedService service = serviceResult.getResult();
                      hasServiceOrder |= (service.getOrder() != 0);
                      pkg.addService(service);
                  }

                  result = serviceResult;
                  break;
              case "provider":
                  // 解析 "provider"
                  ParseResult<ParsedProvider> providerResult =
                          ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser,
                                  flags, PackageParser.sUseRoundIcon, input);
                  if (providerResult.isSuccess()) {
                      pkg.addProvider(providerResult.getResult());
                  }

                  result = providerResult;
                  break;
              case "activity-alias":
                  // 解析 "activity-alias"
                  activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res,
                          parser, PackageParser.sUseRoundIcon, input);
                  if (activityResult.isSuccess()) {
                      ParsedActivity activity = activityResult.getResult();
                      hasActivityOrder |= (activity.getOrder() != 0);
                      pkg.addActivity(activity);
                  }

                  result = activityResult;
                  break;
              default:
                  result = parseBaseAppChildTag(input, tagName, pkg, res, parser, flags);
                  break;
          }

          if (result.isError()) {
              return input.error(result);
          }
      }

      if (TextUtils.isEmpty(pkg.getStaticSharedLibName())) {
          // Add a hidden app detail activity to normal apps which forwards user to App Details
          // page.
          ParseResult<ParsedActivity> a = generateAppDetailsHiddenActivity(input, pkg);
          if (a.isError()) {
              // Error should be impossible here, as the only failure case as of SDK R is a
              // string validation error on a constant ":app_details" string passed in by the
              // parsing code itself. For this reason, this is just a hard failure instead of
              // deferred.
              return input.error(a);
          }

          pkg.addActivity(a.getResult());
      }

      if (hasActivityOrder) {
          pkg.sortActivities();
      }
      if (hasReceiverOrder) {
          pkg.sortReceivers();
      }
      if (hasServiceOrder) {
          pkg.sortServices();
      }

      // Must be run after the entire {@link ApplicationInfo} has been fully processed and after
      // every activity info has had a chance to set it from its attributes.
      setMaxAspectRatio(pkg);
      setMinAspectRatio(pkg);
      setSupportsSizeChanges(pkg);

      pkg.setHasDomainUrls(hasDomainURLs(pkg));

      return input.success(pkg);
  }

parseBaseApk方法開始解析AndroidManifest.xml文件,parseBaseApkTags方法中將application標(biāo)簽和其他標(biāo)簽分開處理,如果是application標(biāo)簽則里面定義了四大組件,通過parseBaseApplication方法對application標(biāo)簽進行解析。

App通過解析后,要對信息進行保存,則調(diào)用PKMS. addForInitLI

private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
          @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
          @Nullable UserHandle user)
                  throws PackageManagerException {
      
      // 判斷系統(tǒng)應(yīng)用是否需要更新
      synchronized (mLock) {
          if (scanSystemPartition) {
              if (isSystemPkgUpdated) {
                 //......
              }
          }
      }

      if (isSystemPkgBetter) {
          // 更新安裝包到 system 分區(qū)中
          synchronized (mLock) {
              // just remove the loaded entries from package lists
              mPackages.remove(pkgSetting.name);
          }

          // 創(chuàng)建安裝參數(shù) InstallArgs
          final InstallArgs args = createInstallArgsForExisting(
                  pkgSetting.codePathString,
                  pkgSetting.resourcePathString, getAppDexInstructionSets(
                          pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
          args.cleanUpResourcesLI();
          synchronized (mLock) {
              mSettings.enableSystemPackageLPw(pkgSetting.name);
          }
      }

      // 安裝包校驗
      collectCertificatesLI(pkgSetting, parsedPackage, forceCollect, skipVerify);
              try (@SuppressWarnings("unused") PackageFreezer freezer = freezePackage(
                      parsedPackage.getPackageName(),
                      "scanPackageInternalLI")) {
                // 如果兩個apk簽名不匹配,則調(diào)用 deletePackageLIF 方法清除 apk 文件及其數(shù)據(jù)
                  deletePackageLIF(parsedPackage.getPackageName(), null, true, null, 0, null,
                          false, null);
              }
              pkgSetting = null;
          } else if (newPkgVersionGreater) {
              // 更新系統(tǒng) apk 程序
              InstallArgs args = createInstallArgsForExisting(
                      pkgSetting.codePathString,
                      pkgSetting.resourcePathString, getAppDexInstructionSets(
                              pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
              synchronized (mInstallLock) {
                  args.cleanUpResourcesLI();
              }
          } 
      }

      // 如果新安裝的系統(tǒng) app 會被舊的 APP 數(shù)據(jù)覆蓋,所以需要隱藏系統(tǒng)應(yīng)用程序,并重新掃描 /data/app 目錄
      if (shouldHideSystemApp) {
          synchronized (mLock) {
              mSettings.disableSystemPackageLPw(parsedPackage.getPackageName(), true);
          }
      }
      return scanResult.pkgSetting.pkg;
  }

總結(jié):

PKMS的啟動流程:在SystemServer進程中啟動 PKMS,通過調(diào)用PKMS的構(gòu)造函數(shù)遍歷系統(tǒng)App和非系統(tǒng)App進行解析對AndroidManifest.xml的結(jié)點進行解析,然后將解析結(jié)果進行保存更新。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容