四、三步曲 - 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的扫描,整体描述图:

messenger apk android messenger apk android 8.1_android

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