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

Commit 05a4dc40 authored by Clark Scheff's avatar Clark Scheff Committed by Gerrit Code Review
Browse files

Themes: Load missing style attributes from original style

If a theme overrides a style in an app and does not include all
the attributes found in the original, it is possible for the app
to crash because it cannot locate an attribute it is expecting.

To overcome this we need to check the attributes in the original
style's bag and add any missing attributes to the current bag being
populated.  Currently we have only seen one theme that causes this
behavior, but there could be others out there or we may eventually
see this happen in the wild as apps update and the themes have not
had a chance to incorporate the new additions from the app.

Change-Id: Id44aa83a6c58a0b042d2b32171bed5e794352670
parent a83d696a
Loading
Loading
Loading
Loading
+67 −0
Original line number Diff line number Diff line
@@ -3547,6 +3547,7 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
            checkOverlay = false;
            ip++;
        }
        uint32_t originalResID = 0;
        if (package->header->resourceIDMap) {
            if (performMapping) {
                uint32_t overlayResID = 0x0;
@@ -3558,6 +3559,7 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
                    ALOGV("resource map 0x%08x -> 0x%08x\n", resID, overlayResID);
                    T = Res_GETTYPE(overlayResID);
                    E = Res_GETENTRY(overlayResID);
                    originalResID = resID;
                    resID = overlayResID;
                } else {
                    // resource not present in overlay package, continue with the next package
@@ -3747,6 +3749,71 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
        if (curEntry > set->numAttrs) {
            set->numAttrs = curEntry;
        }

        // If this style was overridden by a theme then we need to compare our bag with
        // the bag from the original and add any missing attributes to our bag
        if (originalResID && originalResID != resID) {
            const bag_entry* originalBag;
            uint32_t originalTypeSpecFlags = 0;
            const ssize_t NO = getBagLocked(originalResID, &originalBag,
                    &originalTypeSpecFlags, false);
            if (NO <= 0) {
                ALOGW("Failed to retrieve original bag for 0x%08x", originalResID);
            }

            // Now merge in the original attributes...
            bag_entry* entries = (bag_entry*)(set+1);
            size_t curEntry = 0;
            uint32_t pos = 0;
            for (int i = 0; i < NO; i++) {
                TABLE_NOISY(printf("Now at %d\n", i));
                const uint32_t newName = originalBag[i].map.name.ident;
                bool isInside;
                uint32_t oldName = 0;
                curEntry = 0;

                while ((isInside=(curEntry < set->numAttrs))
                        && (oldName=entries[curEntry].map.name.ident) < newName) {
                    curEntry++;
                }

                if ((!isInside) || oldName != newName) {
                    // This is a new attribute...  figure out what to do with it.
                    // Need to alloc more memory...
                    curEntry = set->availAttrs;
                    set->availAttrs++;
                    const size_t newAvail = set->availAttrs;
                    set = (bag_set*)realloc(set,
                                            sizeof(bag_set)
                                            + sizeof(bag_entry)*newAvail);
                    if (set == NULL) {
                        return NO_MEMORY;
                    }
                    entries = (bag_entry*)(set+1);
                    TABLE_NOISY(printf("Reallocated set %p, entries=%p, avail=%d\n",
                                 set, entries, set->availAttrs));
                    if (isInside) {
                        // Going in the middle, need to make space.
                        memmove(entries+curEntry+1, entries+curEntry,
                                sizeof(bag_entry)*(set->numAttrs-curEntry));
                    }
                    TABLE_NOISY(printf("#%d: Inserting new attribute: 0x%08x\n",
                                 curEntry, newName));

                    bag_entry* cur = entries+curEntry;

                    cur->stringBlock = originalBag[i].stringBlock;
                    cur->map.name.ident = originalBag[i].map.name.ident;
                    cur->map.value = originalBag[i].map.value;
                    set->typeSpecFlags |= originalTypeSpecFlags;
                    set->numAttrs = set->availAttrs;
                    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));
                }
            };
        }
    }

    // And this is it...