blob: 822e67d339c5d3a1c76dc39ea696167a0295399a [file] [log] [blame]
paulhu845456e2021-03-17 17:19:09 +08001/*
2 * Copyright (C) 2021 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
17package android.net;
18
paulhu94430952021-03-23 00:24:50 +080019import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER;
20import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE;
21import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY;
paulhu94430952021-03-23 00:24:50 +080022
lucaslin89621282021-06-21 16:39:08 +080023import static com.android.net.module.util.ConnectivitySettingsUtils.getPrivateDnsModeAsString;
24
paulhuc9925e02021-03-17 20:30:33 +080025import android.annotation.IntDef;
paulhu94430952021-03-23 00:24:50 +080026import android.annotation.IntRange;
27import android.annotation.NonNull;
28import android.annotation.Nullable;
29import android.annotation.SystemApi;
30import android.content.Context;
31import android.net.ConnectivityManager.MultipathPreference;
paulhu92f128c2021-07-01 18:04:45 +080032import android.os.Binder;
33import android.os.Build;
paulhu344c1162021-05-11 09:42:50 +080034import android.os.Process;
35import android.os.UserHandle;
paulhu94430952021-03-23 00:24:50 +080036import android.provider.Settings;
37import android.text.TextUtils;
paulhu69afcd52021-04-27 00:14:47 +080038import android.util.ArraySet;
paulhu94430952021-03-23 00:24:50 +080039import android.util.Range;
40
lucaslin89621282021-06-21 16:39:08 +080041import com.android.net.module.util.ConnectivitySettingsUtils;
paulhu94430952021-03-23 00:24:50 +080042import com.android.net.module.util.ProxyUtils;
paulhuc9925e02021-03-17 20:30:33 +080043
44import java.lang.annotation.Retention;
45import java.lang.annotation.RetentionPolicy;
paulhu94430952021-03-23 00:24:50 +080046import java.time.Duration;
47import java.util.List;
paulhu69afcd52021-04-27 00:14:47 +080048import java.util.Set;
49import java.util.StringJoiner;
paulhuc9925e02021-03-17 20:30:33 +080050
paulhu845456e2021-03-17 17:19:09 +080051/**
52 * A manager class for connectivity module settings.
53 *
54 * @hide
55 */
paulhu94430952021-03-23 00:24:50 +080056@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
paulhu845456e2021-03-17 17:19:09 +080057public class ConnectivitySettingsManager {
58
59 private ConnectivitySettingsManager() {}
60
paulhuc9925e02021-03-17 20:30:33 +080061 /** Data activity timeout settings */
62
63 /**
64 * Inactivity timeout to track mobile data activity.
65 *
66 * If set to a positive integer, it indicates the inactivity timeout value in seconds to
67 * infer the data activity of mobile network. After a period of no activity on mobile
68 * networks with length specified by the timeout, an {@code ACTION_DATA_ACTIVITY_CHANGE}
69 * intent is fired to indicate a transition of network status from "active" to "idle". Any
70 * subsequent activity on mobile networks triggers the firing of {@code
71 * ACTION_DATA_ACTIVITY_CHANGE} intent indicating transition from "idle" to "active".
72 *
73 * Network activity refers to transmitting or receiving data on the network interfaces.
74 *
75 * Tracking is disabled if set to zero or negative value.
paulhu94430952021-03-23 00:24:50 +080076 *
77 * @hide
paulhuc9925e02021-03-17 20:30:33 +080078 */
79 public static final String DATA_ACTIVITY_TIMEOUT_MOBILE = "data_activity_timeout_mobile";
80
81 /**
82 * Timeout to tracking Wifi data activity. Same as {@code DATA_ACTIVITY_TIMEOUT_MOBILE}
83 * but for Wifi network.
paulhu94430952021-03-23 00:24:50 +080084 *
85 * @hide
paulhuc9925e02021-03-17 20:30:33 +080086 */
87 public static final String DATA_ACTIVITY_TIMEOUT_WIFI = "data_activity_timeout_wifi";
88
89 /** Dns resolver settings */
90
91 /**
92 * Sample validity in seconds to configure for the system DNS resolver.
paulhu94430952021-03-23 00:24:50 +080093 *
94 * @hide
paulhuc9925e02021-03-17 20:30:33 +080095 */
96 public static final String DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS =
97 "dns_resolver_sample_validity_seconds";
98
99 /**
100 * Success threshold in percent for use with the system DNS resolver.
paulhu94430952021-03-23 00:24:50 +0800101 *
102 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800103 */
104 public static final String DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT =
105 "dns_resolver_success_threshold_percent";
106
107 /**
108 * Minimum number of samples needed for statistics to be considered meaningful in the
109 * system DNS resolver.
paulhu94430952021-03-23 00:24:50 +0800110 *
111 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800112 */
113 public static final String DNS_RESOLVER_MIN_SAMPLES = "dns_resolver_min_samples";
114
115 /**
116 * Maximum number taken into account for statistics purposes in the system DNS resolver.
paulhu94430952021-03-23 00:24:50 +0800117 *
118 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800119 */
120 public static final String DNS_RESOLVER_MAX_SAMPLES = "dns_resolver_max_samples";
121
paulhu94430952021-03-23 00:24:50 +0800122 private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
123 private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
124
paulhuc9925e02021-03-17 20:30:33 +0800125 /** Network switch notification settings */
126
127 /**
128 * The maximum number of notifications shown in 24 hours when switching networks.
paulhu94430952021-03-23 00:24:50 +0800129 *
130 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800131 */
132 public static final String NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT =
133 "network_switch_notification_daily_limit";
134
135 /**
136 * The minimum time in milliseconds between notifications when switching networks.
paulhu94430952021-03-23 00:24:50 +0800137 *
138 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800139 */
140 public static final String NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS =
141 "network_switch_notification_rate_limit_millis";
142
143 /** Captive portal settings */
144
145 /**
146 * The URL used for HTTP captive portal detection upon a new connection.
147 * A 204 response code from the server is used for validation.
paulhu94430952021-03-23 00:24:50 +0800148 *
149 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800150 */
151 public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
152
153 /**
154 * What to do when connecting a network that presents a captive portal.
paulhu94430952021-03-23 00:24:50 +0800155 * Must be one of the CAPTIVE_PORTAL_MODE_* constants below.
paulhuc9925e02021-03-17 20:30:33 +0800156 *
157 * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT.
paulhu94430952021-03-23 00:24:50 +0800158 *
159 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800160 */
161 public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
162
163 /**
164 * Don't attempt to detect captive portals.
165 */
166 public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0;
167
168 /**
169 * When detecting a captive portal, display a notification that
170 * prompts the user to sign in.
171 */
172 public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1;
173
174 /**
175 * When detecting a captive portal, immediately disconnect from the
176 * network and do not reconnect to that network in the future.
177 */
178 public static final int CAPTIVE_PORTAL_MODE_AVOID = 2;
179
180 /** @hide */
181 @Retention(RetentionPolicy.SOURCE)
182 @IntDef(value = {
183 CAPTIVE_PORTAL_MODE_IGNORE,
184 CAPTIVE_PORTAL_MODE_PROMPT,
185 CAPTIVE_PORTAL_MODE_AVOID,
186 })
187 public @interface CaptivePortalMode {}
188
189 /** Global http proxy settings */
190
191 /**
192 * Host name for global http proxy. Set via ConnectivityManager.
paulhu94430952021-03-23 00:24:50 +0800193 *
194 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800195 */
196 public static final String GLOBAL_HTTP_PROXY_HOST = "global_http_proxy_host";
197
198 /**
199 * Integer host port for global http proxy. Set via ConnectivityManager.
paulhu94430952021-03-23 00:24:50 +0800200 *
201 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800202 */
203 public static final String GLOBAL_HTTP_PROXY_PORT = "global_http_proxy_port";
204
205 /**
206 * Exclusion list for global proxy. This string contains a list of
207 * comma-separated domains where the global proxy does not apply.
208 * Domains should be listed in a comma- separated list. Example of
209 * acceptable formats: ".domain1.com,my.domain2.com" Use
210 * ConnectivityManager to set/get.
paulhu94430952021-03-23 00:24:50 +0800211 *
212 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800213 */
214 public static final String GLOBAL_HTTP_PROXY_EXCLUSION_LIST =
215 "global_http_proxy_exclusion_list";
216
217 /**
218 * The location PAC File for the proxy.
paulhu94430952021-03-23 00:24:50 +0800219 *
220 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800221 */
222 public static final String GLOBAL_HTTP_PROXY_PAC = "global_proxy_pac_url";
223
224 /** Private dns settings */
225
226 /**
227 * The requested Private DNS mode (string), and an accompanying specifier (string).
228 *
229 * Currently, the specifier holds the chosen provider name when the mode requests
230 * a specific provider. It may be used to store the provider name even when the
231 * mode changes so that temporarily disabling and re-enabling the specific
232 * provider mode does not necessitate retyping the provider hostname.
paulhu94430952021-03-23 00:24:50 +0800233 *
234 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800235 */
236 public static final String PRIVATE_DNS_MODE = "private_dns_mode";
237
238 /**
239 * The specific Private DNS provider name.
paulhu94430952021-03-23 00:24:50 +0800240 *
241 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800242 */
243 public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier";
244
245 /**
246 * Forced override of the default mode (hardcoded as "automatic", nee "opportunistic").
247 * This allows changing the default mode without effectively disabling other modes,
248 * all of which require explicit user action to enable/configure. See also b/79719289.
249 *
250 * Value is a string, suitable for assignment to PRIVATE_DNS_MODE above.
paulhu94430952021-03-23 00:24:50 +0800251 *
252 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800253 */
254 public static final String PRIVATE_DNS_DEFAULT_MODE = "private_dns_default_mode";
255
256 /** Other settings */
257
258 /**
259 * The number of milliseconds to hold on to a PendingIntent based request. This delay gives
260 * the receivers of the PendingIntent an opportunity to make a new network request before
261 * the Network satisfying the request is potentially removed.
paulhu94430952021-03-23 00:24:50 +0800262 *
263 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800264 */
265 public static final String CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS =
266 "connectivity_release_pending_intent_delay_ms";
267
268 /**
269 * Whether the mobile data connection should remain active even when higher
270 * priority networks like WiFi are active, to help make network switching faster.
271 *
272 * See ConnectivityService for more info.
273 *
274 * (0 = disabled, 1 = enabled)
paulhu94430952021-03-23 00:24:50 +0800275 *
276 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800277 */
278 public static final String MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on";
279
280 /**
281 * Whether the wifi data connection should remain active even when higher
282 * priority networks like Ethernet are active, to keep both networks.
283 * In the case where higher priority networks are connected, wifi will be
284 * unused unless an application explicitly requests to use it.
285 *
286 * See ConnectivityService for more info.
287 *
288 * (0 = disabled, 1 = enabled)
paulhu94430952021-03-23 00:24:50 +0800289 *
290 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800291 */
292 public static final String WIFI_ALWAYS_REQUESTED = "wifi_always_requested";
293
paulhu845456e2021-03-17 17:19:09 +0800294 /**
295 * Whether to automatically switch away from wifi networks that lose Internet access.
296 * Only meaningful if config_networkAvoidBadWifi is set to 0, otherwise the system always
297 * avoids such networks. Valid values are:
298 *
299 * 0: Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
300 * null: Ask the user whether to switch away from bad wifi.
301 * 1: Avoid bad wifi.
paulhu94430952021-03-23 00:24:50 +0800302 *
303 * @hide
paulhu845456e2021-03-17 17:19:09 +0800304 */
305 public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi";
306
307 /**
paulhu94430952021-03-23 00:24:50 +0800308 * Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
309 */
310 public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0;
311
312 /**
313 * Ask the user whether to switch away from bad wifi.
314 */
315 public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1;
316
317 /**
318 * Avoid bad wifi.
319 */
320 public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2;
321
322 /** @hide */
323 @Retention(RetentionPolicy.SOURCE)
324 @IntDef(value = {
325 NETWORK_AVOID_BAD_WIFI_IGNORE,
326 NETWORK_AVOID_BAD_WIFI_PROMPT,
327 NETWORK_AVOID_BAD_WIFI_AVOID,
328 })
329 public @interface NetworkAvoidBadWifi {}
330
331 /**
paulhu845456e2021-03-17 17:19:09 +0800332 * User setting for ConnectivityManager.getMeteredMultipathPreference(). This value may be
333 * overridden by the system based on device or application state. If null, the value
334 * specified by config_networkMeteredMultipathPreference is used.
paulhu94430952021-03-23 00:24:50 +0800335 *
336 * @hide
paulhu845456e2021-03-17 17:19:09 +0800337 */
338 public static final String NETWORK_METERED_MULTIPATH_PREFERENCE =
339 "network_metered_multipath_preference";
paulhu94430952021-03-23 00:24:50 +0800340
341 /**
paulhu344c1162021-05-11 09:42:50 +0800342 * A list of uids that should go on cellular networks in preference even when higher-priority
paulhu7a4eeed2021-03-25 13:17:58 +0800343 * networks are connected.
344 *
345 * @hide
346 */
paulhu344c1162021-05-11 09:42:50 +0800347 public static final String MOBILE_DATA_PREFERRED_UIDS = "mobile_data_preferred_uids";
paulhu7a4eeed2021-03-25 13:17:58 +0800348
349 /**
lucaslin57f9ba82021-04-23 21:03:39 +0800350 * One of the private DNS modes that indicates the private DNS mode is off.
351 */
lucaslin89621282021-06-21 16:39:08 +0800352 public static final int PRIVATE_DNS_MODE_OFF = ConnectivitySettingsUtils.PRIVATE_DNS_MODE_OFF;
lucaslin57f9ba82021-04-23 21:03:39 +0800353
354 /**
355 * One of the private DNS modes that indicates the private DNS mode is automatic, which
356 * will try to use the current DNS as private DNS.
357 */
lucaslin89621282021-06-21 16:39:08 +0800358 public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC =
359 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_OPPORTUNISTIC;
lucaslin57f9ba82021-04-23 21:03:39 +0800360
361 /**
362 * One of the private DNS modes that indicates the private DNS mode is strict and the
363 * {@link #PRIVATE_DNS_SPECIFIER} is required, which will try to use the value of
364 * {@link #PRIVATE_DNS_SPECIFIER} as private DNS.
365 */
lucaslin89621282021-06-21 16:39:08 +0800366 public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME =
367 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
lucaslin57f9ba82021-04-23 21:03:39 +0800368
369 /** @hide */
370 @Retention(RetentionPolicy.SOURCE)
371 @IntDef(value = {
372 PRIVATE_DNS_MODE_OFF,
373 PRIVATE_DNS_MODE_OPPORTUNISTIC,
374 PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
375 })
376 public @interface PrivateDnsMode {}
377
lucaslin57f9ba82021-04-23 21:03:39 +0800378 /**
paulhu91e78062021-05-26 16:16:57 +0800379 * A list of uids that is allowed to use restricted networks.
paulhu69afcd52021-04-27 00:14:47 +0800380 *
381 * @hide
382 */
paulhu91e78062021-05-26 16:16:57 +0800383 public static final String UIDS_ALLOWED_ON_RESTRICTED_NETWORKS =
384 "uids_allowed_on_restricted_networks";
paulhu69afcd52021-04-27 00:14:47 +0800385
386 /**
Patrick Rohra2084362022-01-03 15:55:52 +0100387 * A global rate limit that applies to all networks with NET_CAPABILITY_INTERNET when enabled.
388 *
389 * @hide
390 */
391 public static final String INGRESS_RATE_LIMIT_BYTES_PER_SECOND =
392 "ingress_rate_limit_bytes_per_second";
393
394 /**
paulhu94430952021-03-23 00:24:50 +0800395 * Get mobile data activity timeout from {@link Settings}.
396 *
397 * @param context The {@link Context} to query the setting.
398 * @param def The default timeout if no setting value.
399 * @return The {@link Duration} of timeout to track mobile data activity.
400 */
401 @NonNull
402 public static Duration getMobileDataActivityTimeout(@NonNull Context context,
403 @NonNull Duration def) {
404 final int timeout = Settings.Global.getInt(
405 context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE, (int) def.getSeconds());
406 return Duration.ofSeconds(timeout);
407 }
408
409 /**
410 * Set mobile data activity timeout to {@link Settings}.
411 * Tracking is disabled if set to zero or negative value.
412 *
413 * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be
414 * ignored.
415 *
416 * @param context The {@link Context} to set the setting.
417 * @param timeout The mobile data activity timeout.
418 */
419 public static void setMobileDataActivityTimeout(@NonNull Context context,
420 @NonNull Duration timeout) {
421 Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE,
422 (int) timeout.getSeconds());
423 }
424
425 /**
426 * Get wifi data activity timeout from {@link Settings}.
427 *
428 * @param context The {@link Context} to query the setting.
429 * @param def The default timeout if no setting value.
430 * @return The {@link Duration} of timeout to track wifi data activity.
431 */
432 @NonNull
433 public static Duration getWifiDataActivityTimeout(@NonNull Context context,
434 @NonNull Duration def) {
435 final int timeout = Settings.Global.getInt(
436 context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI, (int) def.getSeconds());
437 return Duration.ofSeconds(timeout);
438 }
439
440 /**
441 * Set wifi data activity timeout to {@link Settings}.
442 * Tracking is disabled if set to zero or negative value.
443 *
444 * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be
445 * ignored.
446 *
447 * @param context The {@link Context} to set the setting.
448 * @param timeout The wifi data activity timeout.
449 */
450 public static void setWifiDataActivityTimeout(@NonNull Context context,
451 @NonNull Duration timeout) {
452 Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI,
453 (int) timeout.getSeconds());
454 }
455
456 /**
457 * Get dns resolver sample validity duration from {@link Settings}.
458 *
459 * @param context The {@link Context} to query the setting.
460 * @param def The default duration if no setting value.
461 * @return The {@link Duration} of sample validity duration to configure for the system DNS
462 * resolver.
463 */
464 @NonNull
465 public static Duration getDnsResolverSampleValidityDuration(@NonNull Context context,
466 @NonNull Duration def) {
467 final int duration = Settings.Global.getInt(context.getContentResolver(),
468 DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, (int) def.getSeconds());
469 return Duration.ofSeconds(duration);
470 }
471
472 /**
473 * Set dns resolver sample validity duration to {@link Settings}. The duration must be a
474 * positive number of seconds.
475 *
476 * @param context The {@link Context} to set the setting.
477 * @param duration The sample validity duration.
478 */
479 public static void setDnsResolverSampleValidityDuration(@NonNull Context context,
480 @NonNull Duration duration) {
481 final int time = (int) duration.getSeconds();
482 if (time <= 0) {
483 throw new IllegalArgumentException("Invalid duration");
484 }
485 Settings.Global.putInt(
486 context.getContentResolver(), DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, time);
487 }
488
489 /**
490 * Get dns resolver success threshold percent from {@link Settings}.
491 *
492 * @param context The {@link Context} to query the setting.
493 * @param def The default value if no setting value.
494 * @return The success threshold in percent for use with the system DNS resolver.
495 */
496 public static int getDnsResolverSuccessThresholdPercent(@NonNull Context context, int def) {
497 return Settings.Global.getInt(
498 context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, def);
499 }
500
501 /**
502 * Set dns resolver success threshold percent to {@link Settings}. The threshold percent must
503 * be 0~100.
504 *
505 * @param context The {@link Context} to set the setting.
506 * @param percent The success threshold percent.
507 */
508 public static void setDnsResolverSuccessThresholdPercent(@NonNull Context context,
509 @IntRange(from = 0, to = 100) int percent) {
510 if (percent < 0 || percent > 100) {
511 throw new IllegalArgumentException("Percent must be 0~100");
512 }
513 Settings.Global.putInt(
514 context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, percent);
515 }
516
517 /**
518 * Get dns resolver samples range from {@link Settings}.
519 *
520 * @param context The {@link Context} to query the setting.
521 * @return The {@link Range<Integer>} of samples needed for statistics to be considered
522 * meaningful in the system DNS resolver.
523 */
524 @NonNull
525 public static Range<Integer> getDnsResolverSampleRanges(@NonNull Context context) {
526 final int minSamples = Settings.Global.getInt(context.getContentResolver(),
527 DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
528 final int maxSamples = Settings.Global.getInt(context.getContentResolver(),
529 DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
530 return new Range<>(minSamples, maxSamples);
531 }
532
533 /**
534 * Set dns resolver samples range to {@link Settings}.
535 *
536 * @param context The {@link Context} to set the setting.
537 * @param range The samples range. The minimum number should be more than 0 and the maximum
538 * number should be less that 64.
539 */
540 public static void setDnsResolverSampleRanges(@NonNull Context context,
541 @NonNull Range<Integer> range) {
542 if (range.getLower() < 0 || range.getUpper() > 64) {
543 throw new IllegalArgumentException("Argument must be 0~64");
544 }
545 Settings.Global.putInt(
546 context.getContentResolver(), DNS_RESOLVER_MIN_SAMPLES, range.getLower());
547 Settings.Global.putInt(
548 context.getContentResolver(), DNS_RESOLVER_MAX_SAMPLES, range.getUpper());
549 }
550
551 /**
552 * Get maximum count (from {@link Settings}) of switching network notifications shown in 24
553 * hours.
554 *
555 * @param context The {@link Context} to query the setting.
556 * @param def The default value if no setting value.
557 * @return The maximum count of notifications shown in 24 hours when switching networks.
558 */
559 public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context,
560 int def) {
561 return Settings.Global.getInt(
562 context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, def);
563 }
564
565 /**
566 * Set maximum count (to {@link Settings}) of switching network notifications shown in 24 hours.
567 * The count must be at least 0.
568 *
569 * @param context The {@link Context} to set the setting.
570 * @param count The maximum count of switching network notifications shown in 24 hours.
571 */
572 public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context,
573 @IntRange(from = 0) int count) {
574 if (count < 0) {
paulhu236a9922021-03-29 10:50:36 +0800575 throw new IllegalArgumentException("Count must be more than 0.");
paulhu94430952021-03-23 00:24:50 +0800576 }
577 Settings.Global.putInt(
578 context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, count);
579 }
580
581 /**
582 * Get minimum duration (from {@link Settings}) between each switching network notifications.
583 *
584 * @param context The {@link Context} to query the setting.
585 * @param def The default time if no setting value.
586 * @return The minimum duration between notifications when switching networks.
587 */
588 @NonNull
589 public static Duration getNetworkSwitchNotificationRateDuration(@NonNull Context context,
590 @NonNull Duration def) {
591 final int duration = Settings.Global.getInt(context.getContentResolver(),
592 NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, (int) def.toMillis());
593 return Duration.ofMillis(duration);
594 }
595
596 /**
597 * Set minimum duration (to {@link Settings}) between each switching network notifications.
paulhu236a9922021-03-29 10:50:36 +0800598 * The duration will be rounded down to the next millisecond, and must be positive.
paulhu94430952021-03-23 00:24:50 +0800599 *
600 * @param context The {@link Context} to set the setting.
601 * @param duration The minimum duration between notifications when switching networks.
602 */
603 public static void setNetworkSwitchNotificationRateDuration(@NonNull Context context,
604 @NonNull Duration duration) {
605 final int time = (int) duration.toMillis();
606 if (time < 0) {
607 throw new IllegalArgumentException("Invalid duration.");
608 }
609 Settings.Global.putInt(context.getContentResolver(),
610 NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, time);
611 }
612
613 /**
614 * Get URL (from {@link Settings}) used for HTTP captive portal detection upon a new connection.
615 *
616 * @param context The {@link Context} to query the setting.
617 * @return The URL used for HTTP captive portal detection upon a new connection.
618 */
619 @Nullable
620 public static String getCaptivePortalHttpUrl(@NonNull Context context) {
621 return Settings.Global.getString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL);
622 }
623
624 /**
625 * Set URL (to {@link Settings}) used for HTTP captive portal detection upon a new connection.
paulhu236a9922021-03-29 10:50:36 +0800626 * The URL is accessed to check for connectivity and presence of a captive portal on a network.
627 * The URL should respond with HTTP status 204 to a GET request, and the stack will use
628 * redirection status as a signal for captive portal detection.
629 * If the URL is set to null or is otherwise incorrect or inaccessible, the stack will fail to
630 * detect connectivity and portals. This will often result in loss of connectivity.
paulhu94430952021-03-23 00:24:50 +0800631 *
632 * @param context The {@link Context} to set the setting.
633 * @param url The URL used for HTTP captive portal detection upon a new connection.
634 */
635 public static void setCaptivePortalHttpUrl(@NonNull Context context, @Nullable String url) {
636 Settings.Global.putString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL, url);
637 }
638
639 /**
640 * Get mode (from {@link Settings}) when connecting a network that presents a captive portal.
641 *
642 * @param context The {@link Context} to query the setting.
643 * @param def The default mode if no setting value.
644 * @return The mode when connecting a network that presents a captive portal.
645 */
646 @CaptivePortalMode
647 public static int getCaptivePortalMode(@NonNull Context context,
648 @CaptivePortalMode int def) {
649 return Settings.Global.getInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, def);
650 }
651
652 /**
653 * Set mode (to {@link Settings}) when connecting a network that presents a captive portal.
654 *
655 * @param context The {@link Context} to set the setting.
656 * @param mode The mode when connecting a network that presents a captive portal.
657 */
658 public static void setCaptivePortalMode(@NonNull Context context, @CaptivePortalMode int mode) {
659 if (!(mode == CAPTIVE_PORTAL_MODE_IGNORE
660 || mode == CAPTIVE_PORTAL_MODE_PROMPT
661 || mode == CAPTIVE_PORTAL_MODE_AVOID)) {
662 throw new IllegalArgumentException("Invalid captive portal mode");
663 }
664 Settings.Global.putInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, mode);
665 }
666
667 /**
668 * Get the global HTTP proxy applied to the device, or null if none.
669 *
670 * @param context The {@link Context} to query the setting.
671 * @return The {@link ProxyInfo} which build from global http proxy settings.
672 */
673 @Nullable
674 public static ProxyInfo getGlobalProxy(@NonNull Context context) {
675 final String host = Settings.Global.getString(
676 context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST);
677 final int port = Settings.Global.getInt(
678 context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* def */);
679 final String exclusionList = Settings.Global.getString(
680 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
681 final String pacFileUrl = Settings.Global.getString(
682 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC);
683
684 if (TextUtils.isEmpty(host) && TextUtils.isEmpty(pacFileUrl)) {
685 return null; // No global proxy.
686 }
687
688 if (TextUtils.isEmpty(pacFileUrl)) {
689 return ProxyInfo.buildDirectProxy(
690 host, port, ProxyUtils.exclusionStringAsList(exclusionList));
691 } else {
692 return ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl));
693 }
694 }
695
696 /**
697 * Set global http proxy settings from given {@link ProxyInfo}.
698 *
699 * @param context The {@link Context} to set the setting.
700 * @param proxyInfo The {@link ProxyInfo} for global http proxy settings which build from
701 * {@link ProxyInfo#buildPacProxy(Uri)} or
702 * {@link ProxyInfo#buildDirectProxy(String, int, List)}
703 */
704 public static void setGlobalProxy(@NonNull Context context, @NonNull ProxyInfo proxyInfo) {
705 final String host = proxyInfo.getHost();
706 final int port = proxyInfo.getPort();
707 final String exclusionList = proxyInfo.getExclusionListAsString();
708 final String pacFileUrl = proxyInfo.getPacFileUrl().toString();
709
710 if (TextUtils.isEmpty(pacFileUrl)) {
711 Settings.Global.putString(context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, host);
712 Settings.Global.putInt(context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, port);
713 Settings.Global.putString(
714 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclusionList);
715 Settings.Global.putString(
716 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
717 } else {
718 Settings.Global.putString(
719 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
720 Settings.Global.putString(
721 context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
722 Settings.Global.putInt(
723 context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
724 Settings.Global.putString(
725 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
726 }
727 }
728
729 /**
730 * Clear all global http proxy settings.
731 *
732 * @param context The {@link Context} to set the setting.
733 */
734 public static void clearGlobalProxy(@NonNull Context context) {
735 Settings.Global.putString(
736 context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
737 Settings.Global.putInt(
738 context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
739 Settings.Global.putString(
740 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
741 Settings.Global.putString(
742 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
743 }
744
lucaslin57f9ba82021-04-23 21:03:39 +0800745 /**
746 * Get private DNS mode from settings.
747 *
748 * @param context The Context to query the private DNS mode from settings.
749 * @return A string of private DNS mode.
750 */
751 @PrivateDnsMode
752 public static int getPrivateDnsMode(@NonNull Context context) {
lucaslin89621282021-06-21 16:39:08 +0800753 return ConnectivitySettingsUtils.getPrivateDnsMode(context);
lucaslin57f9ba82021-04-23 21:03:39 +0800754 }
755
756 /**
757 * Set private DNS mode to settings.
758 *
759 * @param context The {@link Context} to set the private DNS mode.
760 * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants.
761 */
762 public static void setPrivateDnsMode(@NonNull Context context, @PrivateDnsMode int mode) {
lucaslin89621282021-06-21 16:39:08 +0800763 ConnectivitySettingsUtils.setPrivateDnsMode(context, mode);
lucaslin57f9ba82021-04-23 21:03:39 +0800764 }
765
paulhu94430952021-03-23 00:24:50 +0800766 /**
767 * Get specific private dns provider name from {@link Settings}.
768 *
769 * @param context The {@link Context} to query the setting.
770 * @return The specific private dns provider name, or null if no setting value.
771 */
772 @Nullable
773 public static String getPrivateDnsHostname(@NonNull Context context) {
lucaslin89621282021-06-21 16:39:08 +0800774 return ConnectivitySettingsUtils.getPrivateDnsHostname(context);
paulhu94430952021-03-23 00:24:50 +0800775 }
776
777 /**
778 * Set specific private dns provider name to {@link Settings}.
779 *
780 * @param context The {@link Context} to set the setting.
781 * @param specifier The specific private dns provider name.
782 */
lucaslin89621282021-06-21 16:39:08 +0800783 public static void setPrivateDnsHostname(@NonNull Context context, @Nullable String specifier) {
784 ConnectivitySettingsUtils.setPrivateDnsHostname(context, specifier);
paulhu94430952021-03-23 00:24:50 +0800785 }
786
787 /**
788 * Get default private dns mode from {@link Settings}.
789 *
790 * @param context The {@link Context} to query the setting.
791 * @return The default private dns mode.
792 */
793 @PrivateDnsMode
794 @NonNull
795 public static String getPrivateDnsDefaultMode(@NonNull Context context) {
796 return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE);
797 }
798
799 /**
800 * Set default private dns mode to {@link Settings}.
801 *
802 * @param context The {@link Context} to set the setting.
803 * @param mode The default private dns mode. This should be one of the PRIVATE_DNS_MODE_*
804 * constants.
805 */
806 public static void setPrivateDnsDefaultMode(@NonNull Context context,
lucaslin57f9ba82021-04-23 21:03:39 +0800807 @NonNull @PrivateDnsMode int mode) {
paulhu94430952021-03-23 00:24:50 +0800808 if (!(mode == PRIVATE_DNS_MODE_OFF
809 || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
810 || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
811 throw new IllegalArgumentException("Invalid private dns mode");
812 }
lucaslin57f9ba82021-04-23 21:03:39 +0800813 Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE,
814 getPrivateDnsModeAsString(mode));
paulhu94430952021-03-23 00:24:50 +0800815 }
816
817 /**
818 * Get duration (from {@link Settings}) to keep a PendingIntent-based request.
819 *
820 * @param context The {@link Context} to query the setting.
821 * @param def The default duration if no setting value.
822 * @return The duration to keep a PendingIntent-based request.
823 */
824 @NonNull
825 public static Duration getConnectivityKeepPendingIntentDuration(@NonNull Context context,
826 @NonNull Duration def) {
827 final int duration = Settings.Secure.getInt(context.getContentResolver(),
828 CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, (int) def.toMillis());
829 return Duration.ofMillis(duration);
830 }
831
832 /**
833 * Set duration (to {@link Settings}) to keep a PendingIntent-based request.
paulhu236a9922021-03-29 10:50:36 +0800834 * The duration will be rounded down to the next millisecond, and must be positive.
paulhu94430952021-03-23 00:24:50 +0800835 *
836 * @param context The {@link Context} to set the setting.
837 * @param duration The duration to keep a PendingIntent-based request.
838 */
839 public static void setConnectivityKeepPendingIntentDuration(@NonNull Context context,
840 @NonNull Duration duration) {
841 final int time = (int) duration.toMillis();
842 if (time < 0) {
843 throw new IllegalArgumentException("Invalid duration.");
844 }
845 Settings.Secure.putInt(
846 context.getContentResolver(), CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, time);
847 }
848
849 /**
850 * Read from {@link Settings} whether the mobile data connection should remain active
851 * even when higher priority networks are active.
852 *
853 * @param context The {@link Context} to query the setting.
854 * @param def The default value if no setting value.
855 * @return Whether the mobile data connection should remain active even when higher
856 * priority networks are active.
857 */
858 public static boolean getMobileDataAlwaysOn(@NonNull Context context, boolean def) {
859 final int enable = Settings.Global.getInt(
860 context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (def ? 1 : 0));
861 return (enable != 0) ? true : false;
862 }
863
864 /**
865 * Write into {@link Settings} whether the mobile data connection should remain active
866 * even when higher priority networks are active.
867 *
868 * @param context The {@link Context} to set the setting.
869 * @param enable Whether the mobile data connection should remain active even when higher
870 * priority networks are active.
871 */
872 public static void setMobileDataAlwaysOn(@NonNull Context context, boolean enable) {
873 Settings.Global.putInt(
874 context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (enable ? 1 : 0));
875 }
876
877 /**
878 * Read from {@link Settings} whether the wifi data connection should remain active
879 * even when higher priority networks are active.
880 *
881 * @param context The {@link Context} to query the setting.
882 * @param def The default value if no setting value.
883 * @return Whether the wifi data connection should remain active even when higher
884 * priority networks are active.
885 */
886 public static boolean getWifiAlwaysRequested(@NonNull Context context, boolean def) {
887 final int enable = Settings.Global.getInt(
888 context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (def ? 1 : 0));
889 return (enable != 0) ? true : false;
890 }
891
892 /**
893 * Write into {@link Settings} whether the wifi data connection should remain active
894 * even when higher priority networks are active.
895 *
896 * @param context The {@link Context} to set the setting.
897 * @param enable Whether the wifi data connection should remain active even when higher
898 * priority networks are active
899 */
900 public static void setWifiAlwaysRequested(@NonNull Context context, boolean enable) {
901 Settings.Global.putInt(
902 context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (enable ? 1 : 0));
903 }
904
905 /**
906 * Get avoid bad wifi setting from {@link Settings}.
907 *
908 * @param context The {@link Context} to query the setting.
909 * @return The setting whether to automatically switch away from wifi networks that lose
910 * internet access.
911 */
912 @NetworkAvoidBadWifi
913 public static int getNetworkAvoidBadWifi(@NonNull Context context) {
914 final String setting =
915 Settings.Global.getString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI);
916 if ("0".equals(setting)) {
917 return NETWORK_AVOID_BAD_WIFI_IGNORE;
918 } else if ("1".equals(setting)) {
919 return NETWORK_AVOID_BAD_WIFI_AVOID;
920 } else {
921 return NETWORK_AVOID_BAD_WIFI_PROMPT;
922 }
923 }
924
925 /**
926 * Set avoid bad wifi setting to {@link Settings}.
927 *
928 * @param context The {@link Context} to set the setting.
929 * @param value Whether to automatically switch away from wifi networks that lose internet
930 * access.
931 */
932 public static void setNetworkAvoidBadWifi(@NonNull Context context,
933 @NetworkAvoidBadWifi int value) {
934 final String setting;
935 if (value == NETWORK_AVOID_BAD_WIFI_IGNORE) {
936 setting = "0";
937 } else if (value == NETWORK_AVOID_BAD_WIFI_AVOID) {
938 setting = "1";
939 } else if (value == NETWORK_AVOID_BAD_WIFI_PROMPT) {
940 setting = null;
941 } else {
942 throw new IllegalArgumentException("Invalid avoid bad wifi setting");
943 }
944 Settings.Global.putString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI, setting);
945 }
946
947 /**
948 * Get network metered multipath preference from {@link Settings}.
949 *
950 * @param context The {@link Context} to query the setting.
951 * @return The network metered multipath preference which should be one of
952 * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value specified
953 * by config_networkMeteredMultipathPreference is used.
954 */
955 @Nullable
956 public static String getNetworkMeteredMultipathPreference(@NonNull Context context) {
957 return Settings.Global.getString(
958 context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE);
959 }
960
961 /**
962 * Set network metered multipath preference to {@link Settings}.
963 *
964 * @param context The {@link Context} to set the setting.
965 * @param preference The network metered multipath preference which should be one of
966 * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value
967 * specified by config_networkMeteredMultipathPreference is used.
968 */
969 public static void setNetworkMeteredMultipathPreference(@NonNull Context context,
970 @NonNull @MultipathPreference String preference) {
971 if (!(Integer.valueOf(preference) == MULTIPATH_PREFERENCE_HANDOVER
972 || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_RELIABILITY
973 || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_PERFORMANCE)) {
974 throw new IllegalArgumentException("Invalid private dns mode");
975 }
976 Settings.Global.putString(
977 context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE, preference);
978 }
paulhu7a4eeed2021-03-25 13:17:58 +0800979
paulhu91e78062021-05-26 16:16:57 +0800980 private static Set<Integer> getUidSetFromString(@Nullable String uidList) {
981 final Set<Integer> uids = new ArraySet<>();
982 if (TextUtils.isEmpty(uidList)) {
983 return uids;
984 }
985 for (String uid : uidList.split(";")) {
986 uids.add(Integer.valueOf(uid));
987 }
988 return uids;
989 }
990
991 private static String getUidStringFromSet(@NonNull Set<Integer> uidList) {
992 final StringJoiner joiner = new StringJoiner(";");
993 for (Integer uid : uidList) {
994 if (uid < 0 || UserHandle.getAppId(uid) > Process.LAST_APPLICATION_UID) {
995 throw new IllegalArgumentException("Invalid uid");
996 }
997 joiner.add(uid.toString());
998 }
999 return joiner.toString();
1000 }
1001
paulhu7a4eeed2021-03-25 13:17:58 +08001002 /**
paulhu344c1162021-05-11 09:42:50 +08001003 * Get the list of uids(from {@link Settings}) that should go on cellular networks in preference
paulhu7a4eeed2021-03-25 13:17:58 +08001004 * even when higher-priority networks are connected.
1005 *
1006 * @param context The {@link Context} to query the setting.
paulhu344c1162021-05-11 09:42:50 +08001007 * @return A list of uids that should go on cellular networks in preference even when
paulhu7a4eeed2021-03-25 13:17:58 +08001008 * higher-priority networks are connected or null if no setting value.
1009 */
paulhu344c1162021-05-11 09:42:50 +08001010 @NonNull
1011 public static Set<Integer> getMobileDataPreferredUids(@NonNull Context context) {
1012 final String uidList = Settings.Secure.getString(
1013 context.getContentResolver(), MOBILE_DATA_PREFERRED_UIDS);
paulhu91e78062021-05-26 16:16:57 +08001014 return getUidSetFromString(uidList);
paulhu7a4eeed2021-03-25 13:17:58 +08001015 }
1016
1017 /**
paulhu344c1162021-05-11 09:42:50 +08001018 * Set the list of uids(to {@link Settings}) that should go on cellular networks in preference
paulhu7a4eeed2021-03-25 13:17:58 +08001019 * even when higher-priority networks are connected.
1020 *
1021 * @param context The {@link Context} to set the setting.
paulhu344c1162021-05-11 09:42:50 +08001022 * @param uidList A list of uids that should go on cellular networks in preference even when
paulhu7a4eeed2021-03-25 13:17:58 +08001023 * higher-priority networks are connected.
1024 */
paulhu344c1162021-05-11 09:42:50 +08001025 public static void setMobileDataPreferredUids(@NonNull Context context,
1026 @NonNull Set<Integer> uidList) {
paulhu91e78062021-05-26 16:16:57 +08001027 final String uids = getUidStringFromSet(uidList);
1028 Settings.Secure.putString(context.getContentResolver(), MOBILE_DATA_PREFERRED_UIDS, uids);
paulhu7a4eeed2021-03-25 13:17:58 +08001029 }
paulhu69afcd52021-04-27 00:14:47 +08001030
1031 /**
paulhu91e78062021-05-26 16:16:57 +08001032 * Get the list of uids (from {@link Settings}) allowed to use restricted networks.
1033 *
1034 * Access to restricted networks is controlled by the (preinstalled-only)
1035 * CONNECTIVITY_USE_RESTRICTED_NETWORKS permission, but highly privileged
1036 * callers can also set a list of uids that can access restricted networks.
1037 *
1038 * This is useful for example in some jurisdictions where government apps,
1039 * that can't be preinstalled, must still have access to emergency services.
paulhu69afcd52021-04-27 00:14:47 +08001040 *
1041 * @param context The {@link Context} to query the setting.
paulhu91e78062021-05-26 16:16:57 +08001042 * @return A list of uids that is allowed to use restricted networks or null if no setting
paulhu257a5cf2021-05-14 15:27:36 +08001043 * value.
paulhu69afcd52021-04-27 00:14:47 +08001044 */
1045 @NonNull
paulhu91e78062021-05-26 16:16:57 +08001046 public static Set<Integer> getUidsAllowedOnRestrictedNetworks(@NonNull Context context) {
paulhu44280442021-05-31 10:42:13 +08001047 final String uidList = Settings.Global.getString(
paulhu91e78062021-05-26 16:16:57 +08001048 context.getContentResolver(), UIDS_ALLOWED_ON_RESTRICTED_NETWORKS);
1049 return getUidSetFromString(uidList);
paulhu69afcd52021-04-27 00:14:47 +08001050 }
1051
paulhu92f128c2021-07-01 18:04:45 +08001052 private static boolean isCallingFromSystem() {
1053 final int uid = Binder.getCallingUid();
1054 final int pid = Binder.getCallingPid();
1055 if (uid == Process.SYSTEM_UID && pid == Process.myPid()) {
1056 return true;
1057 }
1058 return false;
1059 }
1060
paulhu69afcd52021-04-27 00:14:47 +08001061 /**
paulhu91e78062021-05-26 16:16:57 +08001062 * Set the list of uids(from {@link Settings}) that is allowed to use restricted networks.
paulhu69afcd52021-04-27 00:14:47 +08001063 *
1064 * @param context The {@link Context} to set the setting.
paulhu91e78062021-05-26 16:16:57 +08001065 * @param uidList A list of uids that is allowed to use restricted networks.
paulhu69afcd52021-04-27 00:14:47 +08001066 */
paulhu91e78062021-05-26 16:16:57 +08001067 public static void setUidsAllowedOnRestrictedNetworks(@NonNull Context context,
1068 @NonNull Set<Integer> uidList) {
paulhu92f128c2021-07-01 18:04:45 +08001069 final boolean calledFromSystem = isCallingFromSystem();
1070 if (!calledFromSystem) {
1071 // Enforce NETWORK_SETTINGS check if it's debug build. This is for MTS test only.
1072 if (!Build.isDebuggable()) {
1073 throw new SecurityException("Only system can set this setting.");
1074 }
1075 context.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_SETTINGS,
1076 "Requires NETWORK_SETTINGS permission");
1077 }
paulhu91e78062021-05-26 16:16:57 +08001078 final String uids = getUidStringFromSet(uidList);
paulhu44280442021-05-31 10:42:13 +08001079 Settings.Global.putString(context.getContentResolver(), UIDS_ALLOWED_ON_RESTRICTED_NETWORKS,
paulhu91e78062021-05-26 16:16:57 +08001080 uids);
paulhu69afcd52021-04-27 00:14:47 +08001081 }
Patrick Rohra2084362022-01-03 15:55:52 +01001082
1083 /**
Patrick Rohrca7e5782022-02-18 10:34:20 +01001084 * Get the network bandwidth ingress rate limit.
Patrick Rohra2084362022-01-03 15:55:52 +01001085 *
Patrick Rohrca7e5782022-02-18 10:34:20 +01001086 * The limit is only applicable to networks that provide internet connectivity. -1 codes for no
1087 * bandwidth limitation.
Patrick Rohra2084362022-01-03 15:55:52 +01001088 *
1089 * @param context The {@link Context} to query the setting.
1090 * @return The rate limit in number of bytes per second or -1 if disabled.
1091 */
1092 public static long getIngressRateLimitInBytesPerSecond(@NonNull Context context) {
1093 return Settings.Global.getLong(context.getContentResolver(),
1094 INGRESS_RATE_LIMIT_BYTES_PER_SECOND, -1);
1095 }
1096
1097 /**
Patrick Rohrca7e5782022-02-18 10:34:20 +01001098 * Set the network bandwidth ingress rate limit.
Patrick Rohra2084362022-01-03 15:55:52 +01001099 *
Patrick Rohrca7e5782022-02-18 10:34:20 +01001100 * The limit is applied to all networks that provide internet connectivity. It is applied on a
1101 * per-network basis, meaning that global ingress rate could exceed the limit when communicating
1102 * on multiple networks simultaneously.
Patrick Rohra2084362022-01-03 15:55:52 +01001103 *
1104 * @param context The {@link Context} to set the setting.
1105 * @param rateLimitInBytesPerSec The rate limit in number of bytes per second or -1 to disable.
1106 */
1107 public static void setIngressRateLimitInBytesPerSecond(@NonNull Context context,
Patrick Rohrca7e5782022-02-18 10:34:20 +01001108 @IntRange(from = -1L, to = 0xFFFFFFFFL) long rateLimitInBytesPerSec) {
Patrick Rohra2084362022-01-03 15:55:52 +01001109 if (rateLimitInBytesPerSec < -1) {
1110 throw new IllegalArgumentException(
1111 "Rate limit must be within the range [-1, Integer.MAX_VALUE]");
1112 }
1113 Settings.Global.putLong(context.getContentResolver(),
1114 INGRESS_RATE_LIMIT_BYTES_PER_SECOND,
1115 rateLimitInBytesPerSec);
1116 }
paulhu845456e2021-03-17 17:19:09 +08001117}