From 838c66128fcd6ddcb36ef9b6d6aad8782012b8ff Mon Sep 17 00:00:00 2001 From: Leif Hendrik Wilden Date: Wed, 2 May 2018 12:05:24 -0700 Subject: [PATCH] Allow wifi and ethenet connected at same time. This will improve the user experience on Android TV devices, see bug for details. In addition when connecting adb to the device by ethernet for cts, wifi will not connect, causing lots of tests to fail. For example: [CTS7.1]android.net.wifi.cts.WifiInfoTest#testWifiInfoProperties [CTS7.1]android.net.cts.ConnectivityManagerTest#testConnectivityChanged_ manifestRequestOnlyPreN_shouldReceiveIntent Use command:settings to put global wifi_data_always_on 1 to enable it. Bug: 26102779 Test: Manual, CTS. Change-Id: I711d93061a6bc7164d98a858912f781e1b967406 --- .../android/server/ConnectivityService.java | 51 ++++++++++++++----- .../server/ConnectivityServiceTest.java | 16 +++--- 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index e41a09ef67..2c5327b9be 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -390,9 +390,9 @@ public class ConnectivityService extends IConnectivityManager.Stub private static final int EVENT_PROMPT_UNVALIDATED = 29; /** - * used internally to (re)configure mobile data always-on settings. + * used internally to (re)configure always-on networks. */ - private static final int EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON = 30; + private static final int EVENT_CONFIGURE_ALWAYS_ON_NETWORKS = 30; /** * used to add a network listener with a pending intent @@ -748,6 +748,12 @@ public class ConnectivityService extends IConnectivityManager.Stub mDefaultMobileDataRequest = createDefaultInternetRequestForTransport( NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST); + // The default WiFi request is a background request so that apps using WiFi are + // migrated to a better network (typically ethernet) when one comes up, instead + // of staying on WiFi forever. + mDefaultWifiRequest = createDefaultInternetRequestForTransport( + NetworkCapabilities.TRANSPORT_WIFI, NetworkRequest.Type.BACKGROUND_REQUEST); + mHandlerThread = new HandlerThread("ConnectivityServiceThread"); mHandlerThread.start(); mHandler = new InternalHandler(mHandlerThread.getLooper()); @@ -944,8 +950,8 @@ public class ConnectivityService extends IConnectivityManager.Stub // 2. Give FakeSettingsProvider an alternative notification mechanism and have the test use it // by subclassing SettingsObserver. @VisibleForTesting - void updateMobileDataAlwaysOn() { - mHandler.sendEmptyMessage(EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON); + void updateAlwaysOnNetworks() { + mHandler.sendEmptyMessage(EVENT_CONFIGURE_ALWAYS_ON_NETWORKS); } // See FakeSettingsProvider comment above. @@ -954,22 +960,30 @@ public class ConnectivityService extends IConnectivityManager.Stub mHandler.sendEmptyMessage(EVENT_PRIVATE_DNS_SETTINGS_CHANGED); } - private void handleMobileDataAlwaysOn() { + private void handleAlwaysOnNetworkRequest( + NetworkRequest networkRequest, String settingName, boolean defaultValue) { final boolean enable = toBool(Settings.Global.getInt( - mContext.getContentResolver(), Settings.Global.MOBILE_DATA_ALWAYS_ON, 1)); - final boolean isEnabled = (mNetworkRequests.get(mDefaultMobileDataRequest) != null); + mContext.getContentResolver(), settingName, encodeBool(defaultValue))); + final boolean isEnabled = (mNetworkRequests.get(networkRequest) != null); if (enable == isEnabled) { return; // Nothing to do. } if (enable) { handleRegisterNetworkRequest(new NetworkRequestInfo( - null, mDefaultMobileDataRequest, new Binder())); + null, networkRequest, new Binder())); } else { - handleReleaseNetworkRequest(mDefaultMobileDataRequest, Process.SYSTEM_UID); + handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID); } } + private void handleConfigureAlwaysOnNetworks() { + handleAlwaysOnNetworkRequest( + mDefaultMobileDataRequest,Settings.Global.MOBILE_DATA_ALWAYS_ON, true); + handleAlwaysOnNetworkRequest(mDefaultWifiRequest, Settings.Global.WIFI_ALWAYS_REQUESTED, + false); + } + private void registerSettingsCallbacks() { // Watch for global HTTP proxy changes. mSettingsObserver.observe( @@ -979,7 +993,12 @@ public class ConnectivityService extends IConnectivityManager.Stub // Watch for whether or not to keep mobile data always on. mSettingsObserver.observe( Settings.Global.getUriFor(Settings.Global.MOBILE_DATA_ALWAYS_ON), - EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON); + EVENT_CONFIGURE_ALWAYS_ON_NETWORKS); + + // Watch for whether or not to keep wifi always on. + mSettingsObserver.observe( + Settings.Global.getUriFor(Settings.Global.WIFI_ALWAYS_REQUESTED), + EVENT_CONFIGURE_ALWAYS_ON_NETWORKS); } private void registerPrivateDnsSettingsCallbacks() { @@ -1814,8 +1833,8 @@ public class ConnectivityService extends IConnectivityManager.Stub // for user to unlock device too. updateLockdownVpn(); - // Configure whether mobile data is always on. - mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON)); + // Create network requests for always-on networks. + mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_ALWAYS_ON_NETWORKS)); mHandler.sendMessage(mHandler.obtainMessage(EVENT_SYSTEM_READY)); @@ -3106,8 +3125,8 @@ public class ConnectivityService extends IConnectivityManager.Stub handlePromptUnvalidated((Network) msg.obj); break; } - case EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON: { - handleMobileDataAlwaysOn(); + case EVENT_CONFIGURE_ALWAYS_ON_NETWORKS: { + handleConfigureAlwaysOnNetworks(); break; } // Sent by KeepaliveTracker to process an app request on the state machine thread. @@ -4535,6 +4554,10 @@ public class ConnectivityService extends IConnectivityManager.Stub // priority networks like Wi-Fi are active. private final NetworkRequest mDefaultMobileDataRequest; + // Request used to optionally keep wifi data active even when higher + // priority networks like ethernet are active. + private final NetworkRequest mDefaultWifiRequest; + private NetworkAgentInfo getNetworkForRequest(int requestId) { synchronized (mNetworkForRequestId) { return mNetworkForRequestId.get(requestId); diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index fceaabddfe..7437805313 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -1070,13 +1070,13 @@ public class ConnectivityServiceTest { // Ensure that the default setting for Captive Portals is used for most tests setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT); - setMobileDataAlwaysOn(false); + setAlwaysOnNetworks(false); setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com"); } @After public void tearDown() throws Exception { - setMobileDataAlwaysOn(false); + setAlwaysOnNetworks(false); if (mCellNetworkAgent != null) { mCellNetworkAgent.disconnect(); mCellNetworkAgent = null; @@ -2027,7 +2027,7 @@ public class ConnectivityServiceTest { @Test public void testNetworkGoesIntoBackgroundAfterLinger() { - setMobileDataAlwaysOn(true); + setAlwaysOnNetworks(true); NetworkRequest request = new NetworkRequest.Builder() .clearCapabilities() .build(); @@ -2772,10 +2772,10 @@ public class ConnectivityServiceTest { Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, mode); } - private void setMobileDataAlwaysOn(boolean enable) { + private void setAlwaysOnNetworks(boolean enable) { ContentResolver cr = mServiceContext.getContentResolver(); Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, enable ? 1 : 0); - mService.updateMobileDataAlwaysOn(); + mService.updateAlwaysOnNetworks(); waitForIdle(); } @@ -2797,7 +2797,7 @@ public class ConnectivityServiceTest { public void testBackgroundNetworks() throws Exception { // Create a background request. We can't do this ourselves because ConnectivityService // doesn't have an API for it. So just turn on mobile data always on. - setMobileDataAlwaysOn(true); + setAlwaysOnNetworks(true); final NetworkRequest request = new NetworkRequest.Builder().build(); final NetworkRequest fgRequest = new NetworkRequest.Builder() .addCapability(NET_CAPABILITY_FOREGROUND).build(); @@ -2995,7 +2995,7 @@ public class ConnectivityServiceTest { // Turn on mobile data always on. The factory starts looking again. testFactory.expectAddRequests(1); - setMobileDataAlwaysOn(true); + setAlwaysOnNetworks(true); testFactory.waitForNetworkRequests(2); assertTrue(testFactory.getMyStartRequested()); @@ -3015,7 +3015,7 @@ public class ConnectivityServiceTest { // Turn off mobile data always on and expect the request to disappear... testFactory.expectRemoveRequests(1); - setMobileDataAlwaysOn(false); + setAlwaysOnNetworks(false); testFactory.waitForNetworkRequests(1); // ... and cell data to be torn down.