From 6eac9fb7870376e90ae271c94915a15288e60bd2 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Thu, 17 Jun 2021 22:11:30 +0800 Subject: [PATCH] Provide a way to override the avoid bad wifi configuration ConnectivityManager.setAvoidUnvalidated only works if the config_networkAvoidBadWifi configuration is set to 0 and the NETWORK_AVOID_BAD_WIFI setting is unset. There is no easy way for a testing app to temporary set a test value to verify the behavior of the API. Thus, add a mechanism to allow test app to set a period of time to temporary unstrict the resource configuration, i.e. Temporary simulate config_networkAvoidBadWifi configured to 0. Bug: 186061922 Test: atest CtsNetTestCases FrameworksNetTests Change-Id: If772078c61a9b12926f104d5dfc9c9071e844732 --- .../src/android/net/ConnectivityManager.java | 16 ++++ .../src/android/net/IConnectivityManager.aidl | 2 + .../net/util/MultinetworkPolicyTracker.java | 20 ++++- .../android/server/ConnectivityService.java | 31 ++++++++ .../server/ConnectivityServiceTest.java | 75 +++++++++++++------ 5 files changed, 119 insertions(+), 25 deletions(-) diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java index 20f38533cb..badf2c1025 100644 --- a/framework/src/android/net/ConnectivityManager.java +++ b/framework/src/android/net/ConnectivityManager.java @@ -4703,6 +4703,22 @@ public class ConnectivityManager { } } + /** + * Temporarily allow bad wifi to override {@code config_networkAvoidBadWifi} configuration. + * + * @param timeMs The expired current time. The value should be set within a limited time from + * now. + * + * @hide + */ + public void setTestAllowBadWifiUntil(long timeMs) { + try { + mService.setTestAllowBadWifiUntil(timeMs); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Requests that the system open the captive portal app on the specified network. * diff --git a/framework/src/android/net/IConnectivityManager.aidl b/framework/src/android/net/IConnectivityManager.aidl index c434bbcb0f..50ec78120f 100644 --- a/framework/src/android/net/IConnectivityManager.aidl +++ b/framework/src/android/net/IConnectivityManager.aidl @@ -226,4 +226,6 @@ interface IConnectivityManager void offerNetwork(int providerId, in NetworkScore score, in NetworkCapabilities caps, in INetworkOfferCallback callback); void unofferNetwork(in INetworkOfferCallback callback); + + void setTestAllowBadWifiUntil(long timeMs); } diff --git a/framework/src/android/net/util/MultinetworkPolicyTracker.java b/framework/src/android/net/util/MultinetworkPolicyTracker.java index 0b42a00369..7e62d288f8 100644 --- a/framework/src/android/net/util/MultinetworkPolicyTracker.java +++ b/framework/src/android/net/util/MultinetworkPolicyTracker.java @@ -75,6 +75,7 @@ public class MultinetworkPolicyTracker { private volatile boolean mAvoidBadWifi = true; private volatile int mMeteredMultipathPreference; private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + private volatile long mTestAllowBadWifiUntilMs = 0; // Mainline module can't use internal HandlerExecutor, so add an identical executor here. private static class HandlerExecutor implements Executor { @@ -162,14 +163,31 @@ public class MultinetworkPolicyTracker { * Whether the device or carrier configuration disables avoiding bad wifi by default. */ public boolean configRestrictsAvoidBadWifi() { + final boolean allowBadWifi = mTestAllowBadWifiUntilMs > 0 + && mTestAllowBadWifiUntilMs > System.currentTimeMillis(); + // If the config returns true, then avoid bad wifi design can be controlled by the + // NETWORK_AVOID_BAD_WIFI setting. + if (allowBadWifi) return true; + // TODO: use R.integer.config_networkAvoidBadWifi directly final int id = mResources.get().getIdentifier("config_networkAvoidBadWifi", "integer", mResources.getResourcesContext().getPackageName()); return (getResourcesForActiveSubId().getInteger(id) == 0); } + /** + * Temporarily allow bad wifi to override {@code config_networkAvoidBadWifi} configuration. + * The value works when the time set is more than {@link System.currentTimeMillis()}. + */ + public void setTestAllowBadWifiUntil(long timeMs) { + Log.d(TAG, "setTestAllowBadWifiUntil: " + mTestAllowBadWifiUntilMs); + mTestAllowBadWifiUntilMs = timeMs; + updateAvoidBadWifi(); + } + + @VisibleForTesting @NonNull - private Resources getResourcesForActiveSubId() { + protected Resources getResourcesForActiveSubId() { return SubscriptionManager.getResourcesForSubId( mResources.getResourcesContext(), mActiveSubId); } diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index fd8397fe38..05bacfaeaf 100644 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -650,6 +650,12 @@ public class ConnectivityService extends IConnectivityManager.Stub */ private static final int EVENT_MOBILE_DATA_PREFERRED_UIDS_CHANGED = 54; + /** + * Event to set temporary allow bad wifi within a limited time to override + * {@code config_networkAvoidBadWifi}. + */ + private static final int EVENT_SET_TEST_ALLOW_BAD_WIFI_UNTIL = 55; + /** * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification * should be shown. @@ -662,6 +668,11 @@ public class ConnectivityService extends IConnectivityManager.Stub */ private static final int PROVISIONING_NOTIFICATION_HIDE = 0; + /** + * The maximum alive time to allow bad wifi configuration for testing. + */ + private static final long MAX_TEST_ALLOW_BAD_WIFI_UNTIL_MS = 5 * 60 * 1000L; + private static String eventName(int what) { return sMagicDecoderRing.get(what, Integer.toString(what)); } @@ -4334,6 +4345,22 @@ public class ConnectivityService extends IConnectivityManager.Stub mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_AVOID_UNVALIDATED, network)); } + @Override + public void setTestAllowBadWifiUntil(long timeMs) { + enforceSettingsPermission(); + if (!Build.isDebuggable()) { + throw new IllegalStateException("Does not support in non-debuggable build"); + } + + if (timeMs > System.currentTimeMillis() + MAX_TEST_ALLOW_BAD_WIFI_UNTIL_MS) { + throw new IllegalArgumentException("It should not exceed " + + MAX_TEST_ALLOW_BAD_WIFI_UNTIL_MS + "ms from now"); + } + + mHandler.sendMessage( + mHandler.obtainMessage(EVENT_SET_TEST_ALLOW_BAD_WIFI_UNTIL, timeMs)); + } + private void handleSetAcceptUnvalidated(Network network, boolean accept, boolean always) { if (DBG) log("handleSetAcceptUnvalidated network=" + network + " accept=" + accept + " always=" + always); @@ -4876,6 +4903,10 @@ public class ConnectivityService extends IConnectivityManager.Stub case EVENT_MOBILE_DATA_PREFERRED_UIDS_CHANGED: handleMobileDataPreferredUidsChanged(); break; + case EVENT_SET_TEST_ALLOW_BAD_WIFI_UNTIL: + final long timeMs = ((Long) msg.obj).longValue(); + mMultinetworkPolicyTracker.setTestAllowBadWifiUntil(timeMs); + break; } } } diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java index 3b030d65f8..6c484cca06 100644 --- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java @@ -1496,8 +1496,7 @@ public class ConnectivityServiceTest { return mService.getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd; } - private static class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker { - volatile boolean mConfigRestrictsAvoidBadWifi; + private class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker { volatile int mConfigMeteredMultipathPreference; WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) { @@ -1505,8 +1504,8 @@ public class ConnectivityServiceTest { } @Override - public boolean configRestrictsAvoidBadWifi() { - return mConfigRestrictsAvoidBadWifi; + protected Resources getResourcesForActiveSubId() { + return mResources; } @Override @@ -1723,7 +1722,9 @@ public class ConnectivityServiceTest { .getIdentifier(eq("config_networkSupportedKeepaliveCount"), eq("array"), any()); doReturn(R.array.network_switch_type_name).when(mResources) .getIdentifier(eq("network_switch_type_name"), eq("array"), any()); - + doReturn(R.integer.config_networkAvoidBadWifi).when(mResources) + .getIdentifier(eq("config_networkAvoidBadWifi"), eq("integer"), any()); + doReturn(1).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi); final ConnectivityResources connRes = mock(ConnectivityResources.class); doReturn(mResources).when(connRes).get(); @@ -4645,30 +4646,29 @@ public class ConnectivityServiceTest { } @Test - public void testAvoidBadWifiSetting() throws Exception { + public void testSetAllowBadWifiUntil() throws Exception { + runAsShell(NETWORK_SETTINGS, + () -> mService.setTestAllowBadWifiUntil(System.currentTimeMillis() + 5_000L)); + waitForIdle(); + testAvoidBadWifiConfig_controlledBySettings(); + + runAsShell(NETWORK_SETTINGS, + () -> mService.setTestAllowBadWifiUntil(System.currentTimeMillis() - 5_000L)); + waitForIdle(); + testAvoidBadWifiConfig_ignoreSettings(); + } + + private void testAvoidBadWifiConfig_controlledBySettings() { final ContentResolver cr = mServiceContext.getContentResolver(); final String settingName = ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI; - mPolicyTracker.mConfigRestrictsAvoidBadWifi = false; - String[] values = new String[] {null, "0", "1"}; - for (int i = 0; i < values.length; i++) { - Settings.Global.putInt(cr, settingName, 1); - mPolicyTracker.reevaluate(); - waitForIdle(); - String msg = String.format("config=false, setting=%s", values[i]); - assertTrue(mService.avoidBadWifi()); - assertFalse(msg, mPolicyTracker.shouldNotifyWifiUnvalidated()); - } - - mPolicyTracker.mConfigRestrictsAvoidBadWifi = true; - - Settings.Global.putInt(cr, settingName, 0); + Settings.Global.putString(cr, settingName, "0"); mPolicyTracker.reevaluate(); waitForIdle(); assertFalse(mService.avoidBadWifi()); assertFalse(mPolicyTracker.shouldNotifyWifiUnvalidated()); - Settings.Global.putInt(cr, settingName, 1); + Settings.Global.putString(cr, settingName, "1"); mPolicyTracker.reevaluate(); waitForIdle(); assertTrue(mService.avoidBadWifi()); @@ -4681,13 +4681,40 @@ public class ConnectivityServiceTest { assertTrue(mPolicyTracker.shouldNotifyWifiUnvalidated()); } + private void testAvoidBadWifiConfig_ignoreSettings() { + final ContentResolver cr = mServiceContext.getContentResolver(); + final String settingName = ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI; + + String[] values = new String[] {null, "0", "1"}; + for (int i = 0; i < values.length; i++) { + Settings.Global.putString(cr, settingName, values[i]); + mPolicyTracker.reevaluate(); + waitForIdle(); + String msg = String.format("config=false, setting=%s", values[i]); + assertTrue(mService.avoidBadWifi()); + assertFalse(msg, mPolicyTracker.shouldNotifyWifiUnvalidated()); + } + } + + @Test + public void testAvoidBadWifiSetting() throws Exception { + final ContentResolver cr = mServiceContext.getContentResolver(); + final String settingName = ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI; + + doReturn(1).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi); + testAvoidBadWifiConfig_ignoreSettings(); + + doReturn(0).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi); + testAvoidBadWifiConfig_controlledBySettings(); + } + @Ignore("Refactoring in progress b/178071397") @Test public void testAvoidBadWifi() throws Exception { final ContentResolver cr = mServiceContext.getContentResolver(); // Pretend we're on a carrier that restricts switching away from bad wifi. - mPolicyTracker.mConfigRestrictsAvoidBadWifi = true; + doReturn(0).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi); // File a request for cell to ensure it doesn't go down. final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback(); @@ -4738,13 +4765,13 @@ public class ConnectivityServiceTest { // Simulate switching to a carrier that does not restrict avoiding bad wifi, and expect // that we switch back to cell. - mPolicyTracker.mConfigRestrictsAvoidBadWifi = false; + doReturn(1).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi); mPolicyTracker.reevaluate(); defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); assertEquals(mCm.getActiveNetwork(), cellNetwork); // Switch back to a restrictive carrier. - mPolicyTracker.mConfigRestrictsAvoidBadWifi = true; + doReturn(0).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi); mPolicyTracker.reevaluate(); defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); assertEquals(mCm.getActiveNetwork(), wifiNetwork);