Merge changes from topic "trim_fonts_on_unlock" into udc-dev

* changes:
  Trim font caches when keyguard goes away
  Allow triming of font caches through WindowManager
This commit is contained in:
Treehugger Robot
2023-05-19 09:44:31 +00:00
committed by Android (Google) Code Review
15 changed files with 171 additions and 8 deletions

View File

@@ -23,6 +23,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context; import android.content.Context;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.graphics.HardwareRenderer;
import android.os.Build; import android.os.Build;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
@@ -550,6 +551,11 @@ public final class WindowManagerGlobal {
ThreadedRenderer.trimMemory(level); ThreadedRenderer.trimMemory(level);
} }
/** @hide */
public void trimCaches(@HardwareRenderer.CacheTrimLevel int level) {
ThreadedRenderer.trimCaches(level);
}
public void dumpGfxInfo(FileDescriptor fd, String[] args) { public void dumpGfxInfo(FileDescriptor fd, String[] args) {
FileOutputStream fout = new FileOutputStream(fd); FileOutputStream fout = new FileOutputStream(fd);
PrintWriter pw = new FastPrintWriter(fout); PrintWriter pw = new FastPrintWriter(fout);

View File

@@ -144,6 +144,32 @@ public class HardwareRenderer {
public @interface DumpFlags { public @interface DumpFlags {
} }
/**
* Trims all Skia caches.
* @hide
*/
public static final int CACHE_TRIM_ALL = 0;
/**
* Trims Skia font caches.
* @hide
*/
public static final int CACHE_TRIM_FONT = 1;
/**
* Trims Skia resource caches.
* @hide
*/
public static final int CACHE_TRIM_RESOURCES = 2;
/** @hide */
@IntDef(prefix = {"CACHE_TRIM_"}, value = {
CACHE_TRIM_ALL,
CACHE_TRIM_FONT,
CACHE_TRIM_RESOURCES
})
@Retention(RetentionPolicy.SOURCE)
public @interface CacheTrimLevel {}
/** /**
* Name of the file that holds the shaders cache. * Name of the file that holds the shaders cache.
*/ */
@@ -1131,6 +1157,20 @@ public class HardwareRenderer {
nTrimMemory(level); nTrimMemory(level);
} }
/**
* Invoke this when all font caches should be flushed. This can cause jank on next render
* commands so use it only after expensive font allocation operations which would
* allocate large amount of temporary memory.
*
* @param level Hint about which caches to trim. See {@link #CACHE_TRIM_ALL},
* {@link #CACHE_TRIM_FONT}, {@link #CACHE_TRIM_RESOURCES}
*
* @hide
*/
public static void trimCaches(@CacheTrimLevel int level) {
nTrimCaches(level);
}
/** @hide */ /** @hide */
public static void overrideProperty(@NonNull String name, @NonNull String value) { public static void overrideProperty(@NonNull String name, @NonNull String value) {
if (name == null || value == null) { if (name == null || value == null) {
@@ -1497,6 +1537,8 @@ public class HardwareRenderer {
private static native void nTrimMemory(int level); private static native void nTrimMemory(int level);
private static native void nTrimCaches(int level);
private static native void nOverrideProperty(String name, String value); private static native void nOverrideProperty(String name, String value);
private static native void nFence(long nativeProxy); private static native void nFence(long nativeProxy);

View File

@@ -31,6 +31,12 @@ enum class TrimLevel {
RUNNING_MODERATE = 5, RUNNING_MODERATE = 5,
}; };
enum class CacheTrimLevel {
ALL_CACHES = 0,
FONT_CACHE = 1,
RESOURCE_CACHE = 2,
};
struct MemoryPolicy { struct MemoryPolicy {
// The initial scale factor applied to the display resolution. The default is 1, but // The initial scale factor applied to the display resolution. The default is 1, but
// lower values may be used to start with a smaller initial cache size. The cache will // lower values may be used to start with a smaller initial cache size. The cache will

View File

@@ -362,6 +362,10 @@ static void android_view_ThreadedRenderer_trimMemory(JNIEnv* env, jobject clazz,
RenderProxy::trimMemory(level); RenderProxy::trimMemory(level);
} }
static void android_view_ThreadedRenderer_trimCaches(JNIEnv* env, jobject clazz, jint level) {
RenderProxy::trimCaches(level);
}
static void android_view_ThreadedRenderer_overrideProperty(JNIEnv* env, jobject clazz, static void android_view_ThreadedRenderer_overrideProperty(JNIEnv* env, jobject clazz,
jstring name, jstring value) { jstring name, jstring value) {
const char* nameCharArray = env->GetStringUTFChars(name, NULL); const char* nameCharArray = env->GetStringUTFChars(name, NULL);
@@ -1018,6 +1022,7 @@ static const JNINativeMethod gMethods[] = {
(void*)android_view_ThreadedRenderer_notifyCallbackPending}, (void*)android_view_ThreadedRenderer_notifyCallbackPending},
{"nNotifyExpensiveFrame", "(J)V", {"nNotifyExpensiveFrame", "(J)V",
(void*)android_view_ThreadedRenderer_notifyExpensiveFrame}, (void*)android_view_ThreadedRenderer_notifyExpensiveFrame},
{"nTrimCaches", "(I)V", (void*)android_view_ThreadedRenderer_trimCaches},
}; };
static JavaVM* mJvm = nullptr; static JavaVM* mJvm = nullptr;

View File

@@ -139,6 +139,25 @@ void CacheManager::trimMemory(TrimLevel mode) {
} }
} }
void CacheManager::trimCaches(CacheTrimLevel mode) {
switch (mode) {
case CacheTrimLevel::FONT_CACHE:
SkGraphics::PurgeFontCache();
break;
case CacheTrimLevel::RESOURCE_CACHE:
SkGraphics::PurgeResourceCache();
break;
case CacheTrimLevel::ALL_CACHES:
SkGraphics::PurgeAllCaches();
if (mGrContext) {
mGrContext->purgeUnlockedResources(false);
}
break;
default:
break;
}
}
void CacheManager::trimStaleResources() { void CacheManager::trimStaleResources() {
if (!mGrContext) { if (!mGrContext) {
return; return;

View File

@@ -48,6 +48,7 @@ public:
void configureContext(GrContextOptions* context, const void* identity, ssize_t size); void configureContext(GrContextOptions* context, const void* identity, ssize_t size);
#endif #endif
void trimMemory(TrimLevel mode); void trimMemory(TrimLevel mode);
void trimCaches(CacheTrimLevel mode);
void trimStaleResources(); void trimStaleResources();
void dumpMemoryUsage(String8& log, const RenderState* renderState = nullptr); void dumpMemoryUsage(String8& log, const RenderState* renderState = nullptr);
void getMemoryUsage(size_t* cpuUsage, size_t* gpuUsage); void getMemoryUsage(size_t* cpuUsage, size_t* gpuUsage);

View File

@@ -231,6 +231,15 @@ void RenderProxy::trimMemory(int level) {
} }
} }
void RenderProxy::trimCaches(int level) {
// Avoid creating a RenderThread to do a trimMemory.
if (RenderThread::hasInstance()) {
RenderThread& thread = RenderThread::getInstance();
const auto trimLevel = static_cast<CacheTrimLevel>(level);
thread.queue().post([&thread, trimLevel]() { thread.trimCaches(trimLevel); });
}
}
void RenderProxy::purgeCaches() { void RenderProxy::purgeCaches() {
if (RenderThread::hasInstance()) { if (RenderThread::hasInstance()) {
RenderThread& thread = RenderThread::getInstance(); RenderThread& thread = RenderThread::getInstance();

View File

@@ -105,6 +105,7 @@ public:
void destroyHardwareResources(); void destroyHardwareResources();
static void trimMemory(int level); static void trimMemory(int level);
static void trimCaches(int level);
static void purgeCaches(); static void purgeCaches();
static void overrideProperty(const char* name, const char* value); static void overrideProperty(const char* name, const char* value);

View File

@@ -521,6 +521,11 @@ void RenderThread::trimMemory(TrimLevel level) {
cacheManager().trimMemory(level); cacheManager().trimMemory(level);
} }
void RenderThread::trimCaches(CacheTrimLevel level) {
ATRACE_CALL();
cacheManager().trimCaches(level);
}
} /* namespace renderthread */ } /* namespace renderthread */
} /* namespace uirenderer */ } /* namespace uirenderer */
} /* namespace android */ } /* namespace android */

View File

@@ -174,6 +174,7 @@ public:
} }
void trimMemory(TrimLevel level); void trimMemory(TrimLevel level);
void trimCaches(CacheTrimLevel level);
/** /**
* isCurrent provides a way to query, if the caller is running on * isCurrent provides a way to query, if the caller is running on

View File

@@ -673,6 +673,10 @@ object Flags {
val TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_LOCK = val TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_LOCK =
unreleasedFlag(2401, "trim_resources_with_background_trim_on_lock") unreleasedFlag(2401, "trim_resources_with_background_trim_on_lock")
// TODO:(b/283203305): Tracking bug
@JvmField
val TRIM_FONT_CACHES_AT_UNLOCK = releasedFlag(2402, "trim_font_caches_on_unlock")
// 2700 - unfold transitions // 2700 - unfold transitions
// TODO(b/265764985): Tracking Bug // TODO(b/265764985): Tracking Bug
@Keep @Keep

View File

@@ -18,6 +18,7 @@ package com.android.systemui.keyguard
import android.annotation.WorkerThread import android.annotation.WorkerThread
import android.content.ComponentCallbacks2 import android.content.ComponentCallbacks2
import android.graphics.HardwareRenderer
import android.os.Trace import android.os.Trace
import android.util.Log import android.util.Log
import com.android.systemui.CoreStartable import com.android.systemui.CoreStartable
@@ -27,12 +28,13 @@ import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.WakefulnessState import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.utils.GlobalWindowManager import com.android.systemui.utils.GlobalWindowManager
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
@@ -50,6 +52,7 @@ class ResourceTrimmer
@Inject @Inject
constructor( constructor(
private val keyguardInteractor: KeyguardInteractor, private val keyguardInteractor: KeyguardInteractor,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val globalWindowManager: GlobalWindowManager, private val globalWindowManager: GlobalWindowManager,
@Application private val applicationScope: CoroutineScope, @Application private val applicationScope: CoroutineScope,
@Background private val bgDispatcher: CoroutineDispatcher, @Background private val bgDispatcher: CoroutineDispatcher,
@@ -58,7 +61,10 @@ constructor(
override fun start() { override fun start() {
Log.d(LOG_TAG, "Resource trimmer registered.") Log.d(LOG_TAG, "Resource trimmer registered.")
if (!featureFlags.isEnabled(Flags.TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_LOCK)) { if (
!(featureFlags.isEnabled(Flags.TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_LOCK) ||
featureFlags.isEnabled(Flags.TRIM_FONT_CACHES_AT_UNLOCK))
) {
return return
} }
@@ -78,6 +84,30 @@ constructor(
.distinctUntilChanged() .distinctUntilChanged()
.collect { onWakefulnessUpdated(it.first, it.second, it.third) } .collect { onWakefulnessUpdated(it.first, it.second, it.third) }
} }
applicationScope.launch(bgDispatcher) {
// We drop 1 to avoid triggering on initial collect().
keyguardTransitionInteractor.anyStateToGoneTransition.collect { transition ->
if (transition.transitionState == TransitionState.FINISHED) {
onKeyguardGone()
}
}
}
}
@WorkerThread
private fun onKeyguardGone() {
if (!featureFlags.isEnabled(Flags.TRIM_FONT_CACHES_AT_UNLOCK)) {
return
}
if (DEBUG) {
Log.d(LOG_TAG, "Trimming font caches since keyguard went away.")
}
// We want to clear temporary caches we've created while rendering and animating
// lockscreen elements, especially clocks.
globalWindowManager.trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN)
globalWindowManager.trimCaches(HardwareRenderer.CACHE_TRIM_FONT)
} }
@WorkerThread @WorkerThread

View File

@@ -23,7 +23,6 @@ import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK; import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING; import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
import android.content.ComponentCallbacks2;
import android.content.Context; import android.content.Context;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.hardware.biometrics.BiometricSourceType; import android.hardware.biometrics.BiometricSourceType;
@@ -36,7 +35,6 @@ import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewRootImpl; import android.view.ViewRootImpl;
import android.view.WindowManagerGlobal;
import android.window.BackEvent; import android.window.BackEvent;
import android.window.OnBackAnimationCallback; import android.window.OnBackAnimationCallback;
import android.window.OnBackInvokedDispatcher; import android.window.OnBackInvokedDispatcher;
@@ -985,8 +983,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mShadeViewController.resetViewGroupFade(); mShadeViewController.resetViewGroupFade();
mCentralSurfaces.finishKeyguardFadingAway(); mCentralSurfaces.finishKeyguardFadingAway();
mBiometricUnlockController.finishKeyguardFadingAway(); mBiometricUnlockController.finishKeyguardFadingAway();
WindowManagerGlobal.getInstance().trimMemory(
ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
} }
private void wakeAndUnlockDejank() { private void wakeAndUnlockDejank() {

View File

@@ -1,5 +1,6 @@
package com.android.systemui.utils package com.android.systemui.utils
import android.graphics.HardwareRenderer.CacheTrimLevel
import android.view.WindowManagerGlobal import android.view.WindowManagerGlobal
import javax.inject.Inject import javax.inject.Inject
@@ -13,4 +14,9 @@ class GlobalWindowManager @Inject constructor() {
fun trimMemory(level: Int) { fun trimMemory(level: Int) {
WindowManagerGlobal.getInstance().trimMemory(level) WindowManagerGlobal.getInstance().trimMemory(level)
} }
/** Sends a trim caches command to [WindowManagerGlobal]. */
fun trimCaches(@CacheTrimLevel level: Int) {
WindowManagerGlobal.getInstance().trimCaches(level)
}
} }

