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

Commit 3ba29fc4 authored by Brandon Liu's avatar Brandon Liu Committed by Gerrit Code Review
Browse files

Merge "Fix drawable-state cache expired issue" into main

parents aaddb6cb c4f2605b
Loading
Loading
Loading
Loading
+98 −0
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ import android.graphics.drawable.Drawable.ConstantState;
import android.graphics.drawable.DrawableInflater;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AttributeSet;
@@ -132,6 +133,11 @@ public class Resources {
    private static final Object sSync = new Object();
    private final Object mUpdateLock = new Object();

    /**
     * Controls whether we should preload resources during zygote init.
     */
    private static final boolean PRELOAD_RESOURCES = true;

    // Used by BridgeResources in layoutlib
    @UnsupportedAppUsage
    static Resources mSystem = null;
@@ -2666,6 +2672,98 @@ public class Resources {
        }
    }

    /**
     * Load in commonly used resources, so they can be shared across processes.
     *
     * These tend to be a few Kbytes, but are frequently in the 20-40K range, and occasionally even
     * larger.
     * @hide
     */
    @UnsupportedAppUsage
    public static void preloadResources() {
        try {
            final Resources sysRes = Resources.getSystem();
            sysRes.startPreloading();
            if (PRELOAD_RESOURCES) {
                Log.i(TAG, "Preloading resources...");

                long startTime = SystemClock.uptimeMillis();
                TypedArray ar = sysRes.obtainTypedArray(
                        com.android.internal.R.array.preloaded_drawables);
                int numberOfEntries = preloadDrawables(sysRes, ar);
                ar.recycle();
                Log.i(TAG, "...preloaded " + numberOfEntries + " resources in "
                        + (SystemClock.uptimeMillis() - startTime) + "ms.");

                startTime = SystemClock.uptimeMillis();
                ar = sysRes.obtainTypedArray(
                        com.android.internal.R.array.preloaded_color_state_lists);
                numberOfEntries = preloadColorStateLists(sysRes, ar);
                ar.recycle();
                Log.i(TAG, "...preloaded " + numberOfEntries + " resources in "
                        + (SystemClock.uptimeMillis() - startTime) + "ms.");

                if (sysRes.getBoolean(
                        com.android.internal.R.bool.config_freeformWindowManagement)) {
                    startTime = SystemClock.uptimeMillis();
                    ar = sysRes.obtainTypedArray(
                            com.android.internal.R.array.preloaded_freeform_multi_window_drawables);
                    numberOfEntries = preloadDrawables(sysRes, ar);
                    ar.recycle();
                    Log.i(TAG, "...preloaded " + numberOfEntries + " resource in "
                            + (SystemClock.uptimeMillis() - startTime) + "ms.");
                }
            }
            sysRes.finishPreloading();
        } catch (RuntimeException e) {
            Log.w(TAG, "Failure preloading resources", e);
        }
    }

    private static int preloadColorStateLists(Resources resources, TypedArray ar) {
        final int numberOfEntries = ar.length();
        for (int i = 0; i < numberOfEntries; i++) {
            int id = ar.getResourceId(i, 0);

            if (id != 0) {
                if (resources.getColorStateList(id, null) == null) {
                    throw new IllegalArgumentException(
                            "Unable to find preloaded color resource #0x"
                                    + Integer.toHexString(id)
                                    + " (" + ar.getString(i) + ")");
                }
            }
        }
        return numberOfEntries;
    }

    private static int preloadDrawables(Resources resources, TypedArray ar) {
        final int numberOfEntries = ar.length();
        for (int i = 0; i < numberOfEntries; i++) {
            int id = ar.getResourceId(i, 0);

            if (id != 0) {
                if (resources.getDrawable(id, null) == null) {
                    throw new IllegalArgumentException(
                            "Unable to find preloaded drawable resource #0x"
                                    + Integer.toHexString(id)
                                    + " (" + ar.getString(i) + ")");
                }
            }
        }
        return numberOfEntries;
    }

    /**
     * Clear the cache when the framework resources packages is changed.
     * @hide
     */
    @VisibleForTesting
    public static void resetPreloadDrawableStateCache() {
        ResourcesImpl.resetDrawableStateCache();
        preloadResources();
    }

    /** @hide */
    public void dump(PrintWriter pw, String prefix) {
        pw.println(prefix + "class=" + getClass());
+18 −0
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import android.util.TypedValue;
import android.util.Xml;
import android.view.DisplayAdjustments;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.GrowingArrayUtils;

import libcore.util.NativeAllocationRegistry;
@@ -158,6 +159,23 @@ public class ResourcesImpl {
        sPreloadedDrawables[1] = new LongSparseArray<>();
    }

    /**
     * Clear the cache when the framework resources packages is changed.
     *
     * It's only used in the test initial function instead of regular app behaviors. It doesn't
     * guarantee the thread-safety so mark this with @VisibleForTesting.
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    static void resetDrawableStateCache() {
        synchronized (sSync) {
            sPreloadedDrawables[0].clear();
            sPreloadedDrawables[1].clear();
            sPreloadedColorDrawables.clear();
            sPreloadedComplexColors.clear();
            sPreloaded = false;
        }
    }

    /**
     * Creates a new ResourcesImpl object with CompatibilityInfo.
     *
+1 −94
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import android.app.ApplicationLoaders;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.SharedLibraryInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Build;
import android.os.Environment;
import android.os.IInstalld;
@@ -101,22 +100,11 @@ public class ZygoteInit {
    // --usap-socket-name parameter.
    private static final String SOCKET_NAME_ARG = "--socket-name=";

    /**
     * Used to pre-load resources.
     */
    @UnsupportedAppUsage
    private static Resources mResources;

    /**
     * The path of a file that contains classes to preload.
     */
    private static final String PRELOADED_CLASSES = "/system/etc/preloaded-classes";

    /**
     * Controls whether we should preload resources during zygote init.
     */
    private static final boolean PRELOAD_RESOURCES = true;

    private static final int UNPRIVILEGED_UID = 9999;
    private static final int UNPRIVILEGED_GID = 9999;

@@ -143,7 +131,7 @@ public class ZygoteInit {
        cacheNonBootClasspathClassLoaders();
        bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders
        bootTimingsTraceLog.traceBegin("PreloadResources");
        preloadResources();
        Resources.preloadResources();
        bootTimingsTraceLog.traceEnd(); // PreloadResources
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
        nativePreloadAppProcessHALs();
@@ -413,87 +401,6 @@ public class ZygoteInit {
                });
    }

    /**
     * Load in commonly used resources, so they can be shared across processes.
     *
     * These tend to be a few Kbytes, but are frequently in the 20-40K range, and occasionally even
     * larger.
     */
    private static void preloadResources() {
        try {
            mResources = Resources.getSystem();
            mResources.startPreloading();
            if (PRELOAD_RESOURCES) {
                Log.i(TAG, "Preloading resources...");

                long startTime = SystemClock.uptimeMillis();
                TypedArray ar = mResources.obtainTypedArray(
                        com.android.internal.R.array.preloaded_drawables);
                int N = preloadDrawables(ar);
                ar.recycle();
                Log.i(TAG, "...preloaded " + N + " resources in "
                        + (SystemClock.uptimeMillis() - startTime) + "ms.");

                startTime = SystemClock.uptimeMillis();
                ar = mResources.obtainTypedArray(
                        com.android.internal.R.array.preloaded_color_state_lists);
                N = preloadColorStateLists(ar);
                ar.recycle();
                Log.i(TAG, "...preloaded " + N + " resources in "
                        + (SystemClock.uptimeMillis() - startTime) + "ms.");

                if (mResources.getBoolean(
                        com.android.internal.R.bool.config_freeformWindowManagement)) {
                    startTime = SystemClock.uptimeMillis();
                    ar = mResources.obtainTypedArray(
                            com.android.internal.R.array.preloaded_freeform_multi_window_drawables);
                    N = preloadDrawables(ar);
                    ar.recycle();
                    Log.i(TAG, "...preloaded " + N + " resource in "
                            + (SystemClock.uptimeMillis() - startTime) + "ms.");
                }
            }
            mResources.finishPreloading();
        } catch (RuntimeException e) {
            Log.w(TAG, "Failure preloading resources", e);
        }
    }

    private static int preloadColorStateLists(TypedArray ar) {
        int N = ar.length();
        for (int i = 0; i < N; i++) {
            int id = ar.getResourceId(i, 0);

            if (id != 0) {
                if (mResources.getColorStateList(id, null) == null) {
                    throw new IllegalArgumentException(
                            "Unable to find preloaded color resource #0x"
                                    + Integer.toHexString(id)
                                    + " (" + ar.getString(i) + ")");
                }
            }
        }
        return N;
    }


    private static int preloadDrawables(TypedArray ar) {
        int N = ar.length();
        for (int i = 0; i < N; i++) {
            int id = ar.getResourceId(i, 0);

            if (id != 0) {
                if (mResources.getDrawable(id, null) == null) {
                    throw new IllegalArgumentException(
                            "Unable to find preloaded drawable resource #0x"
                                    + Integer.toHexString(id)
                                    + " (" + ar.getString(i) + ")");
                }
            }
        }
        return N;
    }

    /**
     * Runs several special GCs to try to clean up a few generations of softly- and final-reachable
     * objects, along with any other garbage. This is only useful just before a fork().