[Série Android Framework] Chapitre 4 Principe PMS

1 Introduction au PMS

PMS(PackageManagerService)Est fourni par Android 包管理系统服务, il est utilisé pour gérer tout 包信息, y compris 应用安装, et卸载更新解析AndroidManifest.xml . En analysant chaque application installée AndroidManifest.xml, toutes les données du XML sont enregistrées et les données requises par AMS sont ensuite fournies. Il s'agit d'un cache qui enregistre les données de l'application.

Nous savons tous qu'il AndroidManifest.xmldéfinit toutes les informations contenues dans l'apk 四大组件, 权限etc., c'est un fichier de définition. La chose la plus importante pour que PMS analyse l'apk est de 扫描/data/app和/system/app目录下的apk文件trouver le package apk AndroidManifest.xml, puis 解析AndroidManifest.xml的信息保存到系统内存中, lorsque AMS a besoin de données d'application, il peut trouver PMS et obtenir rapidement des informations pertinentes de la mémoire.

Nous savons que plus il y a d’applications installées sur un appareil Android, plus son démarrage est lent. La raison en est que davantage d'applications sont installées et que PMSl'analyse fastidieuse augmentera naturellement. Le démarrage fastidieux 70%est entièrement lié PMSà l'analyse. Si vous le dites 优化开机启动速度, autant PMScommencer par cela.

Cet article est basé sur Android10(Q)l'analyse du code source

2 PMS début

Tous les services de base du système Android seront démarrés SystemServer, et PMS ne fait pas exception. SystemServerIl démarrera et s'exécutera lorsque le téléphone sera allumé. Sur la façon dont SystemServer est démarré, vous pouvez consulter l'article [Android Framework Series] Chapitre 3 Zygote Process Related et [Android Vehicle Series] Chapitre 10 System Services - SystemServer Source Code Analysis (API28)

Nous savons que PMS est démarré dans le processus SystemServer, voyons comment démarrer PMS :

/frameworks/base/services/java/com/android/server/SystemServer.java

348      public static void main(String[] args) {
    
    
349          new SystemServer().run();
350      }
......
370      private void run() {
    
    
......
507          // Start services.
508          try {
    
    
509              traceBeginAndSlog("StartServices");
510              startBootstrapServices();
511              startCoreServices();
512              startOtherServices();
513              SystemServerInitThreadPool.shutdown();
514          } catch (Throwable ex) {
    
    
515              Slog.e("System", "******************************************");
516              Slog.e("System", "************ Failure starting system services", ex);
517              throw ex;
518          } finally {
    
    
519              traceEnd();
520          }
......
543      }

......
623      private void startBootstrapServices() {
    
    
......
734          try {
    
    
735              Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
736              mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
737                      mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
738          } finally {
    
    
739              Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
740          }
741          mFirstBoot = mPackageManagerService.isFirstBoot();
742          mPackageManager = mSystemContext.getPackageManager();
......
818      }

/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

2283      public static PackageManagerService main(Context context, Installer installer,
2284              boolean factoryTest, boolean onlyCore) {
    
    
2285          // Self-check for initial settings.
2286          PackageManagerServiceCompilerMapping.checkProperties();
2287  
2288          PackageManagerService m = new PackageManagerService(context, installer,
2289                  factoryTest, onlyCore);
2290          m.enableSystemUserPackages();
2291          ServiceManager.addService("package", m);
2292          final PackageManagerNative pmn = m.new PackageManagerNative();
2293          ServiceManager.addService("package_native", pmn);
2294          return m;
2295      }

Zygote进程Appelez la méthode SystemServer.javadans la classe main(), la méthode run()dans la méthode startBootstrapServices()initialise les services de base tels que PMS, appelle sa main()méthode pour créer le service correspondant et y ajoute le service PMS ServiceManager(AMS est également la même opération) pour la gestion des services.

ServiceManageraddService()Seules la méthode et la méthode sont fournies.Lorsque getService()vous app进程avez besoin d'obtenir les données correspondantes 系统服务, vous utiliserez le proxy pour ServiceManagerobtenir le service correspondant et utiliserez la communication Binder pour obtenir les données.Binder

