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

Commit 7b467d8b authored by Kenny Root's avatar Kenny Root
Browse files

Dedupe resource config pointers

When there are two configs in a StringPool that would match a string ID
only keep the more generic entry to save some space. This means that if
you have both "es" and "es_US" translations that have the same
translation, the string entry would be removed from the "es_US" config.

Change-Id: I4d619942d35ddb477e2eabe4437b7f02697c24de
parent 4aaf256e
Loading
Loading
Loading
Loading
+167 −2
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <stdarg.h>

#define NOISY(x) //x
#define NOISY_REF(x) //x

status_t compileXmlFile(const sp<AaptAssets>& assets,
                        const sp<AaptFile>& target,
@@ -1933,7 +1934,7 @@ bool ResourceTable::stringToValue(Res_value* outValue, StringPool* pool,
        // information we have already processed that string!
        outValue->size = sizeof(Res_value);
        outValue->res0 = 0;
        outValue->dataType = outValue->TYPE_STRING;
        outValue->dataType = Res_value::TYPE_STRING;
        outValue->data = 0;
        finalStr = str;
    }
@@ -1942,7 +1943,7 @@ bool ResourceTable::stringToValue(Res_value* outValue, StringPool* pool,
        return false;
    }

    if (outValue->dataType == outValue->TYPE_STRING) {
    if (outValue->dataType == Res_value::TYPE_STRING) {
        // Should do better merging styles.
        if (pool) {
            if (style != NULL && style->size() > 0) {
@@ -2530,6 +2531,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
    // Iterate through all data, collecting all values (strings,
    // references, etc).
    StringPool valueStrings = StringPool(false, bundle->getUTF8());
    ResourceConfigReferences configRefs;
    for (pi=0; pi<N; pi++) {
        sp<Package> p = mOrderedPackages.itemAt(pi);
        if (p->getTypes().size() == 0) {
@@ -2570,6 +2572,13 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
                    if (err != NO_ERROR) {
                        return err;
                    }
                    if (e->getType() == Entry::TYPE_ITEM) {
                        const Item* item = e->getItem();
                        if (item != NULL) {
                            uint32_t poolIndex = item->parsedValue.data;
                            configRefs.add(poolIndex, config);
                        }
                    }
                }
            }
        }
@@ -2578,6 +2587,70 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
        p->setKeyStrings(keyStrings.createStringBlock());
    }

    NOISY_REF(configRefs.dump();)

    // Trim all entries in config tables that are not roots for that string.
    // i.e., rely on the resource system to grab the string from the more
    // generic pool during runtime to save space.
    for (pi=0; pi<N; pi++) {
        sp<Package> p = mOrderedPackages.itemAt(pi);
        if (p->getTypes().size() == 0) {
            // Empty, skip!
            continue;
        }
        const size_t TN = p->getOrderedTypes().size();
        for (size_t ti=0; ti<TN; ti++) {
            sp<Type> t = p->getOrderedTypes().itemAt(ti);
            if (t == NULL) {
                continue;
            }
            size_t CN = t->getOrderedConfigs().size();
            for (size_t ci=0; ci<CN; ci++) {
                sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci);
                if (c == NULL) {
                    continue;
                }
                DefaultKeyedVector<ConfigDescription, sp<Entry> > newEntries;
                size_t EN = c->getEntries().size();
                for (size_t ei=0; ei<EN; ++ei) {
                    ConfigDescription config = c->getEntries().keyAt(ei);
                    if (!filter.match(config)) {
                        continue;
                    }
                    sp<Entry> e = c->getEntries().valueAt(ei);
                    if (e == NULL) {
                        continue;
                    }
                    if (e->getType() == Entry::TYPE_ITEM) {
                        const Item* item = e->getItem();
                        if (item != NULL) {
                            uint32_t poolIndex = item->parsedValue.data;
                            if (!configRefs.isRoot(poolIndex, config)) {
                                NOISY_REF(
                                    printf("  ConfigRef %d: removing ", poolIndex);
                                    DEBUG_LANG(config)
                                    printf("\n");
                                )
                                c->removeEntryAt(ei);
                                t->removeUniqueConfig(config);
                                --ei; --EN;
                            }
                        }
                    }
                }
                if (EN == 0) {
                    // We removed all the entries from a config, so remove the
                    // config itself.
                    NOISY_REF(
                        printf("  ConfigRef REMOVED ENTIRE CONFIG\n");
                    )
                    t->removeOrderedConfigAt(ci);
                    --ci; --CN;
                }
            }
        }
    }

    ssize_t strAmt = 0;
    
    // Now build the array of package chunks.
@@ -3732,3 +3805,95 @@ bool ResourceTable::getItemValue(
    }
    return res;
}

#define DEBUG_LANG(x) printf("lang=%c%c cnt=%c%c ", \
        (x).language[0] ? (x).language[0] : '-', \
        (x).language[1] ? (x).language[1] : '-', \
        (x).country[0] ? (x).country[0] : '-', \
        (x).country[1] ? (x).country[1] : '-');

