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

Commit ab3cb30a authored by Yurii Zubrytskyi's avatar Yurii Zubrytskyi
Browse files

Ensure no duplicates in ThemeKey

Some apps keep adding the same resources to their theme key
objects on e.g. switching dark mode. Need to be prepared to
limit the size of the arrays, otherwise theme switching gets
slower with each toggle

+ a bit more efficient native handling

Bug: 242005877
Test: manual, 10k of theme switches with no noticable slowdown
Change-Id: Icf74770bd41ebeb0a31f527ae3616de00f23b0ae
parent 58645f68
Loading
Loading
Loading
Loading
+31 −9
Original line number Diff line number Diff line
@@ -173,6 +173,7 @@ public class Resources {
     * mThemeRefNextFlushSize is reached.
     */
    private static final int MIN_THEME_REFS_FLUSH_SIZE = 32;
    private static final int MAX_THEME_REFS_FLUSH_SIZE = 512;
    private int mThemeRefsNextFlushSize = MIN_THEME_REFS_FLUSH_SIZE;

    private int mBaseApkAssetsSize;
@@ -364,10 +365,10 @@ public class Resources {

        // Rebase the ThemeImpls using the new ResourcesImpl.
        synchronized (mThemeRefs) {
            cleanupThemeReferences();
            final int count = mThemeRefs.size();
            for (int i = 0; i < count; i++) {
                WeakReference<Theme> weakThemeRef = mThemeRefs.get(i);
                Theme theme = weakThemeRef != null ? weakThemeRef.get() : null;
                Theme theme = mThemeRefs.get(i).get();
                if (theme != null) {
                    theme.rebase(mResourcesImpl);
                }
@@ -2001,6 +2002,15 @@ public class Resources {

        private int mHashCode = 0;

        private boolean containsValue(int resId, boolean force) {
            for (int i = 0; i < mCount; ++i) {
                if (mResId[i] == resId && mForce[i] == force) {
                    return true;
                }
            }
            return false;
        }

        public void append(int resId, boolean force) {
            if (mResId == null) {
                mResId = new int[4];
@@ -2010,6 +2020,11 @@ public class Resources {
                mForce = new boolean[4];
            }

            // Some apps tend to keep adding same resources over and over, let's protect from it.
            if (containsValue(resId, force)) {
                return;
            }

            mResId = GrowingArrayUtils.append(mResId, mCount, resId);
            mForce = GrowingArrayUtils.append(mForce, mCount, force);
            mCount++;
@@ -2073,6 +2088,19 @@ public class Resources {
        }
    }

    static int nextPowerOf2(int number) {
        return number < 2 ? 2 : 1 >> ((int) (Math.log(number - 1) / Math.log(2)) + 1);
    }

    private void cleanupThemeReferences() {
        // Clean up references to garbage collected themes
        if (mThemeRefs.size() > mThemeRefsNextFlushSize) {
            mThemeRefs.removeIf(ref -> ref.refersTo(null));
            mThemeRefsNextFlushSize = Math.min(Math.max(MIN_THEME_REFS_FLUSH_SIZE,
                    nextPowerOf2(mThemeRefs.size())), MAX_THEME_REFS_FLUSH_SIZE);
        }
    }

    /**
     * Generate a new Theme object for this set of Resources.  It initially
     * starts out empty.
@@ -2083,14 +2111,8 @@ public class Resources {
        Theme theme = new Theme();
        theme.setImpl(mResourcesImpl.newThemeImpl());
        synchronized (mThemeRefs) {
            cleanupThemeReferences();
            mThemeRefs.add(new WeakReference<>(theme));

            // Clean up references to garbage collected themes
            if (mThemeRefs.size() > mThemeRefsNextFlushSize) {
                mThemeRefs.removeIf(ref -> ref.refersTo(null));
                mThemeRefsNextFlushSize = Math.max(MIN_THEME_REFS_FLUSH_SIZE,
                        2 * mThemeRefs.size());
            }
        }
        return theme;
    }
+3 −4
Original line number Diff line number Diff line
@@ -1068,7 +1068,7 @@ base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::ResolveBag(
base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::GetBag(uint32_t resid) const {
  std::vector<uint32_t> found_resids;
  const auto bag = GetBag(resid, found_resids);
  cached_bag_resid_stacks_.emplace(resid, found_resids);
  cached_bag_resid_stacks_.emplace(resid, std::move(found_resids));
  return bag;
}

@@ -1468,7 +1468,6 @@ base::expected<std::monostate, NullOrIOError> Theme::ApplyStyle(uint32_t resid,
      continue;
    }

    Theme::Entry new_entry{attr_res_id, it->cookie, (*bag)->type_spec_flags, it->value};
    auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), attr_res_id,
                                     ThemeEntryKeyComparer{});
    if (entry_it != entries_.end() && entry_it->attr_res_id == attr_res_id) {
@@ -1477,10 +1476,10 @@ base::expected<std::monostate, NullOrIOError> Theme::ApplyStyle(uint32_t resid,
        /// true.
        entries_.erase(entry_it);
      } else if (force) {
        *entry_it = new_entry;
        *entry_it = Entry{attr_res_id, it->cookie, (*bag)->type_spec_flags, it->value};
      }
    } else {
      entries_.insert(entry_it, new_entry);
      entries_.insert(entry_it, Entry{attr_res_id, it->cookie, (*bag)->type_spec_flags, it->value});
    }
  }
  return {};