/frameworks/base/core/java/android/app/ActivityThread.java

2131      @UnsupportedAppUsage
2132      public static IPackageManager getPackageManager() {
    
    
2133          if (sPackageManager != null) {
    
    
2134              //Slog.v("PackageManager", "returning cur default = " + sPackageManager);
2135              return sPackageManager;
2136          }
2137          IBinder b = ServiceManager.getService("package");
2138          //Slog.v("PackageManager", "default service binder = " + b);
2139          sPackageManager = IPackageManager.Stub.asInterface(b);
2140          //Slog.v("PackageManager", "default service = " + sPackageManager);
2141          return sPackageManager;
2142      }

3 Analyse PMS

L'analyse PMS fait principalement trois choses :

1. 遍历/data/app和/system/app文件夹,找到apk文件
2. 解压apk文件
3. dom解析AndroidManifest.xml文件,将xml信息存储起来提供给AMS使用

3.1 Parcours du dossier /data/app

/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

......
		 // /data/app目录
663      private static final File sAppInstallDir =
664              new File(Environment.getDataDirectory(), "app");
......
2380      public PackageManagerService(Context context, Installer installer,
2381              boolean factoryTest, boolean onlyCore) {
    
    
......
				  // /system/app 目录
2667              final File systemAppDir = new File(Environment.getRootDirectory(), "app");
				  // 扫描/system/app 目录下的apk文件
2668              scanDirTracedLI(systemAppDir,
2669                      mDefParseFlags
2670                      | PackageParser.PARSE_IS_SYSTEM_DIR,
2671                      scanFlags
2672                      | SCAN_AS_SYSTEM,
2673                      0);
......
				      // 扫描/data/app 目录下的apk文件
2914                  scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
......
3372      }
......
9003      private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags, long currentTime) {
    
    
9004          Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
9005          try {
    
    
9006              scanDirLI(scanDir, parseFlags, scanFlags, currentTime);
9007          } finally {
    
    
9008              Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
9009          }
9010      }
9011  
9012      private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
    
    
9013          final File[] files = scanDir.listFiles();
......
9023          try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
9024                  mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
9025                  mParallelPackageParserCallback)) {
    
    
9026              // Submit files for parsing in parallel
9027              int fileCount = 0;
9028              for (File file : files) {
    
    
9029                  final boolean isPackage = (isApkFile(file) || file.isDirectory())
9030                          && !PackageInstallerService.isStageName(file.getName());
9031                  if (!isPackage) {
    
    
9032                      // Ignore entries which are not packages
9033                      continue;
9034                  }
9035                  parallelPackageParser.submit(file, parseFlags);
9036                  fileCount++;
9037              }
......
9076          }
9077      }

Nous voyons ici parcourir /data/apples /system/appdossiers, trouver le fichier apk, puis submit()analyser l'apk via la méthode. Continuons à regarder submit()la méthode

3.2 Décompressez le fichier apk

/frameworks/base/services/core/java/com/android/server/pm/ParallelPackageParser.java

100      /**
101       * Submits the file for parsing
102       * @param scanFile file to scan
103       * @param parseFlags parse falgs
104       */
105      public void submit(File scanFile, int parseFlags) {
    
    
106          mService.submit(() -> {
    
    
107              ParseResult pr = new ParseResult();
108              Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parallel parsePackage [" + scanFile + "]");
109              try {
    
    
110                  PackageParser pp = new PackageParser();
111                  pp.setSeparateProcesses(mSeparateProcesses);
112                  pp.setOnlyCoreApps(mOnlyCore);
113                  pp.setDisplayMetrics(mMetrics);
114                  pp.setCacheDir(mCacheDir);
115                  pp.setCallback(mPackageParserCallback);
					 // 需要解析的apk文件路径
116                  pr.scanFile = scanFile;
					 // 通过PackageParser对apk进行解析
117                  pr.pkg = parsePackage(pp, scanFile, parseFlags);
118              } catch (Throwable e) {
    
    
119                  pr.throwable = e;
120              } finally {
    
    
121                  Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
122              }
123              try {
    
    
124                  mQueue.put(pr);
125              } catch (InterruptedException e) {
    
    
126                  Thread.currentThread().interrupt();
127                  // Propagate result to callers of take().
128                  // This is helpful to prevent main thread from getting stuck waiting on
129                  // ParallelPackageParser to finish in case of interruption
130                  mInterruptedInThread = Thread.currentThread().getName();
131              }
132          });
133      }
134  
135      @VisibleForTesting
136      protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
137              int parseFlags) throws PackageParser.PackageParserException {
    
    
138          return packageParser.parsePackage(scanFile, parseFlags, true /* useCaches */);
139      }