status_t ResourceConfigReferences::add(uint32_t id, const ResTable_config& config)
{
    ssize_t index = mRoots.indexOfKey(id);
    if (index < 0) {
        index = mRoots.add(id, Vector<const ResTable_config*>());
    }
    Vector<const ResTable_config*>& configRoots = mRoots.editValueFor(id);

    if (!configRoots.isEmpty()) {
        ssize_t NR = configRoots.size();
        for (int ri=0; ri<NR; ++ri) {
            const ResTable_config* current = configRoots[ri];

            if (config.match(*current)) {
                // We already have something more generic than our incoming string.
                NOISY_REF(
                    printf("  ConfigRef %d: ignoring ", id);
                    DEBUG_LANG(config)
                    printf("\n");
                )
                return NO_ERROR;
            } else if (current->match(config)) {
                // more generic
                NOISY_REF(
                    printf("  ConfigRef %d: remove ", id);
                    DEBUG_LANG(current)
                    printf("\n");
                )
                configRoots.removeItemsAt(ri);
                --ri; --NR;
            }
        }
    }
    NOISY_REF(
        printf("  ConfigRef %d: add ", id);
        DEBUG_LANG(config)
        printf("\n");
    )
    ResTable_config *configCopy = (ResTable_config*)malloc(sizeof(ResTable_config));
    memcpy(configCopy, &config, sizeof(ResTable_config));
    configRoots.add(configCopy);

    return NO_ERROR;
}

void ResourceConfigReferences::dump()
{
    printf("ResourceConfigReferences\n");
    const ssize_t NR = mRoots.size();
    for (int ri=0; ri<NR; ++ri) {
        const Vector<const ResTable_config*>& configRoots = mRoots.valueAt(ri);
        printf("  String %d\n", mRoots.keyAt(ri));
        const ssize_t NC = configRoots.size();
        for (int ci=0; ci<NC; ++ci) {
            printf("    ");
            DEBUG_LANG(*configRoots[ci])
            printf("\n");
        }
    }
}

bool ResourceConfigReferences::isRoot(uint32_t id, const ResTable_config& config)
{
    const Vector<const ResTable_config*>& configRoots = mRoots.editValueFor(id);
    const ssize_t NR = configRoots.size();
    for (int ri = 0; ri<NR; ++ri) {
        if (configRoots[ri]->match(config)) {
            return true;
        }
    }
    return false;
}

ResourceConfigReferences::~ResourceConfigReferences()
{
    const ssize_t NR = mRoots.size();
    for (int ri=0; ri<NR; ++ri) {
        Vector<const ResTable_config*> configRoots = mRoots.editValueAt(ri);
        const ssize_t NC = configRoots.size();
        for (int ci=0; ci<NC; ++ci) {
            ResTable_config* config = const_cast<ResTable_config*>(configRoots[ci]);
            free(config);
        }
    }
}
+19 −0
Original line number Diff line number Diff line
@@ -377,6 +377,10 @@ public:
            mEntries.add(config, entry);
        }

        void removeEntryAt(int32_t index) {
            mEntries.removeItemsAt(index);
        }
        
        const DefaultKeyedVector<ConfigDescription, sp<Entry> >& getEntries() const { return mEntries; }
    private:
        const String16 mName;
@@ -448,6 +452,9 @@ public:
        const DefaultKeyedVector<String16, sp<ConfigList> >& getConfigs() const { return mConfigs; }
        const Vector<sp<ConfigList> >& getOrderedConfigs() const { return mOrderedConfigs; }

        void removeUniqueConfig(ConfigDescription& config) { mUniqueConfigs.remove(config); }
        void removeOrderedConfigAt(uint32_t index) { mOrderedConfigs.removeItemsAt(index); }

        const SortedVector<String16>& getCanAddEntries() const { return mCanAddEntries; }
        
        const SourcePos& getPos() const { return mPos; }
@@ -558,5 +565,17 @@ private:
    bool mContainsPseudo;
};

class ResourceConfigReferences
{
public:
    ResourceConfigReferences() : mRoots() {}
    ~ResourceConfigReferences();
    status_t add(uint32_t id, const ResTable_config& config);
    bool isRoot(uint32_t id, const ResTable_config& config);
    void dump();

private:
    KeyedVector<uint32_t, Vector<const ResTable_config*> > mRoots;
};

#endif