1 /*
2  * 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.content.pm.PackageManager.FEATURE_LEANBACK
20 import android.net.INetd
21 import android.net.LocalNetworkConfig
22 import android.net.NativeNetworkConfig
23 import android.net.NativeNetworkType
24 import android.net.NetworkCapabilities
25 import android.net.NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK
26 import android.net.NetworkRequest
27 import android.net.NetworkScore
28 import android.net.NetworkScore.KEEP_CONNECTED_FOR_TEST
29 import android.net.VpnManager
30 import android.os.Build
31 import androidx.test.filters.SmallTest
32 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
33 import com.android.testutils.DevSdkIgnoreRunner
34 import com.android.testutils.RecorderCallback.CallbackEntry.Available
35 import com.android.testutils.TestableNetworkCallback
36 import kotlin.test.assertFailsWith
37 import org.junit.Assert.assertEquals
38 import org.junit.Test
39 import org.junit.runner.RunWith
40 import org.junit.runners.Parameterized
41 import org.mockito.Mockito.doReturn
42 import org.mockito.Mockito.inOrder
43 import org.mockito.Mockito.never
44 import org.mockito.Mockito.timeout
45 
46 private const val TIMEOUT_MS = 2_000L
47 private const val NO_CALLBACK_TIMEOUT_MS = 200L
48 
keepConnectedScorenull49 private fun keepConnectedScore() =
50         FromS(NetworkScore.Builder().setKeepConnectedReason(KEEP_CONNECTED_FOR_TEST).build())
51 
52 private fun defaultLnc() = FromS(LocalNetworkConfig.Builder().build())
53 
54 @DevSdkIgnoreRunner.MonitorThreadLeak
55 @RunWith(DevSdkIgnoreRunner::class)
56 @SmallTest
57 @IgnoreUpTo(Build.VERSION_CODES.R)
58 class CSLocalAgentCreationTests(
59         private val sdkLevel: Int,
60         private val isTv: Boolean,
61         private val addLocalNetCapToRequest: Boolean
62 ) : CSTest() {
63     companion object {
64         @JvmStatic
65         @Parameterized.Parameters
66         fun arguments() = listOf(
67                 arrayOf(VERSION_V, false /* isTv */, true /* addLocalNetCapToRequest */),
68                 arrayOf(VERSION_V, false /* isTv */, false /* addLocalNetCapToRequest */),
69                 arrayOf(VERSION_V, true /* isTv */, true /* addLocalNetCapToRequest */),
70                 arrayOf(VERSION_V, true /* isTv */, false /* addLocalNetCapToRequest */),
71                 arrayOf(VERSION_U, false /* isTv */, true /* addLocalNetCapToRequest */),
72                 arrayOf(VERSION_U, false /* isTv */, false /* addLocalNetCapToRequest */),
73                 arrayOf(VERSION_U, true /* isTv */, true /* addLocalNetCapToRequest */),
74                 arrayOf(VERSION_U, true /* isTv */, false /* addLocalNetCapToRequest */),
75                 arrayOf(VERSION_T, false /* isTv */, false /* addLocalNetCapToRequest */),
76                 arrayOf(VERSION_T, true /* isTv */, false /* addLocalNetCapToRequest */),
77         )
78     }
79 
80     private fun makeNativeNetworkConfigLocal(netId: Int, permission: Int) =
81             NativeNetworkConfig(netId, NativeNetworkType.PHYSICAL_LOCAL, permission,
82                     false /* secure */, VpnManager.TYPE_VPN_NONE, false /* excludeLocalRoutes */)
83 
84     @Test
85     fun testLocalAgents() {
86         val netdInOrder = inOrder(netd)
87         deps.setBuildSdk(sdkLevel)
88         doReturn(isTv).`when`(packageManager).hasSystemFeature(FEATURE_LEANBACK)
89         val allNetworksCb = TestableNetworkCallback()
90         val request = NetworkRequest.Builder()
91         if (addLocalNetCapToRequest) {
92             request.addCapability(NET_CAPABILITY_LOCAL_NETWORK)
93         }
94         cm.registerNetworkCallback(request.build(), allNetworksCb)
95         val ncTemplate = NetworkCapabilities.Builder().run {
96             addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
97             addCapability(NET_CAPABILITY_LOCAL_NETWORK)
98         }.build()
99         val localAgent = if (sdkLevel >= VERSION_V || sdkLevel == VERSION_U && isTv) {
100             Agent(nc = ncTemplate, score = keepConnectedScore(), lnc = defaultLnc())
101         } else {
102             assertFailsWith<IllegalArgumentException> { Agent(nc = ncTemplate, lnc = defaultLnc()) }
103             netdInOrder.verify(netd, never()).networkCreate(any())
104             return
105         }
106         localAgent.connect()
107         netdInOrder.verify(netd).networkCreate(
108                 makeNativeNetworkConfigLocal(localAgent.network.netId, INetd.PERMISSION_NONE))
109         if (addLocalNetCapToRequest) {
110             assertEquals(localAgent.network, allNetworksCb.expect<Available>().network)
111         } else {
112             allNetworksCb.assertNoCallback(NO_CALLBACK_TIMEOUT_MS)
113         }
114         cm.unregisterNetworkCallback(allNetworksCb)
115         localAgent.disconnect()
116         netdInOrder.verify(netd, timeout(TIMEOUT_MS)).networkDestroy(localAgent.network.netId)
117     }
118 
119     @Test
120     fun testBadAgents() {
121         assertFailsWith<IllegalArgumentException> {
122             Agent(nc = NetworkCapabilities.Builder()
123                     .addCapability(NET_CAPABILITY_LOCAL_NETWORK)
124                     .build(),
125                     lnc = null)
126         }
127         assertFailsWith<IllegalArgumentException> {
128             Agent(nc = NetworkCapabilities.Builder().build(), lnc = defaultLnc())
129         }
130     }
131 }
132