[SB Refactor] Add logs for the carrier merged connection.

Bug: 264684296
Fixes: 267501739
Bug: 238425913
Test: Manual: Dumped MobileConnectionLog[3] and verified logs
Test: atest FullMobileConnectionRepositoryTest
CarrierMergedConnectionRepositoryTest

Change-Id: Ife7d154e0bd07f5ede9cfd5404407e1863c78df6
This commit is contained in:
Caitlin Shkuratov
2023-01-30 21:47:48 +00:00
parent d504771ed3
commit 957a878b44
6 changed files with 339 additions and 40 deletions

View File

@@ -91,9 +91,6 @@ class CarrierMergedConnectionRepository(
.map { it.toMobileConnectionModel() }
.stateIn(scope, SharingStarted.WhileSubscribed(), MobileConnectionModel())
// TODO(b/238425913): Add logging to this class.
// TODO(b/238425913): Make sure SignalStrength.getEmptyState is used when appropriate.
// Carrier merged is never roaming.
override val cdmaRoaming: StateFlow<Boolean> = MutableStateFlow(false).asStateFlow()

View File

@@ -117,11 +117,22 @@ class FullMobileConnectionRepository(
override val connectionInfo =
activeRepo
.flatMapLatest { it.connectionInfo }
.logDiffsForTable(
tableLogBuffer,
columnPrefix = "",
initialValue = activeRepo.value.connectionInfo.value,
)
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.connectionInfo.value)
override val dataEnabled =
activeRepo
.flatMapLatest { it.dataEnabled }
.logDiffsForTable(
tableLogBuffer,
columnPrefix = "",
columnName = "dataEnabled",
initialValue = activeRepo.value.dataEnabled.value,
)
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.dataEnabled.value)
override val numberOfLevels =
@@ -132,6 +143,11 @@ class FullMobileConnectionRepository(
override val networkName =
activeRepo
.flatMapLatest { it.networkName }
.logDiffsForTable(
tableLogBuffer,
columnPrefix = "",
initialValue = activeRepo.value.networkName.value,
)
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.networkName.value)
class Factory
@@ -168,7 +184,7 @@ class FullMobileConnectionRepository(
const val MOBILE_CONNECTION_BUFFER_SIZE = 100
/** Returns a log buffer name for a mobile connection with the given [subId]. */
fun tableBufferLogName(subId: Int): String = "MobileConnectionLog [$subId]"
fun tableBufferLogName(subId: Int): String = "MobileConnectionLog[$subId]"
}
}
}

View File

