diff options
author | Kenny Root <kroot@google.com> | 2010-02-22 22:36:26 -0800 |
---|---|---|
committer | Kenny Root <kroot@google.com> | 2010-02-23 10:02:20 -0800 |
commit | 780d2a1b714724d85227141c76b3c64f543f00b4 (patch) | |
tree | 3bd5411acce1ae663e4509c812b3aaa6100c6a41 | |
parent | cfe79e9220c996ed9f60fbc00eebb23e7faba2f0 (diff) | |
download | frameworks_base-780d2a1b714724d85227141c76b3c64f543f00b4.zip frameworks_base-780d2a1b714724d85227141c76b3c64f543f00b4.tar.gz frameworks_base-780d2a1b714724d85227141c76b3c64f543f00b4.tar.bz2 |
Use UTF-8 strings to avoid duplicate caching, part 1
StringBlock instances containing UTF-8 strings use a cache to convert
into UTF-16, but using that cache and then using a JNI call to NewString
causes the UTF-8 string as well as two copies of the UTF-16 string to
be held in memory. Getting the UTF-8 string directly from the StringPool
eliminates one copy of the UTF-16 string being held in memory.
This is part 1. Part 2 will include ResXMLParser optimizations.
Change-Id: Ibd4509a485db746d59cd4b9501f544877139276c
-rw-r--r-- | core/jni/android_util_AssetManager.cpp | 22 | ||||
-rw-r--r-- | core/jni/android_util_StringBlock.cpp | 5 | ||||
-rw-r--r-- | include/utils/ResourceTypes.h | 2 | ||||
-rw-r--r-- | libs/utils/ResourceTypes.cpp | 45 | ||||
-rw-r--r-- | tools/aapt/StringPool.cpp | 8 |
5 files changed, 66 insertions, 16 deletions
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index a82a21e..5afa034 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -1466,19 +1466,25 @@ static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* for (size_t i=0; ((ssize_t)i)<N; i++, bag++) { value = bag->map.value; jstring str = NULL; - + // Take care of resolving the found resource to its final value. ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL); if (value.dataType == Res_value::TYPE_STRING) { - const char16_t* str16 = res.getTableStringBlock(block)->stringAt(value.data, &strLen); - str = env->NewString(str16, strLen); - if (str == NULL) { - doThrow(env, "java/lang/OutOfMemoryError"); - res.unlockBag(startOfBag); - return NULL; + const ResStringPool* pool = res.getTableStringBlock(block); + const char* str8 = pool->string8At(value.data, &strLen); + if (str8 != NULL) { + str = env->NewStringUTF(str8); + } else { + const char16_t* str16 = pool->stringAt(value.data, &strLen); + str = env->NewString(str16, strLen); + if (str == NULL) { + doThrow(env, "java/lang/OutOfMemoryError"); + res.unlockBag(startOfBag); + return NULL; + } } } - + env->SetObjectArrayElement(array, i, str); } res.unlockBag(startOfBag); diff --git a/core/jni/android_util_StringBlock.cpp b/core/jni/android_util_StringBlock.cpp index ffb271c..641fbce 100644 --- a/core/jni/android_util_StringBlock.cpp +++ b/core/jni/android_util_StringBlock.cpp @@ -89,6 +89,11 @@ static jstring android_content_StringBlock_nativeGetString(JNIEnv* env, jobject } size_t len; + const char* str8 = osb->string8At(idx, &len); + if (str8 != NULL) { + return env->NewStringUTF(str8); + } + const char16_t* str = osb->stringAt(idx, &len); if (str == NULL) { doThrow(env, "java/lang/IndexOutOfBoundsException"); diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h index 13ea27e..cd657e8 100644 --- a/include/utils/ResourceTypes.h +++ b/include/utils/ResourceTypes.h @@ -447,6 +447,8 @@ public: } const char16_t* stringAt(size_t idx, size_t* outLen) const; + const char* string8At(size_t idx, size_t* outLen) const; + const ResStringPool_span* styleAt(const ResStringPool_ref& ref) const; const ResStringPool_span* styleAt(size_t idx) const; diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp index e8bd5cf..38600b9 100644 --- a/libs/utils/ResourceTypes.cpp +++ b/libs/utils/ResourceTypes.cpp @@ -497,6 +497,34 @@ const uint16_t* ResStringPool::stringAt(size_t idx, size_t* outLen) const return NULL; } +const char* ResStringPool::string8At(size_t idx, size_t* outLen) const +{ + if (mError == NO_ERROR && idx < mHeader->stringCount) { + const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0; + const uint32_t off = mEntries[idx]/(isUTF8?sizeof(char):sizeof(char16_t)); + if (off < (mStringPoolSize-1)) { + if (isUTF8) { + const uint8_t* strings = (uint8_t*)mStrings; + const uint8_t* str = strings+off; + DECODE_LENGTH(str, sizeof(uint8_t), *outLen) + size_t encLen; + DECODE_LENGTH(str, sizeof(uint8_t), encLen) + if ((uint32_t)(str+encLen-strings) < mStringPoolSize) { + return (const char*)str; + } else { + LOGW("Bad string block: string #%d extends to %d, past end at %d\n", + (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize); + } + } + } else { + LOGW("Bad string block: string #%d entry is at %d, past end at %d\n", + (int)idx, (int)(off*sizeof(uint16_t)), + (int)(mStringPoolSize*sizeof(uint16_t))); + } + } + return NULL; +} + const ResStringPool_span* ResStringPool::styleAt(const ResStringPool_ref& ref) const { return styleAt(ref.index); @@ -4018,14 +4046,19 @@ void ResTable::print_value(const Package* pkg, const Res_value& value) const printf("(attribute) 0x%08x\n", value.data); } else if (value.dataType == Res_value::TYPE_STRING) { size_t len; - const char16_t* str = pkg->header->values.stringAt( + const char* str8 = pkg->header->values.string8At( value.data, &len); - if (str == NULL) { - printf("(string) null\n"); + if (str8 != NULL) { + printf("(string8) \"%s\"\n", str8); } else { - printf("(string%d) \"%s\"\n", - pkg->header->values.isUTF8()?8:16, - String8(str, len).string()); + const char16_t* str16 = pkg->header->values.stringAt( + value.data, &len); + if (str16 != NULL) { + printf("(string16) \"%s\"\n", + String8(str16, len).string()); + } else { + printf("(string) null\n"); + } } } else if (value.dataType == Res_value::TYPE_FLOAT) { printf("(float) %g\n", *(const float*)&value.data); diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp index 51afc0a..a09cec0 100644 --- a/tools/aapt/StringPool.cpp +++ b/tools/aapt/StringPool.cpp @@ -25,8 +25,12 @@ void printStringPool(const ResStringPool* pool) const size_t NS = pool->size(); for (size_t s=0; s<NS; s++) { size_t len; - printf("String #%ld: %s\n", s, - String8(pool->stringAt(s, &len)).string()); + const char *str = (const char*)pool->string8At(s, &len); + if (str == NULL) { + str = String8(pool->stringAt(s, &len)).string(); + } + + printf("String #%ld: %s\n", s, str); } } |