1 /*
<lambda>null2  * Copyright (C) 2021 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 android.net
18 
19 import android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE
20 import android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID
21 import android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_IGNORE
22 import android.net.ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT
23 import android.net.ConnectivitySettingsManager.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS
24 import android.net.ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_MOBILE
25 import android.net.ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_WIFI
26 import android.net.ConnectivitySettingsManager.DNS_RESOLVER_MAX_SAMPLES
27 import android.net.ConnectivitySettingsManager.DNS_RESOLVER_MIN_SAMPLES
28 import android.net.ConnectivitySettingsManager.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS
29 import android.net.ConnectivitySettingsManager.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT
30 import android.net.ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON
31 import android.net.ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT
32 import android.net.ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS
33 import android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE
34 import android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF
35 import android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC
36 import android.net.ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED
37 import android.net.ConnectivitySettingsManager.getCaptivePortalMode
38 import android.net.ConnectivitySettingsManager.getConnectivityKeepPendingIntentDuration
39 import android.net.ConnectivitySettingsManager.getDnsResolverSampleRanges
40 import android.net.ConnectivitySettingsManager.getDnsResolverSampleValidityDuration
41 import android.net.ConnectivitySettingsManager.getDnsResolverSuccessThresholdPercent
42 import android.net.ConnectivitySettingsManager.getIngressRateLimitInBytesPerSecond
43 import android.net.ConnectivitySettingsManager.getMobileDataActivityTimeout
44 import android.net.ConnectivitySettingsManager.getMobileDataAlwaysOn
45 import android.net.ConnectivitySettingsManager.getNetworkSwitchNotificationMaximumDailyCount
46 import android.net.ConnectivitySettingsManager.getNetworkSwitchNotificationRateDuration
47 import android.net.ConnectivitySettingsManager.getPrivateDnsDefaultMode
48 import android.net.ConnectivitySettingsManager.getWifiAlwaysRequested
49 import android.net.ConnectivitySettingsManager.getWifiDataActivityTimeout
50 import android.net.ConnectivitySettingsManager.setCaptivePortalMode
51 import android.net.ConnectivitySettingsManager.setConnectivityKeepPendingIntentDuration
52 import android.net.ConnectivitySettingsManager.setDnsResolverSampleRanges
53 import android.net.ConnectivitySettingsManager.setDnsResolverSampleValidityDuration
54 import android.net.ConnectivitySettingsManager.setDnsResolverSuccessThresholdPercent
55 import android.net.ConnectivitySettingsManager.setIngressRateLimitInBytesPerSecond
56 import android.net.ConnectivitySettingsManager.setMobileDataActivityTimeout
57 import android.net.ConnectivitySettingsManager.setMobileDataAlwaysOn
58 import android.net.ConnectivitySettingsManager.setNetworkSwitchNotificationMaximumDailyCount
59 import android.net.ConnectivitySettingsManager.setNetworkSwitchNotificationRateDuration
60 import android.net.ConnectivitySettingsManager.setPrivateDnsDefaultMode
61 import android.net.ConnectivitySettingsManager.setWifiAlwaysRequested
62 import android.net.ConnectivitySettingsManager.setWifiDataActivityTimeout
63 import android.os.Build
64 import android.platform.test.annotations.AppModeFull
65 import android.provider.Settings
66 import android.util.Range
67 import androidx.test.InstrumentationRegistry
68 import androidx.test.filters.SmallTest
69 import com.android.net.module.util.ConnectivitySettingsUtils.getPrivateDnsModeAsString
70 import com.android.testutils.ConnectivityModuleTest
71 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
72 import com.android.testutils.DevSdkIgnoreRunner
73 import junit.framework.Assert.assertEquals
74 import org.junit.Test
75 import org.junit.runner.RunWith
76 import java.time.Duration
77 import java.util.Objects
78 import kotlin.test.assertFailsWith
79 
80 /**
81  * Tests for [ConnectivitySettingsManager].
82  *
83  * Build, install and run with:
84  * atest android.net.ConnectivitySettingsManagerTest
85  */
86 @RunWith(DevSdkIgnoreRunner::class)
87 @IgnoreUpTo(Build.VERSION_CODES.R)
88 @SmallTest
89 @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
90 class ConnectivitySettingsManagerTest {
91     private val instrumentation = InstrumentationRegistry.getInstrumentation()
92     private val context = instrumentation.context
93     private val resolver = context.contentResolver
94 
95     private val defaultDuration = Duration.ofSeconds(0L)
96     private val testTime1 = 5L
97     private val testTime2 = 10L
98     private val settingsTypeGlobal = "global"
99     private val settingsTypeSecure = "secure"
100 
101     /*** Reset setting value or delete setting if the setting was not existed before testing. */
102     private fun resetSettings(names: Array<String>, type: String, values: Array<String?>) {
103         for (i in names.indices) {
104             if (Objects.equals(values[i], null)) {
105                 instrumentation.uiAutomation.executeShellCommand(
106                         "settings delete $type ${names[i]}")
107             } else {
108                 if (settingsTypeSecure.equals(type)) {
109                     Settings.Secure.putString(resolver, names[i], values[i])
110                 } else {
111                     Settings.Global.putString(resolver, names[i], values[i])
112                 }
113             }
114         }
115     }
116 
117     fun <T> testIntSetting(
118         names: Array<String>,
119         type: String,
120         value1: T,
121         value2: T,
122         getter: () -> T,
123         setter: (value: T) -> Unit,
124         testIntValues: IntArray
125     ) {
126         val originals: Array<String?> = Array(names.size) { i ->
127             if (settingsTypeSecure.equals(type)) {
128                 Settings.Secure.getString(resolver, names[i])
129             } else {
130                 Settings.Global.getString(resolver, names[i])
131             }
132         }
133 
134         try {
135             for (i in names.indices) {
136                 if (settingsTypeSecure.equals(type)) {
137                     Settings.Secure.putString(resolver, names[i], testIntValues[i].toString())
138                 } else {
139                     Settings.Global.putString(resolver, names[i], testIntValues[i].toString())
140                 }
141             }
142             assertEquals(value1, getter())
143 
144             setter(value2)
145             assertEquals(value2, getter())
146         } finally {
147             resetSettings(names, type, originals)
148         }
149     }
150 
151     @Test
152     fun testMobileDataActivityTimeout() {
153         testIntSetting(names = arrayOf(DATA_ACTIVITY_TIMEOUT_MOBILE), type = settingsTypeGlobal,
154                 value1 = Duration.ofSeconds(testTime1), value2 = Duration.ofSeconds(testTime2),
155                 getter = { getMobileDataActivityTimeout(context, defaultDuration) },
156                 setter = { setMobileDataActivityTimeout(context, it) },
157                 testIntValues = intArrayOf(testTime1.toInt()))
158     }
159 
160     @Test
161     fun testWifiDataActivityTimeout() {
162         testIntSetting(names = arrayOf(DATA_ACTIVITY_TIMEOUT_WIFI), type = settingsTypeGlobal,
163                 value1 = Duration.ofSeconds(testTime1), value2 = Duration.ofSeconds(testTime2),
164                 getter = { getWifiDataActivityTimeout(context, defaultDuration) },
165                 setter = { setWifiDataActivityTimeout(context, it) },
166                 testIntValues = intArrayOf(testTime1.toInt()))
167     }
168 
169     @Test
170     fun testDnsResolverSampleValidityDuration() {
171         testIntSetting(names = arrayOf(DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS),
172                 type = settingsTypeGlobal, value1 = Duration.ofSeconds(testTime1),
173                 value2 = Duration.ofSeconds(testTime2),
174                 getter = { getDnsResolverSampleValidityDuration(context, defaultDuration) },
175                 setter = { setDnsResolverSampleValidityDuration(context, it) },
176                 testIntValues = intArrayOf(testTime1.toInt()))
177 
178         assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
179             setDnsResolverSampleValidityDuration(context, Duration.ofSeconds(-1L)) }
180     }
181 
182     @Test
183     fun testDnsResolverSuccessThresholdPercent() {
184         testIntSetting(names = arrayOf(DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT),
185                 type = settingsTypeGlobal, value1 = 5, value2 = 10,
186                 getter = { getDnsResolverSuccessThresholdPercent(context, 0 /* def */) },
187                 setter = { setDnsResolverSuccessThresholdPercent(context, it) },
188                 testIntValues = intArrayOf(5))
189 
190         assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
191             setDnsResolverSuccessThresholdPercent(context, -1) }
192         assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
193             setDnsResolverSuccessThresholdPercent(context, 120) }
194     }
195 
196     @Test
197     fun testDnsResolverSampleRanges() {
198         testIntSetting(names = arrayOf(DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_MAX_SAMPLES),
199                 type = settingsTypeGlobal, value1 = Range(1, 63), value2 = Range(2, 62),
200                 getter = { getDnsResolverSampleRanges(context) },
201                 setter = { setDnsResolverSampleRanges(context, it) },
202                 testIntValues = intArrayOf(1, 63))
203 
204         assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
205             setDnsResolverSampleRanges(context, Range(-1, 62)) }
206         assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
207             setDnsResolverSampleRanges(context, Range(2, 65)) }
208     }
209 
210     @Test
211     fun testNetworkSwitchNotificationMaximumDailyCount() {
212         testIntSetting(names = arrayOf(NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT),
213                 type = settingsTypeGlobal, value1 = 5, value2 = 15,
214                 getter = { getNetworkSwitchNotificationMaximumDailyCount(context, 0 /* def */) },
215                 setter = { setNetworkSwitchNotificationMaximumDailyCount(context, it) },
216                 testIntValues = intArrayOf(5))
217 
218         assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
219             setNetworkSwitchNotificationMaximumDailyCount(context, -1) }
220     }
221 
222     @Test
223     fun testNetworkSwitchNotificationRateDuration() {
224         testIntSetting(names = arrayOf(NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS),
225                 type = settingsTypeGlobal, value1 = Duration.ofMillis(testTime1),
226                 value2 = Duration.ofMillis(testTime2),
227                 getter = { getNetworkSwitchNotificationRateDuration(context, defaultDuration) },
228                 setter = { setNetworkSwitchNotificationRateDuration(context, it) },
229                 testIntValues = intArrayOf(testTime1.toInt()))
230 
231         assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
232             setNetworkSwitchNotificationRateDuration(context, Duration.ofMillis(-1L)) }
233     }
234 
235     @Test
236     fun testCaptivePortalMode() {
237         testIntSetting(names = arrayOf(CAPTIVE_PORTAL_MODE), type = settingsTypeGlobal,
238                 value1 = CAPTIVE_PORTAL_MODE_AVOID, value2 = CAPTIVE_PORTAL_MODE_PROMPT,
239                 getter = { getCaptivePortalMode(context, CAPTIVE_PORTAL_MODE_IGNORE) },
240                 setter = { setCaptivePortalMode(context, it) },
241                 testIntValues = intArrayOf(CAPTIVE_PORTAL_MODE_AVOID))
242 
243         assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
244             setCaptivePortalMode(context, 5 /* mode */) }
245     }
246 
247     @Test
248     fun testPrivateDnsDefaultMode() {
249         val original = Settings.Global.getString(resolver, PRIVATE_DNS_DEFAULT_MODE)
250 
251         try {
252             val mode = getPrivateDnsModeAsString(PRIVATE_DNS_MODE_OPPORTUNISTIC)
253             Settings.Global.putString(resolver, PRIVATE_DNS_DEFAULT_MODE, mode)
254             assertEquals(mode, getPrivateDnsDefaultMode(context))
255 
256             setPrivateDnsDefaultMode(context, PRIVATE_DNS_MODE_OFF)
257             assertEquals(getPrivateDnsModeAsString(PRIVATE_DNS_MODE_OFF),
258                     getPrivateDnsDefaultMode(context))
259         } finally {
260             resetSettings(names = arrayOf(PRIVATE_DNS_DEFAULT_MODE), type = settingsTypeGlobal,
261                     values = arrayOf(original))
262         }
263 
264         assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
265             setPrivateDnsDefaultMode(context, -1) }
266     }
267 
268     @Test
269     fun testConnectivityKeepPendingIntentDuration() {
270         testIntSetting(names = arrayOf(CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS),
271                 type = settingsTypeSecure, value1 = Duration.ofMillis(testTime1),
272                 value2 = Duration.ofMillis(testTime2),
273                 getter = { getConnectivityKeepPendingIntentDuration(context, defaultDuration) },
274                 setter = { setConnectivityKeepPendingIntentDuration(context, it) },
275                 testIntValues = intArrayOf(testTime1.toInt()))
276 
277         assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
278             setConnectivityKeepPendingIntentDuration(context, Duration.ofMillis(-1L)) }
279     }
280 
281     @Test
282     fun testMobileDataAlwaysOn() {
283         testIntSetting(names = arrayOf(MOBILE_DATA_ALWAYS_ON), type = settingsTypeGlobal,
284                 value1 = false, value2 = true,
285                 getter = { getMobileDataAlwaysOn(context, true /* def */) },
286                 setter = { setMobileDataAlwaysOn(context, it) },
287                 testIntValues = intArrayOf(0))
288     }
289 
290     @Test
291     fun testWifiAlwaysRequested() {
292         testIntSetting(names = arrayOf(WIFI_ALWAYS_REQUESTED), type = settingsTypeGlobal,
293                 value1 = false, value2 = true,
294                 getter = { getWifiAlwaysRequested(context, true /* def */) },
295                 setter = { setWifiAlwaysRequested(context, it) },
296                 testIntValues = intArrayOf(0))
297     }
298 
299     @ConnectivityModuleTest // get/setIngressRateLimitInBytesPerSecond was added via module update
300     @Test
301     fun testInternetNetworkRateLimitInBytesPerSecond() {
302         val defaultRate = getIngressRateLimitInBytesPerSecond(context)
303         val testRate = 1000L
304         setIngressRateLimitInBytesPerSecond(context, testRate)
305         assertEquals(testRate, getIngressRateLimitInBytesPerSecond(context))
306 
307         setIngressRateLimitInBytesPerSecond(context, defaultRate)
308         assertEquals(defaultRate, getIngressRateLimitInBytesPerSecond(context))
309 
310         assertFailsWith<IllegalArgumentException>("Expected failure, but setting accepted") {
311             setIngressRateLimitInBytesPerSecond(context, -10)
312         }
313     }
314 }