OSDN Git Service

Check for null-terminator in ResStringPool::string8At
[android-x86/frameworks-base.git] / libs / androidfw / ResourceTypes.cpp
index bdb53c3..7cb4216 100644 (file)
 #define LOG_TAG "ResourceType"
 //#define LOG_NDEBUG 0
 
+#include <ctype.h>
+#include <memory.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <type_traits>
+
 #include <androidfw/ByteBucketArray.h>
 #include <androidfw/ResourceTypes.h>
 #include <androidfw/TypeWrappers.h>
 #include <utils/String16.h>
 #include <utils/String8.h>
 
-#include <stdlib.h>
-#include <string.h>
-#include <memory.h>
-#include <ctype.h>
-#include <stdint.h>
-#include <stddef.h>
+#ifdef __ANDROID__
+#include <binder/TextOutput.h>
+#endif
 
 #ifndef INT32_MAX
 #define INT32_MAX ((int32_t)(2147483647))
 #endif
 
-#define STRING_POOL_NOISY(x) //x
-#define XML_NOISY(x) //x
-#define TABLE_NOISY(x) //x
-#define TABLE_GETENTRY(x) //x
-#define TABLE_SUPER_NOISY(x) //x
-#define LOAD_TABLE_NOISY(x) //x
-#define TABLE_THEME(x) //x
-#define LIB_NOISY(x) //x
-
 namespace android {
 
-#ifdef HAVE_WINSOCK
+#if defined(_WIN32)
 #undef  nhtol
 #undef  htonl
-
-#ifdef HAVE_LITTLE_ENDIAN
 #define ntohl(x)    ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
 #define htonl(x)    ntohl(x)
 #define ntohs(x)    ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
 #define htons(x)    ntohs(x)
-#else
-#define ntohl(x)    (x)
-#define htonl(x)    (x)
-#define ntohs(x)    (x)
-#define htons(x)    (x)
-#endif
 #endif
 
 #define IDMAP_MAGIC             0x504D4449
@@ -72,6 +64,19 @@ namespace android {
 #define APP_PACKAGE_ID      0x7f
 #define SYS_PACKAGE_ID      0x01
 
+static const bool kDebugStringPoolNoisy = false;
+static const bool kDebugXMLNoisy = false;
+static const bool kDebugTableNoisy = false;
+static const bool kDebugTableGetEntry = false;
+static const bool kDebugTableSuperNoisy = false;
+static const bool kDebugLoadTableNoisy = false;
+static const bool kDebugLoadTableSuperNoisy = false;
+static const bool kDebugTableTheme = false;
+static const bool kDebugResXMLTree = false;
+static const bool kDebugLibNoisy = false;
+
+// TODO: This code uses 0xFFFFFFFF converted to bag_set* as a sentinel value. This is bad practice.
+
 // Standard C isspace() is only required to look at the low byte of its input, so
 // produces incorrect results for UTF-16 characters.  For safety's sake, assume that
 // any high-byte UTF-16 code point is not whitespace.
@@ -557,7 +562,7 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
 
         if ((mHeader->flags&ResStringPool_header::UTF8_FLAG &&
                 ((uint8_t*)mStrings)[mStringPoolSize-1] != 0) ||
-                (!mHeader->flags&ResStringPool_header::UTF8_FLAG &&
+                (!(mHeader->flags&ResStringPool_header::UTF8_FLAG) &&
                 ((uint16_t*)mStrings)[mStringPoolSize-1] != 0)) {
             ALOGW("Bad string block: last string is not 0-terminated\n");
             return (mError=BAD_TYPE);
@@ -701,6 +706,12 @@ const char16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const
 
                 *u16len = decodeLength(&str);
                 if ((uint32_t)(str+*u16len-strings) < mStringPoolSize) {
+                    // Reject malformed (non null-terminated) strings
+                    if (str[*u16len] != 0x0000) {
+                        ALOGW("Bad string block: string #%d is not null-terminated",
+                              (int)idx);
+                        return NULL;
+                    }
                     return reinterpret_cast<const char16_t*>(str);
                 } else {
                     ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
@@ -718,13 +729,15 @@ const char16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const
                     AutoMutex lock(mDecodeLock);
 
                     if (mCache == NULL) {
-#ifndef HAVE_ANDROID_OS
-                        STRING_POOL_NOISY(ALOGI("CREATING STRING CACHE OF %d bytes",
-                                mHeader->stringCount*sizeof(char16_t**)));
+#ifndef __ANDROID__
+                        if (kDebugStringPoolNoisy) {
+                            ALOGI("CREATING STRING CACHE OF %zu bytes",
+                                    mHeader->stringCount*sizeof(char16_t**));
+                        }
 #else
                         // We do not want to be in this case when actually running Android.
-                        ALOGW("CREATING STRING CACHE OF %d bytes",
-                                mHeader->stringCount*sizeof(char16_t**));
+                        ALOGW("CREATING STRING CACHE OF %zu bytes",
+                                static_cast<size_t>(mHeader->stringCount*sizeof(char16_t**)));
 #endif
                         mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**));
                         if (mCache == NULL) {
@@ -746,6 +759,13 @@ const char16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const
                         return NULL;
                     }
 
+                    // Reject malformed (non null-terminated) strings
+                    if (u8str[u8len] != 0x00) {
+                        ALOGW("Bad string block: string #%d is not null-terminated",
+                              (int)idx);
+                        return NULL;
+                    }
+
                     char16_t *u16str = (char16_t *)calloc(*u16len+1, sizeof(char16_t));
                     if (!u16str) {
                         ALOGW("No memory when trying to allocate decode cache for string #%d\n",
@@ -753,7 +773,9 @@ const char16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const
                         return NULL;
                     }
 
-                    STRING_POOL_NOISY(ALOGI("Caching UTF8 string: %s", u8str));
+                    if (kDebugStringPoolNoisy) {
+                        ALOGI("Caching UTF8 string: %s", u8str);
+                    }
                     utf8_to_utf16(u8str, u8len, u16str);
                     mCache[idx] = u16str;
                     return u16str;
@@ -785,7 +807,13 @@ const char* ResStringPool::string8At(size_t idx, size_t* outLen) const
             *outLen = decodeLength(&str);
             size_t encLen = decodeLength(&str);
             if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
-                return (const char*)str;
+                // Reject malformed (non null-terminated) strings
+                if (str[encLen] != 0x00) {
+                    ALOGW("Bad string block: string #%d is not null-terminated",
+                          (int)idx);
+                    return NULL;
+                }
+              return (const char*)str;
             } else {
                 ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
                         (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize);
@@ -843,7 +871,9 @@ ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const
     size_t len;
 
     if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) {
-        STRING_POOL_NOISY(ALOGI("indexOfString UTF-8: %s", String8(str, strLen).string()));
+        if (kDebugStringPoolNoisy) {
+            ALOGI("indexOfString UTF-8: %s", String8(str, strLen).string());
+        }
 
         // The string pool contains UTF 8 strings; we don't want to cause
         // temporary UTF-16 strings to be created as we search.
@@ -869,10 +899,14 @@ ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const
                 } else {
                     c = -1;
                 }
-                STRING_POOL_NOISY(ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
-                             (const char*)s, c, (int)l, (int)mid, (int)h));
+                if (kDebugStringPoolNoisy) {
+                    ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
+                            (const char*)s, c, (int)l, (int)mid, (int)h);
+                }
                 if (c == 0) {
-                    STRING_POOL_NOISY(ALOGI("MATCH!"));
+                    if (kDebugStringPoolNoisy) {
+                        ALOGI("MATCH!");
+                    }
                     free(convBuffer);
                     return mid;
                 } else if (c < 0) {
@@ -891,18 +925,22 @@ ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const
             const size_t str8Len = str8.size();
             for (int i=mHeader->stringCount-1; i>=0; i--) {
                 const char* s = string8At(i, &len);
-                STRING_POOL_NOISY(ALOGI("Looking at %s, i=%d\n",
-                             String8(s).string(),
-                             i));
+                if (kDebugStringPoolNoisy) {
+                    ALOGI("Looking at %s, i=%d\n", String8(s).string(), i);
+                }
                 if (s && str8Len == len && memcmp(s, str8.string(), str8Len) == 0) {
-                    STRING_POOL_NOISY(ALOGI("MATCH!"));
+                    if (kDebugStringPoolNoisy) {
+                        ALOGI("MATCH!");
+                    }
                     return i;
                 }
             }
         }
 
     } else {
-        STRING_POOL_NOISY(ALOGI("indexOfString UTF-16: %s", String8(str, strLen).string()));
+        if (kDebugStringPoolNoisy) {
+            ALOGI("indexOfString UTF-16: %s", String8(str, strLen).string());
+        }
 
         if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
             // Do a binary search for the string...
@@ -914,11 +952,14 @@ ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const
                 mid = l + (h - l)/2;
                 const char16_t* s = stringAt(mid, &len);
                 int c = s ? strzcmp16(s, len, str, strLen) : -1;
-                STRING_POOL_NOISY(ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
-                             String8(s).string(),
-                             c, (int)l, (int)mid, (int)h));
+                if (kDebugStringPoolNoisy) {
+                    ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
+                            String8(s).string(), c, (int)l, (int)mid, (int)h);
+                }
                 if (c == 0) {
-                    STRING_POOL_NOISY(ALOGI("MATCH!"));
+                    if (kDebugStringPoolNoisy) {
+                        ALOGI("MATCH!");
+                    }
                     return mid;
                 } else if (c < 0) {
                     l = mid + 1;
@@ -933,11 +974,13 @@ ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const
             // block, start searching at the back.
             for (int i=mHeader->stringCount-1; i>=0; i--) {
                 const char16_t* s = stringAt(i, &len);
-                STRING_POOL_NOISY(ALOGI("Looking at %s, i=%d\n",
-                             String8(s).string(),
-                             i));
+                if (kDebugStringPoolNoisy) {
+                    ALOGI("Looking at %s, i=%d\n", String8(s).string(), i);
+                }
                 if (s && strLen == len && strzcmp16(s, len, str, strLen) == 0) {
-                    STRING_POOL_NOISY(ALOGI("MATCH!"));
+                    if (kDebugStringPoolNoisy) {
+                        ALOGI("MATCH!");
+                    }
                     return i;
                 }
             }
@@ -1138,7 +1181,9 @@ const char16_t* ResXMLParser::getAttributeNamespace(size_t idx, size_t* outLen)
 {
     int32_t id = getAttributeNamespaceID(idx);
     //printf("attribute namespace=%d  idx=%d  event=%p\n", id, idx, mEventCode);
-    //XML_NOISY(printf("getAttributeNamespace 0x%x=0x%x\n", idx, id));
+    if (kDebugXMLNoisy) {
+        printf("getAttributeNamespace 0x%zx=0x%x\n", idx, id);
+    }
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
@@ -1146,7 +1191,9 @@ const char* ResXMLParser::getAttributeNamespace8(size_t idx, size_t* outLen) con
 {
     int32_t id = getAttributeNamespaceID(idx);
     //printf("attribute namespace=%d  idx=%d  event=%p\n", id, idx, mEventCode);
-    //XML_NOISY(printf("getAttributeNamespace 0x%x=0x%x\n", idx, id));
+    if (kDebugXMLNoisy) {
+        printf("getAttributeNamespace 0x%zx=0x%x\n", idx, id);
+    }
     return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL;
 }
 
@@ -1169,7 +1216,9 @@ const char16_t* ResXMLParser::getAttributeName(size_t idx, size_t* outLen) const
 {
     int32_t id = getAttributeNameID(idx);
     //printf("attribute name=%d  idx=%d  event=%p\n", id, idx, mEventCode);
-    //XML_NOISY(printf("getAttributeName 0x%x=0x%x\n", idx, id));
+    if (kDebugXMLNoisy) {
+        printf("getAttributeName 0x%zx=0x%x\n", idx, id);
+    }
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
@@ -1177,7 +1226,9 @@ const char* ResXMLParser::getAttributeName8(size_t idx, size_t* outLen) const
 {
     int32_t id = getAttributeNameID(idx);
     //printf("attribute name=%d  idx=%d  event=%p\n", id, idx, mEventCode);
-    //XML_NOISY(printf("getAttributeName 0x%x=0x%x\n", idx, id));
+    if (kDebugXMLNoisy) {
+        printf("getAttributeName 0x%zx=0x%x\n", idx, id);
+    }
     return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL;
 }
 
@@ -1212,7 +1263,9 @@ int32_t ResXMLParser::getAttributeValueStringID(size_t idx) const
 const char16_t* ResXMLParser::getAttributeStringValue(size_t idx, size_t* outLen) const
 {
     int32_t id = getAttributeValueStringID(idx);
-    //XML_NOISY(printf("getAttributeValue 0x%x=0x%x\n", idx, id));
+    if (kDebugXMLNoisy) {
+        printf("getAttributeValue 0x%zx=0x%x\n", idx, id);
+    }
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
@@ -1303,54 +1356,69 @@ ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen,
                 ns8 = String8(ns, nsLen);
             }
             attr8 = String8(attr, attrLen);
-            STRING_POOL_NOISY(ALOGI("indexOfAttribute UTF8 %s (%d) / %s (%d)", ns8.string(), nsLen,
-                    attr8.string(), attrLen));
+            if (kDebugStringPoolNoisy) {
+                ALOGI("indexOfAttribute UTF8 %s (%zu) / %s (%zu)", ns8.string(), nsLen,
+                        attr8.string(), attrLen);
+            }
             for (size_t i=0; i<N; i++) {
                 size_t curNsLen = 0, curAttrLen = 0;
                 const char* curNs = getAttributeNamespace8(i, &curNsLen);
                 const char* curAttr = getAttributeName8(i, &curAttrLen);
-                STRING_POOL_NOISY(ALOGI("  curNs=%s (%d), curAttr=%s (%d)", curNs, curNsLen,
-                        curAttr, curAttrLen));
+                if (kDebugStringPoolNoisy) {
+                    ALOGI("  curNs=%s (%zu), curAttr=%s (%zu)", curNs, curNsLen, curAttr, curAttrLen);
+                }
                 if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen
                         && memcmp(attr8.string(), curAttr, attrLen) == 0) {
                     if (ns == NULL) {
                         if (curNs == NULL) {
-                            STRING_POOL_NOISY(ALOGI("  FOUND!"));
+                            if (kDebugStringPoolNoisy) {
+                                ALOGI("  FOUND!");
+                            }
                             return i;
                         }
                     } else if (curNs != NULL) {
                         //printf(" --> ns=%s, curNs=%s\n",
                         //       String8(ns).string(), String8(curNs).string());
                         if (memcmp(ns8.string(), curNs, nsLen) == 0) {
-                            STRING_POOL_NOISY(ALOGI("  FOUND!"));
+                            if (kDebugStringPoolNoisy) {
+                                ALOGI("  FOUND!");
+                            }
                             return i;
                         }
                     }
                 }
             }
         } else {
-            STRING_POOL_NOISY(ALOGI("indexOfAttribute UTF16 %s (%d) / %s (%d)",
-                    String8(ns, nsLen).string(), nsLen,
-                    String8(attr, attrLen).string(), attrLen));
+            if (kDebugStringPoolNoisy) {
+                ALOGI("indexOfAttribute UTF16 %s (%zu) / %s (%zu)",
+                        String8(ns, nsLen).string(), nsLen,
+                        String8(attr, attrLen).string(), attrLen);
+            }
             for (size_t i=0; i<N; i++) {
                 size_t curNsLen = 0, curAttrLen = 0;
                 const char16_t* curNs = getAttributeNamespace(i, &curNsLen);
                 const char16_t* curAttr = getAttributeName(i, &curAttrLen);
-                STRING_POOL_NOISY(ALOGI("  curNs=%s (%d), curAttr=%s (%d)",
-                        String8(curNs, curNsLen).string(), curNsLen,
-                        String8(curAttr, curAttrLen).string(), curAttrLen));
+                if (kDebugStringPoolNoisy) {
+                    ALOGI("  curNs=%s (%zu), curAttr=%s (%zu)",
+                            String8(curNs, curNsLen).string(), curNsLen,
+                            String8(curAttr, curAttrLen).string(), curAttrLen);
+                }
                 if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen
                         && (memcmp(attr, curAttr, attrLen*sizeof(char16_t)) == 0)) {
                     if (ns == NULL) {
                         if (curNs == NULL) {
-                            STRING_POOL_NOISY(ALOGI("  FOUND!"));
+                            if (kDebugStringPoolNoisy) {
+                                ALOGI("  FOUND!");
+                            }
                             return i;
                         }
                     } else if (curNs != NULL) {
                         //printf(" --> ns=%s, curNs=%s\n",
                         //       String8(ns).string(), String8(curNs).string());
                         if (memcmp(ns, curNs, nsLen*sizeof(char16_t)) == 0) {
-                            STRING_POOL_NOISY(ALOGI("  FOUND!"));
+                            if (kDebugStringPoolNoisy) {
+                                ALOGI("  FOUND!");
+                            }
                             return i;
                         }
                     }
@@ -1398,7 +1466,9 @@ ResXMLParser::event_code_t ResXMLParser::nextNode()
     do {
         const ResXMLTree_node* next = (const ResXMLTree_node*)
             (((const uint8_t*)mCurNode) + dtohl(mCurNode->header.size));
-        //ALOGW("Next node: prev=%p, next=%p\n", mCurNode, next);
+        if (kDebugXMLNoisy) {
+            ALOGI("Next node: prev=%p, next=%p\n", mCurNode, next);
+        }
 
         if (((const uint8_t*)next) >= mTree.mDataEnd) {
             mCurNode = NULL;
@@ -1475,7 +1545,9 @@ ResXMLTree::ResXMLTree(const DynamicRefTable* dynamicRefTable)
     , mDynamicRefTable(dynamicRefTable)
     , mError(NO_INIT), mOwnedData(NULL)
 {
-    //ALOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
+    if (kDebugResXMLTree) {
+        ALOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
+    }
     restart();
 }
 
@@ -1484,13 +1556,17 @@ ResXMLTree::ResXMLTree()
     , mDynamicRefTable(NULL)
     , mError(NO_INIT), mOwnedData(NULL)
 {
-    //ALOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
+    if (kDebugResXMLTree) {
+        ALOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
+    }
     restart();
 }
 
 ResXMLTree::~ResXMLTree()
 {
-    //ALOGI("Destroying ResXMLTree in %p #%d\n", this, android_atomic_dec(&gCount)-1);
+    if (kDebugResXMLTree) {
+        ALOGI("Destroying ResXMLTree in %p #%d\n", this, android_atomic_dec(&gCount)-1);
+    }
     uninit();
 }
 
@@ -1543,8 +1619,10 @@ status_t ResXMLTree::setTo(const void* data, size_t size, bool copyData)
         }
         const uint16_t type = dtohs(chunk->type);
         const size_t size = dtohl(chunk->size);
-        XML_NOISY(printf("Scanning @ %p: type=0x%x, size=0x%x\n",
-                     (void*)(((uint32_t)chunk)-((uint32_t)mHeader)), type, size));
+        if (kDebugXMLNoisy) {
+            printf("Scanning @ %p: type=0x%x, size=0x%zx\n",
+                    (void*)(((uintptr_t)chunk)-((uintptr_t)mHeader)), type, size);
+        }
         if (type == RES_STRING_POOL_TYPE) {
             mStrings.setTo(chunk, size);
         } else if (type == RES_XML_RESOURCE_MAP_TYPE) {
@@ -1567,7 +1645,9 @@ status_t ResXMLTree::setTo(const void* data, size_t size, bool copyData)
             mRootCode = mEventCode;
             break;
         } else {
-            XML_NOISY(printf("Skipping unknown chunk!\n"));
+            if (kDebugXMLNoisy) {
+                printf("Skipping unknown chunk!\n");
+            }
         }
         lastChunk = chunk;
         chunk = (const ResChunk_header*)
@@ -1796,7 +1876,10 @@ void ResTable_config::swapHtoD() {
     }
 
     // The language & region are equal, so compare the scripts and variants.
-    int script = memcmp(l.localeScript, r.localeScript, sizeof(l.localeScript));
+    const char emptyScript[sizeof(l.localeScript)] = {'\0', '\0', '\0', '\0'};
+    const char *lScript = l.localeScriptWasComputed ? emptyScript : l.localeScript;
+    const char *rScript = r.localeScriptWasComputed ? emptyScript : r.localeScript;
+    int script = memcmp(lScript, rScript, sizeof(l.localeScript));
     if (script) {
         return script;
     }
@@ -1822,6 +1905,8 @@ int ResTable_config::compare(const ResTable_config& o) const {
     if (diff != 0) return diff;
     diff = (int32_t)(screenLayout - o.screenLayout);
     if (diff != 0) return diff;
+    diff = (int32_t)(screenLayout2 - o.screenLayout2);
+    if (diff != 0) return diff;
     diff = (int32_t)(uiMode - o.uiMode);
     if (diff != 0) return diff;
     diff = (int32_t)(smallestScreenWidthDp - o.smallestScreenWidthDp);
@@ -1879,6 +1964,9 @@ int ResTable_config::compareLogical(const ResTable_config& o) const {
     if (screenLayout != o.screenLayout) {
         return screenLayout < o.screenLayout ? -1 : 1;
     }
+    if (screenLayout2 != o.screenLayout2) {
+        return screenLayout2 < o.screenLayout2 ? -1 : 1;
+    }
     if (uiMode != o.uiMode) {
         return uiMode < o.uiMode ? -1 : 1;
     }
@@ -1903,6 +1991,7 @@ int ResTable_config::diff(const ResTable_config& o) const {
     if (version != o.version) diffs |= CONFIG_VERSION;
     if ((screenLayout & MASK_LAYOUTDIR) != (o.screenLayout & MASK_LAYOUTDIR)) diffs |= CONFIG_LAYOUTDIR;
     if ((screenLayout & ~MASK_LAYOUTDIR) != (o.screenLayout & ~MASK_LAYOUTDIR)) diffs |= CONFIG_SCREEN_LAYOUT;
+    if ((screenLayout2 & MASK_SCREENROUND) != (o.screenLayout2 & MASK_SCREENROUND)) diffs |= CONFIG_SCREEN_ROUND;
     if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE;
     if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE;
     if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE;
@@ -1934,11 +2023,11 @@ int ResTable_config::isLocaleMoreSpecificThan(const ResTable_config& o) const {
     // scripts since it seems more useful to do so. We will consider
     // "en-US-POSIX" to be more specific than "en-Latn-US".
 
-    const int score = ((localeScript[0] != 0) ? 1 : 0) +
-        ((localeVariant[0] != 0) ? 2 : 0);
+    const int score = ((localeScript[0] != '\0' && !localeScriptWasComputed) ? 1 : 0) +
+        ((localeVariant[0] != '\0') ? 2 : 0);
 
-    const int oScore = ((o.localeScript[0] != 0) ? 1 : 0) +
-        ((o.localeVariant[0] != 0) ? 2 : 0);
+    const int oScore = (o.localeScript[0] != '\0' && !o.localeScriptWasComputed ? 1 : 0) +
+        ((o.localeVariant[0] != '\0') ? 2 : 0);
 
     return score - oScore;
 
@@ -2008,6 +2097,13 @@ bool ResTable_config::isMoreSpecificThan(const ResTable_config& o) const {
         }
     }
 
+    if (screenLayout2 || o.screenLayout2) {
+        if (((screenLayout2^o.screenLayout2) & MASK_SCREENROUND) != 0) {
+            if (!(screenLayout2 & MASK_SCREENROUND)) return false;
+            if (!(o.screenLayout2 & MASK_SCREENROUND)) return true;
+        }
+    }
+
     if (orientation != o.orientation) {
         if (!orientation) return false;
         if (!o.orientation) return true;
@@ -2080,6 +2176,88 @@ bool ResTable_config::isMoreSpecificThan(const ResTable_config& o) const {
     return false;
 }
 
+bool ResTable_config::isLocaleBetterThan(const ResTable_config& o,
+        const ResTable_config* requested) const {
+    if (requested->locale == 0) {
+        // The request doesn't have a locale, so no resource is better
+        // than the other.
+        return false;
+    }
+
+    if (locale == 0 && o.locale == 0) {
+        // The locales parts of both resources are empty, so no one is better
+        // than the other.
+        return false;
+    }
+
+    // Non-matching locales have been filtered out, so both resources
+    // match the requested locale.
+    //
+    // Because of the locale-related checks in match() and the checks, we know
+    // that:
+    // 1) The resource languages are either empty or match the request;
+    // and
+    // 2) If the request's script is known, the resource scripts are either
+    //    unknown or match the request.
+
+    if (language[0] != o.language[0]) {
+        // The languages of the two resources are not the same. We can only
+        // assume that one of the two resources matched the request because one
+        // doesn't have a language and the other has a matching language.
+        //
+        // We consider the one that has the language specified a better match.
+        //
+        // The exception is that we consider no-language resources a better match
+        // for US English and similar locales than locales that are a descendant
+        // of Internatinal English (en-001), since no-language resources are
+        // where the US English resource have traditionally lived for most apps.
+        if (requested->language[0] == 'e' && requested->language[1] == 'n') {
+            if (requested->country[0] == 'U' && requested->country[1] == 'S') {
+                // For US English itself, we consider a no-locale resource a
+                // better match if the other resource has a country other than
+                // US specified.
+                if (language[0] != '\0') {
+                    return country[0] == '\0' || (country[0] == 'U' && country[1] == 'S');
+                } else {
+                    return !(o.country[0] == '\0' || (o.country[0] == 'U' && o.country[1] == 'S'));
+                }
+            } else if (localeDataIsCloseToUsEnglish(requested->country)) {
+                if (language[0] != '\0') {
+                    return localeDataIsCloseToUsEnglish(country);
+                } else {
+                    return !localeDataIsCloseToUsEnglish(o.country);
+                }
+            }
+        }
+        return (language[0] != '\0');
+    }
+
+    // If we are here, both the resources have the same non-empty language as
+    // the request.
+    //
+    // Because the languages are the same, computeScript() always
+    // returns a non-empty script for languages it knows about, and we have passed
+    // the script checks in match(), the scripts are either all unknown or are
+    // all the same. So we can't gain anything by checking the scripts. We need
+    // to check the region and variant.
+
+    // See if any of the regions is better than the other
+    const int region_comparison = localeDataCompareRegions(
+            country, o.country,
+            language, requested->localeScript, requested->country);
+    if (region_comparison != 0) {
+        return (region_comparison > 0);
+    }
+
+    // The regions are the same. Try the variant.
+    if (requested->localeVariant[0] != '\0'
+            && strncmp(localeVariant, requested->localeVariant, sizeof(localeVariant)) == 0) {
+        return (strncmp(o.localeVariant, requested->localeVariant, sizeof(localeVariant)) != 0);
+    }
+
+    return false;
+}
+
 bool ResTable_config::isBetterThan(const ResTable_config& o,
         const ResTable_config* requested) const {
     if (requested) {
@@ -2093,26 +2271,8 @@ bool ResTable_config::isBetterThan(const ResTable_config& o,
             }
         }
 
-        if (locale || o.locale) {
-            if ((language[0] != o.language[0]) && requested->language[0]) {
-                return (language[0]);
-            }
-
-            if ((country[0] != o.country[0]) && requested->country[0]) {
-                return (country[0]);
-            }
-        }
-
-        if (localeScript[0] || o.localeScript[0]) {
-            if (localeScript[0] != o.localeScript[0] && requested->localeScript[0]) {
-                return localeScript[0];
-            }
-        }
-
-        if (localeVariant[0] || o.localeVariant[0]) {
-            if (localeVariant[0] != o.localeVariant[0] && requested->localeVariant[0]) {
-                return localeVariant[0];
-            }
+        if (isLocaleBetterThan(o, requested)) {
+            return true;
         }
 
         if (screenLayout || o.screenLayout) {
@@ -2151,9 +2311,11 @@ bool ResTable_config::isBetterThan(const ResTable_config& o,
                 myDelta += requested->screenHeightDp - screenHeightDp;
                 otherDelta += requested->screenHeightDp - o.screenHeightDp;
             }
-            //ALOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d",
-            //    screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp,
-            //    requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta);
+            if (kDebugTableSuperNoisy) {
+                ALOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d",
+                        screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp,
+                        requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta);
+            }
             if (myDelta != otherDelta) {
                 return myDelta < otherDelta;
             }
@@ -2193,6 +2355,13 @@ bool ResTable_config::isBetterThan(const ResTable_config& o,
             }
         }
 
+        if (screenLayout2 || o.screenLayout2) {
+            if (((screenLayout2^o.screenLayout2) & MASK_SCREENROUND) != 0 &&
+                    (requested->screenLayout2 & MASK_SCREENROUND)) {
+                return screenLayout2 & MASK_SCREENROUND;
+            }
+        }
+
         if ((orientation != o.orientation) && requested->orientation) {
             return (orientation);
         }
@@ -2351,20 +2520,51 @@ bool ResTable_config::match(const ResTable_config& settings) const {
         }
     }
     if (locale != 0) {
-        // Don't consider the script & variants when deciding matches.
+        // Don't consider country and variants when deciding matches.
+        // (Theoretically, the variant can also affect the script. For
+        // example, "ar-alalc97" probably implies the Latin script, but since
+        // CLDR doesn't support getting likely scripts for that, we'll assume
+        // the variant doesn't change the script.)
         //
-        // If we two configs differ only in their script or language, they
-        // can be weeded out in the isMoreSpecificThan test.
-        if (language[0] != 0
-            && (language[0] != settings.language[0]
-                || language[1] != settings.language[1])) {
+        // If two configs differ only in their country and variant,
+        // they can be weeded out in the isMoreSpecificThan test.
+        if (language[0] != settings.language[0] || language[1] != settings.language[1]) {
             return false;
         }
 
-        if (country[0] != 0
-            && (country[0] != settings.country[0]
-                || country[1] != settings.country[1])) {
-            return false;
+        // For backward compatibility and supporting private-use locales, we
+        // fall back to old behavior if we couldn't determine the script for
+        // either of the desired locale or the provided locale. But if we could determine
+        // the scripts, they should be the same for the locales to match.
+        bool countriesMustMatch = false;
+        char computed_script[4];
+        const char* script;
+        if (settings.localeScript[0] == '\0') { // could not determine the request's script
+            countriesMustMatch = true;
+        } else {
+            if (localeScript[0] == '\0' && !localeScriptWasComputed) {
+                // script was not provided or computed, so we try to compute it
+                localeDataComputeScript(computed_script, language, country);
+                if (computed_script[0] == '\0') { // we could not compute the script
+                    countriesMustMatch = true;
+                } else {
+                    script = computed_script;
+                }
+            } else { // script was provided, so just use it
+                script = localeScript;
+            }
+        }
+
+        if (countriesMustMatch) {
+            if (country[0] != '\0'
+                && (country[0] != settings.country[0]
+                    || country[1] != settings.country[1])) {
+                return false;
+            }
+        } else {
+            if (memcmp(script, settings.localeScript, sizeof(settings.localeScript)) != 0) {
+                return false;
+            }
         }
     }
 
@@ -2406,13 +2606,28 @@ bool ResTable_config::match(const ResTable_config& settings) const {
             return false;
         }
     }
+
+    if (screenConfig2 != 0) {
+        const int screenRound = screenLayout2 & MASK_SCREENROUND;
+        const int setScreenRound = settings.screenLayout2 & MASK_SCREENROUND;
+        if (screenRound != 0 && screenRound != setScreenRound) {
+            return false;
+        }
+    }
+
     if (screenSizeDp != 0) {
         if (screenWidthDp != 0 && screenWidthDp > settings.screenWidthDp) {
-            //ALOGI("Filtering out width %d in requested %d", screenWidthDp, settings.screenWidthDp);
+            if (kDebugTableSuperNoisy) {
+                ALOGI("Filtering out width %d in requested %d", screenWidthDp,
+                        settings.screenWidthDp);
+            }
             return false;
         }
         if (screenHeightDp != 0 && screenHeightDp > settings.screenHeightDp) {
-            //ALOGI("Filtering out height %d in requested %d", screenHeightDp, settings.screenHeightDp);
+            if (kDebugTableSuperNoisy) {
+                ALOGI("Filtering out height %d in requested %d", screenHeightDp,
+                        settings.screenHeightDp);
+            }
             return false;
         }
     }
@@ -2432,9 +2647,13 @@ bool ResTable_config::match(const ResTable_config& settings) const {
             // For compatibility, we count a request for KEYSHIDDEN_NO as also
             // matching the more recent KEYSHIDDEN_SOFT.  Basically
             // KEYSHIDDEN_NO means there is some kind of keyboard available.
-            //ALOGI("Matching keysHidden: have=%d, config=%d\n", keysHidden, setKeysHidden);
+            if (kDebugTableSuperNoisy) {
+                ALOGI("Matching keysHidden: have=%d, config=%d\n", keysHidden, setKeysHidden);
+            }
             if (keysHidden != KEYSHIDDEN_NO || setKeysHidden != KEYSHIDDEN_SOFT) {
-                //ALOGI("No match!");
+                if (kDebugTableSuperNoisy) {
+                    ALOGI("No match!");
+                }
                 return false;
             }
         }
@@ -2469,6 +2688,58 @@ bool ResTable_config::match(const ResTable_config& settings) const {
     return true;
 }
 
+void ResTable_config::appendDirLocale(String8& out) const {
+    if (!language[0]) {
+        return;
+    }
+    const bool scriptWasProvided = localeScript[0] != '\0' && !localeScriptWasComputed;
+    if (!scriptWasProvided && !localeVariant[0]) {
+        // Legacy format.
+        if (out.size() > 0) {
+            out.append("-");
+        }
+
+        char buf[4];
+        size_t len = unpackLanguage(buf);
+        out.append(buf, len);
+
+        if (country[0]) {
+            out.append("-r");
+            len = unpackRegion(buf);
+            out.append(buf, len);
+        }
+        return;
+    }
+
+    // We are writing the modified BCP 47 tag.
+    // It starts with 'b+' and uses '+' as a separator.
+
+    if (out.size() > 0) {
+        out.append("-");
+    }
+    out.append("b+");
+
+    char buf[4];
+    size_t len = unpackLanguage(buf);
+    out.append(buf, len);
+
+    if (scriptWasProvided) {
+        out.append("+");
+        out.append(localeScript, sizeof(localeScript));
+    }
+
+    if (country[0]) {
+        out.append("+");
+        len = unpackRegion(buf);
+        out.append(buf, len);
+    }
+
+    if (localeVariant[0]) {
+        out.append("+");
+        out.append(localeVariant, strnlen(localeVariant, sizeof(localeVariant)));
+    }
+}
+
 void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN]) const {
     memset(str, 0, RESTABLE_MAX_LOCALE_LEN);
 
@@ -2483,7 +2754,7 @@ void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN]) const {
         charsWritten += unpackLanguage(str);
     }
 
-    if (localeScript[0]) {
+    if (localeScript[0] && !localeScriptWasComputed) {
         if (charsWritten) {
             str[charsWritten++] = '-';
         }
@@ -2517,11 +2788,15 @@ void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN]) const {
            config->language[0] ? config->packRegion(start) : config->packLanguage(start);
            break;
        case 4:
-           config->localeScript[0] = toupper(start[0]);
-           for (size_t i = 1; i < 4; ++i) {
-               config->localeScript[i] = tolower(start[i]);
+           if ('0' <= start[0] && start[0] <= '9') {
+               // this is a variant, so fall through
+           } else {
+               config->localeScript[0] = toupper(start[0]);
+               for (size_t i = 1; i < 4; ++i) {
+                   config->localeScript[i] = tolower(start[i]);
+               }
+               break;
            }
-           break;
        case 5:
        case 6:
        case 7:
@@ -2555,6 +2830,10 @@ void ResTable_config::setBcp47Locale(const char* in) {
 
     const size_t size = in + strlen(in) - start;
     assignLocaleComponent(this, start, size);
+    localeScriptWasComputed = (localeScript[0] == '\0');
+    if (localeScriptWasComputed) {
+        computeScript();
+    }
 }
 
 String8 ResTable_config::toString() const {
@@ -2569,12 +2848,7 @@ String8 ResTable_config::toString() const {
         res.appendFormat("mnc%d", dtohs(mnc));
     }
 
-    char localeStr[RESTABLE_MAX_LOCALE_LEN];
-    getBcp47Locale(localeStr);
-    if (strlen(localeStr) > 0) {
-        if (res.size() > 0) res.append("-");
-        res.append(localeStr);
-    }
+    appendDirLocale(res);
 
     if ((screenLayout&MASK_LAYOUTDIR) != 0) {
         if (res.size() > 0) res.append("-");
@@ -2639,6 +2913,20 @@ String8 ResTable_config::toString() const {
                 break;
         }
     }
+    if ((screenLayout2&MASK_SCREENROUND) != 0) {
+        if (res.size() > 0) res.append("-");
+        switch (screenLayout2&MASK_SCREENROUND) {
+            case SCREENROUND_NO:
+                res.append("notround");
+                break;
+            case SCREENROUND_YES:
+                res.append("round");
+                break;
+            default:
+                res.appendFormat("screenRound=%d", dtohs(screenLayout2&MASK_SCREENROUND));
+                break;
+        }
+    }
     if (orientation != ORIENTATION_ANY) {
         if (res.size() > 0) res.append("-");
         switch (orientation) {
@@ -2906,13 +3194,15 @@ struct ResTable::Package
 // table that defined the package); the ones after are skins on top of it.
 struct ResTable::PackageGroup
 {
-    PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id)
+    PackageGroup(
+            ResTable* _owner, const String16& _name, uint32_t _id,
+            bool appAsLib, bool _isSystemAsset)
         : owner(_owner)
         , name(_name)
         , id(_id)
         , largestTypeId(0)
-        , bags(NULL)
-        , dynamicRefTable(static_cast<uint8_t>(_id))
+        , dynamicRefTable(static_cast<uint8_t>(_id), appAsLib)
+        , isSystemAsset(_isSystemAsset)
     { }
 
     ~PackageGroup() {
@@ -2937,28 +3227,41 @@ struct ResTable::PackageGroup
         }
     }
 
+    /**
+     * Clear all cache related data that depends on parameters/configuration.
+     * This includes the bag caches and filtered types.
+     */
     void clearBagCache() {
-        if (bags) {
-            TABLE_NOISY(printf("bags=%p\n", bags));
-            for (size_t i = 0; i < bags->size(); i++) {
-                TABLE_NOISY(printf("type=%d\n", i));
-                const TypeList& typeList = types[i];
-                if (!typeList.isEmpty()) {
-                    bag_set** typeBags = bags->get(i);
-                    TABLE_NOISY(printf("typeBags=%p\n", typeBags));
-                    if (typeBags) {
-                        const size_t N = typeList[0]->entryCount;
-                        TABLE_NOISY(printf("type->entryCount=%x\n", N));
-                        for (size_t j=0; j<N; j++) {
-                            if (typeBags[j] && typeBags[j] != (bag_set*)0xFFFFFFFF)
-                                free(typeBags[j]);
+        for (size_t i = 0; i < typeCacheEntries.size(); i++) {
+            if (kDebugTableNoisy) {
+                printf("type=%zu\n", i);
+            }
+            const TypeList& typeList = types[i];
+            if (!typeList.isEmpty()) {
+                TypeCacheEntry& cacheEntry = typeCacheEntries.editItemAt(i);
+
+                // Reset the filtered configurations.
+                cacheEntry.filteredConfigs.clear();
+
+                bag_set** typeBags = cacheEntry.cachedBags;
+                if (kDebugTableNoisy) {
+                    printf("typeBags=%p\n", typeBags);
+                }
+
+                if (typeBags) {
+                    const size_t N = typeList[0]->entryCount;
+                    if (kDebugTableNoisy) {
+                        printf("type->entryCount=%zu\n", N);
+                    }
+                    for (size_t j = 0; j < N; j++) {
+                        if (typeBags[j] && typeBags[j] != (bag_set*)0xFFFFFFFF) {
+                            free(typeBags[j]);
                         }
-                        free(typeBags);
                     }
+                    free(typeBags);
+                    cacheEntry.cachedBags = NULL;
                 }
             }
-            delete bags;
-            bags = NULL;
         }
     }
 
@@ -2986,9 +3289,11 @@ struct ResTable::PackageGroup
 
     uint8_t                         largestTypeId;
 
-    // Computed attribute bags, first indexed by the type and second
-    // by the entry in that type.
-    ByteBucketArray<bag_set**>*     bags;
+    // Cached objects dependent on the parameters/configuration of this ResTable.
+    // Gets cleared whenever the parameters/configuration changes.
+    // These are stored here in a parallel structure because the data in `types` may
+    // be shared by other ResTable's (framework resources are shared this way).
+    ByteBucketArray<TypeCacheEntry> typeCacheEntries;
 
     // The table mapping dynamic references to resolved references for
     // this package group.
@@ -2996,18 +3301,15 @@ struct ResTable::PackageGroup
     // by having these tables in a per-package scope rather than
     // per-package-group.
     DynamicRefTable                 dynamicRefTable;
-};
 
-struct ResTable::bag_set
-{
-    size_t numAttrs;    // number in array
-    size_t availAttrs;  // total space in array
-    uint32_t typeSpecFlags;
-    // Followed by 'numAttr' bag_entry structures.
+    // If the package group comes from a system asset. Used in
+    // determining non-system locales.
+    const bool                      isSystemAsset;
 };
 
 ResTable::Theme::Theme(const ResTable& table)
     : mTable(table)
+    , mTypeSpecFlags(0)
 {
     memset(mPackages, 0, sizeof(mPackages));
 }
@@ -3040,7 +3342,8 @@ ResTable::Theme::package_info* ResTable::Theme::copy_package(package_info* pi)
         size_t cnt = pi->types[j].numEntries;
         newpi->types[j].numEntries = cnt;
         theme_entry* te = pi->types[j].entries;
-        if (te != NULL) {
+        size_t cnt_max = SIZE_MAX / sizeof(theme_entry);
+        if (te != NULL && (cnt < 0xFFFFFFFF-1) && (cnt < cnt_max)) {
             theme_entry* newte = (theme_entry*)malloc(cnt*sizeof(theme_entry));
             newpi->types[j].entries = newte;
             memcpy(newte, te, cnt*sizeof(theme_entry));
@@ -3057,12 +3360,16 @@ status_t ResTable::Theme::applyStyle(uint32_t resID, bool force)
     uint32_t bagTypeSpecFlags = 0;
     mTable.lock();
     const ssize_t N = mTable.getBagLocked(resID, &bag, &bagTypeSpecFlags);
-    TABLE_NOISY(ALOGV("Applying style 0x%08x to theme %p, count=%d", resID, this, N));
+    if (kDebugTableNoisy) {
+        ALOGV("Applying style 0x%08x to theme %p, count=%zu", resID, this, N);
+    }
     if (N < 0) {
         mTable.unlock();
         return N;
     }
 
+    mTypeSpecFlags |= bagTypeSpecFlags;
+
     uint32_t curPackage = 0xffffffff;
     ssize_t curPackageIndex = 0;
     package_info* curPI = NULL;
@@ -3088,7 +3395,6 @@ status_t ResTable::Theme::applyStyle(uint32_t resID, bool force)
             curPackageIndex = pidx;
             curPI = mPackages[pidx];
             if (curPI == NULL) {
-                PackageGroup* const grp = mTable.mPackageGroups[pidx];
                 curPI = (package_info*)malloc(sizeof(package_info));
                 memset(curPI, 0, sizeof(*curPI));
                 mPackages[pidx] = curPI;
@@ -3106,9 +3412,12 @@ status_t ResTable::Theme::applyStyle(uint32_t resID, bool force)
             if (curEntries == NULL) {
                 PackageGroup* const grp = mTable.mPackageGroups[curPackageIndex];
                 const TypeList& typeList = grp->types[t];
-                int cnt = typeList.isEmpty() ? 0 : typeList[0]->entryCount;
-                curEntries = (theme_entry*)malloc(cnt*sizeof(theme_entry));
-                memset(curEntries, Res_value::TYPE_NULL, cnt*sizeof(theme_entry));
+                size_t cnt = typeList.isEmpty() ? 0 : typeList[0]->entryCount;
+                size_t cnt_max = SIZE_MAX / sizeof(theme_entry);
+                size_t buff_size = (cnt < cnt_max && cnt < 0xFFFFFFFF-1) ?
+                                          cnt*sizeof(theme_entry) : 0;
+                curEntries = (theme_entry*)malloc(buff_size);
+                memset(curEntries, Res_value::TYPE_NULL, buff_size);
                 curPI->types[t].numEntries = cnt;
                 curPI->types[t].entries = curEntries;
             }
@@ -3120,9 +3429,11 @@ status_t ResTable::Theme::applyStyle(uint32_t resID, bool force)
             continue;
         }
         theme_entry* curEntry = curEntries + e;
-        TABLE_NOISY(ALOGV("Attr 0x%08x: type=0x%x, data=0x%08x; curType=0x%x",
-                attrRes, bag->map.value.dataType, bag->map.value.data,
-                curEntry->value.dataType));
+        if (kDebugTableNoisy) {
+            ALOGV("Attr 0x%08x: type=0x%x, data=0x%08x; curType=0x%x",
+                    attrRes, bag->map.value.dataType, bag->map.value.data,
+                    curEntry->value.dataType);
+        }
         if (force || curEntry->value.dataType == Res_value::TYPE_NULL) {
             curEntry->stringBlock = bag->stringBlock;
             curEntry->typeSpecFlags |= bagTypeSpecFlags;
@@ -3134,17 +3445,21 @@ status_t ResTable::Theme::applyStyle(uint32_t resID, bool force)
 
     mTable.unlock();
 
-    //ALOGI("Applying style 0x%08x (force=%d)  theme %p...\n", resID, force, this);
-    //dumpToLog();
+    if (kDebugTableTheme) {
+        ALOGI("Applying style 0x%08x (force=%d)  theme %p...\n", resID, force, this);
+        dumpToLog();
+    }
 
     return NO_ERROR;
 }
 
 status_t ResTable::Theme::setTo(const Theme& other)
 {
-    //ALOGI("Setting theme %p from theme %p...\n", this, &other);
-    //dumpToLog();
-    //other.dumpToLog();
+    if (kDebugTableTheme) {
+        ALOGI("Setting theme %p from theme %p...\n", this, &other);
+        dumpToLog();
+        other.dumpToLog();
+    }
 
     if (&mTable == &other.mTable) {
         for (size_t i=0; i<Res_MAXPACKAGE; i++) {
@@ -3173,8 +3488,36 @@ status_t ResTable::Theme::setTo(const Theme& other)
         }
     }
 
-    //ALOGI("Final theme:");
-    //dumpToLog();
+    mTypeSpecFlags = other.mTypeSpecFlags;
+
+    if (kDebugTableTheme) {
+        ALOGI("Final theme:");
+        dumpToLog();
+    }
+
+    return NO_ERROR;
+}
+
+status_t ResTable::Theme::clear()
+{
+    if (kDebugTableTheme) {
+        ALOGI("Clearing theme %p...\n", this);
+        dumpToLog();
+    }
+
+    for (size_t i = 0; i < Res_MAXPACKAGE; i++) {
+        if (mPackages[i] != NULL) {
+            free_package(mPackages[i]);
+            mPackages[i] = NULL;
+        }
+    }
+
+    mTypeSpecFlags = 0;
+
+    if (kDebugTableTheme) {
+        ALOGI("Final theme:");
+        dumpToLog();
+    }
 
     return NO_ERROR;
 }
@@ -3191,23 +3534,33 @@ ssize_t ResTable::Theme::getAttribute(uint32_t resID, Res_value* outValue,
         const uint32_t t = Res_GETTYPE(resID);
         const uint32_t e = Res_GETENTRY(resID);
 
-        TABLE_THEME(ALOGI("Looking up attr 0x%08x in theme %p", resID, this));
+        if (kDebugTableTheme) {
+            ALOGI("Looking up attr 0x%08x in theme %p", resID, this);
+        }
 
         if (p >= 0) {
             const package_info* const pi = mPackages[p];
-            TABLE_THEME(ALOGI("Found package: %p", pi));
+            if (kDebugTableTheme) {
+                ALOGI("Found package: %p", pi);
+            }
             if (pi != NULL) {
-                TABLE_THEME(ALOGI("Desired type index is %ld in avail %d", t, Res_MAXTYPE + 1));
+                if (kDebugTableTheme) {
+                    ALOGI("Desired type index is %zd in avail %zu", t, Res_MAXTYPE + 1);
+                }
                 if (t <= Res_MAXTYPE) {
                     const type_info& ti = pi->types[t];
-                    TABLE_THEME(ALOGI("Desired entry index is %ld in avail %d", e, ti.numEntries));
+                    if (kDebugTableTheme) {
+                        ALOGI("Desired entry index is %u in avail %zu", e, ti.numEntries);
+                    }
                     if (e < ti.numEntries) {
                         const theme_entry& te = ti.entries[e];
                         if (outTypeSpecFlags != NULL) {
                             *outTypeSpecFlags |= te.typeSpecFlags;
                         }
-                        TABLE_THEME(ALOGI("Theme value: type=0x%x, data=0x%08x",
-                                te.value.dataType, te.value.data));
+                        if (kDebugTableTheme) {
+                            ALOGI("Theme value: type=0x%x, data=0x%08x",
+                                    te.value.dataType, te.value.data);
+                        }
                         const uint8_t type = te.value.dataType;
                         if (type == Res_value::TYPE_ATTRIBUTE) {
                             if (cnt > 0) {
@@ -3241,8 +3594,10 @@ ssize_t ResTable::Theme::resolveAttributeReference(Res_value* inOutValue,
     if (inOutValue->dataType == Res_value::TYPE_ATTRIBUTE) {
         uint32_t newTypeSpecFlags;
         blockIndex = getAttribute(inOutValue->data, inOutValue, &newTypeSpecFlags);
-        TABLE_THEME(ALOGI("Resolving attr reference: blockIndex=%d, type=0x%x, data=%p\n",
-             (int)blockIndex, (int)inOutValue->dataType, (void*)inOutValue->data));
+        if (kDebugTableTheme) {
+            ALOGI("Resolving attr reference: blockIndex=%d, type=0x%x, data=0x%x\n",
+                    (int)blockIndex, (int)inOutValue->dataType, inOutValue->data);
+        }
         if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newTypeSpecFlags;
         //printf("Retrieved attribute new type=0x%x\n", inOutValue->dataType);
         if (blockIndex < 0) {
@@ -3253,6 +3608,11 @@ ssize_t ResTable::Theme::resolveAttributeReference(Res_value* inOutValue,
             inoutTypeSpecFlags, inoutConfig);
 }
 
+uint32_t ResTable::Theme::getChangingConfigurations() const
+{
+    return mTypeSpecFlags;
+}
+
 void ResTable::Theme::dumpToLog() const
 {
     ALOGI("Theme %p:\n", this);
@@ -3281,7 +3641,9 @@ ResTable::ResTable()
 {
     memset(&mParams, 0, sizeof(mParams));
     memset(mPackageMap, 0, sizeof(mPackageMap));
-    //ALOGI("Creating ResTable %p\n", this);
+    if (kDebugTableSuperNoisy) {
+        ALOGI("Creating ResTable %p\n", this);
+    }
 }
 
 ResTable::ResTable(const void* data, size_t size, const int32_t cookie, bool copyData)
@@ -3289,14 +3651,18 @@ ResTable::ResTable(const void* data, size_t size, const int32_t cookie, bool cop
 {
     memset(&mParams, 0, sizeof(mParams));
     memset(mPackageMap, 0, sizeof(mPackageMap));
-    addInternal(data, size, NULL, 0, cookie, copyData);
+    addInternal(data, size, NULL, 0, false, cookie, copyData);
     LOG_FATAL_IF(mError != NO_ERROR, "Error parsing resource table");
-    //ALOGI("Creating ResTable %p\n", this);
+    if (kDebugTableSuperNoisy) {
+        ALOGI("Creating ResTable %p\n", this);
+    }
 }
 
 ResTable::~ResTable()
 {
-    //ALOGI("Destroying ResTable in %p\n", this);
+    if (kDebugTableSuperNoisy) {
+        ALOGI("Destroying ResTable in %p\n", this);
+    }
     uninit();
 }
 
@@ -3306,12 +3672,12 @@ inline ssize_t ResTable::getResourcePackageIndex(uint32_t resID) const
 }
 
 status_t ResTable::add(const void* data, size_t size, const int32_t cookie, bool copyData) {
-    return addInternal(data, size, NULL, 0, cookie, copyData);
+    return addInternal(data, size, NULL, 0, false, cookie, copyData);
 }
 
 status_t ResTable::add(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
-        const int32_t cookie, bool copyData) {
-    return addInternal(data, size, idmapData, idmapDataSize, cookie, copyData);
+        const int32_t cookie, bool copyData, bool appAsLib) {
+    return addInternal(data, size, idmapData, idmapDataSize, appAsLib, cookie, copyData);
 }
 
 status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData) {
@@ -3321,10 +3687,13 @@ status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData) {
         return UNKNOWN_ERROR;
     }
 
-    return addInternal(data, static_cast<size_t>(asset->getLength()), NULL, 0, cookie, copyData);
+    return addInternal(data, static_cast<size_t>(asset->getLength()), NULL, false, 0, cookie,
+            copyData);
 }
 
-status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData) {
+status_t ResTable::add(
+        Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData,
+        bool appAsLib, bool isSystemAsset) {
     const void* data = asset->getBuffer(true);
     if (data == NULL) {
         ALOGW("Unable to get buffer of resource asset file");
@@ -3343,20 +3712,21 @@ status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bo
     }
 
     return addInternal(data, static_cast<size_t>(asset->getLength()),
-            idmapData, idmapSize, cookie, copyData);
+            idmapData, idmapSize, appAsLib, cookie, copyData, isSystemAsset);
 }
 
-status_t ResTable::add(ResTable* src)
+status_t ResTable::add(ResTable* src, bool isSystemAsset)
 {
     mError = src->mError;
 
-    for (size_t i=0; i<src->mHeaders.size(); i++) {
+    for (size_t i=0; i < src->mHeaders.size(); i++) {
         mHeaders.add(src->mHeaders[i]);
     }
 
-    for (size_t i=0; i<src->mPackageGroups.size(); i++) {
+    for (size_t i=0; i < src->mPackageGroups.size(); i++) {
         PackageGroup* srcPg = src->mPackageGroups[i];
-        PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id);
+        PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id,
+                false /* appAsLib */, isSystemAsset || srcPg->isSystemAsset);
         for (size_t j=0; j<srcPg->packages.size(); j++) {
             pg->packages.add(srcPg->packages[j]);
         }
@@ -3397,7 +3767,7 @@ status_t ResTable::addEmpty(const int32_t cookie) {
 }
 
 status_t ResTable::addInternal(const void* data, size_t dataSize, const void* idmapData, size_t idmapDataSize,
-        const int32_t cookie, bool copyData)
+        bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset)
 {
     if (!data) {
         return NO_ERROR;
@@ -3425,9 +3795,10 @@ status_t ResTable::addInternal(const void* data, size_t dataSize, const void* id
 
     const bool notDeviceEndian = htods(0xf0) != 0xf0;
 
-    LOAD_TABLE_NOISY(
-        ALOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%d, copy=%d "
-             "idmap=%p\n", data, dataSize, cookie, copyData, idmap));
+    if (kDebugLoadTableNoisy) {
+        ALOGV("Adding resources to ResTable: data=%p, size=%zu, cookie=%d, copy=%d "
+                "idmap=%p\n", data, dataSize, cookie, copyData, idmapData);
+    }
 
     if (copyData || notDeviceEndian) {
         header->ownedData = malloc(dataSize);
@@ -3440,9 +3811,13 @@ status_t ResTable::addInternal(const void* data, size_t dataSize, const void* id
 
     header->header = (const ResTable_header*)data;
     header->size = dtohl(header->header->header.size);
-    //ALOGI("Got size 0x%x, again size 0x%x, raw size 0x%x\n", header->size,
-    //     dtohl(header->header->header.size), header->header->header.size);
-    LOAD_TABLE_NOISY(ALOGV("Loading ResTable @%p:\n", header->header));
+    if (kDebugLoadTableSuperNoisy) {
+        ALOGI("Got size %zu, again size 0x%x, raw size 0x%x\n", header->size,
+                dtohl(header->header->header.size), header->header->header.size);
+    }
+    if (kDebugLoadTableNoisy) {
+        ALOGV("Loading ResTable @%p:\n", header->header);
+    }
     if (dtohs(header->header->header.headerSize) > header->size
             || header->size > dataSize) {
         ALOGW("Bad resource table: header size 0x%x or total size 0x%x is larger than data size 0x%x\n",
@@ -3470,9 +3845,11 @@ status_t ResTable::addInternal(const void* data, size_t dataSize, const void* id
         if (err != NO_ERROR) {
             return (mError=err);
         }
-        TABLE_NOISY(ALOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
-                     dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
-                     (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header))));
+        if (kDebugTableNoisy) {
+            ALOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
+                    dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
+                    (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
+        }
         const size_t csize = dtohl(chunk->size);
         const uint16_t ctype = dtohs(chunk->type);
         if (ctype == RES_STRING_POOL_TYPE) {
@@ -3493,7 +3870,8 @@ status_t ResTable::addInternal(const void* data, size_t dataSize, const void* id
                 return (mError=BAD_TYPE);
             }
 
-            if (parsePackage((ResTable_package*)chunk, header) != NO_ERROR) {
+            if (parsePackage(
+                    (ResTable_package*)chunk, header, appAsLib, isSystemAsset) != NO_ERROR) {
                 return mError;
             }
             curPackage++;
@@ -3516,7 +3894,9 @@ status_t ResTable::addInternal(const void* data, size_t dataSize, const void* id
         ALOGW("No string values found in resource table!");
     }
 
-    TABLE_NOISY(ALOGV("Returning from add with mError=%d\n", mError));
+    if (kDebugTableNoisy) {
+        ALOGV("Returning from add with mError=%d\n", mError);
+    }
     return mError;
 }
 
@@ -3562,7 +3942,9 @@ bool ResTable::getResourceName(uint32_t resID, bool allowUtf8, resource_name* ou
         if (Res_GETPACKAGE(resID)+1 == 0) {
             ALOGW("No package identifier when getting name for resource number 0x%08x", resID);
         } else {
+#ifndef STATIC_ANDROIDFW_FOR_TOOLS
             ALOGW("No known package when getting name for resource number 0x%08x", resID);
+#endif
         }
         return false;
     }
@@ -3682,15 +4064,16 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag
         return BAD_VALUE;
     }
 
-    TABLE_NOISY(size_t len;
-          printf("Found value: pkg=%d, type=%d, str=%s, int=%d\n",
-                 entry.package->header->index,
-                 outValue->dataType,
-                 outValue->dataType == Res_value::TYPE_STRING
-                 ? String8(entry.package->header->values.stringAt(
-                     outValue->data, &len)).string()
-                 : "",
-                 outValue->data));
+    if (kDebugTableNoisy) {
+        size_t len;
+        printf("Found value: pkg=%zu, type=%d, str=%s, int=%d\n",
+                entry.package->header->index,
+                outValue->dataType,
+                outValue->dataType == Res_value::TYPE_STRING ?
+                    String8(entry.package->header->values.stringAt(outValue->data, &len)).string() :
+                    "",
+                outValue->data);
+    }
 
     if (outSpecFlags != NULL) {
         *outSpecFlags = entry.specFlags;
@@ -3711,15 +4094,16 @@ ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex,
     while (blockIndex >= 0 && value->dataType == Res_value::TYPE_REFERENCE
             && value->data != 0 && count < 20) {
         if (outLastRef) *outLastRef = value->data;
-        uint32_t lastRef = value->data;
         uint32_t newFlags = 0;
         const ssize_t newIndex = getResource(value->data, value, true, 0, &newFlags,
                 outConfig);
         if (newIndex == BAD_INDEX) {
             return BAD_INDEX;
         }
-        TABLE_THEME(ALOGI("Resolving reference %p: newIndex=%d, type=0x%x, data=%p\n",
-             (void*)lastRef, (int)newIndex, (int)value->dataType, (void*)value->data));
+        if (kDebugTableTheme) {
+            ALOGI("Resolving reference 0x%x: newIndex=%d, type=0x%x, data=0x%x\n",
+                    value->data, (int)newIndex, (int)value->dataType, value->data);
+        }
         //printf("Getting reference 0x%08x: newIndex=%d\n", value->data, newIndex);
         if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newFlags;
         if (newIndex < 0) {
@@ -3816,43 +4200,40 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
     }
 
     // First see if we've already computed this bag...
-    if (grp->bags) {
-        bag_set** typeSet = grp->bags->get(t);
-        if (typeSet) {
-            bag_set* set = typeSet[e];
-            if (set) {
-                if (set != (bag_set*)0xFFFFFFFF) {
-                    if (outTypeSpecFlags != NULL) {
-                        *outTypeSpecFlags = set->typeSpecFlags;
-                    }
-                    *outBag = (bag_entry*)(set+1);
-                    //ALOGI("Found existing bag for: %p\n", (void*)resID);
-                    return set->numAttrs;
+    TypeCacheEntry& cacheEntry = grp->typeCacheEntries.editItemAt(t);
+    bag_set** typeSet = cacheEntry.cachedBags;
+    if (typeSet) {
+        bag_set* set = typeSet[e];
+        if (set) {
+            if (set != (bag_set*)0xFFFFFFFF) {
+                if (outTypeSpecFlags != NULL) {
+                    *outTypeSpecFlags = set->typeSpecFlags;
                 }
-                ALOGW("Attempt to retrieve bag 0x%08x which is invalid or in a cycle.",
-                     resID);
-                return BAD_INDEX;
+                *outBag = (bag_entry*)(set+1);
+                if (kDebugTableSuperNoisy) {
+                    ALOGI("Found existing bag for: 0x%x\n", resID);
+                }
+                return set->numAttrs;
             }
+            ALOGW("Attempt to retrieve bag 0x%08x which is invalid or in a cycle.",
+                 resID);
+            return BAD_INDEX;
         }
     }
 
     // Bag not found, we need to compute it!
-    if (!grp->bags) {
-        grp->bags = new ByteBucketArray<bag_set**>();
-        if (!grp->bags) return NO_MEMORY;
-    }
-
-    bag_set** typeSet = grp->bags->get(t);
     if (!typeSet) {
         typeSet = (bag_set**)calloc(NENTRY, sizeof(bag_set*));
         if (!typeSet) return NO_MEMORY;
-        grp->bags->set(t, typeSet);
+        cacheEntry.cachedBags = typeSet;
     }
 
     // Mark that we are currently working on this one.
     typeSet[e] = (bag_set*)0xFFFFFFFF;
 
-    TABLE_NOISY(ALOGI("Building bag: %p\n", (void*)resID));
+    if (kDebugTableNoisy) {
+        ALOGI("Building bag: %x\n", resID);
+    }
 
     // Now collect all bag attributes
     Entry entry;
@@ -3869,13 +4250,13 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
 
     size_t N = count;
 
-    TABLE_NOISY(ALOGI("Found map: size=%p parent=%p count=%d\n",
-                     entrySize, parent, count));
+    if (kDebugTableNoisy) {
+        ALOGI("Found map: size=%x parent=%x count=%d\n", entrySize, parent, count);
 
     // If this map inherits from another, we need to start
     // with its parent's values.  Otherwise start out empty.
-    TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n",
-                       entrySize, parent));
+        ALOGI("Creating new bag, entrySize=0x%08x, parent=0x%08x\n", entrySize, parent);
+    }
 
     // This is what we are building.
     bag_set* set = NULL;
@@ -3904,9 +4285,13 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
         if (NP > 0) {
             memcpy(set+1, parentBag, NP*sizeof(bag_entry));
             set->numAttrs = NP;
-            TABLE_NOISY(ALOGI("Initialized new bag with %d inherited attributes.\n", NP));
+            if (kDebugTableNoisy) {
+                ALOGI("Initialized new bag with %zd inherited attributes.\n", NP);
+            }
         } else {
-            TABLE_NOISY(ALOGI("Initialized new bag with no inherited attributes.\n"));
+            if (kDebugTableNoisy) {
+                ALOGI("Initialized new bag with no inherited attributes.\n");
+            }
             set->numAttrs = 0;
         }
         set->availAttrs = NT;
@@ -3930,10 +4315,13 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
     bag_entry* entries = (bag_entry*)(set+1);
     size_t curEntry = 0;
     uint32_t pos = 0;
-    TABLE_NOISY(ALOGI("Starting with set %p, entries=%p, avail=%d\n",
-                 set, entries, set->availAttrs));
+    if (kDebugTableNoisy) {
+        ALOGI("Starting with set %p, entries=%p, avail=%zu\n", set, entries, set->availAttrs);
+    }
     while (pos < count) {
-        TABLE_NOISY(printf("Now at %p\n", (void*)curOff));
+        if (kDebugTableNoisy) {
+            ALOGI("Now at %p\n", (void*)curOff);
+        }
 
         if (curOff > (dtohl(entry.type->header.size)-sizeof(ResTable_map))) {
             ALOGW("ResTable_map at %d is beyond type chunk data %d",
@@ -3958,8 +4346,10 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
         uint32_t oldName = 0;
         while ((isInside=(curEntry < set->numAttrs))
                 && (oldName=entries[curEntry].map.name.ident) < newName) {
-            TABLE_NOISY(printf("#%d: Keeping existing attribute: 0x%08x\n",
-                         curEntry, entries[curEntry].map.name.ident));
+            if (kDebugTableNoisy) {
+                ALOGI("#%zu: Keeping existing attribute: 0x%08x\n",
+                        curEntry, entries[curEntry].map.name.ident);
+            }
             curEntry++;
         }
 
@@ -3976,8 +4366,10 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
                 }
                 set->availAttrs = newAvail;
                 entries = (bag_entry*)(set+1);
-                TABLE_NOISY(printf("Reallocated set %p, entries=%p, avail=%d\n",
-                             set, entries, set->availAttrs));
+                if (kDebugTableNoisy) {
+                    ALOGI("Reallocated set %p, entries=%p, avail=%zu\n",
+                            set, entries, set->availAttrs);
+                }
             }
             if (isInside) {
                 // Going in the middle, need to make space.
@@ -3985,11 +4377,13 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
                         sizeof(bag_entry)*(set->numAttrs-curEntry));
                 set->numAttrs++;
             }
-            TABLE_NOISY(printf("#%d: Inserting new attribute: 0x%08x\n",
-                         curEntry, newName));
+            if (kDebugTableNoisy) {
+                ALOGI("#%zu: Inserting new attribute: 0x%08x\n", curEntry, newName);
+            }
         } else {
-            TABLE_NOISY(printf("#%d: Replacing existing attribute: 0x%08x\n",
-                         curEntry, oldName));
+            if (kDebugTableNoisy) {
+                ALOGI("#%zu: Replacing existing attribute: 0x%08x\n", curEntry, oldName);
+            }
         }
 
         bag_entry* cur = entries+curEntry;
@@ -4003,9 +4397,11 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
             return UNKNOWN_ERROR;
         }
 
-        TABLE_NOISY(printf("Setting entry #%d %p: block=%d, name=0x%08x, type=%d, data=0x%08x\n",
-                     curEntry, cur, cur->stringBlock, cur->map.name.ident,
-                     cur->map.value.dataType, cur->map.value.data));
+        if (kDebugTableNoisy) {
+            ALOGI("Setting entry #%zu %p: block=%zd, name=0x%08d, type=%d, data=0x%08x\n",
+                    curEntry, cur, cur->stringBlock, cur->map.name.ident,
+                    cur->map.value.dataType, cur->map.value.data);
+        }
 
         // On to the next!
         curEntry++;
@@ -4025,7 +4421,9 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
             *outTypeSpecFlags = set->typeSpecFlags;
         }
         *outBag = (bag_entry*)(set+1);
-        TABLE_NOISY(ALOGI("Returning %d attrs\n", set->numAttrs));
+        if (kDebugTableNoisy) {
+            ALOGI("Returning %zu attrs\n", set->numAttrs);
+        }
         return set->numAttrs;
     }
     return BAD_INDEX;
@@ -4033,14 +4431,56 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
 
 void ResTable::setParameters(const ResTable_config* params)
 {
-    mLock.lock();
-    TABLE_GETENTRY(ALOGI("Setting parameters: %s\n", params->toString().string()));
+    AutoMutex _lock(mLock);
+    AutoMutex _lock2(mFilteredConfigLock);
+
+    if (kDebugTableGetEntry) {
+        ALOGI("Setting parameters: %s\n", params->toString().string());
+    }
     mParams = *params;
-    for (size_t i=0; i<mPackageGroups.size(); i++) {
-        TABLE_NOISY(ALOGI("CLEARING BAGS FOR GROUP %d!", i));
-        mPackageGroups[i]->clearBagCache();
+    for (size_t p = 0; p < mPackageGroups.size(); p++) {
+        PackageGroup* packageGroup = mPackageGroups.editItemAt(p);
+        if (kDebugTableNoisy) {
+            ALOGI("CLEARING BAGS FOR GROUP %zu!", p);
+        }
+        packageGroup->clearBagCache();
+
+        // Find which configurations match the set of parameters. This allows for a much
+        // faster lookup in getEntry() if the set of values is narrowed down.
+        for (size_t t = 0; t < packageGroup->types.size(); t++) {
+            if (packageGroup->types[t].isEmpty()) {
+                continue;
+            }
+
+            TypeList& typeList = packageGroup->types.editItemAt(t);
+
+            // Retrieve the cache entry for this type.
+            TypeCacheEntry& cacheEntry = packageGroup->typeCacheEntries.editItemAt(t);
+
+            for (size_t ts = 0; ts < typeList.size(); ts++) {
+                Type* type = typeList.editItemAt(ts);
+
+                std::shared_ptr<Vector<const ResTable_type*>> newFilteredConfigs =
+                        std::make_shared<Vector<const ResTable_type*>>();
+
+                for (size_t ti = 0; ti < type->configs.size(); ti++) {
+                    ResTable_config config;
+                    config.copyFromDtoH(type->configs[ti]->config);
+
+                    if (config.match(mParams)) {
+                        newFilteredConfigs->add(type->configs[ti]);
+                    }
+                }
+
+                if (kDebugTableNoisy) {
+                    ALOGD("Updating pkg=%zu type=%zu with %zu filtered configs",
+                          p, t, newFilteredConfigs->size());
+                }
+
+                cacheEntry.filteredConfigs.add(newFilteredConfigs);
+            }
+        }
     }
-    mLock.unlock();
 }
 
 void ResTable::getParameters(ResTable_config* params) const
@@ -4075,7 +4515,9 @@ uint32_t ResTable::identifierForName(const char16_t* name, size_t nameLen,
                                      size_t packageLen,
                                      uint32_t* outTypeSpecFlags) const
 {
-    TABLE_SUPER_NOISY(printf("Identifier for name: error=%d\n", mError));
+    if (kDebugTableSuperNoisy) {
+        printf("Identifier for name: error=%d\n", mError);
+    }
 
     // Check for internal resource identifier as the very first thing, so
     // that we will always find them even when there are no resources.
@@ -4168,10 +4610,12 @@ nope:
     }
     nameLen = nameEnd-name;
 
-    TABLE_NOISY(printf("Looking for identifier: type=%s, name=%s, package=%s\n",
-                 String8(type, typeLen).string(),
-                 String8(name, nameLen).string(),
-                 String8(package, packageLen).string()));
+    if (kDebugTableNoisy) {
+        printf("Looking for identifier: type=%s, name=%s, package=%s\n",
+                String8(type, typeLen).string(),
+                String8(name, nameLen).string(),
+                String8(package, packageLen).string());
+    }
 
     const String16 attr("attr");
     const String16 attrPrivate("^attr-private");
@@ -4182,7 +4626,9 @@ nope:
 
         if (strzcmp16(package, packageLen,
                       group->name.string(), group->name.size())) {
-            TABLE_NOISY(printf("Skipping package group: %s\n", String8(group->name).string()));
+            if (kDebugTableNoisy) {
+                printf("Skipping package group: %s\n", String8(group->name).string());
+            }
             continue;
         }
 
@@ -4406,8 +4852,7 @@ static bool parse_unit(const char* str, Res_value* outValue,
     return false;
 }
 
-
-bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue)
+bool U16StringToInt(const char16_t* s, size_t len, Res_value* outValue)
 {
     while (len > 0 && isspace16(*s)) {
         s++;
@@ -4419,7 +4864,7 @@ bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue)
     }
 
     size_t i = 0;
-    int32_t val = 0;
+    int64_t val = 0;
     bool neg = false;
 
     if (*s == '-') {
@@ -4431,28 +4876,50 @@ bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue)
         return false;
     }
 
+    static_assert(std::is_same<uint32_t, Res_value::data_type>::value,
+                  "Res_value::data_type has changed. The range checks in this "
+                  "function are no longer correct.");
+
     // Decimal or hex?
-    if (s[i] == '0' && s[i+1] == 'x') {
-        if (outValue)
-            outValue->dataType = outValue->TYPE_INT_HEX;
+    bool isHex;
+    if (len > 1 && s[i] == '0' && s[i+1] == 'x') {
+        isHex = true;
         i += 2;
+
+        if (neg) {
+            return false;
+        }
+
+        if (i == len) {
+            // Just u"0x"
+            return false;
+        }
+
         bool error = false;
         while (i < len && !error) {
             val = (val*16) + get_hex(s[i], &error);
             i++;
+
+            if (val > std::numeric_limits<uint32_t>::max()) {
+                return false;
+            }
         }
         if (error) {
             return false;
         }
     } else {
-        if (outValue)
-            outValue->dataType = outValue->TYPE_INT_DEC;
+        isHex = false;
         while (i < len) {
             if (s[i] < '0' || s[i] > '9') {
                 return false;
             }
             val = (val*10) + s[i]-'0';
             i++;
+
+            if ((neg && -val < std::numeric_limits<int32_t>::min()) ||
+                (!neg && val > std::numeric_limits<int32_t>::max())) {
+                return false;
+            }
         }
     }
 
@@ -4462,13 +4929,21 @@ bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue)
         i++;
     }
 
-    if (i == len) {
-        if (outValue)
-            outValue->data = val;
-        return true;
+    if (i != len) {
+        return false;
     }
 
-    return false;
+    if (outValue) {
+        outValue->dataType =
+            isHex ? outValue->TYPE_INT_HEX : outValue->TYPE_INT_DEC;
+        outValue->data = static_cast<Res_value::data_type>(val);
+    }
+    return true;
+}
+
+bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue)
+{
+    return U16StringToInt(s, len, outValue);
 }
 
 bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue)
@@ -4495,7 +4970,7 @@ bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue)
     if (len > 0) {
         return false;
     }
-    if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.') {
+    if ((buf[0] < '0' || buf[0] > '9') && buf[0] != '.' && buf[0] != '-' && buf[0] != '+') {
         return false;
     }
 
@@ -4712,9 +5187,11 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
                     rid = Res_MAKEID(
                         accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
                         Res_GETTYPE(rid), Res_GETENTRY(rid));
-                    TABLE_NOISY(printf("Incl %s:%s/%s: 0x%08x\n",
-                           String8(package).string(), String8(type).string(),
-                           String8(name).string(), rid));
+                    if (kDebugTableNoisy) {
+                        ALOGI("Incl %s:%s/%s: 0x%08x\n",
+                                String8(package).string(), String8(type).string(),
+                                String8(name).string(), rid);
+                    }
                 }
 
                 uint32_t packageId = Res_GETPACKAGE(rid) + 1;
@@ -4729,9 +5206,11 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
                 uint32_t rid = accessor->getCustomResourceWithCreation(package, type, name,
                                                                        createIfNotFound);
                 if (rid != 0) {
-                    TABLE_NOISY(printf("Pckg %s:%s/%s: 0x%08x\n",
-                           String8(package).string(), String8(type).string(),
-                           String8(name).string(), rid));
+                    if (kDebugTableNoisy) {
+                        ALOGI("Pckg %s:%s/%s: 0x%08x\n",
+                                String8(package).string(), String8(type).string(),
+                                String8(name).string(), rid);
+                    }
                     uint32_t packageId = Res_GETPACKAGE(rid) + 1;
                     if (packageId == 0x00) {
                         outValue->data = rid;
@@ -4875,16 +5354,17 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
                     return false;
                 }
             }
-            if (!accessor) {
-                outValue->data = rid;
-                return true;
+
+            if (accessor) {
+                rid = Res_MAKEID(
+                    accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
+                    Res_GETTYPE(rid), Res_GETENTRY(rid));
+            }
+
+            uint32_t packageId = Res_GETPACKAGE(rid) + 1;
+            if (packageId != APP_PACKAGE_ID && packageId != SYS_PACKAGE_ID) {
+                outValue->dataType = Res_value::TYPE_DYNAMIC_ATTRIBUTE;
             }
-            rid = Res_MAKEID(
-                accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
-                Res_GETTYPE(rid), Res_GETENTRY(rid));
-            //printf("Incl %s:%s/%s: 0x%08x\n",
-            //       String8(package).string(), String8(type).string(),
-            //       String8(name).string(), rid);
             outValue->data = rid;
             return true;
         }
@@ -4892,11 +5372,17 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
         if (accessor) {
             uint32_t rid = accessor->getCustomResource(package, type, name);
             if (rid != 0) {
-                //printf("Mine %s:%s/%s: 0x%08x\n",
-                //       String8(package).string(), String8(type).string(),
-                //       String8(name).string(), rid);
-                outValue->data = rid;
-                return true;
+                uint32_t packageId = Res_GETPACKAGE(rid) + 1;
+                if (packageId == 0x00) {
+                    outValue->data = rid;
+                    outValue->dataType = Res_value::TYPE_DYNAMIC_ATTRIBUTE;
+                    return true;
+                } else if (packageId == APP_PACKAGE_ID || packageId == SYS_PACKAGE_ID) {
+                    // We accept packageId's generated as 0x01 in order to support
+                    // building the android system resources
+                    outValue->data = rid;
+                    return true;
+                }
             }
         }
 
@@ -5338,11 +5824,23 @@ const DynamicRefTable* ResTable::getDynamicRefTableForCookie(int32_t cookie) con
     return NULL;
 }
 
-void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap) const
-{
+static bool compareResTableConfig(const ResTable_config& a, const ResTable_config& b) {
+    return a.compare(b) < 0;
+}
+
+template <typename Func>
+void ResTable::forEachConfiguration(bool ignoreMipmap, bool ignoreAndroidPackage,
+                                    bool includeSystemConfigs, const Func& f) const {
     const size_t packageCount = mPackageGroups.size();
+    const String16 android("android");
     for (size_t i = 0; i < packageCount; i++) {
         const PackageGroup* packageGroup = mPackageGroups[i];
+        if (ignoreAndroidPackage && android == packageGroup->name) {
+            continue;
+        }
+        if (!includeSystemConfigs && packageGroup->isSystemAsset) {
+            continue;
+        }
         const size_t typeCount = packageGroup->types.size();
         for (size_t j = 0; j < typeCount; j++) {
             const TypeList& typeList = packageGroup->types[j];
@@ -5361,46 +5859,48 @@ void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMi
                     ResTable_config cfg;
                     memset(&cfg, 0, sizeof(ResTable_config));
                     cfg.copyFromDtoH(config->config);
-                    // only insert unique
-                    const size_t N = configs->size();
-                    size_t n;
-                    for (n = 0; n < N; n++) {
-                        if (0 == (*configs)[n].compare(cfg)) {
-                            break;
-                        }
-                    }
-                    // if we didn't find it
-                    if (n == N) {
-                        configs->add(cfg);
-                    }
+
+                    f(cfg);
                 }
             }
         }
     }
 }
 
-void ResTable::getLocales(Vector<String8>* locales) const
-{
-    Vector<ResTable_config> configs;
-    ALOGV("calling getConfigurations");
-    getConfigurations(&configs);
-    ALOGV("called getConfigurations size=%d", (int)configs.size());
-    const size_t I = configs.size();
+void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap,
+                                 bool ignoreAndroidPackage, bool includeSystemConfigs) const {
+    auto func = [&](const ResTable_config& cfg) {
+        const auto beginIter = configs->begin();
+        const auto endIter = configs->end();
 
+        auto iter = std::lower_bound(beginIter, endIter, cfg, compareResTableConfig);
+        if (iter == endIter || iter->compare(cfg) != 0) {
+            configs->insertAt(cfg, std::distance(beginIter, iter));
+        }
+    };
+    forEachConfiguration(ignoreMipmap, ignoreAndroidPackage, includeSystemConfigs, func);
+}
+
+static bool compareString8AndCString(const String8& str, const char* cStr) {
+    return strcmp(str.string(), cStr) < 0;
+}
+
+void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales) const {
     char locale[RESTABLE_MAX_LOCALE_LEN];
-    for (size_t i=0; i<I; i++) {
-        configs[i].getBcp47Locale(locale);
-        const size_t J = locales->size();
-        size_t j;
-        for (j=0; j<J; j++) {
-            if (0 == strcmp(locale, (*locales)[j].string())) {
-                break;
+
+    forEachConfiguration(false, false, includeSystemLocales, [&](const ResTable_config& cfg) {
+        if (cfg.locale != 0) {
+            cfg.getBcp47Locale(locale);
+
+            const auto beginIter = locales->begin();
+            const auto endIter = locales->end();
+
+            auto iter = std::lower_bound(beginIter, endIter, locale, compareString8AndCString);
+            if (iter == endIter || strcmp(iter->string(), locale) != 0) {
+                locales->insertAt(String8(locale), std::distance(beginIter, iter));
             }
         }
-        if (j == J) {
-            locales->add(String8(locale));
-        }
-    }
+    });
 }
 
 StringPoolRef::StringPoolRef(const ResStringPool* pool, uint32_t index)
@@ -5524,9 +6024,32 @@ status_t ResTable::getEntry(
             specFlags = -1;
         }
 
-        const size_t numConfigs = typeSpec->configs.size();
+        const Vector<const ResTable_type*>* candidateConfigs = &typeSpec->configs;
+
+        std::shared_ptr<Vector<const ResTable_type*>> filteredConfigs;
+        if (config && memcmp(&mParams, config, sizeof(mParams)) == 0) {
+            // Grab the lock first so we can safely get the current filtered list.
+            AutoMutex _lock(mFilteredConfigLock);
+
+            // This configuration is equal to the one we have previously cached for,
+            // so use the filtered configs.
+
+            const TypeCacheEntry& cacheEntry = packageGroup->typeCacheEntries[typeIndex];
+            if (i < cacheEntry.filteredConfigs.size()) {
+                if (cacheEntry.filteredConfigs[i]) {
+                    // Grab a reference to the shared_ptr so it doesn't get destroyed while
+                    // going through this list.
+                    filteredConfigs = cacheEntry.filteredConfigs[i];
+
+                    // Use this filtered list.
+                    candidateConfigs = filteredConfigs.get();
+                }
+            }
+        }
+
+        const size_t numConfigs = candidateConfigs->size();
         for (size_t c = 0; c < numConfigs; c++) {
-            const ResTable_type* const thisType = typeSpec->configs[c];
+            const ResTable_type* const thisType = candidateConfigs->itemAt(c);
             if (thisType == NULL) {
                 continue;
             }
@@ -5540,8 +6063,6 @@ status_t ResTable::getEntry(
             }
 
             // Check if there is the desired entry in this type.
-            const uint8_t* const end = reinterpret_cast<const uint8_t*>(thisType)
-                    + dtohl(thisType->header.size);
             const uint32_t* const eindex = reinterpret_cast<const uint32_t*>(
                     reinterpret_cast<const uint8_t*>(thisType) + dtohs(thisType->header.headerSize));
 
@@ -5611,7 +6132,7 @@ status_t ResTable::getEntry(
 }
 
 status_t ResTable::parsePackage(const ResTable_package* const pkg,
-                                const Header* const header)
+                                const Header* const header, bool appAsLib, bool isSystemAsset)
 {
     const uint8_t* base = (const uint8_t*)pkg;
     status_t err = validate_chunk(&pkg->header, sizeof(*pkg) - sizeof(pkg->typeIdOffset),
@@ -5659,8 +6180,8 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
     if (id >= 256) {
         LOG_ALWAYS_FATAL("Package id out of range");
         return NO_ERROR;
-    } else if (id == 0) {
-        // This is a library so assign an ID
+    } else if (id == 0 || (id == 0x7f && appAsLib) || isSystemAsset) {
+        // This is a library or a system asset, so assign an ID
         id = mNextPackageId++;
     }
 
@@ -5692,7 +6213,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
 
         char16_t tmpName[sizeof(pkg->name)/sizeof(pkg->name[0])];
         strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(pkg->name[0]));
-        group = new PackageGroup(this, String16(tmpName), id);
+        group = new PackageGroup(this, String16(tmpName), id, appAsLib, isSystemAsset);
         if (group == NULL) {
             delete package;
             return (mError=NO_MEMORY);
@@ -5730,9 +6251,11 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
     const uint8_t* endPos = ((const uint8_t*)pkg) + dtohs(pkg->header.size);
     while (((const uint8_t*)chunk) <= (endPos-sizeof(ResChunk_header)) &&
            ((const uint8_t*)chunk) <= (endPos-dtohl(chunk->size))) {
-        TABLE_NOISY(ALOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
-                         dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
-                         (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header))));
+        if (kDebugTableNoisy) {
+            ALOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
+                    dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
+                    (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
+        }
         const size_t csize = dtohl(chunk->size);
         const uint16_t ctype = dtohs(chunk->type);
         if (ctype == RES_TABLE_TYPE_SPEC_TYPE) {
@@ -5746,11 +6269,13 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
             const size_t typeSpecSize = dtohl(typeSpec->header.size);
             const size_t newEntryCount = dtohl(typeSpec->entryCount);
 
-            LOAD_TABLE_NOISY(printf("TypeSpec off %p: type=0x%x, headerSize=0x%x, size=%p\n",
-                                    (void*)(base-(const uint8_t*)chunk),
-                                    dtohs(typeSpec->header.type),
-                                    dtohs(typeSpec->header.headerSize),
-                                    (void*)typeSpecSize));
+            if (kDebugLoadTableNoisy) {
+                ALOGI("TypeSpec off %p: type=0x%x, headerSize=0x%x, size=%p\n",
+                        (void*)(base-(const uint8_t*)chunk),
+                        dtohs(typeSpec->header.type),
+                        dtohs(typeSpec->header.headerSize),
+                        (void*)typeSpecSize);
+            }
             // look for block overrun or int overflow when multiplying by 4
             if ((dtohl(typeSpec->entryCount) > (INT32_MAX/sizeof(uint32_t))
                     || dtohs(typeSpec->header.headerSize)+(sizeof(uint32_t)*newEntryCount)
@@ -5808,13 +6333,14 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
             const uint32_t typeSize = dtohl(type->header.size);
             const size_t newEntryCount = dtohl(type->entryCount);
 
-            LOAD_TABLE_NOISY(printf("Type off %p: type=0x%x, headerSize=0x%x, size=%p\n",
-                                    (void*)(base-(const uint8_t*)chunk),
-                                    dtohs(type->header.type),
-                                    dtohs(type->header.headerSize),
-                                    (void*)typeSize));
-            if (dtohs(type->header.headerSize)+(sizeof(uint32_t)*newEntryCount)
-                    > typeSize) {
+            if (kDebugLoadTableNoisy) {
+                printf("Type off %p: type=0x%x, headerSize=0x%x, size=%u\n",
+                        (void*)(base-(const uint8_t*)chunk),
+                        dtohs(type->header.type),
+                        dtohs(type->header.headerSize),
+                        typeSize);
+            }
+            if (dtohs(type->header.headerSize)+(sizeof(uint32_t)*newEntryCount) > typeSize) {
                 ALOGW("ResTable_type entry index to %p extends beyond chunk end 0x%x.",
                         (void*)(dtohs(type->header.headerSize) + (sizeof(uint32_t)*newEntryCount)),
                         typeSize);
@@ -5860,11 +6386,12 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
 
                 t->configs.add(type);
 
-                TABLE_GETENTRY(
+                if (kDebugTableGetEntry) {
                     ResTable_config thisConfig;
                     thisConfig.copyFromDtoH(type->config);
-                    ALOGI("Adding config to type %d: %s\n",
-                          type->id, thisConfig.toString().string()));
+                    ALOGI("Adding config to type %d: %s\n", type->id,
+                            thisConfig.toString().string());
+                }
             } else {
                 ALOGV("Skipping empty ResTable_type for type %d", type->id);
             }
@@ -5898,8 +6425,9 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
     return NO_ERROR;
 }
 
-DynamicRefTable::DynamicRefTable(uint8_t packageId)
+DynamicRefTable::DynamicRefTable(uint8_t packageId, bool appAsLib)
     : mAssignedPackageId(packageId)
+    , mAppAsLib(appAsLib)
 {
     memset(mLookupTable, 0, sizeof(mLookupTable));
 
@@ -5925,8 +6453,10 @@ status_t DynamicRefTable::load(const ResTable_lib_header* const header)
         uint32_t packageId = dtohl(entry->packageId);
         char16_t tmpName[sizeof(entry->packageName) / sizeof(char16_t)];
         strcpy16_dtoh(tmpName, entry->packageName, sizeof(entry->packageName) / sizeof(char16_t));
-        LIB_NOISY(ALOGV("Found lib entry %s with id %d\n", String8(tmpName).string(),
-                dtohl(entry->packageId)));
+        if (kDebugLibNoisy) {
+            ALOGV("Found lib entry %s with id %d\n", String8(tmpName).string(),
+                    dtohl(entry->packageId));
+        }
         if (packageId >= 256) {
             ALOGE("Bad package id 0x%08x", packageId);
             return UNKNOWN_ERROR;
@@ -5982,16 +6512,18 @@ status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const {
     uint32_t res = *resId;
     size_t packageId = Res_GETPACKAGE(res) + 1;
 
-    if (packageId == APP_PACKAGE_ID) {
+    if (packageId == APP_PACKAGE_ID && !mAppAsLib) {
         // No lookup needs to be done, app package IDs are absolute.
         return NO_ERROR;
     }
 
-    if (packageId == 0) {
+    if (packageId == 0 || (packageId == APP_PACKAGE_ID && mAppAsLib)) {
         // The package ID is 0x00. That means that a shared library is accessing
-        // its own local resource, so we fix up the resource with the calling
-        // package ID.
-        *resId |= ((uint32_t) mAssignedPackageId) << 24;
+        // its own local resource.
+        // Or if app resource is loaded as shared library, the resource which has
+        // app package Id is local resources.
+        // so we fix up those resources with the calling package ID.
+        *resId = (0xFFFFFF & (*resId)) | (((uint32_t) mAssignedPackageId) << 24);
         return NO_ERROR;
     }
 
@@ -6013,7 +6545,25 @@ status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const {
 }
 
 status_t DynamicRefTable::lookupResourceValue(Res_value* value) const {
-    if (value->dataType != Res_value::TYPE_DYNAMIC_REFERENCE) {
+    uint8_t resolvedType = Res_value::TYPE_REFERENCE;
+    switch (value->dataType) {
+    case Res_value::TYPE_ATTRIBUTE:
+        resolvedType = Res_value::TYPE_ATTRIBUTE;
+        // fallthrough
+    case Res_value::TYPE_REFERENCE:
+        if (!mAppAsLib) {
+            return NO_ERROR;
+        }
+
+        // If the package is loaded as shared library, the resource reference
+        // also need to be fixed.
+        break;
+    case Res_value::TYPE_DYNAMIC_ATTRIBUTE:
+        resolvedType = Res_value::TYPE_ATTRIBUTE;
+        // fallthrough
+    case Res_value::TYPE_DYNAMIC_REFERENCE:
+        break;
+    default:
         return NO_ERROR;
     }
 
@@ -6022,7 +6572,7 @@ status_t DynamicRefTable::lookupResourceValue(Res_value* value) const {
         return err;
     }
 
-    value->dataType = Res_value::TYPE_REFERENCE;
+    value->dataType = resolvedType;
     return NO_ERROR;
 }
 
@@ -6109,20 +6659,20 @@ status_t ResTable::createIdmap(const ResTable& overlay,
 
             if (Res_GETTYPE(overlayResID) + 1 != static_cast<size_t>(typeMap.overlayTypeId)) {
                 ALOGE("idmap: can't mix type ids in entry map. Resource 0x%08x maps to 0x%08x"
-                        " but entries should map to resources of type %02x",
+                        " but entries should map to resources of type %02zx",
                         resID, overlayResID, typeMap.overlayTypeId);
                 return BAD_TYPE;
             }
 
             if (typeMap.entryOffset + typeMap.entryMap.size() < entryIndex) {
-                // Resize to accomodate this entry and the 0's in between.
-                if (typeMap.entryMap.resize((entryIndex - typeMap.entryOffset) + 1) < 0) {
+                // pad with 0xffffffff's (indicating non-existing entries) before adding this entry
+                size_t index = typeMap.entryMap.size();
+                size_t numItems = entryIndex - (typeMap.entryOffset + index);
+                if (typeMap.entryMap.insertAt(0xffffffff, index, numItems) < 0) {
                     return NO_MEMORY;
                 }
-                typeMap.entryMap.editTop() = Res_GETENTRY(overlayResID);
-            } else {
-                typeMap.entryMap.add(Res_GETENTRY(overlayResID));
             }
+            typeMap.entryMap.add(Res_GETENTRY(overlayResID));
         }
 
         if (!typeMap.entryMap.isEmpty()) {
@@ -6300,6 +6850,8 @@ void ResTable::print_value(const Package* pkg, const Res_value& value) const
         printf("(dynamic reference) 0x%08x\n", value.data);
     } else if (value.dataType == Res_value::TYPE_ATTRIBUTE) {
         printf("(attribute) 0x%08x\n", value.data);
+    } else if (value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE) {
+        printf("(dynamic attribute) 0x%08x\n", value.data);
     } else if (value.dataType == Res_value::TYPE_STRING) {
         size_t len;
         const char* str8 = pkg->header->values.string8At(
@@ -6430,7 +6982,13 @@ void ResTable::print(bool inclValues) const
                     printf("      NON-INTEGER ResTable_type ADDRESS: %p\n", type);
                     continue;
                 }
-                String8 configStr = type->config.toString();
+
+                // Always copy the config, as fields get added and we need to
+                // set the defaults.
+                ResTable_config thisConfig;
+                thisConfig.copyFromDtoH(type->config);
+
+                String8 configStr = thisConfig.toString();
                 printf("      config %s:\n", configStr.size() > 0
                         ? configStr.string() : "(default)");
                 size_t entryCount = dtohl(type->entryCount);
@@ -6445,9 +7003,6 @@ void ResTable::print(bool inclValues) const
                     continue;
                 }
                 for (size_t entryIndex=0; entryIndex<entryCount; entryIndex++) {
-
-                    const uint8_t* const end = ((const uint8_t*)type)
-                        + dtohl(type->header.size);
                     const uint32_t* const eindex = (const uint32_t*)
                         (((const uint8_t*)type) + dtohs(type->header.headerSize));