Merge "Add an API hint for metered multipath traffic."
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index cfbd948..2a985e7 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3407,6 +3407,75 @@
}
/**
+ * It is acceptable to briefly use multipath data to provide seamless connectivity for
+ * time-sensitive user-facing operations when the system default network is temporarily
+ * unresponsive. The amount of data should be limited (less than one megabyte), and the
+ * operation should be infrequent to ensure that data usage is limited.
+ *
+ * An example of such an operation might be a time-sensitive foreground activity, such as a
+ * voice command, that the user is performing while walking out of range of a Wi-Fi network.
+ */
+ public static final int MULTIPATH_PREFERENCE_HANDOVER = 1 << 0;
+
+ /**
+ * It is acceptable to use small amounts of multipath data on an ongoing basis to provide
+ * a backup channel for traffic that is primarily going over another network.
+ *
+ * An example might be maintaining backup connections to peers or servers for the purpose of
+ * fast fallback if the default network is temporarily unresponsive or disconnects. The traffic
+ * on backup paths should be negligible compared to the traffic on the main path.
+ */
+ public static final int MULTIPATH_PREFERENCE_RELIABILITY = 1 << 1;
+
+ /**
+ * It is acceptable to use metered data to improve network latency and performance.
+ */
+ public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 1 << 2;
+
+ /**
+ * Return value to use for unmetered networks. On such networks we currently set all the flags
+ * to true.
+ * @hide
+ */
+ public static final int MULTIPATH_PREFERENCE_UNMETERED =
+ MULTIPATH_PREFERENCE_HANDOVER |
+ MULTIPATH_PREFERENCE_RELIABILITY |
+ MULTIPATH_PREFERENCE_PERFORMANCE;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, value = {
+ MULTIPATH_PREFERENCE_HANDOVER,
+ MULTIPATH_PREFERENCE_RELIABILITY,
+ MULTIPATH_PREFERENCE_PERFORMANCE,
+ })
+ public @interface MultipathPreference {
+ }
+
+ /**
+ * Provides a hint to the calling application on whether it is desirable to use the
+ * multinetwork APIs (e.g., {@link Network#openConnection}, {@link Network#bindSocket}, etc.)
+ * for multipath data transfer on this network when it is not the system default network.
+ * Applications desiring to use multipath network protocols should call this method before
+ * each such operation.
+ * <p>
+ * This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+ *
+ * @param network The network on which the application desires to use multipath data.
+ * If {@code null}, this method will return the a preference that will generally
+ * apply to metered networks.
+ * @return a bitwise OR of zero or more of the {@code MULTIPATH_PREFERENCE_*} constants.
+ */
+ public @MultipathPreference int getMultipathPreference(Network network) {
+ try {
+ return mService.getMultipathPreference(network);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Resets all connectivity manager settings back to factory defaults.
* @hide
*/
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index b123c28..425e494 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -161,6 +161,8 @@
void setAcceptUnvalidated(in Network network, boolean accept, boolean always);
void setAvoidUnvalidated(in Network network);
+ int getMultipathPreference(in Network Network);
+
int getRestoreDefaultNetworkDelay(int networkType);
boolean addVpnAddress(String address, int prefixLength);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7031662..9dde3e2 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2838,6 +2838,18 @@
}
}
+ @Override
+ public int getMultipathPreference(Network network) {
+ enforceAccessPermission();
+
+ NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+ if (nai != null && !nai.networkInfo.isMetered()) {
+ return ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED;
+ }
+
+ return mMultinetworkPolicyTracker.getMeteredMultipathPreference();
+ }
+
private class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
diff --git a/services/net/java/android/net/util/MultinetworkPolicyTracker.java b/services/net/java/android/net/util/MultinetworkPolicyTracker.java
index ebd131b..424e40d 100644
--- a/services/net/java/android/net/util/MultinetworkPolicyTracker.java
+++ b/services/net/java/android/net/util/MultinetworkPolicyTracker.java
@@ -22,6 +22,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
+import android.net.ConnectivityManager;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
@@ -29,10 +30,14 @@
import android.provider.Settings;
import android.util.Slog;
+import java.util.Arrays;
+import java.util.List;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.R;
import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
+import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
/**
* A class to encapsulate management of the "Smart Networking" capability of
@@ -57,12 +62,13 @@
private final Context mContext;
private final Handler mHandler;
private final Runnable mReevaluateRunnable;
- private final Uri mAvoidBadWifiUri;
+ private final List<Uri> mSettingsUris;
private final ContentResolver mResolver;
private final SettingObserver mSettingObserver;
private final BroadcastReceiver mBroadcastReceiver;
private volatile boolean mAvoidBadWifi = true;
+ private volatile int mMeteredMultipathPreference;
public MultinetworkPolicyTracker(Context ctx, Handler handler) {
this(ctx, handler, null);
@@ -72,9 +78,14 @@
mContext = ctx;
mHandler = handler;
mReevaluateRunnable = () -> {
- if (updateAvoidBadWifi() && avoidBadWifiCallback != null) avoidBadWifiCallback.run();
+ if (updateAvoidBadWifi() && avoidBadWifiCallback != null) {
+ avoidBadWifiCallback.run();
+ }
+ updateMeteredMultipathPreference();
};
- mAvoidBadWifiUri = Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI);
+ mSettingsUris = Arrays.asList(
+ Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI),
+ Settings.Global.getUriFor(NETWORK_METERED_MULTIPATH_PREFERENCE));
mResolver = mContext.getContentResolver();
mSettingObserver = new SettingObserver();
mBroadcastReceiver = new BroadcastReceiver() {
@@ -85,10 +96,13 @@
};
updateAvoidBadWifi();
+ updateMeteredMultipathPreference();
}
public void start() {
- mResolver.registerContentObserver(mAvoidBadWifiUri, false, mSettingObserver);
+ for (Uri uri : mSettingsUris) {
+ mResolver.registerContentObserver(uri, false, mSettingObserver);
+ }
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
@@ -108,6 +122,10 @@
return mAvoidBadWifi;
}
+ public int getMeteredMultipathPreference() {
+ return mMeteredMultipathPreference;
+ }
+
/**
* Whether the device or carrier configuration disables avoiding bad wifi by default.
*/
@@ -138,6 +156,23 @@
return mAvoidBadWifi != prev;
}
+ /**
+ * The default (device and carrier-dependent) value for metered multipath preference.
+ */
+ public int configMeteredMultipathPreference() {
+ return mContext.getResources().getInteger(
+ R.integer.config_networkMeteredMultipathPreference);
+ }
+
+ public void updateMeteredMultipathPreference() {
+ String setting = Settings.Global.getString(mResolver, NETWORK_METERED_MULTIPATH_PREFERENCE);
+ try {
+ mMeteredMultipathPreference = Integer.parseInt(setting);
+ } catch (NumberFormatException e) {
+ mMeteredMultipathPreference = configMeteredMultipathPreference();
+ }
+ }
+
private class SettingObserver extends ContentObserver {
public SettingObserver() {
super(null);
@@ -150,7 +185,9 @@
@Override
public void onChange(boolean selfChange, Uri uri) {
- if (!mAvoidBadWifiUri.equals(uri)) return;
+ if (!mSettingsUris.contains(uri)) {
+ Slog.wtf(TAG, "Unexpected settings observation: " + uri);
+ }
reevaluate();
}
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 1cf0d53..2f5c97d 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -632,6 +632,7 @@
private class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
public volatile boolean configRestrictsAvoidBadWifi;
+ public volatile int configMeteredMultipathPreference;
public WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
super(c, h, r);
@@ -641,6 +642,11 @@
public boolean configRestrictsAvoidBadWifi() {
return configRestrictsAvoidBadWifi;
}
+
+ @Override
+ public int configMeteredMultipathPreference() {
+ return configMeteredMultipathPreference;
+ }
}
private class WrappedConnectivityService extends ConnectivityService {
@@ -2454,6 +2460,26 @@
mCm.unregisterNetworkCallback(defaultCallback);
}
+ @SmallTest
+ public void testMeteredMultipathPreferenceSetting() throws Exception {
+ final ContentResolver cr = mServiceContext.getContentResolver();
+ final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
+ final String settingName = Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
+
+ for (int config : Arrays.asList(0, 3, 2)) {
+ for (String setting: Arrays.asList(null, "0", "2", "1")) {
+ tracker.configMeteredMultipathPreference = config;
+ Settings.Global.putString(cr, settingName, setting);
+ tracker.reevaluate();
+ mService.waitForIdle();
+
+ final int expected = (setting != null) ? Integer.parseInt(setting) : config;
+ String msg = String.format("config=%d, setting=%s", config, setting);
+ assertEquals(msg, expected, mCm.getMultipathPreference(null));
+ }
+ }
+ }
+
/**
* Validate that a satisfied network request does not trigger onUnavailable() once the
* time-out period expires.