[Android] Evict preloaded checkout under memory pressure#453
Conversation
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
Package Size
Android file breakdown
Measured from the PR base SHA and PR head SHA. The file breakdown shows uncompressed sizes within each package artifact, so individual files do not sum to the compressed artifact total. This comment reports package artifact sizes only; it is not a final app binary-size report. |
89e6e70 to
284f325
Compare
5bd9b5f to
4a8ed16
Compare
4a8ed16 to
b789d74
Compare
bd21ffc to
eeb5755
Compare
b789d74 to
2a9e701
Compare
eeb5755 to
95c911b
Compare
d81c123 to
ccdc8c9
Compare
95c911b to
a0d96f6
Compare
a0d96f6 to
9d501ce
Compare
ccdc8c9 to
13b1118
Compare
9d501ce to
5fb8321
Compare
c4933ef to
5bc3ee0
Compare
4950275 to
39056a1
Compare
5bc3ee0 to
16414d6
Compare
5e97725 to
846c8f0
Compare
ea93142 to
6312803
Compare
846c8f0 to
9ccc261
Compare
6312803 to
d45eadc
Compare
9ccc261 to
324b331
Compare
d45eadc to
23fda26
Compare
324b331 to
f01da17
Compare
23fda26 to
d4fff69
Compare
f01da17 to
6020bf3
Compare
37982e2 to
e3a3ccf
Compare
6020bf3 to
9d2685c
Compare
Install this buildOpen Tophat, select your target device, then click Install. Links open on the Mac running Tophat.
Checkout Kit E2E results
|
9d2685c to
bd1c71c
Compare
e3a3ccf to
6f38ed6
Compare
| fun evict() { | ||
| val cached = entry | ||
| if (cached == null || cached.view.isPresented) return | ||
| terminate(PreloadState.Evicted) |
There was a problem hiding this comment.
terminate seems to not be defined
| memoryCallbacksRegistered = true | ||
| context.registerComponentCallbacks(object : ComponentCallbacks2 { | ||
| override fun onTrimMemory(level: Int) { | ||
| if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW) { |
There was a problem hiding this comment.
should we do MEMORY_RUNNING_CRITICAL too
@Suppress("DEPRECATION")
private fun isRunningLowOnMemory(level: Int): Boolean =
level in ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW..
ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL
override fun onTrimMemory(level: Int) {
if (isRunningLowOnMemory(level)) {
evict(PreloadState.Evicted)
}
}
| if (memoryCallbacksRegistered) return | ||
| memoryCallbacksRegistered = true | ||
| context.registerComponentCallbacks(object : ComponentCallbacks2 { | ||
| override fun onTrimMemory(level: Int) { |
There was a problem hiding this comment.
Probably worth a comment that these levels aren't reported in API level 34+
It looks like we just get notified of things TRIM_MEMORY_BACKGROUND and TRIM_MEMORY_UI_HIDDEN from that API level on
so the eviction wouldn't work on newer devices
6f38ed6 to
200b47f
Compare
bd1c71c to
6957945
Compare
200b47f to
d812e9a
Compare
0f6be84 to
2f73ea1
Compare
b5368a2 to
ab0b2d8
Compare
3d625ba to
b879a39
Compare
Assisted-By: devx/42793469-bf64-49c6-b1db-f4d6c628a330
ab0b2d8 to
c79c41f
Compare
b879a39 to
6e05554
Compare

Ports the Swift memory-pressure eviction behaviour to Android. Registers a
ComponentCallbacks2on the application context when preloading starts; on a trim-memory signal at or aboveTRIM_MEMORY_RUNNING_LOWthe single cached preload WebView is evicted and the handle transitions to the newPreloadState.Evicted. A presented checkout is spared — eviction is a no-op whileisPresentedis true, mirroring the Swift guard.Eviction fires through the cache's own registered callback, so there's no public entry point; tests drive it via the internal cache. See the two new cases in
PreloadObservabilityTestfor the idle-evict and presented-spared paths.Why ship this
onTrimMemory, Android's low-memory killer reclaims at process granularity and can take the whole host app — voluntarily handing back one WebView is the far cheaper trade. This is the change's main justification.ComponentCallbacks2exists precisely for caches like this. An SDK that holds a heavyweight WebView and ignores trim signals is a memory hog consumers have to work around.isPresented-guarded, so it can only ever reclaim one idle entry and never a live checkout.PreloadState;Evictedcloses it so a preload can't silently vanish under pressure with no corresponding state for consumers to observe.