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.xml
dé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 PMS
l'analyse fastidieuse augmentera naturellement. Le démarrage fastidieux 70%
est entièrement lié PMS
à l'analyse. Si vous le dites 优化开机启动速度
, autant PMS
commencer 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. SystemServer
Il 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.java
dans 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.
ServiceManager
addService()
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 ServiceManager
obtenir 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/app
les /system/app
dossiers, 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é :
- Recherchez le chemin du fichier apk en parcourant
/data/app
un/system/app
dossier ; - 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 ; - 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.
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 :
- Le téléphone s'allume,
内核进程
démarreinit进程
,init进程
démarreSeriviceManager进程
et启动Zygote进程
,Zygote进程
démarreSystemServer
,SystemServer
le processus démarreAMS
,PMS
, et s'enregistre surServiceManager
. PMS
Après avoir étéSystemServer
initialisé, lancez la numérisation/data/app/
et/system/app/
tout sous le répertoireapk文件
, récupérez chaqueapk文件
fichierAndroidManifest.xml
et continuezdom解析
.- L'analyse
AndroidManifest.xml
convertit les informations de données telles que应用信息
,权限
, , etc. dans un cache .四大组件
Java Bean
内存中
- Lorsque
AMS
la récupération est nécessaireapk数据信息
, débrouillez-vousServiceManager
pour vousPMS的Binder代理
débrouillerBinder通信
.
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).