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

Commit f94b34f5 authored by Dianne Hackborn's avatar Dianne Hackborn Committed by Android (Google) Code Review
Browse files

Merge "Resource memory optimization."

parents 552436d1 d45c68dd
Loading
Loading
Loading
Loading
+25 −9
Original line number Diff line number Diff line
@@ -586,7 +586,7 @@ static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject
    }

    ResTable::resource_name name;
    if (!am->getResources().getResourceName(resid, &name)) {
    if (!am->getResources().getResourceName(resid, true, &name)) {
        return NULL;
    }

@@ -594,20 +594,28 @@ static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject
    if (name.package != NULL) {
        str.setTo(name.package, name.packageLen);
    }
    if (name.type != NULL) {
    if (name.type8 != NULL || name.type != NULL) {
        if (str.size() > 0) {
            char16_t div = ':';
            str.append(&div, 1);
        }
        if (name.type8 != NULL) {
            str.append(String16(name.type8, name.typeLen));
        } else {
            str.append(name.type, name.typeLen);
        }
    if (name.name != NULL) {
    }
    if (name.name8 != NULL || name.name != NULL) {
        if (str.size() > 0) {
            char16_t div = '/';
            str.append(&div, 1);
        }
        if (name.name8 != NULL) {
            str.append(String16(name.name8, name.nameLen));
        } else {
            str.append(name.name, name.nameLen);
        }
    }

    return env->NewString((const jchar*)str.string(), str.size());
}
@@ -621,7 +629,7 @@ static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env,
    }

    ResTable::resource_name name;
    if (!am->getResources().getResourceName(resid, &name)) {
    if (!am->getResources().getResourceName(resid, true, &name)) {
        return NULL;
    }

@@ -641,10 +649,14 @@ static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, job
    }

    ResTable::resource_name name;
    if (!am->getResources().getResourceName(resid, &name)) {
    if (!am->getResources().getResourceName(resid, true, &name)) {
        return NULL;
    }

    if (name.type8 != NULL) {
        return env->NewStringUTF(name.type8);
    }

    if (name.type != NULL) {
        return env->NewString((const jchar*)name.type, name.typeLen);
    }
@@ -661,10 +673,14 @@ static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jo
    }

    ResTable::resource_name name;
    if (!am->getResources().getResourceName(resid, &name)) {
    if (!am->getResources().getResourceName(resid, true, &name)) {
        return NULL;
    }

    if (name.name8 != NULL) {
        return env->NewStringUTF(name.name8);
    }

    if (name.name != NULL) {
        return env->NewString((const jchar*)name.name, name.nameLen);
    }
@@ -680,7 +696,7 @@ static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject
{
    if (outValue == NULL) {
         jniThrowNullPointerException(env, "outValue");
         return NULL;
         return 0;
    }
    AssetManager* am = assetManagerForJavaObject(env, clazz);
    if (am == NULL) {
+10 −4
Original line number Diff line number Diff line
@@ -479,7 +479,7 @@ private:
    const uint32_t*             mEntries;
    const uint32_t*             mEntryStyles;
    const void*                 mStrings;
    char16_t**                  mCache;
    char16_t mutable**          mCache;
    uint32_t                    mStringPoolSize;    // number of uint16_t
    const uint32_t*             mStyles;
    uint32_t                    mStylePoolSize;    // number of uint32_t
@@ -683,6 +683,10 @@ public:
    const uint16_t* getAttributeName(size_t idx, size_t* outLen) const;
    uint32_t getAttributeNameResID(size_t idx) const;

    // These will work only if the underlying string pool is UTF-8.
    const char* getAttributeNamespace8(size_t idx, size_t* outLen) const;
    const char* getAttributeName8(size_t idx, size_t* outLen) const;

    int32_t getAttributeValueStringID(size_t idx) const;
    const uint16_t* getAttributeStringValue(size_t idx, size_t* outLen) const;
    
@@ -1294,12 +1298,14 @@ public:
        const char16_t* package;
        size_t packageLen;
        const char16_t* type;
        const char* type8;
        size_t typeLen;
        const char16_t* name;
        const char* name8;
        size_t nameLen;
    };

    bool getResourceName(uint32_t resID, resource_name* outName) const;
    bool getResourceName(uint32_t resID, bool allowUtf8, resource_name* outName) const;

    /**
     * Retrieve the value of a resource.  If the resource is found, returns a
+257 −83
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@
#define INT32_MAX ((int32_t)(2147483647))
#endif

#define POOL_NOISY(x) //x
#define STRING_POOL_NOISY(x) //x
#define XML_NOISY(x) //x
#define TABLE_NOISY(x) //x
#define TABLE_GETENTRY(x) //x
@@ -378,7 +378,6 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
        size_t charSize;
        if (mHeader->flags&ResStringPool_header::UTF8_FLAG) {
            charSize = sizeof(uint8_t);
            mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**));
        } else {
            charSize = sizeof(char16_t);
        }
@@ -593,6 +592,23 @@ const uint16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const
                if ((uint32_t)(u8str+u8len-strings) < mStringPoolSize) {
                    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**)));
#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**));
#endif
                        mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**));
                        if (mCache == NULL) {
                            ALOGW("No memory trying to allocate decode cache table of %d bytes\n",
                                    (int)(mHeader->stringCount*sizeof(char16_t**)));
                            return NULL;
                        }
                    }

                    if (mCache[idx] != NULL) {
                        return mCache[idx];
                    }
@@ -612,6 +628,7 @@ const uint16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const
                        return NULL;
                    }

                    STRING_POOL_NOISY(ALOGI("Caching UTF8 string: %s", u8str));
                    utf8_to_utf16(u8str, u8len, u16str);
                    mCache[idx] = u16str;
                    return u16str;
@@ -633,10 +650,11 @@ const uint16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const
const char* ResStringPool::string8At(size_t idx, size_t* outLen) const
{
    if (mError == NO_ERROR && idx < mHeader->stringCount) {
        const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0;
        const uint32_t off = mEntries[idx]/(isUTF8?sizeof(char):sizeof(char16_t));
        if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) == 0) {
            return NULL;
        }
        const uint32_t off = mEntries[idx]/sizeof(char);
        if (off < (mStringPoolSize-1)) {
            if (isUTF8) {
            const uint8_t* strings = (uint8_t*)mStrings;
            const uint8_t* str = strings+off;
            *outLen = decodeLength(&str);
@@ -647,7 +665,6 @@ const char* ResStringPool::string8At(size_t idx, size_t* outLen) const
                ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
                        (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize);
            }
            }
        } else {
            ALOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
                    (int)idx, (int)(off*sizeof(uint16_t)),
@@ -695,9 +712,67 @@ ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const

    size_t len;

    // TODO optimize searching for UTF-8 strings taking into account
    // the cache fill to determine when to convert the searched-for
    // string key to UTF-8.
    if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) {
        STRING_POOL_NOISY(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.
        if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
            // Do a binary search for the string...  this is a little tricky,
            // because the strings are sorted with strzcmp16().  So to match
            // the ordering, we need to convert strings in the pool to UTF-16.
            // But we don't want to hit the cache, so instead we will have a
            // local temporary allocation for the conversions.
            char16_t* convBuffer = (char16_t*)malloc(strLen+4);
            ssize_t l = 0;
            ssize_t h = mHeader->stringCount-1;

            ssize_t mid;
            while (l <= h) {
                mid = l + (h - l)/2;
                const uint8_t* s = (const uint8_t*)string8At(mid, &len);
                int c;
                if (s != NULL) {
                    char16_t* end = utf8_to_utf16_n(s, len, convBuffer, strLen+3);
                    *end = 0;
                    c = strzcmp16(convBuffer, end-convBuffer, str, strLen);
                } 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 (c == 0) {
                    STRING_POOL_NOISY(ALOGI("MATCH!"));
                    free(convBuffer);
                    return mid;
                } else if (c < 0) {
                    l = mid + 1;
                } else {
                    h = mid - 1;
                }
            }
            free(convBuffer);
        } else {
            // It is unusual to get the ID from an unsorted string block...
            // most often this happens because we want to get IDs for style
            // span tags; since those always appear at the end of the string
            // block, start searching at the back.
            String8 str8(str, strLen);
            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 (s && str8Len == len && memcmp(s, str8.string(), str8Len) == 0) {
                    STRING_POOL_NOISY(ALOGI("MATCH!"));
                    return i;
                }
            }
        }

    } else {
        STRING_POOL_NOISY(ALOGI("indexOfString UTF-16: %s", String8(str, strLen).string()));

        if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
            // Do a binary search for the string...
@@ -709,11 +784,11 @@ 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;
            POOL_NOISY(printf("Looking for %s, at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
                         String8(str).string(),
                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 (c == 0) {
                    STRING_POOL_NOISY(ALOGI("MATCH!"));
                    return mid;
                } else if (c < 0) {
                    l = mid + 1;
@@ -728,15 +803,16 @@ 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);
            POOL_NOISY(printf("Looking for %s, at %s, i=%d\n",
                         String8(str, strLen).string(),
                STRING_POOL_NOISY(ALOGI("Looking at %s, i=%d\n",
                             String8(s).string(),
                             i));
            if (s && strzcmp16(s, len, str, strLen) == 0) {
                if (s && strLen == len && strzcmp16(s, len, str, strLen) == 0) {
                    STRING_POOL_NOISY(ALOGI("MATCH!"));
                    return i;
                }
            }
        }
    }

    return NAME_NOT_FOUND;
}
@@ -936,6 +1012,14 @@ const uint16_t* ResXMLParser::getAttributeNamespace(size_t idx, size_t* outLen)
    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
}

const char* ResXMLParser::getAttributeNamespace8(size_t idx, size_t* outLen) const
{
    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));
    return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL;
}

int32_t ResXMLParser::getAttributeNameID(size_t idx) const
{
    if (mEventCode == START_TAG) {
@@ -959,6 +1043,14 @@ const uint16_t* ResXMLParser::getAttributeName(size_t idx, size_t* outLen) const
    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
}

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));
    return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL;
}

uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const
{
    int32_t id = getAttributeNameID(idx);
@@ -1048,22 +1140,67 @@ ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen,
                                       const char16_t* attr, size_t attrLen) const
{
    if (mEventCode == START_TAG) {
        if (attr == NULL) {
            return NAME_NOT_FOUND;
        }
        const size_t N = getAttributeCount();
        if (mTree.mStrings.isUTF8()) {
            String8 ns8, attr8;
            if (ns != NULL) {
                ns8 = String8(ns, nsLen);
            }
            attr8 = String8(attr, attrLen);
            STRING_POOL_NOISY(ALOGI("indexOfAttribute UTF8 %s (%d) / %s (%d)", 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 (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen
                        && memcmp(attr8.string(), curAttr, attrLen) == 0) {
                    if (ns == NULL) {
                        if (curNs == NULL) {
                            STRING_POOL_NOISY(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!"));
                            return i;
                        }
                    }
                }
            }
        } else {
            STRING_POOL_NOISY(ALOGI("indexOfAttribute UTF16 %s (%d) / %s (%d)",
                    String8(ns, nsLen).string(), nsLen,
                    String8(attr, attrLen).string(), attrLen));
            for (size_t i=0; i<N; i++) {
            size_t curNsLen, curAttrLen;
                size_t curNsLen = 0, curAttrLen = 0;
                const char16_t* curNs = getAttributeNamespace(i, &curNsLen);
                const char16_t* curAttr = getAttributeName(i, &curAttrLen);
            //printf("%d: ns=%p attr=%p curNs=%p curAttr=%p\n",
            //       i, ns, attr, curNs, curAttr);
            //printf(" --> attr=%s, curAttr=%s\n",
            //       String8(attr).string(), String8(curAttr).string());
            if (attr && curAttr && (strzcmp16(attr, attrLen, curAttr, curAttrLen) == 0)) {
                STRING_POOL_NOISY(ALOGI("  curNs=%s (%d), curAttr=%s (%d)",
                        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) return i;
                        if (curNs == NULL) {
                            STRING_POOL_NOISY(ALOGI("  FOUND!"));
                            return i;
                        }
                    } else if (curNs != NULL) {
                        //printf(" --> ns=%s, curNs=%s\n",
                        //       String8(ns).string(), String8(curNs).string());
                    if (strzcmp16(ns, nsLen, curNs, curNsLen) == 0) return i;
                        if (memcmp(ns, curNs, nsLen*sizeof(char16_t)) == 0) {
                            STRING_POOL_NOISY(ALOGI("  FOUND!"));
                            return i;
                        }
                    }
                }
            }
        }
@@ -2940,7 +3077,7 @@ void ResTable::uninit()
    mHeaders.clear();
}

bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const
bool ResTable::getResourceName(uint32_t resID, bool allowUtf8, resource_name* outName) const
{
    if (mError != NO_ERROR) {
        return false;
@@ -2980,14 +3117,29 @@ bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const

        outName->package = grp->name.string();
        outName->packageLen = grp->name.size();
        if (allowUtf8) {
            outName->type8 = grp->basePackage->typeStrings.string8At(t, &outName->typeLen);
            outName->name8 = grp->basePackage->keyStrings.string8At(
                dtohl(entry->key.index), &outName->nameLen);
        } else {
            outName->type8 = NULL;
            outName->name8 = NULL;
        }
        if (outName->type8 == NULL) {
            outName->type = grp->basePackage->typeStrings.stringAt(t, &outName->typeLen);
            // If we have a bad index for some reason, we should abort.
            if (outName->type == NULL) {
                return false;
            }
        }
        if (outName->name8 == NULL) {
            outName->name = grp->basePackage->keyStrings.stringAt(
                dtohl(entry->key.index), &outName->nameLen);

            // If we have a bad index for some reason, we should abort.
        if (outName->type == NULL || outName->name == NULL) {
            if (outName->name == NULL) {
                return false;
            }
        }

        return true;
    }
@@ -4485,7 +4637,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
            while (cnt > 0) {
                if (!Res_INTERNALID(bag->map.name.ident)) {
                    //printf("Trying attr #%08x\n", bag->map.name.ident);
                    if (getResourceName(bag->map.name.ident, &rname)) {
                    if (getResourceName(bag->map.name.ident, false, &rname)) {
                        #if 0
                        printf("Matching %s against %s (0x%08x)\n",
                               String8(s, len).string(),
@@ -4538,7 +4690,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
                for (i=0; i<cnt; i++, bagi++) {
                    if (!Res_INTERNALID(bagi->map.name.ident)) {
                        //printf("Trying attr #%08x\n", bagi->map.name.ident);
                        if (getResourceName(bagi->map.name.ident, &rname)) {
                        if (getResourceName(bagi->map.name.ident, false, &rname)) {
                            #if 0
                            printf("Matching %s against %s (0x%08x)\n",
                                   String8(start,pos-start).string(),
@@ -5216,7 +5368,7 @@ status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, ui
                | (0x00ff0000 & ((typeIndex+1)<<16))
                | (0x0000ffff & (entryIndex));
            resource_name resName;
            if (!this->getResourceName(resID, &resName)) {
            if (!this->getResourceName(resID, true, &resName)) {
                ALOGW("idmap: resource 0x%08x has spec but lacks values, skipping\n", resID);
                // add dummy value, or trimming leading/trailing zeroes later will fail
                vector.push(0);
@@ -5483,12 +5635,23 @@ void ResTable::print(bool inclValues) const
                                    | (0x00ff0000 & ((typeIndex+1)<<16))
                                    | (0x0000ffff & (entryIndex));
                        resource_name resName;
                        if (this->getResourceName(resID, &resName)) {
                        if (this->getResourceName(resID, true, &resName)) {
                            String8 type8;
                            String8 name8;
                            if (resName.type8 != NULL) {
                                type8 = String8(resName.type8, resName.typeLen);
                            } else {
                                type8 = String8(resName.type, resName.typeLen);
                            }
                            if (resName.name8 != NULL) {
                                name8 = String8(resName.name8, resName.nameLen);
                            } else {
                                name8 = String8(resName.name, resName.nameLen);
                            }
                            printf("      spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
                                resID,
                                CHAR16_TO_CSTR(resName.package, resName.packageLen),
                                CHAR16_TO_CSTR(resName.type, resName.typeLen),
                                CHAR16_TO_CSTR(resName.name, resName.nameLen),
                                type8.string(), name8.string(),
                                dtohl(typeConfigs->typeSpecFlags[entryIndex]));
                        } else {
                            printf("      INVALID TYPE CONFIG FOR RESOURCE 0x%08x\n", resID);
@@ -5531,11 +5694,22 @@ void ResTable::print(bool inclValues) const
                                    | (0x00ff0000 & ((typeIndex+1)<<16))
                                    | (0x0000ffff & (entryIndex));
                        resource_name resName;
                        if (this->getResourceName(resID, &resName)) {
                        if (this->getResourceName(resID, true, &resName)) {
                            String8 type8;
                            String8 name8;
                            if (resName.type8 != NULL) {
                                type8 = String8(resName.type8, resName.typeLen);
                            } else {
                                type8 = String8(resName.type, resName.typeLen);
                            }
                            if (resName.name8 != NULL) {
                                name8 = String8(resName.name8, resName.nameLen);
                            } else {
                                name8 = String8(resName.name, resName.nameLen);
                            }
                            printf("        resource 0x%08x %s:%s/%s: ", resID,
                                    CHAR16_TO_CSTR(resName.package, resName.packageLen),
                                    CHAR16_TO_CSTR(resName.type, resName.typeLen),
                                    CHAR16_TO_CSTR(resName.name, resName.nameLen));
                                    type8.string(), name8.string());
                        } else {
                            printf("        INVALID RESOURCE 0x%08x: ", resID);
                        }