四、三步曲 - APK的扫描:
a、PKMS的构造函数中调用了 scanDirTracedLI方法 来扫描某个目录的apk文件,8.1,MT6737芯片包含apk文件的目录
/vendor/overlay 系统的APP类别
/system/framework 系统的APP类别
/system/priv-app 系统的APP类别
/system/app 系统的APP类别
/vendor/app 系统的APP类别
/oem/app 系统的APP类别
b、APK的扫描,整体描述图:
c、PKMS.scanDirTracedLi:首先加入了一些systtrace的日志追踪,然后调用【scanDirLI()】进行分析
public void scanDirTracedLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + dir.getAbsolutePath() + "]");
try {
// 调用此 scanDirLI 函数
scanDirLI(dir, parseFlags, scanFlags, currentTime);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
d、PKMS.scanDirLI: 使用了【ParallelPackageParser】的对象,ParallelPackageParser是【一个阻塞队列】,存储手机系统的所有apk,然后从这些队列里面取出apk,再调用【PackageParser】解析进行解析:
private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
final File[] files = dir.listFiles();
//判断数组中是否有元素
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, "No files in app dir " + dir);
return;
}
if (DEBUG_PACKAGE_SCANNING) {
Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags
+ " flags=0x" + Integer.toHexString(parseFlags));
}
// parallelPackageParser是一个队列,收集系统 apk 文件,
// 然后从这个队列里面一个个取出 apk ,调用 PackageParser 解析
ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
mParallelPackageParserCallback);
// 提交并行解析的文件任务
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成员
// 这里的 submit 函数 很重要,下面就会分析此函数
parallelPackageParser.submit(file, parseFlags);
fileCount++;
}
// Process results one by one
for (; fileCount > 0; fileCount--) {
// 从 parallelPackageParser 中取出队列apk的信息
ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
Throwable throwable = parseResult.throwable;
int errorCode = PackageManager.INSTALL_SUCCEEDED;
if (throwable == null) {
// Static shared libraries have synthetic package names
if (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) {
renameStaticSharedLibraryPackage(parseResult.pkg);
}
try {
if (errorCode == PackageManager.INSTALL_SUCCEEDED) {
// 调用 scanPackageChildLI 方法扫描一个特定的 apk 文件
// 该类的实例代表一个 APK 文件,所以它就是和 apk 文件对应的数据结构。
scanPackageLI(parseResult.pkg, parseResult.scanFile, 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 ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
errorCode == PackageManager.INSTALL_FAILED_INVALID_APK) {
logCriticalInfo(Log.WARN,
"Deleting invalid package at " + parseResult.scanFile);
removeCodePathLI(parseResult.scanFile);
}
}
// 关闭线程池
parallelPackageParser.close();
}
e、【ParallelPackageParser.submit】 : 把扫描路径中的APK等内容,放入【队列mQueue】,并把【parsePackage()】 pp 赋给ParseResult,用于后面的调用
private static final int QUEUE_CAPACITY = 10;
private static final int MAX_THREADS = 4;
// 阻塞队列,队列的初始容量为10,后续可以扩展
private final BlockingQueue<ParseResult> mQueue = new ArrayBlockingQueue<>(QUEUE_CAPACITY);
// 四个核心线程的线程池
private final ExecutorService mService = ConcurrentUtils.newFixedThreadPool(MAX_THREADS,
"package-parsing-thread", Process.THREAD_PRIORITY_FOREGROUND);
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;
// 并把parsePackage()与 pp 赋值ParseResult,用于后面的调用
pr.pkg = parsePackage(pp, scanFile, parseFlags);
// 【注意】parsePackage下面会分析
} catch (Throwable e) {
pr.throwable = e;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
// 把扫描路径中的APK等内容,放入队列mQueue,可以提交很多个,而不会阻塞
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();
}
});
}
f、通过 【PackageParser.parsePackage】 进行apk解析:如果传入的packageFile是目录, 调用【parseClusterPackage()】解析;如果传入的packageFile是APK文件, 调用【parseMonolithicPackage()】解析
public Package parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {
Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;
......
if (packageFile.isDirectory()) {
//如果传入的packageFile是目录,调用parseClusterPackage()解析
parsed = parseClusterPackage(packageFile, flags);
} else {
//如果是APK文件,就调用parseMonolithicPackage()解析
parsed = parseMonolithicPackage(packageFile, flags);
}
......
return parsed;
}
g、【PackageParser.parseMonolithicPackage()】函数,它的作用是【解析给定的APK文件】,将其【作为单个模块包】处理,最终调用【parseBaseApk()】进行解析
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
final AssetManager assets = newConfiguredAssetManager();
final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
......
try {
// 对核心应用解析 【注意】 最终调用 parseBaseApk()进行解析,我们下面来分析
final Package pkg = parseBaseApk(apkFile, assets, flags);
// 设置代码路径
pkg.setCodePath(apkFile.getAbsolutePath());
// 设置apk的32位或者64位库文件
pkg.setUse32bitAbi(lite.use32bitAbi);
return pkg;
} finally {
IoUtils.closeQuietly(assets);
}
}
h、【PackageParser.parseBaseApk()】主要是对【AndroidManifest.xml】进行解析,解析后所有的信息放在
【Package对象】中
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
throws PackageParserException {
// 获取apk的绝对路径
final String apkPath = apkFile.getAbsolutePath();
String volumeUuid = null;
// 判断路径是否以"/mnt/expand/"开头
if (apkPath.startsWith(MNT_EXPAND)) {
// 获取磁盘的uuid
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);
// 将apk加载到资源管理起中,返回一个资源id,对应着一个apk,
// cookie是apk在资源管理中的一个识别码
final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
Resources res = null;
XmlResourceParser parser = null;
try {
res = new Resources(assets, mMetrics, null);
// 获得一个 XML 资源解析对象,该对象解析的是 APK 中的 AndroidManifest.xml 文件
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
final String[] outError = new String[1];
// 【注意】解析后所有的信息放在Package对象中
final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
if (pkg == null) {
throw new PackageParserException(mParseError,
apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
}
//设置uuid
pkg.setVolumeUuid(volumeUuid);
pkg.setApplicationVolumeUuid(volumeUuid);
// 设置apk代码的路径
pkg.setBaseCodePath(apkPath);
// 设置签名为空
pkg.setSignatures(null);
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);
}
}
i、【PackageParser.parseBaseApk】函数,解析apk的解析manifest节点的属性值,版本号,包名版本名称都在这个函数中解析
private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
String[] outError) throws XmlPullParserException, IOException {
final String splitName;
final String pkgName;
try {
// 解析清单文件中的包名
Pair<String, String> packageSplit = parsePackageSplitNames(parser, parser);
pkgName = packageSplit.first;
splitName = packageSplit.second;
if (!TextUtils.isEmpty(splitName)) {
outError[0] = "Expected base APK, but found split " + splitName;
mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
return null;
}
} catch (PackageParserException e) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
return null;
}
if (mCallback != null) {//添加overlay的路径
String[] overlayPaths = mCallback.getOverlayPaths(pkgName, apkPath);
if (overlayPaths != null && overlayPaths.length > 0) {
for (String overlayPath : overlayPaths) {
res.getAssets().addOverlayPath(overlayPath);
}
}
}
// 新建一个Package包的对象,所有与APK相关的数据都保存在这里
final Package pkg = new Package(pkgName);
// 这里主要是解析 manifest 节点的属性,不是内容
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifest);
// 获取versioncode
pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
// 获取revisionCode
pkg.baseRevisionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
// 获取versionName
pkg.mVersionName = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_versionName, 0);
// 判断版本名称是否不为空,不为空,则赋值
if (pkg.mVersionName != null) {
pkg.mVersionName = pkg.mVersionName.intern();
}
// 判断是否为核心应用,通过获取coreApp属性
pkg.coreApp = parser.getAttributeBooleanValue(null, "coreApp", false);
sa.recycle();
// 继续调用parseBaseApkCommon解析manifest节点
return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
}
j、【PackageParser.parseBaseApkCommon】 从【AndroidManifest.xml】中获取标签名,解析标签中的各个item的内容,存入【Package对象】中;例如:获取标签 "application"、"permission"、"package"、"manifest"
这个函数500多行;
private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
IOException {
mParseInstrumentationArgs = null;
int type;
boolean foundApp = false;
// 获取 "manifest" 标签
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifest);
// 获取 android:sharedUserId 的值
String str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
if (str != null && str.length() > 0) {
// 带有 不允许是安装的apk
if ((flags & PARSE_IS_EPHEMERAL) != 0) {
outError[0] = "sharedUserId not allowed in ephemeral application";
mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
return null;
}
// 不是运行是“android”
String nameError = validateName(str, true, false);
if (nameError != null && !"android".equals(pkg.packageName)) {
outError[0] = "<manifest> specifies bad sharedUserId name \""
+ str + "\": " + nameError;
mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
return null;
}
// 拷贝一份数据
pkg.mSharedUserId = str.intern();
// 获取 android:sharedUserLabel 的值
pkg.mSharedUserLabel = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
}
// 获取 android:installLocation 的值
pkg.installLocation = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_installLocation,
PARSE_DEFAULT_INSTALL_LOCATION);
pkg.applicationInfo.installLocation = pkg.installLocation;
// 获取 android:targetSandboxVersion 的值
final int targetSandboxVersion = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_targetSandboxVersion,
PARSE_DEFAULT_TARGET_SANDBOX);
// 放入到pkg对象中
pkg.applicationInfo.targetSandboxVersion = targetSandboxVersion;
/* Set the global "forward lock" flag */
if ((flags & PARSE_FORWARD_LOCK) != 0) {
pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
}
/* Set the global "on SD card" flag */
if ((flags & PARSE_EXTERNAL_STORAGE) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
}
// android:isolatedSplits
if (sa.getBoolean(com.android.internal.R.styleable.AndroidManifest_isolatedSplits, false)) {
pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING;
}
// Resource boolean are -1, so 1 means we don't know the value.
int supportsSmallScreens = 1;
int supportsNormalScreens = 1;
int supportsLargeScreens = 1;
int supportsXLargeScreens = 1;
int resizeable = 1;
int anyDensity = 1;
// 获取标签的深度
int outerDepth = parser.getDepth();
// while循环的条件,没有达到xml文件的尾部,第二,不是结束标签,或者深度大于外部的深度
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();
// acceptedTags 这个值为null
if (acceptedTags != null && !acceptedTags.contains(tagName)) {
Slog.w(TAG, "Skipping unsupported element under <manifest>: "
+ tagName + " at " + mArchiveSourcePath + " "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
// 判断标签 "application"
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;
// 解析 "application"的属性,以为这个为例子,四大组件都在这个里面
if (!parseBaseApplication(pkg, res, parser, flags, outError)) {
return null;
}
} else if (tagName.equals(TAG_OVERLAY)) {//标签"overlay"
........省略很多代码
return pkg;
}
上面解析AndroidManifest.xml,会得到 "application"、"overlay"、"permission"、"usespermission" 等信息
k、【PackageParse.parseBaseApplication】函数,解析"application"标签;这个方法也有500多行;
针对"application"进行展开分析一下,进入 PackageParser.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);
// 解析 application 标签的属性值
if (!parsePackageItemInfo(owner, ai, outError,
"<application>", sa, false /*nameRequired*/,
com.android.internal.R.styleable.AndroidManifestApplication_name,
com.android.internal.R.styleable.AndroidManifestApplication_label,
com.android.internal.R.styleable.AndroidManifestApplication_icon,
com.android.internal.R.styleable.AndroidManifestApplication_roundIcon,
com.android.internal.R.styleable.AndroidManifestApplication_logo,
com.android.internal.R.styleable.AndroidManifestApplication_banner)) {
sa.recycle();
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
// 如果自定义的Application类,不为空,则需要将这个类赋值给ApplicationInfo体会系统的类
if (ai.name != null) {//"android:name"属性值
ai.className = ai.name;
}
........省略
//上面的代码都是用来解析 application 标签的属性值
// 下面正式进入 application 标签的内容解析
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (tagName.equals("activity")) {//解析activity
......
} else if (tagName.equals("receiver")) {//解析receiver
......
} else if (tagName.equals("service")) {//解析service
......
} else if (tagName.equals("provider")) {//解析provider
......
} else if (tagName.equals("activity-alias")) {//解析activity-alias
......
} else if (parser.getName().equals("meta-data")) {//解析meta-data
......
} else if (tagName.equals("static-library")) {//解析static-library
......
} else if (tagName.equals("library")) {//解析library
......
} else if (tagName.equals("uses-static-library")) {//解析uses-static-library
......
} else if (tagName.equals("uses-library")) {//解析uses-library"
......
} else if (tagName.equals("uses-package")) {//解析uses-package
......
} else {
......
}
}
......
return true;
}
l、在 PackageParser 扫描完一个 APK 后,此时系统已经根据该 APK 中 AndroidManifest.xml,创建了一个完整的 Package 对象
m、APK的扫描,自我总结:
第一步:扫描APK,解析AndroidManifest.xml文件,得到清单文件各个标签内容
第二步:解析清单文件到的信息由 Package 保存。从该类的成员变量可看出,和 Android 四大组件相关的信息分别由 activites、receivers、providers、services 保存,由于一个 APK 可声明多个组件,因此activites 和 receivers等均声明为 ArrayList