• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.testutils
18 
19 import android.content.Context
20 import android.net.ConnectivityManager
21 import android.net.ConnectivityManager.FEATURE_QUEUE_NETWORK_AGENT_EVENTS_IN_SYSTEM_SERVER
22 import android.net.InetAddresses.parseNumericAddress
23 import android.net.KeepalivePacketData
24 import android.net.LinkAddress
25 import android.net.LinkProperties
26 import android.net.NetworkAgent
27 import android.net.NetworkAgentConfig
28 import android.net.NetworkCapabilities
29 import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED
30 import android.net.NetworkCapabilities.TRANSPORT_TEST
31 import android.net.NetworkProvider
32 import android.net.NetworkRequest
33 import android.net.NetworkScore
34 import android.net.QosFilter
35 import android.net.Uri
36 import android.os.Looper
37 import android.system.ErrnoException
38 import android.system.Os
39 import android.system.OsConstants
40 import android.system.OsConstants.EADDRNOTAVAIL
41 import android.system.OsConstants.ENETUNREACH
42 import android.system.OsConstants.ENONET
43 import android.system.OsConstants.IPPROTO_UDP
44 import android.system.OsConstants.SOCK_DGRAM
45 import com.android.modules.utils.build.SdkLevel.isAtLeastS
46 import com.android.net.module.util.ArrayTrackRecord
47 import com.android.testutils.CompatUtil.makeTestNetworkSpecifier
48 import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnAddKeepalivePacketFilter
49 import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnAutomaticReconnectDisabled
50 import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnBandwidthUpdateRequested
51 import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnDscpPolicyStatusUpdated
52 import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnNetworkCreated
53 import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnNetworkDestroyed
54 import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnNetworkUnwanted
55 import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnRegisterQosCallback
56 import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnRemoveKeepalivePacketFilter
57 import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnSaveAcceptUnvalidated
58 import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnSignalStrengthThresholdsUpdated
59 import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnStartSocketKeepalive
60 import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnStopSocketKeepalive
61 import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnUnregisterQosCallback
62 import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnValidationStatus
63 import java.net.NetworkInterface
64 import java.net.SocketException
65 import java.time.Duration
66 import kotlin.test.assertEquals
67 import kotlin.test.assertNotNull
68 import kotlin.test.assertNull
69 import kotlin.test.assertTrue
70 import kotlin.test.fail
71 import org.junit.Assert.assertArrayEquals
72 
73 // Any legal score (0~99) for the test network would do, as it is going to be kept up by the
74 // requests filed by the test and should never match normal internet requests. 70 is the default
75 // score of Ethernet networks, it's as good a value as any other.
76 // Note that this can't use NetworkScore.Builder() because this test must be able to
77 // run on R, which doesn't know this class.
78 private const val TEST_NETWORK_SCORE = 70
79 
80 private class Provider(context: Context, looper: Looper) :
81             NetworkProvider(context, looper, "NetworkAgentTest NetworkProvider")
82 
83 private val enabledFeatures = mutableMapOf<Long, Boolean>()
84 
85 public open class TestableNetworkAgent(
86     context: Context,
87     looper: Looper,
88     val nc: NetworkCapabilities,
89     val lp: LinkProperties,
90     conf: NetworkAgentConfig
91 ) : NetworkAgent(context, looper, TestableNetworkAgent::class.java.simpleName /* tag */,
92     nc, lp, TEST_NETWORK_SCORE, conf, Provider(context, looper)) {
93 
isFeatureEnablednull94     override fun isFeatureEnabled(context: Context, feature: Long): Boolean {
95         when (val it = enabledFeatures.get(feature)) {
96             null -> {
97                 val cm = context.getSystemService(ConnectivityManager::class.java)
98                 val res = cm.isFeatureEnabled(feature)
99                 enabledFeatures[feature] = res
100                 return res
101             }
102             else -> return it
103         }
104     }
105 
106     companion object {
setFeatureEnablednull107         fun setFeatureEnabled(flag: Long, enabled: Boolean) = enabledFeatures.set(flag, enabled)
108 
109         /**
110          * Convenience method to create a [NetworkRequest] matching [TestableNetworkAgent]s from
111          * [createOnInterface].
112          */
113         fun makeNetworkRequestForInterface(ifaceName: String) = NetworkRequest.Builder()
114             .removeCapability(NET_CAPABILITY_TRUSTED)
115             .addTransportType(TRANSPORT_TEST)
116             .setNetworkSpecifier(makeTestNetworkSpecifier(ifaceName))
117             .build()
118 
119         /**
120          * Convenience method to initialize a [TestableNetworkAgent] on a given interface.
121          *
122          * This waits for link-local addresses to be setup and ensures LinkProperties are updated
123          * with the addresses.
124          */
125         fun createOnInterface(
126             context: Context,
127             looper: Looper,
128             ifaceName: String,
129             timeoutMs: Long
130         ): TestableNetworkAgent {
131             val lp = LinkProperties().apply {
132                 interfaceName = ifaceName
133             }
134             val agent = TestableNetworkAgent(
135                 context,
136                 looper,
137                 NetworkCapabilities().apply {
138                     removeCapability(NET_CAPABILITY_TRUSTED)
139                     addTransportType(TRANSPORT_TEST)
140                     setNetworkSpecifier(makeTestNetworkSpecifier(ifaceName))
141                 },
142                 lp,
143                 NetworkAgentConfig.Builder().build()
144             )
145             val network = agent.register()
146             agent.markConnected()
147             if (isAtLeastS()) {
148                 // OnNetworkCreated was added in S
149                 agent.eventuallyExpect<OnNetworkCreated>()
150             }
151 
152             // Wait until the link-local address can be used. Address flags are not available
153             // without elevated permissions, so check that bindSocket works.
154             assertEventuallyTrue("No usable v6 address after $timeoutMs ms", timeoutMs) {
155                 // To avoid race condition between socket connection succeeding and interface
156                 // returning a non-empty address list. Verify that interface returns a non-empty
157                 // list, before trying the socket connection.
158                 if (NetworkInterface.getByName(ifaceName).interfaceAddresses.isEmpty()) {
159                     return@assertEventuallyTrue false
160                 }
161 
162                 val sock = Os.socket(OsConstants.AF_INET6, SOCK_DGRAM, IPPROTO_UDP)
163                 tryTest {
164                     network.bindSocket(sock)
165                     Os.connect(sock, parseNumericAddress("ff02::fb%$ifaceName"), 12345)
166                     true
167                 }.catch<ErrnoException> {
168                     if (it.errno != ENETUNREACH && it.errno != EADDRNOTAVAIL) {
169                         throw it
170                     }
171                     false
172                 }.catch<SocketException> {
173                     // OnNetworkCreated does not exist on R, so a SocketException caused by ENONET
174                     // may be seen before the network is created
175                     if (isAtLeastS()) throw it
176                     val cause = it.cause as? ErrnoException ?: throw it
177                     if (cause.errno != ENONET) {
178                         throw it
179                     }
180                     false
181                 } cleanup {
182                     Os.close(sock)
183                 }
184             }
185 
186             agent.lp.setLinkAddresses(NetworkInterface.getByName(ifaceName).interfaceAddresses.map {
187                 LinkAddress(it.address, it.networkPrefixLength.toInt())
188             })
189             agent.sendLinkProperties(agent.lp)
190             return agent
191         }
192     }
193 
194     val DEFAULT_TIMEOUT_MS = 5000L
195 
196     val history = ArrayTrackRecord<CallbackEntry>().newReadHead()
197 
198     sealed class CallbackEntry {
199         object OnBandwidthUpdateRequested : CallbackEntry()
200         object OnNetworkUnwanted : CallbackEntry()
201         data class OnAddKeepalivePacketFilter(
202             val slot: Int,
203             val packet: KeepalivePacketData
204         ) : CallbackEntry()
205         data class OnRemoveKeepalivePacketFilter(val slot: Int) : CallbackEntry()
206         data class OnStartSocketKeepalive(
207             val slot: Int,
208             val interval: Int,
209             val packet: KeepalivePacketData
210         ) : CallbackEntry()
211         data class OnStopSocketKeepalive(val slot: Int) : CallbackEntry()
212         data class OnSaveAcceptUnvalidated(val accept: Boolean) : CallbackEntry()
213         object OnAutomaticReconnectDisabled : CallbackEntry()
214         data class OnValidationStatus(val status: Int, val uri: Uri?) : CallbackEntry()
215         data class OnSignalStrengthThresholdsUpdated(val thresholds: IntArray) : CallbackEntry()
216         object OnNetworkCreated : CallbackEntry()
217         object OnNetworkDestroyed : CallbackEntry()
218         data class OnDscpPolicyStatusUpdated(val policyId: Int, val status: Int) : CallbackEntry()
219         data class OnRegisterQosCallback(
220             val callbackId: Int,
221             val filter: QosFilter
222         ) : CallbackEntry()
223         data class OnUnregisterQosCallback(val callbackId: Int) : CallbackEntry()
224     }
225 
onBandwidthUpdateRequestednull226     override fun onBandwidthUpdateRequested() {
227         history.add(OnBandwidthUpdateRequested)
228     }
229 
onNetworkUnwantednull230     override fun onNetworkUnwanted() {
231         history.add(OnNetworkUnwanted)
232     }
233 
onAddKeepalivePacketFilternull234     override fun onAddKeepalivePacketFilter(slot: Int, packet: KeepalivePacketData) {
235         history.add(OnAddKeepalivePacketFilter(slot, packet))
236     }
237 
onRemoveKeepalivePacketFilternull238     override fun onRemoveKeepalivePacketFilter(slot: Int) {
239         history.add(OnRemoveKeepalivePacketFilter(slot))
240     }
241 
onStartSocketKeepalivenull242     override fun onStartSocketKeepalive(
243         slot: Int,
244         interval: Duration,
245         packet: KeepalivePacketData
246     ) {
247         history.add(OnStartSocketKeepalive(slot, interval.seconds.toInt(), packet))
248     }
249 
onStopSocketKeepalivenull250     override fun onStopSocketKeepalive(slot: Int) {
251         history.add(OnStopSocketKeepalive(slot))
252     }
253 
onSaveAcceptUnvalidatednull254     override fun onSaveAcceptUnvalidated(accept: Boolean) {
255         history.add(OnSaveAcceptUnvalidated(accept))
256     }
257 
onAutomaticReconnectDisablednull258     override fun onAutomaticReconnectDisabled() {
259         history.add(OnAutomaticReconnectDisabled)
260     }
261 
onSignalStrengthThresholdsUpdatednull262     override fun onSignalStrengthThresholdsUpdated(thresholds: IntArray) {
263         history.add(OnSignalStrengthThresholdsUpdated(thresholds))
264     }
265 
expectSignalStrengthsnull266     fun expectSignalStrengths(thresholds: IntArray? = intArrayOf()) {
267         expectCallback<OnSignalStrengthThresholdsUpdated>().let {
268             assertArrayEquals(thresholds, it.thresholds)
269         }
270     }
271 
onQosCallbackRegisterednull272     override fun onQosCallbackRegistered(qosCallbackId: Int, filter: QosFilter) {
273         history.add(OnRegisterQosCallback(qosCallbackId, filter))
274     }
275 
onQosCallbackUnregisterednull276     override fun onQosCallbackUnregistered(qosCallbackId: Int) {
277         history.add(OnUnregisterQosCallback(qosCallbackId))
278     }
279 
onValidationStatusnull280     override fun onValidationStatus(status: Int, uri: Uri?) {
281         history.add(OnValidationStatus(status, uri))
282     }
283 
onNetworkCreatednull284     override fun onNetworkCreated() {
285         history.add(OnNetworkCreated)
286     }
287 
onNetworkDestroyednull288     override fun onNetworkDestroyed() {
289         history.add(OnNetworkDestroyed)
290     }
291 
onDscpPolicyStatusUpdatednull292     override fun onDscpPolicyStatusUpdated(policyId: Int, status: Int) {
293         history.add(OnDscpPolicyStatusUpdated(policyId, status))
294     }
295 
296     // Expects the initial validation event that always occurs immediately after registering
297     // a NetworkAgent whose network does not require validation (which test networks do
298     // not, since they lack the INTERNET capability). It always contains the default argument
299     // for the URI.
<lambda>null300     fun expectValidationBypassedStatus() = expectCallback<OnValidationStatus>().let {
301         assertEquals(it.status, VALID_NETWORK)
302         // The returned Uri is parsed from the empty string, which means it's an
303         // instance of the (private) Uri.StringUri. There are no real good ways
304         // to check this, the least bad is to just convert it to a string and
305         // make sure it's empty.
306         assertEquals("", it.uri.toString())
307     }
308 
expectCallbacknull309     inline fun <reified T : CallbackEntry> expectCallback(): T {
310         val foundCallback = history.poll(DEFAULT_TIMEOUT_MS)
311         assertTrue(foundCallback is T, "Expected ${T::class} but found $foundCallback")
312         return foundCallback
313     }
314 
expectCallbacknull315     inline fun <reified T : CallbackEntry> expectCallback(valid: (T) -> Boolean) {
316         val foundCallback = history.poll(DEFAULT_TIMEOUT_MS)
317         assertTrue(foundCallback is T, "Expected ${T::class} but found $foundCallback")
318         assertTrue(valid(foundCallback), "Unexpected callback : $foundCallback")
319     }
320 
eventuallyExpectnull321     inline fun <reified T : CallbackEntry> eventuallyExpect() =
322             history.poll(DEFAULT_TIMEOUT_MS) { it is T }.also {
323                 assertNotNull(it, "Callback ${T::class} not received")
324     } as T
325 
assertNoCallbacknull326     fun assertNoCallback() {
327         assertTrue(waitForIdle(DEFAULT_TIMEOUT_MS),
328                 "Handler didn't became idle after ${DEFAULT_TIMEOUT_MS}ms")
329         assertNull(history.peek())
330     }
331 }
332