Merge "Fix drawable-state cache expired issue" into main am: 3ba29fc4e8 am: 4c7d041b42

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/2437312

Change-Id: Ia2a62cfbc4c5c093020559c66ff02747812152e8
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Brandon Liu
2023-07-27 20:04:50 +00:00
committed by Automerger Merge Worker
3 changed files with 117 additions and 94 deletions

View File

@@ -54,6 +54,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;
@@ -133,6 +134,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;
@@ -2705,6 +2711,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());

View File

@@ -54,6 +54,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;
@@ -162,6 +163,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.
*

View File

@@ -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;
@@ -104,22 +103,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;
@@ -146,7 +134,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();
@@ -432,87 +420,6 @@ public class ZygoteInit {
ApplicationLoaders.getDefault().createAndCacheNonBootclasspathSystemClassLoaders(libs);
}
/**
* 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().