Android设计模式之解释器模式

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

解释器模式的定义

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

解释器模式的使用场景

1.如果某个简单的语言需要解释执行,而且可以将该语言中的语句表示为一个抽象语法树时,可以考虑使用解释器模式。

2.在某些特定的领域出现不断重复的问题时,可以将该领域的问题转化为一种语法规则下的语句,然后构建解释器来解释该语句。像这样的从一个具体的符号出发,通过不断应用一些产生式规则从而生成一个字符串的集合,我们将描述这个集合的文法称为形式文法,顾名思义,形式文法与形式语言相对应,用来描述形式语言。

解释器模式的定义: 给定一个语言(如由abcdef六个字符串组成的字符串集合),定义它的文法的一种表示(如上面给出的S::=abA*ef和A::=cd),并定义一个解释器,该解释器使用该表示来解释语言中的句子。

 

Android源码中的解释器模式

对于Android来说,解释器模式的应用并不多见,在系统源码中也比较少,依然可以在一些地方看到解释器模式原理的应用。

如:AndroidManifest.xml这个应用配置文件,

如果应用是一本书的话,这个配置文件相当于书的目录,其中包含大量应用配置的声明定义,那么在android中如何读取这个配置文件呢?那么就不得不说PackageParser这个类,该类对AndroidManifest.xml中每一个组件标签创建了相应的类用以存储相应的信息。

 

package android.content.pm;

public class PackageParser {


/**
 * Representation of a full package parsed from APK files on disk. A package
 * consists of a single base APK, and zero or more split APKs.静态内部类
 */
public final static class Package implements Parcelable {
    ... ...
   public Package(String packageName) {
    this.packageName = packageName;
    this.manifestPackageName = packageName;
    applicationInfo.packageName = packageName;
    applicationInfo.uid = -1;
}
}


public final static class Permission extends Component<IntentInfo> implements Parcelable {
        public final PermissionInfo info;
        public boolean tree;
        public PermissionGroup group;

        public Permission(Package _owner) {
            super(_owner);
            info = new PermissionInfo();
        }

        public Permission(Package _owner, PermissionInfo _info) {
            super(_owner);
            info = _info;
        }
        ... ...
}


public final static class PermissionGroup extends Component<IntentInfo> implements Parcelable {
    public final PermissionGroupInfo info;

    public PermissionGroup(Package _owner) {
        super(_owner);
        info = new PermissionGroupInfo();
    }

    public PermissionGroup(Package _owner, PermissionGroupInfo _info) {
        super(_owner);
        info = _info;
    }
    ... ...
}


public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable {
    public final ActivityInfo info;
    private boolean mHasMaxAspectRatio;

    private boolean hasMaxAspectRatio() {
        return mHasMaxAspectRatio;
    }

    public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
        super(args, _info);
        info = _info;
        info.applicationInfo = args.owner.applicationInfo;
    }
    
    ... ...
}


public final static class Provider extends Component<ProviderIntentInfo> implements Parcelable {
    public final ProviderInfo info;
    public boolean syncable;

    public Provider(final ParseComponentArgs args, final ProviderInfo _info) {
        super(args, _info);
        info = _info;
        info.applicationInfo = args.owner.applicationInfo;
        syncable = false;
    }

    public Provider(Provider existingProvider) {
        super(existingProvider);
        this.info = existingProvider.info;
        this.syncable = existingProvider.syncable;
    }
    ... ...
}

public final static class Instrumentation extends Component<IntentInfo> implements
        Parcelable {
    public final InstrumentationInfo info;

    public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) {
        super(args, _info);
        info = _info;
    }
    ... ...
}


public final static class ActivityIntentInfo extends IntentInfo {
    public Activity activity;

    public ActivityIntentInfo(Activity _activity) {
        activity = _activity;
    }
    
    ... ...
}


public final static class ServiceIntentInfo extends IntentInfo {
    public Service service;

    public ServiceIntentInfo(Service _service) {
        service = _service;
    }
    ... ...     
}


public static final class ProviderIntentInfo extends IntentInfo {
    public Provider provider;

