1 Introduction to PMS
PMS(PackageManagerService)
Is provided by Android 包管理系统服务
, it is used to manage all 包信息
, including 应用安装
, 卸载
, 更新
and解析AndroidManifest.xml
. By parsing each installed application AndroidManifest.xml
, all the data in the xml is saved, and the data required by AMS is subsequently provided. It is a cache that saves application data.
We all know that AndroidManifest.xml
it defines all the information in the apk 四大组件
, 权限
etc., it is a definition file. The most important thing for PMS to analyze the apk is to 扫描/data/app和/system/app目录下的apk文件
find the apk package AndroidManifest.xml
, and then 解析AndroidManifest.xml的信息保存到系统内存中
, when AMS needs application data, it can find PMS and quickly get relevant information from the memory.
We know that the more apps installed on an Android device, the slower it will start up. The reason is that if there are more applications installed, PMS
the time-consuming analysis will naturally increase. The time-consuming start-up 70%
is all about PMS
the analysis. If you say it 优化开机启动速度
, you might as well PMS
start with it.
This article is based on Android10(Q)
the source code analysis
2 PMS start
All core services in the Android system will be started SystemServer
, and PMS is no exception. SystemServer
It will start and run when the phone is turned on. About how SystemServer is started, you can check the article [Android Framework Series] Chapter 3 Zygote Process Related and [Android Vehicle Series] Chapter 10 System Services - SystemServer Source Code Analysis (API28)
We know that PMS is started in the SystemServer process, let's take a look at how to start 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进程
Call the method SystemServer.java
in the class main()
, the method run()
in the method startBootstrapServices()
initializes the core services such as PMS, calls its main()
method to create the corresponding service, and adds the PMS service to it ServiceManager
(AMS is also the same operation) for service management.
ServiceManager
addService()
Only the method and method are provided getService()
. When app进程
you need to obtain the corresponding data 系统服务
, you will use the proxy to ServiceManager
obtain the corresponding service and use Binder communication to obtain data.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 PMS Analysis
PMS analysis mainly does three things:
1. 遍历/data/app和/system/app文件夹,找到apk文件
2. 解压apk文件
3. dom解析AndroidManifest.xml文件,将xml信息存储起来提供给AMS使用
3.1 Traversing the /data/app folder
/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 }
We see here traversing /data/app
and /system/app
folders, finding the apk file, and then submit()
analyzing the apk through the method. Let's continue to look at submit()
the method
3.2 Unzip the apk file
/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 }
Pass the apk file path found above into the PackageParser object parsePackage()
to parse the apk. It should be noted here: the parsing methods are different in different system source code versions. The way to start parsing in versions 6.0, 7.0, and 8.0 is still direct parsing, but in 10.0版本开始使用线程池放到子线程去解析,加快了手机启动速度
.
3.3 dom parsing AndroidManifest.xml file
/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 }
The three-step process of parsing here has been completed:
- Find the apk file path by traversing
/data/app
or/system/app
folder; - The method of passing the found path into the PackageParser object
parsePackage()
performs dom analysis on the AndroidManifest.xml of the apk; - Then parse the information according to different tags and store it in the corresponding field of the Package class and cache it in the memory, such as: four major components, permissions and other information. It is convenient for subsequent AMS to obtain and use directly from the Package cache of PMS.
4 Summary
Let's briefly summarize the PMS:
PMS is 包管理系统服务
used to manage all 包信息
, including 应用安装
, 卸载
, 更新
and 解析AndroidManifest.xml
. After the mobile phone is turned on, it will traverse all the devices /data/app/
and /system/app/
directories apk文件
, and by parsing all installed applications , the data ( , , etc.) information AndroidManifest.xml
in the xml will be cached in the memory, and then provided to other services.应用信息
权限
四大组件
AMS
The overall process of PMS:
- The phone turns on,
内核进程
startsinit进程
,init进程
startsSeriviceManager进程
and启动Zygote进程
,Zygote进程
startsSystemServer
,SystemServer
the process startsAMS
,PMS
, and registers toServiceManager
. PMS
After beingSystemServer
initialized, start scanning/data/app/
and/system/app/
all under the directoryapk文件
, get eachapk文件
fileAndroidManifest.xml
, and proceeddom解析
.- Parsing
AndroidManifest.xml
converts data information such as应用信息
,权限
, , etc. into a cache .四大组件
Java Bean
内存中
- When
AMS
fetch is neededapk数据信息
, get by getServiceManager
to getPMS的Binder代理
byBinder通信
.
5 interview questions
1 What does PMS do, how do you understand PMS
Package management, package parsing, result caching, and query interfaces are provided.
1. 遍历/data/app和/system/app文件夹,找到apk文件
2. 解压apk文件
3. dom解析AndroidManifest.xml文件,将xml信息存储起来提供给AMS使用
2 What is the use of being familiar with PMS source code
1. Help understand the principles of the Android package management system
2. Cooperate with AMS through Hook technology to realize hot update, plug-in and other functions.
For example, we can obtain the PackageParser object through reflection, and then call its parsePackage() to pass in the apk path to complete the parsing to obtain the Package object, and then reflect the activities, providers, receivers, and services variables of the PMS to add the data we parsed into it , so that dynamic loading is realized (no need to add information in the AndroidManifest.xml file).