diff options
| -rw-r--r-- | api/current.txt | 4 | ||||
| -rw-r--r-- | api/system-current.txt | 4 | ||||
| -rw-r--r-- | api/test-current.txt | 4 | ||||
| -rw-r--r-- | core/java/android/net/ConnectivityManager.java | 69 | ||||
| -rw-r--r-- | core/java/android/net/IConnectivityManager.aidl | 2 | ||||
| -rwxr-xr-x | core/java/android/provider/Settings.java | 10 | ||||
| -rw-r--r-- | core/res/res/values/config.xml | 5 | ||||
| -rw-r--r-- | core/res/res/values/symbols.xml | 1 | ||||
| -rw-r--r-- | services/core/java/com/android/server/ConnectivityService.java | 12 | ||||
| -rw-r--r-- | services/net/java/android/net/util/MultinetworkPolicyTracker.java | 47 | ||||
| -rw-r--r-- | tests/net/java/com/android/server/ConnectivityServiceTest.java | 26 |
11 files changed, 179 insertions, 5 deletions
diff --git a/api/current.txt b/api/current.txt index 869d148142a7..ba9b1cce79fa 100644 --- a/api/current.txt +++ b/api/current.txt @@ -24604,6 +24604,7 @@ package android.net { method public android.net.Network getBoundNetworkForProcess(); method public android.net.ProxyInfo getDefaultProxy(); method public android.net.LinkProperties getLinkProperties(android.net.Network); + method public int getMultipathPreference(android.net.Network); method public android.net.NetworkCapabilities getNetworkCapabilities(android.net.Network); method public deprecated android.net.NetworkInfo getNetworkInfo(int); method public android.net.NetworkInfo getNetworkInfo(android.net.Network); @@ -24643,6 +24644,9 @@ package android.net { field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity"; field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork"; field public static final java.lang.String EXTRA_REASON = "reason"; + field public static final int MULTIPATH_PREFERENCE_HANDOVER = 1; // 0x1 + field public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 4; // 0x4 + field public static final int MULTIPATH_PREFERENCE_RELIABILITY = 2; // 0x2 field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1 field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3 field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2 diff --git a/api/system-current.txt b/api/system-current.txt index aa49f23ed8a3..a0b95006054a 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -26524,6 +26524,7 @@ package android.net { method public java.lang.String getCaptivePortalServerUrl(); method public android.net.ProxyInfo getDefaultProxy(); method public android.net.LinkProperties getLinkProperties(android.net.Network); + method public int getMultipathPreference(android.net.Network); method public android.net.NetworkCapabilities getNetworkCapabilities(android.net.Network); method public deprecated android.net.NetworkInfo getNetworkInfo(int); method public android.net.NetworkInfo getNetworkInfo(android.net.Network); @@ -26567,6 +26568,9 @@ package android.net { field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity"; field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork"; field public static final java.lang.String EXTRA_REASON = "reason"; + field public static final int MULTIPATH_PREFERENCE_HANDOVER = 1; // 0x1 + field public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 4; // 0x4 + field public static final int MULTIPATH_PREFERENCE_RELIABILITY = 2; // 0x2 field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1 field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3 field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2 diff --git a/api/test-current.txt b/api/test-current.txt index 86936d3d753f..682c0297426d 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -24696,6 +24696,7 @@ package android.net { method public android.net.Network getBoundNetworkForProcess(); method public android.net.ProxyInfo getDefaultProxy(); method public android.net.LinkProperties getLinkProperties(android.net.Network); + method public int getMultipathPreference(android.net.Network); method public android.net.NetworkCapabilities getNetworkCapabilities(android.net.Network); method public deprecated android.net.NetworkInfo getNetworkInfo(int); method public android.net.NetworkInfo getNetworkInfo(android.net.Network); @@ -24735,6 +24736,9 @@ package android.net { field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity"; field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork"; field public static final java.lang.String EXTRA_REASON = "reason"; + field public static final int MULTIPATH_PREFERENCE_HANDOVER = 1; // 0x1 + field public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 4; // 0x4 + field public static final int MULTIPATH_PREFERENCE_RELIABILITY = 2; // 0x2 field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1 field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3 field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2 diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index ac0c0dc5a916..222953e3ae6c 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -3264,6 +3264,75 @@ public class ConnectivityManager { } /** + * 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 4aabda9eb09d..117fa0b476f4 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -163,6 +163,8 @@ interface IConnectivityManager 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/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index d71ce346c0ce..d83f2cbf13bd 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8082,6 +8082,16 @@ public final class Settings { public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi"; /** + * User setting for ConnectivityManager.getMeteredMultipathPreference(). This value may be + * overridden by the system based on device or application state. If null, the value + * specified by config_networkMeteredMultipathPreference is used. + * + * @hide + */ + public static final String NETWORK_METERED_MULTIPATH_PREFERENCE = + "network_metered_multipath_preference"; + + /** * The thresholds of the wifi throughput badging (SD, HD etc.) as a comma-delimited list of * colon-delimited key-value pairs. The key is the badging enum value defined in * android.net.ScoredNetwork and the value is the minimum sustained network throughput in diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 98737622bb3e..fa1c7a103432 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -283,6 +283,11 @@ Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. --> <integer translatable="false" name="config_networkAvoidBadWifi">1</integer> + <!-- Default value for ConnectivityManager.getMultipathPreference() on metered networks. Actual + device behaviour is controlled by Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE. + This is the default value of that setting. --> + <integer translatable="false" name="config_networkMeteredMultipathPreference">3</integer> + <!-- List of regexpressions describing the interface (if any) that represent tetherable USB interfaces. If the device doesn't want to support tethering over USB this should be empty. An example would be "usb.*" --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index b2e37281f13c..571aa1730484 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1801,6 +1801,7 @@ <java-symbol type="integer" name="config_networkNotifySwitchType" /> <java-symbol type="array" name="config_networkNotifySwitches" /> <java-symbol type="integer" name="config_networkAvoidBadWifi" /> + <java-symbol type="integer" name="config_networkMeteredMultipathPreference" /> <java-symbol type="integer" name="config_notificationsBatteryFullARGB" /> <java-symbol type="integer" name="config_notificationsBatteryLedOff" /> <java-symbol type="integer" name="config_notificationsBatteryLedOn" /> diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index ebdd8e42aaac..719a64e32241 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2882,6 +2882,18 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + @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 ebd131bebb2b..424e40d2096f 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.Context; 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.os.UserHandle; 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 @@ public class MultinetworkPolicyTracker { 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 @@ public class MultinetworkPolicyTracker { 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 @@ public class MultinetworkPolicyTracker { }; 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 @@ public class MultinetworkPolicyTracker { return mAvoidBadWifi; } + public int getMeteredMultipathPreference() { + return mMeteredMultipathPreference; + } + /** * Whether the device or carrier configuration disables avoiding bad wifi by default. */ @@ -138,6 +156,23 @@ public class MultinetworkPolicyTracker { 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 @@ public class MultinetworkPolicyTracker { @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 39406a117410..eeaf26f92f47 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -595,6 +595,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { 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); @@ -604,6 +605,11 @@ public class ConnectivityServiceTest extends AndroidTestCase { public boolean configRestrictsAvoidBadWifi() { return configRestrictsAvoidBadWifi; } + + @Override + public int configMeteredMultipathPreference() { + return configMeteredMultipathPreference; + } } private class WrappedConnectivityService extends ConnectivityService { @@ -2282,6 +2288,26 @@ public class ConnectivityServiceTest extends AndroidTestCase { 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. |