1 /*
<lambda>null2 * Copyright (C) 2023 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.server
18
19 import android.net.ConnectivityManager
20 import android.net.ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE
21 import android.net.ConnectivityManager.EXTRA_DEVICE_TYPE
22 import android.net.ConnectivityManager.EXTRA_IS_ACTIVE
23 import android.net.ConnectivityManager.EXTRA_REALTIME_NS
24 import android.net.ConnectivitySettingsManager
25 import android.net.LinkProperties
26 import android.net.NetworkCapabilities
27 import android.net.NetworkCapabilities.NET_CAPABILITY_IMS
28 import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
29 import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED
30 import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED
31 import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
32 import android.net.NetworkCapabilities.TRANSPORT_WIFI
33 import android.net.NetworkRequest
34 import android.os.Build
35 import android.os.ConditionVariable
36 import android.telephony.DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
37 import android.telephony.DataConnectionRealTimeInfo.DC_POWER_STATE_LOW
38 import androidx.test.filters.SmallTest
39 import com.android.net.module.util.BaseNetdUnsolicitedEventListener
40 import com.android.server.CSTest.CSContext
41 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
42 import com.android.testutils.DevSdkIgnoreRunner
43 import com.android.testutils.RecorderCallback.CallbackEntry.Lost
44 import com.android.testutils.TestableNetworkCallback
45 import java.time.Duration
46 import kotlin.test.assertNotNull
47 import org.junit.Assert.assertFalse
48 import org.junit.Assert.assertTrue
49 import org.junit.Test
50 import org.junit.runner.RunWith
51 import org.mockito.ArgumentCaptor
52 import org.mockito.ArgumentMatchers.anyString
53 import org.mockito.ArgumentMatchers.eq
54 import org.mockito.Mockito.anyInt
55 import org.mockito.Mockito.anyLong
56 import org.mockito.Mockito.inOrder
57 import org.mockito.Mockito.never
58 import org.mockito.Mockito.timeout
59 import org.mockito.Mockito.verify
60
61 private const val DATA_CELL_IFNAME = "rmnet_data"
62 private const val IMS_CELL_IFNAME = "rmnet_ims"
63 private const val WIFI_IFNAME = "wlan0"
64 private const val TIMESTAMP = 1234L
65 private const val NETWORK_ACTIVITY_NO_UID = -1
66 private const val PACKAGE_UID = 123
67 private const val TIMEOUT_MS = 250L
68
69 @DevSdkIgnoreRunner.MonitorThreadLeak
70 @RunWith(DevSdkIgnoreRunner::class)
71 @SmallTest
72 @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
73 class CSNetworkActivityTest : CSTest() {
74
75 private fun setMobileDataActivityTimeout(timeoutSeconds: Int) {
76 ConnectivitySettingsManager.setMobileDataActivityTimeout(
77 context, Duration.ofSeconds(timeoutSeconds.toLong())
78 )
79 }
80
81 private fun setWifiDataActivityTimeout(timeoutSeconds: Int) {
82 ConnectivitySettingsManager.setWifiDataActivityTimeout(
83 context, Duration.ofSeconds(timeoutSeconds.toLong())
84 )
85 }
86
87 private fun getRegisteredNetdUnsolicitedEventListener(): BaseNetdUnsolicitedEventListener {
88 val captor = ArgumentCaptor.forClass(BaseNetdUnsolicitedEventListener::class.java)
89 verify(netd).registerUnsolicitedEventListener(captor.capture())
90 return captor.value
91 }
92
93 @Test
94 fun testInterfaceClassActivityChanged_NonDefaultNetwork() {
95 val netdUnsolicitedEventListener = getRegisteredNetdUnsolicitedEventListener()
96 val batteryStatsInorder = inOrder(batteryStats)
97
98 val cellNr = NetworkRequest.Builder()
99 .clearCapabilities()
100 .addTransportType(TRANSPORT_CELLULAR)
101 .addCapability(NET_CAPABILITY_INTERNET)
102 .build()
103 val cellCb = TestableNetworkCallback()
104 // Request cell network to keep cell network up
105 cm.requestNetwork(cellNr, cellCb)
106
107 val defaultCb = TestableNetworkCallback()
108 cm.registerDefaultNetworkCallback(defaultCb)
109
110 val cellNc = NetworkCapabilities.Builder()
111 .addTransportType(TRANSPORT_CELLULAR)
112 .addCapability(NET_CAPABILITY_INTERNET)
113 .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
114 .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
115 .build()
116 val cellLp = LinkProperties().apply {
117 interfaceName = DATA_CELL_IFNAME
118 }
119 // Connect Cellular network
120 val cellAgent = Agent(nc = cellNc, lp = cellLp)
121 cellAgent.connect()
122 defaultCb.expectAvailableCallbacks(cellAgent.network, validated = false)
123
124 val wifiNc = NetworkCapabilities.Builder()
125 .addTransportType(TRANSPORT_WIFI)
126 .addCapability(NET_CAPABILITY_INTERNET)
127 .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
128 .build()
129 val wifiLp = LinkProperties().apply {
130 interfaceName = WIFI_IFNAME
131 }
132 // Connect Wi-Fi network, Wi-Fi network should be the default network.
133 val wifiAgent = Agent(nc = wifiNc, lp = wifiLp)
134 wifiAgent.connect()
135 defaultCb.expectAvailableCallbacks(wifiAgent.network, validated = false)
136 batteryStatsInorder.verify(batteryStats).noteWifiRadioPowerState(eq(DC_POWER_STATE_HIGH),
137 anyLong() /* timestampNs */, eq(NETWORK_ACTIVITY_NO_UID))
138
139 val onNetworkActiveCv = ConditionVariable()
140 val listener = ConnectivityManager.OnNetworkActiveListener { onNetworkActiveCv::open }
141 cm.addDefaultNetworkActiveListener(listener)
142
143 // Cellular network (non default network) goes to inactive state.
144 netdUnsolicitedEventListener.onInterfaceClassActivityChanged(false /* isActive */,
145 cellAgent.network.netId, TIMESTAMP, NETWORK_ACTIVITY_NO_UID)
146 // Non-default network activity change does not change default network activity
147 // But cellular radio power state is updated
148 assertFalse(onNetworkActiveCv.block(TIMEOUT_MS))
149 context.expectNoDataActivityBroadcast(0 /* timeoutMs */)
150 assertTrue(cm.isDefaultNetworkActive)
151 batteryStatsInorder.verify(batteryStats).noteMobileRadioPowerState(eq(DC_POWER_STATE_LOW),
152 anyLong() /* timestampNs */, eq(NETWORK_ACTIVITY_NO_UID))
153
154 // Cellular network (non default network) goes to active state.
155 netdUnsolicitedEventListener.onInterfaceClassActivityChanged(true /* isActive */,
156 cellAgent.network.netId, TIMESTAMP, PACKAGE_UID)
157 // Non-default network activity change does not change default network activity
158 // But cellular radio power state is updated
159 assertFalse(onNetworkActiveCv.block(TIMEOUT_MS))
160 context.expectNoDataActivityBroadcast(0 /* timeoutMs */)
161 assertTrue(cm.isDefaultNetworkActive)
162 batteryStatsInorder.verify(batteryStats).noteMobileRadioPowerState(eq(DC_POWER_STATE_HIGH),
163 anyLong() /* timestampNs */, eq(PACKAGE_UID))
164
165 cm.unregisterNetworkCallback(cellCb)
166 cm.unregisterNetworkCallback(defaultCb)
167 cm.removeDefaultNetworkActiveListener(listener)
168 }
169
170 @Test
171 fun testDataActivityTracking_MultiCellNetwork() {
172 val netdUnsolicitedEventListener = getRegisteredNetdUnsolicitedEventListener()
173 val batteryStatsInorder = inOrder(batteryStats)
174
175 val dataNetworkNc = NetworkCapabilities.Builder()
176 .addTransportType(TRANSPORT_CELLULAR)
177 .addCapability(NET_CAPABILITY_INTERNET)
178 .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
179 .build()
180 val dataNetworkNr = NetworkRequest.Builder()
181 .clearCapabilities()
182 .addTransportType(TRANSPORT_CELLULAR)
183 .addCapability(NET_CAPABILITY_INTERNET)
184 .build()
185 val dataNetworkLp = LinkProperties().apply {
186 interfaceName = DATA_CELL_IFNAME
187 }
188 val dataNetworkCb = TestableNetworkCallback()
189 cm.requestNetwork(dataNetworkNr, dataNetworkCb)
190 val dataNetworkAgent = Agent(nc = dataNetworkNc, lp = dataNetworkLp)
191 val dataNetworkNetId = dataNetworkAgent.network.netId.toString()
192
193 val imsNetworkNc = NetworkCapabilities.Builder()
194 .addTransportType(TRANSPORT_CELLULAR)
195 .addCapability(NET_CAPABILITY_IMS)
196 .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
197 .build()
198 val imsNetworkNr = NetworkRequest.Builder()
199 .clearCapabilities()
200 .addTransportType(TRANSPORT_CELLULAR)
201 .addCapability(NET_CAPABILITY_IMS)
202 .build()
203 val imsNetworkLp = LinkProperties().apply {
204 interfaceName = IMS_CELL_IFNAME
205 }
206 val imsNetworkCb = TestableNetworkCallback()
207 cm.requestNetwork(imsNetworkNr, imsNetworkCb)
208 val imsNetworkAgent = Agent(nc = imsNetworkNc, lp = imsNetworkLp)
209 val imsNetworkNetId = imsNetworkAgent.network.netId.toString()
210
211 dataNetworkAgent.connect()
212 dataNetworkCb.expectAvailableCallbacks(dataNetworkAgent.network, validated = false)
213
214 imsNetworkAgent.connect()
215 imsNetworkCb.expectAvailableCallbacks(imsNetworkAgent.network, validated = false)
216
217 // Both cell networks have idleTimers
218 verify(netd).idletimerAddInterface(eq(DATA_CELL_IFNAME), anyInt(), eq(dataNetworkNetId))
219 verify(netd).idletimerAddInterface(eq(IMS_CELL_IFNAME), anyInt(), eq(imsNetworkNetId))
220 verify(netd, never()).idletimerRemoveInterface(eq(DATA_CELL_IFNAME), anyInt(),
221 eq(dataNetworkNetId))
222 verify(netd, never()).idletimerRemoveInterface(eq(IMS_CELL_IFNAME), anyInt(),
223 eq(imsNetworkNetId))
224
225 // Both cell networks go to inactive state
226 netdUnsolicitedEventListener.onInterfaceClassActivityChanged(false /* isActive */,
227 imsNetworkAgent.network.netId, TIMESTAMP, NETWORK_ACTIVITY_NO_UID)
228 netdUnsolicitedEventListener.onInterfaceClassActivityChanged(false /* isActive */,
229 dataNetworkAgent.network.netId, TIMESTAMP, NETWORK_ACTIVITY_NO_UID)
230
231 // Data cell network goes to active state. This should update the cellular radio power state
232 netdUnsolicitedEventListener.onInterfaceClassActivityChanged(true /* isActive */,
233 dataNetworkAgent.network.netId, TIMESTAMP, PACKAGE_UID)
234 batteryStatsInorder.verify(batteryStats, timeout(TIMEOUT_MS)).noteMobileRadioPowerState(
235 eq(DC_POWER_STATE_HIGH), anyLong() /* timestampNs */, eq(PACKAGE_UID))
236 // Ims cell network goes to active state. But this should not update the cellular radio
237 // power state since cellular radio power state is already high
238 netdUnsolicitedEventListener.onInterfaceClassActivityChanged(true /* isActive */,
239 imsNetworkAgent.network.netId, TIMESTAMP, PACKAGE_UID)
240 waitForIdle()
241 batteryStatsInorder.verify(batteryStats, never()).noteMobileRadioPowerState(anyInt(),
242 anyLong() /* timestampNs */, anyInt())
243
244 // Data cell network goes to inactive state. But this should not update the cellular radio
245 // power state ims cell network is still active state
246 netdUnsolicitedEventListener.onInterfaceClassActivityChanged(false /* isActive */,
247 dataNetworkAgent.network.netId, TIMESTAMP, NETWORK_ACTIVITY_NO_UID)
248 waitForIdle()
249 batteryStatsInorder.verify(batteryStats, never()).noteMobileRadioPowerState(anyInt(),
250 anyLong() /* timestampNs */, anyInt())
251
252 // Ims cell network goes to inactive state.
253 // This should update the cellular radio power state
254 netdUnsolicitedEventListener.onInterfaceClassActivityChanged(false /* isActive */,
255 imsNetworkAgent.network.netId, TIMESTAMP, NETWORK_ACTIVITY_NO_UID)
256 batteryStatsInorder.verify(batteryStats, timeout(TIMEOUT_MS)).noteMobileRadioPowerState(
257 eq(DC_POWER_STATE_LOW), anyLong() /* timestampNs */, eq(NETWORK_ACTIVITY_NO_UID))
258
259 dataNetworkAgent.disconnect()
260 dataNetworkCb.expect<Lost>(dataNetworkAgent.network)
261 verify(netd).idletimerRemoveInterface(eq(DATA_CELL_IFNAME), anyInt(), eq(dataNetworkNetId))
262
263 imsNetworkAgent.disconnect()
264 imsNetworkCb.expect<Lost>(imsNetworkAgent.network)
265 verify(netd).idletimerRemoveInterface(eq(IMS_CELL_IFNAME), anyInt(), eq(imsNetworkNetId))
266
267 cm.unregisterNetworkCallback(dataNetworkCb)
268 cm.unregisterNetworkCallback(imsNetworkCb)
269 }
270
271 @Test
272 fun testCellularIdleTimerSettingsTimeout() {
273 val cellNc = NetworkCapabilities.Builder()
274 .addTransportType(TRANSPORT_CELLULAR)
275 .addCapability(NET_CAPABILITY_INTERNET)
276 .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
277 .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
278 .build()
279 val cellLp = LinkProperties().apply {
280 interfaceName = DATA_CELL_IFNAME
281 }
282
283 val settingsTimeout: Int = deps.defaultCellDataInactivityTimeoutForTest + 432
284 // DATA_ACTIVITY_TIMEOUT_MOBILE is set, so the default should be ignored.
285 setMobileDataActivityTimeout(settingsTimeout)
286 val cellAgent = Agent(nc = cellNc, lp = cellLp)
287 cellAgent.connect()
288
289 verify(netd).idletimerAddInterface(eq(DATA_CELL_IFNAME), eq(settingsTimeout), anyString())
290 }
291
292 @Test
293 fun testCellularIdleTimerDefaultTimeout() {
294 val cellNc = NetworkCapabilities.Builder()
295 .addTransportType(TRANSPORT_CELLULAR)
296 .addCapability(NET_CAPABILITY_INTERNET)
297 .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
298 .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
299 .build()
300 val cellLp = LinkProperties().apply {
301 interfaceName = DATA_CELL_IFNAME
302 }
303
304 val testTimeout: Int = deps.defaultCellDataInactivityTimeoutForTest
305 // DATA_ACTIVITY_TIMEOUT_MOBILE is not set, so the default should be used.
306 val cellAgent = Agent(nc = cellNc, lp = cellLp)
307 cellAgent.connect()
308
309 verify(netd).idletimerAddInterface(eq(DATA_CELL_IFNAME), eq(testTimeout), anyString())
310 }
311
312 @Test
313 fun testCellularIdleTimerDisabled() {
314 val cellNc = NetworkCapabilities.Builder()
315 .addTransportType(TRANSPORT_CELLULAR)
316 .addCapability(NET_CAPABILITY_INTERNET)
317 .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
318 .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
319 .build()
320 val cellLp = LinkProperties().apply {
321 interfaceName = DATA_CELL_IFNAME
322 }
323 setMobileDataActivityTimeout(0)
324 val cellAgent = Agent(nc = cellNc, lp = cellLp)
325 cellAgent.connect()
326
327 verify(netd, never()).idletimerAddInterface(eq(DATA_CELL_IFNAME), anyInt(), anyString())
328 }
329
330 @Test
331 fun testWifiIdleTimerSettingsTimeout() {
332 val wifiNc = NetworkCapabilities.Builder()
333 .addTransportType(TRANSPORT_WIFI)
334 .addCapability(NET_CAPABILITY_INTERNET)
335 .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
336 .build()
337 val wifiLp = LinkProperties().apply {
338 interfaceName = WIFI_IFNAME
339 }
340 val settingsTimeout: Int = deps.defaultWifiDataInactivityTimeout + 435
341 setWifiDataActivityTimeout(settingsTimeout)
342 // DATA_ACTIVITY_TIMEOUT_MOBILE is set, so the default should be ignored.
343 val wifiAgent = Agent(nc = wifiNc, lp = wifiLp)
344 wifiAgent.connect()
345
346 verify(netd).idletimerAddInterface(eq(WIFI_IFNAME), eq(settingsTimeout), anyString())
347 }
348
349 @Test
350 fun testWifiIdleTimerDefaultTimeout() {
351 val wifiNc = NetworkCapabilities.Builder()
352 .addTransportType(TRANSPORT_WIFI)
353 .addCapability(NET_CAPABILITY_INTERNET)
354 .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
355 .build()
356 val wifiLp = LinkProperties().apply {
357 interfaceName = WIFI_IFNAME
358 }
359 val testTimeout: Int = deps.defaultWifiDataInactivityTimeoutForTest
360 // DATA_ACTIVITY_TIMEOUT_WIFI is not set, so the default should be used.
361 val wifiAgent = Agent(nc = wifiNc, lp = wifiLp)
362 wifiAgent.connect()
363
364 verify(netd).idletimerAddInterface(eq(WIFI_IFNAME), eq(testTimeout), anyString())
365 }
366
367 @Test
368 fun testWifiIdleTimerDisabled() {
369 val wifiNc = NetworkCapabilities.Builder()
370 .addTransportType(TRANSPORT_WIFI)
371 .addCapability(NET_CAPABILITY_INTERNET)
372 .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
373 .build()
374 val wifiLp = LinkProperties().apply {
375 interfaceName = WIFI_IFNAME
376 }
377 setWifiDataActivityTimeout(0)
378 val wifiAgent = Agent(nc = wifiNc, lp = wifiLp)
379 wifiAgent.connect()
380
381 verify(netd, never()).idletimerAddInterface(eq(WIFI_IFNAME), anyInt(), anyString())
382 }
383 }
384
385
expectDataActivityBroadcastnull386 internal fun CSContext.expectDataActivityBroadcast(
387 deviceType: Int,
388 isActive: Boolean,
389 tsNanos: Long
390 ) {
391 assertNotNull(orderedBroadcastAsUserHistory.poll(BROADCAST_TIMEOUT_MS) {
392 intent -> intent.action.equals(ACTION_DATA_ACTIVITY_CHANGE) &&
393 intent.getIntExtra(EXTRA_DEVICE_TYPE, -1) == deviceType &&
394 intent.getBooleanExtra(EXTRA_IS_ACTIVE, !isActive) == isActive &&
395 intent.getLongExtra(EXTRA_REALTIME_NS, -1) == tsNanos
396 })
397 }
398