Merge "Add an API hint for metered multipath traffic."
This commit is contained in:
@@ -3406,6 +3406,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
|
||||
|
||||
@@ -161,6 +161,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);
|
||||
|
||||
@@ -2838,6 +2838,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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -632,6 +632,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);
|
||||
@@ -641,6 +642,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
||||
public boolean configRestrictsAvoidBadWifi() {
|
||||
return configRestrictsAvoidBadWifi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int configMeteredMultipathPreference() {
|
||||
return configMeteredMultipathPreference;
|
||||
}
|
||||
}
|
||||
|
||||
private class WrappedConnectivityService extends ConnectivityService {
|
||||
@@ -2454,6 +2460,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.
|
||||
|
||||
Reference in New Issue
Block a user