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

Commit 741b68ab authored by Jeremy Meyer's avatar Jeremy Meyer
Browse files

Only check for xml flag attributes when we know there is one there

This makes it so that when we are flattening xml files we figure out
which elements have the featureFlag attribute and persist that in the
binary xml. Then at runtime we can quickly check that before we try and
find the actual attribute.

Test: Automation
Flag: android.content.res.layout_readwrite_flags
Bug: 398541237
Change-Id: I1015dd45c4a0ba38bea75cad30b59cec4a05d825
parent a2ec91ad
Loading
Loading
Loading
Loading
+30 −12
Original line number Diff line number Diff line
@@ -350,8 +350,11 @@ public final class XmlBlock implements AutoCloseable {
            }

            if (useLayoutReadwrite() && mUsesFeatureFlags && ev == START_TAG) {
                FlagInfo flag = nativeGetFlagInfo(mParseState);
                if (flag != null && flag.mNameIndex > 0) {
                    AconfigFlags flags = ParsingPackageUtils.getAconfigFlags();
                if (flags.skipCurrentElement(/* pkg= */ null, this)) {
                    String flagName = getSequenceString(mStrings.getSequence(flag.mNameIndex));
                    if (flags.skip(/* pkg= */ null, flagName, flag.mNegated)) {
                        int depth = 1;
                        while (depth > 0) {
                            int ev2 = nativeNext(mParseState);
@@ -366,6 +369,7 @@ public final class XmlBlock implements AutoCloseable {
                        return next();
                    }
                }
            }
            if (mDecNextDepth) {
                mDepth--;
                mDecNextDepth = false;
@@ -696,6 +700,17 @@ public final class XmlBlock implements AutoCloseable {

    private final boolean mUsesFeatureFlags;

    // This class only exists for JNI communication
    private static class FlagInfo {
        private int mNameIndex;
        private boolean mNegated;

        private FlagInfo(int nameIndex, boolean negated) {
            mNameIndex = nameIndex;
            mNegated = negated;
        }
    }

    private static final native long nativeCreate(byte[] data,
                                                 int offset,
                                                 int size);
@@ -758,4 +773,7 @@ public final class XmlBlock implements AutoCloseable {

    @CriticalNative
    private static final native int nativeGetSourceResId(long state);

    @FastNative
    private static final native FlagInfo nativeGetFlagInfo(long state);
}
+13 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.internal.pm.pkg.component;

import static android.provider.flags.Flags.newStoragePublicApi;

import static com.android.internal.pm.pkg.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;

import android.aconfig.DeviceProtos;
@@ -320,6 +321,18 @@ public class AconfigFlags {
            negated = true;
            featureFlag = featureFlag.substring(1).strip();
        }
        return skip(pkg, featureFlag, negated);
    }

    /**
     * Check if whatever is behind this flag should be skipped
     *
     * @param pkg The package being parsed
     * @param featureFlag The name of the flag being checked
     * @param negated Whether that flag is negated
     * @return true if the resource is disabled because of its feature flag
     */
    public boolean skip(@Nullable ParsingPackage pkg, String featureFlag, boolean negated) {
        Boolean flagValue = getFlagValue(featureFlag);
        boolean isUndefined = false;
        if (flagValue == null) {
+65 −54
Original line number Diff line number Diff line
@@ -16,22 +16,25 @@
*/

#define LOG_TAG "XmlBlock"

#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include <core_jni_helpers.h>
#include <androidfw/AssetManager.h>
#include <androidfw/ResourceTypes.h>
#include <core_jni_helpers.h>
#include <nativehelper/JNIHelp.h>
#include <stdio.h>
#include <utils/Log.h>
#include <utils/misc.h>

#include <stdio.h>

#include "jni.h"
namespace android {
constexpr int kNullDocument = UNEXPECTED_NULL;
// The reason not to ResXMLParser::BAD_DOCUMENT which is -1 is that other places use the same value.
constexpr int kBadDocument = BAD_VALUE;

static struct flag_info_fields {
    jclass jClass;
    jmethodID jConstructor;
} gFlagInfo;

// ----------------------------------------------------------------------------

static jlong android_content_XmlBlock_nativeCreate(JNIEnv* env, jobject clazz,
@@ -338,6 +341,21 @@ static void android_content_XmlBlock_nativeDestroy(JNIEnv* env, jobject clazz,
    delete osb;
}

static jobject android_content_XmlBlock_nativeGetFlagInfo(JNIEnv* env, jobject clazz, jlong token) {
    ResXMLParser* st = reinterpret_cast<ResXMLParser*>(token);
    if (st == nullptr) {
        return nullptr;
    }

    if (auto info = st->getFlagInfo()) {
        return env->NewObject(gFlagInfo.jClass, gFlagInfo.jConstructor,
                              static_cast<jint>(info->flagNameIndex),
                              static_cast<jboolean>(info->flagNegated));
    } else {
        return nullptr;
    }
}

// ----------------------------------------------------------------------------

/*
@@ -345,57 +363,50 @@ static void android_content_XmlBlock_nativeDestroy(JNIEnv* env, jobject clazz,
 */
static const JNINativeMethod gXmlBlockMethods[] = {
        /* name, signature, funcPtr */
    { "nativeCreate",               "([BII)J",
            (void*) android_content_XmlBlock_nativeCreate },
    { "nativeGetStringBlock",       "(J)J",
            (void*) android_content_XmlBlock_nativeGetStringBlock },
    { "nativeCreateParseState",     "(JI)J",
            (void*) android_content_XmlBlock_nativeCreateParseState },
        {"nativeCreate", "([BII)J", (void*)android_content_XmlBlock_nativeCreate},
        {"nativeGetStringBlock", "(J)J", (void*)android_content_XmlBlock_nativeGetStringBlock},
        {"nativeCreateParseState", "(JI)J", (void*)android_content_XmlBlock_nativeCreateParseState},
        {"nativeDestroyParseState", "(J)V",
         (void*)android_content_XmlBlock_nativeDestroyParseState},
    { "nativeDestroy",              "(J)V",
            (void*) android_content_XmlBlock_nativeDestroy },
        {"nativeDestroy", "(J)V", (void*)android_content_XmlBlock_nativeDestroy},

        // ------------------- @FastNative ----------------------

    { "nativeNext",                 "(J)I",
            (void*) android_content_XmlBlock_nativeNext },
    { "nativeGetNamespace",         "(J)I",
            (void*) android_content_XmlBlock_nativeGetNamespace },
    { "nativeGetName",              "(J)I",
            (void*) android_content_XmlBlock_nativeGetName },
    { "nativeGetText",              "(J)I",
            (void*) android_content_XmlBlock_nativeGetText },
    { "nativeGetLineNumber",        "(J)I",
            (void*) android_content_XmlBlock_nativeGetLineNumber },
        {"nativeNext", "(J)I", (void*)android_content_XmlBlock_nativeNext},
        {"nativeGetNamespace", "(J)I", (void*)android_content_XmlBlock_nativeGetNamespace},
        {"nativeGetName", "(J)I", (void*)android_content_XmlBlock_nativeGetName},
        {"nativeGetText", "(J)I", (void*)android_content_XmlBlock_nativeGetText},
        {"nativeGetLineNumber", "(J)I", (void*)android_content_XmlBlock_nativeGetLineNumber},
        {"nativeGetAttributeCount", "(J)I",
         (void*)android_content_XmlBlock_nativeGetAttributeCount},
        {"nativeGetAttributeNamespace", "(JI)I",
         (void*)android_content_XmlBlock_nativeGetAttributeNamespace},
    { "nativeGetAttributeName",     "(JI)I",
            (void*) android_content_XmlBlock_nativeGetAttributeName },
        {"nativeGetAttributeName", "(JI)I", (void*)android_content_XmlBlock_nativeGetAttributeName},
        {"nativeGetAttributeResource", "(JI)I",
         (void*)android_content_XmlBlock_nativeGetAttributeResource},
        {"nativeGetAttributeDataType", "(JI)I",
         (void*)android_content_XmlBlock_nativeGetAttributeDataType},
    { "nativeGetAttributeData",    "(JI)I",
            (void*) android_content_XmlBlock_nativeGetAttributeData },
        {"nativeGetAttributeData", "(JI)I", (void*)android_content_XmlBlock_nativeGetAttributeData},
        {"nativeGetAttributeStringValue", "(JI)I",
         (void*)android_content_XmlBlock_nativeGetAttributeStringValue},
        {"nativeGetAttributeIndex", "(JLjava/lang/String;Ljava/lang/String;)I",
         (void*)android_content_XmlBlock_nativeGetAttributeIndex},
    { "nativeGetIdAttribute",      "(J)I",
            (void*) android_content_XmlBlock_nativeGetIdAttribute },
        {"nativeGetIdAttribute", "(J)I", (void*)android_content_XmlBlock_nativeGetIdAttribute},
        {"nativeGetClassAttribute", "(J)I",
         (void*)android_content_XmlBlock_nativeGetClassAttribute},
        {"nativeGetStyleAttribute", "(J)I",
         (void*)android_content_XmlBlock_nativeGetStyleAttribute},
    { "nativeGetSourceResId",      "(J)I",
            (void*) android_content_XmlBlock_nativeGetSourceResId},
        {"nativeGetSourceResId", "(J)I", (void*)android_content_XmlBlock_nativeGetSourceResId},
        {"nativeGetFlagInfo", "(J)Landroid/content/res/XmlBlock$FlagInfo;",
         (void*)android_content_XmlBlock_nativeGetFlagInfo},
};

int register_android_content_XmlBlock(JNIEnv* env)
{
    gFlagInfo.jClass =
            MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/content/res/XmlBlock$FlagInfo"));
    gFlagInfo.jConstructor = GetMethodIDOrDie(env, gFlagInfo.jClass, "<init>", "(IZ)V");

    return RegisterMethodsOrDie(env,
            "android/content/res/XmlBlock", gXmlBlockMethods, NELEM(gXmlBlockMethods));
}
+23 −1
Original line number Diff line number Diff line
@@ -44,7 +44,7 @@
#include <utils/Log.h>
#include <utils/String16.h>
#include <utils/String8.h>

#include <android-base/logging.h>
#ifdef __ANDROID__
#include <binder/TextOutput.h>

@@ -1407,6 +1407,28 @@ size_t ResXMLParser::getAttributeCount() const
    return 0;
}

std::optional<ResXMLParser::ResXMLFlagInfo> ResXMLParser::getFlagInfo() const
{
    if (mEventCode == START_TAG) {
        const auto* attrExt = ((const ResXMLTree_attrExt*)mCurExt);
        uint16_t s1 = sizeof(ResXMLTree_attrExt);
        uint16_t s2 = sizeof(ResXMLTreeFlagExt);

        // Flag information is stored in an ResXMLTreeFlagExt. If there is a flag, this is
        // stored right after the ResXMLTree_attrExt. To determine if there is a flagExt we see
        // if the offset to where attributes start is big enough to store both a ResXMLTree_attrExt
        // and a ResXMLTreeFlagExt.
        if (attrExt->attributeStart == (s1 + s2)) {
            auto flag_ext = (const ResXMLTreeFlagExt*)(((const uint8_t*)mCurExt) + s1);
            if (flag_ext->descriptor == ResXMLTreeExtDescriptor::FLAG_INFO) {
                return ResXMLParser::ResXMLFlagInfo{flag_ext->flag_name.index,
                                                  flag_ext->flag_negated};
            }
        }
    }
    return {};
}

int32_t ResXMLParser::getAttributeNamespaceID(size_t idx) const
{
    if (mEventCode == START_TAG) {
+32 −1
Original line number Diff line number Diff line
@@ -715,6 +715,29 @@ struct ResXMLTree_attrExt
    uint16_t styleIndex;
};

enum  ResXMLTreeExtDescriptor : uint8_t {
    PADDING = 0x00,
    FLAG_INFO = 0x01,
};

struct ResXMLTreeFlagExt {

    // defines the type of the extended element structure
    ResXMLTreeExtDescriptor descriptor;

    // if the flag condition is negated
    bool flag_negated;

    // a hole for 4-byte alignment
    uint16_t reserved;

    // The reference into the string pool that the flag name is stored at
    ResStringPool_ref flag_name;
};

static_assert(sizeof(ResXMLTreeFlagExt) == 8);


struct ResXMLTree_attribute
{
    // Namespace of this attribute.
@@ -758,6 +781,12 @@ public:
        const void*                 curExt;
    };

    struct ResXMLFlagInfo
    {
      uint32_t flagNameIndex;
      bool flagNegated;
    };

    void restart();

    const ResStringPool& getStrings() const;
@@ -794,6 +823,8 @@ public:
    
    size_t getAttributeCount() const;

    std::optional<ResXMLFlagInfo> getFlagInfo() const;

    // Returns -1 if no namespace, -2 if idx out of range.
    int32_t getAttributeNamespaceID(size_t idx) const;
    const char16_t* getAttributeNamespace(size_t idx, size_t* outLen) const;
Loading