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