Improvements to CSTest : legacy type, wait for LOST, permissions

• Make sure all Agents have a legacy type. This is necessary to
  avoid crashes in LegacyNetworkTracker
• Wait for LOST when disconnecting a network
• Make sure the test package sees its own permissions (importantly
  it can't see background networks otherwise, because it lacks
  CHANGE_NETWORKING_STATE)

Test: in the followup
Change-Id: I9f699b6372a8fe0d5bcd5310d8f35f72e48a6c61
This commit is contained in:
Chalard Jean
2023-10-06 23:41:00 +09:00
parent f70919fbec
commit 026ca940d9
4 changed files with 54 additions and 7 deletions

View File

@@ -35,6 +35,7 @@ import android.net.networkstack.NetworkStackClientBase
import android.os.HandlerThread import android.os.HandlerThread
import com.android.modules.utils.build.SdkLevel import com.android.modules.utils.build.SdkLevel
import com.android.testutils.RecorderCallback.CallbackEntry.Available import com.android.testutils.RecorderCallback.CallbackEntry.Available
import com.android.testutils.RecorderCallback.CallbackEntry.Lost
import com.android.testutils.TestableNetworkCallback import com.android.testutils.TestableNetworkCallback
import org.mockito.ArgumentCaptor import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.any
@@ -47,6 +48,8 @@ import java.util.concurrent.atomic.AtomicInteger
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.fail import kotlin.test.fail
const val SHORT_TIMEOUT_MS = 200L
private inline fun <reified T> ArgumentCaptor() = ArgumentCaptor.forClass(T::class.java) private inline fun <reified T> ArgumentCaptor() = ArgumentCaptor.forClass(T::class.java)
private val agentCounter = AtomicInteger(1) private val agentCounter = AtomicInteger(1)
@@ -60,6 +63,7 @@ private fun nextAgentId() = agentCounter.getAndIncrement()
*/ */
class CSAgentWrapper( class CSAgentWrapper(
val context: Context, val context: Context,
val deps: ConnectivityService.Dependencies,
csHandlerThread: HandlerThread, csHandlerThread: HandlerThread,
networkStack: NetworkStackClientBase, networkStack: NetworkStackClientBase,
nac: NetworkAgentConfig, nac: NetworkAgentConfig,
@@ -149,6 +153,15 @@ class CSAgentWrapper(
} }
fun disconnect() { fun disconnect() {
val mgr = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val request = NetworkRequest.Builder().apply {
clearCapabilities()
if (nc.transportTypes.isNotEmpty()) addTransportType(nc.transportTypes[0])
}.build()
val cb = TestableNetworkCallback(timeoutMs = SHORT_TIMEOUT_MS)
mgr.registerNetworkCallback(request, cb)
cb.eventuallyExpect<Available> { it.network == agent.network }
agent.unregister() agent.unregister()
cb.eventuallyExpect<Lost> { it.network == agent.network }
} }
} }

View File