    public ProviderIntentInfo(Provider provider) {
        this.provider = provider;
    }
    ... ...
}
}
扫描二维码关注公众号,回复: 4524466 查看本文章

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

在Android中,解析某一个apk文件会调用到PackageManagerService(PMS)中scanPackageLI方法,该方法有两种实现:

#PackageManagerService
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
        long currentTime, UserHandle user) throws PackageManagerException {
    ... ...
}

#PackageManagerService
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
        long currentTime, UserHandle user) throws PackageManagerException {
    ... ...    
}

 两者的唯一区别是scanPackageLI的第一个参数,第一种实现为File类型的对象,而第二种实现为PackageParser.Package类型的对象,在具体解析某一个文件时会先调用第一种实现去解析apk文件,再调用第二种实现将解析后的信息保存至PMS中。

#PackageManagerService
/**
 *  Scans a package and returns the newly parsed package.
 *  Returns {@code null} in case of errors and the error code is stored in mLastScanError
 */
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
        long currentTime, UserHandle user) throws PackageManagerException {
    if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
    PackageParser pp = new PackageParser();
    pp.setSeparateProcesses(mSeparateProcesses);
    pp.setOnlyCoreApps(mOnlyCore);
    pp.setDisplayMetrics(mMetrics);
    pp.setCallback(mPackageParserCallback);

    //解析标志
    if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
        parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
    }

    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
    final PackageParser.Package pkg;
    try {
        //调用PackageParser对象的parsePackage方法解析apk文件
        pkg = pp.parsePackage(scanFile, parseFlags);
    } catch (PackageParserException e) {
        throw PackageManagerException.from(e);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }

    // Static shared libraries have synthetic package names
    if (pkg.applicationInfo.isStaticSharedLibrary()) {
        renameStaticSharedLibraryPackage(pkg);
    }

     //调用该方法的第二种实现,将解析后的信息保存至PMS
    return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);
}

这里重点分析PackageParser类,该类如上所说,承担着具体的解析重任,上述代码中首先调用了其parsePackage方法,该方法也有两种实现:

#PackageParser
/**
 * Equivalent to {@link #parsePackage(File, int, boolean)} with {@code useCaches == false}.
 */
public Package parsePackage(File packageFile, int flags) throws PackageParserException {
    //调用第二种实现进行解析
    return parsePackage(packageFile, flags, false /* useCaches */);
}

#PackageParser
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;

   //parsePackage方法中要  对传入File进行判断。
  //Android 5.0 之后默认支持一个应用关联多个APK的形式,当某个app是这类情况的话,这些APK就会放在一个文件夹中,那么此时就会调用parseClusterPackage处理。
    if (packageFile.isDirectory()) {
        parsed = parseClusterPackage(packageFile, flags);
    } else {

       当传入的file就是一个apk文件的话,调用parseMonolithicPackage来处理。
解析单个apk
首先分析file为一个apk文件的情况,即parseMonolithicPackage:
        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;
}

第一种实现就是上面代码中调用到的方法,其主要逻辑就是为第二种实现准备参数后调用第二个方法。而parsePackage方法的第二种实现逻辑则要复杂的多,在其内部主要对整个AndroidManifest.xml配置文件进行具体的解析。

#PackageParser
/**
 * Parse the given APK file, treating it as as a single monolithic package.
 * <p>
 * Note that this <em>does not</em> perform signature verification; that
 * must be done separately in {@link #collectCertificates(Package, int)}.
 *
 * @deprecated external callers should move to
 *             {@link #parsePackage(File, int)}. Eventually this method will
 *             be marked private.
 */
@Deprecated
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
    //AssetManager是资源管理框架
    final AssetManager assets = newConfiguredAssetManager();
    final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
    if (mOnlyCoreApps) { //PMS初始化时,该变量一般为false,只有在data区加解密等特殊情况下,才为true
  ////如果是核心应用则以更轻量级的方式进行解析后,判断是否是核心应用,非核心应用不执行解析过程
        if (!lite.coreApp) {
            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                    "Not a coreApp: " + apkFile);
        }
    }

    try {
        //先创建一个资源管理框架的对象AssetManager,在将其和apkfile等一起传入parseBaseApk方法;
        // 在parseBaseApk的时候,会把assets传人
        final Package pkg = parseBaseApk(apkFile, assets, flags);
        pkg.setCodePath(apkFile.getAbsolutePath());
        pkg.setUse32bitAbi(lite.use32bitAbi);
        return pkg;
    } finally {
        IoUtils.closeQuietly(assets);
    }
}

 

