| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.server.wifi; |
| |
| import static android.net.wifi.WifiManager.DEVICE_MOBILITY_STATE_STATIONARY; |
| import static android.net.wifi.WifiManager.HOTSPOT_FAILED; |
| import static android.net.wifi.WifiManager.HOTSPOT_STARTED; |
| import static android.net.wifi.WifiManager.HOTSPOT_STOPPED; |
| import static android.net.wifi.WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR; |
| import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY; |
| import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED; |
| 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_ENABLING; |
| import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; |
| import static android.net.wifi.WifiManager.WIFI_FEATURE_INFRA_5G; |
| import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; |
| |
| 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; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| import static org.mockito.Matchers.any; |
| import static org.mockito.Matchers.anyString; |
| import static org.mockito.Matchers.eq; |
| import static org.mockito.Mockito.anyBoolean; |
| import static org.mockito.Mockito.anyInt; |
| import static org.mockito.Mockito.anyLong; |
| import static org.mockito.Mockito.anyObject; |
| import static org.mockito.Mockito.argThat; |
| import static org.mockito.Mockito.atLeastOnce; |
| import static org.mockito.Mockito.doNothing; |
| import static org.mockito.Mockito.doReturn; |
| import static org.mockito.Mockito.doThrow; |
| import static org.mockito.Mockito.inOrder; |
| import static org.mockito.Mockito.isNull; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.never; |
| import static org.mockito.Mockito.reset; |
| import static org.mockito.Mockito.spy; |
| import static org.mockito.Mockito.times; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.Mockito.verifyNoMoreInteractions; |
| import static org.mockito.Mockito.verifyZeroInteractions; |
| import static org.mockito.Mockito.when; |
| |
| import android.Manifest; |
| import android.app.ActivityManager; |
| import android.app.AppOpsManager; |
| import android.app.admin.DeviceAdminInfo; |
| import android.app.admin.DevicePolicyManagerInternal; |
| import android.content.BroadcastReceiver; |
| import android.content.ContentResolver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.content.pm.ApplicationInfo; |
| import android.content.pm.PackageManager; |
| import android.content.pm.ParceledListSlice; |
| import android.content.res.Resources; |
| import android.net.Uri; |
| import android.net.wifi.IDppCallback; |
| import android.net.wifi.INetworkRequestMatchCallback; |
| import android.net.wifi.IOnWifiUsabilityStatsListener; |
| import android.net.wifi.ISoftApCallback; |
| import android.net.wifi.ITrafficStateCallback; |
| import android.net.wifi.ScanResult; |
| import android.net.wifi.WifiConfiguration; |
| import android.net.wifi.WifiConfiguration.KeyMgmt; |
| import android.net.wifi.WifiEnterpriseConfig; |
| import android.net.wifi.WifiInfo; |
| import android.net.wifi.WifiManager; |
| import android.net.wifi.WifiManager.LocalOnlyHotspotCallback; |
| import android.net.wifi.WifiManager.SoftApCallback; |
| import android.net.wifi.WifiSsid; |
| import android.net.wifi.hotspot2.IProvisioningCallback; |
| import android.net.wifi.hotspot2.OsuProvider; |
| import android.net.wifi.hotspot2.PasspointConfiguration; |
| import android.net.wifi.hotspot2.pps.HomeSp; |
| import android.os.Binder; |
| import android.os.Build; |
| import android.os.Handler; |
| import android.os.HandlerThread; |
| import android.os.IBinder; |
| import android.os.IPowerManager; |
| import android.os.Looper; |
| import android.os.Message; |
| import android.os.Messenger; |
| import android.os.PowerManager; |
| import android.os.Process; |
| import android.os.RemoteException; |
| import android.os.UserManager; |
| import android.os.test.TestLooper; |
| import android.telephony.TelephonyManager; |
| |
| import androidx.test.filters.SmallTest; |
| |
| import com.android.internal.os.PowerProfile; |
| import com.android.internal.telephony.TelephonyIntents; |
| import com.android.internal.util.AsyncChannel; |
| import com.android.server.wifi.WifiServiceImpl.LocalOnlyRequestorCallback; |
| import com.android.server.wifi.hotspot2.PasspointManager; |
| import com.android.server.wifi.hotspot2.PasspointProvisioningTestUtil; |
| import com.android.server.wifi.util.WifiAsyncChannel; |
| import com.android.server.wifi.util.WifiPermissionsUtil; |
| import com.android.server.wifi.util.WifiPermissionsWrapper; |
| |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.mockito.ArgumentCaptor; |
| import org.mockito.ArgumentMatcher; |
| import org.mockito.InOrder; |
| import org.mockito.Mock; |
| import org.mockito.MockitoAnnotations; |
| import org.mockito.Spy; |
| |
| import java.io.FileDescriptor; |
| import java.io.PrintWriter; |
| import java.io.StringWriter; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| |
| /** |
| * Unit tests for {@link WifiServiceImpl}. |
| * |
| * Note: this is intended to build up over time and will not immediately cover the entire file. |
| */ |
| @SmallTest |
| public class WifiServiceImplTest { |
| |
| private static final String TAG = "WifiServiceImplTest"; |
| private static final String SCAN_PACKAGE_NAME = "scanPackage"; |
| private static final int DEFAULT_VERBOSE_LOGGING = 0; |
| private static final String ANDROID_SYSTEM_PACKAGE = "android"; |
| private static final String TEST_PACKAGE_NAME = "TestPackage"; |
| private static final String SYSUI_PACKAGE_NAME = "com.android.systemui"; |
| private static final int TEST_PID = 6789; |
| private static final int TEST_PID2 = 9876; |
| private static final int TEST_UID = 1200000; |
| private static final int OTHER_TEST_UID = 1300000; |
| private static final int TEST_USER_HANDLE = 13; |
| private static final int TEST_TRAFFIC_STATE_CALLBACK_IDENTIFIER = 17; |
| private static final int TEST_NETWORK_REQUEST_MATCH_CALLBACK_IDENTIFIER = 234; |
| private static final int TEST_WIFI_USABILITY_STATS_LISTENER_IDENTIFIER = 2; |
| private static final String WIFI_IFACE_NAME = "wlan0"; |
| private static final String WIFI_IFACE_NAME2 = "wlan1"; |
| private static final String TEST_COUNTRY_CODE = "US"; |
| private static final String TEST_FACTORY_MAC = "10:22:34:56:78:92"; |
| private static final List<WifiConfiguration> TEST_WIFI_CONFIGURATION_LIST = Arrays.asList( |
| WifiConfigurationTestUtil.generateWifiConfig( |
| 0, 1000000, "\"red\"", true, true, null, null), |
| WifiConfigurationTestUtil.generateWifiConfig( |
| 1, 1000001, "\"green\"", true, false, "example.com", "Green"), |
| WifiConfigurationTestUtil.generateWifiConfig( |
| 2, 1200000, "\"blue\"", false, true, null, null), |
| WifiConfigurationTestUtil.generateWifiConfig( |
| 3, 1100000, "\"cyan\"", true, true, null, null), |
| WifiConfigurationTestUtil.generateWifiConfig( |
| 4, 1100001, "\"yellow\"", true, true, "example.org", "Yellow"), |
| WifiConfigurationTestUtil.generateWifiConfig( |
| 5, 1100002, "\"magenta\"", false, false, null, null)); |
| |
| private AsyncChannel mAsyncChannel; |
| private WifiServiceImpl mWifiServiceImpl; |
| private TestLooper mLooper; |
| private PowerManager mPowerManager; |
| private Handler mHandler; |
| private Handler mHandlerSpyForCmiRunWithScissors; |
| private Messenger mAppMessenger; |
| private int mPid; |
| private int mPid2 = Process.myPid(); |
| private OsuProvider mOsuProvider; |
| private SoftApCallback mStateMachineSoftApCallback; |
| private ApplicationInfo mApplicationInfo; |
| private static final String DPP_URI = "DPP:some_dpp_uri"; |
| |
| final ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor = |
| ArgumentCaptor.forClass(BroadcastReceiver.class); |
| final ArgumentCaptor<IntentFilter> mIntentFilterCaptor = |
| ArgumentCaptor.forClass(IntentFilter.class); |
| |
| final ArgumentCaptor<Message> mMessageCaptor = ArgumentCaptor.forClass(Message.class); |
| final ArgumentCaptor<SoftApModeConfiguration> mSoftApModeConfigCaptor = |
| ArgumentCaptor.forClass(SoftApModeConfiguration.class); |
| final ArgumentCaptor<Handler> mHandlerCaptor = ArgumentCaptor.forClass(Handler.class); |
| |
| @Mock Context mContext; |
| @Mock WifiInjector mWifiInjector; |
| @Mock WifiCountryCode mWifiCountryCode; |
| @Mock Clock mClock; |
| @Mock WifiController mWifiController; |
| @Mock WifiTrafficPoller mWifiTrafficPoller; |
| @Mock ClientModeImpl mClientModeImpl; |
| @Mock ActiveModeWarden mActiveModeWarden; |
| @Mock HandlerThread mHandlerThread; |
| @Mock Resources mResources; |
| @Mock FrameworkFacade mFrameworkFacade; |
| @Mock WifiLockManager mLockManager; |
| @Mock WifiMulticastLockManager mWifiMulticastLockManager; |
| @Mock WifiLastResortWatchdog mWifiLastResortWatchdog; |
| @Mock WifiBackupRestore mWifiBackupRestore; |
| @Mock WifiMetrics mWifiMetrics; |
| @Mock WifiPermissionsUtil mWifiPermissionsUtil; |
| @Mock WifiPermissionsWrapper mWifiPermissionsWrapper; |
| @Mock WifiSettingsStore mSettingsStore; |
| @Mock ContentResolver mContentResolver; |
| @Mock PackageManager mPackageManager; |
| @Mock UserManager mUserManager; |
| @Mock WifiApConfigStore mWifiApConfigStore; |
| @Mock WifiConfiguration mApConfig; |
| @Mock ActivityManager mActivityManager; |
| @Mock AppOpsManager mAppOpsManager; |
| @Mock IBinder mAppBinder; |
| @Mock IBinder mAnotherAppBinder; |
| @Mock LocalOnlyHotspotRequestInfo mRequestInfo; |
| @Mock LocalOnlyHotspotRequestInfo mRequestInfo2; |
| @Mock IProvisioningCallback mProvisioningCallback; |
| @Mock ISoftApCallback mClientSoftApCallback; |
| @Mock ISoftApCallback mAnotherSoftApCallback; |
| @Mock PowerProfile mPowerProfile; |
| @Mock WifiTrafficPoller mWifiTrafficPolller; |
| @Mock ScanRequestProxy mScanRequestProxy; |
| @Mock ITrafficStateCallback mTrafficStateCallback; |
| @Mock INetworkRequestMatchCallback mNetworkRequestMatchCallback; |
| @Mock WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager; |
| @Mock DevicePolicyManagerInternal mDevicePolicyManagerInternal; |
| @Mock TelephonyManager mTelephonyManager; |
| @Mock IOnWifiUsabilityStatsListener mOnWifiUsabilityStatsListener; |
| @Mock WifiConfigManager mWifiConfigManager; |
| @Mock WifiScoreReport mWifiScoreReport; |
| @Mock WifiScoreCard mWifiScoreCard; |
| @Mock PasspointManager mPasspointManager; |
| @Mock IDppCallback mDppCallback; |
| @Mock WifiKeyStore mWifiKeyStore; |
| |
| @Spy FakeWifiLog mLog; |
| |
| private class WifiAsyncChannelTester { |
| private static final String TAG = "WifiAsyncChannelTester"; |
| public static final int CHANNEL_STATE_FAILURE = -1; |
| public static final int CHANNEL_STATE_DISCONNECTED = 0; |
| public static final int CHANNEL_STATE_HALF_CONNECTED = 1; |
| public static final int CHANNEL_STATE_FULLY_CONNECTED = 2; |
| |
| private int mState = CHANNEL_STATE_DISCONNECTED; |
| private WifiAsyncChannel mChannel; |
| private WifiLog mAsyncTestLog; |
| |
| WifiAsyncChannelTester(WifiInjector wifiInjector) { |
| mAsyncTestLog = wifiInjector.makeLog(TAG); |
| } |
| |
| public int getChannelState() { |
| return mState; |
| } |
| |
| public void connect(final Looper looper, final Messenger messenger, |
| final Handler incomingMessageHandler) { |
| assertEquals("AsyncChannel must be in disconnected state", |
| CHANNEL_STATE_DISCONNECTED, mState); |
| mChannel = new WifiAsyncChannel(TAG); |
| mChannel.setWifiLog(mLog); |
| Handler handler = new Handler(mLooper.getLooper()) { |
| @Override |
| public void handleMessage(Message msg) { |
| switch (msg.what) { |
| case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: |
| if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { |
| mChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); |
| mState = CHANNEL_STATE_HALF_CONNECTED; |
| } else { |
| mState = CHANNEL_STATE_FAILURE; |
| } |
| break; |
| case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED: |
| mState = CHANNEL_STATE_FULLY_CONNECTED; |
| break; |
| case AsyncChannel.CMD_CHANNEL_DISCONNECTED: |
| mState = CHANNEL_STATE_DISCONNECTED; |
| break; |
| default: |
| incomingMessageHandler.handleMessage(msg); |
| break; |
| } |
| } |
| }; |
| mChannel.connect(null, handler, messenger); |
| } |
| |
| private Message sendMessageSynchronously(Message request) { |
| return mChannel.sendMessageSynchronously(request); |
| } |
| |
| private void sendMessage(Message request) { |
| mChannel.sendMessage(request); |
| } |
| } |
| |
| @Before public void setUp() throws Exception { |
| MockitoAnnotations.initMocks(this); |
| mLooper = new TestLooper(); |
| mHandler = spy(new Handler(mLooper.getLooper())); |
| mAppMessenger = new Messenger(mHandler); |
| mAsyncChannel = spy(new AsyncChannel()); |
| mApplicationInfo = new ApplicationInfo(); |
| mApplicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; |
| |
| WifiInjector.sWifiInjector = mWifiInjector; |
| when(mRequestInfo.getPid()).thenReturn(mPid); |
| when(mRequestInfo2.getPid()).thenReturn(mPid2); |
| when(mWifiInjector.getUserManager()).thenReturn(mUserManager); |
| when(mWifiInjector.getWifiCountryCode()).thenReturn(mWifiCountryCode); |
| when(mWifiInjector.getWifiController()).thenReturn(mWifiController); |
| when(mWifiInjector.getWifiMetrics()).thenReturn(mWifiMetrics); |
| when(mWifiInjector.getClientModeImpl()).thenReturn(mClientModeImpl); |
| when(mClientModeImpl.syncInitialize(any())).thenReturn(true); |
| when(mClientModeImpl.getHandler()).thenReturn(new Handler()); |
| when(mWifiInjector.getActiveModeWarden()).thenReturn(mActiveModeWarden); |
| when(mWifiInjector.getWifiServiceHandlerThread()).thenReturn(mHandlerThread); |
| when(mWifiInjector.getPowerProfile()).thenReturn(mPowerProfile); |
| when(mHandlerThread.getLooper()).thenReturn(mLooper.getLooper()); |
| when(mContext.getResources()).thenReturn(mResources); |
| when(mContext.getContentResolver()).thenReturn(mContentResolver); |
| when(mContext.getPackageManager()).thenReturn(mPackageManager); |
| when(mPackageManager.getApplicationInfo(any(), anyInt())).thenReturn(mApplicationInfo); |
| when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore); |
| doNothing().when(mFrameworkFacade).registerContentObserver(eq(mContext), any(), |
| anyBoolean(), any()); |
| when(mContext.getSystemService(Context.ACTIVITY_SERVICE)).thenReturn(mActivityManager); |
| when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager); |
| IPowerManager powerManagerService = mock(IPowerManager.class); |
| mPowerManager = new PowerManager(mContext, powerManagerService, new Handler()); |
| when(mContext.getSystemServiceName(PowerManager.class)).thenReturn(Context.POWER_SERVICE); |
| when(mContext.getSystemService(PowerManager.class)).thenReturn(mPowerManager); |
| WifiAsyncChannel wifiAsyncChannel = new WifiAsyncChannel("WifiServiceImplTest"); |
| wifiAsyncChannel.setWifiLog(mLog); |
| when(mFrameworkFacade.makeWifiAsyncChannel(anyString())).thenReturn(wifiAsyncChannel); |
| when(mWifiPermissionsWrapper.getDevicePolicyManagerInternal()) |
| .thenReturn(mDevicePolicyManagerInternal); |
| when(mWifiInjector.getFrameworkFacade()).thenReturn(mFrameworkFacade); |
| when(mWifiInjector.getWifiLockManager()).thenReturn(mLockManager); |
| when(mWifiInjector.getWifiMulticastLockManager()).thenReturn(mWifiMulticastLockManager); |
| when(mWifiInjector.getWifiLastResortWatchdog()).thenReturn(mWifiLastResortWatchdog); |
| when(mWifiInjector.getWifiBackupRestore()).thenReturn(mWifiBackupRestore); |
| when(mWifiInjector.makeLog(anyString())).thenReturn(mLog); |
| when(mWifiInjector.getWifiTrafficPoller()).thenReturn(mWifiTrafficPoller); |
| when(mWifiInjector.getWifiPermissionsUtil()).thenReturn(mWifiPermissionsUtil); |
| when(mWifiInjector.getWifiPermissionsWrapper()).thenReturn(mWifiPermissionsWrapper); |
| when(mWifiInjector.getWifiSettingsStore()).thenReturn(mSettingsStore); |
| when(mWifiInjector.getClock()).thenReturn(mClock); |
| when(mWifiInjector.getScanRequestProxy()).thenReturn(mScanRequestProxy); |
| when(mWifiInjector.getWifiNetworkSuggestionsManager()) |
| .thenReturn(mWifiNetworkSuggestionsManager); |
| when(mWifiInjector.makeTelephonyManager()).thenReturn(mTelephonyManager); |
| when(mWifiInjector.getWifiConfigManager()).thenReturn(mWifiConfigManager); |
| when(mWifiInjector.getPasspointManager()).thenReturn(mPasspointManager); |
| when(mClientModeImpl.getWifiScoreReport()).thenReturn(mWifiScoreReport); |
| when(mWifiInjector.getWifiScoreCard()).thenReturn(mWifiScoreCard); |
| when(mClientModeImpl.syncStartSubscriptionProvisioning(anyInt(), |
| any(OsuProvider.class), any(IProvisioningCallback.class), any())).thenReturn(true); |
| when(mPackageManager.hasSystemFeature( |
| PackageManager.FEATURE_WIFI_PASSPOINT)).thenReturn(true); |
| // Create an OSU provider that can be provisioned via an open OSU AP |
| mOsuProvider = PasspointProvisioningTestUtil.generateOsuProvider(true); |
| when(mContext.getOpPackageName()).thenReturn(TEST_PACKAGE_NAME); |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED); |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETUP_WIZARD), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED); |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_STACK), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED); |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_MANAGED_PROVISIONING), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED); |
| when(mScanRequestProxy.startScan(anyInt(), anyString())).thenReturn(true); |
| when(mWifiInjector.getWifiKeyStore()).thenReturn(mWifiKeyStore); |
| |
| ArgumentCaptor<SoftApCallback> softApCallbackCaptor = |
| ArgumentCaptor.forClass(SoftApCallback.class); |
| mWifiServiceImpl = new WifiServiceImpl(mContext, mWifiInjector, mAsyncChannel); |
| verify(mActiveModeWarden).registerSoftApCallback(softApCallbackCaptor.capture()); |
| mStateMachineSoftApCallback = softApCallbackCaptor.getValue(); |
| mWifiServiceImpl.setWifiHandlerLogForTest(mLog); |
| mDppCallback = new IDppCallback() { |
| @Override |
| public void onSuccessConfigReceived(int newNetworkId) throws RemoteException { |
| |
| } |
| |
| @Override |
| public void onSuccess(int status) throws RemoteException { |
| |
| } |
| |
| @Override |
| public void onFailure(int status) throws RemoteException { |
| |
| } |
| |
| @Override |
| public void onProgress(int status) throws RemoteException { |
| |
| } |
| |
| @Override |
| public IBinder asBinder() { |
| return null; |
| } |
| }; |
| } |
| |
| private WifiAsyncChannelTester verifyAsyncChannelHalfConnected() throws RemoteException { |
| WifiAsyncChannelTester channelTester = new WifiAsyncChannelTester(mWifiInjector); |
| Handler handler = mock(Handler.class); |
| TestLooper looper = new TestLooper(); |
| channelTester.connect(looper.getLooper(), |
| mWifiServiceImpl.getWifiServiceMessenger(TEST_PACKAGE_NAME), handler); |
| mLooper.dispatchAll(); |
| assertEquals("AsyncChannel must be half connected", |
| WifiAsyncChannelTester.CHANNEL_STATE_HALF_CONNECTED, |
| channelTester.getChannelState()); |
| return channelTester; |
| } |
| |
| /** |
| * Verifies that any operations on WifiServiceImpl without setting up the ClientModeImpl |
| * channel would fail. |
| */ |
| @Test |
| public void testRemoveNetworkUnknown() { |
| assertFalse(mWifiServiceImpl.removeNetwork(-1, TEST_PACKAGE_NAME)); |
| verify(mClientModeImpl, never()).syncRemoveNetwork(any(), anyInt()); |
| } |
| |
| /** |
| * Tests whether we're able to set up an async channel connection with WifiServiceImpl. |
| * This is the path used by some WifiManager public API calls. |
| */ |
| @Test |
| public void testAsyncChannelHalfConnected() throws RemoteException { |
| verifyAsyncChannelHalfConnected(); |
| } |
| |
| /** |
| * Ensure WifiMetrics.dump() is the only dump called when 'dumpsys wifi WifiMetricsProto' is |
| * called. This is required to support simple metrics collection via dumpsys |
| */ |
| @Test |
| public void testWifiMetricsDump() { |
| mWifiServiceImpl.dump(new FileDescriptor(), new PrintWriter(new StringWriter()), |
| new String[]{mWifiMetrics.PROTO_DUMP_ARG}); |
| verify(mWifiMetrics) |
| .dump(any(FileDescriptor.class), any(PrintWriter.class), any(String[].class)); |
| verify(mClientModeImpl, never()) |
| .dump(any(FileDescriptor.class), any(PrintWriter.class), any(String[].class)); |
| } |
| |
| /** |
| * Ensure WifiServiceImpl.dump() doesn't throw an NPE when executed with null args |
| */ |
| @Test |
| public void testDumpNullArgs() { |
| setupClientModeImplHandlerForRunWithScissors(); |
| |
| mWifiServiceImpl.dump(new FileDescriptor(), new PrintWriter(new StringWriter()), null); |
| } |
| |
| /** |
| * Ensure that WifiServiceImpl.dump() calls |
| * {@link ClientModeImpl#updateLinkLayerStatsRssiAndScoreReport()}, then calls |
| * mWifiInjector.getClientModeImplHandler().runWithScissors() at least once before calling |
| * {@link WifiScoreReport#dump(FileDescriptor, PrintWriter, String[])}. |
| * |
| * runWithScissors() needs to be called at least once so that we know that the async call |
| * {@link ClientModeImpl#updateLinkLayerStatsRssiAndScoreReport()} has completed, since |
| * runWithScissors() blocks the current thread until the call completes, which includes all |
| * previous calls posted to that thread. |
| * |
| * This ensures that WifiScoreReport will always get updated RSSI and link layer stats before |
| * dumping during a bug report, no matter if the screen is on or not. |
| */ |
| @Test |
| public void testWifiScoreReportDump() { |
| setupClientModeImplHandlerForRunWithScissors(); |
| |
| mWifiServiceImpl.dump(new FileDescriptor(), new PrintWriter(new StringWriter()), null); |
| |
| InOrder inOrder = inOrder(mClientModeImpl, mHandlerSpyForCmiRunWithScissors, |
| mWifiScoreReport); |
| |
| inOrder.verify(mClientModeImpl).updateLinkLayerStatsRssiAndScoreReport(); |
| inOrder.verify(mHandlerSpyForCmiRunWithScissors, atLeastOnce()) |
| .runWithScissors(any(), anyLong()); |
| inOrder.verify(mWifiScoreReport).dump(any(), any(), any()); |
| } |
| |
| /** |
| * Verify that metrics is incremented correctly for Privileged Apps. |
| */ |
| @Test |
| public void testSetWifiEnabledMetricsPrivilegedApp() throws Exception { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| when(mSettingsStore.handleWifiToggled(anyBoolean())).thenReturn(true); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); |
| |
| InOrder inorder = inOrder(mWifiMetrics); |
| assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true)); |
| assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false)); |
| inorder.verify(mWifiMetrics).incrementNumWifiToggles(eq(true), eq(true)); |
| inorder.verify(mWifiMetrics).incrementNumWifiToggles(eq(true), eq(false)); |
| } |
| |
| /** |
| * Verify that metrics is incremented correctly for normal Apps targeting pre-Q. |
| */ |
| @Test |
| public void testSetWifiEnabledMetricsNormalAppBelowQSDK() throws Exception { |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(anyString(), |
| eq(Build.VERSION_CODES.Q))).thenReturn(true); |
| when(mSettingsStore.handleWifiToggled(anyBoolean())).thenReturn(true); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); |
| |
| InOrder inorder = inOrder(mWifiMetrics); |
| assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true)); |
| assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false)); |
| inorder.verify(mWifiMetrics).incrementNumWifiToggles(eq(false), eq(true)); |
| inorder.verify(mWifiMetrics).incrementNumWifiToggles(eq(false), eq(false)); |
| } |
| |
| /** |
| * Verify that metrics is not incremented by apps targeting Q SDK. |
| */ |
| @Test |
| public void testSetWifiEnabledMetricsNormalAppTargetingQSDKNoIncrement() throws Exception { |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(anyString(), |
| eq(Build.VERSION_CODES.Q))).thenReturn(false); |
| when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); |
| |
| assertFalse(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true)); |
| assertFalse(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false)); |
| verify(mWifiMetrics, never()).incrementNumWifiToggles(anyBoolean(), anyBoolean()); |
| } |
| |
| /** |
| * Verify that wifi can be enabled by a caller with NETWORK_SETTINGS permission. |
| */ |
| @Test |
| public void testSetWifiEnabledSuccessWithNetworkSettingsPermission() throws Exception { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); |
| assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true)); |
| verify(mWifiController).sendMessage(eq(CMD_WIFI_TOGGLED)); |
| } |
| |
| /** |
| * Verify that wifi can be enabled by a caller with NETWORK_MANAGED_PROVISIONING permission. |
| */ |
| @Test |
| public void testSetWifiEnabledSuccessWithNetworkManagedProvisioningPermission() |
| throws Exception { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_MANAGED_PROVISIONING), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); |
| assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true)); |
| verify(mWifiController).sendMessage(eq(CMD_WIFI_TOGGLED)); |
| } |
| |
| /** |
| * Verify that wifi can be enabled by the apps targeting pre-Q SDK. |
| */ |
| @Test |
| public void testSetWifiEnabledSuccessForAppsTargetingBelowQSDK() throws Exception { |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(anyString(), |
| eq(Build.VERSION_CODES.Q))).thenReturn(true); |
| |
| when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); |
| assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true)); |
| |
| verify(mWifiController).sendMessage(eq(CMD_WIFI_TOGGLED)); |
| } |
| |
| /** |
| * Verify that wifi cannot be enabled by the apps targeting Q SDK. |
| */ |
| @Test |
| public void testSetWifiEnabledFailureForAppsTargetingQSDK() throws Exception { |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(anyString(), |
| eq(Build.VERSION_CODES.Q))).thenReturn(false); |
| |
| when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); |
| assertFalse(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true)); |
| |
| verify(mWifiController, never()).sendMessage(eq(CMD_WIFI_TOGGLED)); |
| } |
| |
| /** |
| * Verify a SecurityException is thrown if OPSTR_CHANGE_WIFI_STATE is disabled for the app. |
| */ |
| @Test |
| public void testSetWifiEnableAppOpsRejected() throws Exception { |
| doThrow(new SecurityException()).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(anyString(), |
| eq(Build.VERSION_CODES.Q))).thenReturn(true); |
| when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true); |
| try { |
| mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true); |
| fail(); |
| } catch (SecurityException e) { |
| |
| } |
| verify(mWifiController, never()).sendMessage(eq(CMD_WIFI_TOGGLED)); |
| } |
| |
| /** |
| * Verify a SecurityException is thrown if OP_CHANGE_WIFI_STATE is set to MODE_IGNORED |
| * for the app. |
| */ |
| @Test // No exception expected, but the operation should not be done |
| public void testSetWifiEnableAppOpsIgnored() throws Exception { |
| doReturn(AppOpsManager.MODE_IGNORED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(anyString(), |
| eq(Build.VERSION_CODES.Q))).thenReturn(true); |
| when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true); |
| |
| mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true); |
| verify(mWifiController, never()).sendMessage(eq(CMD_WIFI_TOGGLED)); |
| } |
| |
| /** |
| * Verify that a call from an app with the NETWORK_SETTINGS permission can enable wifi if we |
| * are in airplane mode. |
| */ |
| @Test |
| public void testSetWifiEnabledFromNetworkSettingsHolderWhenInAirplaneMode() throws Exception { |
| when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(true); |
| when(mContext.checkPermission( |
| eq(android.Manifest.permission.NETWORK_SETTINGS), anyInt(), anyInt())) |
| .thenReturn(PackageManager.PERMISSION_GRANTED); |
| |
| assertTrue(mWifiServiceImpl.setWifiEnabled(SYSUI_PACKAGE_NAME, true)); |
| verify(mWifiController).sendMessage(eq(CMD_WIFI_TOGGLED)); |
| } |
| |
| /** |
| * Verify that a caller without the NETWORK_SETTINGS permission can't enable wifi |
| * if we are in airplane mode. |
| */ |
| @Test |
| public void testSetWifiEnabledFromAppFailsWhenInAirplaneMode() throws Exception { |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(anyString(), |
| eq(Build.VERSION_CODES.Q))).thenReturn(true); |
| when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(true); |
| when(mContext.checkPermission( |
| eq(android.Manifest.permission.NETWORK_SETTINGS), anyInt(), anyInt())) |
| .thenReturn(PackageManager.PERMISSION_DENIED); |
| |
| assertFalse(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true)); |
| verify(mWifiController, never()).sendMessage(eq(CMD_WIFI_TOGGLED)); |
| } |
| |
| /** |
| * Verify that a call from an app with the NETWORK_SETTINGS permission can enable wifi if we |
| * are in softap mode. |
| */ |
| @Test |
| public void testSetWifiEnabledFromNetworkSettingsHolderWhenApEnabled() throws Exception { |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| (IntentFilter) argThat(new IntentFilterMatcher())); |
| |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_ENABLED, WIFI_AP_STATE_ENABLING, SAP_START_FAILURE_GENERAL, |
| WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| |
| when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true); |
| when(mContext.checkPermission( |
| eq(android.Manifest.permission.NETWORK_SETTINGS), anyInt(), anyInt())) |
| .thenReturn(PackageManager.PERMISSION_GRANTED); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); |
| assertTrue(mWifiServiceImpl.setWifiEnabled(SYSUI_PACKAGE_NAME, true)); |
| verify(mWifiController).sendMessage(eq(CMD_WIFI_TOGGLED)); |
| } |
| |
| /** |
| * Verify that a call from an app cannot enable wifi if we are in softap mode. |
| */ |
| @Test |
| public void testSetWifiEnabledFromAppFailsWhenApEnabled() throws Exception { |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(anyString(), |
| eq(Build.VERSION_CODES.Q))).thenReturn(true); |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| (IntentFilter) argThat(new IntentFilterMatcher())); |
| |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_ENABLED, WIFI_AP_STATE_ENABLING, SAP_START_FAILURE_GENERAL, |
| WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| |
| when(mContext.checkPermission( |
| eq(android.Manifest.permission.NETWORK_SETTINGS), anyInt(), anyInt())) |
| .thenReturn(PackageManager.PERMISSION_DENIED); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); |
| assertFalse(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true)); |
| verify(mSettingsStore, never()).handleWifiToggled(anyBoolean()); |
| verify(mWifiController, never()).sendMessage(eq(CMD_WIFI_TOGGLED)); |
| } |
| |
| |
| /** |
| * Verify that the CMD_TOGGLE_WIFI message won't be sent if wifi is already on. |
| */ |
| @Test |
| public void testSetWifiEnabledNoToggle() throws Exception { |
| when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(false); |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true)); |
| verify(mWifiController, never()).sendMessage(eq(CMD_WIFI_TOGGLED)); |
| } |
| |
| /** |
| * Verify a SecurityException is thrown if a caller does not have the CHANGE_WIFI_STATE |
| * permission to toggle wifi. |
| */ |
| @Test |
| public void testSetWifiEnableWithoutChangeWifiStatePermission() throws Exception { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.CHANGE_WIFI_STATE), |
| eq("WifiService")); |
| try { |
| mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true); |
| fail(); |
| } catch (SecurityException e) { |
| } |
| } |
| |
| /** |
| * Verify that wifi can be disabled by a caller with NETWORK_SETTINGS permission. |
| */ |
| @Test |
| public void testSetWifiDisabledSuccessWithNetworkSettingsPermission() throws Exception { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| when(mSettingsStore.handleWifiToggled(eq(false))).thenReturn(true); |
| assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false)); |
| verify(mWifiController).sendMessage(eq(CMD_WIFI_TOGGLED)); |
| } |
| |
| /** |
| * Verify that wifi can be disabled by a caller with NETWORK_MANAGED_PROVISIONING permission. |
| */ |
| @Test |
| public void testSetWifiDisabledSuccessWithNetworkManagedProvisioningPermission() |
| throws Exception { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_MANAGED_PROVISIONING), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| when(mSettingsStore.handleWifiToggled(eq(false))).thenReturn(true); |
| assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false)); |
| verify(mWifiController).sendMessage(eq(CMD_WIFI_TOGGLED)); |
| } |
| |
| /** |
| * Verify that wifi can be disabled by the apps targeting pre-Q SDK. |
| */ |
| @Test |
| public void testSetWifiDisabledSuccessForAppsTargetingBelowQSDK() throws Exception { |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(anyString(), |
| eq(Build.VERSION_CODES.Q))).thenReturn(true); |
| |
| when(mSettingsStore.handleWifiToggled(eq(false))).thenReturn(true); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); |
| assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false)); |
| |
| verify(mWifiController).sendMessage(eq(CMD_WIFI_TOGGLED)); |
| } |
| |
| /** |
| * Verify that wifi cannot be disabled by the apps targeting Q SDK. |
| */ |
| @Test |
| public void testSetWifiDisabledFailureForAppsTargetingQSDK() throws Exception { |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(anyString(), |
| eq(Build.VERSION_CODES.Q))).thenReturn(false); |
| |
| when(mSettingsStore.handleWifiToggled(eq(false))).thenReturn(true); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); |
| assertFalse(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false)); |
| |
| verify(mWifiController, never()).sendMessage(eq(CMD_WIFI_TOGGLED)); |
| } |
| |
| /** |
| * Verify that CMD_TOGGLE_WIFI message won't be sent if wifi is already off. |
| */ |
| @Test |
| public void testSetWifiDisabledNoToggle() throws Exception { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| when(mSettingsStore.handleWifiToggled(eq(false))).thenReturn(false); |
| assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false)); |
| verify(mWifiController, never()).sendMessage(eq(CMD_WIFI_TOGGLED)); |
| } |
| |
| /** |
| * Verify a SecurityException is thrown if a caller does not have the CHANGE_WIFI_STATE |
| * permission to toggle wifi. |
| */ |
| @Test |
| public void testSetWifiDisabledWithoutChangeWifiStatePermission() throws Exception { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.CHANGE_WIFI_STATE), |
| eq("WifiService")); |
| try { |
| mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false); |
| fail(); |
| } catch (SecurityException e) { } |
| } |
| |
| /** |
| * Ensure unpermitted callers cannot write the SoftApConfiguration. |
| * |
| * @throws SecurityException |
| */ |
| @Test |
| public void testSetWifiApConfigurationNotSavedWithoutPermission() { |
| when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(false); |
| WifiConfiguration apConfig = new WifiConfiguration(); |
| try { |
| mWifiServiceImpl.setWifiApConfiguration(apConfig, TEST_PACKAGE_NAME); |
| fail("Expected SecurityException"); |
| } catch (SecurityException e) { } |
| } |
| |
| /** |
| * Ensure softap config is written when the caller has the correct permission. |
| */ |
| @Test |
| public void testSetWifiApConfigurationSuccess() { |
| when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true); |
| WifiConfiguration apConfig = createValidSoftApConfiguration(); |
| |
| assertTrue(mWifiServiceImpl.setWifiApConfiguration(apConfig, TEST_PACKAGE_NAME)); |
| mLooper.dispatchAll(); |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| verify(mWifiApConfigStore).setApConfiguration(eq(apConfig)); |
| } |
| |
| /** |
| * Ensure that a null config does not overwrite the saved ap config. |
| */ |
| @Test |
| public void testSetWifiApConfigurationNullConfigNotSaved() { |
| when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true); |
| assertFalse(mWifiServiceImpl.setWifiApConfiguration(null, TEST_PACKAGE_NAME)); |
| verify(mWifiApConfigStore, never()).setApConfiguration(isNull(WifiConfiguration.class)); |
| } |
| |
| /** |
| * Ensure that an invalid config does not overwrite the saved ap config. |
| */ |
| @Test |
| public void testSetWifiApConfigurationWithInvalidConfigNotSaved() { |
| when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true); |
| assertFalse(mWifiServiceImpl.setWifiApConfiguration(new WifiConfiguration(), |
| TEST_PACKAGE_NAME)); |
| verify(mWifiApConfigStore, never()).setApConfiguration(any()); |
| } |
| |
| /** |
| * Ensure unpermitted callers are not able to retrieve the softap config. |
| * |
| * @throws SecurityException |
| */ |
| @Test |
| public void testGetWifiApConfigurationNotReturnedWithoutPermission() { |
| when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(false); |
| try { |
| mWifiServiceImpl.getWifiApConfiguration(); |
| fail("Expected a SecurityException"); |
| } catch (SecurityException e) { |
| } |
| } |
| |
| /** |
| * Ensure permitted callers are able to retrieve the softap config. |
| */ |
| @Test |
| public void testGetWifiApConfigurationSuccess() { |
| setupClientModeImplHandlerForRunWithScissors(); |
| |
| mWifiServiceImpl = new WifiServiceImpl(mContext, mWifiInjector, mAsyncChannel); |
| mWifiServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false); |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| |
| when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true); |
| WifiConfiguration apConfig = new WifiConfiguration(); |
| when(mWifiApConfigStore.getApConfiguration()).thenReturn(apConfig); |
| assertEquals(apConfig, mWifiServiceImpl.getWifiApConfiguration()); |
| } |
| |
| /** |
| * Ensure we return the proper variable for the softap state after getting an AP state change |
| * broadcast. |
| */ |
| @Test |
| public void testGetWifiApEnabled() { |
| setupClientModeImplHandlerForRunWithScissors(); |
| |
| // set up WifiServiceImpl with a live thread for testing |
| HandlerThread serviceHandlerThread = createAndStartHandlerThreadForRunWithScissors(); |
| when(mWifiInjector.getWifiServiceHandlerThread()).thenReturn(serviceHandlerThread); |
| mWifiServiceImpl = new WifiServiceImpl(mContext, mWifiInjector, mAsyncChannel); |
| mWifiServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| // ap should be disabled when wifi hasn't been started |
| assertEquals(WifiManager.WIFI_AP_STATE_DISABLED, mWifiServiceImpl.getWifiApEnabledState()); |
| |
| when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false); |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| |
| // ap should be disabled initially |
| assertEquals(WifiManager.WIFI_AP_STATE_DISABLED, mWifiServiceImpl.getWifiApEnabledState()); |
| |
| // send an ap state change to verify WifiServiceImpl is updated |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| (IntentFilter) argThat(new IntentFilterMatcher())); |
| |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_FAILED, WIFI_AP_STATE_DISABLED, SAP_START_FAILURE_GENERAL, |
| WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| mLooper.dispatchAll(); |
| |
| assertEquals(WifiManager.WIFI_AP_STATE_FAILED, mWifiServiceImpl.getWifiApEnabledState()); |
| } |
| |
| /** |
| * Ensure we do not allow unpermitted callers to get the wifi ap state. |
| */ |
| @Test |
| public void testGetWifiApEnabledPermissionDenied() { |
| // we should not be able to get the state |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.ACCESS_WIFI_STATE), |
| eq("WifiService")); |
| |
| try { |
| mWifiServiceImpl.getWifiApEnabledState(); |
| fail("expected SecurityException"); |
| } catch (SecurityException expected) { } |
| } |
| |
| /** |
| * Make sure we do not start wifi if System services have to be restarted to decrypt the device. |
| */ |
| @Test |
| public void testWifiControllerDoesNotStartWhenDeviceTriggerResetMainAtBoot() { |
| when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(true); |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| verify(mWifiController, never()).start(); |
| } |
| |
| /** |
| * Make sure we do start WifiController (wifi disabled) if the device is already decrypted. |
| */ |
| @Test |
| public void testWifiControllerStartsWhenDeviceIsDecryptedAtBootWithWifiDisabled() { |
| when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false); |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| verify(mWifiController).start(); |
| verify(mWifiController, never()).sendMessage(CMD_WIFI_TOGGLED); |
| } |
| |
| /** |
| * Make sure we do start WifiController (wifi enabled) if the device is already decrypted. |
| */ |
| @Test |
| public void testWifiFullyStartsWhenDeviceIsDecryptedAtBootWithWifiEnabled() { |
| when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false); |
| when(mSettingsStore.handleWifiToggled(true)).thenReturn(true); |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true); |
| when(mClientModeImpl.syncGetWifiState()).thenReturn(WIFI_STATE_DISABLED); |
| when(mContext.getPackageName()).thenReturn(ANDROID_SYSTEM_PACKAGE); |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| mWifiServiceImpl.checkAndStartWifi(); |
| verify(mWifiController).start(); |
| verify(mWifiController).sendMessage(CMD_WIFI_TOGGLED); |
| } |
| |
| /** |
| * Verify caller with proper permission can call startSoftAp. |
| */ |
| @Test |
| public void testStartSoftApWithPermissionsAndNullConfig() { |
| boolean result = mWifiServiceImpl.startSoftAp(null); |
| assertTrue(result); |
| verify(mWifiController) |
| .sendMessage(eq(CMD_SET_AP), eq(1), anyInt(), mSoftApModeConfigCaptor.capture()); |
| assertNull(mSoftApModeConfigCaptor.getValue().getWifiConfiguration()); |
| } |
| |
| /** |
| * Verify caller with proper permissions but an invalid config does not start softap. |
| */ |
| @Test |
| public void testStartSoftApWithPermissionsAndInvalidConfig() { |
| boolean result = mWifiServiceImpl.startSoftAp(mApConfig); |
| assertFalse(result); |
| verifyZeroInteractions(mWifiController); |
| } |
| |
| /** |
| * Verify caller with proper permission and valid config does start softap. |
| */ |
| @Test |
| public void testStartSoftApWithPermissionsAndValidConfig() { |
| WifiConfiguration config = createValidSoftApConfiguration(); |
| boolean result = mWifiServiceImpl.startSoftAp(config); |
| assertTrue(result); |
| verify(mWifiController) |
| .sendMessage(eq(CMD_SET_AP), eq(1), anyInt(), mSoftApModeConfigCaptor.capture()); |
| assertEquals(config, mSoftApModeConfigCaptor.getValue().getWifiConfiguration()); |
| } |
| |
| /** |
| * Verify a SecurityException is thrown when a caller without the correct permission attempts to |
| * start softap. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testStartSoftApWithoutPermissionThrowsException() throws Exception { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_STACK), |
| eq("WifiService")); |
| mWifiServiceImpl.startSoftAp(null); |
| } |
| |
| /** |
| * Verify caller with proper permission can call stopSoftAp. |
| */ |
| @Test |
| public void testStopSoftApWithPermissions() { |
| boolean result = mWifiServiceImpl.stopSoftAp(); |
| assertTrue(result); |
| verify(mWifiController).sendMessage(eq(CMD_SET_AP), eq(0), |
| eq(WifiManager.IFACE_IP_MODE_TETHERED)); |
| } |
| |
| /** |
| * Verify SecurityException is thrown when a caller without the correct permission attempts to |
| * stop softap. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testStopSoftApWithoutPermissionThrowsException() throws Exception { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_STACK), |
| eq("WifiService")); |
| mWifiServiceImpl.stopSoftAp(); |
| } |
| |
| /** |
| * Ensure that we handle app ops check failure when handling scan request. |
| */ |
| @Test |
| public void testStartScanFailureAppOpsIgnored() { |
| setupClientModeImplHandlerForRunWithScissors(); |
| doReturn(AppOpsManager.MODE_IGNORED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), SCAN_PACKAGE_NAME); |
| assertFalse(mWifiServiceImpl.startScan(SCAN_PACKAGE_NAME)); |
| verify(mScanRequestProxy, never()).startScan(Process.myUid(), SCAN_PACKAGE_NAME); |
| } |
| |
| /** |
| * Ensure that we handle scan access permission check failure when handling scan request. |
| */ |
| @Test |
| public void testStartScanFailureInCanAccessScanResultsPermission() { |
| setupClientModeImplHandlerForRunWithScissors(); |
| doThrow(new SecurityException()).when(mWifiPermissionsUtil) |
| .enforceCanAccessScanResults(SCAN_PACKAGE_NAME, Process.myUid()); |
| assertFalse(mWifiServiceImpl.startScan(SCAN_PACKAGE_NAME)); |
| verify(mScanRequestProxy, never()).startScan(Process.myUid(), SCAN_PACKAGE_NAME); |
| } |
| |
| /** |
| * Ensure that we handle scan request failure when posting the runnable to handler fails. |
| */ |
| @Test |
| public void testStartScanFailureInRunWithScissors() { |
| setupClientModeImplHandlerForRunWithScissors(); |
| doReturn(false).when(mHandlerSpyForCmiRunWithScissors) |
| .runWithScissors(any(), anyLong()); |
| assertFalse(mWifiServiceImpl.startScan(SCAN_PACKAGE_NAME)); |
| verify(mScanRequestProxy, never()).startScan(Process.myUid(), SCAN_PACKAGE_NAME); |
| } |
| |
| /** |
| * Ensure that we handle scan request failure from ScanRequestProxy fails. |
| */ |
| @Test |
| public void testStartScanFailureFromScanRequestProxy() { |
| setupClientModeImplHandlerForRunWithScissors(); |
| when(mScanRequestProxy.startScan(anyInt(), anyString())).thenReturn(false); |
| assertFalse(mWifiServiceImpl.startScan(SCAN_PACKAGE_NAME)); |
| verify(mScanRequestProxy).startScan(Process.myUid(), SCAN_PACKAGE_NAME); |
| } |
| |
| static final String TEST_SSID = "Sid's Place"; |
| static final String TEST_SSID_WITH_QUOTES = "\"" + TEST_SSID + "\""; |
| static final String TEST_BSSID = "01:02:03:04:05:06"; |
| static final String TEST_PACKAGE = "package"; |
| static final int TEST_NETWORK_ID = 567; |
| |
| private void setupForGetConnectionInfo() { |
| WifiInfo wifiInfo = new WifiInfo(); |
| wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(TEST_SSID)); |
| wifiInfo.setBSSID(TEST_BSSID); |
| wifiInfo.setNetworkId(TEST_NETWORK_ID); |
| when(mClientModeImpl.syncRequestConnectionInfo()).thenReturn(wifiInfo); |
| } |
| |
| /** |
| * Test that connected SSID and BSSID are not exposed to an app that does not have the |
| * appropriate permissions. |
| */ |
| @Test |
| public void testConnectedIdsAreHiddenFromAppWithoutPermission() throws Exception { |
| setupForGetConnectionInfo(); |
| |
| doThrow(new SecurityException()).when(mWifiPermissionsUtil).enforceCanAccessScanResults( |
| anyString(), anyInt()); |
| |
| WifiInfo connectionInfo = mWifiServiceImpl.getConnectionInfo(TEST_PACKAGE); |
| |
| assertEquals(WifiSsid.NONE, connectionInfo.getSSID()); |
| assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getBSSID()); |
| assertEquals(WifiConfiguration.INVALID_NETWORK_ID, connectionInfo.getNetworkId()); |
| } |
| |
| /** |
| * Test that connected SSID and BSSID are not exposed to an app that does not have the |
| * appropriate permissions, when enforceCanAccessScanResults raises a SecurityException. |
| */ |
| @Test |
| public void testConnectedIdsAreHiddenOnSecurityException() throws Exception { |
| setupForGetConnectionInfo(); |
| |
| doThrow(new SecurityException()).when(mWifiPermissionsUtil).enforceCanAccessScanResults( |
| anyString(), anyInt()); |
| |
| WifiInfo connectionInfo = mWifiServiceImpl.getConnectionInfo(TEST_PACKAGE); |
| |
| assertEquals(WifiSsid.NONE, connectionInfo.getSSID()); |
| assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getBSSID()); |
| assertEquals(WifiConfiguration.INVALID_NETWORK_ID, connectionInfo.getNetworkId()); |
| } |
| |
| /** |
| * Test that connected SSID and BSSID are exposed to an app that does have the |
| * appropriate permissions. |
| */ |
| @Test |
| public void testConnectedIdsAreVisibleFromPermittedApp() throws Exception { |
| setupForGetConnectionInfo(); |
| |
| WifiInfo connectionInfo = mWifiServiceImpl.getConnectionInfo(TEST_PACKAGE); |
| |
| assertEquals(TEST_SSID_WITH_QUOTES, connectionInfo.getSSID()); |
| assertEquals(TEST_BSSID, connectionInfo.getBSSID()); |
| assertEquals(TEST_NETWORK_ID, connectionInfo.getNetworkId()); |
| } |
| |
| /** |
| * Test that configured network list are exposed empty list to an app that does not have the |
| * appropriate permissions. |
| */ |
| @Test |
| public void testConfiguredNetworkListAreEmptyFromAppWithoutPermission() throws Exception { |
| when(mClientModeImpl.syncGetConfiguredNetworks(anyInt(), any(), anyInt())) |
| .thenReturn(TEST_WIFI_CONFIGURATION_LIST); |
| |
| // no permission = target SDK=Q && not a carrier app |
| when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(anyString())).thenReturn( |
| TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS); |
| |
| ParceledListSlice<WifiConfiguration> configs = |
| mWifiServiceImpl.getConfiguredNetworks(TEST_PACKAGE); |
| |
| assertEquals(0, configs.getList().size()); |
| } |
| |
| /** |
| * Test that configured network list are exposed empty list to an app that does not have the |
| * appropriate permissions, when enforceCanAccessScanResults raises a SecurityException. |
| */ |
| @Test |
| public void testConfiguredNetworkListAreEmptyOnSecurityException() throws Exception { |
| when(mClientModeImpl.syncGetConfiguredNetworks(anyInt(), any(), anyInt())) |
| .thenReturn(TEST_WIFI_CONFIGURATION_LIST); |
| |
| doThrow(new SecurityException()).when(mWifiPermissionsUtil).enforceCanAccessScanResults( |
| anyString(), anyInt()); |
| |
| ParceledListSlice<WifiConfiguration> configs = |
| mWifiServiceImpl.getConfiguredNetworks(TEST_PACKAGE); |
| |
| assertEquals(0, configs.getList().size()); |
| |
| } |
| |
| /** |
| * Test that configured network list are exposed to an app that does have the |
| * appropriate permissions. |
| */ |
| @Test |
| public void testConfiguredNetworkListAreVisibleFromPermittedApp() throws Exception { |
| when(mClientModeImpl.syncGetConfiguredNetworks(anyInt(), any(), anyInt())) |
| .thenReturn(TEST_WIFI_CONFIGURATION_LIST); |
| |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| |
| mWifiServiceImpl.mClientModeImplChannel = mAsyncChannel; |
| |
| ParceledListSlice<WifiConfiguration> configs = |
| mWifiServiceImpl.getConfiguredNetworks(TEST_PACKAGE); |
| |
| verify(mClientModeImpl).syncGetConfiguredNetworks(anyInt(), any(), eq(Process.WIFI_UID)); |
| WifiConfigurationTestUtil.assertConfigurationsEqualForBackup( |
| TEST_WIFI_CONFIGURATION_LIST, configs.getList()); |
| } |
| |
| |
| /** |
| * Test that privileged network list are exposed null to an app that does not have the |
| * appropriate permissions. |
| */ |
| @Test |
| public void testPrivilegedConfiguredNetworkListAreEmptyFromAppWithoutPermission() |
| throws Exception { |
| when(mClientModeImpl.syncGetPrivilegedConfiguredNetwork(any())) |
| .thenReturn(TEST_WIFI_CONFIGURATION_LIST); |
| |
| doThrow(new SecurityException()).when(mWifiPermissionsUtil).enforceCanAccessScanResults( |
| anyString(), anyInt()); |
| |
| ParceledListSlice<WifiConfiguration> configs = |
| mWifiServiceImpl.getPrivilegedConfiguredNetworks(TEST_PACKAGE); |
| |
| assertEquals(null, configs); |
| } |
| |
| /** |
| * Test that privileged network list are exposed null to an app that does not have the |
| * appropriate permissions, when enforceCanAccessScanResults raises a SecurityException. |
| */ |
| @Test |
| public void testPrivilegedConfiguredNetworkListAreEmptyOnSecurityException() throws Exception { |
| when(mClientModeImpl.syncGetPrivilegedConfiguredNetwork(any())) |
| .thenReturn(TEST_WIFI_CONFIGURATION_LIST); |
| |
| doThrow(new SecurityException()).when(mWifiPermissionsUtil).enforceCanAccessScanResults( |
| anyString(), anyInt()); |
| |
| ParceledListSlice<WifiConfiguration> configs = |
| mWifiServiceImpl.getPrivilegedConfiguredNetworks(TEST_PACKAGE); |
| |
| assertEquals(null, configs); |
| |
| } |
| |
| /** |
| * Test that privileged network list are exposed to an app that does have the |
| * appropriate permissions (simulated by not throwing an exception for READ_WIFI_CREDENTIAL). |
| */ |
| @Test |
| public void testPrivilegedConfiguredNetworkListAreVisibleFromPermittedApp() throws Exception { |
| when(mClientModeImpl.syncGetPrivilegedConfiguredNetwork(any())) |
| .thenReturn(TEST_WIFI_CONFIGURATION_LIST); |
| |
| mWifiServiceImpl.mClientModeImplChannel = mAsyncChannel; |
| |
| ParceledListSlice<WifiConfiguration> configs = |
| mWifiServiceImpl.getPrivilegedConfiguredNetworks(TEST_PACKAGE); |
| |
| WifiConfigurationTestUtil.assertConfigurationsEqualForBackup( |
| TEST_WIFI_CONFIGURATION_LIST, configs.getList()); |
| } |
| |
| /** |
| * Test fetching of scan results. |
| */ |
| @Test |
| public void testGetScanResults() { |
| setupClientModeImplHandlerForRunWithScissors(); |
| |
| ScanResult[] scanResults = |
| ScanTestUtil.createScanDatas(new int[][]{{2417, 2427, 5180, 5170}})[0] |
| .getResults(); |
| List<ScanResult> scanResultList = |
| new ArrayList<>(Arrays.asList(scanResults)); |
| when(mScanRequestProxy.getScanResults()).thenReturn(scanResultList); |
| |
| String packageName = "test.com"; |
| List<ScanResult> retrievedScanResultList = mWifiServiceImpl.getScanResults(packageName); |
| verify(mScanRequestProxy).getScanResults(); |
| |
| ScanTestUtil.assertScanResultsEquals(scanResults, |
| retrievedScanResultList.toArray(new ScanResult[retrievedScanResultList.size()])); |
| } |
| |
| /** |
| * Ensure that we handle scan results failure when posting the runnable to handler fails. |
| */ |
| @Test |
| public void testGetScanResultsFailureInRunWithScissors() { |
| setupClientModeImplHandlerForRunWithScissors(); |
| doReturn(false).when(mHandlerSpyForCmiRunWithScissors) |
| .runWithScissors(any(), anyLong()); |
| |
| ScanResult[] scanResults = |
| ScanTestUtil.createScanDatas(new int[][]{{2417, 2427, 5180, 5170}})[0] |
| .getResults(); |
| List<ScanResult> scanResultList = |
| new ArrayList<>(Arrays.asList(scanResults)); |
| when(mScanRequestProxy.getScanResults()).thenReturn(scanResultList); |
| |
| String packageName = "test.com"; |
| List<ScanResult> retrievedScanResultList = mWifiServiceImpl.getScanResults(packageName); |
| verify(mScanRequestProxy, never()).getScanResults(); |
| |
| assertTrue(retrievedScanResultList.isEmpty()); |
| } |
| |
| private void registerLOHSRequestFull() { |
| // allow test to proceed without a permission check failure |
| when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true); |
| when(mFrameworkFacade.isAppForeground(anyInt())).thenReturn(true); |
| when(mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) |
| .thenReturn(false); |
| int result = mWifiServiceImpl.startLocalOnlyHotspot(mAppMessenger, mAppBinder, |
| TEST_PACKAGE_NAME); |
| assertEquals(LocalOnlyHotspotCallback.REQUEST_REGISTERED, result); |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| } |
| |
| /** |
| * Verify that the call to startLocalOnlyHotspot returns REQUEST_REGISTERED when successfully |
| * called. |
| */ |
| @Test |
| public void testStartLocalOnlyHotspotSingleRegistrationReturnsRequestRegistered() { |
| registerLOHSRequestFull(); |
| } |
| |
| /** |
| * Verify that a call to startLocalOnlyHotspot throws a SecurityException if the caller does not |
| * have the CHANGE_WIFI_STATE permission. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testStartLocalOnlyHotspotThrowsSecurityExceptionWithoutCorrectPermission() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.CHANGE_WIFI_STATE), |
| eq("WifiService")); |
| mWifiServiceImpl.startLocalOnlyHotspot(mAppMessenger, mAppBinder, TEST_PACKAGE_NAME); |
| } |
| |
| /** |
| * Verify that a call to startLocalOnlyHotspot throws a SecurityException if the caller does not |
| * have Location permission. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testStartLocalOnlyHotspotThrowsSecurityExceptionWithoutLocationPermission() { |
| doThrow(new SecurityException()) |
| .when(mWifiPermissionsUtil).enforceLocationPermission(eq(TEST_PACKAGE_NAME), |
| anyInt()); |
| mWifiServiceImpl.startLocalOnlyHotspot(mAppMessenger, mAppBinder, TEST_PACKAGE_NAME); |
| } |
| |
| /** |
| * Verify that a call to startLocalOnlyHotspot throws a SecurityException if Location mode is |
| * disabled. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testStartLocalOnlyHotspotThrowsSecurityExceptionWithoutLocationEnabled() { |
| when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(false); |
| mWifiServiceImpl.startLocalOnlyHotspot(mAppMessenger, mAppBinder, TEST_PACKAGE_NAME); |
| } |
| |
| /** |
| * Only start LocalOnlyHotspot if the caller is the foreground app at the time of the request. |
| */ |
| @Test |
| public void testStartLocalOnlyHotspotFailsIfRequestorNotForegroundApp() throws Exception { |
| when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true); |
| |
| when(mFrameworkFacade.isAppForeground(anyInt())).thenReturn(false); |
| int result = mWifiServiceImpl.startLocalOnlyHotspot(mAppMessenger, mAppBinder, |
| TEST_PACKAGE_NAME); |
| assertEquals(LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE, result); |
| } |
| |
| /** |
| * Only start LocalOnlyHotspot if we are not tethering. |
| */ |
| @Test |
| public void testTetheringDoesNotStartWhenAlreadyTetheringActive() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| WifiConfiguration config = createValidSoftApConfiguration(); |
| assertTrue(mWifiServiceImpl.startSoftAp(config)); |
| verify(mWifiController) |
| .sendMessage(eq(CMD_SET_AP), eq(1), eq(0), mSoftApModeConfigCaptor.capture()); |
| assertEquals(config, mSoftApModeConfigCaptor.getValue().getWifiConfiguration()); |
| |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_TETHERED); |
| mLooper.dispatchAll(); |
| |
| // Start another session without a stop, that should fail. |
| assertFalse(mWifiServiceImpl.startSoftAp(createValidSoftApConfiguration())); |
| |
| verifyNoMoreInteractions(mWifiController); |
| } |
| |
| /** |
| * Only start LocalOnlyHotspot if we are not tethering. |
| */ |
| @Test |
| public void testHotspotDoesNotStartWhenAlreadyTethering() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true); |
| when(mFrameworkFacade.isAppForeground(anyInt())).thenReturn(true); |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_TETHERED); |
| mLooper.dispatchAll(); |
| int returnCode = mWifiServiceImpl.startLocalOnlyHotspot( |
| mAppMessenger, mAppBinder, TEST_PACKAGE_NAME); |
| assertEquals(ERROR_INCOMPATIBLE_MODE, returnCode); |
| } |
| |
| /** |
| * Only start LocalOnlyHotspot if admin setting does not disallow tethering. |
| */ |
| @Test |
| public void testHotspotDoesNotStartWhenTetheringDisallowed() throws Exception { |
| when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true); |
| when(mFrameworkFacade.isAppForeground(anyInt())).thenReturn(true); |
| when(mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) |
| .thenReturn(true); |
| int returnCode = mWifiServiceImpl.startLocalOnlyHotspot( |
| mAppMessenger, mAppBinder, TEST_PACKAGE_NAME); |
| assertEquals(ERROR_TETHERING_DISALLOWED, returnCode); |
| } |
| |
| /** |
| * Verify that callers can only have one registered LOHS request. |
| */ |
| @Test(expected = IllegalStateException.class) |
| public void testStartLocalOnlyHotspotThrowsExceptionWhenCallerAlreadyRegistered() { |
| registerLOHSRequestFull(); |
| |
| // now do the second request that will fail |
| mWifiServiceImpl.startLocalOnlyHotspot(mAppMessenger, mAppBinder, TEST_PACKAGE_NAME); |
| } |
| |
| /** |
| * Verify that the call to stopLocalOnlyHotspot does not do anything when there aren't any |
| * registered callers. |
| */ |
| @Test |
| public void testStopLocalOnlyHotspotDoesNothingWithoutRegisteredRequests() { |
| // allow test to proceed without a permission check failure |
| mWifiServiceImpl.stopLocalOnlyHotspot(); |
| // there is nothing registered, so this shouldn't do anything |
| verify(mWifiController, never()).sendMessage(eq(CMD_SET_AP), anyInt(), anyInt()); |
| } |
| |
| /** |
| * Verify that the call to stopLocalOnlyHotspot does not do anything when one caller unregisters |
| * but there is still an active request |
| */ |
| @Test |
| public void testStopLocalOnlyHotspotDoesNothingWithARemainingRegisteredRequest() { |
| // register a request that will remain after the stopLOHS call |
| mWifiServiceImpl.registerLOHSForTest(mPid, mRequestInfo); |
| |
| registerLOHSRequestFull(); |
| |
| // Since we are calling with the same pid, the second register call will be removed |
| mWifiServiceImpl.stopLocalOnlyHotspot(); |
| // there is still a valid registered request - do not tear down LOHS |
| verify(mWifiController, never()).sendMessage(eq(CMD_SET_AP), anyInt(), anyInt()); |
| } |
| |
| /** |
| * Verify that the call to stopLocalOnlyHotspot sends a message to WifiController to stop |
| * the softAp when there is one registered caller when that caller is removed. |
| */ |
| @Test |
| public void testStopLocalOnlyHotspotTriggersSoftApStopWithOneRegisteredRequest() { |
| registerLOHSRequestFull(); |
| verify(mWifiController) |
| .sendMessage(eq(CMD_SET_AP), eq(1), anyInt(), any(SoftApModeConfiguration.class)); |
| |
| // No permission check required for change_wifi_state. |
| verify(mContext, never()).enforceCallingOrSelfPermission( |
| eq("android.Manifest.permission.CHANGE_WIFI_STATE"), anyString()); |
| |
| mWifiServiceImpl.stopLocalOnlyHotspot(); |
| // there is was only one request registered, we should tear down softap |
| verify(mWifiController).sendMessage(eq(CMD_SET_AP), eq(0), |
| eq(WifiManager.IFACE_IP_MODE_LOCAL_ONLY)); |
| } |
| |
| /** |
| * Verify that by default startLocalOnlyHotspot starts access point at 2 GHz. |
| */ |
| @Test |
| public void testStartLocalOnlyHotspotAt2Ghz() { |
| registerLOHSRequestFull(); |
| verifyLohsBand(WifiConfiguration.AP_BAND_2GHZ); |
| } |
| |
| /** |
| * Verify that startLocalOnlyHotspot will start access point at 5 GHz if properly configured. |
| */ |
| @Test |
| public void testStartLocalOnlyHotspotAt5Ghz() { |
| when(mResources.getBoolean( |
| eq(com.android.internal.R.bool.config_wifi_local_only_hotspot_5ghz))) |
| .thenReturn(true); |
| when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)).thenReturn(true); |
| when(mClientModeImpl.syncGetSupportedFeatures(any(AsyncChannel.class))) |
| .thenReturn((long) WIFI_FEATURE_INFRA_5G); |
| |
| verify(mAsyncChannel).connect(any(), mHandlerCaptor.capture(), any(Handler.class)); |
| final Handler handler = mHandlerCaptor.getValue(); |
| handler.handleMessage(handler.obtainMessage( |
| AsyncChannel.CMD_CHANNEL_HALF_CONNECTED, AsyncChannel.STATUS_SUCCESSFUL, 0)); |
| |
| registerLOHSRequestFull(); |
| verifyLohsBand(WifiConfiguration.AP_BAND_5GHZ); |
| } |
| |
| private void verifyLohsBand(int expectedBand) { |
| verify(mWifiController) |
| .sendMessage(eq(CMD_SET_AP), eq(1), anyInt(), mSoftApModeConfigCaptor.capture()); |
| final WifiConfiguration configuration = mSoftApModeConfigCaptor.getValue().mConfig; |
| assertNotNull(configuration); |
| assertEquals(expectedBand, configuration.apBand); |
| } |
| |
| /** |
| * Verify that WifiServiceImpl does not send the stop ap message if there were no |
| * pending LOHS requests upon a binder death callback. |
| */ |
| @Test |
| public void testServiceImplNotCalledWhenBinderDeathTriggeredNoRequests() { |
| LocalOnlyRequestorCallback binderDeathCallback = |
| mWifiServiceImpl.new LocalOnlyRequestorCallback(); |
| |
| binderDeathCallback.onLocalOnlyHotspotRequestorDeath(mRequestInfo); |
| verify(mWifiController, never()).sendMessage(eq(CMD_SET_AP), eq(0), |
| eq(WifiManager.IFACE_IP_MODE_LOCAL_ONLY)); |
| } |
| |
| /** |
| * Verify that WifiServiceImpl does not send the stop ap message if there are remaining |
| * registered LOHS requests upon a binder death callback. Additionally verify that softap mode |
| * will be stopped if that remaining request is removed (to verify the binder death properly |
| * cleared the requestor that died). |
| */ |
| @Test |
| public void testServiceImplNotCalledWhenBinderDeathTriggeredWithRegisteredRequests() { |
| LocalOnlyRequestorCallback binderDeathCallback = |
| mWifiServiceImpl.new LocalOnlyRequestorCallback(); |
| |
| // registering a request directly from the test will not trigger a message to start |
| // softap mode |
| mWifiServiceImpl.registerLOHSForTest(mPid, mRequestInfo); |
| |
| registerLOHSRequestFull(); |
| |
| binderDeathCallback.onLocalOnlyHotspotRequestorDeath(mRequestInfo); |
| verify(mWifiController, never()).sendMessage(eq(CMD_SET_AP), anyInt(), anyInt()); |
| |
| reset(mWifiController); |
| |
| // now stop as the second request and confirm CMD_SET_AP will be sent to make sure binder |
| // death requestor was removed |
| mWifiServiceImpl.stopLocalOnlyHotspot(); |
| verify(mWifiController).sendMessage(eq(CMD_SET_AP), eq(0), |
| eq(WifiManager.IFACE_IP_MODE_LOCAL_ONLY)); |
| } |
| |
| /** |
| * Verify that a call to registerSoftApCallback throws a SecurityException if the caller does |
| * not have NETWORK_SETTINGS permission. |
| */ |
| @Test |
| public void registerSoftApCallbackThrowsSecurityExceptionOnMissingPermissions() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| try { |
| final int callbackIdentifier = 1; |
| mWifiServiceImpl.registerSoftApCallback(mAppBinder, mClientSoftApCallback, |
| callbackIdentifier); |
| fail("expected SecurityException"); |
| } catch (SecurityException expected) { |
| } |
| } |
| |
| /** |
| * Verify that a call to registerSoftApCallback throws an IllegalArgumentException if the |
| * parameters are not provided. |
| */ |
| @Test |
| public void registerSoftApCallbackThrowsIllegalArgumentExceptionOnInvalidArguments() { |
| try { |
| final int callbackIdentifier = 1; |
| mWifiServiceImpl.registerSoftApCallback(mAppBinder, null, callbackIdentifier); |
| fail("expected IllegalArgumentException"); |
| } catch (IllegalArgumentException expected) { |
| } |
| } |
| |
| /** |
| * Verify that a call to unregisterSoftApCallback throws a SecurityException if the caller does |
| * not have NETWORK_SETTINGS permission. |
| */ |
| @Test |
| public void unregisterSoftApCallbackThrowsSecurityExceptionOnMissingPermissions() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| try { |
| final int callbackIdentifier = 1; |
| mWifiServiceImpl.unregisterSoftApCallback(callbackIdentifier); |
| fail("expected SecurityException"); |
| } catch (SecurityException expected) { |
| } |
| } |
| |
| /** |
| * Verifies that we handle softap callback registration failure if we encounter an exception |
| * while linking to death. |
| */ |
| @Test |
| public void registerSoftApCallbackFailureOnLinkToDeath() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| doThrow(new RemoteException()) |
| .when(mAppBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt()); |
| mWifiServiceImpl.registerSoftApCallback(mAppBinder, mClientSoftApCallback, 1); |
| mLooper.dispatchAll(); |
| verify(mClientSoftApCallback, never()).onStateChanged(WIFI_AP_STATE_DISABLED, 0); |
| verify(mClientSoftApCallback, never()).onNumClientsChanged(0); |
| } |
| |
| |
| /** |
| * Registers a soft AP callback, then verifies that the current soft AP state and num clients |
| * are sent to caller immediately after callback is registered. |
| */ |
| private void registerSoftApCallbackAndVerify(ISoftApCallback callback, int callbackIdentifier) |
| throws Exception { |
| registerSoftApCallbackAndVerify(mAppBinder, callback, callbackIdentifier); |
| } |
| |
| /** |
| * Registers a soft AP callback, then verifies that the current soft AP state and num clients |
| * are sent to caller immediately after callback is registered. |
| */ |
| private void registerSoftApCallbackAndVerify(IBinder binder, ISoftApCallback callback, |
| int callbackIdentifier) throws Exception { |
| mWifiServiceImpl.registerSoftApCallback(binder, callback, callbackIdentifier); |
| mLooper.dispatchAll(); |
| verify(callback).onStateChanged(WIFI_AP_STATE_DISABLED, 0); |
| verify(callback).onNumClientsChanged(0); |
| } |
| |
| /** |
| * Verify that registering twice with same callbackIdentifier will replace the first callback. |
| */ |
| @Test |
| public void replacesOldCallbackWithNewCallbackWhenRegisteringTwice() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| final int callbackIdentifier = 1; |
| registerSoftApCallbackAndVerify(mAppBinder, mClientSoftApCallback, callbackIdentifier); |
| registerSoftApCallbackAndVerify( |
| mAnotherAppBinder, mAnotherSoftApCallback, callbackIdentifier); |
| |
| verify(mAppBinder).linkToDeath(any(), anyInt()); |
| verify(mAppBinder).unlinkToDeath(any(), anyInt()); |
| verify(mAnotherAppBinder).linkToDeath(any(), anyInt()); |
| verify(mAnotherAppBinder, never()).unlinkToDeath(any(), anyInt()); |
| |
| final int testNumClients = 4; |
| mStateMachineSoftApCallback.onNumClientsChanged(testNumClients); |
| mLooper.dispatchAll(); |
| // Verify only the second callback is being called |
| verify(mClientSoftApCallback, never()).onNumClientsChanged(testNumClients); |
| verify(mAnotherSoftApCallback).onNumClientsChanged(testNumClients); |
| } |
| |
| /** |
| * Verify that unregisterSoftApCallback removes callback from registered callbacks list |
| */ |
| @Test |
| public void unregisterSoftApCallbackRemovesCallback() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| final int callbackIdentifier = 1; |
| registerSoftApCallbackAndVerify(mClientSoftApCallback, callbackIdentifier); |
| |
| mWifiServiceImpl.unregisterSoftApCallback(callbackIdentifier); |
| mLooper.dispatchAll(); |
| |
| final int testNumClients = 4; |
| mStateMachineSoftApCallback.onNumClientsChanged(testNumClients); |
| mLooper.dispatchAll(); |
| verify(mClientSoftApCallback, never()).onNumClientsChanged(testNumClients); |
| } |
| |
| /** |
| * Verify that unregisterSoftApCallback is no-op if callbackIdentifier not registered. |
| */ |
| @Test |
| public void unregisterSoftApCallbackDoesNotRemoveCallbackIfCallbackIdentifierNotMatching() |
| throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| final int callbackIdentifier = 1; |
| registerSoftApCallbackAndVerify(mClientSoftApCallback, callbackIdentifier); |
| |
| final int differentCallbackIdentifier = 2; |
| mWifiServiceImpl.unregisterSoftApCallback(differentCallbackIdentifier); |
| mLooper.dispatchAll(); |
| |
| final int testNumClients = 4; |
| mStateMachineSoftApCallback.onNumClientsChanged(testNumClients); |
| mLooper.dispatchAll(); |
| verify(mClientSoftApCallback).onNumClientsChanged(testNumClients); |
| } |
| |
| /** |
| * Registers two callbacks, remove one then verify the right callback is being called on events. |
| */ |
| @Test |
| public void correctCallbackIsCalledAfterAddingTwoCallbacksAndRemovingOne() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| final int callbackIdentifier = 1; |
| mWifiServiceImpl.registerSoftApCallback(mAppBinder, mClientSoftApCallback, |
| callbackIdentifier); |
| |
| // Change state from default before registering the second callback |
| final int testNumClients = 4; |
| mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); |
| mStateMachineSoftApCallback.onNumClientsChanged(testNumClients); |
| |
| // Register another callback and verify the new state is returned in the immediate callback |
| final int anotherUid = 2; |
| mWifiServiceImpl.registerSoftApCallback(mAppBinder, mAnotherSoftApCallback, anotherUid); |
| mLooper.dispatchAll(); |
| verify(mAnotherSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLED, 0); |
| verify(mAnotherSoftApCallback).onNumClientsChanged(testNumClients); |
| |
| // unregister the fisrt callback |
| mWifiServiceImpl.unregisterSoftApCallback(callbackIdentifier); |
| mLooper.dispatchAll(); |
| |
| // Update soft AP state and verify the remaining callback receives the event |
| mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_FAILED, |
| SAP_START_FAILURE_NO_CHANNEL); |
| mLooper.dispatchAll(); |
| verify(mClientSoftApCallback, never()).onStateChanged(WIFI_AP_STATE_FAILED, |
| SAP_START_FAILURE_NO_CHANNEL); |
| verify(mAnotherSoftApCallback).onStateChanged(WIFI_AP_STATE_FAILED, |
| SAP_START_FAILURE_NO_CHANNEL); |
| } |
| |
| /** |
| * Verify that wifi service registers for callers BinderDeath event |
| */ |
| @Test |
| public void registersForBinderDeathOnRegisterSoftApCallback() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| final int callbackIdentifier = 1; |
| registerSoftApCallbackAndVerify(mClientSoftApCallback, callbackIdentifier); |
| verify(mAppBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt()); |
| } |
| |
| /** |
| * Verify that we un-register the soft AP callback on receiving BinderDied event. |
| */ |
| @Test |
| public void unregistersSoftApCallbackOnBinderDied() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| ArgumentCaptor<IBinder.DeathRecipient> drCaptor = |
| ArgumentCaptor.forClass(IBinder.DeathRecipient.class); |
| final int callbackIdentifier = 1; |
| registerSoftApCallbackAndVerify(mClientSoftApCallback, callbackIdentifier); |
| verify(mAppBinder).linkToDeath(drCaptor.capture(), anyInt()); |
| |
| drCaptor.getValue().binderDied(); |
| mLooper.dispatchAll(); |
| verify(mAppBinder).unlinkToDeath(drCaptor.getValue(), 0); |
| |
| // Verify callback is removed from the list as well |
| final int testNumClients = 4; |
| mStateMachineSoftApCallback.onNumClientsChanged(testNumClients); |
| mLooper.dispatchAll(); |
| verify(mClientSoftApCallback, never()).onNumClientsChanged(testNumClients); |
| } |
| |
| /** |
| * Verify that soft AP callback is called on NumClientsChanged event |
| */ |
| @Test |
| public void callsRegisteredCallbacksOnNumClientsChangedEvent() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| final int callbackIdentifier = 1; |
| registerSoftApCallbackAndVerify(mClientSoftApCallback, callbackIdentifier); |
| |
| final int testNumClients = 4; |
| mStateMachineSoftApCallback.onNumClientsChanged(testNumClients); |
| mLooper.dispatchAll(); |
| verify(mClientSoftApCallback).onNumClientsChanged(testNumClients); |
| } |
| |
| /** |
| * Verify that soft AP callback is called on SoftApStateChanged event |
| */ |
| @Test |
| public void callsRegisteredCallbacksOnSoftApStateChangedEvent() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| final int callbackIdentifier = 1; |
| registerSoftApCallbackAndVerify(mClientSoftApCallback, callbackIdentifier); |
| |
| mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); |
| mLooper.dispatchAll(); |
| verify(mClientSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLED, 0); |
| } |
| |
| /** |
| * Verify that mSoftApState and mSoftApNumClients in WifiServiceImpl are being updated on soft |
| * Ap events, even when no callbacks are registered. |
| */ |
| @Test |
| public void updatesSoftApStateAndNumClientsOnSoftApEvents() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| final int testNumClients = 4; |
| mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); |
| mStateMachineSoftApCallback.onNumClientsChanged(testNumClients); |
| |
| // Register callback after num clients and soft AP are changed. |
| final int callbackIdentifier = 1; |
| mWifiServiceImpl.registerSoftApCallback(mAppBinder, mClientSoftApCallback, |
| callbackIdentifier); |
| mLooper.dispatchAll(); |
| verify(mClientSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLED, 0); |
| verify(mClientSoftApCallback).onNumClientsChanged(testNumClients); |
| } |
| |
| private class IntentFilterMatcher implements ArgumentMatcher<IntentFilter> { |
| @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())); |
| |
| registerLOHSRequestFull(); |
| |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_FAILED, WIFI_AP_STATE_DISABLED, SAP_START_FAILURE_GENERAL, |
| WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| mLooper.dispatchAll(); |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| Message message = mMessageCaptor.getValue(); |
| assertEquals(HOTSPOT_FAILED, message.what); |
| assertEquals(ERROR_GENERIC, message.arg1); |
| } |
| |
| /** |
| * 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())); |
| |
| registerLOHSRequestFull(); |
| |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_FAILED, WIFI_AP_STATE_DISABLED, SAP_START_FAILURE_NO_CHANNEL, |
| WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| |
| mLooper.dispatchAll(); |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| Message message = mMessageCaptor.getValue(); |
| assertEquals(HOTSPOT_FAILED, message.what); |
| assertEquals(ERROR_NO_CHANNEL, message.arg1); |
| } |
| |
| /** |
| * Verify that onStopped is called for registered LOHS callers when a WIFI_AP_STATE_CHANGE |
| * broadcast is received with WIFI_AP_STATE_DISABLING and LOHS was active. |
| */ |
| @Test |
| public void testRegisteredCallbacksTriggeredOnSoftApDisabling() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false); |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| (IntentFilter) argThat(new IntentFilterMatcher())); |
| |
| registerLOHSRequestFull(); |
| |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| mLooper.dispatchAll(); |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| Message message = mMessageCaptor.getValue(); |
| assertEquals(HOTSPOT_STARTED, message.what); |
| reset(mHandler); |
| |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_DISABLING, WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR, |
| WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| |
| mLooper.dispatchAll(); |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| message = mMessageCaptor.getValue(); |
| assertEquals(HOTSPOT_STOPPED, message.what); |
| } |
| |
| |
| /** |
| * Verify that onStopped is called for registered LOHS callers when a WIFI_AP_STATE_CHANGE |
| * broadcast is received with WIFI_AP_STATE_DISABLED and LOHS was enabled. |
| */ |
| @Test |
| public void testRegisteredCallbacksTriggeredOnSoftApDisabled() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false); |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| (IntentFilter) argThat(new IntentFilterMatcher())); |
| |
| registerLOHSRequestFull(); |
| |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| mLooper.dispatchAll(); |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| Message message = mMessageCaptor.getValue(); |
| assertEquals(HOTSPOT_STARTED, message.what); |
| reset(mHandler); |
| |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR, |
| WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| |
| mLooper.dispatchAll(); |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| message = mMessageCaptor.getValue(); |
| assertEquals(HOTSPOT_STOPPED, message.what); |
| } |
| |
| /** |
| * 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())); |
| |
| registerLOHSRequestFull(); |
| |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_ENABLED, WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR, WIFI_IFACE_NAME, |
| IFACE_IP_MODE_LOCAL_ONLY); |
| |
| mLooper.dispatchAll(); |
| verify(mHandler, never()).handleMessage(any(Message.class)); |
| } |
| |
| /** |
| * 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 when LOHS was enabled. |
| */ |
| @Test |
| public void testRegisteredCallbacksTriggeredOnlyOnceWhenSoftApDisabling() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false); |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| (IntentFilter) argThat(new IntentFilterMatcher())); |
| |
| registerLOHSRequestFull(); |
| |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| mLooper.dispatchAll(); |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| Message message = mMessageCaptor.getValue(); |
| assertEquals(HOTSPOT_STARTED, message.what); |
| reset(mHandler); |
| |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_DISABLING, WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR, |
| WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR, |
| WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| |
| mLooper.dispatchAll(); |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| message = mMessageCaptor.getValue(); |
| assertEquals(HOTSPOT_STOPPED, message.what); |
| } |
| |
| /** |
| * 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())); |
| |
| registerLOHSRequestFull(); |
| |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_FAILED, WIFI_AP_STATE_FAILED, ERROR_GENERIC, |
| WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_FAILED, WIFI_AP_STATE_FAILED, ERROR_GENERIC, |
| WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| |
| mLooper.dispatchAll(); |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| Message message = mMessageCaptor.getValue(); |
| assertEquals(HOTSPOT_FAILED, message.what); |
| assertEquals(ERROR_GENERIC, message.arg1); |
| } |
| |
| /** |
| * 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 |
| mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo); |
| |
| registerLOHSRequestFull(); |
| |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_FAILED, WIFI_AP_STATE_FAILED, ERROR_GENERIC, |
| WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_FAILED, WIFI_AP_STATE_FAILED, ERROR_GENERIC, |
| WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| |
| verify(mRequestInfo).sendHotspotFailedMessage(ERROR_GENERIC); |
| mLooper.dispatchAll(); |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| Message message = mMessageCaptor.getValue(); |
| assertEquals(HOTSPOT_FAILED, message.what); |
| assertEquals(ERROR_GENERIC, message.arg1); |
| } |
| |
| /** |
| * Verify that onStopped is called for all registered LOHS callers when |
| * WIFI_AP_STATE_CHANGE broadcasts are received with WIFI_AP_STATE_DISABLED when LOHS was |
| * active. |
| */ |
| @Test |
| public void testAllRegisteredCallbacksTriggeredWhenSoftApStops() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| 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); |
| |
| registerLOHSRequestFull(); |
| |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| mLooper.dispatchAll(); |
| verify(mRequestInfo).sendHotspotStartedMessage(any()); |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| Message message = mMessageCaptor.getValue(); |
| assertEquals(HOTSPOT_STARTED, message.what); |
| reset(mHandler); |
| |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_DISABLING, WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR, |
| WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR, |
| WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| |
| verify(mRequestInfo).sendHotspotStoppedMessage(); |
| mLooper.dispatchAll(); |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| message = mMessageCaptor.getValue(); |
| assertEquals(HOTSPOT_STOPPED, message.what); |
| } |
| |
| /** |
| * Verify that onFailed is called for all registered LOHS callers when |
| * WIFI_AP_STATE_CHANGE broadcasts are received with WIFI_AP_STATE_DISABLED when LOHS was |
| * not active. |
| */ |
| @Test |
| public void testAllRegisteredCallbacksTriggeredWhenSoftApStopsLOHSNotActive() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| 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); |
| mWifiServiceImpl.registerLOHSForTest(TEST_PID2, mRequestInfo2); |
| |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_DISABLING, WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR, |
| WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR, |
| WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| |
| verify(mRequestInfo).sendHotspotFailedMessage(ERROR_GENERIC); |
| verify(mRequestInfo2).sendHotspotFailedMessage(ERROR_GENERIC); |
| } |
| |
| /** |
| * Verify that if we do not have registered LOHS requestors and we receive an update that LOHS |
| * is up and ready for use, we tell WifiController to tear it down. This can happen if softap |
| * mode fails to come up properly and we get an onFailed message for a tethering call and we |
| * had registered callers for LOHS. |
| */ |
| @Test |
| public void testLOHSReadyWithoutRegisteredRequestsStopsSoftApMode() { |
| setupClientModeImplHandlerForPost(); |
| |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| mLooper.dispatchAll(); |
| |
| verify(mWifiController).sendMessage(eq(CMD_SET_AP), eq(0), |
| eq(WifiManager.IFACE_IP_MODE_TETHERED)); |
| } |
| |
| /** |
| * Verify that all registered LOHS requestors are notified via a HOTSPOT_STARTED message that |
| * the hotspot is up and ready to use. |
| */ |
| @Test |
| public void testRegisteredLocalOnlyHotspotRequestorsGetOnStartedCallbackWhenReady() |
| throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| registerLOHSRequestFull(); |
| |
| mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo); |
| |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| mLooper.dispatchAll(); |
| verify(mRequestInfo).sendHotspotStartedMessage(any(WifiConfiguration.class)); |
| |
| mLooper.dispatchAll(); |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| Message message = mMessageCaptor.getValue(); |
| assertEquals(HOTSPOT_STARTED, message.what); |
| assertNotNull((WifiConfiguration) message.obj); |
| } |
| |
| /** |
| * Verify that if a LOHS is already active, a new call to register a request will trigger the |
| * onStarted callback. |
| */ |
| @Test |
| public void testRegisterLocalOnlyHotspotRequestAfterAlreadyStartedGetsOnStartedCallback() |
| throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo); |
| |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| mLooper.dispatchAll(); |
| |
| registerLOHSRequestFull(); |
| |
| mLooper.dispatchAll(); |
| |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| Message message = mMessageCaptor.getValue(); |
| assertEquals(HOTSPOT_STARTED, message.what); |
| // since the first request was registered out of band, the config will be null |
| assertNull((WifiConfiguration) message.obj); |
| } |
| |
| /** |
| * Verify that if a LOHS request is active and we receive an update with an ip mode |
| * configuration error, callers are notified via the onFailed callback with the generic |
| * error and are unregistered. |
| */ |
| @Test |
| public void testCallOnFailedLocalOnlyHotspotRequestWhenIpConfigFails() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| registerLOHSRequestFull(); |
| |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_CONFIGURATION_ERROR); |
| mLooper.dispatchAll(); |
| |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| Message message = mMessageCaptor.getValue(); |
| assertEquals(HOTSPOT_FAILED, message.what); |
| assertEquals(ERROR_GENERIC, message.arg1); |
| |
| verify(mWifiController, never()).sendMessage(eq(CMD_SET_AP), eq(0), |
| eq(WifiManager.IFACE_IP_MODE_LOCAL_ONLY)); |
| |
| // sendMessage should only happen once since the requestor should be unregistered |
| reset(mHandler); |
| |
| // send HOTSPOT_FAILED message should only happen once since the requestor should be |
| // unregistered |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_CONFIGURATION_ERROR); |
| mLooper.dispatchAll(); |
| verify(mHandler, never()).handleMessage(any(Message.class)); |
| } |
| |
| /** |
| * Verify that softap mode is stopped for tethering if we receive an update with an ip mode |
| * configuration error. |
| */ |
| @Test |
| public void testStopSoftApWhenIpConfigFails() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_CONFIGURATION_ERROR); |
| mLooper.dispatchAll(); |
| |
| verify(mWifiController).sendMessage(eq(CMD_SET_AP), eq(0), |
| eq(WifiManager.IFACE_IP_MODE_TETHERED)); |
| } |
| |
| /** |
| * Verify that if a LOHS request is active and tethering starts, callers are notified on the |
| * incompatible mode and are unregistered. |
| */ |
| @Test |
| public void testCallOnFailedLocalOnlyHotspotRequestWhenTetheringStarts() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| registerLOHSRequestFull(); |
| |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_TETHERED); |
| mLooper.dispatchAll(); |
| |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| Message message = mMessageCaptor.getValue(); |
| assertEquals(HOTSPOT_FAILED, message.what); |
| assertEquals(ERROR_INCOMPATIBLE_MODE, message.arg1); |
| |
| // sendMessage should only happen once since the requestor should be unregistered |
| reset(mHandler); |
| |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_TETHERED); |
| mLooper.dispatchAll(); |
| verify(mHandler, never()).handleMessage(any(Message.class)); |
| } |
| |
| /** |
| * Verify that if LOHS is disabled, a new call to register a request will not trigger the |
| * onStopped callback. |
| */ |
| @Test |
| public void testRegisterLocalOnlyHotspotRequestWhenStoppedDoesNotGetOnStoppedCallback() |
| throws Exception { |
| registerLOHSRequestFull(); |
| mLooper.dispatchAll(); |
| |
| verify(mHandler, never()).handleMessage(any(Message.class)); |
| } |
| |
| /** |
| * Verify that if a LOHS was active and then stopped, a new call to register a request will |
| * not trigger the onStarted callback. |
| */ |
| @Test |
| public void testRegisterLocalOnlyHotspotRequestAfterStoppedNoOnStartedCallback() |
| throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false); |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| (IntentFilter) argThat(new IntentFilterMatcher())); |
| |
| // register a request so we don't drop the LOHS interface ip update |
| mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo); |
| |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| mLooper.dispatchAll(); |
| |
| registerLOHSRequestFull(); |
| mLooper.dispatchAll(); |
| |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| assertEquals(HOTSPOT_STARTED, mMessageCaptor.getValue().what); |
| |
| reset(mHandler); |
| |
| // now stop the hotspot |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_DISABLING, WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR, |
| WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR, |
| WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| mLooper.dispatchAll(); |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| assertEquals(HOTSPOT_STOPPED, mMessageCaptor.getValue().what); |
| |
| reset(mHandler); |
| |
| // now register a new caller - they should not get the onStarted callback |
| Messenger messenger2 = new Messenger(mHandler); |
| IBinder binder2 = mock(IBinder.class); |
| |
| int result = mWifiServiceImpl.startLocalOnlyHotspot(messenger2, binder2, TEST_PACKAGE_NAME); |
| assertEquals(LocalOnlyHotspotCallback.REQUEST_REGISTERED, result); |
| mLooper.dispatchAll(); |
| |
| verify(mHandler, never()).handleMessage(any(Message.class)); |
| } |
| |
| /** |
| * Verify that a call to startWatchLocalOnlyHotspot is only allowed from callers with the |
| * signature only NETWORK_SETTINGS permission. |
| * |
| * This test is expecting the permission check to enforce the permission and throw a |
| * SecurityException for callers without the permission. This exception should be bubbled up to |
| * the caller of startLocalOnlyHotspot. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testStartWatchLocalOnlyHotspotNotApprovedCaller() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| mWifiServiceImpl.startWatchLocalOnlyHotspot(mAppMessenger, mAppBinder); |
| } |
| |
| /** |
| * Verify that the call to startWatchLocalOnlyHotspot throws the UnsupportedOperationException |
| * when called until the implementation is complete. |
| */ |
| @Test(expected = UnsupportedOperationException.class) |
| public void testStartWatchLocalOnlyHotspotNotSupported() { |
| mWifiServiceImpl.startWatchLocalOnlyHotspot(mAppMessenger, mAppBinder); |
| } |
| |
| /** |
| * Verify that a call to stopWatchLocalOnlyHotspot is only allowed from callers with the |
| * signature only NETWORK_SETTINGS permission. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testStopWatchLocalOnlyHotspotNotApprovedCaller() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| mWifiServiceImpl.stopWatchLocalOnlyHotspot(); |
| } |
| |
| /** |
| * Verify that the call to stopWatchLocalOnlyHotspot throws the UnsupportedOperationException |
| * until the implementation is complete. |
| */ |
| @Test(expected = UnsupportedOperationException.class) |
| public void testStopWatchLocalOnlyHotspotNotSupported() { |
| mWifiServiceImpl.stopWatchLocalOnlyHotspot(); |
| } |
| |
| /** |
| * Verify that the call to addOrUpdateNetwork for installing Passpoint profile is redirected |
| * to the Passpoint specific API addOrUpdatePasspointConfiguration. |
| */ |
| @Test |
| public void testAddPasspointProfileViaAddNetwork() throws Exception { |
| WifiConfiguration config = WifiConfigurationTestUtil.createPasspointNetwork(); |
| config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS); |
| |
| PackageManager pm = mock(PackageManager.class); |
| when(pm.hasSystemFeature(PackageManager.FEATURE_WIFI_PASSPOINT)).thenReturn(true); |
| when(mContext.getPackageManager()).thenReturn(pm); |
| when(pm.getApplicationInfo(any(), anyInt())).thenReturn(mApplicationInfo); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(anyString(), |
| eq(Build.VERSION_CODES.Q))).thenReturn(true); |
| |
| when(mClientModeImpl.syncAddOrUpdatePasspointConfig(any(), |
| any(PasspointConfiguration.class), anyInt(), eq(TEST_PACKAGE_NAME))).thenReturn( |
| true); |
| assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)); |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| verify(mClientModeImpl).syncAddOrUpdatePasspointConfig(any(), |
| any(PasspointConfiguration.class), anyInt(), eq(TEST_PACKAGE_NAME)); |
| reset(mClientModeImpl); |
| |
| when(mClientModeImpl.syncAddOrUpdatePasspointConfig(any(), |
| any(PasspointConfiguration.class), anyInt(), eq(TEST_PACKAGE_NAME))).thenReturn( |
| false); |
| assertEquals(-1, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)); |
| verify(mClientModeImpl).syncAddOrUpdatePasspointConfig(any(), |
| any(PasspointConfiguration.class), anyInt(), eq(TEST_PACKAGE_NAME)); |
| } |
| |
| /** |
| * Verify that the call to getAllMatchingFqdnsForScanResults is not redirected to specific API |
| * syncGetAllMatchingFqdnsForScanResults when the caller doesn't have NETWORK_SETTINGS |
| * permissions and NETWORK_SETUP_WIZARD. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testGetAllMatchingFqdnsForScanResultsWithoutPermissions() { |
| mWifiServiceImpl.getAllMatchingFqdnsForScanResults(new ArrayList<>()); |
| } |
| |
| /** |
| * Verify that the call to getWifiConfigsForPasspointProfiles is not redirected to specific API |
| * syncGetWifiConfigsForPasspointProfiles when the caller doesn't have NETWORK_SETTINGS |
| * permissions and NETWORK_SETUP_WIZARD. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testGetWifiConfigsForPasspointProfilesWithoutPermissions() { |
| mWifiServiceImpl.getWifiConfigsForPasspointProfiles(new ArrayList<>()); |
| } |
| |
| /** |
| * Verify that the call to getMatchingOsuProviders is not redirected to specific API |
| * syncGetMatchingOsuProviders when the caller doesn't have NETWORK_SETTINGS |
| * permissions and NETWORK_SETUP_WIZARD. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testGetMatchingOsuProvidersWithoutPermissions() { |
| mWifiServiceImpl.getMatchingOsuProviders(new ArrayList<>()); |
| } |
| |
| /** |
| * Verify that the call to getMatchingPasspointConfigsForOsuProviders is not redirected to |
| * specific API syncGetMatchingPasspointConfigsForOsuProviders when the caller doesn't have |
| * NETWORK_SETTINGS permissions and NETWORK_SETUP_WIZARD. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testGetMatchingPasspointConfigsForOsuProvidersWithoutPermissions() { |
| mWifiServiceImpl.getMatchingPasspointConfigsForOsuProviders(new ArrayList<>()); |
| } |
| |
| /** |
| * Verify that the call to startSubscriptionProvisioning is redirected to the Passpoint |
| * specific API startSubscriptionProvisioning when the caller has the right permissions. |
| */ |
| @Test |
| public void testStartSubscriptionProvisioningWithPermission() throws Exception { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETUP_WIZARD), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| |
| mWifiServiceImpl.startSubscriptionProvisioning(mOsuProvider, mProvisioningCallback); |
| verify(mClientModeImpl).syncStartSubscriptionProvisioning(anyInt(), |
| eq(mOsuProvider), eq(mProvisioningCallback), any()); |
| } |
| |
| /** |
| * Verify that the call to startSubscriptionProvisioning is not directed to the Passpoint |
| * specific API startSubscriptionProvisioning when the feature is not supported. |
| */ |
| @Test(expected = UnsupportedOperationException.class) |
| public void testStartSubscriptionProvisioniningPasspointUnsupported() throws Exception { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETUP_WIZARD), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| when(mPackageManager.hasSystemFeature( |
| PackageManager.FEATURE_WIFI_PASSPOINT)).thenReturn(false); |
| mWifiServiceImpl.startSubscriptionProvisioning(mOsuProvider, mProvisioningCallback); |
| } |
| |
| /** |
| * Verify that the call to startSubscriptionProvisioning is not redirected to the Passpoint |
| * specific API startSubscriptionProvisioning when the caller provides invalid arguments |
| */ |
| @Test(expected = IllegalArgumentException.class) |
| public void testStartSubscriptionProvisioningWithInvalidProvider() throws Exception { |
| mWifiServiceImpl.startSubscriptionProvisioning(null, mProvisioningCallback); |
| } |
| |
| |
| /** |
| * Verify that the call to startSubscriptionProvisioning is not redirected to the Passpoint |
| * specific API startSubscriptionProvisioning when the caller provides invalid callback |
| */ |
| @Test(expected = IllegalArgumentException.class) |
| public void testStartSubscriptionProvisioningWithInvalidCallback() throws Exception { |
| mWifiServiceImpl.startSubscriptionProvisioning(mOsuProvider, null); |
| } |
| |
| /** |
| * Verify that the call to startSubscriptionProvisioning is not redirected to the Passpoint |
| * specific API startSubscriptionProvisioning when the caller doesn't have NETWORK_SETTINGS |
| * permissions and NETWORK_SETUP_WIZARD. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testStartSubscriptionProvisioningWithoutPermissions() throws Exception { |
| when(mContext.checkCallingOrSelfPermission( |
| eq(android.Manifest.permission.NETWORK_SETTINGS))).thenReturn( |
| PackageManager.PERMISSION_DENIED); |
| when(mContext.checkSelfPermission( |
| eq(android.Manifest.permission.NETWORK_SETUP_WIZARD))).thenReturn( |
| PackageManager.PERMISSION_DENIED); |
| |
| mWifiServiceImpl.startSubscriptionProvisioning(mOsuProvider, mProvisioningCallback); |
| } |
| |
| /** |
| * Verify that the call to getPasspointConfigurations is not redirected to specific API |
| * syncGetPasspointConfigs when the caller doesn't have NETWORK_SETTINGS permissions and |
| * NETWORK_SETUP_WIZARD. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testGetPasspointConfigurationsWithOutPermissions() { |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(false); |
| when(mWifiPermissionsUtil.checkNetworkSetupWizardPermission(anyInt())).thenReturn(false); |
| |
| mWifiServiceImpl.getPasspointConfigurations(TEST_PACKAGE_NAME); |
| } |
| |
| /** |
| * Verify that getPasspointConfigurations called by apps that has invalid package will |
| * throw {@link SecurityException}. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testGetPasspointConfigurationWithInvalidPackage() { |
| doThrow(new SecurityException()).when(mAppOpsManager).checkPackage(anyInt(), |
| eq(TEST_PACKAGE_NAME)); |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); |
| when(mWifiPermissionsUtil.checkNetworkSetupWizardPermission(anyInt())).thenReturn(true); |
| |
| mWifiServiceImpl.getPasspointConfigurations(TEST_PACKAGE_NAME); |
| } |
| |
| /** |
| * Verify that getPasspointConfigurations called by apps targeting below Q SDK will return |
| * empty list if the caller doesn't have NETWORK_SETTINGS permissions and NETWORK_SETUP_WIZARD. |
| */ |
| @Test |
| public void testGetPasspointConfigurationForAppsTargetingBelowQSDK() { |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(false); |
| when(mWifiPermissionsUtil.checkNetworkSetupWizardPermission(anyInt())).thenReturn(false); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(eq(TEST_PACKAGE_NAME), |
| eq(Build.VERSION_CODES.Q))).thenReturn(true); |
| |
| List<PasspointConfiguration> result = mWifiServiceImpl.getPasspointConfigurations( |
| TEST_PACKAGE_NAME); |
| assertNotNull(result); |
| assertEquals(0, result.size()); |
| } |
| |
| /** |
| * Verify that the call to removePasspointConfiguration is not redirected to specific API |
| * syncRemovePasspointConfig when the caller doesn't have NETWORK_SETTINGS and |
| * NETWORK_CARRIER_PROVISIONING permission. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testRemovePasspointConfigurationWithOutPermissions() { |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(false); |
| when(mWifiPermissionsUtil.checkNetworkCarrierProvisioningPermission(anyInt())).thenReturn( |
| false); |
| |
| mWifiServiceImpl.removePasspointConfiguration(null, null); |
| } |
| |
| /** |
| * Verify that the call to removePasspointConfiguration for apps targeting below Q SDK will |
| * return false if the caller doesn't have NETWORK_SETTINGS and NETWORK_CARRIER_PROVISIONING |
| * permission. |
| */ |
| @Test |
| public void testRemovePasspointConfigurationForAppsTargetingBelowQSDK() { |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(false); |
| when(mWifiPermissionsUtil.checkNetworkCarrierProvisioningPermission(anyInt())).thenReturn( |
| false); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(isNull(), |
| eq(Build.VERSION_CODES.Q))).thenReturn(true); |
| |
| assertFalse(mWifiServiceImpl.removePasspointConfiguration(null, null)); |
| } |
| |
| /** |
| * Verify that a call to {@link WifiServiceImpl#restoreBackupData(byte[])} is only allowed from |
| * callers with the signature only NETWORK_SETTINGS permission. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testRestoreBackupDataNotApprovedCaller() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| mWifiServiceImpl.restoreBackupData(null); |
| verify(mWifiBackupRestore, never()).retrieveConfigurationsFromBackupData(any(byte[].class)); |
| } |
| |
| /** |
| * Verify that a call to {@link WifiServiceImpl#restoreSupplicantBackupData(byte[], byte[])} is |
| * only allowed from callers with the signature only NETWORK_SETTINGS permission. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testRestoreSupplicantBackupDataNotApprovedCaller() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| mWifiServiceImpl.restoreSupplicantBackupData(null, null); |
| verify(mWifiBackupRestore, never()).retrieveConfigurationsFromSupplicantBackupData( |
| any(byte[].class), any(byte[].class)); |
| } |
| |
| /** |
| * Verify that a call to {@link WifiServiceImpl#retrieveBackupData()} is only allowed from |
| * callers with the signature only NETWORK_SETTINGS permission. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testRetrieveBackupDataNotApprovedCaller() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| mWifiServiceImpl.retrieveBackupData(); |
| verify(mWifiBackupRestore, never()).retrieveBackupDataFromConfigurations(any(List.class)); |
| } |
| |
| /** |
| * Verify that a call to {@link WifiServiceImpl#enableVerboseLogging(int)} is allowed from |
| * callers with the signature only NETWORK_SETTINGS permission. |
| */ |
| @Test |
| public void testEnableVerboseLoggingWithNetworkSettingsPermission() { |
| doNothing().when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| // Vebose logging is enabled first in the constructor for WifiServiceImpl, so reset |
| // before invocation. |
| reset(mClientModeImpl); |
| mWifiServiceImpl.enableVerboseLogging(1); |
| verify(mClientModeImpl).enableVerboseLogging(anyInt()); |
| } |
| |
| /** |
| * Verify that a call to {@link WifiServiceImpl#enableVerboseLogging(int)} is not allowed from |
| * callers without the signature only NETWORK_SETTINGS permission. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testEnableVerboseLoggingWithNoNetworkSettingsPermission() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| // Vebose logging is enabled first in the constructor for WifiServiceImpl, so reset |
| // before invocation. |
| reset(mClientModeImpl); |
| mWifiServiceImpl.enableVerboseLogging(1); |
| verify(mClientModeImpl, never()).enableVerboseLogging(anyInt()); |
| } |
| |
| /** |
| * Helper to test handling of async messages by wifi service when the message comes from an |
| * app without {@link android.Manifest.permission#CHANGE_WIFI_STATE} permission. |
| */ |
| private void verifyAsyncChannelMessageHandlingWithoutChangePermisson( |
| int requestMsgWhat, int expectedReplyMsgwhat) throws RemoteException { |
| WifiAsyncChannelTester tester = verifyAsyncChannelHalfConnected(); |
| |
| int uidWithoutPermission = 5; |
| when(mWifiPermissionsUtil.checkChangePermission(eq(uidWithoutPermission))) |
| .thenReturn(false); |
| |
| Message request = Message.obtain(); |
| request.what = requestMsgWhat; |
| request.sendingUid = uidWithoutPermission; |
| |
| mLooper.startAutoDispatch(); |
| Message reply = tester.sendMessageSynchronously(request); |
| mLooper.stopAutoDispatch(); |
| |
| verify(mClientModeImpl, never()).sendMessage(any(Message.class)); |
| assertEquals(expectedReplyMsgwhat, reply.what); |
| assertEquals(WifiManager.NOT_AUTHORIZED, reply.arg1); |
| } |
| |
| /** |
| * Helper to test handling of async messages by wifi service when the message comes from an |
| * app without one of the privileged permissions. |
| */ |
| private void verifyAsyncChannelMessageHandlingWithoutPrivilegedPermissons( |
| int requestMsgWhat, int expectedReplyMsgwhat) throws RemoteException { |
| WifiAsyncChannelTester tester = verifyAsyncChannelHalfConnected(); |
| |
| int uidWithoutPermission = 5; |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED); |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETUP_WIZARD), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED); |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_STACK), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED); |
| |
| Message request = Message.obtain(); |
| request.what = requestMsgWhat; |
| request.sendingUid = uidWithoutPermission; |
| |
| mLooper.startAutoDispatch(); |
| Message reply = tester.sendMessageSynchronously(request); |
| mLooper.stopAutoDispatch(); |
| |
| verify(mClientModeImpl, never()).sendMessage(any(Message.class)); |
| assertEquals(expectedReplyMsgwhat, reply.what); |
| assertEquals(WifiManager.NOT_AUTHORIZED, reply.arg1); |
| } |
| |
| /** |
| * Verify that the CONNECT_NETWORK message received from an app without |
| * one of the privileged permission is rejected with the correct error code. |
| */ |
| @Test |
| public void testConnectNetworkWithoutPrivilegedPermission() throws Exception { |
| verifyAsyncChannelMessageHandlingWithoutPrivilegedPermissons( |
| WifiManager.CONNECT_NETWORK, WifiManager.CONNECT_NETWORK_FAILED); |
| } |
| |
| /** |
| * Verify that the FORGET_NETWORK message received from an app without |
| * one of the privileged permission is rejected with the correct error code. |
| */ |
| @Test |
| public void testForgetNetworkWithoutPrivilegedPermission() throws Exception { |
| verifyAsyncChannelMessageHandlingWithoutPrivilegedPermissons( |
| WifiManager.SAVE_NETWORK, WifiManager.SAVE_NETWORK_FAILED); |
| } |
| |
| /** |
| * Verify that the DISABLE_NETWORK message received from an app without |
| * one of the privileged permission is rejected with the correct error code. |
| */ |
| @Test |
| public void testDisableNetworkWithoutPrivilegedPermission() throws Exception { |
| verifyAsyncChannelMessageHandlingWithoutPrivilegedPermissons( |
| WifiManager.DISABLE_NETWORK, WifiManager.DISABLE_NETWORK_FAILED); |
| } |
| |
| /** |
| * Verify that the RSSI_PKTCNT_FETCH message received from an app without |
| * {@link android.Manifest.permission#CHANGE_WIFI_STATE} permission is rejected with the correct |
| * error code. |
| */ |
| @Test |
| public void testRssiPktcntFetchWithoutChangePermission() throws Exception { |
| verifyAsyncChannelMessageHandlingWithoutChangePermisson( |
| WifiManager.RSSI_PKTCNT_FETCH, WifiManager.RSSI_PKTCNT_FETCH_FAILED); |
| } |
| |
| /** |
| * Helper to test handling of async messages by wifi service when the message comes from an |
| * app with {@link android.Manifest.permission#CHANGE_WIFI_STATE} permission. |
| */ |
| private void verifyAsyncChannelMessageHandlingWithChangePermisson( |
| int requestMsgWhat, Object requestMsgObj) throws RemoteException { |
| WifiAsyncChannelTester tester = verifyAsyncChannelHalfConnected(); |
| |
| when(mWifiPermissionsUtil.checkChangePermission(anyInt())).thenReturn(true); |
| |
| Message request = Message.obtain(); |
| request.what = requestMsgWhat; |
| request.obj = requestMsgObj; |
| |
| tester.sendMessage(request); |
| mLooper.dispatchAll(); |
| |
| ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); |
| verify(mClientModeImpl).sendMessage(messageArgumentCaptor.capture()); |
| assertEquals(requestMsgWhat, messageArgumentCaptor.getValue().what); |
| } |
| |
| /** |
| * Helper to test handling of async messages by wifi service when the message comes from an |
| * app with one of the privileged permissions. |
| */ |
| private void verifyAsyncChannelMessageHandlingWithPrivilegedPermissions( |
| int requestMsgWhat, Object requestMsgObj) throws RemoteException { |
| WifiAsyncChannelTester tester = verifyAsyncChannelHalfConnected(); |
| |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| |
| Message request = Message.obtain(); |
| request.what = requestMsgWhat; |
| request.obj = requestMsgObj; |
| |
| tester.sendMessage(request); |
| mLooper.dispatchAll(); |
| |
| ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); |
| verify(mClientModeImpl).sendMessage(messageArgumentCaptor.capture()); |
| assertEquals(requestMsgWhat, messageArgumentCaptor.getValue().what); |
| } |
| |
| /** |
| * Verify that the CONNECT_NETWORK message received from an app with |
| * one of the privileged permission is forwarded to ClientModeImpl. |
| */ |
| @Test |
| public void testConnectNetworkWithPrivilegedPermission() throws Exception { |
| verifyAsyncChannelMessageHandlingWithPrivilegedPermissions( |
| WifiManager.CONNECT_NETWORK, new WifiConfiguration()); |
| } |
| |
| /** |
| * Verify that the SAVE_NETWORK message received from an app with |
| * one of the privileged permission is forwarded to ClientModeImpl. |
| */ |
| @Test |
| public void testSaveNetworkWithPrivilegedPermission() throws Exception { |
| verifyAsyncChannelMessageHandlingWithPrivilegedPermissions( |
| WifiManager.SAVE_NETWORK, new WifiConfiguration()); |
| } |
| |
| /** |
| * Verify that the DISABLE_NETWORK message received from an app with |
| * one of the privileged permission is forwarded to ClientModeImpl. |
| */ |
| @Test |
| public void testDisableNetworkWithPrivilegedPermission() throws Exception { |
| verifyAsyncChannelMessageHandlingWithPrivilegedPermissions( |
| WifiManager.DISABLE_NETWORK, new Object()); |
| } |
| |
| /** |
| * Verify that the RSSI_PKTCNT_FETCH message received from an app with |
| * one of the privileged permission is forwarded to ClientModeImpl. |
| */ |
| @Test |
| public void testRssiPktcntFetchWithChangePermission() throws Exception { |
| verifyAsyncChannelMessageHandlingWithChangePermisson( |
| WifiManager.RSSI_PKTCNT_FETCH, new Object()); |
| } |
| |
| /** |
| * Verify that setCountryCode() calls WifiCountryCode object on succeess. |
| */ |
| @Test |
| public void testSetCountryCode() throws Exception { |
| mWifiServiceImpl.setCountryCode(TEST_COUNTRY_CODE); |
| verify(mWifiCountryCode).setCountryCode(TEST_COUNTRY_CODE); |
| } |
| |
| /** |
| * Verify that setCountryCode() fails and doesn't call WifiCountryCode object |
| * if the caller doesn't have CONNECTIVITY_INTERNAL permission. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testSetCountryCodeFailsWithoutConnectivityInternalPermission() throws Exception { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission( |
| eq(android.Manifest.permission.CONNECTIVITY_INTERNAL), |
| eq("ConnectivityService")); |
| mWifiServiceImpl.setCountryCode(TEST_COUNTRY_CODE); |
| verify(mWifiCountryCode, never()).setCountryCode(TEST_COUNTRY_CODE); |
| } |
| |
| private void setupClientModeImplHandlerForPost() { |
| when(mWifiInjector.getClientModeImplHandler()).thenReturn(mHandler); |
| } |
| |
| /** |
| * Set the wifi state machine mock to return a handler created on test thread. |
| */ |
| private void setupClientModeImplHandlerForRunWithScissors() { |
| HandlerThread handlerThread = createAndStartHandlerThreadForRunWithScissors(); |
| mHandlerSpyForCmiRunWithScissors = spy(handlerThread.getThreadHandler()); |
| when(mWifiInjector.getClientModeImplHandler()) |
| .thenReturn(mHandlerSpyForCmiRunWithScissors); |
| } |
| |
| private HandlerThread createAndStartHandlerThreadForRunWithScissors() { |
| HandlerThread handlerThread = new HandlerThread("ServiceHandlerThreadForTest"); |
| handlerThread.start(); |
| return handlerThread; |
| } |
| |
| /** |
| * Tests the scenario when a scan request arrives while the device is idle. In this case |
| * the scan is done when idle mode ends. |
| */ |
| @Test |
| public void testHandleDelayedScanAfterIdleMode() throws Exception { |
| setupClientModeImplHandlerForRunWithScissors(); |
| when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false); |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| (IntentFilter) argThat(new IdleModeIntentMatcher())); |
| |
| // Tell the wifi service that the device became idle. |
| when(mPowerManager.isDeviceIdleMode()).thenReturn(true); |
| TestUtil.sendIdleModeChanged(mBroadcastReceiverCaptor.getValue(), mContext); |
| |
| // Send a scan request while the device is idle. |
| assertFalse(mWifiServiceImpl.startScan(SCAN_PACKAGE_NAME)); |
| // No scans must be made yet as the device is idle. |
| verify(mScanRequestProxy, never()).startScan(Process.myUid(), SCAN_PACKAGE_NAME); |
| |
| // Tell the wifi service that idle mode ended. |
| when(mPowerManager.isDeviceIdleMode()).thenReturn(false); |
| TestUtil.sendIdleModeChanged(mBroadcastReceiverCaptor.getValue(), mContext); |
| |
| // Must scan now. |
| verify(mScanRequestProxy).startScan(Process.myUid(), TEST_PACKAGE_NAME); |
| // The app ops check is executed with this package's identity (not the identity of the |
| // original remote caller who requested the scan while idle). |
| verify(mAppOpsManager).noteOp( |
| AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| |
| // Send another scan request. The device is not idle anymore, so it must be executed |
| // immediately. |
| assertTrue(mWifiServiceImpl.startScan(SCAN_PACKAGE_NAME)); |
| verify(mScanRequestProxy).startScan(Process.myUid(), SCAN_PACKAGE_NAME); |
| } |
| |
| /** |
| * Verify that if the caller has NETWORK_SETTINGS permission, then it doesn't need |
| * CHANGE_WIFI_STATE permission. |
| * @throws Exception |
| */ |
| @Test |
| public void testDisconnectWithNetworkSettingsPerm() throws Exception { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission( |
| android.Manifest.permission.CHANGE_WIFI_STATE, "WifiService"); |
| doThrow(new SecurityException()).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| assertTrue(mWifiServiceImpl.disconnect(TEST_PACKAGE_NAME)); |
| verify(mClientModeImpl).disconnectCommand(); |
| } |
| |
| /** |
| * Verify that if the caller doesn't have NETWORK_SETTINGS permission, it could still |
| * get access with the CHANGE_WIFI_STATE permission. |
| * @throws Exception |
| */ |
| @Test |
| public void testDisconnectWithChangeWifiStatePerm() throws Exception { |
| assertFalse(mWifiServiceImpl.disconnect(TEST_PACKAGE_NAME)); |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| verify(mClientModeImpl, never()).disconnectCommand(); |
| } |
| |
| /** |
| * Verify that the operation fails if the caller has neither NETWORK_SETTINGS or |
| * CHANGE_WIFI_STATE permissions. |
| * @throws Exception |
| */ |
| @Test |
| public void testDisconnectRejected() throws Exception { |
| doThrow(new SecurityException()).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| try { |
| mWifiServiceImpl.disconnect(TEST_PACKAGE_NAME); |
| fail(); |
| } catch (SecurityException e) { |
| |
| } |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| verify(mClientModeImpl, never()).disconnectCommand(); |
| } |
| |
| @Test |
| public void testPackageRemovedBroadcastHandling() { |
| when(mWifiInjector.getClientModeImplHandler()).thenReturn(mHandler); |
| mWifiServiceImpl.checkAndStartWifi(); |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| argThat((IntentFilter filter) -> |
| filter.hasAction(Intent.ACTION_PACKAGE_FULLY_REMOVED))); |
| |
| int uid = TEST_UID; |
| String packageName = TEST_PACKAGE_NAME; |
| // Send the broadcast |
| Intent intent = new Intent(Intent.ACTION_PACKAGE_FULLY_REMOVED); |
| intent.putExtra(Intent.EXTRA_UID, uid); |
| intent.setData(Uri.fromParts("package", packageName, "")); |
| mBroadcastReceiverCaptor.getValue().onReceive(mContext, intent); |
| |
| verify(mClientModeImpl).removeAppConfigs(packageName, uid); |
| |
| mLooper.dispatchAll(); |
| verify(mScanRequestProxy).clearScanRequestTimestampsForApp(packageName, uid); |
| verify(mWifiNetworkSuggestionsManager).removeApp(packageName); |
| verify(mClientModeImpl).removeNetworkRequestUserApprovedAccessPointsForApp(packageName); |
| verify(mPasspointManager).removePasspointProviderWithPackage(packageName); |
| } |
| |
| @Test |
| public void testPackageRemovedBroadcastHandlingWithNoUid() { |
| when(mWifiInjector.getClientModeImplHandler()).thenReturn(mHandler); |
| mWifiServiceImpl.checkAndStartWifi(); |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| argThat((IntentFilter filter) -> |
| filter.hasAction(Intent.ACTION_PACKAGE_FULLY_REMOVED))); |
| |
| String packageName = TEST_PACKAGE_NAME; |
| // Send the broadcast |
| Intent intent = new Intent(Intent.ACTION_PACKAGE_FULLY_REMOVED); |
| intent.setData(Uri.fromParts("package", packageName, "")); |
| mBroadcastReceiverCaptor.getValue().onReceive(mContext, intent); |
| |
| verify(mClientModeImpl, never()).removeAppConfigs(anyString(), anyInt()); |
| |
| mLooper.dispatchAll(); |
| verify(mScanRequestProxy, never()).clearScanRequestTimestampsForApp(anyString(), anyInt()); |
| verify(mWifiNetworkSuggestionsManager, never()).removeApp(anyString()); |
| verify(mClientModeImpl, never()).removeNetworkRequestUserApprovedAccessPointsForApp( |
| packageName); |
| verify(mPasspointManager, never()).removePasspointProviderWithPackage(anyString()); |
| } |
| |
| @Test |
| public void testPackageRemovedBroadcastHandlingWithNoPackageName() { |
| when(mWifiInjector.getClientModeImplHandler()).thenReturn(mHandler); |
| mWifiServiceImpl.checkAndStartWifi(); |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| argThat((IntentFilter filter) -> |
| filter.hasAction(Intent.ACTION_PACKAGE_FULLY_REMOVED))); |
| |
| int uid = TEST_UID; |
| // Send the broadcast |
| Intent intent = new Intent(Intent.ACTION_PACKAGE_FULLY_REMOVED); |
| intent.putExtra(Intent.EXTRA_UID, uid); |
| mBroadcastReceiverCaptor.getValue().onReceive(mContext, intent); |
| |
| verify(mClientModeImpl, never()).removeAppConfigs(anyString(), anyInt()); |
| |
| mLooper.dispatchAll(); |
| verify(mScanRequestProxy, never()).clearScanRequestTimestampsForApp(anyString(), anyInt()); |
| verify(mWifiNetworkSuggestionsManager, never()).removeApp(anyString()); |
| verify(mClientModeImpl, never()).removeNetworkRequestUserApprovedAccessPointsForApp( |
| anyString()); |
| verify(mPasspointManager, never()).removePasspointProviderWithPackage(anyString()); |
| } |
| |
| @Test |
| public void testUserRemovedBroadcastHandling() { |
| mWifiServiceImpl.checkAndStartWifi(); |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| argThat((IntentFilter filter) -> |
| filter.hasAction(Intent.ACTION_USER_REMOVED))); |
| |
| int userHandle = TEST_USER_HANDLE; |
| // Send the broadcast |
| Intent intent = new Intent(Intent.ACTION_USER_REMOVED); |
| intent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle); |
| mBroadcastReceiverCaptor.getValue().onReceive(mContext, intent); |
| |
| verify(mClientModeImpl).removeUserConfigs(userHandle); |
| } |
| |
| @Test |
| public void testUserRemovedBroadcastHandlingWithWrongIntentAction() { |
| mWifiServiceImpl.checkAndStartWifi(); |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| argThat((IntentFilter filter) -> |
| filter.hasAction(Intent.ACTION_USER_REMOVED))); |
| |
| int userHandle = TEST_USER_HANDLE; |
| // Send the broadcast with wrong action |
| Intent intent = new Intent(Intent.ACTION_USER_FOREGROUND); |
| intent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle); |
| mBroadcastReceiverCaptor.getValue().onReceive(mContext, intent); |
| |
| verify(mClientModeImpl, never()).removeUserConfigs(userHandle); |
| } |
| |
| /** |
| * Test for needs5GHzToAnyApBandConversion returns true. Requires the NETWORK_SETTINGS |
| * permission. |
| */ |
| @Test |
| public void testNeeds5GHzToAnyApBandConversionReturnedTrue() { |
| when(mResources.getBoolean( |
| eq(com.android.internal.R.bool.config_wifi_convert_apband_5ghz_to_any))) |
| .thenReturn(true); |
| assertTrue(mWifiServiceImpl.needs5GHzToAnyApBandConversion()); |
| |
| verify(mContext).enforceCallingOrSelfPermission( |
| eq(android.Manifest.permission.NETWORK_SETTINGS), eq("WifiService")); |
| } |
| |
| /** |
| * Test for needs5GHzToAnyApBandConversion returns false. Requires the NETWORK_SETTINGS |
| * permission. |
| */ |
| @Test |
| public void testNeeds5GHzToAnyApBandConversionReturnedFalse() { |
| when(mResources.getBoolean( |
| eq(com.android.internal.R.bool.config_wifi_convert_apband_5ghz_to_any))) |
| .thenReturn(false); |
| |
| assertFalse(mWifiServiceImpl.needs5GHzToAnyApBandConversion()); |
| |
| verify(mContext).enforceCallingOrSelfPermission( |
| eq(android.Manifest.permission.NETWORK_SETTINGS), eq("WifiService")); |
| } |
| |
| /** |
| * The API impl for needs5GHzToAnyApBandConversion requires the NETWORK_SETTINGS permission, |
| * verify an exception is thrown without holding the permission. |
| */ |
| @Test |
| public void testNeeds5GHzToAnyApBandConversionThrowsWithoutProperPermissions() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| |
| try { |
| mWifiServiceImpl.needs5GHzToAnyApBandConversion(); |
| // should have thrown an exception - fail test |
| fail(); |
| } catch (SecurityException e) { |
| // expected |
| } |
| } |
| |
| |
| private class IdleModeIntentMatcher implements ArgumentMatcher<IntentFilter> { |
| @Override |
| public boolean matches(IntentFilter filter) { |
| return filter.hasAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); |
| } |
| } |
| |
| /** |
| * Verifies that enforceChangePermission(String package) is called and the caller doesn't |
| * have NETWORK_SETTINGS permission |
| */ |
| private void verifyCheckChangePermission(String callingPackageName) { |
| verify(mContext, atLeastOnce()) |
| .checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt()); |
| verify(mContext, atLeastOnce()).enforceCallingOrSelfPermission( |
| android.Manifest.permission.CHANGE_WIFI_STATE, "WifiService"); |
| verify(mAppOpsManager, atLeastOnce()).noteOp( |
| AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), callingPackageName); |
| } |
| |
| private WifiConfiguration createValidSoftApConfiguration() { |
| WifiConfiguration apConfig = new WifiConfiguration(); |
| apConfig.SSID = "TestAp"; |
| apConfig.preSharedKey = "thisIsABadPassword"; |
| apConfig.allowedKeyManagement.set(KeyMgmt.WPA2_PSK); |
| apConfig.apBand = WifiConfiguration.AP_BAND_2GHZ; |
| |
| return apConfig; |
| } |
| |
| /** |
| * Verifies that sim state change does not set or reset the country code |
| */ |
| @Test |
| public void testSimStateChangeDoesNotResetCountryCode() { |
| mWifiServiceImpl.checkAndStartWifi(); |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| (IntentFilter) argThat((IntentFilter filter) -> |
| filter.hasAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED))); |
| |
| int userHandle = TEST_USER_HANDLE; |
| // Send the broadcast |
| Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); |
| intent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle); |
| mBroadcastReceiverCaptor.getValue().onReceive(mContext, intent); |
| verifyNoMoreInteractions(mWifiCountryCode); |
| } |
| |
| /** |
| * Verify calls to notify users of a softap config change check the NETWORK_SETTINGS permission. |
| */ |
| @Test |
| public void testNotifyUserOfApBandConversionChecksNetworkSettingsPermission() { |
| mWifiServiceImpl.notifyUserOfApBandConversion(TEST_PACKAGE_NAME); |
| verify(mContext).enforceCallingOrSelfPermission( |
| eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| verify(mWifiApConfigStore).notifyUserOfApBandConversion(eq(TEST_PACKAGE_NAME)); |
| } |
| |
| /** |
| * Verify calls to notify users do not trigger a notification when NETWORK_SETTINGS is not held |
| * by the caller. |
| */ |
| @Test |
| public void testNotifyUserOfApBandConversionThrowsExceptionWithoutNetworkSettingsPermission() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| try { |
| mWifiServiceImpl.notifyUserOfApBandConversion(TEST_PACKAGE_NAME); |
| fail("Expected Security exception"); |
| } catch (SecurityException e) { } |
| } |
| |
| /** |
| * Verify that a call to registerTrafficStateCallback throws a SecurityException if the caller |
| * does not have NETWORK_SETTINGS permission. |
| */ |
| @Test |
| public void registerTrafficStateCallbackThrowsSecurityExceptionOnMissingPermissions() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| try { |
| mWifiServiceImpl.registerTrafficStateCallback(mAppBinder, mTrafficStateCallback, |
| TEST_TRAFFIC_STATE_CALLBACK_IDENTIFIER); |
| fail("expected SecurityException"); |
| } catch (SecurityException expected) { |
| } |
| } |
| |
| /** |
| * Verify that a call to registerTrafficStateCallback throws an IllegalArgumentException if the |
| * parameters are not provided. |
| */ |
| @Test |
| public void registerTrafficStateCallbackThrowsIllegalArgumentExceptionOnInvalidArguments() { |
| try { |
| mWifiServiceImpl.registerTrafficStateCallback( |
| mAppBinder, null, TEST_TRAFFIC_STATE_CALLBACK_IDENTIFIER); |
| fail("expected IllegalArgumentException"); |
| } catch (IllegalArgumentException expected) { |
| } |
| } |
| |
| /** |
| * Verify that a call to unregisterTrafficStateCallback throws a SecurityException if the caller |
| * does not have NETWORK_SETTINGS permission. |
| */ |
| @Test |
| public void unregisterTrafficStateCallbackThrowsSecurityExceptionOnMissingPermissions() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| try { |
| mWifiServiceImpl.unregisterTrafficStateCallback(TEST_TRAFFIC_STATE_CALLBACK_IDENTIFIER); |
| fail("expected SecurityException"); |
| } catch (SecurityException expected) { |
| } |
| } |
| |
| /** |
| * Verify that registerTrafficStateCallback adds callback to {@link WifiTrafficPoller}. |
| */ |
| @Test |
| public void registerTrafficStateCallbackAndVerify() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| mWifiServiceImpl.registerTrafficStateCallback( |
| mAppBinder, mTrafficStateCallback, TEST_TRAFFIC_STATE_CALLBACK_IDENTIFIER); |
| mLooper.dispatchAll(); |
| verify(mWifiTrafficPoller).addCallback( |
| mAppBinder, mTrafficStateCallback, TEST_TRAFFIC_STATE_CALLBACK_IDENTIFIER); |
| } |
| |
| /** |
| * Verify that unregisterTrafficStateCallback removes callback from {@link WifiTrafficPoller}. |
| */ |
| @Test |
| public void unregisterTrafficStateCallbackAndVerify() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| mWifiServiceImpl.unregisterTrafficStateCallback(0); |
| mLooper.dispatchAll(); |
| verify(mWifiTrafficPoller).removeCallback(0); |
| } |
| |
| /** |
| * Verify that a call to registerNetworkRequestMatchCallback throws a SecurityException if the |
| * caller does not have NETWORK_SETTINGS permission. |
| */ |
| @Test |
| public void registerNetworkRequestMatchCallbackThrowsSecurityExceptionOnMissingPermissions() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| try { |
| mWifiServiceImpl.registerNetworkRequestMatchCallback(mAppBinder, |
| mNetworkRequestMatchCallback, |
| TEST_NETWORK_REQUEST_MATCH_CALLBACK_IDENTIFIER); |
| fail("expected SecurityException"); |
| } catch (SecurityException expected) { |
| } |
| } |
| |
| /** |
| * Verify that a call to registerNetworkRequestMatchCallback throws an IllegalArgumentException |
| * if the parameters are not provided. |
| */ |
| @Test |
| public void |
| registerNetworkRequestMatchCallbackThrowsIllegalArgumentExceptionOnInvalidArguments() { |
| try { |
| mWifiServiceImpl.registerNetworkRequestMatchCallback( |
| mAppBinder, null, TEST_NETWORK_REQUEST_MATCH_CALLBACK_IDENTIFIER); |
| fail("expected IllegalArgumentException"); |
| } catch (IllegalArgumentException expected) { |
| } |
| } |
| |
| /** |
| * Verify that a call to unregisterNetworkRequestMatchCallback throws a SecurityException if the |
| * caller does not have NETWORK_SETTINGS permission. |
| */ |
| @Test |
| public void unregisterNetworkRequestMatchCallbackThrowsSecurityExceptionOnMissingPermissions() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| try { |
| mWifiServiceImpl.unregisterNetworkRequestMatchCallback( |
| TEST_NETWORK_REQUEST_MATCH_CALLBACK_IDENTIFIER); |
| fail("expected SecurityException"); |
| } catch (SecurityException expected) { |
| } |
| } |
| |
| /** |
| * Verify that registerNetworkRequestMatchCallback adds callback to |
| * {@link ClientModeImpl}. |
| */ |
| @Test |
| public void registerNetworkRequestMatchCallbackAndVerify() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| mWifiServiceImpl.registerNetworkRequestMatchCallback( |
| mAppBinder, mNetworkRequestMatchCallback, |
| TEST_NETWORK_REQUEST_MATCH_CALLBACK_IDENTIFIER); |
| mLooper.dispatchAll(); |
| verify(mClientModeImpl).addNetworkRequestMatchCallback( |
| mAppBinder, mNetworkRequestMatchCallback, |
| TEST_NETWORK_REQUEST_MATCH_CALLBACK_IDENTIFIER); |
| } |
| |
| /** |
| * Verify that unregisterNetworkRequestMatchCallback removes callback from |
| * {@link ClientModeImpl}. |
| */ |
| @Test |
| public void unregisterNetworkRequestMatchCallbackAndVerify() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| mWifiServiceImpl.unregisterNetworkRequestMatchCallback( |
| TEST_NETWORK_REQUEST_MATCH_CALLBACK_IDENTIFIER); |
| mLooper.dispatchAll(); |
| verify(mClientModeImpl).removeNetworkRequestMatchCallback( |
| TEST_NETWORK_REQUEST_MATCH_CALLBACK_IDENTIFIER); |
| } |
| |
| /** |
| * Verify that Wifi configuration and Passpoint configuration are removed in factoryReset. |
| */ |
| @Test |
| public void testFactoryReset() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); |
| final String fqdn = "example.com"; |
| WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork(); |
| openNetwork.networkId = TEST_NETWORK_ID; |
| WifiConfiguration eapNetwork = WifiConfigurationTestUtil.createEapNetwork( |
| WifiEnterpriseConfig.Eap.TLS, WifiEnterpriseConfig.Phase2.NONE); |
| eapNetwork.networkId = TEST_NETWORK_ID + 1; |
| PasspointConfiguration config = new PasspointConfiguration(); |
| HomeSp homeSp = new HomeSp(); |
| homeSp.setFqdn(fqdn); |
| config.setHomeSp(homeSp); |
| |
| mWifiServiceImpl.mClientModeImplChannel = mAsyncChannel; |
| when(mClientModeImpl.syncGetConfiguredNetworks(anyInt(), any(), anyInt())) |
| .thenReturn(Arrays.asList(openNetwork, eapNetwork)); |
| when(mClientModeImpl.syncGetPasspointConfigs(any())).thenReturn(Arrays.asList(config)); |
| |
| mWifiServiceImpl.factoryReset(TEST_PACKAGE_NAME); |
| mLooper.dispatchAll(); |
| |
| verify(mClientModeImpl).syncRemoveNetwork(mAsyncChannel, openNetwork.networkId); |
| verify(mClientModeImpl).syncRemoveNetwork(mAsyncChannel, eapNetwork.networkId); |
| verify(mWifiKeyStore).removeKeys(eapNetwork.enterpriseConfig, true); |
| verify(mClientModeImpl).syncRemovePasspointConfig(mAsyncChannel, fqdn); |
| verify(mWifiConfigManager).clearDeletedEphemeralNetworks(); |
| verify(mClientModeImpl).clearNetworkRequestUserApprovedAccessPoints(); |
| verify(mWifiNetworkSuggestionsManager).clear(); |
| verify(mWifiScoreCard).clear(); |
| } |
| |
| /** |
| * Verify that Passpoint configuration is not removed in factoryReset if Passpoint feature |
| * is not supported. |
| */ |
| @Test |
| public void testFactoryResetWithoutPasspointSupport() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| mWifiServiceImpl.mClientModeImplChannel = mAsyncChannel; |
| when(mPackageManager.hasSystemFeature( |
| PackageManager.FEATURE_WIFI_PASSPOINT)).thenReturn(false); |
| |
| mWifiServiceImpl.factoryReset(TEST_PACKAGE_NAME); |
| mLooper.dispatchAll(); |
| |
| verify(mClientModeImpl).syncGetConfiguredNetworks(anyInt(), any(), anyInt()); |
| verify(mClientModeImpl, never()).syncGetPasspointConfigs(any()); |
| verify(mClientModeImpl, never()).syncRemovePasspointConfig(any(), anyString()); |
| verify(mWifiConfigManager).clearDeletedEphemeralNetworks(); |
| verify(mClientModeImpl).clearNetworkRequestUserApprovedAccessPoints(); |
| verify(mWifiNetworkSuggestionsManager).clear(); |
| } |
| |
| /** |
| * Verify that a call to factoryReset throws a SecurityException if the caller does not have |
| * the CONNECTIVITY_INTERNAL permission. |
| */ |
| @Test |
| public void testFactoryResetWithoutConnectivityInternalPermission() throws Exception { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(Manifest.permission.CONNECTIVITY_INTERNAL), |
| eq("ConnectivityService")); |
| mWifiServiceImpl.mClientModeImplChannel = mAsyncChannel; |
| |
| try { |
| mWifiServiceImpl.factoryReset(TEST_PACKAGE_NAME); |
| fail(); |
| } catch (SecurityException e) { |
| } |
| verify(mClientModeImpl, never()).syncGetConfiguredNetworks(anyInt(), any(), anyInt()); |
| verify(mClientModeImpl, never()).syncGetPasspointConfigs(any()); |
| } |
| |
| /** |
| * Verify that add or update networks is not allowed for apps targeting Q SDK. |
| */ |
| @Test |
| public void testAddOrUpdateNetworkIsNotAllowedForAppsTargetingQSDK() throws Exception { |
| mLooper.dispatchAll(); |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mClientModeImpl.syncAddOrUpdateNetwork(any(), any())).thenReturn(0); |
| |
| WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); |
| assertEquals(-1, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)); |
| |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| verify(mClientModeImpl, never()).syncAddOrUpdateNetwork(any(), any()); |
| verify(mWifiMetrics, never()).incrementNumAddOrUpdateNetworkCalls(); |
| } |
| |
| /** |
| * Verify that add or update networks is allowed for apps targeting below Q SDK. |
| */ |
| @Test |
| public void testAddOrUpdateNetworkIsAllowedForAppsTargetingBelowQSDK() throws Exception { |
| mLooper.dispatchAll(); |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mClientModeImpl.syncAddOrUpdateNetwork(any(), any())).thenReturn(0); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(anyString(), |
| eq(Build.VERSION_CODES.Q))).thenReturn(true); |
| |
| WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); |
| assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)); |
| |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| verify(mClientModeImpl).syncAddOrUpdateNetwork(any(), any()); |
| verify(mWifiMetrics).incrementNumAddOrUpdateNetworkCalls(); |
| } |
| |
| /** |
| * Verify that add or update networks is allowed for settings app. |
| */ |
| @Test |
| public void testAddOrUpdateNetworkIsAllowedForSettingsApp() throws Exception { |
| mLooper.dispatchAll(); |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| mApplicationInfo.targetSdkVersion = Build.VERSION_CODES.P; |
| when(mClientModeImpl.syncAddOrUpdateNetwork(any(), any())).thenReturn(0); |
| |
| WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); |
| assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)); |
| |
| // Ensure that we don't check for change permission. |
| verify(mContext, never()).enforceCallingOrSelfPermission( |
| android.Manifest.permission.CHANGE_WIFI_STATE, "WifiService"); |
| verify(mAppOpsManager, never()).noteOp( |
| AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| verify(mClientModeImpl).syncAddOrUpdateNetwork(any(), any()); |
| verify(mWifiMetrics).incrementNumAddOrUpdateNetworkCalls(); |
| } |
| |
| /** |
| * Verify that add or update networks is allowed for system apps. |
| */ |
| @Test |
| public void testAddOrUpdateNetworkIsAllowedForSystemApp() throws Exception { |
| mLooper.dispatchAll(); |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM; |
| when(mClientModeImpl.syncAddOrUpdateNetwork(any(), any())).thenReturn(0); |
| |
| WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); |
| assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)); |
| |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| verify(mClientModeImpl).syncAddOrUpdateNetwork(any(), any()); |
| verify(mWifiMetrics).incrementNumAddOrUpdateNetworkCalls(); |
| } |
| |
| /** |
| * Verify that add or update networks is allowed for apps holding system alert permission. |
| */ |
| @Test |
| public void testAddOrUpdateNetworkIsAllowedForAppsWithSystemAlertPermission() throws Exception { |
| mLooper.dispatchAll(); |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| |
| when(mWifiPermissionsUtil.checkSystemAlertWindowPermission( |
| Process.myUid(), TEST_PACKAGE_NAME)).thenReturn(true); |
| when(mClientModeImpl.syncAddOrUpdateNetwork(any(), any())).thenReturn(0); |
| |
| WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); |
| assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)); |
| |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| verify(mWifiPermissionsUtil).checkSystemAlertWindowPermission(anyInt(), anyString()); |
| verify(mClientModeImpl).syncAddOrUpdateNetwork(any(), any()); |
| verify(mWifiMetrics).incrementNumAddOrUpdateNetworkCalls(); |
| } |
| |
| /** |
| * Verify that add or update networks is allowed for DeviceOwner app. |
| */ |
| @Test |
| public void testAddOrUpdateNetworkIsAllowedForDOApp() throws Exception { |
| mLooper.dispatchAll(); |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mDevicePolicyManagerInternal.isActiveAdminWithPolicy( |
| Process.myUid(), DeviceAdminInfo.USES_POLICY_DEVICE_OWNER)) |
| .thenReturn(true); |
| when(mClientModeImpl.syncAddOrUpdateNetwork(any(), any())).thenReturn(0); |
| |
| WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); |
| assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)); |
| |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| verify(mClientModeImpl).syncAddOrUpdateNetwork(any(), any()); |
| verify(mWifiMetrics).incrementNumAddOrUpdateNetworkCalls(); |
| } |
| |
| /** |
| * Verify that add or update networks is allowed for ProfileOwner app. |
| */ |
| @Test |
| public void testAddOrUpdateNetworkIsAllowedForPOApp() throws Exception { |
| mLooper.dispatchAll(); |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mDevicePolicyManagerInternal.isActiveAdminWithPolicy( |
| Process.myUid(), DeviceAdminInfo.USES_POLICY_PROFILE_OWNER)) |
| .thenReturn(true); |
| when(mClientModeImpl.syncAddOrUpdateNetwork(any(), any())).thenReturn(0); |
| |
| WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); |
| assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)); |
| |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| verify(mClientModeImpl).syncAddOrUpdateNetwork(any(), any()); |
| verify(mWifiMetrics).incrementNumAddOrUpdateNetworkCalls(); |
| } |
| |
| /** |
| * Verify that enableNetwork is allowed for privileged Apps |
| */ |
| @Test |
| public void testEnableNetworkAllowedForPrivilegedApps() throws Exception { |
| mLooper.dispatchAll(); |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| |
| mWifiServiceImpl.enableNetwork(TEST_NETWORK_ID, true, TEST_PACKAGE_NAME); |
| |
| verify(mClientModeImpl).syncEnableNetwork(eq(mAsyncChannel), eq(TEST_NETWORK_ID), |
| eq(true)); |
| verify(mWifiMetrics).incrementNumEnableNetworkCalls(); |
| } |
| |
| /** |
| * Verify that enableNetwork is allowed for Apps targeting a SDK version less than Q |
| */ |
| @Test |
| public void testEnabledNetworkAllowedForAppsTargetingLessThanQ() throws Exception { |
| mLooper.dispatchAll(); |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(anyString(), |
| eq(Build.VERSION_CODES.Q))).thenReturn(true); |
| |
| mWifiServiceImpl.enableNetwork(TEST_NETWORK_ID, true, TEST_PACKAGE_NAME); |
| |
| verify(mClientModeImpl).syncEnableNetwork(eq(mAsyncChannel), eq(TEST_NETWORK_ID), |
| eq(true)); |
| verify(mWifiMetrics).incrementNumEnableNetworkCalls(); |
| } |
| |
| /** |
| * Verify that enableNetwork is not allowed for Apps targeting Q SDK |
| */ |
| @Test |
| public void testEnableNetworkNotAllowedForAppsTargetingQ() throws Exception { |
| mLooper.dispatchAll(); |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| |
| mWifiServiceImpl.enableNetwork(TEST_NETWORK_ID, true, TEST_PACKAGE_NAME); |
| |
| verify(mClientModeImpl, never()).syncEnableNetwork(anyObject(), anyInt(), anyBoolean()); |
| verify(mWifiMetrics, never()).incrementNumEnableNetworkCalls(); |
| } |
| |
| /** |
| * Ensure that we invoke {@link WifiNetworkSuggestionsManager} to add network |
| * suggestions. |
| */ |
| @Test |
| public void testAddNetworkSuggestions() { |
| setupClientModeImplHandlerForRunWithScissors(); |
| |
| when(mWifiNetworkSuggestionsManager.add(any(), anyInt(), anyString())) |
| .thenReturn(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS); |
| assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS, |
| mWifiServiceImpl.addNetworkSuggestions(mock(List.class), TEST_PACKAGE_NAME)); |
| |
| when(mWifiNetworkSuggestionsManager.add(any(), anyInt(), anyString())) |
| .thenReturn(WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE); |
| assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE, |
| mWifiServiceImpl.addNetworkSuggestions(mock(List.class), TEST_PACKAGE_NAME)); |
| |
| doReturn(false).when(mHandlerSpyForCmiRunWithScissors) |
| .runWithScissors(any(), anyLong()); |
| assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL, |
| mWifiServiceImpl.addNetworkSuggestions(mock(List.class), TEST_PACKAGE_NAME)); |
| |
| verify(mWifiNetworkSuggestionsManager, times(2)).add( |
| any(), eq(Binder.getCallingUid()), eq(TEST_PACKAGE_NAME)); |
| } |
| |
| /** |
| * Ensure that we invoke {@link WifiNetworkSuggestionsManager} to remove network |
| * suggestions. |
| */ |
| @Test |
| public void testRemoveNetworkSuggestions() { |
| setupClientModeImplHandlerForRunWithScissors(); |
| |
| when(mWifiNetworkSuggestionsManager.remove(any(), anyInt(), anyString())) |
| .thenReturn(WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID); |
| assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID, |
| mWifiServiceImpl.removeNetworkSuggestions(mock(List.class), TEST_PACKAGE_NAME)); |
| |
| when(mWifiNetworkSuggestionsManager.remove(any(), anyInt(), anyString())) |
| .thenReturn(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS); |
| assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS, |
| mWifiServiceImpl.removeNetworkSuggestions(mock(List.class), TEST_PACKAGE_NAME)); |
| |
| doReturn(false).when(mHandlerSpyForCmiRunWithScissors) |
| .runWithScissors(any(), anyLong()); |
| assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL, |
| mWifiServiceImpl.removeNetworkSuggestions(mock(List.class), TEST_PACKAGE_NAME)); |
| |
| verify(mWifiNetworkSuggestionsManager, times(2)).remove( |
| any(), eq(Binder.getCallingUid()), eq(TEST_PACKAGE_NAME)); |
| } |
| |
| /** |
| * Verify that if the caller has NETWORK_SETTINGS permission, then it can invoke |
| * {@link WifiManager#disableEphemeralNetwork(String)}. |
| */ |
| @Test |
| public void testDisableEphemeralNetworkWithNetworkSettingsPerm() throws Exception { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| mWifiServiceImpl.disableEphemeralNetwork(new String(), TEST_PACKAGE_NAME); |
| verify(mClientModeImpl).disableEphemeralNetwork(anyString()); |
| } |
| |
| /** |
| * Verify that if the caller does not have NETWORK_SETTINGS permission, then it cannot invoke |
| * {@link WifiManager#disableEphemeralNetwork(String)}. |
| */ |
| @Test |
| public void testDisableEphemeralNetworkWithoutNetworkSettingsPerm() throws Exception { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED); |
| mWifiServiceImpl.disableEphemeralNetwork(new String(), TEST_PACKAGE_NAME); |
| verify(mClientModeImpl, never()).disableEphemeralNetwork(anyString()); |
| } |
| |
| /** |
| * Verify getting the factory MAC address. |
| */ |
| @Test |
| public void testGetFactoryMacAddresses() throws Exception { |
| setupClientModeImplHandlerForRunWithScissors(); |
| when(mClientModeImpl.getFactoryMacAddress()).thenReturn(TEST_FACTORY_MAC); |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); |
| final String[] factoryMacs = mWifiServiceImpl.getFactoryMacAddresses(); |
| assertEquals(1, factoryMacs.length); |
| assertEquals(TEST_FACTORY_MAC, factoryMacs[0]); |
| verify(mClientModeImpl).getFactoryMacAddress(); |
| } |
| |
| /** |
| * Verify getting the factory MAC address returns null when posting the runnable to handler |
| * fails. |
| */ |
| @Test |
| public void testGetFactoryMacAddressesPostFail() throws Exception { |
| setupClientModeImplHandlerForRunWithScissors(); |
| doReturn(false).when(mHandlerSpyForCmiRunWithScissors) |
| .runWithScissors(any(), anyLong()); |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); |
| assertNull(mWifiServiceImpl.getFactoryMacAddresses()); |
| verify(mClientModeImpl, never()).getFactoryMacAddress(); |
| } |
| |
| /** |
| * Verify getting the factory MAC address returns null when the lower layers fail. |
| */ |
| @Test |
| public void testGetFactoryMacAddressesFail() throws Exception { |
| setupClientModeImplHandlerForRunWithScissors(); |
| when(mClientModeImpl.getFactoryMacAddress()).thenReturn(null); |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); |
| assertNull(mWifiServiceImpl.getFactoryMacAddresses()); |
| verify(mClientModeImpl).getFactoryMacAddress(); |
| } |
| |
| /** |
| * Verify getting the factory MAC address throws a SecurityException if the calling app |
| * doesn't have NETWORK_SETTINGS permission. |
| */ |
| @Test |
| public void testGetFactoryMacAddressesFailNoNetworkSettingsPermission() throws Exception { |
| setupClientModeImplHandlerForRunWithScissors(); |
| when(mClientModeImpl.getFactoryMacAddress()).thenReturn(TEST_FACTORY_MAC); |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(false); |
| try { |
| mWifiServiceImpl.getFactoryMacAddresses(); |
| fail(); |
| } catch (SecurityException e) { |
| assertTrue("Exception message should contain 'factory MAC'", |
| e.toString().contains("factory MAC")); |
| } |
| } |
| |
| /** |
| * Verify that a call to setDeviceMobilityState throws a SecurityException if the |
| * caller does not have WIFI_SET_DEVICE_MOBILITY_STATE permission. |
| */ |
| @Test |
| public void setDeviceMobilityStateThrowsSecurityExceptionOnMissingPermissions() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingPermission( |
| eq(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE), |
| eq("WifiService")); |
| try { |
| mWifiServiceImpl.setDeviceMobilityState(DEVICE_MOBILITY_STATE_STATIONARY); |
| fail("expected SecurityException"); |
| } catch (SecurityException expected) { |
| } |
| } |
| |
| /** |
| * Verifies that setDeviceMobilityState runs on a separate handler thread. |
| */ |
| @Test |
| public void setDeviceMobilityStateRunsOnHandler() { |
| setupClientModeImplHandlerForPost(); |
| |
| mWifiServiceImpl.setDeviceMobilityState(DEVICE_MOBILITY_STATE_STATIONARY); |
| verify(mClientModeImpl, never()).setDeviceMobilityState(anyInt()); |
| mLooper.dispatchAll(); |
| verify(mClientModeImpl).setDeviceMobilityState(eq(DEVICE_MOBILITY_STATE_STATIONARY)); |
| } |
| |
| /** |
| * Verify that a call to addOnWifiUsabilityStatsListener throws a SecurityException if |
| * the caller does not have WIFI_UPDATE_USABILITY_STATS_SCORE permission. |
| */ |
| @Test |
| public void testAddStatsListenerThrowsSecurityExceptionOnMissingPermissions() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingPermission( |
| eq(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE), |
| eq("WifiService")); |
| try { |
| mWifiServiceImpl.addOnWifiUsabilityStatsListener(mAppBinder, |
| mOnWifiUsabilityStatsListener, TEST_WIFI_USABILITY_STATS_LISTENER_IDENTIFIER); |
| fail("expected SecurityException"); |
| } catch (SecurityException expected) { |
| } |
| } |
| |
| /** |
| * Verify that a call to addOnWifiUsabilityStatsListener throws an IllegalArgumentException |
| * if the parameters are not provided. |
| */ |
| @Test |
| public void testAddStatsListenerThrowsIllegalArgumentExceptionOnInvalidArguments() { |
| try { |
| mWifiServiceImpl.addOnWifiUsabilityStatsListener( |
| mAppBinder, null, TEST_WIFI_USABILITY_STATS_LISTENER_IDENTIFIER); |
| fail("expected IllegalArgumentException"); |
| } catch (IllegalArgumentException expected) { |
| } |
| } |
| |
| /** |
| * Verify that a call to removeOnWifiUsabilityStatsListener throws a SecurityException if |
| * the caller does not have WIFI_UPDATE_USABILITY_STATS_SCORE permission. |
| */ |
| @Test |
| public void testRemoveStatsListenerThrowsSecurityExceptionOnMissingPermissions() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingPermission( |
| eq(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE), |
| eq("WifiService")); |
| try { |
| mWifiServiceImpl.removeOnWifiUsabilityStatsListener( |
| TEST_WIFI_USABILITY_STATS_LISTENER_IDENTIFIER); |
| fail("expected SecurityException"); |
| } catch (SecurityException expected) { |
| } |
| } |
| |
| /** |
| * Verify that addOnWifiUsabilityStatsListener adds listener to {@link WifiMetrics}. |
| */ |
| @Test |
| public void testAddOnWifiUsabilityStatsListenerAndVerify() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| mWifiServiceImpl.addOnWifiUsabilityStatsListener(mAppBinder, mOnWifiUsabilityStatsListener, |
| TEST_WIFI_USABILITY_STATS_LISTENER_IDENTIFIER); |
| mLooper.dispatchAll(); |
| verify(mWifiMetrics).addOnWifiUsabilityListener(mAppBinder, mOnWifiUsabilityStatsListener, |
| TEST_WIFI_USABILITY_STATS_LISTENER_IDENTIFIER); |
| } |
| |
| /** |
| * Verify that removeOnWifiUsabilityStatsListener removes listener from |
| * {@link WifiMetrics}. |
| */ |
| @Test |
| public void testRemoveOnWifiUsabilityStatsListenerAndVerify() throws Exception { |
| setupClientModeImplHandlerForPost(); |
| |
| mWifiServiceImpl.removeOnWifiUsabilityStatsListener(0); |
| mLooper.dispatchAll(); |
| verify(mWifiMetrics).removeOnWifiUsabilityListener(0); |
| } |
| |
| /** |
| * Verify that a call to updateWifiUsabilityScore throws a SecurityException if the |
| * caller does not have UPDATE_WIFI_USABILITY_SCORE permission. |
| */ |
| @Test |
| public void testUpdateWifiUsabilityScoreThrowsSecurityExceptionOnMissingPermissions() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingPermission( |
| eq(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE), |
| eq("WifiService")); |
| try { |
| mWifiServiceImpl.updateWifiUsabilityScore(anyInt(), anyInt(), 15); |
| fail("expected SecurityException"); |
| } catch (SecurityException expected) { |
| } |
| } |
| |
| /** |
| * Verify that mClientModeImpl in WifiServiceImpl is being updated on Wifi usability score |
| * update event. |
| */ |
| @Test |
| public void testWifiUsabilityScoreUpdateAfterScoreEvent() { |
| setupClientModeImplHandlerForPost(); |
| |
| mWifiServiceImpl.updateWifiUsabilityScore(anyInt(), anyInt(), 15); |
| mLooper.dispatchAll(); |
| verify(mClientModeImpl).updateWifiUsabilityScore(anyInt(), anyInt(), anyInt()); |
| } |
| |
| private void setupMaxApInterfaces(int val) { |
| when(mResources.getInteger( |
| eq(com.android.internal.R.integer.config_wifi_max_ap_interfaces))) |
| .thenReturn(val); |
| } |
| |
| private void startLohsAndTethering(int apCount) { |
| // initialization |
| setupClientModeImplHandlerForPost(); |
| setupMaxApInterfaces(apCount); |
| mWifiServiceImpl.checkAndStartWifi(); |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| (IntentFilter) argThat(new IntentFilterMatcher())); |
| |
| // start LOHS |
| registerLOHSRequestFull(); |
| String ifaceName = apCount >= 2 ? WIFI_IFACE_NAME2 : WIFI_IFACE_NAME; |
| mWifiServiceImpl.updateInterfaceIpState(ifaceName, IFACE_IP_MODE_LOCAL_ONLY); |
| mLooper.dispatchAll(); |
| verify(mWifiController) |
| .sendMessage(eq(CMD_SET_AP), eq(1), anyInt(), any(SoftApModeConfiguration.class)); |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| assertEquals(HOTSPOT_STARTED, mMessageCaptor.getValue().what); |
| reset(mWifiController); |
| reset(mHandler); |
| |
| // start tethering |
| boolean tetheringResult = mWifiServiceImpl.startSoftAp(null); |
| assertTrue(tetheringResult); |
| verify(mWifiController) |
| .sendMessage(eq(CMD_SET_AP), eq(1), anyInt(), any(SoftApModeConfiguration.class)); |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_TETHERED); |
| mLooper.dispatchAll(); |
| } |
| |
| /** |
| * Verify LOHS gets stopped when trying to start tethering concurrently on devices that |
| * doesn't support dual AP operation. |
| */ |
| @Test |
| public void testStartLohsAndTethering1AP() { |
| startLohsAndTethering(1); |
| |
| // verify LOHS got stopped |
| mLooper.dispatchAll(); |
| verify(mHandler).handleMessage(mMessageCaptor.capture()); |
| assertEquals(HOTSPOT_FAILED, mMessageCaptor.getValue().what); |
| verify(mWifiController) |
| .sendMessage(eq(CMD_SET_AP), eq(0), eq(WifiManager.IFACE_IP_MODE_LOCAL_ONLY)); |
| } |
| |
| /** |
| * Verify LOHS doesn't get stopped when trying to start tethering concurrently on devices |
| * that does support dual AP operation. |
| */ |
| @Test |
| public void testStartLohsAndTethering2AP() { |
| startLohsAndTethering(2); |
| |
| // verify LOHS didn't get stopped |
| mLooper.dispatchAll(); |
| verify(mHandler, never()).handleMessage(any(Message.class)); |
| verify(mWifiController, never()).sendMessage(eq(CMD_SET_AP), eq(0), anyInt()); |
| } |
| |
| /** |
| * Verify that the call to startDppAsConfiguratorInitiator throws a security exception when the |
| * caller doesn't have NETWORK_SETTINGS permissions or NETWORK_SETUP_WIZARD. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testStartDppAsConfiguratorInitiatorWithoutPermissions() { |
| mWifiServiceImpl.startDppAsConfiguratorInitiator(mAppBinder, DPP_URI, |
| 1, 1, mDppCallback); |
| } |
| |
| /** |
| * Verify that the call to startDppAsEnrolleeInitiator throws a security exception when the |
| * caller doesn't have NETWORK_SETTINGS permissions or NETWORK_SETUP_WIZARD. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testStartDppAsEnrolleeInitiatorWithoutPermissions() { |
| mWifiServiceImpl.startDppAsEnrolleeInitiator(mAppBinder, DPP_URI, mDppCallback); |
| } |
| |
| /** |
| * Verify that the call to stopDppSession throws a security exception when the |
| * caller doesn't have NETWORK_SETTINGS permissions or NETWORK_SETUP_WIZARD. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testStopDppSessionWithoutPermissions() { |
| try { |
| mWifiServiceImpl.stopDppSession(); |
| } catch (RemoteException e) { |
| } |
| } |
| } |