[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:
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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? {
|
||||
|
||||
@@ -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]"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)) }
|
||||
}
|
||||
|
||||
@@ -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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user