Transmettez le chemin du fichier apk trouvé ci-dessus dans l'objet PackageParser parsePackage()pour analyser l'apk. Il convient de noter ici : les méthodes d'analyse sont différentes selon les différentes versions du code source du système. La façon de démarrer l'analyse dans les versions 6.0, 7.0 et 8.0 est toujours l'analyse directe, mais dans 10.0版本开始使用线程池放到子线程去解析,加快了手机启动速度.

3.3 dom analyse le fichier AndroidManifest.xml

/frameworks/base/core/java/android/content/pm/PackageParser.java

1011      @UnsupportedAppUsage
1012      public Package parsePackage(File packageFile, int flags, boolean useCaches)
1013              throws PackageParserException {
    
    
1014          Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;
1015          if (parsed != null) {
    
    
				  // 直接返回缓存
1016              return parsed;
1017          }
1018  
1019          long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
			  // apk文件非目录,执行parseMonolithicPackage()
1020          if (packageFile.isDirectory()) {
    
    
1021              parsed = parseClusterPackage(packageFile, flags);
1022          } else {
    
    
1023              parsed = parseMonolithicPackage(packageFile, flags);
1024          }
......
1036          return parsed;
1037      }
......
1289      @Deprecated
1290      @UnsupportedAppUsage
1291      public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
    
    
......
1300          final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
1301          try {
    
    
				  // apk解析方法parseBaseApk()
1302              final Package pkg = parseBaseApk(apkFile, assetLoader.getBaseAssetManager(), flags);
1303              pkg.setCodePath(apkFile.getCanonicalPath());
1304              pkg.setUse32bitAbi(lite.use32bitAbi);
1305              return pkg;
1306          } catch (IOException e) {
    
    
1307              throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
1308                      "Failed to get path: " + apkFile, e);
1309          } finally {
    
    
1310              IoUtils.closeQuietly(assetLoader);
1311          }
1312      }
1313  
1314      private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
1315              throws PackageParserException {
    
    
1316          final String apkPath = apkFile.getAbsolutePath();
......
1328  		  // 开始 dom 解析 AndroidManifest.xml
1329          XmlResourceParser parser = null;
1330          try {
    
    
1331              final int cookie = assets.findCookieForPath(apkPath);
1332              if (cookie == 0) {
    
    
1333                  throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
1334                          "Failed adding asset path: " + apkPath);
1335              }
1336              parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
......
1340              final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
......
1351              return pkg;
1352  
1353          } catch (PackageParserException e) {
    
    
1354              throw e;
1355          } catch (Exception e) {
    
    
1356              throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
1357                      "Failed to read manifest from " + apkPath, e);
1358          } finally {
    
    
1359              IoUtils.closeQuietly(parser);
1360          }
1361      }
......