@@ -36,7 +36,6 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
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.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
@@ -62,7 +61,6 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.mapNotNull
@@ -87,7 +85,7 @@ class MobileConnectionRepositoryImpl(
private val mobileMappingsProxy: MobileMappingsProxy,
bgDispatcher: CoroutineDispatcher,
logger: ConnectivityPipelineLogger,
mobileLogger: TableLogBuffer,
override val tableLogBuffer: TableLogBuffer,
scope: CoroutineScope,
) : MobileConnectionRepository {
init {
@@ -101,8 +99,6 @@ class MobileConnectionRepositoryImpl(
private val telephonyCallbackEvent = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
override val tableLogBuffer: TableLogBuffer = mobileLogger
/**
* This flow defines the single shared connection to system_server via TelephonyCallback. Any
* new callback should be added to this listener and funneled through callbackEvents via a data
@@ -243,11 +239,6 @@ class MobileConnectionRepositoryImpl(
val initial = MobileConnectionModel()
callbackEvents
.scan(initial, ::updateConnectionState)
.logDiffsForTable(
mobileLogger,
columnPrefix = "MobileConnection ($subId)",
initialValue = initial,
)
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
}
@@ -285,24 +276,12 @@ class MobileConnectionRepositoryImpl(
intent.toNetworkNameModel(networkNameSeparator) ?: defaultNetworkName
}
}
.distinctUntilChanged()
.logDiffsForTable(
mobileLogger,
columnPrefix = "",
initialValue = defaultNetworkName,
)
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
override val dataEnabled = run {
val initial = telephonyManager.isDataConnectionAllowed
callbackEvents
.mapNotNull { (it as? CallbackEvent.OnDataEnabledChanged)?.enabled }
.logDiffsForTable(
mobileLogger,
columnPrefix = "",
columnName = "dataEnabled",
initialValue = initial
)
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
}

View File

@@ -16,20 +16,32 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
import android.telephony.ServiceState
import android.telephony.SignalStrength
import android.telephony.TelephonyCallback
import android.telephony.TelephonyManager
import androidx.test.filters.SmallTest
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.MobileConnectionModel
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_OPERATOR
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_PRIMARY_LEVEL
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.getTelephonyCallbackForType
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
import com.android.systemui.util.mockito.any
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.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
import java.io.StringWriter
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -52,9 +64,10 @@ import org.mockito.Mockito.verify
class FullMobileConnectionRepositoryTest : SysuiTestCase() {
private lateinit var underTest: FullMobileConnectionRepository
private val systemClock = FakeSystemClock()
private val testDispatcher = UnconfinedTestDispatcher()
private val testScope = TestScope(testDispatcher)
private val tableLogBuffer = mock<TableLogBuffer>()
private val tableLogBuffer = TableLogBuffer(maxSize = 100, name = "TestName", systemClock)
private val mobileFactory = mock<MobileConnectionRepositoryImpl.Factory>()
private val carrierMergedFactory = mock<CarrierMergedConnectionRepository.Factory>()
@@ -347,8 +360,214 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
.isSameInstanceAs(connection1Repeat.tableLogBuffer)
}
// TODO(b/238425913): Verify that the logging switches correctly (once the carrier merged repo
// implements logging).
@Test
fun connectionInfo_logging_notCarrierMerged_getsUpdates() =
testScope.runTest {
// SETUP: Use real repositories to verify the diffing still works. (See b/267501739.)
val telephonyManager = mock<TelephonyManager>()
createRealMobileRepo(telephonyManager)
createRealCarrierMergedRepo(FakeWifiRepository())
initializeRepo(startingIsCarrierMerged = false)
val job = underTest.connectionInfo.launchIn(this)
// WHEN we set up some mobile connection info
val serviceState = ServiceState()
serviceState.setOperatorName("longName", "OpTypical", "1")
serviceState.isEmergencyOnly = false
getTelephonyCallbackForType<TelephonyCallback.ServiceStateListener>(telephonyManager)
.onServiceStateChanged(serviceState)
// THEN it's logged to the buffer
assertThat(dumpBuffer()).contains("$COL_OPERATOR${BUFFER_SEPARATOR}OpTypical")
assertThat(dumpBuffer()).contains("$COL_EMERGENCY${BUFFER_SEPARATOR}false")
// WHEN we update mobile connection info
val serviceState2 = ServiceState()
serviceState2.setOperatorName("longName", "OpDiff", "1")
serviceState2.isEmergencyOnly = true
getTelephonyCallbackForType<TelephonyCallback.ServiceStateListener>(telephonyManager)
.onServiceStateChanged(serviceState2)
// THEN the updates are logged
assertThat(dumpBuffer()).contains("$COL_OPERATOR${BUFFER_SEPARATOR}OpDiff")
assertThat(dumpBuffer()).contains("$COL_EMERGENCY${BUFFER_SEPARATOR}true")
job.cancel()
}
@Test
fun connectionInfo_logging_carrierMerged_getsUpdates() =
testScope.runTest {
// SETUP: Use real repositories to verify the diffing still works. (See b/267501739.)
createRealMobileRepo(mock())
val wifiRepository = FakeWifiRepository()
createRealCarrierMergedRepo(wifiRepository)
initializeRepo(startingIsCarrierMerged = true)
val job = underTest.connectionInfo.launchIn(this)
// WHEN we set up carrier merged info
val networkId = 2
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
networkId,
SUB_ID,
level = 3,
)
)
// THEN the carrier merged info is logged
assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}3")
// WHEN we update the info
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
networkId,
SUB_ID,
level = 1,
)
)
// THEN the updates are logged
assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}1")
job.cancel()
}
@Test
fun connectionInfo_logging_updatesWhenCarrierMergedUpdates() =
testScope.runTest {
// SETUP: Use real repositories to verify the diffing still works. (See b/267501739.)
val telephonyManager = mock<TelephonyManager>()
createRealMobileRepo(telephonyManager)
val wifiRepository = FakeWifiRepository()
createRealCarrierMergedRepo(wifiRepository)
initializeRepo(startingIsCarrierMerged = false)
val job = underTest.connectionInfo.launchIn(this)
// WHEN we set up some mobile connection info
val signalStrength = mock<SignalStrength>()
whenever(signalStrength.level).thenReturn(1)
getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>(telephonyManager)
.onSignalStrengthsChanged(signalStrength)
// THEN it's logged to the buffer
assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}1")
// WHEN isCarrierMerged is set to true
val networkId = 2
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
networkId,
SUB_ID,
level = 3,
)
)
underTest.setIsCarrierMerged(true)
// THEN the carrier merged info is logged
assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}3")
// WHEN the carrier merge network is updated
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
networkId,
SUB_ID,
level = 4,
)
)
// THEN the new level is logged
assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}4")
// WHEN isCarrierMerged is set to false
underTest.setIsCarrierMerged(false)
// THEN the typical info is logged
// Note: Since our first logs also had the typical info, we need to search the log
// contents for after our carrier merged level log.
val fullBuffer = dumpBuffer()
val carrierMergedContentIndex = fullBuffer.indexOf("${BUFFER_SEPARATOR}4")
val bufferAfterCarrierMerged = fullBuffer.substring(carrierMergedContentIndex)
assertThat(bufferAfterCarrierMerged).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}1")
// WHEN the normal network is updated
val newMobileInfo =
MobileConnectionModel(
operatorAlphaShort = "Mobile Operator 2",
primaryLevel = 0,
)
mobileRepo.setConnectionInfo(newMobileInfo)
// THEN the new level is logged
assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}0")
job.cancel()
}
@Test
fun connectionInfo_logging_doesNotLogUpdatesForNotActiveRepo() =
testScope.runTest {
// SETUP: Use real repositories to verify the diffing still works. (See b/267501739.)
val telephonyManager = mock<TelephonyManager>()
createRealMobileRepo(telephonyManager)
val wifiRepository = FakeWifiRepository()
createRealCarrierMergedRepo(wifiRepository)
// WHEN isCarrierMerged = false
initializeRepo(startingIsCarrierMerged = false)
val job = underTest.connectionInfo.launchIn(this)
val signalStrength = mock<SignalStrength>()
whenever(signalStrength.level).thenReturn(1)
getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>(telephonyManager)
.onSignalStrengthsChanged(signalStrength)
// THEN updates to the carrier merged level aren't logged
val networkId = 2
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
networkId,
SUB_ID,
level = 4,
)
)
assertThat(dumpBuffer()).doesNotContain("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}4")
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
networkId,
SUB_ID,
level = 3,
)
)
assertThat(dumpBuffer()).doesNotContain("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}3")
// WHEN isCarrierMerged is set to true
underTest.setIsCarrierMerged(true)
// THEN updates to the normal level aren't logged
whenever(signalStrength.level).thenReturn(5)
getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>(telephonyManager)
.onSignalStrengthsChanged(signalStrength)
assertThat(dumpBuffer()).doesNotContain("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}5")
whenever(signalStrength.level).thenReturn(6)
getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>(telephonyManager)
.onSignalStrengthsChanged(signalStrength)
assertThat(dumpBuffer()).doesNotContain("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}6")
job.cancel()
}
private fun initializeRepo(startingIsCarrierMerged: Boolean) {
underTest =
@@ -364,9 +583,68 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
)
}
private fun createRealMobileRepo(
telephonyManager: TelephonyManager,
): MobileConnectionRepositoryImpl {
whenever(telephonyManager.subscriptionId).thenReturn(SUB_ID)
val realRepo =
MobileConnectionRepositoryImpl(
context,
SUB_ID,
defaultNetworkName = NetworkNameModel.Default("default"),
networkNameSeparator = SEP,
telephonyManager,
systemUiCarrierConfig = mock(),
fakeBroadcastDispatcher,
mobileMappingsProxy = mock(),
testDispatcher,
logger = mock(),
tableLogBuffer,
testScope.backgroundScope,
)
whenever(
mobileFactory.build(
eq(SUB_ID),
any(),
eq(DEFAULT_NAME),
eq(SEP),
)
)
.thenReturn(realRepo)
return realRepo
}
private fun createRealCarrierMergedRepo(
wifiRepository: FakeWifiRepository,
): CarrierMergedConnectionRepository {
wifiRepository.setIsWifiEnabled(true)
wifiRepository.setIsWifiDefault(true)
val realRepo =
CarrierMergedConnectionRepository(
SUB_ID,
tableLogBuffer,
defaultNetworkName = NetworkNameModel.Default("default"),
testScope.backgroundScope,
wifiRepository,
)
whenever(carrierMergedFactory.build(eq(SUB_ID), any(), eq(DEFAULT_NAME)))
.thenReturn(realRepo)
return realRepo
}
private fun dumpBuffer(): String {
val outputWriter = StringWriter()
tableLogBuffer.dump(PrintWriter(outputWriter), arrayOf())
return outputWriter.toString()
}
private companion object {
const val SUB_ID = 42
private val DEFAULT_NAME = NetworkNameModel.Default("default name")
private const val SEP = "-"
private const val BUFFER_SEPARATOR = "|"
}
}

View File

@@ -71,7 +71,6 @@ import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
@@ -86,7 +85,6 @@ import org.junit.After
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@@ -670,16 +668,8 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
job.cancel()
}
private fun getTelephonyCallbacks(): List<TelephonyCallback> {
val callbackCaptor = argumentCaptor<TelephonyCallback>()
Mockito.verify(telephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture())
return callbackCaptor.allValues
}
private inline fun <reified T> getTelephonyCallbackForType(): T {
val cbs = getTelephonyCallbacks().filterIsInstance<T>()
assertThat(cbs.size).isEqualTo(1)
return cbs[0]
return MobileTelephonyHelpers.getTelephonyCallbackForType(telephonyManager)
}
/** Convenience constructor for SignalStrength */

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2023 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.repository.prod
import android.telephony.TelephonyCallback
import android.telephony.TelephonyManager
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.google.common.truth.Truth.assertThat
import org.mockito.Mockito.verify
/** Helper methods for telephony-related callbacks for mobile tests. */
object MobileTelephonyHelpers {
fun getTelephonyCallbacks(mockTelephonyManager: TelephonyManager): List<TelephonyCallback> {
val callbackCaptor = argumentCaptor<TelephonyCallback>()
verify(mockTelephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture())
return callbackCaptor.allValues
}
inline fun <reified T> getTelephonyCallbackForType(mockTelephonyManager: TelephonyManager): T {
val cbs = getTelephonyCallbacks(mockTelephonyManager).filterIsInstance<T>()
assertThat(cbs.size).isEqualTo(1)
return cbs[0]
}
}