本文基于Android 10源码分析
前言
PackageManagerService(简称PKMS),是Android系统中核心服务之一,管理着所有与package相关的工作,常见的比如安装、卸载应用, 信息查询等工作,主要完成以下核心功能:
-
解析AndroidManifest.xml清单文件,解析清单文件中的所有节点信息;
-
扫描本地文件,主要针对apk,主要是系统应用、本地安装应用等;
-
管理本地apk,主要包括安装、删除等等;
-
管理设备上安装的所有应用程序,并在系统启动时加载应用程序;
-
根据请求的Intent匹配到对应的Activity、Provider、Service,提供包含包名和Component的信息对象;
-
调用需要权限的系统函数时,检查程序是否具备相应权限从而保证系统安全;
-
提供应用程序的安装、卸载的接口。
本篇文章重点介绍一下apk的扫描过程。
1.扫描流程
在上一篇文章介绍了PKMS的构造函数中调用了scanDirTracedLI方法来扫描某个目录的apk文件,在Android 10上扫描的目录有:
/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
(1)这里就从scanDirTracedLI()方法为入口来分析:
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
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);
}
}
(2)接着调用到PKMS的scanDirLI方法
scanDirLI()中使用了ParallelPackageParser的对象,ParallelPackageParser是一个队列,保存手机所有系统的apk,然后从这些队列里面取出apk,再调用PackageParser 解析进行解析。
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
final File[] files = scanDir.listFiles();
...
//parallelPackageParser是一个队列,收集系统apk文件,
//然后从这个队列里面一个个取出apk调用PackageParser解析
try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
mParallelPackageParserCallback)) {
// 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文件,如果不是则跳过继续扫描
if (!isPackage) {
// Ignore entries which are not packages
continue;
}
//把APK信息存入parallelPackageParser中的对象mQueue,
//PackageParser()函数赋给了队列中的pkg成员
parallelPackageParser.submit(file, parseFlags);
fileCount++;
}
// Process results one by one
//从parallelPackageParser中取出队列apk的信息
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.pkg.applicationInfo.isStaticSharedLibrary()) {
renameStaticSharedLibraryPackage(parseResult.pkg);
}
//调用scanPackageChildLI方法扫描一个特定的apk文件
//该类的实例代表一个APK文件,所以它就是和apk文件对应的数据结构。
try {
scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
currentTime, null);
} catch (PackageManagerException e) {
errorCode = e.error;
Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
}
} else if (throwable instanceof PackageParser.PackageParserException) {
PackageParser.PackageParserException e = (PackageParser.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);
}
// Delete invalid userdata apps
//如果是非系统apk并且解析失败
if ((scanFlags & SCAN_AS_SYSTEM) == 0 &&
errorCode != PackageManager.INSTALL_SUCCEEDED) {
logCriticalInfo(Log.WARN,
"Deleting invalid package at " + parseResult.scanFile);
//非系统Package扫描失败,删除文件
removeCodePathLI(parseResult.scanFile);
}
}
}
}
(3)时序图
PKMS03.png1.1 parallelPackageParser.submit()
继续分析parallelPackageParser.submit(file, parseFlags)这个方法,把扫描路径中的APK等内容,放入队列mQueue,并把parsePackage()赋给ParseResult,用于后面的调用。
// frameworks/base/services/core/java/com/android/server/pm/ParallelPackageParser.java
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;
//这个方法获取PackageParser.Package对象
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();
}
});
}
(1)通过parsePackage进行apk解析,如果传入的packageFile是目录,调用parseClusterPackage()解析,如果传入的是APK文件,就调用parseMonolithicPackage()解析。
// frameworks/base/core/java/android/content/pm/PackageParser.java
public Package parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserExceparseClusterPackageption {
....
if (packageFile.isDirectory()) {
// 解析目录
parsed = parseClusterPackage(packageFile, flags);
} else {
// 解析APK
parsed = parseMonolithicPackage(packageFile, flags);
}
....
}
(2)先来看看parseClusterPackage()方法
作用:解析给定目录中包含的所有apk,将它们视为单个包。这还可以执行完整性检查,比如需要相同的包名和版本代码、单个基本APK和唯一的拆分名称。
首先通过parseClusterPackageLite()对目录下的apk文件进行初步分析,主要区别是核心应用还是非核心应用。核心应用只有一个,非核心应用可以没有,或者多个,非核心应用的作用主要用来保存资源和代码。然后对核心应用调用parseBaseApk分析并生成Package。对非核心应用调用parseSplitApk,分析结果放在前面的Package对象中。
// frameworks/base/core/java/android/content/pm/PackageParser.java
private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
//获取应用目录的PackageLite对象,这个对象分开保存了目录下的核心应用以及非核心应用的名称
final PackageLite lite = parseClusterPackageLite(packageDir, 0);
//如果lite中没有核心应用,退出
if (mOnlyCoreApps && !lite.coreApp) {
throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"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) {
throw new PackageParserException(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);
//对核心应用解析
final Package pkg = parseBaseApk(baseApk, assets, flags);
if (pkg == null) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
"Failed to parse base APK: " + baseApk);
}
if (!ArrayUtils.isEmpty(lite.splitNames)) {
final int num = lite.splitNames.length;
pkg.splitNames = lite.splitNames;
pkg.splitCodePaths = lite.splitCodePaths;
pkg.splitRevisionCodes = lite.splitRevisionCodes;
pkg.splitFlags = new int[num];
pkg.splitPrivateFlags = new int[num];
pkg.applicationInfo.splitNames = pkg.splitNames;
pkg.applicationInfo.splitDependencies = splitDependencies;
pkg.applicationInfo.splitClassLoaderNames = new String[num];
for (int i = 0; i < num; i++) {
final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
//对非核心应用的处理
parseSplitApk(pkg, i, splitAssets, flags);
}
}
pkg.setCodePath(packageDir.getCanonicalPath());
pkg.setUse32bitAbi(lite.use32bitAbi);
return pkg;
} catch (IOException e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to get path: " + lite.baseCodePath, e);
} finally {
IoUtils.closeQuietly(assetLoader);
}
}
(3)再看parseMonolithicPackage(),它的作用是解析给定的APK文件,将其作为单个单块包处理。
最终也是调用parseBaseApk()进行解析,我们接下来看下parseBaseApk():
// frameworks/base/core/java/android/content/pm/PackageParser.java
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 {
// 对核心应用解析
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);
}
}
(4)parseBaseApk()主要是对AndroidManifest.xml进行解析,解析后所有的信息放在Package对象中:
// frameworks/base/core/java/android/content/pm/PackageParser.java
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
...
XmlResourceParser parser = null;
...
final int cookie = assets.findCookieForPath(apkPath);
if (cookie == 0) {
throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
"Failed adding asset path: " + apkPath);
}
//获得一个XML资源解析对象,该对象解析的是APK中的AndroidManifest.xml文件。
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
final Resources res = new Resources(assets, mMetrics, null);
final String[] outError = new String[1];
//再调用重载函数parseBaseApk()最终到parseBaseApkCommon(),
//解析AndroidManifest.xml后得到一个Package对象
final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
...
pkg.setVolumeUuid(volumeUuid);
pkg.setApplicationVolumeUuid(volumeUuid);
pkg.setBaseCodePath(apkPath);
pkg.setSigningDetails(SigningDetails.UNKNOWN);
return pkg;
...
}
(5)从AndroidManifest.xml中获取标签名,解析标签中的各个item的内容,存入Package对象中,例如获取标签"application"、"permission"。
// frameworks/base/core/java/android/content/pm/PackageParser.java
private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
IOException {
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifest);
//拿到AndroidManifest.xml 中的sharedUserId, 一般情况下有“android.uid.system”等信息
String str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
//从AndroidManifest.xml中获取标签名
String tagName = parser.getName();
//如果读到AndroidManifest.xml中的tag是"application",执行parseBaseApplication()进行解析
if (tagName.equals(TAG_APPLICATION)) {
if (foundApp) {
...
}
foundApp = true;
//解析"application"的信息,赋值给pkg
if (!parseBaseApplication(pkg, res, parser, flags, outError)) {
return null;
}
...
//如果标签是"permission"
else if (tagName.equals(TAG_PERMISSION)) {
//进行"permission"的解析
if (!parsePermission(pkg, res, parser, outError)) {
return null;
}
....
}
}
}
}
(6)上面解析AndroidManifest.xml,会得到"application"、"overlay"、"permission"、"uses-permission"等信息,下面就针对"application"进行展开分析一下,进入parseBaseApplication()函数。
// frameworks/base/core/java/android/content/pm/PackageParser.java
private boolean parseBaseApplication(Package owner, Resources res,
XmlResourceParser parser, int flags, String[] outError)
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
//获取"application"子标签的标签内容
String tagName = parser.getName();
//如果标签是"activity"
if (tagName.equals("activity")) {
//解析Activity的信息,把activity加入Package对象
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")) {
//如果标签是"receiver",获取receiver信息,加入Package对象
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",获取service信息,加入Package对象
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",获取provider信息,加入Package对象
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);
}
...
}
}
关于如何使用 XmlPullParser来解析xml文件,请参考: Android XML文件结构 和 用XmlPullParser 来解析xml文件
在PackageParser扫描完一个APK后,此时系统已经根据该APK中AndroidManifest.xml,创建了一个完整的 Package对象。
1.2 scanPackageChildLI()
回到《1.扫描流程》中,scanDirLI()方法调用到scanPackageChildLI()。调用addForInitLI()在platform初始化时,把Package内容加入到内部数据结构。
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private PackageParser.Package scanPackageChildLI(PackageParser.Package pkg,
final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user)
throws PackageManagerException {
...
// Scan the parent
PackageParser.Package scannedPkg = addForInitLI(pkg, parseFlags,
scanFlags, currentTime, user);
// Scan the children
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPackage = pkg.childPackages.get(i);
//在平台初始化期间向内部数据结构添加新包,
//在platform初始化时,把Package内容加入到内部数据结构。
addForInitLI(childPackage, parseFlags, scanFlags,
currentTime, user);
}
if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
}
}
(1)在addForInitLI()中,进行安装包校验、签名检查、apk更新等操作,把Package加入系统
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private PackageParser.Package addForInitLI(PackageParser.Package pkg,
@ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user)
throws PackageManagerException {
// 判断系统应用是否需要更新
synchronized (mPackages) {
// 更新子应用
if (isSystemPkgUpdated) {
...
}
if (isSystemPkgBetter) {
// 更新安装包到system分区中
synchronized (mPackages) {
// just remove the loaded entries from package lists
mPackages.remove(pkgSetting.name);
}
...
// 创建安装参数InstallArgs
final InstallArgs args = createInstallArgsForExisting(
pkgSetting.codePathString,
pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
args.cleanUpResourcesLI();
synchronized (mPackages) {
mSettings.enableSystemPackageLPw(pkgSetting.name);
}
}
// 安装包校验
collectCertificatesLI(pkgSetting, pkg, forceCollect, skipVerify);
...
try (PackageFreezer freezer = freezePackage(pkg.packageName,
"scanPackageInternalLI")) {
// 如果两个apk签名不匹配,则调用deletePackageLIF方法清除apk文件及其数据
deletePackageLIF(pkg.packageName, null, true, null, 0, null, false, null);
}
...
// 更新系统apk程序
InstallArgs args = createInstallArgsForExisting(
pkgSetting.codePathString,
pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
}
// 如果新安装的系统APP会被旧的APP数据覆盖,所以需要隐藏隐藏系统应用程序,
//并重新扫描data/app目录
if (shouldHideSystemApp) {
synchronized (mPackages) {
mSettings.disableSystemPackageLPw(pkg.packageName, true);
}
}
}
2.总结
回顾一下整个APK的扫描过程:
-
按照core app > system app > other app优先级扫描APK,解析AndroidManifest.xml文件,得到各个标签内容;
-
解析XML文件得到的信息由Package保存。从该类的成员变量可看出,和 Android 四大组件相关的信息分别由 activites、receivers、providers、services 保存。由于一个APK可声明多个组件,因此activites和receivers等均声明为ArrayList。
-
在PackageParser扫描完一个APK后,此时系统已经根据该APK中AndroidManifest.xml,创建了一个完整的 Package对象,下一步就是将该Package加入到系统中;
-
非系统Package扫描失败,删除文件。
网友评论