View File

@@ -1,6 +1,7 @@
package com.android.systemui.keyguard package com.android.systemui.keyguard
import android.content.ComponentCallbacks2 import android.content.ComponentCallbacks2
import android.graphics.HardwareRenderer
import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
@@ -9,7 +10,11 @@ import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeCommandQueue import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.shared.model.WakeSleepReason import com.android.systemui.keyguard.shared.model.WakeSleepReason
import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.keyguard.shared.model.WakefulnessState import com.android.systemui.keyguard.shared.model.WakefulnessState
@@ -25,6 +30,7 @@ import org.junit.runner.RunWith
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.times import org.mockito.Mockito.times
import org.mockito.Mockito.verify import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.Mockito.verifyZeroInteractions import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
@@ -37,6 +43,7 @@ class ResourceTrimmerTest : SysuiTestCase() {
private val testScope = TestScope(testDispatcher) private val testScope = TestScope(testDispatcher)
private val keyguardRepository = FakeKeyguardRepository() private val keyguardRepository = FakeKeyguardRepository()
private val featureFlags = FakeFeatureFlags() private val featureFlags = FakeFeatureFlags()
private val keyguardTransitionRepository = FakeKeyguardTransitionRepository()
@Mock private lateinit var globalWindowManager: GlobalWindowManager @Mock private lateinit var globalWindowManager: GlobalWindowManager
private lateinit var resourceTrimmer: ResourceTrimmer private lateinit var resourceTrimmer: ResourceTrimmer
@@ -45,13 +52,15 @@ class ResourceTrimmerTest : SysuiTestCase() {
fun setUp() { fun setUp() {
MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this)
featureFlags.set(Flags.TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_LOCK, true) featureFlags.set(Flags.TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_LOCK, true)
featureFlags.set(Flags.TRIM_FONT_CACHES_AT_UNLOCK, true)
featureFlags.set(Flags.FACE_AUTH_REFACTOR, false) featureFlags.set(Flags.FACE_AUTH_REFACTOR, false)
keyguardRepository.setWakefulnessModel( keyguardRepository.setWakefulnessModel(
WakefulnessModel(WakefulnessState.AWAKE, WakeSleepReason.OTHER, WakeSleepReason.OTHER) WakefulnessModel(WakefulnessState.AWAKE, WakeSleepReason.OTHER, WakeSleepReason.OTHER)
) )
keyguardRepository.setDozeAmount(0f) keyguardRepository.setDozeAmount(0f)
keyguardRepository.setKeyguardGoingAway(false)
val interactor = val keyguardInteractor =
KeyguardInteractor( KeyguardInteractor(
keyguardRepository, keyguardRepository,
FakeCommandQueue(), FakeCommandQueue(),
@@ -60,7 +69,8 @@ class ResourceTrimmerTest : SysuiTestCase() {
) )
resourceTrimmer = resourceTrimmer =
ResourceTrimmer( ResourceTrimmer(
interactor, keyguardInteractor,
KeyguardTransitionInteractor(keyguardTransitionRepository),
globalWindowManager, globalWindowManager,
testScope.backgroundScope, testScope.backgroundScope,
testDispatcher, testDispatcher,
@@ -191,4 +201,26 @@ class ResourceTrimmerTest : SysuiTestCase() {
verifyZeroInteractions(globalWindowManager) verifyZeroInteractions(globalWindowManager)
} }
} }
@Test
fun keyguardTransitionsToGone_trimsFontCache() =
testScope.runTest {
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(KeyguardState.LOCKSCREEN, KeyguardState.GONE)
)
verify(globalWindowManager, times(1))
.trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN)
verify(globalWindowManager, times(1)).trimCaches(HardwareRenderer.CACHE_TRIM_FONT)
verifyNoMoreInteractions(globalWindowManager)
}
@Test
fun keyguardTransitionsToGone_flagDisabled_doesNotTrimFontCache() =
testScope.runTest {
featureFlags.set(Flags.TRIM_FONT_CACHES_AT_UNLOCK, false)
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(KeyguardState.LOCKSCREEN, KeyguardState.GONE)
)
verifyNoMoreInteractions(globalWindowManager)
}
} }