Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2017 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 | |
markchien | 503be61 | 2020-04-12 21:41:29 +0800 | [diff] [blame] | 17 | package com.android.networkstack.tethering; |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 18 | |
Erik Kline | 54f2f37 | 2017-05-15 21:11:47 +0900 | [diff] [blame] | 19 | import static android.content.Context.TELEPHONY_SERVICE; |
Erik Kline | 1e54351 | 2017-03-09 11:44:11 +0900 | [diff] [blame] | 20 | import static android.net.ConnectivityManager.TYPE_ETHERNET; |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 21 | import static android.net.ConnectivityManager.TYPE_MOBILE; |
| 22 | import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; |
| 23 | import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; |
markchien | 2dfee02 | 2020-01-13 16:09:42 +0800 | [diff] [blame] | 24 | import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; |
Remi NGUYEN VAN | e3bb5c5 | 2018-06-12 15:57:04 +0900 | [diff] [blame] | 25 | |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 26 | import android.content.Context; |
| 27 | import android.content.res.Resources; |
markchien | 0df2ebc4 | 2019-09-30 14:40:57 +0800 | [diff] [blame] | 28 | import android.net.TetheringConfigurationParcel; |
Erik Kline | e93ed61 | 2018-04-10 07:01:16 +0000 | [diff] [blame] | 29 | import android.net.util.SharedLog; |
markchien | 2dfee02 | 2020-01-13 16:09:42 +0800 | [diff] [blame] | 30 | import android.provider.DeviceConfig; |
markchien | 0b59507 | 2019-01-08 23:52:21 +0800 | [diff] [blame] | 31 | import android.telephony.SubscriptionManager; |
Erik Kline | e0f3403 | 2018-02-28 15:01:35 +0900 | [diff] [blame] | 32 | import android.telephony.TelephonyManager; |
| 33 | import android.text.TextUtils; |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 34 | |
Chalard Jean | 918a68b | 2018-01-19 17:00:47 +0900 | [diff] [blame] | 35 | import com.android.internal.annotations.VisibleForTesting; |
| 36 | |
Erik Kline | 9db1b54 | 2017-03-16 14:10:27 +0900 | [diff] [blame] | 37 | import java.io.PrintWriter; |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 38 | import java.util.ArrayList; |
| 39 | import java.util.Arrays; |
| 40 | import java.util.Collection; |
Erik Kline | 9db1b54 | 2017-03-16 14:10:27 +0900 | [diff] [blame] | 41 | import java.util.StringJoiner; |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 42 | |
| 43 | |
| 44 | /** |
| 45 | * A utility class to encapsulate the various tethering configuration elements. |
| 46 | * |
| 47 | * This configuration data includes elements describing upstream properties |
| 48 | * (preferred and required types of upstream connectivity as well as default |
| 49 | * DNS servers to use if none are available) and downstream properties (such |
| 50 | * as regular expressions use to match suitable downstream interfaces and the |
| 51 | * DHCPv4 ranges to use). |
| 52 | * |
| 53 | * @hide |
| 54 | */ |
| 55 | public class TetheringConfiguration { |
| 56 | private static final String TAG = TetheringConfiguration.class.getSimpleName(); |
| 57 | |
Erik Kline | e0f3403 | 2018-02-28 15:01:35 +0900 | [diff] [blame] | 58 | private static final String[] EMPTY_STRING_ARRAY = new String[0]; |
| 59 | |
Remi NGUYEN VAN | e3bb5c5 | 2018-06-12 15:57:04 +0900 | [diff] [blame] | 60 | // Default ranges used for the legacy DHCP server. |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 61 | // USB is 192.168.42.1 and 255.255.255.0 |
| 62 | // Wifi is 192.168.43.1 and 255.255.255.0 |
| 63 | // BT is limited to max default of 5 connections. 192.168.44.1 to 192.168.48.1 |
| 64 | // with 255.255.255.0 |
| 65 | // P2P is 192.168.49.1 and 255.255.255.0 |
Remi NGUYEN VAN | e3bb5c5 | 2018-06-12 15:57:04 +0900 | [diff] [blame] | 66 | private static final String[] LEGACY_DHCP_DEFAULT_RANGE = { |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 67 | "192.168.42.2", "192.168.42.254", "192.168.43.2", "192.168.43.254", |
| 68 | "192.168.44.2", "192.168.44.254", "192.168.45.2", "192.168.45.254", |
| 69 | "192.168.46.2", "192.168.46.254", "192.168.47.2", "192.168.47.254", |
| 70 | "192.168.48.2", "192.168.48.254", "192.168.49.2", "192.168.49.254", |
| 71 | }; |
| 72 | |
markchien | a6ba54d | 2019-09-03 15:58:06 +0800 | [diff] [blame] | 73 | private static final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"}; |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 74 | |
markchien | 2dfee02 | 2020-01-13 16:09:42 +0800 | [diff] [blame] | 75 | /** |
Nucca Chen | 95e0bac | 2020-05-12 11:34:28 +0000 | [diff] [blame] | 76 | * Override enabling BPF offload configuration for tethering. |
| 77 | */ |
| 78 | public static final String OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD = |
| 79 | "override_tether_enable_bpf_offload"; |
| 80 | |
| 81 | /** |
markchien | 2dfee02 | 2020-01-13 16:09:42 +0800 | [diff] [blame] | 82 | * Use the old dnsmasq DHCP server for tethering instead of the framework implementation. |
| 83 | */ |
| 84 | public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER = |
| 85 | "tether_enable_legacy_dhcp_server"; |
| 86 | |
junyulai | aea13ae | 2020-04-30 15:21:55 +0800 | [diff] [blame] | 87 | /** |
| 88 | * Default value that used to periodic polls tether offload stats from tethering offload HAL |
| 89 | * to make the data warnings work. |
| 90 | */ |
| 91 | public static final int DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS = 5000; |
| 92 | |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 93 | public final String[] tetherableUsbRegexs; |
| 94 | public final String[] tetherableWifiRegexs; |
Jimmy Chen | bcd86d0 | 2019-07-15 18:03:23 +0800 | [diff] [blame] | 95 | public final String[] tetherableWifiP2pRegexs; |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 96 | public final String[] tetherableBluetoothRegexs; |
Milim Lee | 31ef4c0 | 2019-10-17 05:02:33 +0900 | [diff] [blame] | 97 | public final String[] tetherableNcmRegexs; |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 98 | public final boolean isDunRequired; |
Erik Kline | 7230290 | 2018-06-14 17:36:40 +0900 | [diff] [blame] | 99 | public final boolean chooseUpstreamAutomatically; |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 100 | public final Collection<Integer> preferredUpstreamIfaceTypes; |
Remi NGUYEN VAN | e3bb5c5 | 2018-06-12 15:57:04 +0900 | [diff] [blame] | 101 | public final String[] legacyDhcpRanges; |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 102 | public final String[] defaultIPv4DNS; |
Remi NGUYEN VAN | e3bb5c5 | 2018-06-12 15:57:04 +0900 | [diff] [blame] | 103 | public final boolean enableLegacyDhcpServer; |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 104 | |
Erik Kline | e0f3403 | 2018-02-28 15:01:35 +0900 | [diff] [blame] | 105 | public final String[] provisioningApp; |
| 106 | public final String provisioningAppNoUi; |
markchien | 3b51963 | 2018-09-07 16:19:12 +0800 | [diff] [blame] | 107 | public final int provisioningCheckPeriod; |
Mark Chien | 5b0fdf6 | 2020-06-12 17:35:18 +0000 | [diff] [blame] | 108 | public final String provisioningResponse; |
Erik Kline | e0f3403 | 2018-02-28 15:01:35 +0900 | [diff] [blame] | 109 | |
markchien | 986750b | 2019-12-06 15:24:53 +0800 | [diff] [blame] | 110 | public final int activeDataSubId; |
markchien | 0b59507 | 2019-01-08 23:52:21 +0800 | [diff] [blame] | 111 | |
junyulai | aea13ae | 2020-04-30 15:21:55 +0800 | [diff] [blame] | 112 | private final int mOffloadPollInterval; |
Nucca Chen | 1c63ba3 | 2020-06-17 07:03:57 +0000 | [diff] [blame] | 113 | // TODO: Add to TetheringConfigurationParcel if required. |
| 114 | private final boolean mEnableBpfOffload; |
junyulai | aea13ae | 2020-04-30 15:21:55 +0800 | [diff] [blame] | 115 | |
markchien | 0b59507 | 2019-01-08 23:52:21 +0800 | [diff] [blame] | 116 | public TetheringConfiguration(Context ctx, SharedLog log, int id) { |
Erik Kline | 6bd7453 | 2017-05-19 10:10:41 +0900 | [diff] [blame] | 117 | final SharedLog configLog = log.forSubComponent("config"); |
| 118 | |
markchien | 986750b | 2019-12-06 15:24:53 +0800 | [diff] [blame] | 119 | activeDataSubId = id; |
| 120 | Resources res = getResources(ctx, activeDataSubId); |
markchien | 0b59507 | 2019-01-08 23:52:21 +0800 | [diff] [blame] | 121 | |
markchien | da4519a | 2020-01-14 12:46:53 +0800 | [diff] [blame] | 122 | tetherableUsbRegexs = getResourceStringArray(res, R.array.config_tether_usb_regexs); |
Milim Lee | 31ef4c0 | 2019-10-17 05:02:33 +0900 | [diff] [blame] | 123 | tetherableNcmRegexs = getResourceStringArray(res, R.array.config_tether_ncm_regexs); |
Erik Kline | 9e22554 | 2017-06-08 17:48:48 +0900 | [diff] [blame] | 124 | // TODO: Evaluate deleting this altogether now that Wi-Fi always passes |
| 125 | // us an interface name. Careful consideration needs to be given to |
| 126 | // implications for Settings and for provisioning checks. |
markchien | da4519a | 2020-01-14 12:46:53 +0800 | [diff] [blame] | 127 | tetherableWifiRegexs = getResourceStringArray(res, R.array.config_tether_wifi_regexs); |
| 128 | tetherableWifiP2pRegexs = getResourceStringArray( |
| 129 | res, R.array.config_tether_wifi_p2p_regexs); |
| 130 | tetherableBluetoothRegexs = getResourceStringArray( |
| 131 | res, R.array.config_tether_bluetooth_regexs); |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 132 | |
markchien | 986750b | 2019-12-06 15:24:53 +0800 | [diff] [blame] | 133 | isDunRequired = checkDunRequired(ctx); |
Erik Kline | 6bd7453 | 2017-05-19 10:10:41 +0900 | [diff] [blame] | 134 | |
markchien | da4519a | 2020-01-14 12:46:53 +0800 | [diff] [blame] | 135 | chooseUpstreamAutomatically = getResourceBoolean( |
Treehugger Robot | ddc32f6 | 2020-05-14 16:33:30 +0000 | [diff] [blame] | 136 | res, R.bool.config_tether_upstream_automatic, false /** defaultValue */); |
markchien | db3a236 | 2018-10-05 12:36:08 +0800 | [diff] [blame] | 137 | preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, isDunRequired); |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 138 | |
markchien | 0b59507 | 2019-01-08 23:52:21 +0800 | [diff] [blame] | 139 | legacyDhcpRanges = getLegacyDhcpRanges(res); |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 140 | defaultIPv4DNS = copy(DEFAULT_IPV4_DNS); |
Nucca Chen | 1c63ba3 | 2020-06-17 07:03:57 +0000 | [diff] [blame] | 141 | mEnableBpfOffload = getEnableBpfOffload(res); |
markchien | 2dfee02 | 2020-01-13 16:09:42 +0800 | [diff] [blame] | 142 | enableLegacyDhcpServer = getEnableLegacyDhcpServer(res); |
Erik Kline | 6bd7453 | 2017-05-19 10:10:41 +0900 | [diff] [blame] | 143 | |
markchien | da4519a | 2020-01-14 12:46:53 +0800 | [diff] [blame] | 144 | provisioningApp = getResourceStringArray(res, R.array.config_mobile_hotspot_provision_app); |
Mark Chien | 5b0fdf6 | 2020-06-12 17:35:18 +0000 | [diff] [blame] | 145 | provisioningAppNoUi = getResourceString(res, |
| 146 | R.string.config_mobile_hotspot_provision_app_no_ui); |
markchien | 3b51963 | 2018-09-07 16:19:12 +0800 | [diff] [blame] | 147 | provisioningCheckPeriod = getResourceInteger(res, |
markchien | da4519a | 2020-01-14 12:46:53 +0800 | [diff] [blame] | 148 | R.integer.config_mobile_hotspot_provision_check_period, |
markchien | 3b51963 | 2018-09-07 16:19:12 +0800 | [diff] [blame] | 149 | 0 /* No periodic re-check */); |
Mark Chien | 5b0fdf6 | 2020-06-12 17:35:18 +0000 | [diff] [blame] | 150 | provisioningResponse = getResourceString(res, |
| 151 | R.string.config_mobile_hotspot_provision_response); |
Erik Kline | e0f3403 | 2018-02-28 15:01:35 +0900 | [diff] [blame] | 152 | |
junyulai | aea13ae | 2020-04-30 15:21:55 +0800 | [diff] [blame] | 153 | mOffloadPollInterval = getResourceInteger(res, |
| 154 | R.integer.config_tether_offload_poll_interval, |
| 155 | DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); |
| 156 | |
Erik Kline | 6bd7453 | 2017-05-19 10:10:41 +0900 | [diff] [blame] | 157 | configLog.log(toString()); |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 158 | } |
| 159 | |
markchien | a6ba54d | 2019-09-03 15:58:06 +0800 | [diff] [blame] | 160 | /** Check whether input interface belong to usb.*/ |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 161 | public boolean isUsb(String iface) { |
| 162 | return matchesDownstreamRegexs(iface, tetherableUsbRegexs); |
| 163 | } |
| 164 | |
markchien | a6ba54d | 2019-09-03 15:58:06 +0800 | [diff] [blame] | 165 | /** Check whether input interface belong to wifi.*/ |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 166 | public boolean isWifi(String iface) { |
| 167 | return matchesDownstreamRegexs(iface, tetherableWifiRegexs); |
| 168 | } |
| 169 | |
Jimmy Chen | bcd86d0 | 2019-07-15 18:03:23 +0800 | [diff] [blame] | 170 | /** Check whether this interface is Wifi P2P interface. */ |
| 171 | public boolean isWifiP2p(String iface) { |
| 172 | return matchesDownstreamRegexs(iface, tetherableWifiP2pRegexs); |
| 173 | } |
| 174 | |
markchien | a6ba54d | 2019-09-03 15:58:06 +0800 | [diff] [blame] | 175 | /** Check whether using legacy mode for wifi P2P. */ |
Jimmy Chen | bcd86d0 | 2019-07-15 18:03:23 +0800 | [diff] [blame] | 176 | public boolean isWifiP2pLegacyTetheringMode() { |
| 177 | return (tetherableWifiP2pRegexs == null || tetherableWifiP2pRegexs.length == 0); |
| 178 | } |
| 179 | |
markchien | a6ba54d | 2019-09-03 15:58:06 +0800 | [diff] [blame] | 180 | /** Check whether input interface belong to bluetooth.*/ |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 181 | public boolean isBluetooth(String iface) { |
| 182 | return matchesDownstreamRegexs(iface, tetherableBluetoothRegexs); |
| 183 | } |
| 184 | |
Milim Lee | 31ef4c0 | 2019-10-17 05:02:33 +0900 | [diff] [blame] | 185 | /** Check if interface is ncm */ |
| 186 | public boolean isNcm(String iface) { |
| 187 | return matchesDownstreamRegexs(iface, tetherableNcmRegexs); |
| 188 | } |
| 189 | |
markchien | a6ba54d | 2019-09-03 15:58:06 +0800 | [diff] [blame] | 190 | /** Check whether no ui entitlement application is available.*/ |
Erik Kline | e0f3403 | 2018-02-28 15:01:35 +0900 | [diff] [blame] | 191 | public boolean hasMobileHotspotProvisionApp() { |
| 192 | return !TextUtils.isEmpty(provisioningAppNoUi); |
| 193 | } |
| 194 | |
markchien | a6ba54d | 2019-09-03 15:58:06 +0800 | [diff] [blame] | 195 | /** Does the dumping.*/ |
Erik Kline | 9db1b54 | 2017-03-16 14:10:27 +0900 | [diff] [blame] | 196 | public void dump(PrintWriter pw) { |
markchien | 986750b | 2019-12-06 15:24:53 +0800 | [diff] [blame] | 197 | pw.print("activeDataSubId: "); |
| 198 | pw.println(activeDataSubId); |
markchien | 0b59507 | 2019-01-08 23:52:21 +0800 | [diff] [blame] | 199 | |
Erik Kline | 9db1b54 | 2017-03-16 14:10:27 +0900 | [diff] [blame] | 200 | dumpStringArray(pw, "tetherableUsbRegexs", tetherableUsbRegexs); |
| 201 | dumpStringArray(pw, "tetherableWifiRegexs", tetherableWifiRegexs); |
Jimmy Chen | bcd86d0 | 2019-07-15 18:03:23 +0800 | [diff] [blame] | 202 | dumpStringArray(pw, "tetherableWifiP2pRegexs", tetherableWifiP2pRegexs); |
Erik Kline | 9db1b54 | 2017-03-16 14:10:27 +0900 | [diff] [blame] | 203 | dumpStringArray(pw, "tetherableBluetoothRegexs", tetherableBluetoothRegexs); |
Milim Lee | 31ef4c0 | 2019-10-17 05:02:33 +0900 | [diff] [blame] | 204 | dumpStringArray(pw, "tetherableNcmRegexs", tetherableNcmRegexs); |
Erik Kline | 9db1b54 | 2017-03-16 14:10:27 +0900 | [diff] [blame] | 205 | |
| 206 | pw.print("isDunRequired: "); |
| 207 | pw.println(isDunRequired); |
| 208 | |
Erik Kline | 7230290 | 2018-06-14 17:36:40 +0900 | [diff] [blame] | 209 | pw.print("chooseUpstreamAutomatically: "); |
| 210 | pw.println(chooseUpstreamAutomatically); |
markchien | 87d3f7d | 2020-01-08 20:58:23 +0800 | [diff] [blame] | 211 | pw.print("legacyPreredUpstreamIfaceTypes: "); |
| 212 | pw.println(Arrays.toString(toIntArray(preferredUpstreamIfaceTypes))); |
Erik Kline | 9db1b54 | 2017-03-16 14:10:27 +0900 | [diff] [blame] | 213 | |
Remi NGUYEN VAN | e3bb5c5 | 2018-06-12 15:57:04 +0900 | [diff] [blame] | 214 | dumpStringArray(pw, "legacyDhcpRanges", legacyDhcpRanges); |
Erik Kline | 9db1b54 | 2017-03-16 14:10:27 +0900 | [diff] [blame] | 215 | dumpStringArray(pw, "defaultIPv4DNS", defaultIPv4DNS); |
Erik Kline | e0f3403 | 2018-02-28 15:01:35 +0900 | [diff] [blame] | 216 | |
junyulai | aea13ae | 2020-04-30 15:21:55 +0800 | [diff] [blame] | 217 | pw.print("offloadPollInterval: "); |
| 218 | pw.println(mOffloadPollInterval); |
| 219 | |
Erik Kline | e0f3403 | 2018-02-28 15:01:35 +0900 | [diff] [blame] | 220 | dumpStringArray(pw, "provisioningApp", provisioningApp); |
| 221 | pw.print("provisioningAppNoUi: "); |
| 222 | pw.println(provisioningAppNoUi); |
Remi NGUYEN VAN | 9865cc1 | 2018-08-30 16:49:52 +0900 | [diff] [blame] | 223 | |
Nucca Chen | 95e0bac | 2020-05-12 11:34:28 +0000 | [diff] [blame] | 224 | pw.print("enableBpfOffload: "); |
Nucca Chen | 1c63ba3 | 2020-06-17 07:03:57 +0000 | [diff] [blame] | 225 | pw.println(mEnableBpfOffload); |
Nucca Chen | 95e0bac | 2020-05-12 11:34:28 +0000 | [diff] [blame] | 226 | |
Remi NGUYEN VAN | 9865cc1 | 2018-08-30 16:49:52 +0900 | [diff] [blame] | 227 | pw.print("enableLegacyDhcpServer: "); |
| 228 | pw.println(enableLegacyDhcpServer); |
Erik Kline | 9db1b54 | 2017-03-16 14:10:27 +0900 | [diff] [blame] | 229 | } |
| 230 | |
markchien | a6ba54d | 2019-09-03 15:58:06 +0800 | [diff] [blame] | 231 | /** Returns the string representation of this object.*/ |
Erik Kline | 6bd7453 | 2017-05-19 10:10:41 +0900 | [diff] [blame] | 232 | public String toString() { |
| 233 | final StringJoiner sj = new StringJoiner(" "); |
markchien | 986750b | 2019-12-06 15:24:53 +0800 | [diff] [blame] | 234 | sj.add(String.format("activeDataSubId:%d", activeDataSubId)); |
Erik Kline | 6bd7453 | 2017-05-19 10:10:41 +0900 | [diff] [blame] | 235 | sj.add(String.format("tetherableUsbRegexs:%s", makeString(tetherableUsbRegexs))); |
| 236 | sj.add(String.format("tetherableWifiRegexs:%s", makeString(tetherableWifiRegexs))); |
Jimmy Chen | bcd86d0 | 2019-07-15 18:03:23 +0800 | [diff] [blame] | 237 | sj.add(String.format("tetherableWifiP2pRegexs:%s", makeString(tetherableWifiP2pRegexs))); |
Erik Kline | 6bd7453 | 2017-05-19 10:10:41 +0900 | [diff] [blame] | 238 | sj.add(String.format("tetherableBluetoothRegexs:%s", |
| 239 | makeString(tetherableBluetoothRegexs))); |
| 240 | sj.add(String.format("isDunRequired:%s", isDunRequired)); |
Erik Kline | 7230290 | 2018-06-14 17:36:40 +0900 | [diff] [blame] | 241 | sj.add(String.format("chooseUpstreamAutomatically:%s", chooseUpstreamAutomatically)); |
junyulai | aea13ae | 2020-04-30 15:21:55 +0800 | [diff] [blame] | 242 | sj.add(String.format("offloadPollInterval:%d", mOffloadPollInterval)); |
Erik Kline | 6bd7453 | 2017-05-19 10:10:41 +0900 | [diff] [blame] | 243 | sj.add(String.format("preferredUpstreamIfaceTypes:%s", |
markchien | 87d3f7d | 2020-01-08 20:58:23 +0800 | [diff] [blame] | 244 | toIntArray(preferredUpstreamIfaceTypes))); |
Erik Kline | e0f3403 | 2018-02-28 15:01:35 +0900 | [diff] [blame] | 245 | sj.add(String.format("provisioningApp:%s", makeString(provisioningApp))); |
| 246 | sj.add(String.format("provisioningAppNoUi:%s", provisioningAppNoUi)); |
Nucca Chen | 1c63ba3 | 2020-06-17 07:03:57 +0000 | [diff] [blame] | 247 | sj.add(String.format("enableBpfOffload:%s", mEnableBpfOffload)); |
Remi NGUYEN VAN | 9865cc1 | 2018-08-30 16:49:52 +0900 | [diff] [blame] | 248 | sj.add(String.format("enableLegacyDhcpServer:%s", enableLegacyDhcpServer)); |
Erik Kline | 6bd7453 | 2017-05-19 10:10:41 +0900 | [diff] [blame] | 249 | return String.format("TetheringConfiguration{%s}", sj.toString()); |
| 250 | } |
| 251 | |
Erik Kline | 9db1b54 | 2017-03-16 14:10:27 +0900 | [diff] [blame] | 252 | private static void dumpStringArray(PrintWriter pw, String label, String[] values) { |
| 253 | pw.print(label); |
| 254 | pw.print(": "); |
| 255 | |
| 256 | if (values != null) { |
| 257 | final StringJoiner sj = new StringJoiner(", ", "[", "]"); |
markchien | a6ba54d | 2019-09-03 15:58:06 +0800 | [diff] [blame] | 258 | for (String value : values) sj.add(value); |
Erik Kline | 9db1b54 | 2017-03-16 14:10:27 +0900 | [diff] [blame] | 259 | pw.print(sj.toString()); |
| 260 | } else { |
| 261 | pw.print("null"); |
| 262 | } |
| 263 | |
| 264 | pw.println(); |
| 265 | } |
| 266 | |
Erik Kline | 6bd7453 | 2017-05-19 10:10:41 +0900 | [diff] [blame] | 267 | private static String makeString(String[] strings) { |
Erik Kline | e0f3403 | 2018-02-28 15:01:35 +0900 | [diff] [blame] | 268 | if (strings == null) return "null"; |
Erik Kline | 6bd7453 | 2017-05-19 10:10:41 +0900 | [diff] [blame] | 269 | final StringJoiner sj = new StringJoiner(",", "[", "]"); |
| 270 | for (String s : strings) sj.add(s); |
| 271 | return sj.toString(); |
| 272 | } |
| 273 | |
markchien | db3a236 | 2018-10-05 12:36:08 +0800 | [diff] [blame] | 274 | /** Check whether dun is required. */ |
markchien | 986750b | 2019-12-06 15:24:53 +0800 | [diff] [blame] | 275 | public static boolean checkDunRequired(Context ctx) { |
Erik Kline | 54f2f37 | 2017-05-15 21:11:47 +0900 | [diff] [blame] | 276 | final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE); |
markchien | 986750b | 2019-12-06 15:24:53 +0800 | [diff] [blame] | 277 | // TelephonyManager would uses the active data subscription, which should be the one used |
| 278 | // by tethering. |
| 279 | return (tm != null) ? tm.isTetheringApnRequired() : false; |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 280 | } |
| 281 | |
junyulai | aea13ae | 2020-04-30 15:21:55 +0800 | [diff] [blame] | 282 | public int getOffloadPollInterval() { |
| 283 | return mOffloadPollInterval; |
| 284 | } |
| 285 | |
Nucca Chen | 1c63ba3 | 2020-06-17 07:03:57 +0000 | [diff] [blame] | 286 | public boolean isBpfOffloadEnabled() { |
| 287 | return mEnableBpfOffload; |
| 288 | } |
| 289 | |
markchien | db3a236 | 2018-10-05 12:36:08 +0800 | [diff] [blame] | 290 | private static Collection<Integer> getUpstreamIfaceTypes(Resources res, boolean dunRequired) { |
markchien | da4519a | 2020-01-14 12:46:53 +0800 | [diff] [blame] | 291 | final int[] ifaceTypes = res.getIntArray(R.array.config_tether_upstream_types); |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 292 | final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length); |
| 293 | for (int i : ifaceTypes) { |
| 294 | switch (i) { |
| 295 | case TYPE_MOBILE: |
| 296 | case TYPE_MOBILE_HIPRI: |
markchien | db3a236 | 2018-10-05 12:36:08 +0800 | [diff] [blame] | 297 | if (dunRequired) continue; |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 298 | break; |
| 299 | case TYPE_MOBILE_DUN: |
markchien | db3a236 | 2018-10-05 12:36:08 +0800 | [diff] [blame] | 300 | if (!dunRequired) continue; |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 301 | break; |
| 302 | } |
| 303 | upstreamIfaceTypes.add(i); |
| 304 | } |
| 305 | |
| 306 | // Fix up upstream interface types for DUN or mobile. NOTE: independent |
markchien | db3a236 | 2018-10-05 12:36:08 +0800 | [diff] [blame] | 307 | // of the value of |dunRequired|, cell data of one form or another is |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 308 | // *always* an upstream, regardless of the upstream interface types |
| 309 | // specified by configuration resources. |
markchien | db3a236 | 2018-10-05 12:36:08 +0800 | [diff] [blame] | 310 | if (dunRequired) { |
Erik Kline | 1e54351 | 2017-03-09 11:44:11 +0900 | [diff] [blame] | 311 | appendIfNotPresent(upstreamIfaceTypes, TYPE_MOBILE_DUN); |
Jayachandran C | 5805982 | 2017-05-17 23:53:59 -0700 | [diff] [blame] | 312 | } else { |
Jayachandran C | 5805982 | 2017-05-17 23:53:59 -0700 | [diff] [blame] | 313 | // Do not modify if a cellular interface type is already present in the |
| 314 | // upstream interface types. Add TYPE_MOBILE and TYPE_MOBILE_HIPRI if no |
| 315 | // cellular interface types are found in the upstream interface types. |
markchien | db3a236 | 2018-10-05 12:36:08 +0800 | [diff] [blame] | 316 | // This preserves backwards compatibility and prevents the DUN and default |
| 317 | // mobile types incorrectly appearing together, which could happen on |
| 318 | // previous releases in the common case where checkDunRequired returned |
| 319 | // DUN_UNSPECIFIED. |
| 320 | if (!containsOneOf(upstreamIfaceTypes, TYPE_MOBILE, TYPE_MOBILE_HIPRI)) { |
Jayachandran C | 5805982 | 2017-05-17 23:53:59 -0700 | [diff] [blame] | 321 | upstreamIfaceTypes.add(TYPE_MOBILE); |
| 322 | upstreamIfaceTypes.add(TYPE_MOBILE_HIPRI); |
| 323 | } |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 324 | } |
| 325 | |
Erik Kline | 1e54351 | 2017-03-09 11:44:11 +0900 | [diff] [blame] | 326 | // Always make sure our good friend Ethernet is present. |
| 327 | // TODO: consider unilaterally forcing this at the front. |
| 328 | prependIfNotPresent(upstreamIfaceTypes, TYPE_ETHERNET); |
| 329 | |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 330 | return upstreamIfaceTypes; |
| 331 | } |
| 332 | |
| 333 | private static boolean matchesDownstreamRegexs(String iface, String[] regexs) { |
| 334 | for (String regex : regexs) { |
| 335 | if (iface.matches(regex)) return true; |
| 336 | } |
| 337 | return false; |
| 338 | } |
| 339 | |
markchien | 0b59507 | 2019-01-08 23:52:21 +0800 | [diff] [blame] | 340 | private static String[] getLegacyDhcpRanges(Resources res) { |
markchien | da4519a | 2020-01-14 12:46:53 +0800 | [diff] [blame] | 341 | final String[] fromResource = getResourceStringArray(res, R.array.config_tether_dhcp_range); |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 342 | if ((fromResource.length > 0) && (fromResource.length % 2 == 0)) { |
| 343 | return fromResource; |
| 344 | } |
Remi NGUYEN VAN | e3bb5c5 | 2018-06-12 15:57:04 +0900 | [diff] [blame] | 345 | return copy(LEGACY_DHCP_DEFAULT_RANGE); |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 346 | } |
| 347 | |
Mark Chien | 5b0fdf6 | 2020-06-12 17:35:18 +0000 | [diff] [blame] | 348 | private static String getResourceString(Resources res, final int resId) { |
Erik Kline | e0f3403 | 2018-02-28 15:01:35 +0900 | [diff] [blame] | 349 | try { |
Mark Chien | 5b0fdf6 | 2020-06-12 17:35:18 +0000 | [diff] [blame] | 350 | return res.getString(resId); |
Erik Kline | e0f3403 | 2018-02-28 15:01:35 +0900 | [diff] [blame] | 351 | } catch (Resources.NotFoundException e) { |
| 352 | return ""; |
| 353 | } |
| 354 | } |
| 355 | |
Nucca Chen | 95e0bac | 2020-05-12 11:34:28 +0000 | [diff] [blame] | 356 | private static boolean getResourceBoolean(Resources res, int resId, boolean defaultValue) { |
Erik Kline | 7230290 | 2018-06-14 17:36:40 +0900 | [diff] [blame] | 357 | try { |
markchien | 0b59507 | 2019-01-08 23:52:21 +0800 | [diff] [blame] | 358 | return res.getBoolean(resId); |
Erik Kline | 7230290 | 2018-06-14 17:36:40 +0900 | [diff] [blame] | 359 | } catch (Resources.NotFoundException e404) { |
Nucca Chen | 95e0bac | 2020-05-12 11:34:28 +0000 | [diff] [blame] | 360 | return defaultValue; |
Erik Kline | 7230290 | 2018-06-14 17:36:40 +0900 | [diff] [blame] | 361 | } |
| 362 | } |
| 363 | |
markchien | 0b59507 | 2019-01-08 23:52:21 +0800 | [diff] [blame] | 364 | private static String[] getResourceStringArray(Resources res, int resId) { |
Erik Kline | e0f3403 | 2018-02-28 15:01:35 +0900 | [diff] [blame] | 365 | try { |
markchien | 0b59507 | 2019-01-08 23:52:21 +0800 | [diff] [blame] | 366 | final String[] strArray = res.getStringArray(resId); |
Erik Kline | e0f3403 | 2018-02-28 15:01:35 +0900 | [diff] [blame] | 367 | return (strArray != null) ? strArray : EMPTY_STRING_ARRAY; |
| 368 | } catch (Resources.NotFoundException e404) { |
| 369 | return EMPTY_STRING_ARRAY; |
| 370 | } |
| 371 | } |
| 372 | |
markchien | 3b51963 | 2018-09-07 16:19:12 +0800 | [diff] [blame] | 373 | private static int getResourceInteger(Resources res, int resId, int defaultValue) { |
| 374 | try { |
| 375 | return res.getInteger(resId); |
| 376 | } catch (Resources.NotFoundException e404) { |
| 377 | return defaultValue; |
| 378 | } |
| 379 | } |
| 380 | |
Nucca Chen | 95e0bac | 2020-05-12 11:34:28 +0000 | [diff] [blame] | 381 | private boolean getEnableBpfOffload(final Resources res) { |
| 382 | // Get BPF offload config |
| 383 | // Priority 1: Device config |
| 384 | // Priority 2: Resource config |
| 385 | // Priority 3: Default value |
Treehugger Robot | ddc32f6 | 2020-05-14 16:33:30 +0000 | [diff] [blame] | 386 | final boolean defaultValue = getResourceBoolean( |
Nucca Chen | 95e0bac | 2020-05-12 11:34:28 +0000 | [diff] [blame] | 387 | res, R.bool.config_tether_enable_bpf_offload, true /** default value */); |
| 388 | |
Treehugger Robot | ddc32f6 | 2020-05-14 16:33:30 +0000 | [diff] [blame] | 389 | return getDeviceConfigBoolean(OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD, defaultValue); |
Nucca Chen | 95e0bac | 2020-05-12 11:34:28 +0000 | [diff] [blame] | 390 | } |
| 391 | |
markchien | 2dfee02 | 2020-01-13 16:09:42 +0800 | [diff] [blame] | 392 | private boolean getEnableLegacyDhcpServer(final Resources res) { |
Nucca Chen | 95e0bac | 2020-05-12 11:34:28 +0000 | [diff] [blame] | 393 | return getResourceBoolean( |
Treehugger Robot | ddc32f6 | 2020-05-14 16:33:30 +0000 | [diff] [blame] | 394 | res, R.bool.config_tether_enable_legacy_dhcp_server, false /** defaultValue */) |
| 395 | || getDeviceConfigBoolean( |
| 396 | TETHER_ENABLE_LEGACY_DHCP_SERVER, false /** defaultValue */); |
| 397 | } |
| 398 | |
| 399 | private boolean getDeviceConfigBoolean(final String name, final boolean defaultValue) { |
| 400 | // Due to the limitation of static mock for testing, using #getDeviceConfigProperty instead |
| 401 | // of DeviceConfig#getBoolean. If using #getBoolean here, the test can't know that the |
| 402 | // returned boolean value comes from device config or default value (because of null |
| 403 | // property string). See the test case testBpfOffload{*} in TetheringConfigurationTest.java. |
| 404 | final String value = getDeviceConfigProperty(name); |
| 405 | return value != null ? Boolean.parseBoolean(value) : defaultValue; |
markchien | 2dfee02 | 2020-01-13 16:09:42 +0800 | [diff] [blame] | 406 | } |
| 407 | |
| 408 | @VisibleForTesting |
Treehugger Robot | ddc32f6 | 2020-05-14 16:33:30 +0000 | [diff] [blame] | 409 | protected String getDeviceConfigProperty(String name) { |
| 410 | return DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, name); |
Remi NGUYEN VAN | e3bb5c5 | 2018-06-12 15:57:04 +0900 | [diff] [blame] | 411 | } |
| 412 | |
markchien | 0b59507 | 2019-01-08 23:52:21 +0800 | [diff] [blame] | 413 | private Resources getResources(Context ctx, int subId) { |
| 414 | if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| 415 | return getResourcesForSubIdWrapper(ctx, subId); |
| 416 | } else { |
| 417 | return ctx.getResources(); |
| 418 | } |
| 419 | } |
| 420 | |
| 421 | @VisibleForTesting |
| 422 | protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) { |
| 423 | return SubscriptionManager.getResourcesForSubId(ctx, subId); |
| 424 | } |
| 425 | |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 426 | private static String[] copy(String[] strarray) { |
| 427 | return Arrays.copyOf(strarray, strarray.length); |
| 428 | } |
Erik Kline | 1e54351 | 2017-03-09 11:44:11 +0900 | [diff] [blame] | 429 | |
| 430 | private static void prependIfNotPresent(ArrayList<Integer> list, int value) { |
| 431 | if (list.contains(value)) return; |
| 432 | list.add(0, value); |
| 433 | } |
| 434 | |
| 435 | private static void appendIfNotPresent(ArrayList<Integer> list, int value) { |
| 436 | if (list.contains(value)) return; |
| 437 | list.add(value); |
| 438 | } |
| 439 | |
| 440 | private static boolean containsOneOf(ArrayList<Integer> list, Integer... values) { |
| 441 | for (Integer value : values) { |
| 442 | if (list.contains(value)) return true; |
| 443 | } |
| 444 | return false; |
| 445 | } |
markchien | 0df2ebc4 | 2019-09-30 14:40:57 +0800 | [diff] [blame] | 446 | |
markchien | 87d3f7d | 2020-01-08 20:58:23 +0800 | [diff] [blame] | 447 | private static int[] toIntArray(Collection<Integer> values) { |
| 448 | final int[] result = new int[values.size()]; |
| 449 | int index = 0; |
| 450 | for (Integer value : values) { |
| 451 | result[index++] = value; |
| 452 | } |
| 453 | return result; |
| 454 | } |
| 455 | |
markchien | 0df2ebc4 | 2019-09-30 14:40:57 +0800 | [diff] [blame] | 456 | /** |
| 457 | * Convert this TetheringConfiguration to a TetheringConfigurationParcel. |
| 458 | */ |
| 459 | public TetheringConfigurationParcel toStableParcelable() { |
| 460 | final TetheringConfigurationParcel parcel = new TetheringConfigurationParcel(); |
markchien | 986750b | 2019-12-06 15:24:53 +0800 | [diff] [blame] | 461 | parcel.subId = activeDataSubId; |
markchien | 0df2ebc4 | 2019-09-30 14:40:57 +0800 | [diff] [blame] | 462 | parcel.tetherableUsbRegexs = tetherableUsbRegexs; |
| 463 | parcel.tetherableWifiRegexs = tetherableWifiRegexs; |
| 464 | parcel.tetherableBluetoothRegexs = tetherableBluetoothRegexs; |
| 465 | parcel.isDunRequired = isDunRequired; |
| 466 | parcel.chooseUpstreamAutomatically = chooseUpstreamAutomatically; |
| 467 | |
markchien | 87d3f7d | 2020-01-08 20:58:23 +0800 | [diff] [blame] | 468 | parcel.preferredUpstreamIfaceTypes = toIntArray(preferredUpstreamIfaceTypes); |
markchien | 0df2ebc4 | 2019-09-30 14:40:57 +0800 | [diff] [blame] | 469 | |
| 470 | parcel.legacyDhcpRanges = legacyDhcpRanges; |
| 471 | parcel.defaultIPv4DNS = defaultIPv4DNS; |
| 472 | parcel.enableLegacyDhcpServer = enableLegacyDhcpServer; |
| 473 | parcel.provisioningApp = provisioningApp; |
| 474 | parcel.provisioningAppNoUi = provisioningAppNoUi; |
| 475 | parcel.provisioningCheckPeriod = provisioningCheckPeriod; |
| 476 | return parcel; |
| 477 | } |
Erik Kline | 79868f8 | 2017-01-21 14:33:56 +0900 | [diff] [blame] | 478 | } |