Merge "Add an API hint for metered multipath traffic."

This commit is contained in:
Treehugger Robot
2017-04-10 05:40:08 +00:00
committed by Gerrit Code Review
5 changed files with 151 additions and 5 deletions

View File

@@ -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. * Resets all connectivity manager settings back to factory defaults.
* @hide * @hide

View File

@@ -161,6 +161,8 @@ interface IConnectivityManager
void setAcceptUnvalidated(in Network network, boolean accept, boolean always); void setAcceptUnvalidated(in Network network, boolean accept, boolean always);
void setAvoidUnvalidated(in Network network); void setAvoidUnvalidated(in Network network);
int getMultipathPreference(in Network Network);
int getRestoreDefaultNetworkDelay(int networkType); int getRestoreDefaultNetworkDelay(int networkType);
boolean addVpnAddress(String address, int prefixLength); boolean addVpnAddress(String address, int prefixLength);

View File

@@ -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 { private class InternalHandler extends Handler {
public InternalHandler(Looper looper) { public InternalHandler(Looper looper) {
super(looper); super(looper);

View File

@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.Uri; import android.net.Uri;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
@@ -29,10 +30,14 @@ import android.os.UserHandle;
import android.provider.Settings; import android.provider.Settings;
import android.util.Slog; import android.util.Slog;
import java.util.Arrays;
import java.util.List;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.R; import com.android.internal.R;
import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI; 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 * A class to encapsulate management of the "Smart Networking" capability of
@@ -57,12 +62,13 @@ public class MultinetworkPolicyTracker {
private final Context mContext; private final Context mContext;
private final Handler mHandler; private final Handler mHandler;
private final Runnable mReevaluateRunnable; private final Runnable mReevaluateRunnable;
private final Uri mAvoidBadWifiUri; private final List<Uri> mSettingsUris;
private final ContentResolver mResolver; private final ContentResolver mResolver;
private final SettingObserver mSettingObserver; private final SettingObserver mSettingObserver;
private final BroadcastReceiver mBroadcastReceiver; private final BroadcastReceiver mBroadcastReceiver;
private volatile boolean mAvoidBadWifi = true; private volatile boolean mAvoidBadWifi = true;
private volatile int mMeteredMultipathPreference;
public MultinetworkPolicyTracker(Context ctx, Handler handler) { public MultinetworkPolicyTracker(Context ctx, Handler handler) {
this(ctx, handler, null); this(ctx, handler, null);
@@ -72,9 +78,14 @@ public class MultinetworkPolicyTracker {
mContext = ctx; mContext = ctx;
mHandler = handler; mHandler = handler;
mReevaluateRunnable = () -> { 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(); mResolver = mContext.getContentResolver();
mSettingObserver = new SettingObserver(); mSettingObserver = new SettingObserver();
mBroadcastReceiver = new BroadcastReceiver() { mBroadcastReceiver = new BroadcastReceiver() {
@@ -85,10 +96,13 @@ public class MultinetworkPolicyTracker {
}; };
updateAvoidBadWifi(); updateAvoidBadWifi();
updateMeteredMultipathPreference();
} }
public void start() { public void start() {
mResolver.registerContentObserver(mAvoidBadWifiUri, false, mSettingObserver); for (Uri uri : mSettingsUris) {
mResolver.registerContentObserver(uri, false, mSettingObserver);
}
final IntentFilter intentFilter = new IntentFilter(); final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
@@ -108,6 +122,10 @@ public class MultinetworkPolicyTracker {
return mAvoidBadWifi; return mAvoidBadWifi;
} }
public int getMeteredMultipathPreference() {
return mMeteredMultipathPreference;
}
/** /**
* Whether the device or carrier configuration disables avoiding bad wifi by default. * Whether the device or carrier configuration disables avoiding bad wifi by default.
*/ */
@@ -138,6 +156,23 @@ public class MultinetworkPolicyTracker {
return mAvoidBadWifi != prev; 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 { private class SettingObserver extends ContentObserver {
public SettingObserver() { public SettingObserver() {
super(null); super(null);
@@ -150,7 +185,9 @@ public class MultinetworkPolicyTracker {
@Override @Override
public void onChange(boolean selfChange, Uri uri) { public void onChange(boolean selfChange, Uri uri) {
if (!mAvoidBadWifiUri.equals(uri)) return; if (!mSettingsUris.contains(uri)) {
Slog.wtf(TAG, "Unexpected settings observation: " + uri);
}
reevaluate(); reevaluate();
} }
} }

View File

@@ -632,6 +632,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
private class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker { private class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
public volatile boolean configRestrictsAvoidBadWifi; public volatile boolean configRestrictsAvoidBadWifi;
public volatile int configMeteredMultipathPreference;
public WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) { public WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
super(c, h, r); super(c, h, r);
@@ -641,6 +642,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
public boolean configRestrictsAvoidBadWifi() { public boolean configRestrictsAvoidBadWifi() {
return configRestrictsAvoidBadWifi; return configRestrictsAvoidBadWifi;
} }
@Override
public int configMeteredMultipathPreference() {
return configMeteredMultipathPreference;
}
} }
private class WrappedConnectivityService extends ConnectivityService { private class WrappedConnectivityService extends ConnectivityService {
@@ -2454,6 +2460,26 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mCm.unregisterNetworkCallback(defaultCallback); 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 * Validate that a satisfied network request does not trigger onUnavailable() once the
* time-out period expires. * time-out period expires.