1913      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
1914      private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
1915              String[] outError) throws XmlPullParserException, IOException {
    
    
1916          final String splitName;
1917          final String pkgName;
1918  
1919          try {
    
    
1920              Pair<String, String> packageSplit = parsePackageSplitNames(parser, parser);
1921              pkgName = packageSplit.first; // 包名
1922              splitName = packageSplit.second;
......
1932          }
......
			  // 将解析的信息(四大组件、权限等)存储到Package
1943          final Package pkg = new Package(pkgName);
.....
1975          return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
1976      }
......
6403      /**
6404       * Representation of a full package parsed from APK files on disk. A package
6405       * consists of a single base APK, and zero or more split APKs.
6406       */
6407      public final static class Package implements Parcelable {
    
    
......
			  // 包名
6409          @UnsupportedAppUsage
6410          public String packageName; 
			  // 应用信息
6453          @UnsupportedAppUsage
6454          public ApplicationInfo applicationInfo = new ApplicationInfo();
6455  
			  // 权限相关信息
6456          @UnsupportedAppUsage
6457          public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
6458          @UnsupportedAppUsage
6459          public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
			  // 四大组件相关信息
6460          @UnsupportedAppUsage
6461          public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
6462          @UnsupportedAppUsage
6463          public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
6464          @UnsupportedAppUsage
6465          public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
6466          @UnsupportedAppUsage
6467          public final ArrayList<Service> services = new ArrayList<Service>(0);
......
7499      }

Le processus d'analyse en trois étapes ici est terminé :

  1. Recherchez le chemin du fichier apk en parcourant /data/appun /system/appdossier ;
  2. La méthode de transmission du chemin trouvé dans l'objet PackageParser parsePackage()effectue une analyse dom sur le fichier AndroidManifest.xml de l'apk ;
  3. Analysez ensuite les informations en fonction de différentes balises et stockez-les dans le champ correspondant de la classe Package et mettez-les en cache dans la mémoire, telles que : quatre composants principaux, autorisations et autres informations. Il est pratique pour les AMS suivants d'obtenir et d'utiliser directement à partir du cache de packages de PMS.
    insérer la description de l'image ici

4 Résumé

Résumons brièvement le PMS : PMS
est 包管理系统服务utilisé pour gérer tous les 包信息, y compris 应用安装, et . Une fois le téléphone mobile allumé, il parcourra tous les appareils sur l'appareil et sous le répertoire , et mettra en cache toutes les informations de données ( ,, etc.) dans le fichier XML dans la mémoire en analysant toutes les applications installées , puis les fournira. à d'autres services.卸载更新解析AndroidManifest.xml/data/app//system/app/apk文件AndroidManifest.xml应用信息权限四大组件AMS

Le processus global du PMS :

  1. Le téléphone s'allume, 内核进程démarre init进程, init进程démarre SeriviceManager进程et 启动Zygote进程, Zygote进程démarre SystemServer, SystemServerle processus démarre AMS, PMS, et s'enregistre sur ServiceManager.
  2. PMSAprès avoir été SystemServerinitialisé, lancez la numérisation /data/app/et /system/app/tout sous le répertoire apk文件, récupérez chaque apk文件fichier AndroidManifest.xmlet continuez dom解析.
  3. L'analyse AndroidManifest.xmlconvertit les informations de données telles que 应用信息, 权限, , etc. dans un cache .四大组件Java Bean内存中
  4. Lorsque AMSla récupération est nécessaire apk数据信息, débrouillez-vous ServiceManagerpour vous PMS的Binder代理débrouiller Binder通信.
    insérer la description de l'image ici

5 questions d'entretien

1 Que fait le PMS, comment comprenez-vous le PMS

La gestion des packages, l'analyse des packages, la mise en cache des résultats et les interfaces de requête sont fournies.
1. 遍历/data/app和/system/app文件夹,找到apk文件
2. 解压apk文件
3. dom解析AndroidManifest.xml文件,将xml信息存储起来提供给AMS使用

2 A quoi sert de se familiariser avec le code source du PMS

1. Aider à comprendre les principes du système de gestion de packages Android
2. Coopérer avec AMS via la technologie Hook pour réaliser des mises à jour à chaud, des plug-ins et d'autres fonctions.

Par exemple, nous pouvons obtenir l'objet PackageParser par réflexion, puis appeler son parsePackage() pour transmettre le chemin apk afin de terminer l'analyse pour obtenir l'objet Package, puis refléter les activités, fournisseurs, récepteurs et variables de services de l'objet PackageParser. PMS pour y ajouter les données que nous avons analysées, afin que le chargement dynamique soit réalisé (pas besoin d'ajouter des informations dans le fichier AndroidManifest.xml).

Je suppose que tu aimes

Origine blog.csdn.net/u010687761/article/details/131445261
conseillé
Classement