Merge commit '06d8b7b8' into manualmerge
Conflicts: core/jni/android_util_AssetManager.cpp Change-Id: I77b72d0d3ec8184ccd97419e4c76b7d55b1a52ca
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <androidfw/Asset.h>
|
||||
#include <androidfw/AssetManager.h>
|
||||
#include <androidfw/AttributeFinder.h>
|
||||
#include <androidfw/ResourceTypes.h>
|
||||
|
||||
#include <private/android_filesystem_config.h> // for AID_SYSTEM
|
||||
@@ -1000,6 +1001,30 @@ static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
|
||||
theme->dumpToLog();
|
||||
}
|
||||
|
||||
class XmlAttributeFinder : public BackTrackingAttributeFinder<XmlAttributeFinder, jsize> {
|
||||
public:
|
||||
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,
|
||||
@@ -1077,13 +1102,13 @@ static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject c
|
||||
res.lock();
|
||||
|
||||
// Retrieve the default style bag, if requested.
|
||||
const ResTable::bag_entry* defStyleEnt = NULL;
|
||||
const ResTable::bag_entry* defStyleStart = NULL;
|
||||
uint32_t defStyleTypeSetFlags = 0;
|
||||
ssize_t bagOff = defStyleRes != 0
|
||||
? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
|
||||
? res.getBagLocked(defStyleRes, &defStyleStart, &defStyleTypeSetFlags) : -1;
|
||||
defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
|
||||
const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
|
||||
(bagOff >= 0 ? bagOff : 0);;
|
||||
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.
|
||||
@@ -1114,21 +1139,16 @@ static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject c
|
||||
}
|
||||
}
|
||||
|
||||
// Skip through the default style values until the end or the next possible match.
|
||||
while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
|
||||
defStyleEnt++;
|
||||
}
|
||||
// Retrieve the current default style attribute if it matches, and step to next.
|
||||
if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
|
||||
if (value.dataType == Res_value::TYPE_NULL) {
|
||||
block = defStyleEnt->stringBlock;
|
||||
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 = defStyleEnt->map.value;
|
||||
value = defStyleEntry->map.value;
|
||||
if (kDebugStyles) {
|
||||
ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
|
||||
}
|
||||
}
|
||||
defStyleEnt++;
|
||||
}
|
||||
|
||||
uint32_t resid = 0;
|
||||
@@ -1300,34 +1320,32 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla
|
||||
res.lock();
|
||||
|
||||
// Retrieve the default style bag, if requested.
|
||||
const ResTable::bag_entry* defStyleEnt = NULL;
|
||||
const ResTable::bag_entry* defStyleAttrStart = NULL;
|
||||
uint32_t defStyleTypeSetFlags = 0;
|
||||
ssize_t bagOff = defStyleRes != 0
|
||||
? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
|
||||
? res.getBagLocked(defStyleRes, &defStyleAttrStart, &defStyleTypeSetFlags) : -1;
|
||||
defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
|
||||
const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
|
||||
(bagOff >= 0 ? bagOff : 0);
|
||||
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* styleEnt = NULL;
|
||||
const ResTable::bag_entry* styleAttrStart = NULL;
|
||||
uint32_t styleTypeSetFlags = 0;
|
||||
bagOff = style != 0 ? res.getBagLocked(style, &styleEnt, &styleTypeSetFlags) : -1;
|
||||
bagOff = style != 0 ? res.getBagLocked(style, &styleAttrStart, &styleTypeSetFlags) : -1;
|
||||
styleTypeSetFlags |= styleBagTypeSetFlags;
|
||||
const ResTable::bag_entry* endStyleEnt = styleEnt +
|
||||
(bagOff >= 0 ? bagOff : 0);
|
||||
const ResTable::bag_entry* const styleAttrEnd = styleAttrStart + (bagOff >= 0 ? bagOff : 0);
|
||||
BagAttributeFinder styleAttrFinder(styleAttrStart, styleAttrEnd);
|
||||
|
||||
// Retrieve the XML attributes, if requested.
|
||||
const jsize NX = xmlParser ? xmlParser->getAttributeCount() : 0;
|
||||
jsize ix=0;
|
||||
uint32_t curXmlAttr = xmlParser ? xmlParser->getAttributeNameResID(ix) : 0;
|
||||
|
||||
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++) {
|
||||
for (jsize ii = 0; ii < NI; ii++) {
|
||||
const uint32_t curIdent = (uint32_t)src[ii];
|
||||
|
||||
if (kDebugStyles) {
|
||||
@@ -1342,54 +1360,43 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla
|
||||
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) {
|
||||
// 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(ix, &value);
|
||||
ix++;
|
||||
curXmlAttr = xmlParser->getAttributeNameResID(ix);
|
||||
xmlParser->getAttributeValue(xmlAttrIdx, &value);
|
||||
if (kDebugStyles) {
|
||||
ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
|
||||
}
|
||||
}
|
||||
|
||||
// Skip through the style values until the end or the next possible match.
|
||||
while (styleEnt < endStyleEnt && curIdent > styleEnt->map.name.ident) {
|
||||
styleEnt++;
|
||||
}
|
||||
// Retrieve the current style attribute if it matches, and step to next.
|
||||
if (styleEnt < endStyleEnt && curIdent == styleEnt->map.name.ident) {
|
||||
if (value.dataType == Res_value::TYPE_NULL) {
|
||||
block = styleEnt->stringBlock;
|
||||
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 = styleEnt->map.value;
|
||||
value = styleAttrEntry->map.value;
|
||||
if (kDebugStyles) {
|
||||
ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
|
||||
}
|
||||
}
|
||||
styleEnt++;
|
||||
}
|
||||
|
||||
// Skip through the default style values until the end or the next possible match.
|
||||
while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
|
||||
defStyleEnt++;
|
||||
}
|
||||
// Retrieve the current default style attribute if it matches, and step to next.
|
||||
if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
|
||||
if (value.dataType == Res_value::TYPE_NULL) {
|
||||
block = defStyleEnt->stringBlock;
|
||||
typeSetFlags = defStyleTypeSetFlags;
|
||||
value = defStyleEnt->map.value;
|
||||
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);
|
||||
}
|
||||
}
|
||||
defStyleEnt++;
|
||||
}
|
||||
|
||||
uint32_t resid = 0;
|
||||
@@ -1397,7 +1404,10 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla
|
||||
// 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 (newBlock >= 0) {
|
||||
block = newBlock;
|
||||
}
|
||||
|
||||
if (kDebugStyles) {
|
||||
ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
|
||||
}
|
||||
@@ -1417,7 +1427,11 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla
|
||||
return JNI_FALSE;
|
||||
}
|
||||
}
|
||||
if (newBlock >= 0) block = newBlock;
|
||||
|
||||
if (newBlock >= 0) {
|
||||
block = newBlock;
|
||||
}
|
||||
|
||||
if (kDebugStyles) {
|
||||
ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
|
||||
}
|
||||
@@ -1441,8 +1455,8 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla
|
||||
// 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_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;
|
||||
|
||||
201
include/androidfw/AttributeFinder.h
Normal file
201
include/androidfw/AttributeFinder.h
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef H_ATTRIBUTE_FINDER
|
||||
#define H_ATTRIBUTE_FINDER
|
||||
|
||||
#include <stdint.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
static inline uint32_t getPackage(uint32_t attr) {
|
||||
return attr >> 24;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper class to search linearly for the requested
|
||||
* attribute, maintaining it's position and optimizing for
|
||||
* the case that subsequent searches will involve an attribute with
|
||||
* a higher attribute ID.
|
||||
*
|
||||
* In the case that a subsequent attribute has a different package ID,
|
||||
* its resource ID may not be larger than the preceding search, so
|
||||
* back tracking is supported for this case. This
|
||||
* back tracking requirement is mainly for shared library
|
||||
* resources, whose package IDs get assigned at runtime
|
||||
* and thus attributes from a shared library may
|
||||
* be out of order.
|
||||
*
|
||||
* We make two assumptions about the order of attributes:
|
||||
* 1) The input has the same sorting rules applied to it as
|
||||
* the attribute data contained by this class.
|
||||
* 2) Attributes are grouped by package ID.
|
||||
* 3) Among attributes with the same package ID, the attributes are
|
||||
* sorted by increasing resource ID.
|
||||
*
|
||||
* Ex: 02010000, 02010001, 010100f4, 010100f5, 0x7f010001, 07f010003
|
||||
*
|
||||
* The total order of attributes (including package ID) can not be linear
|
||||
* as shared libraries get assigned dynamic package IDs at runtime, which
|
||||
* may break the sort order established at build time.
|
||||
*/
|
||||
template <typename Derived, typename Iterator>
|
||||
class BackTrackingAttributeFinder {
|
||||
public:
|
||||
BackTrackingAttributeFinder(const Iterator& begin, const Iterator& end);
|
||||
|
||||
Iterator find(uint32_t attr);
|
||||
|
||||
private:
|
||||
void jumpToClosestAttribute(uint32_t packageId);
|
||||
void markCurrentPackageId(uint32_t packageId);
|
||||
|
||||
Iterator mBegin;
|
||||
Iterator mEnd;
|
||||
Iterator mCurrent;
|
||||
Iterator mLargest;
|
||||
uint32_t mLastPackageId;
|
||||
uint32_t mCurrentAttr;
|
||||
|
||||
// Package Offsets (best-case, fast look-up).
|
||||
Iterator mFrameworkStart;
|
||||
Iterator mAppStart;
|
||||
|
||||
// Worst case, we have shared-library resources.
|
||||
KeyedVector<uint32_t, Iterator> mPackageOffsets;
|
||||
};
|
||||
|
||||
template <typename Derived, typename Iterator> inline
|
||||
BackTrackingAttributeFinder<Derived, Iterator>::BackTrackingAttributeFinder(const Iterator& begin, const Iterator& end)
|
||||
: mBegin(begin)
|
||||
, mEnd(end)
|
||||
, mCurrent(begin)
|
||||
, mLargest(begin)
|
||||
, mLastPackageId(0)
|
||||
, mCurrentAttr(0)
|
||||
, mFrameworkStart(end)
|
||||
, mAppStart(end) {
|
||||
}
|
||||
|
||||
template <typename Derived, typename Iterator>
|
||||
void BackTrackingAttributeFinder<Derived, Iterator>::jumpToClosestAttribute(const uint32_t packageId) {
|
||||
switch (packageId) {
|
||||
case 0x01:
|
||||
mCurrent = mFrameworkStart;
|
||||
break;
|
||||
case 0x7f:
|
||||
mCurrent = mAppStart;
|
||||
break;
|
||||
default: {
|
||||
ssize_t idx = mPackageOffsets.indexOfKey(packageId);
|
||||
if (idx >= 0) {
|
||||
// We have seen this package ID before, so jump to the first
|
||||
// attribute with this package ID.
|
||||
mCurrent = mPackageOffsets[idx];
|
||||
} else {
|
||||
mCurrent = mEnd;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We have never seen this package ID yet, so jump to the
|
||||
// latest/largest index we have processed so far.
|
||||
if (mCurrent == mEnd) {
|
||||
mCurrent = mLargest;
|
||||
}
|
||||
|
||||
if (mCurrent != mEnd) {
|
||||
mCurrentAttr = static_cast<const Derived*>(this)->getAttribute(mCurrent);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Derived, typename Iterator>
|
||||
void BackTrackingAttributeFinder<Derived, Iterator>::markCurrentPackageId(const uint32_t packageId) {
|
||||
switch (packageId) {
|
||||
case 0x01:
|
||||
mFrameworkStart = mCurrent;
|
||||
break;
|
||||
case 0x7f:
|
||||
mAppStart = mCurrent;
|
||||
break;
|
||||
default:
|
||||
mPackageOffsets.add(packageId, mCurrent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Derived, typename Iterator>
|
||||
Iterator BackTrackingAttributeFinder<Derived, Iterator>::find(uint32_t attr) {
|
||||
if (!(mBegin < mEnd)) {
|
||||
return mEnd;
|
||||
}
|
||||
|
||||
if (mCurrentAttr == 0) {
|
||||
// One-time initialization.
|
||||
mCurrentAttr = static_cast<const Derived*>(this)->getAttribute(mBegin);
|
||||
mLastPackageId = getPackage(mCurrentAttr);
|
||||
markCurrentPackageId(mLastPackageId);
|
||||
}
|
||||
|
||||
// Looking for the needle (attribute we're looking for)
|
||||
// in the haystack (the attributes we're searching through)
|
||||
const uint32_t needlePackageId = getPackage(attr);
|
||||
if (mLastPackageId != needlePackageId) {
|
||||
jumpToClosestAttribute(needlePackageId);
|
||||
mLastPackageId = needlePackageId;
|
||||
}
|
||||
|
||||
// Walk through the xml attributes looking for the requested attribute.
|
||||
while (mCurrent != mEnd) {
|
||||
const uint32_t haystackPackageId = getPackage(mCurrentAttr);
|
||||
if (needlePackageId == haystackPackageId && attr < mCurrentAttr) {
|
||||
// The attribute we are looking was not found.
|
||||
break;
|
||||
}
|
||||
const uint32_t prevAttr = mCurrentAttr;
|
||||
|
||||
// Move to the next attribute in the XML.
|
||||
++mCurrent;
|
||||
if (mCurrent != mEnd) {
|
||||
mCurrentAttr = static_cast<const Derived*>(this)->getAttribute(mCurrent);
|
||||
const uint32_t newHaystackPackageId = getPackage(mCurrentAttr);
|
||||
if (haystackPackageId != newHaystackPackageId) {
|
||||
// We've moved to the next group of attributes
|
||||
// with a new package ID, so we should record
|
||||
// the offset of this new package ID.
|
||||
markCurrentPackageId(newHaystackPackageId);
|
||||
}
|
||||
}
|
||||
|
||||
if (mCurrent > mLargest) {
|
||||
// We've moved past the latest attribute we've
|
||||
// seen.
|
||||
mLargest = mCurrent;
|
||||
}
|
||||
|
||||
if (attr == prevAttr) {
|
||||
// We found the attribute we were looking for.
|
||||
return mCurrent - 1;
|
||||
}
|
||||
}
|
||||
return mEnd;
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // H_ATTRIBUTE_FINDER
|
||||
@@ -1220,7 +1220,11 @@ uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const
|
||||
{
|
||||
int32_t id = getAttributeNameID(idx);
|
||||
if (id >= 0 && (size_t)id < mTree.mNumResIds) {
|
||||
return dtohl(mTree.mResIds[id]);
|
||||
uint32_t resId = dtohl(mTree.mResIds[id]);
|
||||
if (mTree.mDynamicRefTable != NULL) {
|
||||
mTree.mDynamicRefTable->lookupResourceId(&resId);
|
||||
}
|
||||
return resId;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -6142,11 +6146,11 @@ status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const {
|
||||
// Do a proper lookup.
|
||||
uint8_t translatedId = mLookupTable[packageId];
|
||||
if (translatedId == 0) {
|
||||
ALOGE("DynamicRefTable(0x%02x): No mapping for build-time package ID 0x%02x.",
|
||||
ALOGV("DynamicRefTable(0x%02x): No mapping for build-time package ID 0x%02x.",
|
||||
(uint8_t)mAssignedPackageId, (uint8_t)packageId);
|
||||
for (size_t i = 0; i < 256; i++) {
|
||||
if (mLookupTable[i] != 0) {
|
||||
ALOGE("e[0x%02x] -> 0x%02x", (uint8_t)i, mLookupTable[i]);
|
||||
ALOGV("e[0x%02x] -> 0x%02x", (uint8_t)i, mLookupTable[i]);
|
||||
}
|
||||
}
|
||||
return UNKNOWN_ERROR;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
# ==========================================================
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
testFiles := \
|
||||
AttributeFinder_test.cpp \
|
||||
ByteBucketArray_test.cpp \
|
||||
Config_test.cpp \
|
||||
ConfigLocale_test.cpp \
|
||||
|
||||
111
libs/androidfw/tests/AttributeFinder_test.cpp
Normal file
111
libs/androidfw/tests/AttributeFinder_test.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <androidfw/AttributeFinder.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using android::BackTrackingAttributeFinder;
|
||||
|
||||
class MockAttributeFinder : public BackTrackingAttributeFinder<MockAttributeFinder, int> {
|
||||
public:
|
||||
MockAttributeFinder(const uint32_t* attrs, int len)
|
||||
: BackTrackingAttributeFinder(0, len) {
|
||||
mAttrs = new uint32_t[len];
|
||||
memcpy(mAttrs, attrs, sizeof(*attrs) * len);
|
||||
}
|
||||
|
||||
~MockAttributeFinder() {
|
||||
delete mAttrs;
|
||||
}
|
||||
|
||||
inline uint32_t getAttribute(const int index) const {
|
||||
return mAttrs[index];
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t* mAttrs;
|
||||
};
|
||||
|
||||
static const uint32_t sortedAttributes[] = {
|
||||
0x01010000, 0x01010001, 0x01010002, 0x01010004,
|
||||
0x02010001, 0x02010010, 0x7f010001
|
||||
};
|
||||
|
||||
static const uint32_t packageUnsortedAttributes[] = {
|
||||
0x02010001, 0x02010010, 0x01010000, 0x01010001,
|
||||
0x01010002, 0x01010004, 0x7f010001
|
||||
};
|
||||
|
||||
TEST(AttributeFinderTest, IteratesSequentially) {
|
||||
const int end = sizeof(sortedAttributes) / sizeof(*sortedAttributes);
|
||||
MockAttributeFinder finder(sortedAttributes, end);
|
||||
|
||||
EXPECT_EQ(0, finder.find(0x01010000));
|
||||
EXPECT_EQ(1, finder.find(0x01010001));
|
||||
EXPECT_EQ(2, finder.find(0x01010002));
|
||||
EXPECT_EQ(3, finder.find(0x01010004));
|
||||
EXPECT_EQ(4, finder.find(0x02010001));
|
||||
EXPECT_EQ(5, finder.find(0x02010010));
|
||||
EXPECT_EQ(6, finder.find(0x7f010001));
|
||||
EXPECT_EQ(end, finder.find(0x7f010002));
|
||||
}
|
||||
|
||||
TEST(AttributeFinderTest, PackagesAreOutOfOrder) {
|
||||
const int end = sizeof(sortedAttributes) / sizeof(*sortedAttributes);
|
||||
MockAttributeFinder finder(sortedAttributes, end);
|
||||
|
||||
EXPECT_EQ(6, finder.find(0x7f010001));
|
||||
EXPECT_EQ(end, finder.find(0x7f010002));
|
||||
EXPECT_EQ(4, finder.find(0x02010001));
|
||||
EXPECT_EQ(5, finder.find(0x02010010));
|
||||
EXPECT_EQ(0, finder.find(0x01010000));
|
||||
EXPECT_EQ(1, finder.find(0x01010001));
|
||||
EXPECT_EQ(2, finder.find(0x01010002));
|
||||
EXPECT_EQ(3, finder.find(0x01010004));
|
||||
}
|
||||
|
||||
TEST(AttributeFinderTest, SomeAttributesAreNotFound) {
|
||||
const int end = sizeof(sortedAttributes) / sizeof(*sortedAttributes);
|
||||
MockAttributeFinder finder(sortedAttributes, end);
|
||||
|
||||
EXPECT_EQ(0, finder.find(0x01010000));
|
||||
EXPECT_EQ(1, finder.find(0x01010001));
|
||||
EXPECT_EQ(2, finder.find(0x01010002));
|
||||
EXPECT_EQ(end, finder.find(0x01010003));
|
||||
EXPECT_EQ(3, finder.find(0x01010004));
|
||||
EXPECT_EQ(end, finder.find(0x01010005));
|
||||
EXPECT_EQ(end, finder.find(0x01010006));
|
||||
EXPECT_EQ(4, finder.find(0x02010001));
|
||||
EXPECT_EQ(end, finder.find(0x02010002));
|
||||
}
|
||||
|
||||
TEST(AttributeFinderTest, FindAttributesInPackageUnsortedAttributeList) {
|
||||
const int end = sizeof(packageUnsortedAttributes) / sizeof(*packageUnsortedAttributes);
|
||||
MockAttributeFinder finder(packageUnsortedAttributes, end);
|
||||
|
||||
EXPECT_EQ(2, finder.find(0x01010000));
|
||||
EXPECT_EQ(3, finder.find(0x01010001));
|
||||
EXPECT_EQ(4, finder.find(0x01010002));
|
||||
EXPECT_EQ(end, finder.find(0x01010003));
|
||||
EXPECT_EQ(5, finder.find(0x01010004));
|
||||
EXPECT_EQ(end, finder.find(0x01010005));
|
||||
EXPECT_EQ(end, finder.find(0x01010006));
|
||||
EXPECT_EQ(0, finder.find(0x02010001));
|
||||
EXPECT_EQ(end, finder.find(0x02010002));
|
||||
EXPECT_EQ(1, finder.find(0x02010010));
|
||||
EXPECT_EQ(6, finder.find(0x7f010001));
|
||||
}
|
||||
Reference in New Issue
Block a user