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