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

Commit edf62212 authored by Fabián Kozynski's avatar Fabián Kozynski
Browse files

Add a TableLog for hydrator

This adds an optional TableLog for hydrator to allow logging of changing
states.

As a first use, add it to QSFragmentComposeViewModel.

Flag: EXEMPT logging
Fixes: 379669380
Test: manual, dump QSFragmentComposeViewModel

Change-Id: Ie103fa01d36d54a9f02ad2f25dd521ab25183ae2
parent feb3f74a
Loading
Loading
Loading
Loading
+34 −20
Original line number Diff line number Diff line
@@ -21,11 +21,11 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.snapshots.StateFactoryMarker
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.app.tracing.coroutines.traceCoroutine
import com.android.systemui.log.table.TableLogBuffer
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
import com.android.app.tracing.coroutines.launchTraced as launch

/**
 * Keeps snapshot/Compose [State]s up-to-date.
@@ -47,6 +47,12 @@ class Hydrator(
     * concatenation or templating.
     */
    private val traceName: String,
    /**
     * An optional [TableLogBuffer] to log emissions to the states. [traceName] will be used as the
     * prefix for the columns logged by this [Hydrator], allowing to aggregate multiple hydrators in
     * the same table.
     */
    private val tableLogBuffer: TableLogBuffer? = null,
) : ExclusiveActivatable() {

    private val children = mutableListOf<NamedActivatable>()
@@ -62,15 +68,8 @@ class Hydrator(
     *   automatically set on the returned [State].
     */
    @StateFactoryMarker
    fun <T> hydratedStateOf(
        traceName: String,
        source: StateFlow<T>,
    ): State<T> {
        return hydratedStateOf(
            traceName = traceName,
            initialValue = source.value,
            source = source,
        )
    fun <T> hydratedStateOf(traceName: String, source: StateFlow<T>): State<T> {
        return hydratedStateOf(traceName = traceName, initialValue = source.value, source = source)
    }

    /**
@@ -81,26 +80,44 @@ class Hydrator(
     *   performance findings with actual code. One recommendation: prefer whole string literals
     *   instead of some complex concatenation or templating scheme. Use `null` to disable
     *   performance tracing for this state.
     *
     *   If a [TableLogBuffer] was provided, every emission to the flow will be logged using the
     *   [traceName] as the column name. For this to work correctly, all the states in the same
     *   hydrator should have different [traceName]. Use `null` to disable logging for this state.
     *
     * @param initialValue The first value to place on the [State]
     * @param source The upstream [Flow] to collect from; values emitted to it will be automatically
     *   set on the returned [State].
     */
    @StateFactoryMarker
    fun <T> hydratedStateOf(
        traceName: String?,
        initialValue: T,
        source: Flow<T>,
    ): State<T> {
    fun <T> hydratedStateOf(traceName: String?, initialValue: T, source: Flow<T>): State<T> {
        check(!isActive) { "Cannot call hydratedStateOf after Hydrator is already active." }

        val mutableState = mutableStateOf(initialValue)
        traceName?.let { name ->
            tableLogBuffer?.logChange(
                prefix = this.traceName,
                columnName = name,
                value = initialValue?.toString(),
                isInitial = true,
            )
        }
        children.add(
            NamedActivatable(
                traceName = traceName,
                activatable =
                    object : ExclusiveActivatable() {
                        override suspend fun onActivated(): Nothing {
                            source.collect { mutableState.value = it }
                            source.collect {
                                traceName?.let { name ->
                                    tableLogBuffer?.logChange(
                                        prefix = this@Hydrator.traceName,
                                        columnName = name,
                                        value = it?.toString(),
                                    )
                                }
                                mutableState.value = it
                            }
                            awaitCancellation()
                        }
                    },
@@ -122,8 +139,5 @@ class Hydrator(
        }
    }

    private data class NamedActivatable(
        val traceName: String?,
        val activatable: Activatable,
    )
    private data class NamedActivatable(val traceName: String?, val activatable: Activatable)
}
+24 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.qs.composefragment.dagger

import javax.inject.Qualifier

@Qualifier
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class QSFragmentComposeLog
+11 −0
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.systemui.qs.composefragment.dagger
import android.content.Context
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.qs.flags.QSComposeFragment
import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.util.Utils
@@ -38,5 +40,14 @@ interface QSFragmentComposeModule {
        fun providesUsingMedia(@ShadeDisplayAware context: Context): Boolean {
            return QSComposeFragment.isEnabled && Utils.useQsMediaPlayer(context)
        }

        @Provides
        @SysUISingleton
        @QSFragmentComposeLog
        fun providesQSFragmentComposeViewModelTableLog(
            factory: TableLogBufferFactory
        ): TableLogBuffer {
            return factory.create("QSFragmentComposeViewModel", 200)
        }
    }
}
+4 −1
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager.Companion.LOCATION_QQS
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager.Companion.LOCATION_QS
@@ -48,6 +49,7 @@ import com.android.systemui.media.dagger.MediaModule.QS_PANEL
import com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.FooterActionsController
import com.android.systemui.qs.composefragment.dagger.QSFragmentComposeLog
import com.android.systemui.qs.composefragment.dagger.QSFragmentComposeModule
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
import com.android.systemui.qs.panels.domain.interactor.TileSquishinessInteractor
@@ -101,6 +103,7 @@ constructor(
    private val largeScreenHeaderHelper: LargeScreenHeaderHelper,
    private val squishinessInteractor: TileSquishinessInteractor,
    private val inFirstPageViewModel: InFirstPageViewModel,
    @QSFragmentComposeLog private val tableLogBuffer: TableLogBuffer,
    mediaInRowInLandscapeViewModelFactory: MediaInRowInLandscapeViewModel.Factory,
    @Named(QUICK_QS_PANEL) val qqsMediaHost: MediaHost,
    @Named(QS_PANEL) val qsMediaHost: MediaHost,
@@ -112,7 +115,7 @@ constructor(
    private val qqsMediaInRowViewModel = mediaInRowInLandscapeViewModelFactory.create(LOCATION_QQS)
    private val qsMediaInRowViewModel = mediaInRowInLandscapeViewModelFactory.create(LOCATION_QS)

    private val hydrator = Hydrator("QSFragmentComposeViewModel.hydrator")
    private val hydrator = Hydrator("QSFragmentComposeViewModel.hydrator", tableLogBuffer)

    val footerActionsViewModel =
        footerActionsViewModelFactory.create(lifecycleScope).also {
+2 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import com.android.systemui.common.ui.domain.interactor.configurationInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.log.table.logcatTableLogBuffer
import com.android.systemui.media.controls.ui.view.qqsMediaHost
import com.android.systemui.media.controls.ui.view.qsMediaHost
import com.android.systemui.qs.composefragment.dagger.usingMediaInComposeFragment
@@ -58,6 +59,7 @@ val Kosmos.qsFragmentComposeViewModelFactory by
                    largeScreenHeaderHelper,
                    tileSquishinessInteractor,
                    inFirstPageViewModel,
                    logcatTableLogBuffer(this@Fixture),
                    mediaInRowInLandscapeViewModelFactory,
                    qqsMediaHost,
                    qsMediaHost,