彻底搞懂PMS即PackageManagerService,看这一篇就够了
前言
把一个安卓应用的apk文件下载下来之后,点击它进行安装,然后安装完成后,在桌面上点击它的图标进入app到使用,这个过程相信大家都很熟悉了,那么当点击这个apk进行安装的时候,PMS就开始进行工作,下面将详细讲解它是怎样工作的。
提示:以下是本篇文章正文内容
一、PackageManagerService
简称PMS,当安卓系统要安装某个应用时,apk文件会被加载到/data/app目录下,然后PMS就对该目录下的apk缓存文件进行扫描:
也就是说PMS就会在/data/app目录里对这个apk文件进行解析,apk文件里是有很多文件的,因此要让系统迅速定位到这么多类(四大组件等),就应该有个服务事先把它们的包名路径等信息加载好,这样就可以快速地定位到这些类(比如入口Activity等),而这个服务就是PMS,然后AMS即ActivityManagerService就能根据PMS里面的这些类信息来进行创建入口Activity等四大组件类并启动。
另外,在安卓手机开机时,PMS也会去扫描加载/data/app目录和system/app里每个apk里的所有类信息,然后缓存到PMS它自己里面定义好的集合里,供AMS使用。
PMS加载每个apk(包括系统apk)里的清单文件,然后把里面相应的类(节点)信息进行分类存储。
像上图AndroidManifest.xml清单文件里的节点信息,它是一个xml文件,PMS将这些节点信息缓存起来不用占太多容量,而且节点信息又清晰明了,有了这些信息足以让AMS快速去反射创建类对象,然后进行启动。
PMS使用的是一个工具类PackageParse去解析清单文件的,将里面的节点信息(Activity、Service、provider等)解析出来缓存到PMS里面的一个Package里的不同集合里:
但这里要注意的是,收集Activity信息的集合里的这个Activity类它不是我们平常见到的活动类Activity类,它是Package类里的自己定义的特殊Activity,里面存储的只是清单文件里关于Activity类的一些路径、是否是启动活动等的一些配置信息,因此它不是正常的完整活动类Activity:
上面这些集合就是Package类里对于清单文件里配置的四大组件而定义的缓存集合,这些集合就是用来缓存清单文件里配置的四大组件,但并不是真正的四大组件的类。
每个apk对应一个缓存对象Package,而PMS是一个单独进程,来管理这些Package对象。
之后当用户点击app图标的那一刻,AMS就根据PMS里Package里的这些集合里的类信息以及intent里设置的意图信息,然后定位到要显示的类,创建然后启动它:
AMS从PMS里拿到这个启动类的信息数据之后,就缓存到它自己的ActivityThread里的ActivityClientRecord集合里,也就是跳转记录集合里:
二、SystemServer
SystemServer是管理和启动所有服务的类,PMS和AMS就是它负责管理和启动的。而它自己的启动方法run方法则是在手机开启时就会被调用:
/**
* The main entry point from zygote.
*/
public static void main(String[] args) {
new SystemServer().run();
}
可以看到,它是在main里调用的,而main方法又是被zygote进程调用的,也就是说SystemServer进程是被zygote进程启动的。重新看回SystemServer的run方法,往下看:
...
// Start services.
try {
traceBeginAndSlog("StartServices");
startBootstrapServices();
startCoreServices();
startOtherServices();
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
traceEnd();
}
...
这里面启动了很多服务,看startBootstrapServices()方法:
...
// Activity manager runs the show.
traceBeginAndSlog("StartActivityManager");
// TODO: Might need to move after migration to WM.
ActivityTaskManagerService atm = mSystemServiceManager.startService(
ActivityTaskManagerService.Lifecycle.class).getService();
mActivityManagerService = ActivityManagerService.Lifecycle.startService(
mSystemServiceManager, atm);
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
mWindowManagerGlobalLock = atm.getGlobalLock();
traceEnd();
...
traceBeginAndSlog("StartPackageManagerService");
try {
Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
} finally {
Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
}
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
traceEnd();
...
可以看到,构建了AMS对象也就是mActivityManagerService ,然后启动了AMS,继续往下看就是调用了PackageManagerService的main方法,即启动了PMS,所以我们也可以知道,当开机时,SystemServer会去启动AMS和PMS等这些服务:
而且从run方法来看,这个方法里这么多代码,相信里面也是不少耗时功能的,所以这也是手机开机时比较耗时的原因之一。
如果我们想拿到PMS对象,则可以通过context的getPackageManager()方法,但它返回的是PackageManager抽象对象,因此要调用它的实现对象ContextImpl的实现方法:
@Override
public PackageManager getPackageManager() {
if (mPackageManager != null) {
return mPackageManager;
}
IPackageManager pm = ActivityThread.getPackageManager();
if (pm != null) {
// Doesn't matter if we make more than one instance.
return (mPackageManager = new ApplicationPackageManager(this, pm));
}
return null;
}
可以看到,通过ActivityThread的getPackageManager方法去获取,然后返回的是IPackageManager抽象对象,它是个Binder对象,因为此时我们是在app里使用context去获取PMS,这相当于app进程和SystemServer进程的通信(SystemServer拥有PMS),也就是跨进程间通信,因此要使用Binder机制来进行获取进程对象的:
@UnsupportedAppUsage
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
//Slog.v("PackageManager", "returning cur default = " + sPackageManager);
return sPackageManager;
}
IBinder b = ServiceManager.getService("package");
//Slog.v("PackageManager", "default service binder = " + b);
sPackageManager = IPackageManager.Stub.asInterface(b);
//Slog.v("PackageManager", "default service = " + sPackageManager);
return sPackageManager;
}
既然PMS也是服务,那么我们来看它的main方法:
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// Self-check for initial settings.
PackageManagerServiceCompilerMapping.checkProperties();
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
m.enableSystemUserPackages();
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
return m;
}
先是构造了自己PackageManagerService对象m,然后按照key-value方式存放到ServiceManager里,其实就是缓存,下次再来取PMS对象时,就可以直接按照key方法来取:
所以可以知道ServiceManager存储了很多服务的对象:
App应用就可以去调用ServiceManager去取这些服务对象了,当然取出来的是Binder对象,存的时候则是真实的服务对象。
我们继续看回PMS的main方法里,它构造了自己,因此来看它的构造方法:
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
LockGuard.installLock(mPackages, LockGuard.INDEX_PACKAGES);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "create package manager");
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
if (mSdkVersion <= 0) {
Slog.w(TAG, "**** ro.build.version.sdk not set!");
}
mContext = context;
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
mMetrics = new DisplayMetrics();
mInstaller = installer;
...
代码很长,所以这也解释了为什么手机开机时要花费这么长时间了,我们往下看这段代码:
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
...
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
// Remove disable package settings for updated system apps that were
// removed via an OTA. If the update is no longer present, remove the
// app completely. Otherwise, revoke their system privileges.
...
}
...
}
这里调用了一个scanDirTracedLI()方法,里面有个变量sAppInstallDir,可以看看它是什么:
//Directory where installed applications are stored
private static final File sAppInstallDir =
new File(Environment.getDataDirectory(), "app");
通过注释可以知道,这个sAppInstallDir就是缓存的要安装的应用的路径,也就是安装app时它的apk文件缓存的目录:
DIR_ANDROID_ADTA的值就是data/app目录,刚刚可以看到sAppInstallDir被传到这个scanDirTracedLI方法里,这个方法就是去扫描data/app目录下每个apk方法,而系统app的apk缓存文件(system/app)也是在PMS构造方法里去扫描的:
// Collect ordinary system packages.
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
scanDirTracedLI(systemAppDir,
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM,
0);
而这里的systemAppDir跟踪一下可以知道就是system/app目录:
接下来我们来看看scanDirTracedLI()这个扫描方法的详情:
private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags, long currentTime) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
try {
scanDirLI(scanDir, parseFlags, scanFlags, currentTime);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
它里面调用了scanDirLI(),那么继续跟踪此方法:
private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
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));
}
try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
mParallelPackageParserCallback)) {
// Submit files for parsing in parallel
int fileCount = 0;
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
if (!isPackage) {
// Ignore entries which are not packages
continue;
}
parallelPackageParser.submit(file, parseFlags);
fileCount++;
}
...
}
}
}
可以看到关键代码for循环里遍历每个apk文件,然后判断是否是apk文件才去解析,然后把apk文件传到了parallelPackageParser的submit方法里,来看看这个方法的详情:
public void submit(File scanFile, int parseFlags) {
mService.submit(() -> {
ParseResult pr = new ParseResult();
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parallel parsePackage [" + scanFile + "]");
try {
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
pp.setCacheDir(mCacheDir);
pp.setCallback(mPackageParserCallback);
pr.scanFile = scanFile;
pr.pkg = parsePackage(pp, scanFile, parseFlags);
} catch (Throwable e) {
pr.throwable = e;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
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();
}
});
}
实质上是调用了mService的submit方法,这个mService是一个线程池:
private final ExecutorService mService = ConcurrentUtils.newFixedThreadPool(MAX_THREADS,
"package-parsing-thread", Process.THREAD_PRIORITY_FOREGROUND);
线程核心数为4,也就是说,解析apk其实是启动了一个线程池去解析的:
这是安卓29(10.0)的版本下的解析代码,而以前版本比如6.0-8.0的版本下是没有使用线程池去解析的,直接在扫描方法里解析的:
可以看到,6.0版本的解析过程中就没有启动线程池,而是直接就使用PackageParse去解析了,所以对比10.0系统,谷歌很明显优化了PMS在解析apk文件时的操作,启动了线程池去解析,因此现在新版的安卓手机开机时间会比以前快很多。而9.0和11.0也是启动了线程池去解析的,这里就不展示源码,感兴趣可自行搜索查看。
三、解析
上文parallelPackageParser的submit()里已经知道,里面会使用线程池,然后调用parsePackage()方法,该方法就是进行解析,把清单文件里的类信息都解析成Package对象返回给PMS:
现在来看看parsePackage()方法里的详情:
@VisibleForTesting
protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
int parseFlags) throws PackageParser.PackageParserException {
return packageParser.parsePackage(scanFile, parseFlags, true /* useCaches */);
}
接着跟踪packageParser的parsePackge()方法:
/**
* Equivalent to {@link #parsePackage(File, int, boolean)} with {@code useCaches == false}.
*/
@UnsupportedAppUsage
public Package parsePackage(File packageFile, int flags) throws PackageParserException {
return parsePackage(packageFile, flags, false /* useCaches */);
}
返回的是Package的parsePackage()方法,所以继续跟踪:
public Package parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {
Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;
if (parsed != null) {
return parsed;
}
long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
if (packageFile.isDirectory()) {
parsed = parseClusterPackage(packageFile, flags);
} else {
parsed = parseMonolithicPackage(packageFile, flags);
}
long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
cacheResult(packageFile, flags, parsed);
if (LOG_PARSE_TIMINGS) {
parseTime = cacheTime - parseTime;
cacheTime = SystemClock.uptimeMillis() - cacheTime;
if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) {
Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime
+ "ms, update_cache=" + cacheTime + " ms");
}
}
return parsed;
}
首先就是判断有无缓存useCaches,有则从缓存里直接调用getCachedResult()获取这个解析对象Package,没有缓存则重新解析,这种缓存机制也是9.0之后才有,9.0之前的版本是没有缓存,每次都需重新解析(所以这也是优化解析性能的一个点,感兴趣可自行查看源码对比):
继续往下看解析方法可以看到,里面有个判断packageFile.isDirectory(),如果不是目录,也就是有apk文件的,则调用parseMonolithicPackage(),因此继续看该方法的详情:
@Deprecated
@UnsupportedAppUsage
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
if (mOnlyCoreApps) {
if (!lite.coreApp) {
throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"Not a coreApp: " + apkFile);
}
}
final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
try {
final Package pkg = parseBaseApk(apkFile, assetLoader.getBaseAssetManager(), flags);
pkg.setCodePath(apkFile.getCanonicalPath());
pkg.setUse32bitAbi(lite.use32bitAbi);
return pkg;
} catch (IOException e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to get path: " + apkFile, e);
} finally {
IoUtils.closeQuietly(assetLoader);
}
}
代码虽然有点长,但还是可以看到中间调用了parseBaseApk()方法:
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
String volumeUuid = null;
if (apkPath.startsWith(MNT_EXPAND)) {
final int end = apkPath.indexOf('/', MNT_EXPAND.length());
volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
}
mParseError = PackageManager.INSTALL_SUCCEEDED;
mArchiveSourcePath = apkFile.getAbsolutePath();
if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
XmlResourceParser parser = null;
try {
final int cookie = assets.findCookieForPath(apkPath);
if (cookie == 0) {
throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
"Failed adding asset path: " + apkPath);
}
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
final Resources res = new Resources(assets, mMetrics, null);
final String[] outError = new String[1];
final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
if (pkg == null) {
throw new PackageParserException(mParseError,
apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
}
pkg.setVolumeUuid(volumeUuid);
pkg.setApplicationVolumeUuid(volumeUuid);
pkg.setBaseCodePath(apkPath);
pkg.setSigningDetails(SigningDetails.UNKNOWN);
return pkg;
} catch (PackageParserException e) {
throw e;
} catch (Exception e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to read manifest from " + apkPath, e);
} finally {
IoUtils.closeQuietly(parser);
}
}
看到这里相信大家都能知道,parseBaseApk这个方法就是去解析清单文件AndroidManifest.xml,最终得把解析的节点信息都封装在Package对象,一个apk对应一个Package对象,然后返回给PMS,看看这个Package类:
public final static class Package implements Parcelable {
@UnsupportedAppUsage
public String packageName;
// The package name declared in the manifest as the package can be
// renamed, for example static shared libs use synthetic package names.
public String manifestPackageName;
...
// For now we only support one application per package.
@UnsupportedAppUsage
public ApplicationInfo applicationInfo = new ApplicationInfo();
@UnsupportedAppUsage
public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
@UnsupportedAppUsage
public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
@UnsupportedAppUsage
public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
@UnsupportedAppUsage
public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
@UnsupportedAppUsage
public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
@UnsupportedAppUsage
public final ArrayList<Service> services = new ArrayList<Service>(0);
@UnsupportedAppUsage
public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
@UnsupportedAppUsage
public final ArrayList<String> requestedPermissions = new ArrayList<String>();
...
可以看到,有包名信息,还有权限集合,以及四大组件对应的存储集合,每个集合存放对应的类型(Activity、Service、Provider和PermissionGroup等)。
我们继续看回parseBaseApk()方法:
openXmlResourceParser()方法打开的就是我们的清单文件,也就是解析xml文件的节点信息,最后返回解析对象,然后把解析对象又传到了下面调用的parseBaseApk()方法里:
来看parseBaseApk方法的详情:
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
String[] outError) throws XmlPullParserException, IOException {
final String splitName;
final String pkgName;
...
final Package pkg = new Package(pkgName);
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifest);
pkg.mVersionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
pkg.mVersionCodeMajor = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_versionCodeMajor, 0);
pkg.applicationInfo.setVersionCode(pkg.getLongVersionCode());
pkg.baseRevisionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
pkg.mVersionName = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_versionName, 0);
if (pkg.mVersionName != null) {
pkg.mVersionName = pkg.mVersionName.intern();
}
pkg.coreApp = parser.getAttributeBooleanValue(null, "coreApp", false);
pkg.mCompileSdkVersion = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_compileSdkVersion, 0);
pkg.applicationInfo.compileSdkVersion = pkg.mCompileSdkVersion;
pkg.mCompileSdkVersionCodename = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_compileSdkVersionCodename, 0);
if (pkg.mCompileSdkVersionCodename != null) {
pkg.mCompileSdkVersionCodename = pkg.mCompileSdkVersionCodename.intern();
}
pkg.applicationInfo.compileSdkVersionCodename = pkg.mCompileSdkVersionCodename;
sa.recycle();
return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
}
该方法是为了获取到app的版本号等信息(清单文件里定义的sdkVersion等),最后返回parseBaseApkCommon()方法:
private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
IOException {
...
int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (acceptedTags != null && !acceptedTags.contains(tagName)) {
Slog.w(TAG, "Skipping unsupported element under <manifest>: "
+ tagName + " at " + mArchiveSourcePath + " "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
if (tagName.equals(TAG_APPLICATION)) {
if (foundApp) {
if (RIGID_PARSER) {
outError[0] = "<manifest> has more than one <application>";
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
} else {
Slog.w(TAG, "<manifest> has more than one <application>");
XmlUtils.skipCurrentTag(parser);
continue;
}
}
foundApp = true;
if (!parseBaseApplication(pkg, res, parser, flags, outError)) {
return null;
}
}
...
else if (tagName.equals(TAG_PERMISSION_GROUP)) {
if (!parsePermissionGroup(pkg, flags, res, parser, outError)) {
return null;
}
} else if (tagName.equals(TAG_PERMISSION)) {
if (!parsePermission(pkg, res, parser, outError)) {
return null;
}
}
...
}
可以看到关键的代码,while循环里获取清单文件AndroidManifest.xml里每个节点,对不同的节点进行相应的解析方法,我们可以来看看其中一个方法,比如parseBaseApplication():
private boolean parseBaseApplication(Package owner, Resources res,
XmlResourceParser parser, int flags, String[] outError)
throws XmlPullParserException, IOException {
final ApplicationInfo ai = owner.applicationInfo;
final String pkgName = owner.applicationInfo.packageName;
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifestApplication);
...
String tagName = parser.getName();
if (tagName.equals("activity")) {
Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
owner.baseHardwareAccelerated);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
hasActivityOrder |= (a.order != 0);
owner.activities.add(a);
} else if (tagName.equals("receiver")) {
Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
true, false);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
hasReceiverOrder |= (a.order != 0);
owner.receivers.add(a);
} else if (tagName.equals("service")) {
Service s = parseService(owner, res, parser, flags, outError, cachedArgs);
if (s == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
hasServiceOrder |= (s.order != 0);
owner.services.add(s);
} else if (tagName.equals("provider")) {
Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs);
if (p == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.providers.add(p);
}
可以看到,分别对清单文件里application节点里的元素activity节点和service节点等进行解析与创建,创建的是Package它自己的Activity类和Service类,这些类跟我们平时见到的Activity类和Service类是不同的,是PMS的自定义的内部类,用来存储清单文件里我们设置的类的信息,用相应的集合来存储,最后供AMS创建真正的类时用的。
public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable {
@UnsupportedAppUsage
public final ActivityInfo info;
private boolean mHasMaxAspectRatio;
private boolean mHasMinAspectRatio;
private boolean hasMaxAspectRatio() {
return mHasMaxAspectRatio;
}
private boolean hasMinAspectRatio() {
return mHasMinAspectRatio;
}
// To construct custom activity which does not exist in manifest
Activity(final Package owner, final String className, final ActivityInfo info) {
super(owner, new ArrayList<>(0), className);
this.info = info;
this.info.applicationInfo = owner.applicationInfo;
}
...
}
不过这里要注意的是,解析广播组件的时候,用的也是Activity来构造,那是因为广播和Activity在清单文件里设置的时候很像,因此这里也是处于方便的考虑,把广播也认作是Activity。
最后解析出来的Activity对象都被添加到Package里对应的集合里:
也就是这些集合:
@UnsupportedAppUsage
public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
@UnsupportedAppUsage
public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
@UnsupportedAppUsage
public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
@UnsupportedAppUsage
public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
@UnsupportedAppUsage
public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
@UnsupportedAppUsage
public final ArrayList<Service> services = new ArrayList<Service>(0);
@UnsupportedAppUsage
public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
我们再来看看parseActivity()方法:
private Activity parseActivity(Package owner, Resources res,
XmlResourceParser parser, int flags, String[] outError, CachedComponentArgs cachedArgs,
boolean receiver, boolean hardwareAccelerated)
throws XmlPullParserException, IOException {
...
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
if (parser.getName().equals("intent-filter")) {
ActivityIntentInfo intent = new ActivityIntentInfo(a);
if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/,
intent, outError)) {
return null;
}
if (intent.countActions() == 0) {
Slog.w(TAG, "No actions in intent filter at "
+ mArchiveSourcePath + " "
+ parser.getPositionDescription());
} else {
a.order = Math.max(intent.getOrder(), a.order);
a.intents.add(intent);
}
...
}
...
可以该方法里解析activity节点时,也会遍历activity节点里的子节点,即解析清单文件里面的比如activity节点里的intent-filter信息,把ActivityIntentInfo对象intent解析出来然后放进Activity的intents集合里,这个intents集合是Component类里的II集合(Activity继承Component):
public static abstract class Component<II extends IntentInfo> {
@UnsupportedAppUsage
public final ArrayList<II> intents;
@UnsupportedAppUsage
public final String className;
@UnsupportedAppUsage
public Bundle metaData;
@UnsupportedAppUsage
public Package owner;
/** The order of this component in relation to its peers */
public int order;
ComponentName componentName;
String componentShortName;
...
四、总结
相信经过上面的讲解之后,大家都会对PMS有了更深的理解了,而且在开发过程中,我们自己也可以通过PMS去做一些事情,既然通过源码知道了PMS是通过scanDirTracedLI()方法去扫描apk文件里的清单文件,然后把里面的类等信息解析成一个Package对象(通过PackageParser的parsePackage()方法所得),那我们也可以通过反射对应的方法去对一些特定的apk文件进行扫描和解析,然后根据Package对象获取到里面的类信息,去创建我们需要的四大组件类,从而达到我们的app和其他apk进行通信的目的了。还有很多这些类似的应用场景也是可以利用PMS去完成的。