summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2016-09-19 01:00:19 +0900
committergitbuildkicker <android-build@google.com>2016-09-21 19:41:45 -0700
commit1571c02dae5aa1fc831e242bf76fc0076e31d96c (patch)
tree8cd7218deab84f6f2676441138fe1e304e6559a3
parent8e64c012abae20bb75d0da0197718b63803c2c1d (diff)
downloadbase-1571c02dae5aa1fc831e242bf76fc0076e31d96c.tar.gz
Support "don't ask again" in the avoid bad wifi dialog.
This contains the following changes: 1. Make NETWORK_AVOID_BAD_WIFI a tristate: 0 means never avoid bad wifi, unset means prompt the user, 1 means always avoid. 2. Look at NETWORK_AVOID_BAD_WIFI only if the carrier restricts avoiding bad wifi (previously, we relied on the setting being null and defaulting to the value of the config variable). 3. Add an avoidUnvalidated bit to NetworkAgentInfo to track whether the user has requested switching away from this unvalidated network even though avoiding bad wifi is generally disabled. This is set to true when the user selects "switch" in the dialog without setting the "Don't ask again" checkbox. 4. Add a hidden setAvoidUnvalidated API to ConnectivityManager to set the avoidUnvalidated bit. 5. Additional unit test coverage. Bug: 31075769 Change-Id: I1be60c3016c8095df3c4752330149ce638bd0ce1 (cherry picked from commit 165c51c0eb9834a3d95ce0b31b07c7c8975a54d7)
-rw-r--r--core/java/android/net/ConnectivityManager.java21
-rw-r--r--core/java/android/net/IConnectivityManager.aidl1
-rwxr-xr-xcore/java/android/provider/Settings.java7
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java62
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java16
-rw-r--r--services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java97
6 files changed, 181 insertions, 23 deletions
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 52d6b56609de..b9e9b283106f 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3198,6 +3198,27 @@ public class ConnectivityManager {
}
/**
+ * Informs the system to penalize {@code network}'s score when it becomes unvalidated. This is
+ * only meaningful if the system is configured not to penalize such networks, e.g., if the
+ * {@code config_networkAvoidBadWifi} configuration variable is set to 0 and the {@code
+ * NETWORK_AVOID_BAD_WIFI setting is unset}.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}
+ *
+ * @param network The network to accept.
+ *
+ * @hide
+ */
+ public void setAvoidUnvalidated(Network network) {
+ try {
+ mService.setAvoidUnvalidated(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 d48c155986f3..4aabda9eb09d 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -161,6 +161,7 @@ interface IConnectivityManager
void releaseNetworkRequest(in NetworkRequest networkRequest);
void setAcceptUnvalidated(in Network network, boolean accept, boolean always);
+ void setAvoidUnvalidated(in Network network);
int getRestoreDefaultNetworkDelay(int networkType);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6949e43d9991..ce6fcdd71952 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7443,6 +7443,13 @@ public final class Settings {
/**
* Whether to automatically switch away from wifi networks that lose Internet access.
+ * Only meaningful if config_networkAvoidBadWifi is set to 0, otherwise the system always
+ * avoids such networks. Valid values are:
+ *
+ * 0: Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
+ * null: Ask the user whether to switch away from bad wifi.
+ * 1: Avoid bad wifi.
+ *
* @hide
*/
public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi";
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 59c8840ebf17..a0ef25ed4c57 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -366,6 +366,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
private static final int EVENT_SET_ACCEPT_UNVALIDATED = 28;
/**
+ * used to specify whether a network should not be penalized when it becomes unvalidated.
+ */
+ private static final int EVENT_SET_AVOID_UNVALIDATED = 35;
+
+ /**
* used to ask the user to confirm a connection to an unvalidated network.
* obj = network
*/
@@ -2681,6 +2686,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
accept ? 1 : 0, always ? 1: 0, network));
}
+ @Override
+ public void setAvoidUnvalidated(Network network) {
+ enforceConnectivityInternalPermission();
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_AVOID_UNVALIDATED, network));
+ }
+
private void handleSetAcceptUnvalidated(Network network, boolean accept, boolean always) {
if (DBG) log("handleSetAcceptUnvalidated network=" + network +
" accept=" + accept + " always=" + always);
@@ -2721,6 +2732,20 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
+ private void handleSetAvoidUnvalidated(Network network) {
+ NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+ if (nai == null || nai.lastValidated) {
+ // Nothing to do. The network either disconnected or revalidated.
+ return;
+ }
+ if (!nai.avoidUnvalidated) {
+ int oldScore = nai.getCurrentScore();
+ nai.avoidUnvalidated = true;
+ rematchAllNetworksAndRequests(nai, oldScore);
+ sendUpdatedScoreToFactories(nai);
+ }
+ }
+
private void scheduleUnvalidatedPrompt(NetworkAgentInfo nai) {
if (VDBG) log("scheduleUnvalidatedPrompt " + nai.network);
mHandler.sendMessageDelayed(
@@ -2728,28 +2753,31 @@ public class ConnectivityService extends IConnectivityManager.Stub
PROMPT_UNVALIDATED_DELAY_MS);
}
- private boolean mAvoidBadWifi;
+ private boolean mAvoidBadWifi = true;
public boolean avoidBadWifi() {
return mAvoidBadWifi;
}
@VisibleForTesting
- public boolean updateAvoidBadWifi() {
- // There are two modes: either we always automatically avoid unvalidated wifi, or we show a
- // dialog and don't switch to it. The behaviour is controlled by the NETWORK_AVOID_BAD_WIFI
- // setting. If the setting has no value, then the value is taken from the config value,
- // which can be changed via OEM/carrier overlays.
- //
- // The only valid values for NETWORK_AVOID_BAD_WIFI are null and unset. Currently, the unit
- // test uses 0 in order to avoid having to mock out fetching the carrier setting.
- int defaultAvoidBadWifi =
- mContext.getResources().getInteger(R.integer.config_networkAvoidBadWifi);
- int avoid = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.NETWORK_AVOID_BAD_WIFI, defaultAvoidBadWifi);
+ /** Whether the device or carrier configuration disables avoiding bad wifi by default. */
+ public boolean configRestrictsAvoidBadWifi() {
+ return mContext.getResources().getInteger(R.integer.config_networkAvoidBadWifi) == 0;
+ }
+
+ /** Whether we should display a notification when wifi becomes unvalidated. */
+ public boolean shouldNotifyWifiUnvalidated() {
+ return configRestrictsAvoidBadWifi() &&
+ Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.NETWORK_AVOID_BAD_WIFI) == null;
+ }
+
+ private boolean updateAvoidBadWifi() {
+ boolean settingAvoidBadWifi = "1".equals(Settings.Global.getString(
+ mContext.getContentResolver(), Settings.Global.NETWORK_AVOID_BAD_WIFI));
boolean prev = mAvoidBadWifi;
- mAvoidBadWifi = (avoid == 1);
+ mAvoidBadWifi = settingAvoidBadWifi || !configRestrictsAvoidBadWifi();
return mAvoidBadWifi != prev;
}
@@ -2802,7 +2830,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkCapabilities nc = nai.networkCapabilities;
if (DBG) log("handleNetworkUnvalidated " + nai.name() + " cap=" + nc);
- if (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) && !avoidBadWifi()) {
+ if (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) && shouldNotifyWifiUnvalidated()) {
showValidationNotification(nai, NotificationType.LOST_INTERNET);
}
}
@@ -2880,6 +2908,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
handleSetAcceptUnvalidated((Network) msg.obj, msg.arg1 != 0, msg.arg2 != 0);
break;
}
+ case EVENT_SET_AVOID_UNVALIDATED: {
+ handleSetAvoidUnvalidated((Network) msg.obj);
+ break;
+ }
case EVENT_PROMPT_UNVALIDATED: {
handlePromptUnvalidated((Network) msg.obj);
break;
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 3503eacb0735..9c48aeeefeb6 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -138,12 +138,14 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
public boolean everValidated;
// The result of the last validation attempt on this network (true if validated, false if not).
- // This bit exists only because we never unvalidate a network once it's been validated, and that
- // is because the network scoring and revalidation code does not (may not?) deal properly with
- // networks becoming unvalidated.
- // TODO: Fix the network scoring code, remove this, and rename everValidated to validated.
public boolean lastValidated;
+ // If true, becoming unvalidated will lower the network's score. This is only meaningful if the
+ // system is configured not to do this for certain networks, e.g., if the
+ // config_networkAvoidBadWifi option is set to 0 and the user has not overridden that via
+ // Settings.Global.NETWORK_AVOID_BAD_WIFI.
+ public boolean avoidUnvalidated;
+
// Whether a captive portal was ever detected on this network.
// This is a sticky bit; once set it is never cleared.
public boolean everCaptivePortalDetected;
@@ -365,8 +367,10 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
// Return true on devices configured to ignore score penalty for wifi networks
// that become unvalidated (b/31075769).
private boolean ignoreWifiUnvalidationPenalty() {
- boolean isWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
- return isWifi && !mConnService.avoidBadWifi() && everValidated;
+ boolean isWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) &&
+ networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ boolean avoidBadWifi = mConnService.avoidBadWifi() || avoidUnvalidated;
+ return isWifi && !avoidBadWifi && everValidated;
}
// Get the current score for this Network. This may be modified from what the
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index fa2381451af9..2055d16f3286 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -82,6 +82,7 @@ import com.android.server.net.NetworkPinner;
import java.net.InetAddress;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
@@ -601,6 +602,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
private class WrappedConnectivityService extends ConnectivityService {
private WrappedNetworkMonitor mLastCreatedNetworkMonitor;
+ public boolean configRestrictsAvoidBadWifi;
public WrappedConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager,
@@ -656,6 +658,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
return new FakeWakeupMessage(context, handler, cmdName, cmd, 0, 0, obj);
}
+ @Override
+ public boolean configRestrictsAvoidBadWifi() {
+ return configRestrictsAvoidBadWifi;
+ }
+
public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() {
return mLastCreatedNetworkMonitor;
}
@@ -1957,8 +1964,48 @@ public class ConnectivityServiceTest extends AndroidTestCase {
@SmallTest
public void testAvoidBadWifiSetting() throws Exception {
+ final ContentResolver cr = mServiceContext.getContentResolver();
+ final String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
+
+ mService.configRestrictsAvoidBadWifi = false;
+ String[] values = new String[] {null, "0", "1"};
+ for (int i = 0; i < values.length; i++) {
+ Settings.Global.putInt(cr, settingName, 1);
+ mService.updateNetworkAvoidBadWifi();
+ mService.waitForIdle();
+ String msg = String.format("config=false, setting=%s", values[i]);
+ assertTrue(msg, mService.avoidBadWifi());
+ assertFalse(msg, mService.shouldNotifyWifiUnvalidated());
+ }
+
+ mService.configRestrictsAvoidBadWifi = true;
+
+ Settings.Global.putInt(cr, settingName, 0);
+ mService.updateNetworkAvoidBadWifi();
+ mService.waitForIdle();
+ assertFalse(mService.avoidBadWifi());
+ assertFalse(mService.shouldNotifyWifiUnvalidated());
+
+ Settings.Global.putInt(cr, settingName, 1);
+ mService.updateNetworkAvoidBadWifi();
+ mService.waitForIdle();
+ assertTrue(mService.avoidBadWifi());
+ assertFalse(mService.shouldNotifyWifiUnvalidated());
+
+ Settings.Global.putString(cr, settingName, null);
+ mService.updateNetworkAvoidBadWifi();
+ mService.waitForIdle();
+ assertFalse(mService.avoidBadWifi());
+ assertTrue(mService.shouldNotifyWifiUnvalidated());
+ }
+
+ @SmallTest
+ public void testAvoidBadWifi() throws Exception {
ContentResolver cr = mServiceContext.getContentResolver();
+ // Pretend we're on a carrier that restricts switching away from bad wifi.
+ mService.configRestrictsAvoidBadWifi = true;
+
// File a request for cell to ensure it doesn't go down.
final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
final NetworkRequest cellRequest = new NetworkRequest.Builder()
@@ -1975,8 +2022,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
TestNetworkCallback validatedWifiCallback = new TestNetworkCallback();
mCm.registerNetworkCallback(validatedWifiRequest, validatedWifiCallback);
- // Takes effect on every rematch.
Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 0);
+ mService.updateNetworkAvoidBadWifi();
// Bring up validated cell.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -2005,7 +2052,42 @@ public class ConnectivityServiceTest extends AndroidTestCase {
NET_CAPABILITY_VALIDATED));
assertEquals(mCm.getActiveNetwork(), wifiNetwork);
- // Simulate the user selecting "switch" on the dialog.
+ // Simulate switching to a carrier that does not restrict avoiding bad wifi, and expect
+ // that we switch back to cell.
+ mService.configRestrictsAvoidBadWifi = false;
+ mService.updateNetworkAvoidBadWifi();
+ defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ assertEquals(mCm.getActiveNetwork(), cellNetwork);
+
+ // Switch back to a restrictive carrier.
+ mService.configRestrictsAvoidBadWifi = true;
+ mService.updateNetworkAvoidBadWifi();
+ defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ assertEquals(mCm.getActiveNetwork(), wifiNetwork);
+
+ // Simulate the user selecting "switch" on the dialog, and check that we switch to cell.
+ mCm.setAvoidUnvalidated(wifiNetwork);
+ defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
+ NET_CAPABILITY_VALIDATED));
+ assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
+ NET_CAPABILITY_VALIDATED));
+ assertEquals(mCm.getActiveNetwork(), cellNetwork);
+
+ // Disconnect and reconnect wifi to clear the one-time switch above.
+ mWiFiNetworkAgent.disconnect();
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+ defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ validatedWifiCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ wifiNetwork = mWiFiNetworkAgent.getNetwork();
+
+ // Fail validation on wifi and expect the dialog to appear.
+ mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
+ mCm.reportNetworkConnectivity(wifiNetwork, false);
+ validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+
+ // Simulate the user selecting "switch" and checking the don't ask again checkbox.
Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
mService.updateNetworkAvoidBadWifi();
@@ -2017,6 +2099,17 @@ public class ConnectivityServiceTest extends AndroidTestCase {
NET_CAPABILITY_VALIDATED));
assertEquals(mCm.getActiveNetwork(), cellNetwork);
+ // Simulate the user turning the cellular fallback setting off and then on.
+ // We switch to wifi and then to cell.
+ Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
+ mService.updateNetworkAvoidBadWifi();
+ defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ assertEquals(mCm.getActiveNetwork(), wifiNetwork);
+ Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
+ mService.updateNetworkAvoidBadWifi();
+ defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ assertEquals(mCm.getActiveNetwork(), cellNetwork);
+
// If cell goes down, we switch to wifi.
mCellNetworkAgent.disconnect();
defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);