Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 71fd52c6 authored by Steve Elliott's avatar Steve Elliott
Browse files

[kairos] drop upstream ref when statesource killed

Should improve memory usage.

Flag: com.android.systemui.status_bar_mobile_icon_kairos
Bug: 383172066
Test: atest
Change-Id: Iaee905aa70122b0b4086b362bc8ae8727ad11776
parent 7f36a510
Loading
Loading
Loading
Loading
+4 −11
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package com.android.systemui.kairos

import com.android.systemui.kairos.internal.CompletableLazy
import com.android.systemui.kairos.internal.EventsImpl
import com.android.systemui.kairos.internal.Init
import com.android.systemui.kairos.internal.InitScope
import com.android.systemui.kairos.internal.Network
@@ -28,7 +27,7 @@ import com.android.systemui.kairos.internal.StateSource
import com.android.systemui.kairos.internal.activated
import com.android.systemui.kairos.internal.constInit
import com.android.systemui.kairos.internal.constState
import com.android.systemui.kairos.internal.filterImpl
import com.android.systemui.kairos.internal.distinctChanges
import com.android.systemui.kairos.internal.flatMapStateImpl
import com.android.systemui.kairos.internal.init
import com.android.systemui.kairos.internal.mapImpl
@@ -247,21 +246,15 @@ internal constructor(
    internal val state = run {
        val changes = input.impl
        val state: StateSource<T> = StateSource(initialValue, nameData)
        val mapImpl =
            mapImpl(upstream = { changes.activated() }, nameData + "forceValue") { it, _ ->
                it!!.value
            }
        val calm: EventsImpl<T> =
            filterImpl(nameData + "calm", { mapImpl }) { new ->
                new != state.getCurrentWithEpoch(evalScope = this).first
            }
        val forced = mapImpl({ changes.activated() }, nameData + "forced") { it, _ -> it!!.value }
        val calm = distinctChanges({ forced }, nameData + "calm", state)
        @Suppress("DeferredResultUnused")
        network.transaction("MutableState.init") {
            calm.activate(evalScope = this, downstream = Schedulable.S(state))?.let {
                (connection, needsEval) ->
                state.upstreamConnection = connection
                if (needsEval) {
                    schedule(state)
                    state.schedule(0, this)
                }
            }
        }
+8 −7
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import com.android.systemui.kairos.util.NameTag
import com.android.systemui.kairos.util.WithPrev
import com.android.systemui.kairos.util.map
import com.android.systemui.kairos.util.mapMaybeValues
import com.android.systemui.kairos.util.maybeOf
import com.android.systemui.kairos.util.nameTag
import com.android.systemui.kairos.util.plus
import com.android.systemui.kairos.util.toNameData
@@ -1256,7 +1257,7 @@ internal fun <A, B> StateScope.applyLatestStateful(
    init: Stateful<A>,
): Pair<Events<B>, DeferredValue<A>> {
    val singletonMap =
        events.mapCheap(nameData + "singletonMap") { spec -> mapOf(Unit to Maybe.present(spec)) }
        events.mapCheap(nameData + "singletonMap") { spec -> mapOf(Unit to maybeOf(spec)) }
    val (events, result) =
        applyLatestStatefulForKey(nameData, singletonMap, init = mapOf(Unit to init), numKeys = 1)
    val outEvents: Events<B> =
@@ -1403,7 +1404,7 @@ internal fun <A> StateScope.childStateScope(
): DeferredValue<A> {
    val turnOff =
        nextOnly(nameData + "onlyOne", stop).mapCheap(nameData + "turnOff") {
            mapOf(Unit to Maybe.absent<Stateful<A>>())
            mapOf(Unit to maybeOf<Stateful<A>>())
        }
    val (_, init: DeferredValue<Map<Unit, A>>) =
        applyLatestStatefulForKey(nameData, turnOff, init = mapOf(Unit to stateful), numKeys = 1)
@@ -1464,8 +1465,8 @@ internal fun <A> StateScope.pairwise(
    nameData: NameData,
    events: Events<A>,
): Events<WithPrev<A, A>> {
    val mapPresent = events.mapCheap(nameData + "mapPresent") { Maybe.present(it) }
    val pairwise = pairwise(nameData, mapPresent, Maybe.absent)
    val mapPresent = events.mapCheap(nameData + "mapPresent") { maybeOf(it) }
    val pairwise = pairwise(nameData, mapPresent, maybeOf())
    return pairwise.mapMaybe(nameData + "zipMaybe") { (prev, next) ->
        prev.zipWith(next, ::WithPrev)
    }
@@ -1518,8 +1519,8 @@ internal fun <A, B, C> StateScope.sample(
    val state =
        holdState(
            nameData + "otherStore",
            other.mapCheap(nameData + "mapOtherPresent") { Maybe.present(it) },
            Maybe.absent,
            other.mapCheap(nameData + "mapOtherPresent") { maybeOf(it) },
            maybeOf(),
        )
    return events
        .map(nameData) { a -> state.sample().map { transform(a, it) } }
@@ -1639,7 +1640,7 @@ internal fun <K, V> StateScope.filterIncrementally(
): Incremental<K, V> =
    mapIncrementalState(nameData, incremental) { entry ->
        transform(entry).map(nameData + { "filter[key=${entry.key}]" }) {
            if (it) Maybe.present(entry.value) else Maybe.absent
            if (it) maybeOf(entry.value) else maybeOf()
        }
    }

+4 −4
Original line number Diff line number Diff line
@@ -16,9 +16,9 @@

package com.android.systemui.kairos

import com.android.systemui.kairos.util.Maybe
import com.android.systemui.kairos.util.NameData
import com.android.systemui.kairos.util.These
import com.android.systemui.kairos.util.maybeOf
import com.android.systemui.kairos.util.nameTag
import com.android.systemui.kairos.util.plus
import com.android.systemui.kairos.util.toNameData
@@ -166,10 +166,10 @@ internal fun <A, B, C> Events<A>.samplePromptly(
        .mapMaybe(nameData) { these ->
            when (these) {
                // both present, transform the upstream value and the new value
                is These.Both -> Maybe.present(transform(these.first.first, these.second))
                is These.Both -> maybeOf(transform(these.first.first, these.second))
                // no upstream present, so don't perform the sample
                is These.Second -> Maybe.absent()
                is These.Second -> maybeOf()
                // just the upstream, so transform the upstream and the old value
                is These.First -> Maybe.present(transform(these.value.first, these.value.second))
                is These.First -> maybeOf(transform(these.value.first, these.value.second))
            }
        }
+26 −20
Original line number Diff line number Diff line
@@ -47,7 +47,6 @@ import com.android.systemui.kairos.util.Maybe.Absent
import com.android.systemui.kairos.util.Maybe.Present
import com.android.systemui.kairos.util.NameData
import com.android.systemui.kairos.util.NameTag
import com.android.systemui.kairos.util.appendNames
import com.android.systemui.kairos.util.forceInit
import com.android.systemui.kairos.util.map
import com.android.systemui.kairos.util.mapName
@@ -192,28 +191,36 @@ internal class BuildScopeImpl(
        name: NameTag?,
    ): Pair<Events<Map<K, Maybe<A>>>, DeferredValue<Map<K, B>>> {
        val nameData = name.toNameData("Events.applyLatestSpecForKey")
        val eventsByKey: KeyedEvents<K, Maybe<BuildSpec<A>>> = groupByKey(numKeys)
        val eventsByKey: KeyedEvents<K, Maybe<BuildSpec<A>>> =
            groupByKey(nameData + "eventsByKey", numKeys)
        val childCoroutineScope = coroutineScope.childScope()
        val initOut: Lazy<Map<K, B>> = deferAsync {
            // swap out the CoroutineScope used for this build scope with the child scope
            reenterBuildScope(this@BuildScopeImpl, childCoroutineScope).run {
                initialSpecs.unwrapped.value.mapValues { (k, spec) ->
                val newEnd = eventsByKey[k]
                val newScope = childBuildScope(newEnd, nameData.mapName { "$it[key=$k]" })
                    val newEnd: Events<Maybe<BuildSpec<A>>> = eventsByKey[k]
                    val newScope =
                        childBuildScope(
                            newEnd,
                            nameData.mapName { "$it[key=$k, epoch=$epoch, init=true]" },
                        )
                    newScope.spec()
                }
            }
        // TODO: should this also be used for the initOut?
        val childScope = coroutineScope.childScope()
        }
        val changesImpl: EventsImpl<Map<K, Maybe<A>>> =
            mapImpl(
                upstream = { this@applyLatestSpecForKey.init.connect(evalScope = this) },
                nameData + "changes",
            ) { upstreamMap, _ ->
                reenterBuildScope(this@BuildScopeImpl, childScope).run {
                reenterBuildScope(this@BuildScopeImpl, childCoroutineScope).run {
                    upstreamMap.mapValues { (k: K, ma: Maybe<BuildSpec<A>>) ->
                        ma.map { spec ->
                            val newEnd =
                                skipNext(nameData.mapName { "$it[key=$k]-newEnd" }, eventsByKey[k])
                            val newScope =
                                childBuildScope(newEnd, nameData.mapName { "$it[key=$k]" })
                            val newName =
                                nameData.mapName { "$it[key=$k, epoch=$epoch, init = false]" }
                            val newEnd: Events<Maybe<BuildSpec<A>>> =
                                skipNext(newName + "newEnd", eventsByKey[k])
                            val newScope = childBuildScope(newEnd, newName)
                            newScope.spec()
                        }
                    }
@@ -289,21 +296,20 @@ internal class BuildScopeImpl(
                name: NameTag?,
                block: suspend KairosCoroutineScope.() -> R,
            ): Deferred<R> {
                val asynaNameData = name.toNameData("EffectScope.async")
                val asyncNameData = name.toNameData("EffectScope.async")
                return childScope.async(context, start) newScope@{
                    val childEndSignal: Events<Unit> =
                        this@BuildScopeImpl.newStopEmitter(
                                asynaNameData.appendNames("childEndSignal")
                            )
                            .apply { this@newScope.invokeOnCancel { emit(Unit) } }
                        this@BuildScopeImpl.newStopEmitter(asyncNameData + "childEndSignal").apply {
                            this@newScope.invokeOnCancel { emit(Unit) }
                        }
                    val childStateScope: StateScopeImpl =
                        this@BuildScopeImpl.stateScope.childStateScope(
                            childEndSignal,
                            asynaNameData,
                            asyncNameData,
                        )
                    val localNetwork =
                        LocalNetwork(
                            asynaNameData,
                            asyncNameData,
                            network = this@BuildScopeImpl.network,
                            scope = this@newScope,
                            aliveLazy = childStateScope.aliveLazy,
+2 −3
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import com.android.systemui.kairos.internal.store.SingletonMapK
import com.android.systemui.kairos.util.Maybe
import com.android.systemui.kairos.util.Maybe.Present
import com.android.systemui.kairos.util.NameData
import com.android.systemui.kairos.util.maybeOf
import com.android.systemui.kairos.util.plus

internal inline fun <A> filterPresentImpl(
@@ -47,8 +48,6 @@ internal inline fun <A> filterImpl(
    crossinline f: EvalScope.(A) -> Boolean,
): EventsImpl<A> {
    val mapped =
        mapImpl(getPulse, nameData + "toMaybe") { it, _ ->
            if (f(it)) Maybe.present(it) else Maybe.absent
        }
        mapImpl(getPulse, nameData + "toMaybe") { it, _ -> if (f(it)) maybeOf(it) else maybeOf() }
    return filterPresentImpl(nameData) { mapped }
}
Loading