Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 02d2b5a4 authored by Xavier Ducrohet's avatar Xavier Ducrohet
Browse files

LayoutLib: When possible ensure parsers are popped from the stack.

Some parser consumers (seems to be mostly resource inflation)
don't use the pull parser up to the END_DOCUMENT tag, making
the parser not pop itself from the parser stack automatically.

This is likely due to the XML resources being very shallow (1-2 levels
max), and the inflater just reading the content that it expects instead
of parsing till the document is done.

This ensures that *some* parsers are pop'ed from the stack when
used. Some other parsers we don't really control and hope the
user will parse till END_DOCUMENT.

Change-Id: Ie1f5762983fed2b2ae97b896218ae12b493e7ad9
parent bbcf2079
Loading
Loading
Loading
Loading
+9 −6
Original line number Diff line number Diff line
@@ -294,7 +294,8 @@ public final class BridgeTypedArray extends TypedArray {
            return null;
        }

        String value = mResourceData[index].getValue();
        ResourceValue resValue = mResourceData[index];
        String value = resValue.getValue();

        if (value == null) {
            return null;
@@ -308,11 +309,13 @@ public final class BridgeTypedArray extends TypedArray {
                parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
                parser.setInput(new FileReader(f));

                ColorStateList colorStateList = ColorStateList.createFromXml(
                        mContext.getResources(),
                        // FIXME: we need to know if this resource is platform or not
                        new BridgeXmlBlockParser(parser, mContext, false));
                return colorStateList;
                BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
                        parser, mContext, resValue.isFramework());
                try {
                    return ColorStateList.createFromXml(mContext.getResources(), blockParser);
                } finally {
                    blockParser.ensurePopped();
                }
            } catch (XmlPullParserException e) {
                Bridge.getLog().error(LayoutLog.TAG_BROKEN,
                        "Failed to configure parser for " + value, e, null /*data*/);
+12 −2
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@ public class BridgeXmlBlockParser implements XmlResourceParser {
    private boolean mStarted = false;
    private int mEventType = START_DOCUMENT;

    private boolean mPopped = true; // default to true in case it's not pushed.

    /**
     * Builds a {@link BridgeXmlBlockParser}.
     * @param parser The XmlPullParser to get the content from.
@@ -59,6 +61,7 @@ public class BridgeXmlBlockParser implements XmlResourceParser {

        if (mContext != null) {
            mContext.pushParser(this);
            mPopped = false;
        }
    }

@@ -82,6 +85,13 @@ public class BridgeXmlBlockParser implements XmlResourceParser {
        return null;
    }

    public void ensurePopped() {
        if (mContext != null && mPopped == false) {
            mContext.popParser();
            mPopped = true;
        }
    }

    // ------- XmlResourceParser implementation

    public void setFeature(String name, boolean state)
@@ -249,9 +259,9 @@ public class BridgeXmlBlockParser implements XmlResourceParser {
        }
        int ev = mParser.next();

        if (ev == END_TAG && mParser.getDepth() == 1 && mContext != null) {
        if (ev == END_TAG && mParser.getDepth() == 1) {
            // done with parser remove it from the context stack.
            mContext.popParser();
            ensurePopped();
        }
        mEventType = ev;
        return ev;
+6 −2
Original line number Diff line number Diff line
@@ -76,9 +76,13 @@ abstract class CustomBar extends LinearLayout {
                "UTF8");

        BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
                parser, (BridgeContext) context, false);
                parser, (BridgeContext) context, false /*platformFile*/);

        try {
            inflater.inflate(bridgeParser, this, true);
        } finally {
            bridgeParser.ensurePopped();
        }
    }

    private InputStream getIcon(String iconName, Density[] densityInOut, String[] pathOut,
+5 −4
Original line number Diff line number Diff line
@@ -182,8 +182,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
        context.setBridgeInflater(mInflater);
        mInflater.setFactory2(context);

        mBlockParser = new BridgeXmlBlockParser(params.getLayoutDescription(),
                context, false /* platformResourceFlag */);
        mBlockParser = new BridgeXmlBlockParser(
                params.getLayoutDescription(), context, false /* platformResourceFlag */);

        return SUCCESS.createResult();
    }
@@ -562,13 +562,14 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
        BridgeContext context = getContext();

        // create a block parser for the XML
        BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(childXml, context,
                false /* platformResourceFlag */);
        BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
                childXml, context, false /* platformResourceFlag */);

        // inflate the child without adding it to the root since we want to control where it'll
        // get added. We do pass the parentView however to ensure that the layoutParams will
        // be created correctly.
        final View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/);
        blockParser.ensurePopped();

        invalidateRenderingSize();

+14 −7
Original line number Diff line number Diff line
@@ -126,8 +126,13 @@ public final class ResourceHelper {
                    parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
                    parser.setInput(new FileReader(f));

                    return ColorStateList.createFromXml(context.getResources(),
                            new BridgeXmlBlockParser(parser, context, resValue.isFramework()));
                    BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
                            parser, context, resValue.isFramework());
                    try {
                        return ColorStateList.createFromXml(context.getResources(), blockParser);
                    } finally {
                        blockParser.ensurePopped();
                    }
                } catch (XmlPullParserException e) {
                    Bridge.getLog().error(LayoutLog.TAG_BROKEN,
                            "Failed to configure parser for " + value, e, null /*data*/);
@@ -164,8 +169,6 @@ public final class ResourceHelper {
     * @param context the current context
     */
    public static Drawable getDrawable(ResourceValue value, BridgeContext context) {
        Drawable d = null;

        String stringValue = value.getValue();
        if (RenderResources.REFERENCE_NULL.equals(stringValue)) {
            return null;
@@ -205,9 +208,13 @@ public final class ResourceHelper {
                    parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
                    parser.setInput(new FileReader(f));

                    d = Drawable.createFromXml(context.getResources(),
                            new BridgeXmlBlockParser(parser, context, value.isFramework()));
                    return d;
                    BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
                            parser, context, value.isFramework());
                    try {
                        return Drawable.createFromXml(context.getResources(), blockParser);
                    } finally {
                        blockParser.ensurePopped();
                    }
                } catch (Exception e) {
                    // this is an error and not warning since the file existence is checked before
                    // attempting to parse it.