[Sb refactor] Add logging to mobile connections pipeline

Add logging to all inputs into the mobile connections pipeline,
including the TelephonyCallback that is used to calculate most of the
relevant state for an individual icon

Test: MobileConnectionsRepositoryTest
Bug: 238425913
Bug: 240569788
Change-Id: I6eccf2d21f942a19dde8543a7926e3ce1c069db4
This commit is contained in:
Evan Laird
2022-12-15 17:56:32 -05:00
parent bcfa7ada7c
commit 4e53da6d8d
8 changed files with 433 additions and 87 deletions

View File

@@ -26,6 +26,8 @@ import android.telephony.TelephonyCallback.ServiceStateListener
import android.telephony.TelephonyCallback.SignalStrengthsListener
import android.telephony.TelephonyDisplayInfo
import android.telephony.TelephonyManager
import com.android.systemui.log.table.Diffable
import com.android.systemui.log.table.TableRowLogger
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Disconnected
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
@@ -79,4 +81,72 @@ data class MobileConnectionModel(
* [TelephonyDisplayInfo.getNetworkType]. This is used to look up the proper network type icon
*/
val resolvedNetworkType: ResolvedNetworkType = ResolvedNetworkType.UnknownNetworkType,
)
) : Diffable<MobileConnectionModel> {
override fun logDiffs(prevVal: MobileConnectionModel, row: TableRowLogger) {
if (prevVal.dataConnectionState != dataConnectionState) {
row.logChange(COL_CONNECTION_STATE, dataConnectionState.toString())
}
if (prevVal.isEmergencyOnly != isEmergencyOnly) {
row.logChange(COL_EMERGENCY, isEmergencyOnly)
}
if (prevVal.isRoaming != isRoaming) {
row.logChange(COL_ROAMING, isRoaming)
}
if (prevVal.operatorAlphaShort != operatorAlphaShort) {
row.logChange(COL_OPERATOR, operatorAlphaShort)
}
if (prevVal.isGsm != isGsm) {
row.logChange(COL_IS_GSM, isGsm)
}
if (prevVal.cdmaLevel != cdmaLevel) {
row.logChange(COL_CDMA_LEVEL, cdmaLevel)
}
if (prevVal.primaryLevel != primaryLevel) {
row.logChange(COL_PRIMARY_LEVEL, primaryLevel)
}
if (prevVal.dataActivityDirection != dataActivityDirection) {
row.logChange(COL_ACTIVITY_DIRECTION, dataActivityDirection.toString())
}
if (prevVal.carrierNetworkChangeActive != carrierNetworkChangeActive) {
row.logChange(COL_CARRIER_NETWORK_CHANGE, carrierNetworkChangeActive)
}
if (prevVal.resolvedNetworkType != resolvedNetworkType) {
row.logChange(COL_RESOLVED_NETWORK_TYPE, resolvedNetworkType.toString())
}
}
override fun logFull(row: TableRowLogger) {
row.logChange(COL_CONNECTION_STATE, dataConnectionState.toString())
row.logChange(COL_EMERGENCY, isEmergencyOnly)
row.logChange(COL_ROAMING, isRoaming)
row.logChange(COL_OPERATOR, operatorAlphaShort)
row.logChange(COL_IS_GSM, isGsm)
row.logChange(COL_CDMA_LEVEL, cdmaLevel)
row.logChange(COL_PRIMARY_LEVEL, primaryLevel)
row.logChange(COL_ACTIVITY_DIRECTION, dataActivityDirection.toString())
row.logChange(COL_CARRIER_NETWORK_CHANGE, carrierNetworkChangeActive)
row.logChange(COL_RESOLVED_NETWORK_TYPE, resolvedNetworkType.toString())
}
companion object {
const val COL_EMERGENCY = "EmergencyOnly"
const val COL_ROAMING = "Roaming"
const val COL_OPERATOR = "OperatorName"
const val COL_IS_GSM = "IsGsm"
const val COL_CDMA_LEVEL = "CdmaLevel"
const val COL_PRIMARY_LEVEL = "PrimaryLevel"
const val COL_CONNECTION_STATE = "ConnectionState"
const val COL_ACTIVITY_DIRECTION = "DataActivity"
const val COL_CARRIER_NETWORK_CHANGE = "CarrierNetworkChangeActive"
const val COL_RESOLVED_NETWORK_TYPE = "NetworkType"
}
}