#PackageParser
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
        throws PackageParserException {
    final String apkPath = apkFile.getAbsolutePath(); // 返回apkFile绝对路径名字字符串

    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);

    final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);

    Resources res = null;
    XmlResourceParser parser = null;
    try {
        res = new Resources(assets, mMetrics, null);

       //创建AndroidMainfest.xml的xml解析器
        parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);

        final String[] outError = new String[1];
      // 开始真正解析AndroidMainfest.xml 
        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.setSignatures(null);
        //porting theme<
        // If the pkg is a theme, we need to know what themes it overlays
        // and determine if it has an icon pack
        if (pkg.mIsThemeApk) {
            //Determine existance of Overlays
            //<panjuan for overlay 0207
            ArrayList<String> overlayTargets = scanPackageOverlays(apkFile);
            for(String overlay : overlayTargets) {
                pkg.mOverlayTargets.add(overlay);
            }//panjuan for overlay>

            pkg.hasIconPack = packageHasIconPack(apkFile);
        }
        //porting theme>
        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);
    }
}

该方法说白了,就是对AndroidMainfest.xml文件进行解析。真正解析这个xml的是其内部调用的parseBaseApk方法。该方法先调用以pkgName为参数的构造方法创建一个PackageParser.Package对象。

#PackageParser 内部类  Package 
/**
 * Representation of a full package parsed from APK files on disk. A package
 * consists of a single base APK, and zero or more split APKs.
 */
public final static class Package implements Parcelable {


public Package(String packageName) {
    this.packageName = packageName;
    this.manifestPackageName = packageName;
    applicationInfo.packageName = packageName;
    applicationInfo.uid = -1;
}
}

#PackageParser 
private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
            String[] outError) throws XmlPullParserException, IOException {
       
 ... ...   
return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
}
#PackageParser 

//该方法中有比较重要的解析
 private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
            XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
            IOException {

... ...
if (!parseBaseApplication(pkg, res, parser, flags, outError)) {
    return null;
}
... ...
}

可以看到,parseBaseApkCommon方法的主要作用其实就是对AndroidManifest.xml配置文件中manifest下的每个子节点进行解析,这里主要看一下:parseBaseApplication方法是如何对application节点进行解析的。

/**
 * Parse the {@code application} XML tree at the current parse location in a
 * <em>base APK</em> manifest.
 * <p>
 * When adding new features, carefully consider if they should also be
 * supported by split APKs.
 */
private boolean parseBaseApplication(Package owner, Resources res,
        XmlResourceParser parser, int flags, String[] outError)
    throws XmlPullParserException, IOException {
        ... ...

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 a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
                owner.baseHardwareAccelerated);
        if (a == null) {
            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
            return false;
        }

        owner.activities.add(a);

    }
    ... ...
}
}

在程序中可以看到,parseBaseApplication除了对application节点内的属性进行解析之外,其主要逻辑还是通过遍历解析其子节点,然后继续分别调用不同的解析方法对其进行解析,这里以parseActivity为例。

 

private Activity parseActivity(Package owner, Resources res,
            XmlResourceParser parser, int flags, String[] outError, CachedComponentArgs cachedArgs,
            boolean receiver, boolean hardwareAccelerated)
            throws XmlPullParserException, IOException {
        ... ...
}

这里需要注意的是,parseActivity方法不仅承担着对Activity的解析,其同样承担着对Broadcast的解析。与parseApplication方法类似,parseActivity内部逻辑也是遍历其子标签,并调用相应的方法对其进行解析,如上述代码中的parseIntent和parseMetaData。

 参考《Android源码设计模式》

 

猜你喜欢

转载自blog.csdn.net/zhangying1994/article/details/84842250