From 878e0cccd652ea556680b9cc101b01142e9ad919 Mon Sep 17 00:00:00 2001 From: Rebecca Silberstein Date: Tue, 16 May 2017 10:51:51 -0700 Subject: WifiServiceImpl: listen and act on softap changes The registered callers of LocalOnlyHotspot need to be updated when the hotspot fails or stops. This is currently implemented by having WifiServiceImpl listen for WIFI_AP_STATE_CHANGE broadcasts. When updates about softap failures or stopping (disabling or disabled) are received, appropriate messages are constructed and sent to registered callers. This CL additionally adds tests confirming this behavior. An additional helper methods were added to aid testing for sending the broadcasts and sending messages to the registered LOHS requestors. Bug: 31466854 Test: frameworks/opt/net/wifi/tests/wifitests/runtests.sh Change-Id: I5ade861423c7ea25690a084e9e4c7c9861f1dbcd --- .../wifi/LocalOnlyHotspotRequestInfoTest.java | 48 +++- .../src/com/android/server/wifi/TestUtil.java | 15 ++ .../android/server/wifi/WifiServiceImplTest.java | 241 ++++++++++++++++++++- 3 files changed, 288 insertions(+), 16 deletions(-) (limited to 'tests') diff --git a/tests/wifitests/src/com/android/server/wifi/LocalOnlyHotspotRequestInfoTest.java b/tests/wifitests/src/com/android/server/wifi/LocalOnlyHotspotRequestInfoTest.java index 0e8ead2e6..5f170b8f3 100644 --- a/tests/wifitests/src/com/android/server/wifi/LocalOnlyHotspotRequestInfoTest.java +++ b/tests/wifitests/src/com/android/server/wifi/LocalOnlyHotspotRequestInfoTest.java @@ -17,11 +17,10 @@ package com.android.server.wifi; import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.*; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; import android.os.Handler; import android.os.IBinder; import android.os.Message; @@ -129,23 +128,48 @@ public class LocalOnlyHotspotRequestInfoTest { } /** - * Verify the uid is properly set. + * Verify the pid is properly set. */ @Test - public void verifyUid() { + public void verifyPid() { mLOHSRequestInfo = new LocalOnlyHotspotRequestInfo(mAppBinder, mMessenger, mCallback); - assertEquals(Process.myUid(), mLOHSRequestInfo.getUid()); + assertEquals(Process.myPid(), mLOHSRequestInfo.getPid()); } /** - * Verify that sendMessage does send a Message properly + * Verify that sendHotspotFailedMessage does send a Message properly */ @Test - public void verifySendMessenger() throws Exception { + public void verifySendFailedMessage() throws Exception { mLOHSRequestInfo = new LocalOnlyHotspotRequestInfo(mAppBinder, mMessenger, mCallback); - mLOHSRequestInfo.sendMessage(1, 1); + mLOHSRequestInfo.sendHotspotFailedMessage( + WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC); Message message = mTestLooper.nextMessage(); - assertEquals(1, message.what); - assertEquals(1, message.arg1); + assertEquals(WifiManager.HOTSPOT_FAILED, message.what); + assertEquals(WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC, message.arg1); + } + + /** + * Verify that sendHotspotStartedMessage does send a Message properly + */ + @Test + public void verifySendStartedMessage() throws Exception { + mLOHSRequestInfo = new LocalOnlyHotspotRequestInfo(mAppBinder, mMessenger, mCallback); + WifiConfiguration config = mock(WifiConfiguration.class); + mLOHSRequestInfo.sendHotspotStartedMessage(config); + Message message = mTestLooper.nextMessage(); + assertEquals(WifiManager.HOTSPOT_STARTED, message.what); + assertEquals(config, (WifiConfiguration) message.obj); + } + + /** + * Verify that sendHotspotStoppedMessage does send a Message properly + */ + @Test + public void verifySendStoppedMessage() throws Exception { + mLOHSRequestInfo = new LocalOnlyHotspotRequestInfo(mAppBinder, mMessenger, mCallback); + mLOHSRequestInfo.sendHotspotStoppedMessage(); + Message message = mTestLooper.nextMessage(); + assertEquals(WifiManager.HOTSPOT_STOPPED, message.what); } } diff --git a/tests/wifitests/src/com/android/server/wifi/TestUtil.java b/tests/wifitests/src/com/android/server/wifi/TestUtil.java index 3b43ad8c5..90df07a61 100644 --- a/tests/wifitests/src/com/android/server/wifi/TestUtil.java +++ b/tests/wifitests/src/com/android/server/wifi/TestUtil.java @@ -70,6 +70,21 @@ public class TestUtil { broadcastReceiver.onReceive(context, intent); } + /** + * Send {@link WifiManager#WIFI_AP_STATE_CHANGED} broadcast. + */ + public static void sendWifiApStateChanged(BroadcastReceiver broadcastReceiver, + Context context, int apState, int previousState, int error) { + Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); + intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, apState); + intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousState); + if (apState == WifiManager.WIFI_AP_STATE_FAILED) { + //only set reason number when softAP start failed + intent.putExtra(WifiManager.EXTRA_WIFI_AP_FAILURE_REASON, error); + } + broadcastReceiver.onReceive(context, intent); + } + /** * Send {@link ConnectivityManager#ACTION_TETHER_STATE_CHANGED} broadcast. */ diff --git a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java index bef3fc104..f1c19e6b3 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java @@ -16,12 +16,21 @@ package com.android.server.wifi; +import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC; import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE; +import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_NO_CHANNEL; import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_TETHERING_DISALLOWED; +import static android.net.wifi.WifiManager.SAP_START_FAILURE_GENERAL; +import static android.net.wifi.WifiManager.SAP_START_FAILURE_NO_CHANNEL; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; import static android.provider.Settings.Secure.LOCATION_MODE_HIGH_ACCURACY; import static android.provider.Settings.Secure.LOCATION_MODE_OFF; +import static com.android.server.wifi.LocalOnlyHotspotRequestInfo.HOTSPOT_NO_ERROR; import static com.android.server.wifi.WifiController.CMD_SET_AP; import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED; @@ -35,8 +44,10 @@ import static org.mockito.Mockito.*; import android.app.ActivityManager; import android.app.AppOpsManager; +import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; +import android.content.IntentFilter; import android.content.res.Resources; import android.net.IpConfiguration; import android.net.wifi.ScanSettings; @@ -64,6 +75,8 @@ import com.android.server.wifi.util.WifiPermissionsUtil; import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; @@ -89,14 +102,21 @@ public class WifiServiceImplTest { private static final String TEST_PACKAGE_NAME = "TestPackage"; private static final String SETTINGS_PACKAGE_NAME = "com.android.settings"; private static final String SYSUI_PACKAGE_NAME = "com.android.systemui"; - private static final int TEST_UID = 6789; + private static final int TEST_PID = 6789; + private static final int TEST_PID2 = 9876; private WifiServiceImpl mWifiServiceImpl; private TestLooper mLooper; private PowerManager mPowerManager; private Handler mHandler; private Messenger mAppMessenger; - private int mUid; + private int mPid; + + final ArgumentCaptor mBroadcastReceiverCaptor = + ArgumentCaptor.forClass(BroadcastReceiver.class); + final ArgumentCaptor mIntentFilterCaptor = + ArgumentCaptor.forClass(IntentFilter.class); + @Mock Context mContext; @Mock WifiInjector mWifiInjector; @@ -182,10 +202,10 @@ public class WifiServiceImplTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); mLooper = new TestLooper(); - mHandler = new Handler(mLooper.getLooper()); + mHandler = spy(new Handler(mLooper.getLooper())); mAppMessenger = new Messenger(mHandler); - when(mRequestInfo.getUid()).thenReturn(mUid); + when(mRequestInfo.getPid()).thenReturn(mPid); when(mWifiInjector.getUserManager()).thenReturn(mUserManager); when(mWifiInjector.getWifiController()).thenReturn(mWifiController); when(mWifiInjector.getWifiMetrics()).thenReturn(mWifiMetrics); @@ -824,6 +844,219 @@ public class WifiServiceImplTest { verify(mWifiController, never()).sendMessage(eq(CMD_SET_AP), eq(0), eq(0)); } + private class IntentFilterMatcher implements ArgumentMatcher { + @Override + public boolean matches(IntentFilter filter) { + return filter.hasAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); + } + } + + /** + * Verify that onFailed is called for registered LOHS callers when a WIFI_AP_STATE_CHANGE + * broadcast is received. + */ + @Test + public void testRegisteredCallbacksTriggeredOnSoftApFailureGeneric() throws Exception { + when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false); + when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); + mWifiServiceImpl.checkAndStartWifi(); + + verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), + (IntentFilter) argThat(new IntentFilterMatcher())); + + mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo); + + TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, + WIFI_AP_STATE_FAILED, WIFI_AP_STATE_DISABLED, SAP_START_FAILURE_GENERAL); + + verify(mRequestInfo).sendHotspotFailedMessage(ERROR_GENERIC); + } + + /** + * Verify that onFailed is called for registered LOHS callers when a WIFI_AP_STATE_CHANGE + * broadcast is received with the SAP_START_FAILURE_NO_CHANNEL error. + */ + @Test + public void testRegisteredCallbacksTriggeredOnSoftApFailureNoChannel() throws Exception { + when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false); + when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); + mWifiServiceImpl.checkAndStartWifi(); + + verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), + (IntentFilter) argThat(new IntentFilterMatcher())); + + mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo); + + TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, + WIFI_AP_STATE_FAILED, WIFI_AP_STATE_DISABLED, SAP_START_FAILURE_NO_CHANNEL); + + verify(mRequestInfo).sendHotspotFailedMessage(ERROR_NO_CHANNEL); + } + + /** + * Verify that onStopped is called for registered LOHS callers when a WIFI_AP_STATE_CHANGE + * broadcast is received with WIFI_AP_STATE_DISABLING. + */ + @Test + public void testRegisteredCallbacksTriggeredOnSoftApDisabling() throws Exception { + when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false); + when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); + mWifiServiceImpl.checkAndStartWifi(); + + verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), + (IntentFilter) argThat(new IntentFilterMatcher())); + + mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo); + + TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, + WIFI_AP_STATE_DISABLING, WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR); + + verify(mRequestInfo).sendHotspotStoppedMessage(); + } + + + /** + * Verify that onStopped is called for registered LOHS callers when a WIFI_AP_STATE_CHANGE + * broadcast is received with WIFI_AP_STATE_DISABLED. + */ + @Test + public void testRegisteredCallbacksTriggeredOnSoftApDisabled() throws Exception { + when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false); + when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); + mWifiServiceImpl.checkAndStartWifi(); + + verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), + (IntentFilter) argThat(new IntentFilterMatcher())); + + mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo); + + TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, + WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR); + + verify(mRequestInfo).sendHotspotStoppedMessage(); + } + + /** + * Verify that no callbacks are called for registered LOHS callers when a WIFI_AP_STATE_CHANGE + * broadcast is received and the softap started. + */ + @Test + public void testRegisteredCallbacksNotTriggeredOnSoftApStart() throws Exception { + when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false); + when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); + mWifiServiceImpl.checkAndStartWifi(); + + verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), + (IntentFilter) argThat(new IntentFilterMatcher())); + + mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo); + + TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, + WIFI_AP_STATE_ENABLED, WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR); + verifyNoMoreInteractions(mRequestInfo); + } + + /** + * Verify that onStopped is called only once for registered LOHS callers when + * WIFI_AP_STATE_CHANGE broadcasts are received with WIFI_AP_STATE_DISABLING and + * WIFI_AP_STATE_DISABLED. + */ + @Test + public void testRegisteredCallbacksTriggeredOnlyOnceWhenSoftApDisabling() throws Exception { + when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false); + when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); + mWifiServiceImpl.checkAndStartWifi(); + + verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), + (IntentFilter) argThat(new IntentFilterMatcher())); + + mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo); + + TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, + WIFI_AP_STATE_DISABLING, WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR); + TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, + WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR); + + verify(mRequestInfo).sendHotspotStoppedMessage(); + } + + /** + * Verify that onFailed is called only once for registered LOHS callers when + * WIFI_AP_STATE_CHANGE broadcasts are received with WIFI_AP_STATE_FAILED twice. + */ + @Test + public void testRegisteredCallbacksTriggeredOnlyOnceWhenSoftApFailsTwice() throws Exception { + when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false); + when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); + mWifiServiceImpl.checkAndStartWifi(); + + verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), + (IntentFilter) argThat(new IntentFilterMatcher())); + + mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo); + + TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, + WIFI_AP_STATE_FAILED, WIFI_AP_STATE_FAILED, ERROR_GENERIC); + TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, + WIFI_AP_STATE_FAILED, WIFI_AP_STATE_FAILED, ERROR_GENERIC); + + verify(mRequestInfo).sendHotspotFailedMessage(ERROR_GENERIC); + } + + /** + * Verify that onFailed is called for all registered LOHS callers when + * WIFI_AP_STATE_CHANGE broadcasts are received with WIFI_AP_STATE_FAILED. + */ + @Test + public void testAllRegisteredCallbacksTriggeredWhenSoftApFails() throws Exception { + when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false); + when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); + mWifiServiceImpl.checkAndStartWifi(); + + verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), + (IntentFilter) argThat(new IntentFilterMatcher())); + + // make an additional request for this test + LocalOnlyHotspotRequestInfo request2 = mock(LocalOnlyHotspotRequestInfo.class); + mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo); + mWifiServiceImpl.registerLOHSForTest(TEST_PID2, request2); + + TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, + WIFI_AP_STATE_FAILED, WIFI_AP_STATE_FAILED, ERROR_GENERIC); + TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, + WIFI_AP_STATE_FAILED, WIFI_AP_STATE_FAILED, ERROR_GENERIC); + + verify(mRequestInfo).sendHotspotFailedMessage(ERROR_GENERIC); + verify(request2).sendHotspotFailedMessage(ERROR_GENERIC); + } + + /** + * Verify that onFailed is called for all registered LOHS callers when + * WIFI_AP_STATE_CHANGE broadcasts are received with WIFI_AP_STATE_DISABLED. + */ + @Test + public void testAllRegisteredCallbacksTriggeredWhenSoftApStops() throws Exception { + when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false); + when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); + mWifiServiceImpl.checkAndStartWifi(); + + verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), + (IntentFilter) argThat(new IntentFilterMatcher())); + + // make an additional request for this test + LocalOnlyHotspotRequestInfo request2 = mock(LocalOnlyHotspotRequestInfo.class); + mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo); + mWifiServiceImpl.registerLOHSForTest(TEST_PID2, request2); + + TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, + WIFI_AP_STATE_DISABLING, WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR); + TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, + WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR); + + verify(mRequestInfo).sendHotspotStoppedMessage(); + verify(request2).sendHotspotStoppedMessage(); + } + /** * Verify that a call to startWatchLocalOnlyHotspot is only allowed from callers with the * signature only NETWORK_SETTINGS permission. -- cgit v1.2.3