Android 源码的解释器模式

Android 源码的解释器模式

解释器模式介绍

解释器模式是一种用得比较少的行为型模式,其提供了一种解释语言的语法或表达式的方式。该模式定义了一个表达式接口,通过该接口解释一个特定的上下文。

解释器模式的定义

给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。

PackageParser

Android 的 PackageParser 类对 AndroidManifest.xml 中的每一个组件标签创建了相应的类用以存储相应的信息。

    public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable {
    ...
    public final static class Service extends Component<ServiceIntentInfo> implements Parcelable {
    ...
    public final static class Provider extends Component<ProviderIntentInfo> implements Parcelable {
    ...
    public final static class Instrumentation extends Component<IntentInfo> implements
    ...

PackageParser 为 Activity、Service、Provider 等组件在其内部以内部类的方式创建了对应的类,按照解释器模式的定义,这些类都对应 AndroidManifest.xml 文件中的一个标签,也就是一条文法,其在对该配置文件解析时充分运用了解释器模式分离实现、解释执行的特性。

在 Android 中,解析某个 apk 文件会调用到 PackageManagerService 中的 scanPackageLI 方法。

scanPackageLI 方法会调用 PackageParser 的 parsePackage 方法。

    private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
            long currentTime, UserHandle user) throws PackageManagerException {
        PackageParser pp = new PackageParser();
        ...
        final PackageParser.Package pkg;
        try {
            pkg = pp.parsePackage(scanFile, parseFlags);
        }
        ...
        return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
    }

parsePackage 方法经过多次调用,最后会调用 parseBaseApkCommon 方法,解析 AndroidManifest 的每个子节点。

    private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
            XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
            IOException {
            ...
            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;
                }
            }
            ...
        return pkg;
    }

parseBaseApkCommon 调用 parseBaseApplication 解析 application 节点。

    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;
        ...
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
            ...
            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);

            }
            ...
        return true;
    }

可以看出 parseBaseApplication 发现 activity 标签时,会使用 parseActivity 解析 activity。

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 (parser.getName().equals("intent-filter")) {
                ActivityIntentInfo intent = new ActivityIntentInfo(a);
                if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/,
                        intent, outError)) {
                    return null;
                }
                ...
            } else if (parser.getName().equals("meta-data")) {
                if ((a.metaData = parseMetaData(res, parser, a.metaData,
                        outError)) == null) {
                    return null;
                }
            ...
        return a;
    }

与 parseBaseApplication 类似,parseActivity 内部逻辑也是遍历子标签,并调用相应方法对其进行解析,比如 parseIntent 和 parseMetaData。

发布了105 篇原创文章 · 获赞 2 · 访问量 3761

猜你喜欢

转载自blog.csdn.net/caoshen2014/article/details/102945752