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