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

Commit f7097c2c authored by Jeremy Meyer's avatar Jeremy Meyer Committed by Android (Google) Code Review
Browse files

Merge "Track generations in resource caches"

parents 50be0bf2 599a7f22
Loading
Loading
Loading
Loading
+13 −10
Original line number Diff line number Diff line
@@ -111,19 +111,20 @@ public class AnimatorInflater {
            float pathErrorScale) throws NotFoundException {
        final ConfigurationBoundResourceCache<Animator> animatorCache = resources
                .getAnimatorCache();
        Animator animator = animatorCache.getInstance(id, resources, theme);
        if (animator != null) {
        ConfigurationBoundResourceCache.Entry<Animator> animatorEntry =
                animatorCache.getInstance(id, resources, theme);
        if (animatorEntry.hasValue()) {
            if (DBG_ANIMATOR_INFLATER) {
                Log.d(TAG, "loaded animator from cache, " + resources.getResourceName(id));
            }
            return animator;
            return animatorEntry.getValue();
        } else if (DBG_ANIMATOR_INFLATER) {
            Log.d(TAG, "cache miss for animator " + resources.getResourceName(id));
        }
        XmlResourceParser parser = null;
        try {
            parser = resources.getAnimation(id);
            animator = createAnimatorFromXml(resources, theme, parser, pathErrorScale);
            Animator animator = createAnimatorFromXml(resources, theme, parser, pathErrorScale);
            if (animator != null) {
                animator.appendChangingConfigurations(getChangingConfigs(resources, id));
                final ConstantState<Animator> constantState = animator.createConstantState();
@@ -131,7 +132,7 @@ public class AnimatorInflater {
                    if (DBG_ANIMATOR_INFLATER) {
                        Log.d(TAG, "caching animator for res " + resources.getResourceName(id));
                    }
                    animatorCache.put(id, theme, constantState);
                    animatorCache.put(id, theme, constantState, animatorEntry.getGeneration());
                    // create a new animator so that cached version is never used by the user
                    animator = constantState.newInstance(resources, theme);
                }
@@ -160,20 +161,22 @@ public class AnimatorInflater {
        final ConfigurationBoundResourceCache<StateListAnimator> cache = resources
                .getStateListAnimatorCache();
        final Theme theme = context.getTheme();
        StateListAnimator animator = cache.getInstance(id, resources, theme);
        if (animator != null) {
            return animator;
        ConfigurationBoundResourceCache.Entry<StateListAnimator> animatorEntry =
                cache.getInstance(id, resources, theme);
        if (animatorEntry.hasValue()) {
            return animatorEntry.getValue();
        }
        XmlResourceParser parser = null;
        try {
            parser = resources.getAnimation(id);
            animator = createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser));
            StateListAnimator animator =
                    createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser));
            if (animator != null) {
                animator.appendChangingConfigurations(getChangingConfigs(resources, id));
                final ConstantState<StateListAnimator> constantState = animator
                        .createConstantState();
                if (constantState != null) {
                    cache.put(id, theme, constantState);
                    cache.put(id, theme, constantState, animatorEntry.getGeneration());
                    // return a clone so that the animator in constant state is never used.
                    animator = constantState.newInstance(resources, theme);
                }
+6 −6
Original line number Diff line number Diff line
@@ -37,16 +37,16 @@ public class ConfigurationBoundResourceCache<T> extends ThemedResourceCache<Cons
     * @param key a key that uniquely identifies the drawable resource
     * @param resources a Resources object from which to create new instances.
     * @param theme the theme where the resource will be used
     * @return a new instance of the resource, or {@code null} if not in
     * @return an Entry wrapping a new instance of the resource, or {@code null} if not in
     *         the cache
     */
    public T getInstance(long key, Resources resources, Resources.Theme theme) {
        final ConstantState<T> entry = get(key, theme);
        if (entry != null) {
            return entry.newInstance(resources, theme);
    public Entry<T> getInstance(long key, Resources resources, Resources.Theme theme) {
        final Entry<ConstantState<T>> e = get(key, theme);
        if (e.hasValue()) {
            return new Entry<>(e.getValue().newInstance(resources, theme), e.getGeneration());
        }

        return null;
        return new Entry<>(null, e.getGeneration());
    }

    @Override
+21 −3
Original line number Diff line number Diff line
@@ -40,14 +40,32 @@ class DrawableCache extends ThemedResourceCache<Drawable.ConstantState> {
     */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public Drawable getInstance(long key, Resources resources, Resources.Theme theme) {
        final Drawable.ConstantState entry = get(key, theme);
        if (entry != null) {
            return entry.newDrawable(resources, theme);
        final Entry<Drawable.ConstantState> entry = get(key, theme);
        if (entry.getValue() != null) {
            return entry.getValue().newDrawable(resources, theme);
        }

        return null;
    }

    /**
     * If the resource is cached, creates and returns a new instance of it.
     *
     * @param key a key that uniquely identifies the drawable resource
     * @param resources a Resources object from which to create new instances.
     * @param theme the theme where the resource will be used
     * @return an Entry wrapping a a new instance of the resource, or {@code null} if not in
     *         the cache
     */
    public Entry<Drawable> getDrawable(long key, Resources resources, Resources.Theme theme) {
        final Entry<Drawable.ConstantState> e = get(key, theme);
        if (e.hasValue()) {
            return new Entry<>(e.getValue().newDrawable(resources, theme), e.getGeneration());
        }

        return new Entry<>(null, e.getGeneration());
    }

    @Override
    public boolean shouldInvalidateEntry(Drawable.ConstantState entry, int configChanges) {
        return Configuration.needNewResources(configChanges, entry.getChangingConfigurations());
+21 −11
Original line number Diff line number Diff line
@@ -650,15 +650,21 @@ public class ResourcesImpl {
                key = (((long) value.assetCookie) << 32) | value.data;
            }

            int cacheGeneration;
            // First, check whether we have a cached version of this drawable
            // that was inflated against the specified theme. Skip the cache if
            // we're currently preloading or we're not using the cache.
            if (!mPreloading && useCache) {
                final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme);
                if (cachedDrawable != null) {
                    cachedDrawable.setChangingConfigurations(value.changingConfigurations);
                    return cachedDrawable;
                }
                final ThemedResourceCache.Entry<Drawable> cachedDrawable =
                        caches.getDrawable(key, wrapper, theme);
                if (cachedDrawable.hasValue()) {
                    cachedDrawable.getValue().setChangingConfigurations(
                            value.changingConfigurations);
                    return cachedDrawable.getValue();
                }
                cacheGeneration = cachedDrawable.getGeneration();
            } else {
                cacheGeneration = ThemedResourceCache.UNDEFINED_GENERATION;
            }

            // Next, check preloaded drawables. Preloaded drawables may contain
@@ -702,7 +708,8 @@ public class ResourcesImpl {
            if (dr != null) {
                dr.setChangingConfigurations(value.changingConfigurations);
                if (useCache) {
                    cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr);
                    cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr,
                            cacheGeneration);
                    if (needsNewDrawableAfterCache) {
                        Drawable.ConstantState state = dr.getConstantState();
                        if (state != null) {
@@ -733,7 +740,7 @@ public class ResourcesImpl {
    }

    private void cacheDrawable(TypedValue value, boolean isColorDrawable, DrawableCache caches,
            Resources.Theme theme, boolean usesTheme, long key, Drawable dr) {
            Resources.Theme theme, boolean usesTheme, long key, Drawable dr, int cacheGeneration) {
        final Drawable.ConstantState cs = dr.getConstantState();
        if (cs == null) {
            return;
@@ -761,7 +768,7 @@ public class ResourcesImpl {
            }
        } else {
            synchronized (mAccessLock) {
                caches.put(key, theme, cs, usesTheme);
                caches.put(key, theme, cs, cacheGeneration, usesTheme);
            }
        }
    }
@@ -1002,14 +1009,16 @@ public class ResourcesImpl {
            TypedValue value, int id) {
        final long key = (((long) value.assetCookie) << 32) | value.data;
        final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
        ComplexColor complexColor = cache.getInstance(key, wrapper, theme);
        if (complexColor != null) {
            return complexColor;
        ThemedResourceCache.Entry<ComplexColor> complexColorEntry =
                cache.getInstance(key, wrapper, theme);
        if (complexColorEntry.hasValue()) {
            return complexColorEntry.getValue();
        }

        final android.content.res.ConstantState<ComplexColor> factory =
                sPreloadedComplexColors.get(key);

        ComplexColor complexColor = null;
        if (factory != null) {
            complexColor = factory.newInstance(wrapper, theme);
        }
@@ -1026,7 +1035,8 @@ public class ResourcesImpl {
                    sPreloadedComplexColors.put(key, complexColor.getConstantState());
                }
            } else {
                cache.put(key, theme, complexColor.getConstantState());
                cache.put(key, theme, complexColor.getConstantState(),
                        complexColorEntry.getGeneration());
            }
        }
        return complexColor;
+39 −8
Original line number Diff line number Diff line
@@ -33,11 +33,37 @@ import java.lang.ref.WeakReference;
 * @param <T> type of data to cache
 */
abstract class ThemedResourceCache<T> {
    public static final int UNDEFINED_GENERATION = -1;
    @UnsupportedAppUsage
    private ArrayMap<ThemeKey, LongSparseArray<WeakReference<T>>> mThemedEntries;
    private LongSparseArray<WeakReference<T>> mUnthemedEntries;
    private LongSparseArray<WeakReference<T>> mNullThemedEntries;

    private int mGeneration;

    public static class Entry<S> {
        private S mValue;
        private int mGeneration;


        public S getValue() {
            return mValue;
        }

        public boolean hasValue() {
            return mValue != null;
        }

        public int getGeneration() {
            return mGeneration;
        }

        Entry(S value, int generation) {
            this.mValue = value;
            this.mGeneration = generation;
        }
    }

    /**
     * Adds a new theme-dependent entry to the cache.
     *
@@ -45,9 +71,10 @@ abstract class ThemedResourceCache<T> {
     * @param theme the theme against which this entry was inflated, or
     *              {@code null} if the entry has no theme applied
     * @param entry the entry to cache
     * @param generation The generation of the cache to compare against before storing
     */
    public void put(long key, @Nullable Theme theme, @NonNull T entry) {
        put(key, theme, entry, true);
    public void put(long key, @Nullable Theme theme, @NonNull T entry, int generation) {
        put(key, theme, entry, generation, true);
    }

    /**
@@ -57,10 +84,12 @@ abstract class ThemedResourceCache<T> {
     * @param theme the theme against which this entry was inflated, or
     *              {@code null} if the entry has no theme applied
     * @param entry the entry to cache
     * @param generation The generation of the cache to compare against before storing
     * @param usesTheme {@code true} if the entry is affected theme changes,
     *                  {@code false} otherwise
     */
    public void put(long key, @Nullable Theme theme, @NonNull T entry, boolean usesTheme) {
    public void put(long key, @Nullable Theme theme, @NonNull T entry, int generation,
            boolean usesTheme) {
        if (entry == null) {
            return;
        }
@@ -72,7 +101,8 @@ abstract class ThemedResourceCache<T> {
            } else {
                entries = getThemedLocked(theme, true);
            }
            if (entries != null) {
            if (entries != null
                    && ((generation == mGeneration) || (generation == UNDEFINED_GENERATION)))  {
                entries.put(key, new WeakReference<>(entry));
            }
        }
@@ -86,7 +116,7 @@ abstract class ThemedResourceCache<T> {
     * @return a cached entry, or {@code null} if not in the cache
     */
    @Nullable
    public T get(long key, @Nullable Theme theme) {
    public Entry get(long key, @Nullable Theme theme) {
        // The themed (includes null-themed) and unthemed caches are mutually
        // exclusive, so we'll give priority to whichever one we think we'll
        // hit first. Since most of the framework drawables are themed, that's
@@ -96,7 +126,7 @@ abstract class ThemedResourceCache<T> {
            if (themedEntries != null) {
                final WeakReference<T> themedEntry = themedEntries.get(key);
                if (themedEntry != null) {
                    return themedEntry.get();
                    return new Entry(themedEntry.get(), mGeneration);
                }
            }

@@ -104,12 +134,12 @@ abstract class ThemedResourceCache<T> {
            if (unthemedEntries != null) {
                final WeakReference<T> unthemedEntry = unthemedEntries.get(key);
                if (unthemedEntry != null) {
                    return unthemedEntry.get();
                    return new Entry(unthemedEntry.get(), mGeneration);
                }
            }
        }

        return null;
        return new Entry(null, mGeneration);
    }

    /**
@@ -121,6 +151,7 @@ abstract class ThemedResourceCache<T> {
    @UnsupportedAppUsage
    public void onConfigurationChange(@Config int configChanges) {
        prune(configChanges);
        mGeneration++;
    }

    /**
Loading