Merge "Fix drawable-state cache expired issue" into main
This commit is contained in:
@@ -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());
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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().
|
||||
|
||||
Reference in New Issue
Block a user