Trim font caches when keyguard goes away
Right now we send a trim UI_HIDDEN command to trim the resources used by
lockscreen after unlock, but that does not clean up any font caches
generated by e.g. lockscreen clock animation. This can result in
significant memory bloat for user apps once the device is unlock.
This trims font caches after unlock as well to increase availability of
resources for apps.
Bug:275486055
Bug:278225145
Bug:283203305
Test: newly added unit tests for ResourceTrimmer
ran LockscreenWithSwipeMicrobenchmark and confirmed lower memory
use
Change-Id: I84637049a106a94bf9f06c5261c2941b55db4ba0
This commit is contained in:
@@ -676,6 +676,10 @@ object Flags {
|
||||
val TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_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
|
||||
// TODO(b/265764985): Tracking Bug
|
||||
@Keep
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.systemui.keyguard
|
||||
|
||||
import android.annotation.WorkerThread
|
||||
import android.content.ComponentCallbacks2
|
||||
import android.graphics.HardwareRenderer
|
||||
import android.os.Trace
|
||||
import android.util.Log
|
||||
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.Flags
|
||||
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.utils.GlobalWindowManager
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
@@ -50,6 +52,7 @@ class ResourceTrimmer
|
||||
@Inject
|
||||
constructor(
|
||||
private val keyguardInteractor: KeyguardInteractor,
|
||||
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
|
||||
private val globalWindowManager: GlobalWindowManager,
|
||||
@Application private val applicationScope: CoroutineScope,
|
||||
@Background private val bgDispatcher: CoroutineDispatcher,
|
||||
@@ -58,7 +61,10 @@ constructor(
|
||||
|
||||
override fun start() {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -78,6 +84,30 @@ constructor(
|
||||
.distinctUntilChanged()
|
||||
.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
|
||||
|
||||
@@ -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_PULSING;
|
||||
|
||||
import android.content.ComponentCallbacks2;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.hardware.biometrics.BiometricSourceType;
|
||||
@@ -36,7 +35,6 @@ import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewRootImpl;
|
||||
import android.view.WindowManagerGlobal;
|
||||
import android.window.BackEvent;
|
||||
import android.window.OnBackAnimationCallback;
|
||||
import android.window.OnBackInvokedDispatcher;
|
||||
@@ -985,8 +983,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
mShadeViewController.resetViewGroupFade();
|
||||
mCentralSurfaces.finishKeyguardFadingAway();
|
||||
mBiometricUnlockController.finishKeyguardFadingAway();
|
||||
WindowManagerGlobal.getInstance().trimMemory(
|
||||
ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
|
||||
}
|
||||
|
||||
private void wakeAndUnlockDejank() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.android.systemui.utils
|
||||
|
||||
import android.graphics.HardwareRenderer.CacheTrimLevel
|
||||
import android.view.WindowManagerGlobal
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -13,4 +14,9 @@ class GlobalWindowManager @Inject constructor() {
|
||||
fun trimMemory(level: Int) {
|
||||
WindowManagerGlobal.getInstance().trimMemory(level)
|
||||
}
|
||||
|
||||
/** Sends a trim caches command to [WindowManagerGlobal]. */
|
||||
fun trimCaches(@CacheTrimLevel level: Int) {
|
||||
WindowManagerGlobal.getInstance().trimCaches(level)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.android.systemui.keyguard
|
||||
|
||||
import android.content.ComponentCallbacks2
|
||||
import android.graphics.HardwareRenderer
|
||||
import android.testing.AndroidTestingRunner
|
||||
import androidx.test.filters.SmallTest
|
||||
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.FakeKeyguardBouncerRepository
|
||||
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.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.WakefulnessModel
|
||||
import com.android.systemui.keyguard.shared.model.WakefulnessState
|
||||
@@ -25,6 +30,7 @@ import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.times
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.verifyNoMoreInteractions
|
||||
import org.mockito.Mockito.verifyZeroInteractions
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@@ -37,6 +43,7 @@ class ResourceTrimmerTest : SysuiTestCase() {
|
||||
private val testScope = TestScope(testDispatcher)
|
||||
private val keyguardRepository = FakeKeyguardRepository()
|
||||
private val featureFlags = FakeFeatureFlags()
|
||||
private val keyguardTransitionRepository = FakeKeyguardTransitionRepository()
|
||||
|
||||
@Mock private lateinit var globalWindowManager: GlobalWindowManager
|
||||
private lateinit var resourceTrimmer: ResourceTrimmer
|
||||
@@ -45,13 +52,15 @@ class ResourceTrimmerTest : SysuiTestCase() {
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
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)
|
||||
keyguardRepository.setWakefulnessModel(
|
||||
WakefulnessModel(WakefulnessState.AWAKE, WakeSleepReason.OTHER, WakeSleepReason.OTHER)
|
||||
)
|
||||
keyguardRepository.setDozeAmount(0f)
|
||||
keyguardRepository.setKeyguardGoingAway(false)
|
||||
|
||||
val interactor =
|
||||
val keyguardInteractor =
|
||||
KeyguardInteractor(
|
||||
keyguardRepository,
|
||||
FakeCommandQueue(),
|
||||
@@ -60,7 +69,8 @@ class ResourceTrimmerTest : SysuiTestCase() {
|
||||
)
|
||||
resourceTrimmer =
|
||||
ResourceTrimmer(
|
||||
interactor,
|
||||
keyguardInteractor,
|
||||
KeyguardTransitionInteractor(keyguardTransitionRepository),
|
||||
globalWindowManager,
|
||||
testScope.backgroundScope,
|
||||
testDispatcher,
|
||||
@@ -191,4 +201,26 @@ class ResourceTrimmerTest : SysuiTestCase() {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user