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.LinkProperties
25 import android.net.NetworkCapabilities
26 import android.net.NetworkCapabilities.NET_CAPABILITY_IMS
27 import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
28 import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED
29 import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED
30 import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
31 import android.net.NetworkCapabilities.TRANSPORT_WIFI
32 import android.net.NetworkRequest
33 import android.os.Build
34 import android.os.ConditionVariable
35 import android.telephony.DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
36 import android.telephony.DataConnectionRealTimeInfo.DC_POWER_STATE_LOW
37 import androidx.test.filters.SmallTest
38 import com.android.net.module.util.BaseNetdUnsolicitedEventListener
39 import com.android.server.CSTest.CSContext
40 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
41 import com.android.testutils.DevSdkIgnoreRunner
42 import com.android.testutils.RecorderCallback.CallbackEntry.Lost
43 import com.android.testutils.TestableNetworkCallback
44 import kotlin.test.assertNotNull
45 import org.junit.Assert.assertFalse
46 import org.junit.Assert.assertTrue
47 import org.junit.Test
48 import org.junit.runner.RunWith
49 import org.mockito.ArgumentCaptor
50 import org.mockito.ArgumentMatchers.eq
51 import org.mockito.Mockito.anyInt
52 import org.mockito.Mockito.anyLong
53 import org.mockito.Mockito.inOrder
54 import org.mockito.Mockito.never
55 import org.mockito.Mockito.timeout
56 import org.mockito.Mockito.verify
57
58 private const val DATA_CELL_IFNAME = "rmnet_data"
59 private const val IMS_CELL_IFNAME = "rmnet_ims"
60 private const val WIFI_IFNAME = "wlan0"
61 private const val TIMESTAMP = 1234L
62 private const val NETWORK_ACTIVITY_NO_UID = -1
63 private const val PACKAGE_UID = 123
64 private const val TIMEOUT_MS = 250L
65
66 @DevSdkIgnoreRunner.MonitorThreadLeak
67 @RunWith(DevSdkIgnoreRunner::class)
68 @SmallTest
69 @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
70 class CSNetworkActivityTest : CSTest() {
71
72 private fun getRegisteredNetdUnsolicitedEventListener(): BaseNetdUnsolicitedEventListener {
73 val captor = ArgumentCaptor.forClass(BaseNetdUnsolicitedEventListener::class.java)
74 verify(netd).registerUnsolicitedEventListener(captor.capture())
75 return captor.value
76 }
77
78 @Test
79 fun testInterfaceClassActivityChanged_NonDefaultNetwork() {
80 val netdUnsolicitedEventListener = getRegisteredNetdUnsolicitedEventListener()
81 val batteryStatsInorder = inOrder(batteryStats)
82
83 val cellNr = NetworkRequest.Builder()
84 .clearCapabilities()
85 .addTransportType(TRANSPORT_CELLULAR)
86 .addCapability(NET_CAPABILITY_INTERNET)
87 .build()
88 val cellCb = TestableNetworkCallback()
89 // Request cell network to keep cell network up
90 cm.requestNetwork(cellNr, cellCb)
91
92 val defaultCb = TestableNetworkCallback()
93 cm.registerDefaultNetworkCallback(defaultCb)
94
95 val cellNc = NetworkCapabilities.Builder()
96 .addTransportType(TRANSPORT_CELLULAR)
97 .addCapability(NET_CAPABILITY_INTERNET)
98 .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
99 .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
100 .build()
101 val cellLp = LinkProperties().apply {
102 interfaceName = DATA_CELL_IFNAME
103 }
104 // Connect Cellular network
105 val cellAgent = Agent(nc = cellNc, lp = cellLp)
106 cellAgent.connect()
107 defaultCb.expectAvailableCallbacks(cellAgent.network, validated = false)
108
109 val wifiNc = NetworkCapabilities.Builder()
110 .addTransportType(TRANSPORT_WIFI)
111 .addCapability(NET_CAPABILITY_INTERNET)
112 .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
113 .build()
114 val wifiLp = LinkProperties().apply {
115 interfaceName = WIFI_IFNAME
116 }
117 // Connect Wi-Fi network, Wi-Fi network should be the default network.
118 val wifiAgent = Agent(nc = wifiNc, lp = wifiLp)
119 wifiAgent.connect()
120 defaultCb.expectAvailableCallbacks(wifiAgent.network, validated = false)
121 batteryStatsInorder.verify(batteryStats).noteWifiRadioPowerState(eq(DC_POWER_STATE_HIGH),
122 anyLong() /* timestampNs */, eq(NETWORK_ACTIVITY_NO_UID))
123
124 val onNetworkActiveCv = ConditionVariable()
125 val listener = ConnectivityManager.OnNetworkActiveListener { onNetworkActiveCv::open }
126 cm.addDefaultNetworkActiveListener(listener)
127
128 // Cellular network (non default network) goes to inactive state.
129 netdUnsolicitedEventListener.onInterfaceClassActivityChanged(false /* isActive */,
130 cellAgent.network.netId, TIMESTAMP, NETWORK_ACTIVITY_NO_UID)
131 // Non-default network activity change does not change default network activity
132 // But cellular radio power state is updated
133 assertFalse(onNetworkActiveCv.block(TIMEOUT_MS))
134 context.expectNoDataActivityBroadcast(0 /* timeoutMs */)
135 assertTrue(cm.isDefaultNetworkActive)
136 batteryStatsInorder.verify(batteryStats).noteMobileRadioPowerState(eq(DC_POWER_STATE_LOW),
137 anyLong() /* timestampNs */, eq(NETWORK_ACTIVITY_NO_UID))
138
139 // Cellular network (non default network) goes to active state.
140 netdUnsolicitedEventListener.onInterfaceClassActivityChanged(true /* isActive */,
141 cellAgent.network.netId, TIMESTAMP, PACKAGE_UID)
142 // Non-default network activity change does not change default network activity
143 // But cellular radio power state is updated
144 assertFalse(onNetworkActiveCv.block(TIMEOUT_MS))
145 context.expectNoDataActivityBroadcast(0 /* timeoutMs */)
146 assertTrue(cm.isDefaultNetworkActive)
147 batteryStatsInorder.verify(batteryStats).noteMobileRadioPowerState(eq(DC_POWER_STATE_HIGH),
148 anyLong() /* timestampNs */, eq(PACKAGE_UID))
149
150 cm.unregisterNetworkCallback(cellCb)
151 cm.unregisterNetworkCallback(defaultCb)
152 cm.removeDefaultNetworkActiveListener(listener)
153 }
154
155 @Test
156 fun testDataActivityTracking_MultiCellNetwork() {
157 val netdUnsolicitedEventListener = getRegisteredNetdUnsolicitedEventListener()
158 val batteryStatsInorder = inOrder(batteryStats)
159
160 val dataNetworkNc = NetworkCapabilities.Builder()
161 .addTransportType(TRANSPORT_CELLULAR)
162 .addCapability(NET_CAPABILITY_INTERNET)
163 .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
164 .build()
165 val dataNetworkNr = NetworkRequest.Builder()
166 .clearCapabilities()
167 .addTransportType(TRANSPORT_CELLULAR)
168 .addCapability(NET_CAPABILITY_INTERNET)
169 .build()
170 val dataNetworkLp = LinkProperties().apply {
171 interfaceName = DATA_CELL_IFNAME
172 }
173 val dataNetworkCb = TestableNetworkCallback()
174 cm.requestNetwork(dataNetworkNr, dataNetworkCb)
175 val dataNetworkAgent = Agent(nc = dataNetworkNc, lp = dataNetworkLp)
176 val dataNetworkNetId = dataNetworkAgent.network.netId.toString()
177
178 val imsNetworkNc = NetworkCapabilities.Builder()
179 .addTransportType(TRANSPORT_CELLULAR)
180 .addCapability(NET_CAPABILITY_IMS)
181 .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
182 .build()
183 val imsNetworkNr = NetworkRequest.Builder()
184 .clearCapabilities()
185 .addTransportType(TRANSPORT_CELLULAR)
186 .addCapability(NET_CAPABILITY_IMS)
187 .build()
188 val imsNetworkLp = LinkProperties().apply {
189 interfaceName = IMS_CELL_IFNAME
190 }
191 val imsNetworkCb = TestableNetworkCallback()
192 cm.requestNetwork(imsNetworkNr, imsNetworkCb)
193 val imsNetworkAgent = Agent(nc = imsNetworkNc, lp = imsNetworkLp)
194 val imsNetworkNetId = imsNetworkAgent.network.netId.toString()
195
196 dataNetworkAgent.connect()
197 dataNetworkCb.expectAvailableCallbacks(dataNetworkAgent.network, validated = false)
198
199 imsNetworkAgent.connect()
200 imsNetworkCb.expectAvailableCallbacks(imsNetworkAgent.network, validated = false)
201
202 // Both cell networks have idleTimers
203 verify(netd).idletimerAddInterface(eq(DATA_CELL_IFNAME), anyInt(), eq(dataNetworkNetId))
204 verify(netd).idletimerAddInterface(eq(IMS_CELL_IFNAME), anyInt(), eq(imsNetworkNetId))
205 verify(netd, never()).idletimerRemoveInterface(eq(DATA_CELL_IFNAME), anyInt(),
206 eq(dataNetworkNetId))
207 verify(netd, never()).idletimerRemoveInterface(eq(IMS_CELL_IFNAME), anyInt(),
208 eq(imsNetworkNetId))
209
210 // Both cell networks go to inactive state
211 netdUnsolicitedEventListener.onInterfaceClassActivityChanged(false /* isActive */,
212 imsNetworkAgent.network.netId, TIMESTAMP, NETWORK_ACTIVITY_NO_UID)
213 netdUnsolicitedEventListener.onInterfaceClassActivityChanged(false /* isActive */,
214 dataNetworkAgent.network.netId, TIMESTAMP, NETWORK_ACTIVITY_NO_UID)
215
216 // Data cell network goes to active state. This should update the cellular radio power state
217 netdUnsolicitedEventListener.onInterfaceClassActivityChanged(true /* isActive */,
218 dataNetworkAgent.network.netId, TIMESTAMP, PACKAGE_UID)
219 batteryStatsInorder.verify(batteryStats, timeout(TIMEOUT_MS)).noteMobileRadioPowerState(
220 eq(DC_POWER_STATE_HIGH), anyLong() /* timestampNs */, eq(PACKAGE_UID))
221 // Ims cell network goes to active state. But this should not update the cellular radio
222 // power state since cellular radio power state is already high
223 netdUnsolicitedEventListener.onInterfaceClassActivityChanged(true /* isActive */,
224 imsNetworkAgent.network.netId, TIMESTAMP, PACKAGE_UID)
225 waitForIdle()
226 batteryStatsInorder.verify(batteryStats, never()).noteMobileRadioPowerState(anyInt(),
227 anyLong() /* timestampNs */, anyInt())
228
229 // Data cell network goes to inactive state. But this should not update the cellular radio
230 // power state ims cell network is still active state
231 netdUnsolicitedEventListener.onInterfaceClassActivityChanged(false /* isActive */,
232 dataNetworkAgent.network.netId, TIMESTAMP, NETWORK_ACTIVITY_NO_UID)
233 waitForIdle()
234 batteryStatsInorder.verify(batteryStats, never()).noteMobileRadioPowerState(anyInt(),
235 anyLong() /* timestampNs */, anyInt())
236
237 // Ims cell network goes to inactive state.
238 // This should update the cellular radio power state
239 netdUnsolicitedEventListener.onInterfaceClassActivityChanged(false /* isActive */,
240 imsNetworkAgent.network.netId, TIMESTAMP, NETWORK_ACTIVITY_NO_UID)
241 batteryStatsInorder.verify(batteryStats, timeout(TIMEOUT_MS)).noteMobileRadioPowerState(
242 eq(DC_POWER_STATE_LOW), anyLong() /* timestampNs */, eq(NETWORK_ACTIVITY_NO_UID))
243
244 dataNetworkAgent.disconnect()
245 dataNetworkCb.expect<Lost>(dataNetworkAgent.network)
246 verify(netd).idletimerRemoveInterface(eq(DATA_CELL_IFNAME), anyInt(), eq(dataNetworkNetId))
247
248 imsNetworkAgent.disconnect()
249 imsNetworkCb.expect<Lost>(imsNetworkAgent.network)
250 verify(netd).idletimerRemoveInterface(eq(IMS_CELL_IFNAME), anyInt(), eq(imsNetworkNetId))
251
252 cm.unregisterNetworkCallback(dataNetworkCb)
253 cm.unregisterNetworkCallback(imsNetworkCb)
254 }
255 }
256
expectDataActivityBroadcastnull257 internal fun CSContext.expectDataActivityBroadcast(
258 deviceType: Int,
259 isActive: Boolean,
260 tsNanos: Long
261 ) {
262 assertNotNull(orderedBroadcastAsUserHistory.poll(BROADCAST_TIMEOUT_MS) {
263 intent -> intent.action.equals(ACTION_DATA_ACTIVITY_CHANGE) &&
264 intent.getIntExtra(EXTRA_DEVICE_TYPE, -1) == deviceType &&
265 intent.getBooleanExtra(EXTRA_IS_ACTIVE, !isActive) == isActive &&
266 intent.getLongExtra(EXTRA_REALTIME_NS, -1) == tsNanos
267 })
268 }
269