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 17 package com.android.networkstack.tethering; 18 19 import static android.content.Context.TELEPHONY_SERVICE; 20 import static android.net.ConnectivityManager.TYPE_ETHERNET; 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; 24 import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; 25 import static android.provider.DeviceConfig.NAMESPACE_TETHERING; 26 27 import static com.android.net.module.util.DeviceConfigUtils.TETHERING_MODULE_NAME; 28 import static com.android.networkstack.apishim.ConstantsShim.KEY_CARRIER_SUPPORTS_TETHERING_BOOL; 29 30 import android.content.ContentResolver; 31 import android.content.Context; 32 import android.content.res.Resources; 33 import android.net.TetheringConfigurationParcel; 34 import android.os.PersistableBundle; 35 import android.provider.DeviceConfig; 36 import android.provider.Settings; 37 import android.telephony.CarrierConfigManager; 38 import android.telephony.SubscriptionManager; 39 import android.telephony.TelephonyManager; 40 import android.text.TextUtils; 41 42 import androidx.annotation.NonNull; 43 44 import com.android.internal.annotations.VisibleForTesting; 45 import com.android.modules.utils.build.SdkLevel; 46 import com.android.net.module.util.DeviceConfigUtils; 47 import com.android.net.module.util.SharedLog; 48 49 import java.io.PrintWriter; 50 import java.util.ArrayList; 51 import java.util.Arrays; 52 import java.util.Collection; 53 import java.util.StringJoiner; 54 55 /** 56 * A utility class to encapsulate the various tethering configuration elements. 57 * 58 * This configuration data includes elements describing upstream properties 59 * (preferred and required types of upstream connectivity as well as default 60 * DNS servers to use if none are available) and downstream properties (such 61 * as regular expressions use to match suitable downstream interfaces and the 62 * DHCPv4 ranges to use). 63 * 64 * @hide 65 */ 66 public class TetheringConfiguration { 67 private static final String TAG = TetheringConfiguration.class.getSimpleName(); 68 69 private static final String[] EMPTY_STRING_ARRAY = new String[0]; 70 71 // Default ranges used for the legacy DHCP server. 72 // USB is 192.168.42.1 and 255.255.255.0 73 // Wifi is 192.168.43.1 and 255.255.255.0 74 // BT is limited to max default of 5 connections. 192.168.44.1 to 192.168.48.1 75 // with 255.255.255.0 76 // P2P is 192.168.49.1 and 255.255.255.0 77 private static final String[] LEGACY_DHCP_DEFAULT_RANGE = { 78 "192.168.42.2", "192.168.42.254", "192.168.43.2", "192.168.43.254", 79 "192.168.44.2", "192.168.44.254", "192.168.45.2", "192.168.45.254", 80 "192.168.46.2", "192.168.46.254", "192.168.47.2", "192.168.47.254", 81 "192.168.48.2", "192.168.48.254", "192.168.49.2", "192.168.49.254", 82 }; 83 84 private static final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"}; 85 86 @VisibleForTesting 87 public static final int TETHER_USB_RNDIS_FUNCTION = 0; 88 89 @VisibleForTesting 90 public static final int TETHER_USB_NCM_FUNCTION = 1; 91 92 /** 93 * Override enabling BPF offload configuration for tethering. 94 */ 95 public static final String OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD = 96 "override_tether_enable_bpf_offload"; 97 98 /** 99 * Use the old dnsmasq DHCP server for tethering instead of the framework implementation. 100 */ 101 public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER = 102 "tether_enable_legacy_dhcp_server"; 103 104 public static final String USE_LEGACY_WIFI_P2P_DEDICATED_IP = 105 "use_legacy_wifi_p2p_dedicated_ip"; 106 107 /** 108 * Experiment flag to force choosing upstreams automatically. 109 * 110 * This setting is intended to help force-enable the feature on OEM devices that disabled it 111 * via resource overlays, and later noticed issues. To that end, it overrides 112 * config_tether_upstream_automatic when set to true. 113 * 114 * This flag is enabled if !=0 and less than the module APEX version: see 115 * {@link DeviceConfigUtils#isFeatureEnabled}. It is also ignored after R, as later devices 116 * should just set config_tether_upstream_automatic to true instead. 117 */ 118 public static final String TETHER_FORCE_UPSTREAM_AUTOMATIC_VERSION = 119 "tether_force_upstream_automatic_version"; 120 121 /** 122 * Settings key to foce choosing usb functions for usb tethering. 123 * 124 * TODO: Remove this hard code string and make Settings#TETHER_FORCE_USB_FUNCTIONS as API. 125 */ 126 public static final String TETHER_FORCE_USB_FUNCTIONS = 127 "tether_force_usb_functions"; 128 129 /** 130 * Experiment flag to enable TETHERING_WEAR. 131 */ 132 public static final String TETHER_ENABLE_WEAR_TETHERING = 133 "tether_enable_wear_tethering"; 134 135 /** 136 * Default value that used to periodic polls tether offload stats from tethering offload HAL 137 * to make the data warnings work. 138 */ 139 public static final int DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS = 5000; 140 141 public final String[] tetherableUsbRegexs; 142 public final String[] tetherableWifiRegexs; 143 public final String[] tetherableWigigRegexs; 144 public final String[] tetherableWifiP2pRegexs; 145 public final String[] tetherableBluetoothRegexs; 146 public final String[] tetherableNcmRegexs; 147 public final boolean isDunRequired; 148 public final boolean chooseUpstreamAutomatically; 149 public final Collection<Integer> preferredUpstreamIfaceTypes; 150 public final String[] legacyDhcpRanges; 151 public final String[] defaultIPv4DNS; 152 153 public final String[] provisioningApp; 154 public final String provisioningAppNoUi; 155 public final int provisioningCheckPeriod; 156 public final String provisioningResponse; 157 158 public final boolean isCarrierSupportTethering; 159 public final boolean isCarrierConfigAffirmsEntitlementCheckRequired; 160 161 public final int activeDataSubId; 162 163 private final Dependencies mDeps; 164 165 private final boolean mEnableLegacyDhcpServer; 166 private final int mOffloadPollInterval; 167 // TODO: Add to TetheringConfigurationParcel if required. 168 private final boolean mEnableBpfOffload; 169 private final boolean mEnableWifiP2pDedicatedIp; 170 private final int mP2pLeasesSubnetPrefixLength; 171 172 private final boolean mEnableWearTethering; 173 174 private final int mUsbTetheringFunction; 175 protected final ContentResolver mContentResolver; 176 177 /** 178 * A class wrapping dependencies of {@link TetheringConfiguration}, useful for testing. 179 */ 180 @VisibleForTesting 181 public static class Dependencies { isFeatureEnabled(@onNull Context context, @NonNull String namespace, @NonNull String name, @NonNull String moduleName, boolean defaultEnabled)182 boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace, 183 @NonNull String name, @NonNull String moduleName, boolean defaultEnabled) { 184 return DeviceConfigUtils.isFeatureEnabled(context, namespace, name, 185 moduleName, defaultEnabled); 186 } 187 getDeviceConfigBoolean(@onNull String namespace, @NonNull String name, boolean defaultValue)188 boolean getDeviceConfigBoolean(@NonNull String namespace, @NonNull String name, 189 boolean defaultValue) { 190 return DeviceConfig.getBoolean(namespace, name, defaultValue); 191 } 192 } 193 TetheringConfiguration(@onNull Context ctx, @NonNull SharedLog log, int id)194 public TetheringConfiguration(@NonNull Context ctx, @NonNull SharedLog log, int id) { 195 this(ctx, log, id, new Dependencies()); 196 } 197 198 @VisibleForTesting TetheringConfiguration(@onNull Context ctx, @NonNull SharedLog log, int id, @NonNull Dependencies deps)199 public TetheringConfiguration(@NonNull Context ctx, @NonNull SharedLog log, int id, 200 @NonNull Dependencies deps) { 201 mDeps = deps; 202 final SharedLog configLog = log.forSubComponent("config"); 203 204 activeDataSubId = id; 205 Resources res = getResources(ctx, activeDataSubId); 206 mContentResolver = ctx.getContentResolver(); 207 208 mUsbTetheringFunction = getUsbTetheringFunction(res); 209 210 final String[] ncmRegexs = getResourceStringArray(res, R.array.config_tether_ncm_regexs); 211 // If usb tethering use NCM and config_tether_ncm_regexs is not empty, use 212 // config_tether_ncm_regexs for tetherableUsbRegexs. 213 if (isUsingNcm() && (ncmRegexs.length != 0)) { 214 tetherableUsbRegexs = ncmRegexs; 215 tetherableNcmRegexs = EMPTY_STRING_ARRAY; 216 } else { 217 tetherableUsbRegexs = getResourceStringArray(res, R.array.config_tether_usb_regexs); 218 tetherableNcmRegexs = ncmRegexs; 219 } 220 // TODO: Evaluate deleting this altogether now that Wi-Fi always passes 221 // us an interface name. Careful consideration needs to be given to 222 // implications for Settings and for provisioning checks. 223 tetherableWifiRegexs = getResourceStringArray(res, R.array.config_tether_wifi_regexs); 224 // TODO: Remove entire wigig code once tethering module no longer support R devices. 225 tetherableWigigRegexs = SdkLevel.isAtLeastS() 226 ? new String[0] : getResourceStringArray(res, R.array.config_tether_wigig_regexs); 227 tetherableWifiP2pRegexs = getResourceStringArray( 228 res, R.array.config_tether_wifi_p2p_regexs); 229 tetherableBluetoothRegexs = getResourceStringArray( 230 res, R.array.config_tether_bluetooth_regexs); 231 232 isDunRequired = checkDunRequired(ctx); 233 234 // Here is how automatic mode enable/disable support on different Android version: 235 // - R : can be enabled/disabled by resource config_tether_upstream_automatic. 236 // but can be force-enabled by flag TETHER_FORCE_UPSTREAM_AUTOMATIC_VERSION. 237 // - S, T: can be enabled/disabled by resource config_tether_upstream_automatic. 238 // - U+ : automatic mode only. 239 final boolean forceAutomaticUpstream = SdkLevel.isAtLeastU() || (!SdkLevel.isAtLeastS() 240 && isConnectivityFeatureEnabled(ctx, TETHER_FORCE_UPSTREAM_AUTOMATIC_VERSION)); 241 chooseUpstreamAutomatically = forceAutomaticUpstream || getResourceBoolean( 242 res, R.bool.config_tether_upstream_automatic, false /** defaultValue */); 243 preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, isDunRequired); 244 245 legacyDhcpRanges = getLegacyDhcpRanges(res); 246 defaultIPv4DNS = copy(DEFAULT_IPV4_DNS); 247 mEnableBpfOffload = getEnableBpfOffload(res); 248 mEnableLegacyDhcpServer = getEnableLegacyDhcpServer(res); 249 250 provisioningApp = getResourceStringArray(res, R.array.config_mobile_hotspot_provision_app); 251 provisioningAppNoUi = getResourceString(res, 252 R.string.config_mobile_hotspot_provision_app_no_ui); 253 provisioningCheckPeriod = getResourceInteger(res, 254 R.integer.config_mobile_hotspot_provision_check_period, 255 0 /* No periodic re-check */); 256 provisioningResponse = getResourceString(res, 257 R.string.config_mobile_hotspot_provision_response); 258 259 PersistableBundle carrierConfigs = getCarrierConfig(ctx, activeDataSubId); 260 isCarrierSupportTethering = carrierConfigAffirmsCarrierSupport(carrierConfigs); 261 isCarrierConfigAffirmsEntitlementCheckRequired = 262 carrierConfigAffirmsEntitlementCheckRequired(carrierConfigs); 263 264 mOffloadPollInterval = getResourceInteger(res, 265 R.integer.config_tether_offload_poll_interval, 266 DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS); 267 268 mEnableWifiP2pDedicatedIp = getResourceBoolean(res, 269 R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip, 270 false /* defaultValue */); 271 272 mP2pLeasesSubnetPrefixLength = getP2pLeasesSubnetPrefixLengthFromRes(res, configLog); 273 274 mEnableWearTethering = shouldEnableWearTethering(ctx); 275 276 configLog.log(toString()); 277 } 278 getP2pLeasesSubnetPrefixLengthFromRes(final Resources res, final SharedLog log)279 private int getP2pLeasesSubnetPrefixLengthFromRes(final Resources res, final SharedLog log) { 280 if (!mEnableWifiP2pDedicatedIp) return 0; 281 282 int prefixLength = getResourceInteger(res, 283 R.integer.config_p2p_leases_subnet_prefix_length, 0 /* default value */); 284 285 // DhcpLeaseRepository ignores the first and last addresses of the range so the max prefix 286 // length is 30. 287 if (prefixLength < 0 || prefixLength > 30) { 288 log.e("Invalid p2p leases subnet prefix length configuration: " + prefixLength); 289 return 0; 290 } 291 292 return prefixLength; 293 } 294 295 /** Check whether using legacy dhcp server. */ useLegacyDhcpServer()296 public boolean useLegacyDhcpServer() { 297 return mEnableLegacyDhcpServer; 298 } 299 300 /** Check whether using ncm for usb tethering */ isUsingNcm()301 public boolean isUsingNcm() { 302 return mUsbTetheringFunction == TETHER_USB_NCM_FUNCTION; 303 } 304 305 /** Check whether input interface belong to usb.*/ isUsb(String iface)306 public boolean isUsb(String iface) { 307 return matchesDownstreamRegexs(iface, tetherableUsbRegexs); 308 } 309 310 /** Check whether input interface belong to wifi.*/ isWifi(String iface)311 public boolean isWifi(String iface) { 312 return matchesDownstreamRegexs(iface, tetherableWifiRegexs); 313 } 314 315 /** Check whether input interface belong to wigig.*/ isWigig(String iface)316 public boolean isWigig(String iface) { 317 return matchesDownstreamRegexs(iface, tetherableWigigRegexs); 318 } 319 320 /** Check whether this interface is Wifi P2P interface. */ isWifiP2p(String iface)321 public boolean isWifiP2p(String iface) { 322 return matchesDownstreamRegexs(iface, tetherableWifiP2pRegexs); 323 } 324 325 /** Check whether using legacy mode for wifi P2P. */ isWifiP2pLegacyTetheringMode()326 public boolean isWifiP2pLegacyTetheringMode() { 327 return (tetherableWifiP2pRegexs == null || tetherableWifiP2pRegexs.length == 0); 328 } 329 330 /** Check whether input interface belong to bluetooth.*/ isBluetooth(String iface)331 public boolean isBluetooth(String iface) { 332 return matchesDownstreamRegexs(iface, tetherableBluetoothRegexs); 333 } 334 335 /** Check if interface is ncm */ isNcm(String iface)336 public boolean isNcm(String iface) { 337 return matchesDownstreamRegexs(iface, tetherableNcmRegexs); 338 } 339 340 /** Check whether no ui entitlement application is available.*/ hasMobileHotspotProvisionApp()341 public boolean hasMobileHotspotProvisionApp() { 342 return !TextUtils.isEmpty(provisioningAppNoUi); 343 } 344 345 /** Check whether dedicated wifi p2p address is enabled. */ shouldEnableWifiP2pDedicatedIp()346 public boolean shouldEnableWifiP2pDedicatedIp() { 347 return mEnableWifiP2pDedicatedIp; 348 } 349 350 /** 351 * Get subnet prefix length of dhcp leases for wifi p2p. 352 * This feature only support when wifi p2p use dedicated address. If 353 * #shouldEnableWifiP2pDedicatedIp is false, this method would always return 0. 354 */ getP2pLeasesSubnetPrefixLength()355 public int getP2pLeasesSubnetPrefixLength() { 356 return mP2pLeasesSubnetPrefixLength; 357 } 358 359 /** Returns true if wearable device tethering is enabled. */ isWearTetheringEnabled()360 public boolean isWearTetheringEnabled() { 361 return mEnableWearTethering; 362 } 363 364 /** Does the dumping.*/ dump(PrintWriter pw)365 public void dump(PrintWriter pw) { 366 pw.print("activeDataSubId: "); 367 pw.println(activeDataSubId); 368 369 dumpStringArray(pw, "tetherableUsbRegexs", tetherableUsbRegexs); 370 dumpStringArray(pw, "tetherableWifiRegexs", tetherableWifiRegexs); 371 dumpStringArray(pw, "tetherableWifiP2pRegexs", tetherableWifiP2pRegexs); 372 dumpStringArray(pw, "tetherableBluetoothRegexs", tetherableBluetoothRegexs); 373 dumpStringArray(pw, "tetherableNcmRegexs", tetherableNcmRegexs); 374 375 pw.print("isDunRequired: "); 376 pw.println(isDunRequired); 377 378 pw.print("chooseUpstreamAutomatically: "); 379 pw.println(chooseUpstreamAutomatically); 380 pw.print("legacyPreredUpstreamIfaceTypes: "); 381 pw.println(Arrays.toString(toIntArray(preferredUpstreamIfaceTypes))); 382 383 dumpStringArray(pw, "legacyDhcpRanges", legacyDhcpRanges); 384 dumpStringArray(pw, "defaultIPv4DNS", defaultIPv4DNS); 385 386 pw.print("offloadPollInterval: "); 387 pw.println(mOffloadPollInterval); 388 389 dumpStringArray(pw, "provisioningApp", provisioningApp); 390 pw.print("provisioningAppNoUi: "); 391 pw.println(provisioningAppNoUi); 392 393 pw.println("isCarrierSupportTethering: " + isCarrierSupportTethering); 394 pw.println("isCarrierConfigAffirmsEntitlementCheckRequired: " 395 + isCarrierConfigAffirmsEntitlementCheckRequired); 396 397 pw.print("enableBpfOffload: "); 398 pw.println(mEnableBpfOffload); 399 400 pw.print("enableLegacyDhcpServer: "); 401 pw.println(mEnableLegacyDhcpServer); 402 403 pw.print("enableWifiP2pDedicatedIp: "); 404 pw.println(mEnableWifiP2pDedicatedIp); 405 406 pw.print("p2pLeasesSubnetPrefixLength: "); 407 pw.println(mP2pLeasesSubnetPrefixLength); 408 409 pw.print("enableWearTethering: "); 410 pw.println(mEnableWearTethering); 411 412 pw.print("mUsbTetheringFunction: "); 413 pw.println(isUsingNcm() ? "NCM" : "RNDIS"); 414 } 415 416 /** Returns the string representation of this object.*/ toString()417 public String toString() { 418 final StringJoiner sj = new StringJoiner(" "); 419 sj.add(String.format("activeDataSubId:%d", activeDataSubId)); 420 sj.add(String.format("tetherableUsbRegexs:%s", makeString(tetherableUsbRegexs))); 421 sj.add(String.format("tetherableWifiRegexs:%s", makeString(tetherableWifiRegexs))); 422 sj.add(String.format("tetherableWifiP2pRegexs:%s", makeString(tetherableWifiP2pRegexs))); 423 sj.add(String.format("tetherableBluetoothRegexs:%s", 424 makeString(tetherableBluetoothRegexs))); 425 sj.add(String.format("isDunRequired:%s", isDunRequired)); 426 sj.add(String.format("chooseUpstreamAutomatically:%s", chooseUpstreamAutomatically)); 427 sj.add(String.format("offloadPollInterval:%d", mOffloadPollInterval)); 428 sj.add(String.format("preferredUpstreamIfaceTypes:%s", 429 toIntArray(preferredUpstreamIfaceTypes))); 430 sj.add(String.format("provisioningApp:%s", makeString(provisioningApp))); 431 sj.add(String.format("provisioningAppNoUi:%s", provisioningAppNoUi)); 432 sj.add(String.format("isCarrierSupportTethering:%s", isCarrierSupportTethering)); 433 sj.add(String.format("isCarrierConfigAffirmsEntitlementCheckRequired:%s", 434 isCarrierConfigAffirmsEntitlementCheckRequired)); 435 sj.add(String.format("enableBpfOffload:%s", mEnableBpfOffload)); 436 sj.add(String.format("enableLegacyDhcpServer:%s", mEnableLegacyDhcpServer)); 437 sj.add(String.format("enableWearTethering:%s", mEnableWearTethering)); 438 return String.format("TetheringConfiguration{%s}", sj.toString()); 439 } 440 dumpStringArray(PrintWriter pw, String label, String[] values)441 private static void dumpStringArray(PrintWriter pw, String label, String[] values) { 442 pw.print(label); 443 pw.print(": "); 444 445 if (values != null) { 446 final StringJoiner sj = new StringJoiner(", ", "[", "]"); 447 for (String value : values) sj.add(value); 448 pw.print(sj.toString()); 449 } else { 450 pw.print("null"); 451 } 452 453 pw.println(); 454 } 455 makeString(String[] strings)456 private static String makeString(String[] strings) { 457 if (strings == null) return "null"; 458 final StringJoiner sj = new StringJoiner(",", "[", "]"); 459 for (String s : strings) sj.add(s); 460 return sj.toString(); 461 } 462 463 /** Check whether dun is required. */ checkDunRequired(Context ctx)464 public static boolean checkDunRequired(Context ctx) { 465 final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE); 466 // TelephonyManager would uses the active data subscription, which should be the one used 467 // by tethering. 468 return (tm != null) ? tm.isTetheringApnRequired() : false; 469 } 470 getOffloadPollInterval()471 public int getOffloadPollInterval() { 472 return mOffloadPollInterval; 473 } 474 isBpfOffloadEnabled()475 public boolean isBpfOffloadEnabled() { 476 return mEnableBpfOffload; 477 } 478 getUsbTetheringFunction(Resources res)479 private int getUsbTetheringFunction(Resources res) { 480 final int valueFromRes = getResourceInteger(res, R.integer.config_tether_usb_functions, 481 TETHER_USB_RNDIS_FUNCTION /* defaultValue */); 482 return getSettingsIntValue(TETHER_FORCE_USB_FUNCTIONS, valueFromRes); 483 } 484 getSettingsIntValue(final String name, final int defaultValue)485 private int getSettingsIntValue(final String name, final int defaultValue) { 486 final String value = getSettingsValue(name); 487 try { 488 return value != null ? Integer.parseInt(value) : defaultValue; 489 } catch (NumberFormatException e) { 490 return defaultValue; 491 } 492 } 493 494 @VisibleForTesting getSettingsValue(final String name)495 protected String getSettingsValue(final String name) { 496 return Settings.Global.getString(mContentResolver, name); 497 } 498 getUpstreamIfaceTypes(Resources res, boolean dunRequired)499 private static Collection<Integer> getUpstreamIfaceTypes(Resources res, boolean dunRequired) { 500 final int[] ifaceTypes = res.getIntArray(R.array.config_tether_upstream_types); 501 final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length); 502 for (int i : ifaceTypes) { 503 switch (i) { 504 case TYPE_MOBILE: 505 case TYPE_MOBILE_HIPRI: 506 if (dunRequired) continue; 507 break; 508 case TYPE_MOBILE_DUN: 509 if (!dunRequired) continue; 510 break; 511 } 512 upstreamIfaceTypes.add(i); 513 } 514 515 // Fix up upstream interface types for DUN or mobile. NOTE: independent 516 // of the value of |dunRequired|, cell data of one form or another is 517 // *always* an upstream, regardless of the upstream interface types 518 // specified by configuration resources. 519 if (dunRequired) { 520 appendIfNotPresent(upstreamIfaceTypes, TYPE_MOBILE_DUN); 521 } else { 522 // Do not modify if a cellular interface type is already present in the 523 // upstream interface types. Add TYPE_MOBILE and TYPE_MOBILE_HIPRI if no 524 // cellular interface types are found in the upstream interface types. 525 // This preserves backwards compatibility and prevents the DUN and default 526 // mobile types incorrectly appearing together, which could happen on 527 // previous releases in the common case where checkDunRequired returned 528 // DUN_UNSPECIFIED. 529 if (!containsOneOf(upstreamIfaceTypes, TYPE_MOBILE, TYPE_MOBILE_HIPRI)) { 530 upstreamIfaceTypes.add(TYPE_MOBILE); 531 upstreamIfaceTypes.add(TYPE_MOBILE_HIPRI); 532 } 533 } 534 535 // Always make sure our good friend Ethernet is present. 536 // TODO: consider unilaterally forcing this at the front. 537 prependIfNotPresent(upstreamIfaceTypes, TYPE_ETHERNET); 538 539 return upstreamIfaceTypes; 540 } 541 matchesDownstreamRegexs(String iface, String[] regexs)542 private static boolean matchesDownstreamRegexs(String iface, String[] regexs) { 543 for (String regex : regexs) { 544 if (iface.matches(regex)) return true; 545 } 546 return false; 547 } 548 getLegacyDhcpRanges(Resources res)549 private static String[] getLegacyDhcpRanges(Resources res) { 550 final String[] fromResource = getResourceStringArray(res, R.array.config_tether_dhcp_range); 551 if ((fromResource.length > 0) && (fromResource.length % 2 == 0)) { 552 return fromResource; 553 } 554 return copy(LEGACY_DHCP_DEFAULT_RANGE); 555 } 556 getResourceString(Resources res, final int resId)557 private static String getResourceString(Resources res, final int resId) { 558 try { 559 return res.getString(resId); 560 } catch (Resources.NotFoundException e) { 561 return ""; 562 } 563 } 564 getResourceBoolean(Resources res, int resId, boolean defaultValue)565 private static boolean getResourceBoolean(Resources res, int resId, boolean defaultValue) { 566 try { 567 return res.getBoolean(resId); 568 } catch (Resources.NotFoundException e404) { 569 return defaultValue; 570 } 571 } 572 getResourceStringArray(Resources res, int resId)573 private static String[] getResourceStringArray(Resources res, int resId) { 574 try { 575 final String[] strArray = res.getStringArray(resId); 576 return (strArray != null) ? strArray : EMPTY_STRING_ARRAY; 577 } catch (Resources.NotFoundException e404) { 578 return EMPTY_STRING_ARRAY; 579 } 580 } 581 getResourceInteger(Resources res, int resId, int defaultValue)582 private static int getResourceInteger(Resources res, int resId, int defaultValue) { 583 try { 584 return res.getInteger(resId); 585 } catch (Resources.NotFoundException e404) { 586 return defaultValue; 587 } 588 } 589 getEnableBpfOffload(final Resources res)590 private boolean getEnableBpfOffload(final Resources res) { 591 // Get BPF offload config 592 // Priority 1: Device config 593 // Priority 2: Resource config 594 // Priority 3: Default value 595 final boolean defaultValue = getResourceBoolean( 596 res, R.bool.config_tether_enable_bpf_offload, true /** default value */); 597 598 return getDeviceConfigBoolean(OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD, defaultValue); 599 } 600 getEnableLegacyDhcpServer(final Resources res)601 private boolean getEnableLegacyDhcpServer(final Resources res) { 602 return getResourceBoolean( 603 res, R.bool.config_tether_enable_legacy_dhcp_server, false /** defaultValue */) 604 || getDeviceConfigBoolean( 605 TETHER_ENABLE_LEGACY_DHCP_SERVER, false /** defaultValue */); 606 } 607 shouldEnableWearTethering(Context context)608 private boolean shouldEnableWearTethering(Context context) { 609 return SdkLevel.isAtLeastT() 610 && isTetheringFeatureEnabled(context, TETHER_ENABLE_WEAR_TETHERING); 611 } 612 getDeviceConfigBoolean(final String name, final boolean defaultValue)613 private boolean getDeviceConfigBoolean(final String name, final boolean defaultValue) { 614 return mDeps.getDeviceConfigBoolean(NAMESPACE_CONNECTIVITY, name, defaultValue); 615 } 616 617 /** 618 * This is deprecated because connectivity namespace already be used for NetworkStack mainline 619 * module. Tethering should use its own namespace to roll out the feature flag. 620 * @deprecated new caller should use isTetheringFeatureEnabled instead. 621 */ 622 @Deprecated isConnectivityFeatureEnabled(Context ctx, String featureVersionFlag)623 private boolean isConnectivityFeatureEnabled(Context ctx, String featureVersionFlag) { 624 return isFeatureEnabled(ctx, NAMESPACE_CONNECTIVITY, featureVersionFlag); 625 } 626 isTetheringFeatureEnabled(Context ctx, String featureVersionFlag)627 private boolean isTetheringFeatureEnabled(Context ctx, String featureVersionFlag) { 628 return isFeatureEnabled(ctx, NAMESPACE_TETHERING, featureVersionFlag); 629 } 630 isFeatureEnabled(Context ctx, String namespace, String featureVersionFlag)631 private boolean isFeatureEnabled(Context ctx, String namespace, String featureVersionFlag) { 632 return mDeps.isFeatureEnabled(ctx, namespace, featureVersionFlag, TETHERING_MODULE_NAME, 633 false /* defaultEnabled */); 634 } 635 getResources(Context ctx, int subId)636 private Resources getResources(Context ctx, int subId) { 637 if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 638 return getResourcesForSubIdWrapper(ctx, subId); 639 } else { 640 return ctx.getResources(); 641 } 642 } 643 644 @VisibleForTesting getResourcesForSubIdWrapper(Context ctx, int subId)645 protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) { 646 return SubscriptionManager.getResourcesForSubId(ctx, subId); 647 } 648 copy(String[] strarray)649 private static String[] copy(String[] strarray) { 650 return Arrays.copyOf(strarray, strarray.length); 651 } 652 prependIfNotPresent(ArrayList<Integer> list, int value)653 private static void prependIfNotPresent(ArrayList<Integer> list, int value) { 654 if (list.contains(value)) return; 655 list.add(0, value); 656 } 657 appendIfNotPresent(ArrayList<Integer> list, int value)658 private static void appendIfNotPresent(ArrayList<Integer> list, int value) { 659 if (list.contains(value)) return; 660 list.add(value); 661 } 662 containsOneOf(ArrayList<Integer> list, Integer... values)663 private static boolean containsOneOf(ArrayList<Integer> list, Integer... values) { 664 for (Integer value : values) { 665 if (list.contains(value)) return true; 666 } 667 return false; 668 } 669 toIntArray(Collection<Integer> values)670 private static int[] toIntArray(Collection<Integer> values) { 671 final int[] result = new int[values.size()]; 672 int index = 0; 673 for (Integer value : values) { 674 result[index++] = value; 675 } 676 return result; 677 } 678 carrierConfigAffirmsEntitlementCheckRequired( PersistableBundle carrierConfig)679 private static boolean carrierConfigAffirmsEntitlementCheckRequired( 680 PersistableBundle carrierConfig) { 681 if (carrierConfig == null) { 682 return true; 683 } 684 return carrierConfig.getBoolean( 685 CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true); 686 } 687 carrierConfigAffirmsCarrierSupport(PersistableBundle carrierConfig)688 private static boolean carrierConfigAffirmsCarrierSupport(PersistableBundle carrierConfig) { 689 if (!SdkLevel.isAtLeastT() || carrierConfig == null) { 690 return true; 691 } 692 return carrierConfig.getBoolean(KEY_CARRIER_SUPPORTS_TETHERING_BOOL, true); 693 } 694 695 /** 696 * Get carrier configuration bundle. 697 */ getCarrierConfig(Context context, int activeDataSubId)698 public static PersistableBundle getCarrierConfig(Context context, int activeDataSubId) { 699 final CarrierConfigManager configManager = 700 context.getSystemService(CarrierConfigManager.class); 701 if (configManager == null) { 702 return null; 703 } 704 705 final PersistableBundle carrierConfig = configManager.getConfigForSubId(activeDataSubId); 706 if (CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfig)) { 707 return carrierConfig; 708 } 709 return null; 710 } 711 712 /** 713 * Convert this TetheringConfiguration to a TetheringConfigurationParcel. 714 */ toStableParcelable()715 public TetheringConfigurationParcel toStableParcelable() { 716 final TetheringConfigurationParcel parcel = new TetheringConfigurationParcel(); 717 parcel.tetherableUsbRegexs = tetherableUsbRegexs; 718 parcel.tetherableWifiRegexs = tetherableWifiRegexs; 719 parcel.tetherableBluetoothRegexs = tetherableBluetoothRegexs; 720 parcel.legacyDhcpRanges = legacyDhcpRanges; 721 parcel.provisioningApp = provisioningApp; 722 parcel.provisioningAppNoUi = provisioningAppNoUi; 723 724 return parcel; 725 } 726 } 727