• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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