Add RESTRICTED_ALLOWED_APPS setting

This setting is OEM upstream requirement for third party apps
using restricted networks.

Bug: 185149952
Test: atests FrameworksNetTests
Change-Id: I5e16b46cf2935f38ee1e516bb8b85fa487cf9f61
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index 78dff21..524db18 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -65,6 +65,7 @@
     method @NonNull public static String getPrivateDnsDefaultMode(@NonNull android.content.Context);
     method @Nullable public static String getPrivateDnsHostname(@NonNull android.content.Context);
     method public static int getPrivateDnsMode(@NonNull android.content.Context);
+    method @NonNull public static java.util.Set<java.lang.String> getRestrictedAllowedApps(@NonNull android.content.Context);
     method public static boolean getWifiAlwaysRequested(@NonNull android.content.Context, boolean);
     method @NonNull public static java.time.Duration getWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
     method public static void setCaptivePortalHttpUrl(@NonNull android.content.Context, @Nullable String);
@@ -84,6 +85,7 @@
     method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull int);
     method public static void setPrivateDnsHostname(@NonNull android.content.Context, @Nullable String);
     method public static void setPrivateDnsMode(@NonNull android.content.Context, int);
+    method public static void setRestrictedAllowedApps(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.String>);
     method public static void setWifiAlwaysRequested(@NonNull android.content.Context, boolean);
     method public static void setWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
     field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2
diff --git a/framework/src/android/net/ConnectivitySettingsManager.java b/framework/src/android/net/ConnectivitySettingsManager.java
index 31e1fb0..c4bb2d3 100644
--- a/framework/src/android/net/ConnectivitySettingsManager.java
+++ b/framework/src/android/net/ConnectivitySettingsManager.java
@@ -30,6 +30,7 @@
 import android.net.ConnectivityManager.MultipathPreference;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.Range;
 
 import com.android.net.module.util.ProxyUtils;
@@ -38,6 +39,9 @@
 import java.lang.annotation.RetentionPolicy;
 import java.time.Duration;
 import java.util.List;
+import java.util.Set;
+import java.util.StringJoiner;
+import java.util.regex.Pattern;
 
 /**
  * A manager class for connectivity module settings.
@@ -369,6 +373,13 @@
     private static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING = "hostname";
 
     /**
+     * A list of apps that should be granted netd system permission for using restricted networks.
+     *
+     * @hide
+     */
+    public static final String RESTRICTED_ALLOWED_APPS = "restricted_allowed_apps";
+
+    /**
      * Get mobile data activity timeout from {@link Settings}.
      *
      * @param context The {@link Context} to query the setting.
@@ -1014,4 +1025,47 @@
     public static void setMobileDataPreferredApps(@NonNull Context context, @Nullable String list) {
         Settings.Secure.putString(context.getContentResolver(), MOBILE_DATA_PREFERRED_APPS, list);
     }
+
+    /**
+     * Get the list of apps(from {@link Settings}) that should be granted netd system permission for
+     * using restricted networks.
+     *
+     * @param context The {@link Context} to query the setting.
+     * @return A list of apps that should be granted netd system permission for using restricted
+     *         networks or null if no setting value.
+     */
+    @NonNull
+    public static Set<String> getRestrictedAllowedApps(@NonNull Context context) {
+        final String appList = Settings.Secure.getString(
+                context.getContentResolver(), RESTRICTED_ALLOWED_APPS);
+        if (TextUtils.isEmpty(appList)) {
+            return new ArraySet<>();
+        }
+        return new ArraySet<>(appList.split(";"));
+    }
+
+    /**
+     * Set the list of apps(from {@link Settings}) that should be granted netd system permission for
+     * using restricted networks.
+     *
+     * Note: Please refer to android developer guidelines for valid app(package name).
+     * https://developer.android.com/guide/topics/manifest/manifest-element.html#package
+     *
+     * @param context The {@link Context} to set the setting.
+     * @param list A list of apps that should be granted netd system permission for using
+     *             restricted networks.
+     */
+    public static void setRestrictedAllowedApps(@NonNull Context context,
+            @NonNull Set<String> list) {
+        final Pattern appPattern = Pattern.compile("[a-zA-Z_0-9]+([.][a-zA-Z_0-9]+)*");
+        final StringJoiner joiner = new StringJoiner(";");
+        for (String app : list) {
+            if (!appPattern.matcher(app).matches()) {
+                throw new IllegalArgumentException("Invalid app(package name)");
+            }
+            joiner.add(app);
+        }
+        Settings.Secure.putString(
+                context.getContentResolver(), RESTRICTED_ALLOWED_APPS, joiner.toString());
+    }
 }