@@ -30,6 +30,12 @@ import android.net.LinkProperties
import android.net.NetworkAgentConfig import android.net.NetworkAgentConfig
import android.net.NetworkCapabilities import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED
import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
import android.net.NetworkCapabilities.TRANSPORT_TEST
import android.net.NetworkCapabilities.TRANSPORT_VPN
import android.net.NetworkCapabilities.TRANSPORT_WIFI
import android.net.NetworkPolicyManager import android.net.NetworkPolicyManager
import android.net.NetworkProvider import android.net.NetworkProvider
import android.net.NetworkScore import android.net.NetworkScore
@@ -79,6 +85,17 @@ internal const val VERSION_U = 4
internal const val VERSION_V = 5 internal const val VERSION_V = 5
internal const val VERSION_MAX = VERSION_V internal const val VERSION_MAX = VERSION_V
private fun NetworkCapabilities.getLegacyType() =
when (transportTypes.getOrElse(0) { TRANSPORT_WIFI }) {
TRANSPORT_BLUETOOTH -> ConnectivityManager.TYPE_BLUETOOTH
TRANSPORT_CELLULAR -> ConnectivityManager.TYPE_MOBILE
TRANSPORT_ETHERNET -> ConnectivityManager.TYPE_ETHERNET
TRANSPORT_TEST -> ConnectivityManager.TYPE_TEST
TRANSPORT_VPN -> ConnectivityManager.TYPE_VPN
TRANSPORT_WIFI -> ConnectivityManager.TYPE_WIFI
else -> ConnectivityManager.TYPE_NONE
}
/** /**
* Base class for tests testing ConnectivityService and its satellites. * Base class for tests testing ConnectivityService and its satellites.
* *
@@ -127,7 +144,7 @@ open class CSTest {
val networkStack = mock<NetworkStackClientBase>() val networkStack = mock<NetworkStackClientBase>()
val csHandlerThread = HandlerThread("CSTestHandler") val csHandlerThread = HandlerThread("CSTestHandler")
val sysResources = mock<Resources>().also { initMockedResources(it) } val sysResources = mock<Resources>().also { initMockedResources(it) }
val packageManager = makeMockPackageManager() val packageManager = makeMockPackageManager(instrumentationContext)
val connResources = makeMockConnResources(sysResources, packageManager) val connResources = makeMockConnResources(sysResources, packageManager)
val netd = mock<INetd>() val netd = mock<INetd>()
@@ -272,12 +289,12 @@ open class CSTest {
// Network agents. See CSAgentWrapper. This class contains utility methods to simplify // Network agents. See CSAgentWrapper. This class contains utility methods to simplify
// creation. // creation.
fun Agent( fun Agent(
nac: NetworkAgentConfig = emptyAgentConfig(),
nc: NetworkCapabilities = defaultNc(), nc: NetworkCapabilities = defaultNc(),
nac: NetworkAgentConfig = emptyAgentConfig(nc.getLegacyType()),
lp: LinkProperties = defaultLp(), lp: LinkProperties = defaultLp(),
score: FromS<NetworkScore> = defaultScore(), score: FromS<NetworkScore> = defaultScore(),
provider: NetworkProvider? = null provider: NetworkProvider? = null
) = CSAgentWrapper(context, csHandlerThread, networkStack, nac, nc, lp, score, provider) ) = CSAgentWrapper(context, deps, csHandlerThread, networkStack, nac, nc, lp, score, provider)
fun Agent(vararg transports: Int, lp: LinkProperties = defaultLp()): CSAgentWrapper { fun Agent(vararg transports: Int, lp: LinkProperties = defaultLp()): CSAgentWrapper {
val nc = NetworkCapabilities.Builder().apply { val nc = NetworkCapabilities.Builder().apply {

View File

@@ -38,6 +38,7 @@ import android.net.NetworkCapabilities
import android.net.NetworkScore import android.net.NetworkScore
import android.net.RouteInfo import android.net.RouteInfo
import android.net.metrics.IpConnectivityLog import android.net.metrics.IpConnectivityLog
import android.os.Binder
import android.os.Handler import android.os.Handler
import android.os.HandlerThread import android.os.HandlerThread
import android.os.SystemClock import android.os.SystemClock
@@ -54,20 +55,23 @@ import com.android.server.ConnectivityService.Dependencies
import com.android.server.connectivity.ConnectivityResources import com.android.server.connectivity.ConnectivityResources
import org.mockito.ArgumentMatchers import org.mockito.ArgumentMatchers
import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong import org.mockito.ArgumentMatchers.anyLong
import org.mockito.ArgumentMatchers.anyString import org.mockito.ArgumentMatchers.anyString
import org.mockito.ArgumentMatchers.argThat import org.mockito.ArgumentMatchers.argThat
import org.mockito.ArgumentMatchers.eq import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito import org.mockito.Mockito
import org.mockito.Mockito.doAnswer import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.doNothing import org.mockito.Mockito.doNothing
import org.mockito.Mockito.doReturn
import kotlin.test.fail import kotlin.test.fail
internal inline fun <reified T> mock() = Mockito.mock(T::class.java) internal inline fun <reified T> mock() = Mockito.mock(T::class.java)
internal inline fun <reified T> any() = any(T::class.java) internal inline fun <reified T> any() = any(T::class.java)
internal fun emptyAgentConfig() = NetworkAgentConfig.Builder().build() internal fun emptyAgentConfig(legacyType: Int) = NetworkAgentConfig.Builder()
.setLegacyType(legacyType)
.build()
internal fun defaultNc() = NetworkCapabilities.Builder() internal fun defaultNc() = NetworkCapabilities.Builder()
// Add sensible defaults for agents that don't want to care // Add sensible defaults for agents that don't want to care
@@ -98,9 +102,22 @@ internal fun makeActivityManager() = mock<ActivityManager>().also {
} }
} }
internal fun makeMockPackageManager() = mock<PackageManager>().also { pm -> internal fun makeMockPackageManager(realContext: Context) = mock<PackageManager>().also { pm ->
val supported = listOf(FEATURE_WIFI, FEATURE_WIFI_DIRECT, FEATURE_BLUETOOTH, FEATURE_ETHERNET) val supported = listOf(FEATURE_WIFI, FEATURE_WIFI_DIRECT, FEATURE_BLUETOOTH, FEATURE_ETHERNET)
doReturn(true).`when`(pm).hasSystemFeature(argThat { supported.contains(it) }) doReturn(true).`when`(pm).hasSystemFeature(argThat { supported.contains(it) })
val myPackageName = realContext.packageName
val myPackageInfo = realContext.packageManager.getPackageInfo(myPackageName,
PackageManager.GET_PERMISSIONS)
// Very high version code so that the checks for the module version will always
// say that it is recent enough. This is the most sensible default, but if some
// test needs to test with different version codes they can re-mock this with a
// different value.
myPackageInfo.longVersionCode = 9999999L
doReturn(arrayOf(myPackageName)).`when`(pm).getPackagesForUid(Binder.getCallingUid())
doReturn(myPackageInfo).`when`(pm).getPackageInfoAsUser(
eq(myPackageName), anyInt(), eq(UserHandle.getCallingUserId()))
doReturn(listOf(myPackageInfo)).`when`(pm)
.getInstalledPackagesAsUser(eq(PackageManager.GET_PERMISSIONS), anyInt())
} }
internal fun makeMockConnResources(resources: Resources, pm: PackageManager) = mock<Context>().let { internal fun makeMockConnResources(resources: Resources, pm: PackageManager) = mock<Context>().let {