1 /* <lambda>null2 * Copyright (C) 2020 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.cts 18 19 import android.Manifest 20 import android.net.util.NetworkStackUtils 21 import android.provider.DeviceConfig 22 import android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY 23 import android.util.Log 24 import com.android.testutils.runAsShell 25 import com.android.testutils.tryTest 26 import java.util.concurrent.CompletableFuture 27 import java.util.concurrent.Executor 28 import java.util.concurrent.TimeUnit 29 30 /** 31 * Collection of utility methods for configuring network validation. 32 */ 33 internal object NetworkValidationTestUtil { 34 val TAG = NetworkValidationTestUtil::class.simpleName 35 const val TIMEOUT_MS = 20_000L 36 37 /** 38 * Clear the test network validation URLs. 39 */ 40 @JvmStatic fun clearValidationTestUrlsDeviceConfig() { 41 setHttpsUrlDeviceConfig(null) 42 setHttpUrlDeviceConfig(null) 43 setUrlExpirationDeviceConfig(null) 44 } 45 46 /** 47 * Set the test validation HTTPS URL. 48 * 49 * @see NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL 50 */ 51 @JvmStatic fun setHttpsUrlDeviceConfig(url: String?) = 52 setConfig(NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL, url) 53 54 /** 55 * Set the test validation HTTP URL. 56 * 57 * @see NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL 58 */ 59 @JvmStatic fun setHttpUrlDeviceConfig(url: String?) = 60 setConfig(NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL, url) 61 62 /** 63 * Set the test validation URL expiration. 64 * 65 * @see NetworkStackUtils.TEST_URL_EXPIRATION_TIME 66 */ 67 @JvmStatic fun setUrlExpirationDeviceConfig(timestamp: Long?) = 68 setConfig(NetworkStackUtils.TEST_URL_EXPIRATION_TIME, timestamp?.toString()) 69 70 private fun setConfig(configKey: String, value: String?): String? { 71 Log.i(TAG, "Setting config \"$configKey\" to \"$value\"") 72 val readWritePermissions = arrayOf( 73 Manifest.permission.READ_DEVICE_CONFIG, 74 Manifest.permission.WRITE_DEVICE_CONFIG) 75 76 val existingValue = runAsShell(*readWritePermissions) { 77 DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, configKey) 78 } 79 if (existingValue == value) { 80 // Already the correct value. There may be a race if a change is already in flight, 81 // but if multiple threads update the config there is no way to fix that anyway. 82 Log.i(TAG, "\$configKey\" already had value \"$value\"") 83 return value 84 } 85 86 val future = CompletableFuture<String>() 87 val listener = DeviceConfig.OnPropertiesChangedListener { 88 // The listener receives updates for any change to any key, so don't react to 89 // changes that do not affect the relevant key 90 if (!it.keyset.contains(configKey)) return@OnPropertiesChangedListener 91 if (it.getString(configKey, null) == value) { 92 future.complete(value) 93 } 94 } 95 96 return tryTest { 97 runAsShell(*readWritePermissions) { 98 DeviceConfig.addOnPropertiesChangedListener( 99 NAMESPACE_CONNECTIVITY, 100 inlineExecutor, 101 listener) 102 DeviceConfig.setProperty( 103 NAMESPACE_CONNECTIVITY, 104 configKey, 105 value, 106 false /* makeDefault */) 107 // Don't drop the permission until the config is applied, just in case 108 future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS) 109 }.also { 110 Log.i(TAG, "Config \"$configKey\" successfully set to \"$value\"") 111 } 112 } cleanup { 113 DeviceConfig.removeOnPropertiesChangedListener(listener) 114 } 115 } 116 117 private val inlineExecutor get() = Executor { r -> r.run() } 118 } 119