diff --git a/common/flags.aconfig b/common/flags.aconfig index 2e552a1ba9..72352028a4 100644 --- a/common/flags.aconfig +++ b/common/flags.aconfig @@ -20,3 +20,10 @@ flag { description: "Remove expired services from MdnsServiceCache" bug: "304649384" } + +flag { + name: "set_data_saver_via_cm" + namespace: "android_core_networking" + description: "Set data saver through ConnectivityManager API" + bug: "297836825" +} diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt index 193bd920d2..782e20a981 100644 --- a/framework/api/module-lib-current.txt +++ b/framework/api/module-lib-current.txt @@ -24,6 +24,7 @@ package android.net { method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptPartialConnectivity(@NonNull android.net.Network, boolean, boolean); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptUnvalidated(@NonNull android.net.Network, boolean, boolean); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAvoidUnvalidated(@NonNull android.net.Network); + method @FlaggedApi("com.android.net.flags.set_data_saver_via_cm") @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setDataSaverEnabled(boolean); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setFirewallChainEnabled(int, boolean); method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setGlobalProxy(@Nullable android.net.ProxyInfo); method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setLegacyLockdownVpnEnabled(boolean); diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java index 23155210be..8963e308da 100644 --- a/framework/src/android/net/ConnectivityManager.java +++ b/framework/src/android/net/ConnectivityManager.java @@ -26,6 +26,7 @@ import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT; import static android.net.QosCallback.QosCallbackRegistrationException; import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -115,6 +116,14 @@ public class ConnectivityManager { private static final String TAG = "ConnectivityManager"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + // TODO : remove this class when udc-mainline-prod is abandoned and android.net.flags.Flags is + // available here + /** @hide */ + public static class Flags { + static final String SET_DATA_SAVER_VIA_CM = + "com.android.net.flags.set_data_saver_via_cm"; + } + /** * A change in network connectivity has occurred. A default connection has either * been established or lost. The NetworkInfo for the affected network is @@ -5940,6 +5949,28 @@ public class ConnectivityManager { return new Range(TUN_INTF_NETID_START, TUN_INTF_NETID_START + TUN_INTF_NETID_RANGE - 1); } + /** + * Sets data saver switch. + * + * @param enable True if enable. + * @throws IllegalStateException if failed. + * @hide + */ + @FlaggedApi(Flags.SET_DATA_SAVER_VIA_CM) + @SystemApi(client = MODULE_LIBRARIES) + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_STACK, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK + }) + public void setDataSaverEnabled(final boolean enable) { + try { + mService.setDataSaverEnabled(enable); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Adds the specified UID to the list of UIds that are allowed to use data on metered networks * even when background data is restricted. The deny list takes precedence over the allow list. diff --git a/framework/src/android/net/IConnectivityManager.aidl b/framework/src/android/net/IConnectivityManager.aidl index ebe8bca77e..9f56e7efb1 100644 --- a/framework/src/android/net/IConnectivityManager.aidl +++ b/framework/src/android/net/IConnectivityManager.aidl @@ -238,6 +238,8 @@ interface IConnectivityManager void setTestAllowBadWifiUntil(long timeMs); + void setDataSaverEnabled(boolean enable); + void updateMeteredNetworkAllowList(int uid, boolean add); void updateMeteredNetworkDenyList(int uid, boolean add); diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index c19878cb91..967bcc89c1 100755 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -12544,6 +12544,20 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + @Override + public void setDataSaverEnabled(final boolean enable) { + enforceNetworkStackOrSettingsPermission(); + try { + final boolean ret = mNetd.bandwidthEnableDataSaver(enable); + if (!ret) { + throw new IllegalStateException("Error when changing iptables: " + enable); + } + } catch (RemoteException e) { + // Lack of permission or binder errors. + throw new IllegalStateException(e); + } + } + @Override public void updateMeteredNetworkAllowList(final int uid, final boolean add) { enforceNetworkStackOrSettingsPermission();