View File

@@ -21,22 +21,48 @@ import android.telephony.TelephonyManager.EXTRA_DATA_SPN
import android.telephony.TelephonyManager.EXTRA_PLMN
import android.telephony.TelephonyManager.EXTRA_SHOW_PLMN
import android.telephony.TelephonyManager.EXTRA_SHOW_SPN
import com.android.systemui.log.table.Diffable
import com.android.systemui.log.table.TableRowLogger
/**
* Encapsulates the data needed to show a network name for a mobile network. The data is parsed from
* the intent sent by [android.telephony.TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED].
*/
sealed interface NetworkNameModel {
sealed interface NetworkNameModel : Diffable<NetworkNameModel> {
val name: String
/** The default name is read from [com.android.internal.R.string.lockscreen_carrier_default] */
data class Default(override val name: String) : NetworkNameModel
data class Default(override val name: String) : NetworkNameModel {
override fun logDiffs(prevVal: NetworkNameModel, row: TableRowLogger) {
if (prevVal !is Default || prevVal.name != name) {
row.logChange(COL_NETWORK_NAME, "Default($name)")
}
}
override fun logFull(row: TableRowLogger) {
row.logChange(COL_NETWORK_NAME, "Default($name)")
}
}
/**
* This name has been derived from telephony intents. see
* [android.telephony.TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED]
*/
data class Derived(override val name: String) : NetworkNameModel
data class Derived(override val name: String) : NetworkNameModel {
override fun logDiffs(prevVal: NetworkNameModel, row: TableRowLogger) {
if (prevVal !is Derived || prevVal.name != name) {
row.logChange(COL_NETWORK_NAME, "Derived($name)")
}
}
override fun logFull(row: TableRowLogger) {
row.logChange(COL_NETWORK_NAME, "Derived($name)")
}
}
companion object {
const val COL_NETWORK_NAME = "networkName"
}
}
fun Intent.toNetworkNameModel(separator: String): NetworkNameModel? {

View File

@@ -36,6 +36,9 @@ import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
@@ -46,7 +49,6 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameMo
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
import com.android.systemui.util.settings.GlobalSettings
import javax.inject.Inject
@@ -59,6 +61,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
@@ -79,6 +82,7 @@ class MobileConnectionRepositoryImpl(
mobileMappingsProxy: MobileMappingsProxy,
bgDispatcher: CoroutineDispatcher,
logger: ConnectivityPipelineLogger,
mobileLogger: TableLogBuffer,
scope: CoroutineScope,
) : MobileConnectionRepository {
init {
@@ -95,7 +99,6 @@ class MobileConnectionRepositoryImpl(
override val connectionInfo: StateFlow<MobileConnectionModel> = run {
var state = MobileConnectionModel()
conflatedCallbackFlow {
// TODO (b/240569788): log all of these into the connectivity logger
val callback =
object :
TelephonyCallback(),
@@ -106,6 +109,7 @@ class MobileConnectionRepositoryImpl(
TelephonyCallback.CarrierNetworkListener,
TelephonyCallback.DisplayInfoListener {
override fun onServiceStateChanged(serviceState: ServiceState) {
logger.logOnServiceStateChanged(serviceState, subId)
state =
state.copy(
isEmergencyOnly = serviceState.isEmergencyOnly,
@@ -116,6 +120,7 @@ class MobileConnectionRepositoryImpl(
}
override fun onSignalStrengthsChanged(signalStrength: SignalStrength) {
logger.logOnSignalStrengthsChanged(signalStrength, subId)
val cdmaLevel =
signalStrength
.getCellSignalStrengths(CellSignalStrengthCdma::class.java)
@@ -142,12 +147,14 @@ class MobileConnectionRepositoryImpl(
dataState: Int,
networkType: Int
) {
logger.logOnDataConnectionStateChanged(dataState, networkType, subId)
state =
state.copy(dataConnectionState = dataState.toDataConnectionType())
trySend(state)
}
override fun onDataActivity(direction: Int) {
logger.logOnDataActivity(direction, subId)
state =
state.copy(
dataActivityDirection = direction.toMobileDataActivityModel()
@@ -156,6 +163,7 @@ class MobileConnectionRepositoryImpl(
}
override fun onCarrierNetworkChange(active: Boolean) {
logger.logOnCarrierNetworkChange(active, subId)
state = state.copy(carrierNetworkChangeActive = active)
trySend(state)
}
@@ -163,6 +171,7 @@ class MobileConnectionRepositoryImpl(
override fun onDisplayInfoChanged(
telephonyDisplayInfo: TelephonyDisplayInfo
) {
logger.logOnDisplayInfoChanged(telephonyDisplayInfo, subId)
val networkType =
if (telephonyDisplayInfo.networkType == NETWORK_TYPE_UNKNOWN) {
@@ -193,7 +202,11 @@ class MobileConnectionRepositoryImpl(
awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
}
.onEach { telephonyCallbackEvent.tryEmit(Unit) }
.logOutputChange(logger, "MobileSubscriptionModel")
.logDiffsForTable(
mobileLogger,
columnPrefix = "MobileConnection ($subId)",
initialValue = state,
)
.stateIn(scope, SharingStarted.WhileSubscribed(), state)
}
@@ -243,19 +256,43 @@ class MobileConnectionRepositoryImpl(
intent.toNetworkNameModel(networkNameSeparator) ?: defaultNetworkName
}
}
.distinctUntilChanged()
.logDiffsForTable(
mobileLogger,
columnPrefix = "",
initialValue = defaultNetworkName,
)
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
override val dataEnabled: StateFlow<Boolean> =
override val dataEnabled: StateFlow<Boolean> = run {
val initial = dataConnectionAllowed()
telephonyPollingEvent
.mapLatest { dataConnectionAllowed() }
.stateIn(scope, SharingStarted.WhileSubscribed(), dataConnectionAllowed())
.distinctUntilChanged()
.logDiffsForTable(
mobileLogger,
columnPrefix = "",
columnName = "dataEnabled",
initialValue = initial,
)
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
}
private fun dataConnectionAllowed(): Boolean = telephonyManager.isDataConnectionAllowed
override val isDefaultDataSubscription: StateFlow<Boolean> =
override val isDefaultDataSubscription: StateFlow<Boolean> = run {
val initialValue = defaultDataSubId.value == subId
defaultDataSubId
.mapLatest { it == subId }
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultDataSubId.value == subId)
.distinctUntilChanged()
.logDiffsForTable(
mobileLogger,
columnPrefix = "",
columnName = "isDefaultDataSub",
initialValue = initialValue,
)
.stateIn(scope, SharingStarted.WhileSubscribed(), initialValue)
}
class Factory
@Inject
@@ -266,6 +303,7 @@ class MobileConnectionRepositoryImpl(
private val logger: ConnectivityPipelineLogger,
private val globalSettings: GlobalSettings,
private val mobileMappingsProxy: MobileMappingsProxy,
private val logFactory: TableLogBufferFactory,
@Background private val bgDispatcher: CoroutineDispatcher,
@Application private val scope: CoroutineScope,
) {
@@ -276,6 +314,8 @@ class MobileConnectionRepositoryImpl(
defaultDataSubId: StateFlow<Int>,
globalMobileDataSettingChangedEvent: Flow<Unit>,
): MobileConnectionRepository {
val mobileLogger = logFactory.create(tableBufferLogName(subId), 100)
return MobileConnectionRepositoryImpl(
context,
subId,
@@ -289,8 +329,13 @@ class MobileConnectionRepositoryImpl(
mobileMappingsProxy,
bgDispatcher,
logger,
mobileLogger,
scope,
)
}
}
companion object {
fun tableBufferLogName(subId: Int): String = "MobileConnectionLog [$subId]"
}
}

View File

@@ -51,6 +51,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConn
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
import com.android.systemui.util.settings.GlobalSettings
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -120,6 +121,7 @@ constructor(
awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(callback) }
}
.mapLatest { fetchSubscriptionsList().map { it.toSubscriptionModel() } }
.logInputChange(logger, "onSubscriptionsChanged")
.onEach { infos -> dropUnusedReposFromCache(infos) }
.stateIn(scope, started = SharingStarted.WhileSubscribed(), listOf())
@@ -136,6 +138,8 @@ constructor(
telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
}
.distinctUntilChanged()
.logInputChange(logger, "onActiveDataSubscriptionIdChanged")
.stateIn(scope, started = SharingStarted.WhileSubscribed(), INVALID_SUBSCRIPTION_ID)
private val defaultDataSubIdChangeEvent: MutableSharedFlow<Unit> =
@@ -149,6 +153,7 @@ constructor(
intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, INVALID_SUBSCRIPTION_ID)
}
.distinctUntilChanged()
.logInputChange(logger, "ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED")
.onEach { defaultDataSubIdChangeEvent.tryEmit(Unit) }
.stateIn(
scope,
@@ -157,13 +162,15 @@ constructor(
)
private val carrierConfigChangedEvent =
broadcastDispatcher.broadcastFlow(
IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)
)
broadcastDispatcher
.broadcastFlow(IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED))
.logInputChange(logger, "ACTION_CARRIER_CONFIG_CHANGED")
override val defaultDataSubRatConfig: StateFlow<Config> =
merge(defaultDataSubIdChangeEvent, carrierConfigChangedEvent)
.mapLatest { Config.readConfig(context) }
.distinctUntilChanged()
.logInputChange(logger, "defaultDataSubRatConfig")
.stateIn(
scope,
SharingStarted.WhileSubscribed(),
@@ -171,10 +178,16 @@ constructor(
)
override val defaultMobileIconMapping: Flow<Map<String, MobileIconGroup>> =
defaultDataSubRatConfig.map { mobileMappingsProxy.mapIconSets(it) }
defaultDataSubRatConfig
.map { mobileMappingsProxy.mapIconSets(it) }
.distinctUntilChanged()
.logInputChange(logger, "defaultMobileIconMapping")
override val defaultMobileIconGroup: Flow<MobileIconGroup> =
defaultDataSubRatConfig.map { mobileMappingsProxy.getDefaultIcons(it) }
defaultDataSubRatConfig
.map { mobileMappingsProxy.getDefaultIcons(it) }
.distinctUntilChanged()
.logInputChange(logger, "defaultMobileIconGroup")
override fun getRepoForSubId(subId: Int): MobileConnectionRepository {
if (!isValidSubId(subId)) {
@@ -191,22 +204,24 @@ constructor(
* In single-SIM devices, the [MOBILE_DATA] setting is phone-wide. For multi-SIM, the individual
* connection repositories also observe the URI for [MOBILE_DATA] + subId.
*/
override val globalMobileDataSettingChangedEvent: Flow<Unit> = conflatedCallbackFlow {
val observer =
object : ContentObserver(null) {
override fun onChange(selfChange: Boolean) {
trySend(Unit)
}
override val globalMobileDataSettingChangedEvent: Flow<Unit> =
conflatedCallbackFlow {
val observer =
object : ContentObserver(null) {
override fun onChange(selfChange: Boolean) {
trySend(Unit)
}
}
globalSettings.registerContentObserver(
globalSettings.getUriFor(MOBILE_DATA),
true,
observer
)
awaitClose { context.contentResolver.unregisterContentObserver(observer) }
}
globalSettings.registerContentObserver(
globalSettings.getUriFor(MOBILE_DATA),
true,
observer
)
awaitClose { context.contentResolver.unregisterContentObserver(observer) }
}
.logInputChange(logger, "globalMobileDataSettingChangedEvent")
@SuppressLint("MissingPermission")
override val defaultMobileNetworkConnectivity: StateFlow<MobileConnectivityModel> =
@@ -236,6 +251,8 @@ constructor(
awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
}
.distinctUntilChanged()
.logInputChange(logger, "defaultMobileNetworkConnectivity")
.stateIn(scope, SharingStarted.WhileSubscribed(), MobileConnectivityModel())
private fun isValidSubId(subId: Int): Boolean {

View File

@@ -18,8 +18,11 @@ package com.android.systemui.statusbar.pipeline.shared
import android.net.Network
import android.net.NetworkCapabilities
import com.android.systemui.log.dagger.StatusBarConnectivityLog
import android.telephony.ServiceState
import android.telephony.SignalStrength
import android.telephony.TelephonyDisplayInfo
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.dagger.StatusBarConnectivityLog
import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.toString
@@ -28,7 +31,9 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.onEach
@SysUISingleton
class ConnectivityPipelineLogger @Inject constructor(
class ConnectivityPipelineLogger
@Inject
constructor(
@StatusBarConnectivityLog private val buffer: LogBuffer,
) {
/**
@@ -37,34 +42,23 @@ class ConnectivityPipelineLogger @Inject constructor(
* Use this method for inputs that don't have any extra information besides their callback name.
*/
fun logInputChange(callbackName: String) {
buffer.log(SB_LOGGING_TAG, LogLevel.INFO, { str1 = callbackName }, { "Input: $str1" })
}
/** Logs a change in one of the **raw inputs** to the connectivity pipeline. */
fun logInputChange(callbackName: String, changeInfo: String?) {
buffer.log(
SB_LOGGING_TAG,
LogLevel.INFO,
{ str1 = callbackName },
{ "Input: $str1" }
{
str1 = callbackName
str2 = changeInfo
},
{ "Input: $str1: $str2" }
)
}
/**
* Logs a change in one of the **raw inputs** to the connectivity pipeline.
*/
fun logInputChange(callbackName: String, changeInfo: String?) {
buffer.log(
SB_LOGGING_TAG,
LogLevel.INFO,
{
str1 = callbackName
str2 = changeInfo
},
{
"Input: $str1: $str2"
}
)
}
/**
* Logs a **data transformation** that we performed within the connectivity pipeline.
*/
/** Logs a **data transformation** that we performed within the connectivity pipeline. */
fun logTransformation(transformationName: String, oldValue: Any?, newValue: Any?) {
if (oldValue == newValue) {
buffer.log(
@@ -74,9 +68,7 @@ class ConnectivityPipelineLogger @Inject constructor(
str1 = transformationName
str2 = oldValue.toString()
},
{
"Transform: $str1: $str2 (transformation didn't change it)"
}
{ "Transform: $str1: $str2 (transformation didn't change it)" }
)
} else {
buffer.log(
@@ -87,27 +79,21 @@ class ConnectivityPipelineLogger @Inject constructor(
str2 = oldValue.toString()
str3 = newValue.toString()
},
{
"Transform: $str1: $str2 -> $str3"
}
{ "Transform: $str1: $str2 -> $str3" }
)
}
}
/**
* Logs a change in one of the **outputs** to the connectivity pipeline.
*/
/** Logs a change in one of the **outputs** to the connectivity pipeline. */
fun logOutputChange(outputParamName: String, changeInfo: String) {
buffer.log(
SB_LOGGING_TAG,
LogLevel.INFO,
{
str1 = outputParamName
str2 = changeInfo
},
{
"Output: $str1: $str2"
}
SB_LOGGING_TAG,
LogLevel.INFO,
{
str1 = outputParamName
str2 = changeInfo
},
{ "Output: $str1: $str2" }
)
}
@@ -119,31 +105,101 @@ class ConnectivityPipelineLogger @Inject constructor(
int1 = network.getNetId()
str1 = networkCapabilities.toString()
},
{
"onCapabilitiesChanged: net=$int1 capabilities=$str1"
}
{ "onCapabilitiesChanged: net=$int1 capabilities=$str1" }
)
}
fun logOnLost(network: Network) {
buffer.log(
SB_LOGGING_TAG,
LogLevel.INFO,
{ int1 = network.getNetId() },
{ "onLost: net=$int1" }
)
}
fun logOnServiceStateChanged(serviceState: ServiceState, subId: Int) {
buffer.log(
SB_LOGGING_TAG,
LogLevel.INFO,
{
int1 = network.getNetId()
int1 = subId
bool1 = serviceState.isEmergencyOnly
bool2 = serviceState.roaming
str1 = serviceState.operatorAlphaShort
},
{
"onLost: net=$int1"
"onServiceStateChanged: subId=$int1 emergencyOnly=$bool1 roaming=$bool2" +
" operator=$str1"
}
)
}
fun logOnSignalStrengthsChanged(signalStrength: SignalStrength, subId: Int) {
buffer.log(
SB_LOGGING_TAG,
LogLevel.INFO,
{
int1 = subId
str1 = signalStrength.toString()
},
{ "onSignalStrengthsChanged: subId=$int1 strengths=$str1" }
)
}
fun logOnDataConnectionStateChanged(dataState: Int, networkType: Int, subId: Int) {
buffer.log(
SB_LOGGING_TAG,
LogLevel.INFO,
{
int1 = subId
int2 = dataState
str1 = networkType.toString()
},
{ "onDataConnectionStateChanged: subId=$int1 dataState=$int2 networkType=$str1" },
)
}
fun logOnDataActivity(direction: Int, subId: Int) {
buffer.log(
SB_LOGGING_TAG,
LogLevel.INFO,
{
int1 = subId
int2 = direction
},
{ "onDataActivity: subId=$int1 direction=$int2" },
)
}
fun logOnCarrierNetworkChange(active: Boolean, subId: Int) {
buffer.log(
SB_LOGGING_TAG,
LogLevel.INFO,
{
int1 = subId
bool1 = active
},
{ "onCarrierNetworkChange: subId=$int1 active=$bool1" },
)
}
fun logOnDisplayInfoChanged(displayInfo: TelephonyDisplayInfo, subId: Int) {
buffer.log(
SB_LOGGING_TAG,
LogLevel.INFO,
{
int1 = subId
str1 = displayInfo.toString()
},
{ "onDisplayInfoChanged: subId=$int1 displayInfo=$str1" },
)
}
companion object {
const val SB_LOGGING_TAG = "SbConnectivity"
/**
* Log a change in one of the **inputs** to the connectivity pipeline.
*/
/** Log a change in one of the **inputs** to the connectivity pipeline. */
fun Flow<Unit>.logInputChange(
logger: ConnectivityPipelineLogger,
inputParamName: String,
@@ -155,26 +211,26 @@ class ConnectivityPipelineLogger @Inject constructor(
* Log a change in one of the **inputs** to the connectivity pipeline.
*
* @param prettyPrint an optional function to transform the value into a readable string.
* [toString] is used if no custom function is provided.
* [toString] is used if no custom function is provided.
*/
fun <T> Flow<T>.logInputChange(
logger: ConnectivityPipelineLogger,
inputParamName: String,
prettyPrint: (T) -> String = { it.toString() }
): Flow<T> {
return this.onEach {logger.logInputChange(inputParamName, prettyPrint(it)) }
return this.onEach { logger.logInputChange(inputParamName, prettyPrint(it)) }
}
/**
* Log a change in one of the **outputs** to the connectivity pipeline.
*
* @param prettyPrint an optional function to transform the value into a readable string.
* [toString] is used if no custom function is provided.
* [toString] is used if no custom function is provided.
*/
fun <T> Flow<T>.logOutputChange(
logger: ConnectivityPipelineLogger,
outputParamName: String,
prettyPrint: (T) -> String = { it.toString() }
logger: ConnectivityPipelineLogger,
outputParamName: String,
prettyPrint: (T) -> String = { it.toString() }
): Flow<T> {
return this.onEach { logger.logOutputChange(outputParamName, prettyPrint(it)) }
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2022 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.statusbar.pipeline.mobile.data.model
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.table.TableRowLogger
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_ACTIVITY_DIRECTION
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_CARRIER_NETWORK_CHANGE
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_CDMA_LEVEL
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_CONNECTION_STATE
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_EMERGENCY
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_IS_GSM
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_OPERATOR
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_PRIMARY_LEVEL
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_RESOLVED_NETWORK_TYPE
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_ROAMING
import com.google.common.truth.Truth.assertThat
import org.junit.Test
@SmallTest
class MobileConnectionModelTest : SysuiTestCase() {
@Test
fun `log diff - initial log contains all columns`() {
val logger = TestLogger()
val connection = MobileConnectionModel()
connection.logFull(logger)
assertThat(logger.changes)
.contains(Pair(COL_EMERGENCY, connection.isEmergencyOnly.toString()))
assertThat(logger.changes).contains(Pair(COL_ROAMING, connection.isRoaming.toString()))
assertThat(logger.changes)
.contains(Pair(COL_OPERATOR, connection.operatorAlphaShort.toString()))
assertThat(logger.changes).contains(Pair(COL_IS_GSM, connection.isGsm.toString()))
assertThat(logger.changes).contains(Pair(COL_CDMA_LEVEL, connection.cdmaLevel.toString()))
assertThat(logger.changes)
.contains(Pair(COL_PRIMARY_LEVEL, connection.primaryLevel.toString()))
assertThat(logger.changes)
.contains(Pair(COL_CONNECTION_STATE, connection.dataConnectionState.toString()))
assertThat(logger.changes)
.contains(Pair(COL_ACTIVITY_DIRECTION, connection.dataActivityDirection.toString()))
assertThat(logger.changes)
.contains(
Pair(COL_CARRIER_NETWORK_CHANGE, connection.carrierNetworkChangeActive.toString())
)
assertThat(logger.changes)
.contains(Pair(COL_RESOLVED_NETWORK_TYPE, connection.resolvedNetworkType.toString()))
}
@Test
fun `log diff - primary level changes - only level is logged`() {
val logger = TestLogger()
val connectionOld = MobileConnectionModel(primaryLevel = 1)
val connectionNew = MobileConnectionModel(primaryLevel = 2)
connectionNew.logDiffs(connectionOld, logger)
assertThat(logger.changes).isEqualTo(listOf(Pair(COL_PRIMARY_LEVEL, "2")))
}
private class TestLogger : TableRowLogger {
val changes = mutableListOf<Pair<String, String>>()
override fun logChange(columnName: String, value: String?) {
changes.add(Pair(columnName, value.toString()))
}
override fun logChange(columnName: String, value: Int) {
changes.add(Pair(columnName, value.toString()))
}
override fun logChange(columnName: String, value: Boolean) {
changes.add(Pair(columnName, value.toString()))
}
}
}

View File

@@ -50,6 +50,7 @@ import android.telephony.TelephonyManager.NETWORK_TYPE_LTE
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
@@ -90,6 +91,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
@Mock private lateinit var telephonyManager: TelephonyManager
@Mock private lateinit var logger: ConnectivityPipelineLogger
@Mock private lateinit var tableLogger: TableLogBuffer
private val scope = CoroutineScope(IMMEDIATE)
private val mobileMappings = FakeMobileMappingsProxy()
@@ -116,6 +118,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
mobileMappings,
IMMEDIATE,
logger,
tableLogger,
scope,
)
}

View File

@@ -34,12 +34,15 @@ import com.android.internal.telephony.PhoneConstants
import com.android.settingslib.R
import com.android.settingslib.mobile.MobileMappings
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.settings.FakeSettings
@@ -57,6 +60,7 @@ import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -72,6 +76,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
@Mock private lateinit var subscriptionManager: SubscriptionManager
@Mock private lateinit var telephonyManager: TelephonyManager
@Mock private lateinit var logger: ConnectivityPipelineLogger
@Mock private lateinit var logBufferFactory: TableLogBufferFactory
private val mobileMappings = FakeMobileMappingsProxy()
@@ -89,6 +94,10 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
}
}
whenever(logBufferFactory.create(anyString(), anyInt())).thenAnswer { _ ->
mock<TableLogBuffer>()
}
connectionFactory =
MobileConnectionRepositoryImpl.Factory(
fakeBroadcastDispatcher,
@@ -99,6 +108,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
logger = logger,
mobileMappingsProxy = mobileMappings,
scope = scope,
logFactory = logBufferFactory,
)
underTest =
@@ -270,6 +280,32 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
job.cancel()
}
@Test
fun `connection repository - log buffer contains sub id in its name`() =
runBlocking(IMMEDIATE) {
val job = underTest.subscriptions.launchIn(this)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_1, SUB_2))
getSubscriptionCallback().onSubscriptionsChanged()
// Get repos to trigger creation
underTest.getRepoForSubId(SUB_1_ID)
verify(logBufferFactory)
.create(
eq(MobileConnectionRepositoryImpl.tableBufferLogName(SUB_1_ID)),
anyInt(),
)
underTest.getRepoForSubId(SUB_2_ID)
verify(logBufferFactory)
.create(
eq(MobileConnectionRepositoryImpl.tableBufferLogName(SUB_2_ID)),
anyInt(),
)
job.cancel()
}
@Test
fun testDefaultDataSubId_updatesOnBroadcast() =
runBlocking(IMMEDIATE) {