Move attribute resolution from core/jni to libandroidfw
Without the entire JNI environment, testing the attribute
resolution code will be much easier and enable safer
refactoring.
Change-Id: I2815cc1e10a694a3b01bc37e191a0d5e9d0e6735
Test: Existing CTS tests pass
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index ef32afee..5a4348e 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -31,7 +31,7 @@
#include "androidfw/Asset.h"
#include "androidfw/AssetManager.h"
-#include "androidfw/AttributeFinder.h"
+#include "androidfw/AttributeResolution.h"
#include "androidfw/ResourceTypes.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_util_Binder.h"
@@ -51,7 +51,6 @@
namespace android {
static const bool kThrowOnBadId = false;
-static const bool kDebugStyles = false;
// ----------------------------------------------------------------------------
@@ -1121,30 +1120,6 @@
theme->dumpToLog();
}
-class XmlAttributeFinder : public BackTrackingAttributeFinder<XmlAttributeFinder, jsize> {
-public:
- explicit XmlAttributeFinder(const ResXMLParser* parser)
- : BackTrackingAttributeFinder(0, parser != NULL ? parser->getAttributeCount() : 0)
- , mParser(parser) {}
-
- inline uint32_t getAttribute(jsize index) const {
- return mParser->getAttributeNameResID(index);
- }
-
-private:
- const ResXMLParser* mParser;
-};
-
-class BagAttributeFinder : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
-public:
- BagAttributeFinder(const ResTable::bag_entry* start, const ResTable::bag_entry* end)
- : BackTrackingAttributeFinder(start, end) {}
-
- inline uint32_t getAttribute(const ResTable::bag_entry* entry) const {
- return entry->map.name.ident;
- }
-};
-
static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
jlong themeToken,
jint defStyleAttr,
@@ -1167,16 +1142,6 @@
return JNI_FALSE;
}
- if (kDebugStyles) {
- ALOGI("APPLY STYLE: theme=0x%" PRIx64 " defStyleAttr=0x%x "
- "defStyleRes=0x%x", themeToken, defStyleAttr, defStyleRes);
- }
-
- ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
- const ResTable& res = theme->getResTable();
- ResTable_config config;
- Res_value value;
-
const jsize NI = env->GetArrayLength(attrs);
const jsize NV = env->GetArrayLength(outValues);
if (NV < (NI*STYLE_NUM_ENTRIES)) {
@@ -1193,159 +1158,32 @@
const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
- jint* dest = baseDest;
- if (dest == NULL) {
+ if (baseDest == NULL) {
env->ReleasePrimitiveArrayCritical(attrs, src, 0);
return JNI_FALSE;
}
jint* indices = NULL;
- int indicesIdx = 0;
if (outIndices != NULL) {
if (env->GetArrayLength(outIndices) > NI) {
indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
}
}
- // Load default style from attribute, if specified...
- uint32_t defStyleBagTypeSetFlags = 0;
- if (defStyleAttr != 0) {
- Res_value value;
- if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
- if (value.dataType == Res_value::TYPE_REFERENCE) {
- defStyleRes = value.data;
- }
- }
- }
-
- // Now lock down the resource object and start pulling stuff from it.
- res.lock();
-
- // Retrieve the default style bag, if requested.
- const ResTable::bag_entry* defStyleStart = NULL;
- uint32_t defStyleTypeSetFlags = 0;
- ssize_t bagOff = defStyleRes != 0
- ? res.getBagLocked(defStyleRes, &defStyleStart, &defStyleTypeSetFlags) : -1;
- defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
- const ResTable::bag_entry* const defStyleEnd = defStyleStart + (bagOff >= 0 ? bagOff : 0);
- BagAttributeFinder defStyleAttrFinder(defStyleStart, defStyleEnd);
-
- // Now iterate through all of the attributes that the client has requested,
- // filling in each with whatever data we can find.
- ssize_t block = 0;
- uint32_t typeSetFlags;
- for (jsize ii=0; ii<NI; ii++) {
- const uint32_t curIdent = (uint32_t)src[ii];
-
- if (kDebugStyles) {
- ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
- }
-
- // Try to find a value for this attribute... we prioritize values
- // coming from, first XML attributes, then XML style, then default
- // style, and finally the theme.
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- typeSetFlags = 0;
- config.density = 0;
-
- // Retrieve the current input value if available.
- if (NSV > 0 && srcValues[ii] != 0) {
- block = -1;
- value.dataType = Res_value::TYPE_ATTRIBUTE;
- value.data = srcValues[ii];
- if (kDebugStyles) {
- ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- }
-
- if (value.dataType == Res_value::TYPE_NULL) {
- const ResTable::bag_entry* const defStyleEntry = defStyleAttrFinder.find(curIdent);
- if (defStyleEntry != defStyleEnd) {
- block = defStyleEntry->stringBlock;
- typeSetFlags = defStyleTypeSetFlags;
- value = defStyleEntry->map.value;
- if (kDebugStyles) {
- ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- }
- }
-
- uint32_t resid = 0;
- if (value.dataType != Res_value::TYPE_NULL) {
- // Take care of resolving the found resource to its final value.
- ssize_t newBlock = theme->resolveAttributeReference(&value, block,
- &resid, &typeSetFlags, &config);
- if (newBlock >= 0) block = newBlock;
- if (kDebugStyles) {
- ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- } else {
- // If we still don't have a value for this attribute, try to find
- // it in the theme!
- ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
- if (newBlock >= 0) {
- if (kDebugStyles) {
- ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- newBlock = res.resolveReference(&value, block, &resid,
- &typeSetFlags, &config);
- if (kThrowOnBadId) {
- if (newBlock == BAD_INDEX) {
- jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
- return JNI_FALSE;
- }
- }
- if (newBlock >= 0) block = newBlock;
- if (kDebugStyles) {
- ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- }
- }
-
- // Deal with the special @null value -- it turns back to TYPE_NULL.
- if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
- if (kDebugStyles) {
- ALOGI("-> Setting to @null!");
- }
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- block = -1;
- }
-
- if (kDebugStyles) {
- ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType,
- value.data);
- }
-
- // Write the final value back to Java.
- dest[STYLE_TYPE] = value.dataType;
- dest[STYLE_DATA] = value.data;
- dest[STYLE_ASSET_COOKIE] =
- block != -1 ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
- dest[STYLE_RESOURCE_ID] = resid;
- dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
- dest[STYLE_DENSITY] = config.density;
-
- if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
- indicesIdx++;
- indices[indicesIdx] = ii;
- }
-
- dest += STYLE_NUM_ENTRIES;
- }
-
- res.unlock();
+ ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
+ bool result = resolveAttrs(theme, defStyleAttr, defStyleRes,
+ (uint32_t*) srcValues, NSV,
+ (uint32_t*) src, NI,
+ (uint32_t*) baseDest,
+ (uint32_t*) indices);
if (indices != NULL) {
- indices[0] = indicesIdx;
env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
}
env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
env->ReleasePrimitiveArrayCritical(attrs, src, 0);
-
- return JNI_TRUE;
+ return result ? JNI_TRUE : JNI_FALSE;
}
static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
@@ -1370,18 +1208,6 @@
return JNI_FALSE;
}
- if (kDebugStyles) {
- ALOGI("APPLY STYLE: theme=0x%" PRIx64 " defStyleAttr=0x%x defStyleRes=0x%x "
- "xml=0x%" PRIx64, themeToken, defStyleAttr, defStyleRes,
- xmlParserToken);
- }
-
- ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
- const ResTable& res = theme->getResTable();
- ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
- ResTable_config config;
- Res_value value;
-
const jsize NI = env->GetArrayLength(attrs);
const jsize NV = env->GetArrayLength(outValues);
if (NV < (NI*STYLE_NUM_ENTRIES)) {
@@ -1395,211 +1221,32 @@
}
jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
- jint* dest = baseDest;
- if (dest == NULL) {
+ if (baseDest == NULL) {
env->ReleasePrimitiveArrayCritical(attrs, src, 0);
return JNI_FALSE;
}
jint* indices = NULL;
- int indicesIdx = 0;
if (outIndices != NULL) {
if (env->GetArrayLength(outIndices) > NI) {
indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
}
}
- // Load default style from attribute, if specified...
- uint32_t defStyleBagTypeSetFlags = 0;
- if (defStyleAttr != 0) {
- Res_value value;
- if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
- if (value.dataType == Res_value::TYPE_REFERENCE) {
- defStyleRes = value.data;
- }
- }
- }
-
- // Retrieve the style class associated with the current XML tag.
- int style = 0;
- uint32_t styleBagTypeSetFlags = 0;
- if (xmlParser != NULL) {
- ssize_t idx = xmlParser->indexOfStyle();
- if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
- if (value.dataType == value.TYPE_ATTRIBUTE) {
- if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
- value.dataType = Res_value::TYPE_NULL;
- }
- }
- if (value.dataType == value.TYPE_REFERENCE) {
- style = value.data;
- }
- }
- }
-
- // Now lock down the resource object and start pulling stuff from it.
- res.lock();
-
- // Retrieve the default style bag, if requested.
- const ResTable::bag_entry* defStyleAttrStart = NULL;
- uint32_t defStyleTypeSetFlags = 0;
- ssize_t bagOff = defStyleRes != 0
- ? res.getBagLocked(defStyleRes, &defStyleAttrStart, &defStyleTypeSetFlags) : -1;
- defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
- const ResTable::bag_entry* const defStyleAttrEnd = defStyleAttrStart + (bagOff >= 0 ? bagOff : 0);
- BagAttributeFinder defStyleAttrFinder(defStyleAttrStart, defStyleAttrEnd);
-
- // Retrieve the style class bag, if requested.
- const ResTable::bag_entry* styleAttrStart = NULL;
- uint32_t styleTypeSetFlags = 0;
- bagOff = style != 0 ? res.getBagLocked(style, &styleAttrStart, &styleTypeSetFlags) : -1;
- styleTypeSetFlags |= styleBagTypeSetFlags;
- const ResTable::bag_entry* const styleAttrEnd = styleAttrStart + (bagOff >= 0 ? bagOff : 0);
- BagAttributeFinder styleAttrFinder(styleAttrStart, styleAttrEnd);
-
- // Retrieve the XML attributes, if requested.
- static const ssize_t kXmlBlock = 0x10000000;
- XmlAttributeFinder xmlAttrFinder(xmlParser);
- const jsize xmlAttrEnd = xmlParser != NULL ? xmlParser->getAttributeCount() : 0;
-
- // Now iterate through all of the attributes that the client has requested,
- // filling in each with whatever data we can find.
- ssize_t block = 0;
- uint32_t typeSetFlags;
- for (jsize ii = 0; ii < NI; ii++) {
- const uint32_t curIdent = (uint32_t)src[ii];
-
- if (kDebugStyles) {
- ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
- }
-
- // Try to find a value for this attribute... we prioritize values
- // coming from, first XML attributes, then XML style, then default
- // style, and finally the theme.
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- typeSetFlags = 0;
- config.density = 0;
-
- // Walk through the xml attributes looking for the requested attribute.
- const jsize xmlAttrIdx = xmlAttrFinder.find(curIdent);
- if (xmlAttrIdx != xmlAttrEnd) {
- // We found the attribute we were looking for.
- block = kXmlBlock;
- xmlParser->getAttributeValue(xmlAttrIdx, &value);
- if (kDebugStyles) {
- ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- }
-
- if (value.dataType == Res_value::TYPE_NULL) {
- // Walk through the style class values looking for the requested attribute.
- const ResTable::bag_entry* const styleAttrEntry = styleAttrFinder.find(curIdent);
- if (styleAttrEntry != styleAttrEnd) {
- // We found the attribute we were looking for.
- block = styleAttrEntry->stringBlock;
- typeSetFlags = styleTypeSetFlags;
- value = styleAttrEntry->map.value;
- if (kDebugStyles) {
- ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- }
- }
-
- if (value.dataType == Res_value::TYPE_NULL) {
- // Walk through the default style values looking for the requested attribute.
- const ResTable::bag_entry* const defStyleAttrEntry = defStyleAttrFinder.find(curIdent);
- if (defStyleAttrEntry != defStyleAttrEnd) {
- // We found the attribute we were looking for.
- block = defStyleAttrEntry->stringBlock;
- typeSetFlags = styleTypeSetFlags;
- value = defStyleAttrEntry->map.value;
- if (kDebugStyles) {
- ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- }
- }
-
- uint32_t resid = 0;
- if (value.dataType != Res_value::TYPE_NULL) {
- // Take care of resolving the found resource to its final value.
- ssize_t newBlock = theme->resolveAttributeReference(&value, block,
- &resid, &typeSetFlags, &config);
- if (newBlock >= 0) {
- block = newBlock;
- }
-
- if (kDebugStyles) {
- ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- } else {
- // If we still don't have a value for this attribute, try to find
- // it in the theme!
- ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
- if (newBlock >= 0) {
- if (kDebugStyles) {
- ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- newBlock = res.resolveReference(&value, block, &resid,
- &typeSetFlags, &config);
- if (kThrowOnBadId) {
- if (newBlock == BAD_INDEX) {
- jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
- return JNI_FALSE;
- }
- }
-
- if (newBlock >= 0) {
- block = newBlock;
- }
-
- if (kDebugStyles) {
- ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- }
- }
-
- // Deal with the special @null value -- it turns back to TYPE_NULL.
- if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
- if (kDebugStyles) {
- ALOGI("-> Setting to @null!");
- }
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- block = kXmlBlock;
- }
-
- if (kDebugStyles) {
- ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType, value.data);
- }
-
- // Write the final value back to Java.
- dest[STYLE_TYPE] = value.dataType;
- dest[STYLE_DATA] = value.data;
- dest[STYLE_ASSET_COOKIE] = block != kXmlBlock ?
- static_cast<jint>(res.getTableCookie(block)) : -1;
- dest[STYLE_RESOURCE_ID] = resid;
- dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
- dest[STYLE_DENSITY] = config.density;
-
- if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
- indicesIdx++;
- indices[indicesIdx] = ii;
- }
-
- dest += STYLE_NUM_ENTRIES;
- }
-
- res.unlock();
+ ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
+ ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
+ bool result = applyStyle(theme, xmlParser,
+ defStyleAttr, defStyleRes,
+ (uint32_t*) src, NI,
+ (uint32_t*) baseDest,
+ (uint32_t*) indices);
if (indices != NULL) {
- indices[0] = indicesIdx;
env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
}
env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
env->ReleasePrimitiveArrayCritical(attrs, src, 0);
-
- return JNI_TRUE;
+ return result ? JNI_TRUE : JNI_FALSE;
}
static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
@@ -1627,8 +1274,6 @@
}
const ResTable& res(am->getResources());
ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
- ResTable_config config;
- Res_value value;
const jsize NI = env->GetArrayLength(attrs);
const jsize NV = env->GetArrayLength(outValues);
@@ -1643,108 +1288,29 @@
}
jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
- jint* dest = baseDest;
- if (dest == NULL) {
+ if (baseDest == NULL) {
env->ReleasePrimitiveArrayCritical(attrs, src, 0);
return JNI_FALSE;
}
jint* indices = NULL;
- int indicesIdx = 0;
if (outIndices != NULL) {
if (env->GetArrayLength(outIndices) > NI) {
indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
}
}
- // Now lock down the resource object and start pulling stuff from it.
- res.lock();
-
- // Retrieve the XML attributes, if requested.
- const jsize NX = xmlParser->getAttributeCount();
- jsize ix=0;
- uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
-
- static const ssize_t kXmlBlock = 0x10000000;
-
- // Now iterate through all of the attributes that the client has requested,
- // filling in each with whatever data we can find.
- ssize_t block = 0;
- uint32_t typeSetFlags;
- for (jsize ii=0; ii<NI; ii++) {
- const uint32_t curIdent = (uint32_t)src[ii];
-
- // Try to find a value for this attribute...
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- typeSetFlags = 0;
- config.density = 0;
-
- // Skip through XML attributes until the end or the next possible match.
- while (ix < NX && curIdent > curXmlAttr) {
- ix++;
- curXmlAttr = xmlParser->getAttributeNameResID(ix);
- }
- // Retrieve the current XML attribute if it matches, and step to next.
- if (ix < NX && curIdent == curXmlAttr) {
- block = kXmlBlock;
- xmlParser->getAttributeValue(ix, &value);
- ix++;
- curXmlAttr = xmlParser->getAttributeNameResID(ix);
- }
-
- //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
- uint32_t resid = 0;
- if (value.dataType != Res_value::TYPE_NULL) {
- // Take care of resolving the found resource to its final value.
- //printf("Resolving attribute reference\n");
- ssize_t newBlock = res.resolveReference(&value, block, &resid,
- &typeSetFlags, &config);
- if (kThrowOnBadId) {
- if (newBlock == BAD_INDEX) {
- jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
- return JNI_FALSE;
- }
- }
- if (newBlock >= 0) block = newBlock;
- }
-
- // Deal with the special @null value -- it turns back to TYPE_NULL.
- if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- }
-
- //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
-
- // Write the final value back to Java.
- dest[STYLE_TYPE] = value.dataType;
- dest[STYLE_DATA] = value.data;
- dest[STYLE_ASSET_COOKIE] =
- block != kXmlBlock ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
- dest[STYLE_RESOURCE_ID] = resid;
- dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
- dest[STYLE_DENSITY] = config.density;
-
- if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
- indicesIdx++;
- indices[indicesIdx] = ii;
- }
-
- dest += STYLE_NUM_ENTRIES;
- }
-
- res.unlock();
+ bool result = retrieveAttributes(&res, xmlParser,
+ (uint32_t*) src, NI,
+ (uint32_t*) baseDest,
+ (uint32_t*) indices);
if (indices != NULL) {
- indices[0] = indicesIdx;
env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
}
-
env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
env->ReleasePrimitiveArrayCritical(attrs, src, 0);
-
- return JNI_TRUE;
+ return result ? JNI_TRUE : JNI_FALSE;
}
static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,