1 /*
2 * Copyright (C) 2024 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.app.ActivityManager.UidFrozenStateChangedCallback
20 import android.app.ActivityManager.UidFrozenStateChangedCallback.UID_FROZEN_STATE_FROZEN
21 import android.app.ActivityManager.UidFrozenStateChangedCallback.UID_FROZEN_STATE_UNFROZEN
22 import android.net.ConnectivityManager.BLOCKED_REASON_APP_BACKGROUND
23 import android.net.ConnectivityManager.BLOCKED_REASON_NONE
24 import android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND
25 import android.net.ConnectivityManager.FIREWALL_RULE_ALLOW
26 import android.net.ConnectivityManager.FIREWALL_RULE_DENY
27 import android.net.LinkProperties
28 import android.net.NetworkCapabilities
29 import android.os.Build
30 import com.android.net.module.util.BaseNetdUnsolicitedEventListener
31 import com.android.server.connectivity.ConnectivityFlags.DELAY_DESTROY_SOCKETS
32 import com.android.testutils.DevSdkIgnoreRule
33 import com.android.testutils.DevSdkIgnoreRunner
34 import org.junit.Test
35 import org.junit.runner.RunWith
36 import org.mockito.ArgumentCaptor
37 import org.mockito.Mockito.any
38 import org.mockito.Mockito.doReturn
39 import org.mockito.Mockito.inOrder
40 import org.mockito.Mockito.never
41 import org.mockito.Mockito.verify
42
43 private const val TIMESTAMP = 1234L
44 private const val TEST_UID = 1234
45 private const val TEST_UID2 = 5678
46 private const val TEST_CELL_IFACE = "test_rmnet"
47
cellNcnull48 private fun cellNc() = NetworkCapabilities.Builder()
49 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
50 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
51 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
52 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
53 .build()
54
55 private fun cellLp() = LinkProperties().also{
56 it.interfaceName = TEST_CELL_IFACE
57 }
58
59 @RunWith(DevSdkIgnoreRunner::class)
60 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
61 class CSDestroySocketTest : CSTest() {
getRegisteredNetdUnsolicitedEventListenernull62 private fun getRegisteredNetdUnsolicitedEventListener(): BaseNetdUnsolicitedEventListener {
63 val captor = ArgumentCaptor.forClass(BaseNetdUnsolicitedEventListener::class.java)
64 verify(netd).registerUnsolicitedEventListener(captor.capture())
65 return captor.value
66 }
67
getUidFrozenStateChangedCallbacknull68 private fun getUidFrozenStateChangedCallback(): UidFrozenStateChangedCallback {
69 val captor = ArgumentCaptor.forClass(UidFrozenStateChangedCallback::class.java)
70 verify(activityManager).registerUidFrozenStateChangedCallback(any(), captor.capture())
71 return captor.value
72 }
73
doTestBackgroundRestrictionDestroySocketsnull74 private fun doTestBackgroundRestrictionDestroySockets(
75 restrictionWithIdleNetwork: Boolean,
76 expectDelay: Boolean
77 ) {
78 val netdEventListener = getRegisteredNetdUnsolicitedEventListener()
79 val inOrder = inOrder(destroySocketsWrapper)
80
81 val cellAgent = Agent(nc = cellNc(), lp = cellLp())
82 cellAgent.connect()
83 if (restrictionWithIdleNetwork) {
84 // Make cell default network idle
85 netdEventListener.onInterfaceClassActivityChanged(
86 false, // isActive
87 cellAgent.network.netId,
88 TIMESTAMP,
89 TEST_UID
90 )
91 }
92
93 // Set deny rule on background chain for TEST_UID
94 doReturn(BLOCKED_REASON_APP_BACKGROUND)
95 .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(TEST_UID)
96 cm.setUidFirewallRule(
97 FIREWALL_CHAIN_BACKGROUND,
98 TEST_UID,
99 FIREWALL_RULE_DENY
100 )
101 waitForIdle()
102 if (expectDelay) {
103 inOrder.verify(destroySocketsWrapper, never())
104 .destroyLiveTcpSocketsByOwnerUids(setOf(TEST_UID))
105 } else {
106 inOrder.verify(destroySocketsWrapper)
107 .destroyLiveTcpSocketsByOwnerUids(setOf(TEST_UID))
108 }
109
110 netdEventListener.onInterfaceClassActivityChanged(
111 true, // isActive
112 cellAgent.network.netId,
113 TIMESTAMP,
114 TEST_UID
115 )
116 waitForIdle()
117 if (expectDelay) {
118 inOrder.verify(destroySocketsWrapper)
119 .destroyLiveTcpSocketsByOwnerUids(setOf(TEST_UID))
120 } else {
121 inOrder.verify(destroySocketsWrapper, never())
122 .destroyLiveTcpSocketsByOwnerUids(setOf(TEST_UID))
123 }
124
125 cellAgent.disconnect()
126 }
127
128 @Test
129 @FeatureFlags(flags = [Flag(DELAY_DESTROY_SOCKETS, true)])
testBackgroundAppDestroySocketsnull130 fun testBackgroundAppDestroySockets() {
131 doTestBackgroundRestrictionDestroySockets(
132 restrictionWithIdleNetwork = true,
133 expectDelay = true
134 )
135 }
136
137 @Test
138 @FeatureFlags(flags = [Flag(DELAY_DESTROY_SOCKETS, true)])
testBackgroundAppDestroySockets_activeNetworknull139 fun testBackgroundAppDestroySockets_activeNetwork() {
140 doTestBackgroundRestrictionDestroySockets(
141 restrictionWithIdleNetwork = false,
142 expectDelay = false
143 )
144 }
145
146 @Test
147 @FeatureFlags(flags = [Flag(DELAY_DESTROY_SOCKETS, false)])
testBackgroundAppDestroySockets_featureIsDisablednull148 fun testBackgroundAppDestroySockets_featureIsDisabled() {
149 doTestBackgroundRestrictionDestroySockets(
150 restrictionWithIdleNetwork = true,
151 expectDelay = false
152 )
153 }
154
155 @Test
testReplaceFirewallChainnull156 fun testReplaceFirewallChain() {
157 val netdEventListener = getRegisteredNetdUnsolicitedEventListener()
158 val inOrder = inOrder(destroySocketsWrapper)
159
160 val cellAgent = Agent(nc = cellNc(), lp = cellLp())
161 cellAgent.connect()
162 // Make cell default network idle
163 netdEventListener.onInterfaceClassActivityChanged(
164 false, // isActive
165 cellAgent.network.netId,
166 TIMESTAMP,
167 TEST_UID
168 )
169
170 // Set allow rule on background chain for TEST_UID
171 doReturn(BLOCKED_REASON_NONE)
172 .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(TEST_UID)
173 cm.setUidFirewallRule(
174 FIREWALL_CHAIN_BACKGROUND,
175 TEST_UID,
176 FIREWALL_RULE_ALLOW
177 )
178 // Set deny rule on background chain for TEST_UID
179 doReturn(BLOCKED_REASON_APP_BACKGROUND)
180 .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(TEST_UID2)
181 cm.setUidFirewallRule(
182 FIREWALL_CHAIN_BACKGROUND,
183 TEST_UID2,
184 FIREWALL_RULE_DENY
185 )
186
187 // Put only TEST_UID2 on background chain (deny TEST_UID and allow TEST_UID2)
188 doReturn(setOf(TEST_UID))
189 .`when`(bpfNetMaps).getUidsWithAllowRuleOnAllowListChain(FIREWALL_CHAIN_BACKGROUND)
190 doReturn(BLOCKED_REASON_APP_BACKGROUND)
191 .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(TEST_UID)
192 doReturn(BLOCKED_REASON_NONE)
193 .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(TEST_UID2)
194 cm.replaceFirewallChain(FIREWALL_CHAIN_BACKGROUND, intArrayOf(TEST_UID2))
195 waitForIdle()
196 inOrder.verify(destroySocketsWrapper, never())
197 .destroyLiveTcpSocketsByOwnerUids(setOf(TEST_UID))
198
199 netdEventListener.onInterfaceClassActivityChanged(
200 true, // isActive
201 cellAgent.network.netId,
202 TIMESTAMP,
203 TEST_UID
204 )
205 waitForIdle()
206 inOrder.verify(destroySocketsWrapper)
207 .destroyLiveTcpSocketsByOwnerUids(setOf(TEST_UID))
208
209 cellAgent.disconnect()
210 }
211
doTestDestroySocketsnull212 private fun doTestDestroySockets(
213 isFrozen: Boolean,
214 denyOnBackgroundChain: Boolean,
215 enableBackgroundChain: Boolean,
216 expectDestroySockets: Boolean
217 ) {
218 val netdEventListener = getRegisteredNetdUnsolicitedEventListener()
219 val frozenStateCallback = getUidFrozenStateChangedCallback()
220
221 // Make cell default network idle
222 val cellAgent = Agent(nc = cellNc(), lp = cellLp())
223 cellAgent.connect()
224 netdEventListener.onInterfaceClassActivityChanged(
225 false, // isActive
226 cellAgent.network.netId,
227 TIMESTAMP,
228 TEST_UID
229 )
230
231 // Set deny rule on background chain for TEST_UID
232 doReturn(BLOCKED_REASON_APP_BACKGROUND)
233 .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(TEST_UID)
234 cm.setUidFirewallRule(
235 FIREWALL_CHAIN_BACKGROUND,
236 TEST_UID,
237 FIREWALL_RULE_DENY
238 )
239
240 // Freeze TEST_UID
241 frozenStateCallback.onUidFrozenStateChanged(
242 intArrayOf(TEST_UID),
243 intArrayOf(UID_FROZEN_STATE_FROZEN)
244 )
245
246 if (!isFrozen) {
247 // Unfreeze TEST_UID
248 frozenStateCallback.onUidFrozenStateChanged(
249 intArrayOf(TEST_UID),
250 intArrayOf(UID_FROZEN_STATE_UNFROZEN)
251 )
252 }
253 if (!enableBackgroundChain) {
254 // Disable background chain
255 cm.setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, false)
256 }
257 if (!denyOnBackgroundChain) {
258 // Set allow rule on background chain for TEST_UID
259 doReturn(BLOCKED_REASON_NONE)
260 .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(TEST_UID)
261 cm.setUidFirewallRule(
262 FIREWALL_CHAIN_BACKGROUND,
263 TEST_UID,
264 FIREWALL_RULE_ALLOW
265 )
266 }
267 verify(destroySocketsWrapper, never()).destroyLiveTcpSocketsByOwnerUids(setOf(TEST_UID))
268
269 // Make cell network active
270 netdEventListener.onInterfaceClassActivityChanged(
271 true, // isActive
272 cellAgent.network.netId,
273 TIMESTAMP,
274 TEST_UID
275 )
276 waitForIdle()
277
278 if (expectDestroySockets) {
279 verify(destroySocketsWrapper).destroyLiveTcpSocketsByOwnerUids(setOf(TEST_UID))
280 } else {
281 verify(destroySocketsWrapper, never()).destroyLiveTcpSocketsByOwnerUids(setOf(TEST_UID))
282 }
283 }
284
285 @Test
testDestroySockets_backgroundDeny_frozennull286 fun testDestroySockets_backgroundDeny_frozen() {
287 doTestDestroySockets(
288 isFrozen = true,
289 denyOnBackgroundChain = true,
290 enableBackgroundChain = true,
291 expectDestroySockets = true
292 )
293 }
294
295 @Test
testDestroySockets_backgroundDeny_nonFrozennull296 fun testDestroySockets_backgroundDeny_nonFrozen() {
297 doTestDestroySockets(
298 isFrozen = false,
299 denyOnBackgroundChain = true,
300 enableBackgroundChain = true,
301 expectDestroySockets = true
302 )
303 }
304
305 @Test
testDestroySockets_backgroundAllow_frozennull306 fun testDestroySockets_backgroundAllow_frozen() {
307 doTestDestroySockets(
308 isFrozen = true,
309 denyOnBackgroundChain = false,
310 enableBackgroundChain = true,
311 expectDestroySockets = true
312 )
313 }
314
315 @Test
testDestroySockets_backgroundAllow_nonFrozennull316 fun testDestroySockets_backgroundAllow_nonFrozen() {
317 // If the app is neither frozen nor under background restriction, sockets are not
318 // destroyed
319 doTestDestroySockets(
320 isFrozen = false,
321 denyOnBackgroundChain = false,
322 enableBackgroundChain = true,
323 expectDestroySockets = false
324 )
325 }
326
327 @Test
testDestroySockets_backgroundChainDisabled_nonFrozennull328 fun testDestroySockets_backgroundChainDisabled_nonFrozen() {
329 // If the app is neither frozen nor under background restriction, sockets are not
330 // destroyed
331 doTestDestroySockets(
332 isFrozen = false,
333 denyOnBackgroundChain = true,
334 enableBackgroundChain = false,
335 expectDestroySockets = false
336 )
337 }
338 }
339