| /* |
| * 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.Manifest.permission.ACCESS_WIFI_STATE; |
| import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_METERED; |
| import static android.net.wifi.WifiManager.DEVICE_MOBILITY_STATE_STATIONARY; |
| 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.LocalOnlyHotspotCallback.REQUEST_REGISTERED; |
| import static android.net.wifi.WifiManager.SAP_START_FAILURE_GENERAL; |
| import static android.net.wifi.WifiManager.SAP_START_FAILURE_NO_CHANNEL; |
| import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; |
| import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; |
| import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; |
| import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; |
| import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; |
| |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; |
| import static com.android.server.wifi.LocalOnlyHotspotRequestInfo.HOTSPOT_NO_ERROR; |
| import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_VERBOSE_LOGGING_ENABLED; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import static org.junit.Assert.assertArrayEquals; |
| 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.AdditionalAnswers.returnsSecondArg; |
| import static org.mockito.ArgumentMatchers.notNull; |
| import static org.mockito.ArgumentMatchers.nullable; |
| 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.argThat; |
| import static org.mockito.Mockito.atLeastOnce; |
| import static org.mockito.Mockito.clearInvocations; |
| import static org.mockito.Mockito.doAnswer; |
| import static org.mockito.Mockito.doNothing; |
| import static org.mockito.Mockito.doReturn; |
| import static org.mockito.Mockito.doThrow; |
| import static org.mockito.Mockito.ignoreStubs; |
| import static org.mockito.Mockito.inOrder; |
| import static org.mockito.Mockito.isNull; |
| import static org.mockito.Mockito.lenient; |
| 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.validateMockitoUsage; |
| 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.test.MockAnswerUtil; |
| 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.PackageInfo; |
| import android.content.pm.PackageManager; |
| import android.content.pm.ParceledListSlice; |
| import android.content.res.Resources; |
| import android.net.MacAddress; |
| import android.net.NetworkStack; |
| import android.net.Uri; |
| import android.net.wifi.IActionListener; |
| import android.net.wifi.IDppCallback; |
| import android.net.wifi.ILocalOnlyHotspotCallback; |
| import android.net.wifi.INetworkRequestMatchCallback; |
| import android.net.wifi.IOnWifiActivityEnergyInfoListener; |
| import android.net.wifi.IOnWifiUsabilityStatsListener; |
| import android.net.wifi.IScanResultsCallback; |
| import android.net.wifi.ISoftApCallback; |
| import android.net.wifi.ISuggestionConnectionStatusListener; |
| import android.net.wifi.ITrafficStateCallback; |
| import android.net.wifi.IWifiConnectedNetworkScorer; |
| import android.net.wifi.ScanResult; |
| import android.net.wifi.SoftApConfiguration; |
| import android.net.wifi.SoftApInfo; |
| import android.net.wifi.WifiClient; |
| 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.WifiNetworkSuggestion; |
| import android.net.wifi.WifiScanner; |
| 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.Credential; |
| 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.IThermalService; |
| import android.os.Message; |
| import android.os.PowerManager; |
| import android.os.Process; |
| import android.os.RemoteException; |
| import android.os.UserHandle; |
| import android.os.UserManager; |
| import android.os.connectivity.WifiActivityEnergyInfo; |
| import android.os.test.TestLooper; |
| import android.telephony.CarrierConfigManager; |
| import android.telephony.PhoneStateListener; |
| import android.telephony.SubscriptionManager; |
| import android.telephony.TelephonyManager; |
| |
| import androidx.test.filters.SmallTest; |
| |
| import com.android.internal.os.PowerProfile; |
| 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.proto.nano.WifiMetricsProto.UserActionEvent; |
| import com.android.server.wifi.util.ApConfigUtil; |
| import com.android.server.wifi.util.WifiAsyncChannel; |
| import com.android.server.wifi.util.WifiPermissionsUtil; |
| import com.android.server.wifi.util.WifiPermissionsWrapper; |
| import com.android.wifi.resources.R; |
| |
| import org.junit.After; |
| 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.Mockito; |
| import org.mockito.MockitoAnnotations; |
| import org.mockito.MockitoSession; |
| |
| import java.io.FileDescriptor; |
| import java.io.PrintWriter; |
| import java.io.StringWriter; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * 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 extends WifiBaseTest { |
| |
| 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 TEST_FEATURE_ID = "TestFeature"; |
| 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 int TEST_WIFI_CONNECTED_NETWORK_SCORER_IDENTIFIER = 1; |
| 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 MacAddress TEST_FACTORY_MAC_ADDR = MacAddress.fromString(TEST_FACTORY_MAC); |
| private static final String TEST_FQDN = "testfqdn"; |
| private static final String TEST_FRIENDLY_NAME = "testfriendlyname"; |
| 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 static final int TEST_AP_FREQUENCY = 2412; |
| private static final int TEST_AP_BANDWIDTH = SoftApInfo.CHANNEL_WIDTH_20MHZ; |
| private static final int NETWORK_CALLBACK_ID = 1100; |
| private static final String TEST_CAP = "[RSN-PSK-CCMP]"; |
| private static final String TEST_SSID = "Sid's Place"; |
| private static final String TEST_SSID_WITH_QUOTES = "\"" + TEST_SSID + "\""; |
| private static final String TEST_BSSID = "01:02:03:04:05:06"; |
| private static final String TEST_PACKAGE = "package"; |
| private static final int TEST_NETWORK_ID = 567; |
| |
| private SoftApInfo mTestSoftApInfo; |
| private AsyncChannel mAsyncChannel; |
| private WifiServiceImpl mWifiServiceImpl; |
| private TestLooper mLooper; |
| private PowerManager mPowerManager; |
| private PhoneStateListener mPhoneStateListener; |
| private int mPid; |
| private int mPid2 = Process.myPid(); |
| private OsuProvider mOsuProvider; |
| private SoftApCallback mStateMachineSoftApCallback; |
| private SoftApCallback mLohsApCallback; |
| private String mLohsInterfaceName; |
| private ApplicationInfo mApplicationInfo; |
| private static final String DPP_URI = "DPP:some_dpp_uri"; |
| |
| private 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 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 SoftApBackupRestore mSoftApBackupRestore; |
| @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 WakeupController mWakeupController; |
| @Mock ITrafficStateCallback mTrafficStateCallback; |
| @Mock INetworkRequestMatchCallback mNetworkRequestMatchCallback; |
| @Mock WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager; |
| @Mock TelephonyManager mTelephonyManager; |
| @Mock IOnWifiUsabilityStatsListener mOnWifiUsabilityStatsListener; |
| @Mock WifiConfigManager mWifiConfigManager; |
| @Mock WifiScoreReport mWifiScoreReport; |
| @Mock WifiScoreCard mWifiScoreCard; |
| @Mock WifiHealthMonitor mWifiHealthMonitor; |
| @Mock PasspointManager mPasspointManager; |
| @Mock IDppCallback mDppCallback; |
| @Mock SarManager mSarManager; |
| @Mock ILocalOnlyHotspotCallback mLohsCallback; |
| @Mock IScanResultsCallback mScanResultsCallback; |
| @Mock ISuggestionConnectionStatusListener mSuggestionConnectionStatusListener; |
| @Mock IOnWifiActivityEnergyInfoListener mOnWifiActivityEnergyInfoListener; |
| @Mock IWifiConnectedNetworkScorer mWifiConnectedNetworkScorer; |
| @Mock WifiSettingsConfigStore mWifiSettingsConfigStore; |
| @Mock WifiScanAlwaysAvailableSettingsCompatibility mScanAlwaysAvailableSettingsCompatibility; |
| @Mock PackageInfo mPackageInfo; |
| |
| WifiLog mLog = new LogcatLog(TAG); |
| |
| @Before public void setUp() throws Exception { |
| MockitoAnnotations.initMocks(this); |
| mLooper = new TestLooper(); |
| mAsyncChannel = spy(new AsyncChannel()); |
| mApplicationInfo = new ApplicationInfo(); |
| mApplicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; |
| when(mResources.getInteger( |
| eq(R.integer.config_wifiHardwareSoftapMaxClientCount))) |
| .thenReturn(10); |
| 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.getWifiMetrics()).thenReturn(mWifiMetrics); |
| when(mWifiInjector.getClientModeImpl()).thenReturn(mClientModeImpl); |
| when(mClientModeImpl.getHandler()).thenReturn(new Handler()); |
| when(mWifiInjector.getActiveModeWarden()).thenReturn(mActiveModeWarden); |
| when(mWifiInjector.getAsyncChannelHandlerThread()).thenReturn(mHandlerThread); |
| when(mWifiInjector.getWifiHandlerThread()).thenReturn(mHandlerThread); |
| when(mHandlerThread.getThreadHandler()).thenReturn(new Handler(mLooper.getLooper())); |
| when(mHandlerThread.getLooper()).thenReturn(mLooper.getLooper()); |
| when(mContext.getResources()).thenReturn(mResources); |
| when(mContext.getContentResolver()).thenReturn(mContentResolver); |
| when(mContext.getPackageManager()).thenReturn(mPackageManager); |
| when(mPackageManager.getApplicationInfoAsUser(any(), anyInt(), any())) |
| .thenReturn(mApplicationInfo); |
| when(mPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(mPackageInfo); |
| 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); |
| IThermalService thermalService = mock(IThermalService.class); |
| mPowerManager = |
| new PowerManager(mContext, powerManagerService, thermalService, 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(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.getSoftApBackupRestore()).thenReturn(mSoftApBackupRestore); |
| 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.getWakeupController()).thenReturn(mWakeupController); |
| when(mWifiInjector.getWifiNetworkSuggestionsManager()) |
| .thenReturn(mWifiNetworkSuggestionsManager); |
| when(mWifiInjector.makeTelephonyManager()).thenReturn(mTelephonyManager); |
| when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager); |
| when(mWifiInjector.getWifiConfigManager()).thenReturn(mWifiConfigManager); |
| when(mWifiInjector.getPasspointManager()).thenReturn(mPasspointManager); |
| when(mClientModeImpl.getWifiScoreReport()).thenReturn(mWifiScoreReport); |
| when(mWifiInjector.getWifiScoreCard()).thenReturn(mWifiScoreCard); |
| when(mWifiInjector.getWifiHealthMonitor()).thenReturn(mWifiHealthMonitor); |
| when(mWifiInjector.getSarManager()).thenReturn(mSarManager); |
| when(mWifiInjector.getWifiNetworkScoreCache()) |
| .thenReturn(mock(WifiNetworkScoreCache.class)); |
| when(mWifiInjector.getWifiThreadRunner()) |
| .thenReturn(new WifiThreadRunner(new Handler(mLooper.getLooper()))); |
| when(mWifiInjector.getSettingsConfigStore()).thenReturn(mWifiSettingsConfigStore); |
| when(mWifiInjector.getWifiScanAlwaysAvailableSettingsCompatibility()) |
| .thenReturn(mScanAlwaysAvailableSettingsCompatibility); |
| when(mClientModeImpl.syncStartSubscriptionProvisioning(anyInt(), |
| any(OsuProvider.class), any(IProvisioningCallback.class), any())).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.getAttributionTag()).thenReturn(TEST_FEATURE_ID); |
| 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(mLohsCallback.asBinder()).thenReturn(mock(IBinder.class)); |
| when(mWifiSettingsConfigStore.get(eq(WIFI_VERBOSE_LOGGING_ENABLED))).thenReturn(true); |
| |
| mWifiServiceImpl = makeWifiServiceImpl(); |
| 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, String ssid, String channelList, int[] bandList) |
| throws RemoteException { |
| |
| } |
| |
| @Override |
| public void onProgress(int status) throws RemoteException { |
| |
| } |
| |
| @Override |
| public IBinder asBinder() { |
| return null; |
| } |
| }; |
| |
| // permission not granted by default |
| doThrow(SecurityException.class).when(mContext).enforceCallingOrSelfPermission( |
| eq(Manifest.permission.NETWORK_SETUP_WIZARD), any()); |
| mTestSoftApInfo = new SoftApInfo(); |
| mTestSoftApInfo.setFrequency(TEST_AP_FREQUENCY); |
| mTestSoftApInfo.setBandwidth(TEST_AP_BANDWIDTH); |
| } |
| |
| /** |
| * Called after each test |
| */ |
| @After |
| public void cleanup() { |
| validateMockitoUsage(); |
| } |
| |
| private WifiServiceImpl makeWifiServiceImpl() { |
| reset(mActiveModeWarden); |
| WifiServiceImpl wifiServiceImpl = |
| new WifiServiceImpl(mContext, mWifiInjector, mAsyncChannel); |
| ArgumentCaptor<SoftApCallback> softApCallbackCaptor = |
| ArgumentCaptor.forClass(SoftApCallback.class); |
| verify(mActiveModeWarden).registerSoftApCallback(softApCallbackCaptor.capture()); |
| mStateMachineSoftApCallback = softApCallbackCaptor.getValue(); |
| ArgumentCaptor<SoftApCallback> lohsCallbackCaptor = |
| ArgumentCaptor.forClass(SoftApCallback.class); |
| mLohsInterfaceName = WIFI_IFACE_NAME; |
| verify(mActiveModeWarden).registerLohsCallback(lohsCallbackCaptor.capture()); |
| mLohsApCallback = lohsCallbackCaptor.getValue(); |
| mLooper.dispatchAll(); |
| return wifiServiceImpl; |
| } |
| |
| private WifiServiceImpl makeWifiServiceImplWithMockRunnerWhichTimesOut() { |
| WifiThreadRunner mockRunner = mock(WifiThreadRunner.class); |
| when(mockRunner.call(any(), any())).then(returnsSecondArg()); |
| when(mockRunner.call(any(), any(int.class))).then(returnsSecondArg()); |
| when(mockRunner.call(any(), any(boolean.class))).then(returnsSecondArg()); |
| when(mockRunner.post(any())).thenReturn(false); |
| |
| when(mWifiInjector.getWifiThreadRunner()).thenReturn(mockRunner); |
| return makeWifiServiceImpl(); |
| } |
| |
| /** |
| * Test that REMOVE_NETWORK returns failure to public API when WifiConfigManager returns |
| * failure. |
| */ |
| @Test |
| public void testRemoveNetworkFailureAppBelowQSdk() { |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME, |
| TEST_FEATURE_ID, null); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(anyString(), |
| eq(Build.VERSION_CODES.Q), anyInt())).thenReturn(true); |
| when(mWifiConfigManager.removeNetwork(anyInt(), anyInt(), anyString())).thenReturn(false); |
| |
| mLooper.startAutoDispatch(); |
| boolean succeeded = mWifiServiceImpl.removeNetwork(0, TEST_PACKAGE_NAME); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| assertFalse(succeeded); |
| } |
| |
| /** |
| * 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).setEnhancedMacRandomizationForceEnabled(anyBoolean()); |
| verify(mWifiMetrics).setIsScanningAlwaysEnabled(anyBoolean()); |
| verify(mWifiMetrics).setVerboseLoggingEnabled(anyBoolean()); |
| 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() { |
| mLooper.startAutoDispatch(); |
| mWifiServiceImpl.dump(new FileDescriptor(), new PrintWriter(new StringWriter()), null); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| } |
| |
| /** |
| * 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() { |
| mLooper.startAutoDispatch(); |
| mWifiServiceImpl.dump(new FileDescriptor(), new PrintWriter(new StringWriter()), null); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| InOrder inOrder = inOrder(mClientModeImpl, mWifiScoreReport); |
| |
| inOrder.verify(mClientModeImpl).updateLinkLayerStatsRssiAndScoreReport(); |
| 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(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).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).logUserActionEvent(UserActionEvent.EVENT_TOGGLE_WIFI_ON); |
| inorder.verify(mWifiMetrics).incrementNumWifiToggles(eq(true), eq(true)); |
| inorder.verify(mWifiMetrics).logUserActionEvent(eq(UserActionEvent.EVENT_TOGGLE_WIFI_OFF), |
| anyInt()); |
| 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), anyInt())).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), anyInt())).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(mActiveModeWarden).wifiToggled(); |
| } |
| |
| /** |
| * 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(mActiveModeWarden).wifiToggled(); |
| } |
| |
| /** |
| * Verify that wifi can be enabled by the DO apps targeting Q SDK. |
| */ |
| @Test |
| public void testSetWifiEnabledSuccessForDOAppsTargetingQSdk() 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), anyInt())).thenReturn(false); |
| when(mWifiPermissionsUtil.isDeviceOwner(Binder.getCallingUid(), TEST_PACKAGE_NAME)) |
| .thenReturn(true); |
| |
| when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); |
| assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true)); |
| |
| verify(mActiveModeWarden).wifiToggled(); |
| } |
| |
| /** |
| * Verify that wifi can be enabled by the system apps targeting Q SDK. |
| */ |
| @Test |
| public void testSetWifiEnabledSuccessForSystemAppsTargetingQSdk() 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), anyInt())).thenReturn(false); |
| mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM; |
| |
| when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); |
| assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true)); |
| |
| verify(mActiveModeWarden).wifiToggled(); |
| } |
| |
| /** |
| * 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), anyInt())).thenReturn(true); |
| |
| when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); |
| assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true)); |
| |
| verify(mActiveModeWarden).wifiToggled(); |
| } |
| |
| /** |
| * 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), anyInt())).thenReturn(false); |
| |
| when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); |
| assertFalse(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true)); |
| |
| verify(mActiveModeWarden, never()).wifiToggled(); |
| } |
| |
| /** |
| * 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), anyInt())).thenReturn(true); |
| when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true); |
| try { |
| mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true); |
| fail(); |
| } catch (SecurityException e) { |
| |
| } |
| verify(mActiveModeWarden, never()).wifiToggled(); |
| } |
| |
| /** |
| * 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), anyInt())).thenReturn(true); |
| when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true); |
| |
| mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true); |
| verify(mActiveModeWarden, never()).wifiToggled(); |
| } |
| |
| /** |
| * 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(mActiveModeWarden).wifiToggled(); |
| } |
| |
| /** |
| * 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), anyInt())).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(mActiveModeWarden, never()).wifiToggled(); |
| } |
| |
| /** |
| * Helper to verify registering for state changes. |
| */ |
| private void verifyApRegistration() { |
| assertNotNull(mLohsApCallback); |
| } |
| |
| /** |
| * Helper to emulate local-only hotspot state changes. |
| * |
| * Must call verifyApRegistration first. |
| */ |
| private void changeLohsState(int apState, int previousState, int error) { |
| // TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext, |
| // apState, previousState, error, WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| mLohsApCallback.onStateChanged(apState, error); |
| } |
| |
| /** |
| * 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(); |
| mLooper.dispatchAll(); |
| |
| verifyApRegistration(); |
| mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); |
| |
| 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(mActiveModeWarden).wifiToggled(); |
| } |
| |
| /** |
| * 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), anyInt())).thenReturn(true); |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| |
| verifyApRegistration(); |
| mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); |
| |
| 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(mActiveModeWarden, never()).wifiToggled(); |
| } |
| |
| |
| /** |
| * 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(mActiveModeWarden, never()).wifiToggled(); |
| } |
| |
| /** |
| * 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(mActiveModeWarden).wifiToggled(); |
| } |
| |
| /** |
| * 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(mActiveModeWarden).wifiToggled(); |
| } |
| |
| /** |
| * Verify that wifi can be disabled by the PO apps targeting Q SDK. |
| */ |
| @Test |
| public void testSetWifiDisabledSuccessForPOAppsTargetingQSdk() 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), anyInt())).thenReturn(false); |
| when(mWifiPermissionsUtil.isProfileOwner(Binder.getCallingUid(), TEST_PACKAGE_NAME)) |
| .thenReturn(true); |
| |
| when(mSettingsStore.handleWifiToggled(eq(false))).thenReturn(true); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); |
| assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false)); |
| |
| verify(mActiveModeWarden).wifiToggled(); |
| } |
| |
| /** |
| * Verify that wifi can be disabled by the system apps targeting Q SDK. |
| */ |
| @Test |
| public void testSetWifiDisabledSuccessForSystemAppsTargetingQSdk() 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), anyInt())).thenReturn(false); |
| mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM; |
| |
| when(mSettingsStore.handleWifiToggled(eq(false))).thenReturn(true); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); |
| assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false)); |
| |
| verify(mActiveModeWarden).wifiToggled(); |
| } |
| |
| |
| /** |
| * 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), anyInt())).thenReturn(true); |
| |
| when(mSettingsStore.handleWifiToggled(eq(false))).thenReturn(true); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); |
| assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false)); |
| |
| verify(mActiveModeWarden).wifiToggled(); |
| } |
| |
| /** |
| * 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), anyInt())).thenReturn(false); |
| |
| when(mSettingsStore.handleWifiToggled(eq(false))).thenReturn(true); |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(false); |
| assertFalse(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false)); |
| |
| verify(mActiveModeWarden, never()).wifiToggled(); |
| } |
| |
| /** |
| * 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(mActiveModeWarden, never()).wifiToggled(); |
| } |
| |
| /** |
| * 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. |
| */ |
| @Test |
| public void testSetWifiApConfigurationNotSavedWithoutPermission() throws Exception { |
| 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() throws Exception { |
| when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true); |
| WifiConfiguration wifiApConfig = createValidWifiApConfiguration(); |
| |
| assertTrue(mWifiServiceImpl.setWifiApConfiguration(wifiApConfig, TEST_PACKAGE_NAME)); |
| mLooper.dispatchAll(); |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| verify(mWifiApConfigStore).setApConfiguration(eq( |
| ApConfigUtil.fromWifiConfiguration(wifiApConfig))); |
| } |
| |
| /** |
| * Ensure that a null config does not overwrite the saved ap config. |
| */ |
| @Test |
| public void testSetWifiApConfigurationNullConfigNotSaved() throws Exception { |
| when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true); |
| assertFalse(mWifiServiceImpl.setWifiApConfiguration(null, TEST_PACKAGE_NAME)); |
| verify(mWifiApConfigStore, never()).setApConfiguration(isNull(SoftApConfiguration.class)); |
| } |
| |
| /** |
| * Ensure that an invalid config does not overwrite the saved ap config. |
| */ |
| @Test |
| public void testSetWifiApConfigurationWithInvalidConfigNotSaved() throws Exception { |
| when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true); |
| assertFalse(mWifiServiceImpl.setWifiApConfiguration(new WifiConfiguration(), |
| TEST_PACKAGE_NAME)); |
| verify(mWifiApConfigStore, never()).setApConfiguration(any()); |
| } |
| |
| /** |
| * Ensure unpermitted callers cannot write the SoftApConfiguration. |
| */ |
| @Test |
| public void testSetSoftApConfigurationNotSavedWithoutPermission() throws Exception { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| SoftApConfiguration apConfig = createValidSoftApConfiguration(); |
| try { |
| mWifiServiceImpl.setSoftApConfiguration(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 testSetSoftApConfigurationSuccess() throws Exception { |
| doNothing().when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| SoftApConfiguration apConfig = createValidSoftApConfiguration(); |
| |
| assertTrue(mWifiServiceImpl.setSoftApConfiguration(apConfig, TEST_PACKAGE_NAME)); |
| mLooper.dispatchAll(); |
| verify(mWifiApConfigStore).setApConfiguration(eq(apConfig)); |
| verify(mActiveModeWarden).updateSoftApConfiguration(apConfig); |
| verify(mContext).enforceCallingOrSelfPermission( |
| eq(android.Manifest.permission.NETWORK_SETTINGS), eq("WifiService")); |
| } |
| |
| /** |
| * Ensure that a null config does not overwrite the saved ap config. |
| */ |
| @Test |
| public void testSetSoftApConfigurationNullConfigNotSaved() throws Exception { |
| doNothing().when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| assertFalse(mWifiServiceImpl.setSoftApConfiguration(null, TEST_PACKAGE_NAME)); |
| verify(mWifiApConfigStore, never()).setApConfiguration(isNull(SoftApConfiguration.class)); |
| verify(mActiveModeWarden, never()).updateSoftApConfiguration(any()); |
| verify(mContext).enforceCallingOrSelfPermission( |
| eq(android.Manifest.permission.NETWORK_SETTINGS), eq("WifiService")); |
| } |
| |
| /** |
| * Ensure that an invalid config does not overwrite the saved ap config. |
| */ |
| @Test |
| public void testSetSoftApConfigurationWithInvalidConfigNotSaved() throws Exception { |
| doNothing().when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| assertFalse(mWifiServiceImpl.setSoftApConfiguration( |
| new SoftApConfiguration.Builder().build(), TEST_PACKAGE_NAME)); |
| verify(mWifiApConfigStore, never()).setApConfiguration(any()); |
| verify(mContext).enforceCallingOrSelfPermission( |
| eq(android.Manifest.permission.NETWORK_SETTINGS), eq("WifiService")); |
| } |
| |
| /** |
| * Ensure unpermitted callers are not able to retrieve the softap config. |
| */ |
| @Test |
| public void testGetSoftApConfigurationNotReturnedWithoutPermission() throws Exception { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| try { |
| mWifiServiceImpl.getSoftApConfiguration(); |
| fail("Expected a SecurityException"); |
| } catch (SecurityException e) { |
| } |
| } |
| |
| /** |
| * Ensure permitted callers are able to retrieve the softap config. |
| */ |
| @Test |
| public void testGetSoftApConfigurationSuccess() throws Exception { |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| doNothing().when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| SoftApConfiguration apConfig = createValidSoftApConfiguration(); |
| when(mWifiApConfigStore.getApConfiguration()).thenReturn(apConfig); |
| |
| mLooper.startAutoDispatch(); |
| assertThat(apConfig).isEqualTo(mWifiServiceImpl.getSoftApConfiguration()); |
| |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| } |
| |
| /** |
| * Ensure unpermitted callers are not able to retrieve the softap config. |
| */ |
| @Test |
| public void testGetWifiApConfigurationNotReturnedWithoutPermission() throws Exception { |
| 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() throws Exception { |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true); |
| SoftApConfiguration apConfig = new SoftApConfiguration.Builder().build(); |
| when(mWifiApConfigStore.getApConfiguration()).thenReturn(apConfig); |
| |
| mLooper.startAutoDispatch(); |
| WifiConfigurationTestUtil.assertConfigurationEqualForSoftAp( |
| apConfig.toWifiConfiguration(), |
| mWifiServiceImpl.getWifiApConfiguration()); |
| |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| } |
| |
| /** |
| * Ensure we return the proper variable for the softap state after getting an AP state change |
| * broadcast. |
| */ |
| @Test |
| public void testGetWifiApEnabled() throws Exception { |
| // ap should be disabled when wifi hasn't been started |
| assertEquals(WifiManager.WIFI_AP_STATE_DISABLED, mWifiServiceImpl.getWifiApEnabledState()); |
| |
| 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 |
| verifyApRegistration(); |
| mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); |
| mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL); |
| 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(ACCESS_WIFI_STATE), |
| eq("WifiService")); |
| |
| try { |
| mWifiServiceImpl.getWifiApEnabledState(); |
| fail("expected SecurityException"); |
| } catch (SecurityException expected) { } |
| } |
| |
| /** |
| * Make sure we do start WifiController (wifi disabled) if the device is already decrypted. |
| */ |
| @Test |
| public void testWifiControllerStartsWhenDeviceBootsWithWifiDisabled() { |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| verify(mWifiConfigManager).loadFromStore(); |
| verify(mActiveModeWarden).start(); |
| verify(mActiveModeWarden, never()).wifiToggled(); |
| } |
| |
| @Test |
| public void testWifiVerboseLoggingInitialization() { |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| when(mWifiSettingsConfigStore.get(eq(WIFI_VERBOSE_LOGGING_ENABLED))).thenReturn(true); |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| verify(mWifiConfigManager).loadFromStore(); |
| verify(mClientModeImpl).enableVerboseLogging(1); |
| verify(mActiveModeWarden).start(); |
| } |
| |
| /** |
| * Make sure we do start WifiController (wifi enabled) if the device is already decrypted. |
| */ |
| @Test |
| public void testWifiFullyStartsWhenDeviceBootsWithWifiEnabled() { |
| 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(); |
| mLooper.dispatchAll(); |
| verify(mWifiConfigManager).loadFromStore(); |
| verify(mActiveModeWarden).start(); |
| } |
| |
| /** |
| * Verify caller with proper permission can call startSoftAp. |
| */ |
| @Test |
| public void testStartSoftApWithPermissionsAndNullConfig() { |
| boolean result = mWifiServiceImpl.startSoftAp(null); |
| assertTrue(result); |
| verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture()); |
| assertNull(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); |
| } |
| |
| /** |
| * Verify caller with proper permissions but an invalid config does not start softap. |
| */ |
| @Test |
| public void testStartSoftApWithPermissionsAndInvalidConfig() { |
| boolean result = mWifiServiceImpl.startSoftAp(mApConfig); |
| assertFalse(result); |
| verify(mActiveModeWarden, never()).startSoftAp(any()); |
| } |
| |
| /** |
| * Verify caller with proper permission and valid config does start softap. |
| */ |
| @Test |
| public void testStartSoftApWithPermissionsAndValidConfig() { |
| WifiConfiguration config = createValidWifiApConfiguration(); |
| boolean result = mWifiServiceImpl.startSoftAp(config); |
| assertTrue(result); |
| verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture()); |
| WifiConfigurationTestUtil.assertConfigurationEqualForSoftAp( |
| config, |
| mSoftApModeConfigCaptor.getValue().getSoftApConfiguration().toWifiConfiguration()); |
| } |
| |
| /** |
| * 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 { |
| when(mContext.checkCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK)) |
| .thenReturn(PackageManager.PERMISSION_DENIED); |
| doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission( |
| eq(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK), any()); |
| mWifiServiceImpl.startSoftAp(null); |
| } |
| |
| /** |
| * Verify that startSoftAP() succeeds if the caller does not have the NETWORK_STACK permission |
| * but does have the MAINLINE_NETWORK_STACK permission. |
| */ |
| @Test |
| public void testStartSoftApWithoutNetworkStackWithMainlineNetworkStackSucceeds() { |
| when(mContext.checkCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK)) |
| .thenReturn(PackageManager.PERMISSION_DENIED); |
| WifiConfiguration config = createValidWifiApConfiguration(); |
| boolean result = mWifiServiceImpl.startSoftAp(config); |
| assertTrue(result); |
| verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture()); |
| WifiConfigurationTestUtil.assertConfigurationEqualForSoftAp( |
| config, |
| mSoftApModeConfigCaptor.getValue().getSoftApConfiguration().toWifiConfiguration()); |
| verify(mContext).enforceCallingOrSelfPermission( |
| eq(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK), any()); |
| } |
| |
| /** |
| * Verify that startSoftAp() with valid config succeeds after a failed call |
| */ |
| @Test |
| public void testStartSoftApWithValidConfigSucceedsAfterFailure() { |
| // First initiate a failed call |
| assertFalse(mWifiServiceImpl.startSoftAp(mApConfig)); |
| verify(mActiveModeWarden, never()).startSoftAp(any()); |
| |
| // Next attempt a valid config |
| WifiConfiguration config = createValidWifiApConfiguration(); |
| assertTrue(mWifiServiceImpl.startSoftAp(config)); |
| verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture()); |
| WifiConfigurationTestUtil.assertConfigurationEqualForSoftAp( |
| config, |
| mSoftApModeConfigCaptor.getValue().getSoftApConfiguration().toWifiConfiguration()); |
| } |
| |
| /** |
| * Verify caller with proper permission can call startTetheredHotspot. |
| */ |
| @Test |
| public void testStartTetheredHotspotWithPermissionsAndNullConfig() { |
| boolean result = mWifiServiceImpl.startTetheredHotspot(null); |
| assertTrue(result); |
| verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture()); |
| assertNull(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); |
| } |
| |
| /** |
| * Verify caller with proper permissions but an invalid config does not start softap. |
| */ |
| @Test |
| public void testStartTetheredHotspotWithPermissionsAndInvalidConfig() { |
| boolean result = mWifiServiceImpl.startTetheredHotspot( |
| new SoftApConfiguration.Builder().build()); |
| assertFalse(result); |
| verify(mActiveModeWarden, never()).startSoftAp(any()); |
| } |
| |
| /** |
| * Verify caller with proper permission and valid config does start softap. |
| */ |
| @Test |
| public void testStartTetheredHotspotWithPermissionsAndValidConfig() { |
| SoftApConfiguration config = createValidSoftApConfiguration(); |
| boolean result = mWifiServiceImpl.startTetheredHotspot(config); |
| assertTrue(result); |
| verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture()); |
| assertThat(config).isEqualTo(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); |
| } |
| |
| /** |
| * Verify attempt to start softAp with a supported 5GHz band succeeds. |
| */ |
| @Test |
| public void testStartTetheredHotspotWithSupported5gBand() { |
| when(mClientModeImpl.isWifiBandSupported(WifiScanner.WIFI_BAND_5_GHZ)).thenReturn(true); |
| |
| SoftApConfiguration config = new SoftApConfiguration.Builder() |
| .setSsid("TestAp") |
| .setPassphrase("thisIsABadPassword", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) |
| .setBand(SoftApConfiguration.BAND_5GHZ) |
| .build(); |
| |
| mLooper.startAutoDispatch(); |
| boolean result = mWifiServiceImpl.startTetheredHotspot(config); |
| |
| assertTrue(result); |
| verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture()); |
| assertThat(config).isEqualTo(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); |
| } |
| |
| /** |
| * Verify attempt to start softAp with a non-supported 5GHz band fails. |
| */ |
| @Test |
| public void testStartTetheredHotspotWithUnSupported5gBand() { |
| when(mClientModeImpl.isWifiBandSupported(WifiScanner.WIFI_BAND_5_GHZ)).thenReturn(false); |
| |
| SoftApConfiguration config = new SoftApConfiguration.Builder() |
| .setSsid("TestAp") |
| .setPassphrase("thisIsABadPassword", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) |
| .setBand(SoftApConfiguration.BAND_5GHZ) |
| .build(); |
| |
| mLooper.startAutoDispatch(); |
| boolean result = mWifiServiceImpl.startTetheredHotspot(config); |
| |
| assertFalse(result); |
| verify(mActiveModeWarden, never()).startSoftAp(any()); |
| } |
| |
| /** |
| * Verify attempt to start softAp with a supported 6GHz band succeeds. |
| */ |
| @Test |
| public void testStartTetheredHotspotWithSupported6gBand() { |
| when(mResources.getBoolean( |
| eq(R.bool.config_wifiSoftap6ghzSupported))) |
| .thenReturn(true); |
| when(mClientModeImpl.isWifiBandSupported(WifiScanner.WIFI_BAND_6_GHZ)).thenReturn(true); |
| |
| SoftApConfiguration config = new SoftApConfiguration.Builder() |
| .setSsid("TestAp") |
| .setPassphrase("thisIsABadPassword", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) |
| .setBand(SoftApConfiguration.BAND_6GHZ) |
| .build(); |
| |
| mLooper.startAutoDispatch(); |
| boolean result = mWifiServiceImpl.startTetheredHotspot(config); |
| |
| assertTrue(result); |
| verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture()); |
| assertThat(config).isEqualTo(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); |
| } |
| |
| /** |
| * Verify attempt to start softAp with a non-supported 6GHz band fails. |
| */ |
| @Test |
| public void testStartTetheredHotspotWithUnSupported6gBand() { |
| when(mResources.getBoolean( |
| eq(R.bool.config_wifiSoftap6ghzSupported))) |
| .thenReturn(false); |
| when(mClientModeImpl.isWifiBandSupported(WifiScanner.WIFI_BAND_6_GHZ)).thenReturn(true); |
| |
| SoftApConfiguration config = new SoftApConfiguration.Builder() |
| .setSsid("TestAp") |
| .setPassphrase("thisIsABadPassword", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) |
| .setBand(SoftApConfiguration.BAND_6GHZ) |
| .build(); |
| |
| mLooper.startAutoDispatch(); |
| boolean result = mWifiServiceImpl.startTetheredHotspot(config); |
| |
| assertFalse(result); |
| verify(mActiveModeWarden, never()).startSoftAp(any()); |
| } |
| |
| /** |
| * Verify attempt to start softAp with a supported band succeeds. |
| */ |
| @Test |
| public void testStartTetheredHotspotWithSupportedBand() { |
| when(mClientModeImpl.isWifiBandSupported(WifiScanner.WIFI_BAND_5_GHZ)).thenReturn(true); |
| |
| SoftApConfiguration config = new SoftApConfiguration.Builder() |
| .setSsid("TestAp") |
| .setPassphrase("thisIsABadPassword", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) |
| .setBand(SoftApConfiguration.BAND_5GHZ) |
| .build(); |
| |
| mLooper.startAutoDispatch(); |
| boolean result = mWifiServiceImpl.startTetheredHotspot(config); |
| |
| assertTrue(result); |
| verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture()); |
| assertThat(config).isEqualTo(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); |
| } |
| |
| /** |
| * Verify a SecurityException is thrown when a caller without the correct permission attempts to |
| * start softap. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testStartTetheredHotspotWithoutPermissionThrowsException() throws Exception { |
| when(mContext.checkCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK)) |
| .thenReturn(PackageManager.PERMISSION_DENIED); |
| doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission( |
| eq(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK), any()); |
| mWifiServiceImpl.startTetheredHotspot(null); |
| } |
| |
| /** |
| * Verify that startTetheredHotspot() succeeds if the caller does not have the |
| * NETWORK_STACK permission but does have the MAINLINE_NETWORK_STACK permission. |
| */ |
| @Test |
| public void testStartTetheredHotspotWithoutNetworkStackWithMainlineNetworkStackSucceeds() { |
| when(mContext.checkCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK)) |
| .thenReturn(PackageManager.PERMISSION_DENIED); |
| SoftApConfiguration config = createValidSoftApConfiguration(); |
| boolean result = mWifiServiceImpl.startTetheredHotspot(config); |
| assertTrue(result); |
| verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture()); |
| assertThat(config).isEqualTo(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); |
| verify(mContext).enforceCallingOrSelfPermission( |
| eq(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK), any()); |
| } |
| |
| /** |
| * Verify a valied call to startTetheredHotspot succeeds after a failed call. |
| */ |
| @Test |
| public void testStartTetheredHotspotWithValidConfigSucceedsAfterFailedCall() { |
| // First issue an invalid call |
| assertFalse(mWifiServiceImpl.startTetheredHotspot( |
| new SoftApConfiguration.Builder().build())); |
| verify(mActiveModeWarden, never()).startSoftAp(any()); |
| |
| // Now attempt a successful call |
| assertTrue(mWifiServiceImpl.startTetheredHotspot(null)); |
| verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture()); |
| assertNull(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); |
| } |
| |
| /** |
| * Verify caller with proper permission can call stopSoftAp. |
| */ |
| @Test |
| public void testStopSoftApWithPermissions() { |
| boolean result = mWifiServiceImpl.stopSoftAp(); |
| assertTrue(result); |
| verify(mActiveModeWarden).stopSoftAp(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 { |
| when(mContext.checkCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK)) |
| .thenReturn(PackageManager.PERMISSION_DENIED); |
| doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission( |
| eq(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK), any()); |
| mWifiServiceImpl.stopSoftAp(); |
| } |
| |
| /** |
| * Ensure that we handle app ops check failure when handling scan request. |
| */ |
| @Test |
| public void testStartScanFailureAppOpsIgnored() { |
| doReturn(AppOpsManager.MODE_IGNORED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), SCAN_PACKAGE_NAME); |
| mLooper.startAutoDispatch(); |
| assertFalse(mWifiServiceImpl.startScan(SCAN_PACKAGE_NAME, TEST_FEATURE_ID)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| 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() { |
| doThrow(new SecurityException()).when(mWifiPermissionsUtil) |
| .enforceCanAccessScanResults(SCAN_PACKAGE_NAME, TEST_FEATURE_ID, Process.myUid(), |
| null); |
| mLooper.startAutoDispatch(); |
| assertFalse(mWifiServiceImpl.startScan(SCAN_PACKAGE_NAME, TEST_FEATURE_ID)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| 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() { |
| mWifiServiceImpl = makeWifiServiceImplWithMockRunnerWhichTimesOut(); |
| |
| mLooper.startAutoDispatch(); |
| assertFalse(mWifiServiceImpl.startScan(SCAN_PACKAGE_NAME, TEST_FEATURE_ID)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| verify(mScanRequestProxy, never()).startScan(anyInt(), eq(SCAN_PACKAGE_NAME)); |
| } |
| |
| /** |
| * Ensure that we handle scan request failure from ScanRequestProxy fails. |
| */ |
| @Test |
| public void testStartScanFailureFromScanRequestProxy() { |
| when(mScanRequestProxy.startScan(anyInt(), anyString())).thenReturn(false); |
| |
| mLooper.startAutoDispatch(); |
| assertFalse(mWifiServiceImpl.startScan(SCAN_PACKAGE_NAME, TEST_FEATURE_ID)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| verify(mScanRequestProxy).startScan(Binder.getCallingUid(), SCAN_PACKAGE_NAME); |
| } |
| |
| private void setupForGetConnectionInfo() { |
| WifiInfo wifiInfo = new WifiInfo(); |
| wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(TEST_SSID)); |
| wifiInfo.setBSSID(TEST_BSSID); |
| wifiInfo.setNetworkId(TEST_NETWORK_ID); |
| wifiInfo.setFQDN(TEST_FQDN); |
| wifiInfo.setProviderFriendlyName(TEST_FRIENDLY_NAME); |
| 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(), nullable(String.class), anyInt(), nullable(String.class)); |
| |
| WifiInfo connectionInfo = mWifiServiceImpl.getConnectionInfo(TEST_PACKAGE, TEST_FEATURE_ID); |
| |
| assertEquals(WifiManager.UNKNOWN_SSID, connectionInfo.getSSID()); |
| assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getBSSID()); |
| assertEquals(WifiConfiguration.INVALID_NETWORK_ID, connectionInfo.getNetworkId()); |
| assertNull(connectionInfo.getPasspointFqdn()); |
| assertNull(connectionInfo.getPasspointProviderFriendlyName()); |
| } |
| |
| /** |
| * 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(), nullable(String.class), anyInt(), nullable(String.class)); |
| |
| WifiInfo connectionInfo = mWifiServiceImpl.getConnectionInfo(TEST_PACKAGE, TEST_FEATURE_ID); |
| |
| assertEquals(WifiManager.UNKNOWN_SSID, connectionInfo.getSSID()); |
| assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getBSSID()); |
| assertEquals(WifiConfiguration.INVALID_NETWORK_ID, connectionInfo.getNetworkId()); |
| assertNull(connectionInfo.getPasspointFqdn()); |
| assertNull(connectionInfo.getPasspointProviderFriendlyName()); |
| } |
| |
| /** |
| * 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, TEST_FEATURE_ID); |
| |
| assertEquals(TEST_SSID_WITH_QUOTES, connectionInfo.getSSID()); |
| assertEquals(TEST_BSSID, connectionInfo.getBSSID()); |
| assertEquals(TEST_NETWORK_ID, connectionInfo.getNetworkId()); |
| assertEquals(TEST_FQDN, connectionInfo.getPasspointFqdn()); |
| assertEquals(TEST_FRIENDLY_NAME, connectionInfo.getPasspointProviderFriendlyName()); |
| } |
| |
| /** |
| * 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(mWifiConfigManager.getSavedNetworks(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, TEST_FEATURE_ID); |
| |
| 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(mWifiConfigManager.getSavedNetworks(anyInt())) |
| .thenReturn(TEST_WIFI_CONFIGURATION_LIST); |
| |
| doThrow(new SecurityException()).when(mWifiPermissionsUtil).enforceCanAccessScanResults( |
| anyString(), nullable(String.class), anyInt(), nullable(String.class)); |
| |
| ParceledListSlice<WifiConfiguration> configs = |
| mWifiServiceImpl.getConfiguredNetworks(TEST_PACKAGE, TEST_FEATURE_ID); |
| |
| 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(mWifiConfigManager.getSavedNetworks(anyInt())) |
| .thenReturn(TEST_WIFI_CONFIGURATION_LIST); |
| |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| |
| mWifiServiceImpl.mClientModeImplChannel = mAsyncChannel; |
| |
| mLooper.startAutoDispatch(); |
| ParceledListSlice<WifiConfiguration> configs = |
| mWifiServiceImpl.getConfiguredNetworks(TEST_PACKAGE, TEST_FEATURE_ID); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| verify(mWifiConfigManager).getSavedNetworks(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() { |
| when(mWifiConfigManager.getConfiguredNetworksWithPasswords()) |
| .thenReturn(TEST_WIFI_CONFIGURATION_LIST); |
| |
| doThrow(new SecurityException()).when(mWifiPermissionsUtil).enforceCanAccessScanResults( |
| anyString(), nullable(String.class), anyInt(), nullable(String.class)); |
| |
| mLooper.startAutoDispatch(); |
| ParceledListSlice<WifiConfiguration> configs = |
| mWifiServiceImpl.getPrivilegedConfiguredNetworks(TEST_PACKAGE, TEST_FEATURE_ID); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| assertNull(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() { |
| when(mWifiConfigManager.getConfiguredNetworksWithPasswords()) |
| .thenReturn(TEST_WIFI_CONFIGURATION_LIST); |
| |
| doThrow(new SecurityException()).when(mWifiPermissionsUtil).enforceCanAccessScanResults( |
| anyString(), nullable(String.class), anyInt(), nullable(String.class)); |
| |
| mLooper.startAutoDispatch(); |
| ParceledListSlice<WifiConfiguration> configs = |
| mWifiServiceImpl.getPrivilegedConfiguredNetworks(TEST_PACKAGE, TEST_FEATURE_ID); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| assertNull(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() { |
| when(mWifiConfigManager.getConfiguredNetworksWithPasswords()) |
| .thenReturn(TEST_WIFI_CONFIGURATION_LIST); |
| |
| mLooper.startAutoDispatch(); |
| ParceledListSlice<WifiConfiguration> configs = |
| mWifiServiceImpl.getPrivilegedConfiguredNetworks(TEST_PACKAGE, TEST_FEATURE_ID); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| WifiConfigurationTestUtil.assertConfigurationsEqualForBackup( |
| TEST_WIFI_CONFIGURATION_LIST, configs.getList()); |
| } |
| |
| /** |
| * Test fetching of scan results. |
| */ |
| @Test |
| public void testGetScanResults() { |
| 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"; |
| String featureId = "test.com.featureId"; |
| mLooper.startAutoDispatch(); |
| List<ScanResult> retrievedScanResultList = mWifiServiceImpl.getScanResults(packageName, |
| featureId); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| 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() { |
| mWifiServiceImpl = makeWifiServiceImplWithMockRunnerWhichTimesOut(); |
| |
| 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"; |
| String featureId = "test.com.featureId"; |
| mLooper.startAutoDispatch(); |
| List<ScanResult> retrievedScanResultList = mWifiServiceImpl.getScanResults(packageName, |
| featureId); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| verify(mScanRequestProxy, never()).getScanResults(); |
| |
| assertTrue(retrievedScanResultList.isEmpty()); |
| } |
| |
| /** |
| * Test fetching of matching scan results with provided WifiNetworkSuggestion, but it doesn't |
| * specify the scan results to be filtered. |
| */ |
| @Test |
| public void testGetMatchingScanResultsWithoutSpecifiedScanResults() { |
| 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); |
| WifiNetworkSuggestion mockSuggestion = mock(WifiNetworkSuggestion.class); |
| List<WifiNetworkSuggestion> matchingSuggestions = new ArrayList<>() {{ |
| add(mockSuggestion); |
| }}; |
| Map<WifiNetworkSuggestion, List<ScanResult>> result = new HashMap<>() {{ |
| put(mockSuggestion, scanResultList); |
| }}; |
| when(mWifiNetworkSuggestionsManager.getMatchingScanResults(eq(matchingSuggestions), |
| eq(scanResultList))).thenReturn(result); |
| |
| String packageName = "test.com"; |
| String featureId = "test.com.featureId"; |
| mLooper.startAutoDispatch(); |
| Map<WifiNetworkSuggestion, List<ScanResult>> retrievedScanResults = |
| mWifiServiceImpl.getMatchingScanResults( |
| matchingSuggestions, null, packageName, featureId); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| ScanTestUtil.assertScanResultsEquals(scanResults, |
| retrievedScanResults.get(mockSuggestion) |
| .toArray(new ScanResult[retrievedScanResults.size()])); |
| } |
| |
| /** |
| * Test fetching of matching scan results with provided WifiNetworkSuggestion and ScanResults. |
| */ |
| @Test |
| public void testGetMatchingScanResultsWithSpecifiedScanResults() { |
| ScanResult[] scanResults = |
| ScanTestUtil.createScanDatas(new int[][]{{2417, 2427, 5180, 5170}})[0] |
| .getResults(); |
| List<ScanResult> scanResultList = |
| new ArrayList<>(Arrays.asList(scanResults)); |
| WifiNetworkSuggestion mockSuggestion = mock(WifiNetworkSuggestion.class); |
| List<WifiNetworkSuggestion> matchingSuggestions = new ArrayList<>() {{ |
| add(mockSuggestion); |
| }}; |
| Map<WifiNetworkSuggestion, List<ScanResult>> result = new HashMap<>() {{ |
| put(mockSuggestion, scanResultList); |
| }}; |
| when(mWifiNetworkSuggestionsManager.getMatchingScanResults(eq(matchingSuggestions), |
| eq(scanResultList))).thenReturn(result); |
| |
| String packageName = "test.com"; |
| String featureId = "test.com.featureId"; |
| mLooper.startAutoDispatch(); |
| Map<WifiNetworkSuggestion, List<ScanResult>> retrievedScanResults = |
| mWifiServiceImpl.getMatchingScanResults( |
| matchingSuggestions, scanResultList, packageName, featureId); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| ScanTestUtil.assertScanResultsEquals(scanResults, |
| retrievedScanResults.get(mockSuggestion) |
| .toArray(new ScanResult[retrievedScanResults.size()])); |
| } |
| |
| /** |
| * Ensure that we handle failure when posting the runnable to handler fails. |
| */ |
| @Test |
| public void testGetMatchingScanResultsFailureInRunWithScissors() { |
| mWifiServiceImpl = makeWifiServiceImplWithMockRunnerWhichTimesOut(); |
| |
| 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); |
| WifiNetworkSuggestion mockSuggestion = mock(WifiNetworkSuggestion.class); |
| List<WifiNetworkSuggestion> matchingSuggestions = new ArrayList<>() {{ |
| add(mockSuggestion); |
| }}; |
| Map<WifiNetworkSuggestion, List<ScanResult>> result = new HashMap<>() {{ |
| put(mockSuggestion, scanResultList); |
| }}; |
| when(mWifiNetworkSuggestionsManager.getMatchingScanResults(eq(matchingSuggestions), |
| eq(scanResultList))).thenReturn(result); |
| |
| String packageName = "test.com"; |
| String featureId = "test.com.featureId"; |
| mLooper.startAutoDispatch(); |
| Map<WifiNetworkSuggestion, List<ScanResult>> retrievedScanResults = |
| mWifiServiceImpl.getMatchingScanResults( |
| matchingSuggestions, null, packageName, featureId); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| assertTrue(retrievedScanResults.isEmpty()); |
| } |
| |
| private void setupLohsPermissions() { |
| when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true); |
| when(mFrameworkFacade.isAppForeground(any(), anyInt())).thenReturn(true); |
| when(mUserManager.hasUserRestrictionForUser( |
| eq(UserManager.DISALLOW_CONFIG_TETHERING), any())) |
| .thenReturn(false); |
| } |
| |
| private void registerLOHSRequestFull() { |
| setupLohsPermissions(); |
| int result = mWifiServiceImpl.startLocalOnlyHotspot(mLohsCallback, TEST_PACKAGE_NAME, |
| TEST_FEATURE_ID, null); |
| 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( |
| mLohsCallback, TEST_PACKAGE_NAME, TEST_FEATURE_ID, null); |
| } |
| |
| /** |
| * 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), |
| eq(TEST_FEATURE_ID), |
| anyInt()); |
| mWifiServiceImpl.startLocalOnlyHotspot( |
| mLohsCallback, TEST_PACKAGE_NAME, TEST_FEATURE_ID, null); |
| } |
| |
| /** |
| * 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( |
| mLohsCallback, TEST_PACKAGE_NAME, TEST_FEATURE_ID, null); |
| } |
| |
| /** |
| * 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(any(), anyInt())).thenReturn(false); |
| int result = mWifiServiceImpl.startLocalOnlyHotspot( |
| mLohsCallback, TEST_PACKAGE_NAME, TEST_FEATURE_ID, null); |
| assertEquals(LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE, result); |
| } |
| |
| /** |
| * Only start tethering if we are not tethering. |
| */ |
| @Test |
| public void testTetheringDoesNotStartWhenAlreadyTetheringActive() throws Exception { |
| WifiConfiguration config = createValidWifiApConfiguration(); |
| assertTrue(mWifiServiceImpl.startSoftAp(config)); |
| verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture()); |
| WifiConfigurationTestUtil.assertConfigurationEqualForSoftAp( |
| config, |
| mSoftApModeConfigCaptor.getValue().getSoftApConfiguration().toWifiConfiguration()); |
| mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_TETHERED); |
| mLooper.dispatchAll(); |
| assertEquals(WIFI_AP_STATE_ENABLED, mWifiServiceImpl.getWifiApEnabledState()); |
| reset(mActiveModeWarden); |
| |
| // Start another session without a stop, that should fail. |
| assertFalse(mWifiServiceImpl.startSoftAp(createValidWifiApConfiguration())); |
| |
| verifyNoMoreInteractions(mActiveModeWarden); |
| } |
| |
| /** |
| * Only start tethering if we are not tethering in new API: startTetheredHotspot. |
| */ |
| @Test |
| public void testStartTetheredHotspotDoesNotStartWhenAlreadyTetheringActive() throws Exception { |
| SoftApConfiguration config = createValidSoftApConfiguration(); |
| assertTrue(mWifiServiceImpl.startTetheredHotspot(config)); |
| verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture()); |
| assertThat(config).isEqualTo(mSoftApModeConfigCaptor.getValue().getSoftApConfiguration()); |
| mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_TETHERED); |
| mLooper.dispatchAll(); |
| assertEquals(WIFI_AP_STATE_ENABLED, mWifiServiceImpl.getWifiApEnabledState()); |
| reset(mActiveModeWarden); |
| |
| // Start another session without a stop, that should fail. |
| assertFalse(mWifiServiceImpl.startTetheredHotspot(config)); |
| |
| verifyNoMoreInteractions(mActiveModeWarden); |
| } |
| |
| /** |
| * Only start LocalOnlyHotspot if we are not tethering. |
| */ |
| @Test |
| public void testHotspotDoesNotStartWhenAlreadyTethering() throws Exception { |
| WifiConfiguration config = createValidWifiApConfiguration(); |
| assertTrue(mWifiServiceImpl.startSoftAp(config)); |
| mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_TETHERED); |
| |
| when(mWifiPermissionsUtil.isLocationModeEnabled()).thenReturn(true); |
| when(mFrameworkFacade.isAppForeground(any(), anyInt())).thenReturn(true); |
| mLooper.dispatchAll(); |
| int returnCode = mWifiServiceImpl.startLocalOnlyHotspot( |
| mLohsCallback, TEST_PACKAGE_NAME, TEST_FEATURE_ID, null); |
| 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(any(), anyInt())).thenReturn(true); |
| when(mUserManager.hasUserRestrictionForUser( |
| eq(UserManager.DISALLOW_CONFIG_TETHERING), any())) |
| .thenReturn(true); |
| int returnCode = mWifiServiceImpl.startLocalOnlyHotspot( |
| mLohsCallback, TEST_PACKAGE_NAME, TEST_FEATURE_ID, null); |
| 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( |
| mLohsCallback, TEST_PACKAGE_NAME, TEST_FEATURE_ID, null); |
| } |
| |
| /** |
| * Verify that the call to stopLocalOnlyHotspot does not do anything when there aren't any |
| * registered callers. |
| */ |
| @Test |
| public void testStopLocalOnlyHotspotDoesNothingWithoutRegisteredRequests() throws Exception { |
| // allow test to proceed without a permission check failure |
| mWifiServiceImpl.stopLocalOnlyHotspot(); |
| mLooper.dispatchAll(); |
| // there is nothing registered, so this shouldn't do anything |
| verify(mActiveModeWarden, never()).stopSoftAp(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 testStopLocalOnlyHotspotDoesNothingWithRemainingRequest() throws Exception { |
| // register a request that will remain after the stopLOHS call |
| mWifiServiceImpl.registerLOHSForTest(mPid, mRequestInfo); |
| |
| setupLocalOnlyHotspot(); |
| |
| // Since we are calling with the same pid, the second register call will be removed |
| mWifiServiceImpl.stopLocalOnlyHotspot(); |
| mLooper.dispatchAll(); |
| // there is still a valid registered request - do not tear down LOHS |
| verify(mActiveModeWarden, never()).stopSoftAp(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 testStopLocalOnlyHotspotTriggersStopWithOneRegisteredRequest() throws Exception { |
| setupLocalOnlyHotspot(); |
| |
| verify(mActiveModeWarden).startSoftAp(any()); |
| |
| mWifiServiceImpl.stopLocalOnlyHotspot(); |
| mLooper.dispatchAll(); |
| |
| // No permission check required for change_wifi_state. |
| verify(mContext, never()).enforceCallingOrSelfPermission( |
| eq("android.Manifest.permission.CHANGE_WIFI_STATE"), anyString()); |
| |
| // there is was only one request registered, we should tear down LOHS |
| verify(mActiveModeWarden).stopSoftAp(WifiManager.IFACE_IP_MODE_LOCAL_ONLY); |
| } |
| |
| /** |
| * Verify that by default startLocalOnlyHotspot starts access point at 2 GHz. |
| */ |
| @Test |
| public void testStartLocalOnlyHotspotAt2Ghz() { |
| registerLOHSRequestFull(); |
| verifyLohsBand(SoftApConfiguration.BAND_2GHZ); |
| } |
| |
| /** |
| * Verify that startLocalOnlyHotspot will start access point at 6 GHz if properly configured |
| * and if feasible, even if the 5GHz is enabled. |
| */ |
| @Test |
| public void testStartLocalOnlyHotspotAt6Ghz() { |
| when(mResources.getBoolean( |
| eq(R.bool.config_wifi_local_only_hotspot_5ghz))) |
| .thenReturn(true); |
| when(mResources.getBoolean( |
| eq(R.bool.config_wifiLocalOnlyHotspot6ghz))) |
| .thenReturn(true); |
| when(mClientModeImpl.isWifiBandSupported(WifiScanner.WIFI_BAND_5_GHZ)).thenReturn(true); |
| when(mClientModeImpl.isWifiBandSupported(WifiScanner.WIFI_BAND_6_GHZ)).thenReturn(true); |
| when(mResources.getBoolean( |
| eq(R.bool.config_wifiSoftap6ghzSupported))) |
| .thenReturn(true); |
| when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)).thenReturn(true); |
| |
| 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)); |
| |
| mLooper.startAutoDispatch(); |
| registerLOHSRequestFull(); |
| verifyLohsBand(SoftApConfiguration.BAND_6GHZ); |
| } |
| |
| /** |
| * Verify that startLocalOnlyHotspot will start access point at 5 GHz if both 5GHz and 6GHz |
| * are enabled, but SoftAp is not supported for 6GHz. |
| */ |
| @Test |
| public void testStartLocalOnlyHotspotAt5Ghz() { |
| when(mResources.getBoolean( |
| eq(R.bool.config_wifi_local_only_hotspot_5ghz))) |
| .thenReturn(true); |
| when(mResources.getBoolean( |
| eq(R.bool.config_wifiLocalOnlyHotspot6ghz))) |
| .thenReturn(true); |
| when(mClientModeImpl.isWifiBandSupported(WifiScanner.WIFI_BAND_5_GHZ)).thenReturn(true); |
| when(mClientModeImpl.isWifiBandSupported(WifiScanner.WIFI_BAND_6_GHZ)).thenReturn(true); |
| when(mResources.getBoolean( |
| eq(R.bool.config_wifiSoftap6ghzSupported))) |
| .thenReturn(false); |
| when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)).thenReturn(true); |
| |
| 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)); |
| |
| mLooper.startAutoDispatch(); |
| registerLOHSRequestFull(); |
| verifyLohsBand(SoftApConfiguration.BAND_5GHZ); |
| } |
| |
| private void verifyLohsBand(int expectedBand) { |
| verify(mActiveModeWarden).startSoftAp(mSoftApModeConfigCaptor.capture()); |
| final SoftApConfiguration configuration = |
| mSoftApModeConfigCaptor.getValue().getSoftApConfiguration(); |
| assertNotNull(configuration); |
| assertEquals(expectedBand, configuration.getBand()); |
| } |
| |
| private static class FakeLohsCallback extends ILocalOnlyHotspotCallback.Stub { |
| boolean mIsStarted = false; |
| SoftApConfiguration mSoftApConfig = null; |
| |
| @Override |
| public void onHotspotStarted(SoftApConfiguration softApConfig) { |
| mIsStarted = true; |
| this.mSoftApConfig = softApConfig; |
| } |
| |
| @Override |
| public void onHotspotStopped() { |
| mIsStarted = false; |
| mSoftApConfig = null; |
| } |
| |
| @Override |
| public void onHotspotFailed(int i) { |
| mIsStarted = false; |
| mSoftApConfig = null; |
| } |
| } |
| |
| private void setupForCustomLohs() { |
| setupLohsPermissions(); |
| when(mContext.checkPermission(eq(Manifest.permission.NETWORK_SETUP_WIZARD), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| setupWardenForCustomLohs(); |
| } |
| |
| private void setupWardenForCustomLohs() { |
| doAnswer(invocation -> { |
| changeLohsState(WIFI_AP_STATE_ENABLED, WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR); |
| mWifiServiceImpl.updateInterfaceIpState(mLohsInterfaceName, IFACE_IP_MODE_LOCAL_ONLY); |
| return null; |
| }).when(mActiveModeWarden).startSoftAp(any()); |
| } |
| |
| @Test(expected = SecurityException.class) |
| public void testCustomLohs_FailsWithoutPermission() { |
| SoftApConfiguration customConfig = new SoftApConfiguration.Builder() |
| .setSsid("customConfig") |
| .build(); |
| // set up basic permissions, but not NETWORK_SETUP_WIZARD |
| setupLohsPermissions(); |
| setupWardenForCustomLohs(); |
| mWifiServiceImpl.startLocalOnlyHotspot(mLohsCallback, TEST_PACKAGE_NAME, TEST_FEATURE_ID, |
| customConfig); |
| } |
| |
| private static void nopDeathCallback(LocalOnlyHotspotRequestInfo requestor) { |
| } |
| |
| @Test |
| public void testCustomLohs_ExclusiveAfterShared() { |
| FakeLohsCallback sharedCallback = new FakeLohsCallback(); |
| FakeLohsCallback exclusiveCallback = new FakeLohsCallback(); |
| SoftApConfiguration exclusiveConfig = new SoftApConfiguration.Builder() |
| .setSsid("customSsid") |
| .build(); |
| |
| setupForCustomLohs(); |
| mWifiServiceImpl.registerLOHSForTest(mPid, new LocalOnlyHotspotRequestInfo( |
| sharedCallback, WifiServiceImplTest::nopDeathCallback, null)); |
| assertThat(mWifiServiceImpl.startLocalOnlyHotspot(exclusiveCallback, TEST_PACKAGE_NAME, |
| TEST_FEATURE_ID, exclusiveConfig)).isEqualTo(ERROR_GENERIC); |
| mLooper.dispatchAll(); |
| |
| assertThat(sharedCallback.mIsStarted).isTrue(); |
| assertThat(exclusiveCallback.mIsStarted).isFalse(); |
| } |
| |
| @Test |
| public void testCustomLohs_ExclusiveBeforeShared() { |
| FakeLohsCallback sharedCallback = new FakeLohsCallback(); |
| FakeLohsCallback exclusiveCallback = new FakeLohsCallback(); |
| SoftApConfiguration exclusiveConfig = new SoftApConfiguration.Builder() |
| .setSsid("customSsid") |
| .build(); |
| |
| setupForCustomLohs(); |
| mWifiServiceImpl.registerLOHSForTest(mPid, new LocalOnlyHotspotRequestInfo( |
| exclusiveCallback, WifiServiceImplTest::nopDeathCallback, exclusiveConfig)); |
| assertThat(mWifiServiceImpl.startLocalOnlyHotspot(sharedCallback, TEST_PACKAGE_NAME, |
| TEST_FEATURE_ID, null)).isEqualTo(ERROR_GENERIC); |
| mLooper.dispatchAll(); |
| |
| assertThat(exclusiveCallback.mIsStarted).isTrue(); |
| assertThat(sharedCallback.mIsStarted).isFalse(); |
| } |
| |
| @Test |
| public void testCustomLohs_Wpa2() { |
| SoftApConfiguration config = new SoftApConfiguration.Builder() |
| .setSsid("customSsid") |
| .setPassphrase("passphrase", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) |
| .build(); |
| FakeLohsCallback callback = new FakeLohsCallback(); |
| |
| setupForCustomLohs(); |
| assertThat( |
| mWifiServiceImpl.startLocalOnlyHotspot(callback, TEST_PACKAGE_NAME, TEST_FEATURE_ID, |
| config)).isEqualTo(REQUEST_REGISTERED); |
| mLooper.dispatchAll(); |
| |
| assertThat(callback.mIsStarted).isTrue(); |
| assertThat(callback.mSoftApConfig.getSsid()).isEqualTo("customSsid"); |
| assertThat(callback.mSoftApConfig.getSecurityType()) |
| .isEqualTo(SoftApConfiguration.SECURITY_TYPE_WPA2_PSK); |
| assertThat(callback.mSoftApConfig.getPassphrase()).isEqualTo("passphrase"); |
| } |
| |
| @Test |
| public void testCustomLohs_Open() { |
| SoftApConfiguration config = new SoftApConfiguration.Builder() |
| .setSsid("customSsid") |
| .build(); |
| FakeLohsCallback callback = new FakeLohsCallback(); |
| |
| setupForCustomLohs(); |
| assertThat( |
| mWifiServiceImpl.startLocalOnlyHotspot(callback, TEST_PACKAGE_NAME, TEST_FEATURE_ID, |
| config)).isEqualTo(REQUEST_REGISTERED); |
| mLooper.dispatchAll(); |
| |
| assertThat(callback.mIsStarted).isTrue(); |
| assertThat(callback.mSoftApConfig.getSsid()).isEqualTo("customSsid"); |
| assertThat(callback.mSoftApConfig.getSecurityType()) |
| .isEqualTo(SoftApConfiguration.SECURITY_TYPE_OPEN); |
| assertThat(callback.mSoftApConfig.getPassphrase()).isNull(); |
| } |
| |
| @Test |
| public void testCustomLohs_GeneratesSsidIfAbsent() { |
| SoftApConfiguration config = new SoftApConfiguration.Builder() |
| .setPassphrase("passphrase", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) |
| .build(); |
| FakeLohsCallback callback = new FakeLohsCallback(); |
| |
| setupForCustomLohs(); |
| assertThat( |
| mWifiServiceImpl.startLocalOnlyHotspot(callback, TEST_PACKAGE_NAME, TEST_FEATURE_ID, |
| config)).isEqualTo(REQUEST_REGISTERED); |
| mLooper.dispatchAll(); |
| |
| assertThat(callback.mIsStarted).isTrue(); |
| assertThat(callback.mSoftApConfig.getSsid()).isNotEmpty(); |
| } |
| |
| @Test |
| public void testCustomLohs_ForwardsBssid() { |
| SoftApConfiguration config = new SoftApConfiguration.Builder() |
| .setBssid(MacAddress.fromString("aa:bb:cc:dd:ee:ff")) |
| .build(); |
| FakeLohsCallback callback = new FakeLohsCallback(); |
| |
| setupForCustomLohs(); |
| assertThat( |
| mWifiServiceImpl.startLocalOnlyHotspot(callback, TEST_PACKAGE_NAME, TEST_FEATURE_ID, |
| config)).isEqualTo(REQUEST_REGISTERED); |
| mLooper.dispatchAll(); |
| |
| assertThat(callback.mIsStarted).isTrue(); |
| assertThat(callback.mSoftApConfig.getBssid().toString()) |
| .ignoringCase().isEqualTo("aa:bb:cc:dd:ee:ff"); |
| } |
| |
| /** |
| * 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(mActiveModeWarden, never()).stopSoftAp(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 testServiceImplNotCalledWhenBinderDeathTriggeredWithRequests() throws Exception { |
| 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); |
| |
| setupLocalOnlyHotspot(); |
| |
| binderDeathCallback.onLocalOnlyHotspotRequestorDeath(mRequestInfo); |
| verify(mActiveModeWarden, never()).stopSoftAp(anyInt()); |
| |
| reset(mActiveModeWarden); |
| |
| // now stop as the second request and confirm CMD_SET_AP will be sent to make sure binder |
| // death requestor was removed |
| mWifiServiceImpl.stopLocalOnlyHotspot(); |
| mLooper.dispatchAll(); |
| verify(mActiveModeWarden).stopSoftAp(WifiManager.IFACE_IP_MODE_LOCAL_ONLY); |
| } |
| |
| /** |
| * Verify that a call to registerSoftApCallback throws a SecurityException if the caller does |
| * not have neither NETWORK_SETTINGS nor MAINLINE_NETWORK_STACK permission. |
| */ |
| @Test(expected = SecurityException.class) |
| public void registerSoftApCallbackThrowsSecurityExceptionOnMissingPermissions() { |
| when(mContext.checkCallingOrSelfPermission(android.Manifest.permission.NETWORK_SETTINGS)) |
| .thenReturn(PackageManager.PERMISSION_DENIED); |
| when(mContext.checkCallingOrSelfPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)) |
| .thenReturn(PackageManager.PERMISSION_DENIED); |
| final int callbackIdentifier = 1; |
| mWifiServiceImpl.registerSoftApCallback( |
| mAppBinder, mClientSoftApCallback, callbackIdentifier); |
| } |
| |
| /** |
| * 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 neither NETWORK_SETTINGS nor MAINLINE_NETWORK_STACK permission. |
| */ |
| @Test(expected = SecurityException.class) |
| public void unregisterSoftApCallbackThrowsSecurityExceptionOnMissingPermissions() { |
| when(mContext.checkCallingOrSelfPermission(android.Manifest.permission.NETWORK_SETTINGS)) |
| .thenReturn(PackageManager.PERMISSION_DENIED); |
| when(mContext.checkCallingOrSelfPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)) |
| .thenReturn(PackageManager.PERMISSION_DENIED); |
| final int callbackIdentifier = 1; |
| mWifiServiceImpl.unregisterSoftApCallback(callbackIdentifier); |
| } |
| |
| /** |
| * Verifies that we handle softap callback registration failure if we encounter an exception |
| * while linking to death. |
| */ |
| @Test |
| public void registerSoftApCallbackFailureOnLinkToDeath() throws Exception { |
| 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()).onConnectedClientsChanged(any()); |
| verify(mClientSoftApCallback, never()).onInfoChanged(any()); |
| verify(mClientSoftApCallback, never()).onCapabilityChanged(any()); |
| } |
| |
| |
| /** |
| * 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).onConnectedClientsChanged(Mockito.<WifiClient>anyList()); |
| verify(callback).onInfoChanged(new SoftApInfo()); |
| verify(callback).onCapabilityChanged(ApConfigUtil.updateCapabilityFromResource(mContext)); |
| // Don't need to invoke callback when register. |
| verify(callback, never()).onBlockedClientConnecting(any(), anyInt()); |
| } |
| |
| /** |
| * Verify that registering twice with same callbackIdentifier will replace the first callback. |
| */ |
| @Test |
| public void replacesOldCallbackWithNewCallbackWhenRegisteringTwice() throws Exception { |
| 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 WifiClient testClient = new WifiClient(TEST_FACTORY_MAC_ADDR); |
| final List<WifiClient> testClients = new ArrayList(); |
| testClients.add(testClient); |
| mStateMachineSoftApCallback.onConnectedClientsChanged(testClients); |
| mLooper.dispatchAll(); |
| // Verify only the second callback is being called |
| verify(mClientSoftApCallback, never()).onConnectedClientsChanged(testClients); |
| verify(mAnotherSoftApCallback).onConnectedClientsChanged(testClients); |
| } |
| |
| /** |
| * Verify that unregisterSoftApCallback removes callback from registered callbacks list |
| */ |
| @Test |
| public void unregisterSoftApCallbackRemovesCallback() throws Exception { |
| final int callbackIdentifier = 1; |
| registerSoftApCallbackAndVerify(mClientSoftApCallback, callbackIdentifier); |
| |
| mWifiServiceImpl.unregisterSoftApCallback(callbackIdentifier); |
| mLooper.dispatchAll(); |
| |
| final WifiClient testClient = new WifiClient(TEST_FACTORY_MAC_ADDR); |
| final List<WifiClient> testClients = new ArrayList(); |
| testClients.add(testClient); |
| mStateMachineSoftApCallback.onConnectedClientsChanged(testClients); |
| mLooper.dispatchAll(); |
| verify(mClientSoftApCallback, never()).onConnectedClientsChanged(testClients); |
| } |
| |
| /** |
| * Verify that unregisterSoftApCallback is no-op if callbackIdentifier not registered. |
| */ |
| @Test |
| public void unregisterSoftApCallbackDoesNotRemoveCallbackIfCallbackIdentifierNotMatching() |
| throws Exception { |
| final int callbackIdentifier = 1; |
| registerSoftApCallbackAndVerify(mClientSoftApCallback, callbackIdentifier); |
| |
| final int differentCallbackIdentifier = 2; |
| mWifiServiceImpl.unregisterSoftApCallback(differentCallbackIdentifier); |
| mLooper.dispatchAll(); |
| |
| final WifiClient testClient = new WifiClient(TEST_FACTORY_MAC_ADDR); |
| final List<WifiClient> testClients = new ArrayList(); |
| testClients.add(testClient); |
| mStateMachineSoftApCallback.onConnectedClientsChanged(testClients); |
| mLooper.dispatchAll(); |
| verify(mClientSoftApCallback).onConnectedClientsChanged(testClients); |
| } |
| |
| /** |
| * Registers two callbacks, remove one then verify the right callback is being called on events. |
| */ |
| @Test |
| public void correctCallbackIsCalledAfterAddingTwoCallbacksAndRemovingOne() throws Exception { |
| final int callbackIdentifier = 1; |
| WifiClient testWifiClient = new WifiClient(MacAddress.fromString("22:33:44:55:66:77")); |
| mWifiServiceImpl.registerSoftApCallback(mAppBinder, mClientSoftApCallback, |
| callbackIdentifier); |
| mLooper.dispatchAll(); |
| |
| // Change state from default before registering the second callback |
| final List<WifiClient> testClients = new ArrayList(); |
| mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); |
| mStateMachineSoftApCallback.onConnectedClientsChanged(testClients); |
| mStateMachineSoftApCallback.onInfoChanged(mTestSoftApInfo); |
| mStateMachineSoftApCallback.onBlockedClientConnecting(testWifiClient, 0); |
| |
| |
| // 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).onConnectedClientsChanged(testClients); |
| verify(mAnotherSoftApCallback).onInfoChanged(mTestSoftApInfo); |
| // Verify only first callback will receive onBlockedClientConnecting since it call after |
| // first callback register but before another callback register. |
| verify(mClientSoftApCallback).onBlockedClientConnecting(testWifiClient, 0); |
| verify(mAnotherSoftApCallback, never()).onBlockedClientConnecting(testWifiClient, 0); |
| |
| // 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 { |
| 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 { |
| 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 WifiClient testClient = new WifiClient(TEST_FACTORY_MAC_ADDR); |
| final List<WifiClient> testClients = new ArrayList(); |
| testClients.add(testClient); |
| mStateMachineSoftApCallback.onConnectedClientsChanged(testClients); |
| mLooper.dispatchAll(); |
| verify(mClientSoftApCallback, never()).onConnectedClientsChanged(testClients); |
| } |
| |
| /** |
| * Verify that soft AP callback is called on NumClientsChanged event |
| */ |
| @Test |
| public void callsRegisteredCallbacksOnConnectedClientsChangedEvent() throws Exception { |
| final int callbackIdentifier = 1; |
| registerSoftApCallbackAndVerify(mClientSoftApCallback, callbackIdentifier); |
| |
| final WifiClient testClient = new WifiClient(TEST_FACTORY_MAC_ADDR); |
| final List<WifiClient> testClients = new ArrayList(); |
| testClients.add(testClient); |
| mStateMachineSoftApCallback.onConnectedClientsChanged(testClients); |
| mLooper.dispatchAll(); |
| verify(mClientSoftApCallback).onConnectedClientsChanged(testClients); |
| } |
| |
| /** |
| * Verify that soft AP callback is called on SoftApStateChanged event |
| */ |
| @Test |
| public void callsRegisteredCallbacksOnSoftApStateChangedEvent() throws Exception { |
| 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 updatesSoftApStateAndConnectedClientsOnSoftApEvents() throws Exception { |
| final List<WifiClient> testClients = new ArrayList(); |
| WifiClient testWifiClient = new WifiClient(MacAddress.fromString("22:33:44:55:66:77")); |
| mStateMachineSoftApCallback.onStateChanged(WIFI_AP_STATE_ENABLED, 0); |
| mStateMachineSoftApCallback.onConnectedClientsChanged(testClients); |
| mStateMachineSoftApCallback.onInfoChanged(mTestSoftApInfo); |
| mStateMachineSoftApCallback.onBlockedClientConnecting(testWifiClient, 0); |
| |
| // 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).onConnectedClientsChanged(testClients); |
| verify(mClientSoftApCallback).onInfoChanged(mTestSoftApInfo); |
| // Don't need to invoke callback when register. |
| verify(mClientSoftApCallback, never()).onBlockedClientConnecting(any(), anyInt()); |
| } |
| |
| 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 on SAP_START_FAILURE_GENERAL. |
| */ |
| @Test |
| public void testRegisteredCallbacksTriggeredOnSoftApFailureGeneric() throws Exception { |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| |
| verifyApRegistration(); |
| |
| registerLOHSRequestFull(); |
| |
| changeLohsState(WIFI_AP_STATE_FAILED, WIFI_AP_STATE_DISABLED, SAP_START_FAILURE_GENERAL); |
| mLooper.dispatchAll(); |
| |
| verify(mLohsCallback).onHotspotFailed(ERROR_GENERIC); |
| } |
| |
| /** |
| * Verify that onFailed is called for registered LOHS callers on SAP_START_FAILURE_NO_CHANNEL. |
| */ |
| @Test |
| public void testRegisteredCallbacksTriggeredOnSoftApFailureNoChannel() throws Exception { |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| |
| verifyApRegistration(); |
| |
| registerLOHSRequestFull(); |
| |
| changeLohsState(WIFI_AP_STATE_FAILED, |
| WIFI_AP_STATE_DISABLED, SAP_START_FAILURE_NO_CHANNEL); |
| |
| mLooper.dispatchAll(); |
| verify(mLohsCallback).onHotspotFailed(ERROR_NO_CHANNEL); |
| } |
| |
| /** |
| * Common setup for starting a LOHS. |
| */ |
| private void setupLocalOnlyHotspot() throws Exception { |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| |
| verifyApRegistration(); |
| |
| registerLOHSRequestFull(); |
| |
| changeLohsState(WIFI_AP_STATE_ENABLED, WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR); |
| mWifiServiceImpl.updateInterfaceIpState(mLohsInterfaceName, IFACE_IP_MODE_LOCAL_ONLY); |
| mLooper.dispatchAll(); |
| verify(mLohsCallback).onHotspotStarted(any()); |
| } |
| |
| /** |
| * Verify that onStopped is called for registered LOHS callers when a callback is |
| * received with WIFI_AP_STATE_DISABLING and LOHS was active. |
| */ |
| @Test |
| public void testRegisteredCallbacksTriggeredOnSoftApDisabling() throws Exception { |
| setupLocalOnlyHotspot(); |
| |
| changeLohsState(WIFI_AP_STATE_DISABLING, WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR); |
| |
| mLooper.dispatchAll(); |
| verify(mLohsCallback).onHotspotStopped(); |
| } |
| |
| |
| /** |
| * Verify that onStopped is called for registered LOHS callers when a callback is |
| * received with WIFI_AP_STATE_DISABLED and LOHS was enabled. |
| */ |
| @Test |
| public void testRegisteredCallbacksTriggeredOnSoftApDisabled() throws Exception { |
| setupLocalOnlyHotspot(); |
| |
| changeLohsState(WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR); |
| |
| mLooper.dispatchAll(); |
| verify(mLohsCallback).onHotspotStopped(); |
| } |
| |
| /** |
| * Verify that no callbacks are called for registered LOHS callers when a callback is |
| * received and the softap started. |
| */ |
| @Test |
| public void testRegisteredCallbacksNotTriggeredOnSoftApStart() throws Exception { |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| |
| verifyApRegistration(); |
| |
| registerLOHSRequestFull(); |
| |
| changeLohsState(WIFI_AP_STATE_ENABLED, WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR); |
| |
| mLooper.dispatchAll(); |
| verifyZeroInteractions(ignoreStubs(mLohsCallback)); |
| } |
| |
| /** |
| * Verify that onStopped is called only once for registered LOHS callers when |
| * callbacks are received with WIFI_AP_STATE_DISABLING and |
| * WIFI_AP_STATE_DISABLED when LOHS was enabled. |
| */ |
| @Test |
| public void testRegisteredCallbacksTriggeredOnlyOnceWhenSoftApDisabling() throws Exception { |
| setupLocalOnlyHotspot(); |
| |
| changeLohsState(WIFI_AP_STATE_DISABLING, WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR); |
| changeLohsState(WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR); |
| |
| mLooper.dispatchAll(); |
| verify(mLohsCallback).onHotspotStopped(); |
| } |
| |
| /** |
| * Verify that onFailed is called only once for registered LOHS callers when |
| * callbacks are received with WIFI_AP_STATE_FAILED twice. |
| */ |
| @Test |
| public void testRegisteredCallbacksTriggeredOnlyOnceWhenSoftApFailsTwice() throws Exception { |
| setupLocalOnlyHotspot(); |
| |
| changeLohsState(WIFI_AP_STATE_FAILED, WIFI_AP_STATE_FAILED, ERROR_GENERIC); |
| changeLohsState(WIFI_AP_STATE_FAILED, WIFI_AP_STATE_FAILED, ERROR_GENERIC); |
| |
| mLooper.dispatchAll(); |
| verify(mLohsCallback).onHotspotFailed(ERROR_GENERIC); |
| } |
| |
| /** |
| * Verify that onFailed is called for all registered LOHS callers when |
| * callbacks are received with WIFI_AP_STATE_FAILED. |
| */ |
| @Test |
| public void testAllRegisteredCallbacksTriggeredWhenSoftApFails() throws Exception { |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| |
| verifyApRegistration(); |
| |
| // make an additional request for this test |
| mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo); |
| |
| registerLOHSRequestFull(); |
| |
| changeLohsState(WIFI_AP_STATE_FAILED, WIFI_AP_STATE_FAILED, ERROR_GENERIC); |
| changeLohsState(WIFI_AP_STATE_FAILED, WIFI_AP_STATE_FAILED, ERROR_GENERIC); |
| |
| verify(mRequestInfo).sendHotspotFailedMessage(ERROR_GENERIC); |
| mLooper.dispatchAll(); |
| verify(mLohsCallback).onHotspotFailed(ERROR_GENERIC); |
| } |
| |
| /** |
| * Verify that onStopped is called for all registered LOHS callers when |
| * callbacks are received with WIFI_AP_STATE_DISABLED when LOHS was |
| * active. |
| */ |
| @Test |
| public void testAllRegisteredCallbacksTriggeredWhenSoftApStops() throws Exception { |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| |
| verifyApRegistration(); |
| |
| mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo); |
| |
| registerLOHSRequestFull(); |
| |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| mLooper.dispatchAll(); |
| verify(mRequestInfo).sendHotspotStartedMessage(any()); |
| verify(mLohsCallback).onHotspotStarted(any()); |
| |
| reset(mRequestInfo); |
| clearInvocations(mLohsCallback); |
| |
| changeLohsState(WIFI_AP_STATE_DISABLING, WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR); |
| changeLohsState(WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR); |
| |
| verify(mRequestInfo).sendHotspotStoppedMessage(); |
| mLooper.dispatchAll(); |
| verify(mLohsCallback).onHotspotStopped(); |
| } |
| |
| /** |
| * Verify that onFailed is called for all registered LOHS callers when |
| * callbacks are received with WIFI_AP_STATE_DISABLED when LOHS was |
| * not active. |
| */ |
| @Test |
| public void testAllRegisteredCallbacksTriggeredWhenSoftApStopsLOHSNotActive() throws Exception { |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| |
| verifyApRegistration(); |
| |
| mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo); |
| mWifiServiceImpl.registerLOHSForTest(TEST_PID2, mRequestInfo2); |
| |
| changeLohsState(WIFI_AP_STATE_DISABLING, WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR); |
| changeLohsState(WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR); |
| |
| 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() { |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| mLooper.dispatchAll(); |
| |
| verify(mActiveModeWarden).stopSoftAp(WifiManager.IFACE_IP_MODE_LOCAL_ONLY); |
| } |
| |
| /** |
| * 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 { |
| registerLOHSRequestFull(); |
| |
| mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo); |
| |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| mLooper.dispatchAll(); |
| verify(mRequestInfo).sendHotspotStartedMessage(any(SoftApConfiguration.class)); |
| |
| mLooper.dispatchAll(); |
| verify(mLohsCallback).onHotspotStarted(notNull()); |
| } |
| |
| /** |
| * 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 { |
| mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo); |
| |
| changeLohsState(WIFI_AP_STATE_ENABLED, WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR); |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| mLooper.dispatchAll(); |
| |
| registerLOHSRequestFull(); |
| |
| mLooper.dispatchAll(); |
| |
| verify(mLohsCallback).onHotspotStarted(any()); |
| } |
| |
| /** |
| * 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 { |
| setupLocalOnlyHotspot(); |
| reset(mActiveModeWarden); |
| |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_CONFIGURATION_ERROR); |
| mLooper.dispatchAll(); |
| |
| verify(mLohsCallback).onHotspotFailed(ERROR_GENERIC); |
| verify(mActiveModeWarden).stopSoftAp(WifiManager.IFACE_IP_MODE_LOCAL_ONLY); |
| |
| clearInvocations(mLohsCallback); |
| |
| // 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(); |
| verifyZeroInteractions(ignoreStubs(mLohsCallback)); |
| } |
| |
| /** |
| * 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 { |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_TETHERED); |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_CONFIGURATION_ERROR); |
| mLooper.dispatchAll(); |
| |
| verify(mActiveModeWarden).stopSoftAp(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 { |
| registerLOHSRequestFull(); |
| |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| mLooper.dispatchAll(); |
| verify(mLohsCallback).onHotspotStarted(any()); |
| clearInvocations(mLohsCallback); |
| |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_TETHERED); |
| mLooper.dispatchAll(); |
| |
| verify(mLohsCallback).onHotspotFailed(ERROR_INCOMPATIBLE_MODE); |
| |
| // sendMessage should only happen once since the requestor should be unregistered |
| clearInvocations(mLohsCallback); |
| |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_TETHERED); |
| mLooper.dispatchAll(); |
| verifyZeroInteractions(ignoreStubs(mLohsCallback)); |
| } |
| |
| /** |
| * 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(); |
| |
| verifyZeroInteractions(ignoreStubs(mLohsCallback)); |
| } |
| |
| /** |
| * 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 { |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| verifyApRegistration(); |
| |
| // register a request so we don't drop the LOHS interface ip update |
| mWifiServiceImpl.registerLOHSForTest(TEST_PID, mRequestInfo); |
| changeLohsState(WIFI_AP_STATE_ENABLED, WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR); |
| mWifiServiceImpl.updateInterfaceIpState(WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY); |
| mLooper.dispatchAll(); |
| |
| registerLOHSRequestFull(); |
| mLooper.dispatchAll(); |
| |
| verify(mLohsCallback).onHotspotStarted(any()); |
| |
| clearInvocations(mLohsCallback); |
| |
| // now stop the hotspot |
| changeLohsState(WIFI_AP_STATE_DISABLING, WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR); |
| changeLohsState(WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR); |
| mLooper.dispatchAll(); |
| verify(mLohsCallback).onHotspotStopped(); |
| |
| clearInvocations(mLohsCallback); |
| |
| // now register a new caller - they should not get the onStarted callback |
| ILocalOnlyHotspotCallback callback2 = mock(ILocalOnlyHotspotCallback.class); |
| when(callback2.asBinder()).thenReturn(mock(IBinder.class)); |
| |
| int result = mWifiServiceImpl.startLocalOnlyHotspot( |
| callback2, TEST_PACKAGE_NAME, TEST_FEATURE_ID, null); |
| assertEquals(LocalOnlyHotspotCallback.REQUEST_REGISTERED, result); |
| mLooper.dispatchAll(); |
| |
| verify(mLohsCallback, never()).onHotspotStarted(any()); |
| } |
| |
| /** |
| * 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(mLohsCallback); |
| } |
| |
| /** |
| * 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(mLohsCallback); |
| } |
| |
| /** |
| * 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(mContext.getPackageManager()).thenReturn(pm); |
| when(pm.getApplicationInfoAsUser(any(), anyInt(), any())).thenReturn(mApplicationInfo); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(anyString(), |
| eq(Build.VERSION_CODES.Q), anyInt())).thenReturn(true); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(anyString(), |
| eq(Build.VERSION_CODES.R), anyInt())).thenReturn(true); |
| |
| when(mPasspointManager.addOrUpdateProvider( |
| any(PasspointConfiguration.class), anyInt(), eq(TEST_PACKAGE_NAME), eq(false), |
| eq(true))).thenReturn(true); |
| mLooper.startAutoDispatch(); |
| assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| verify(mPasspointManager).addOrUpdateProvider( |
| any(PasspointConfiguration.class), anyInt(), eq(TEST_PACKAGE_NAME), eq(false), |
| eq(true)); |
| reset(mPasspointManager); |
| |
| when(mPasspointManager.addOrUpdateProvider( |
| any(PasspointConfiguration.class), anyInt(), eq(TEST_PACKAGE_NAME), anyBoolean(), |
| anyBoolean())).thenReturn(false); |
| mLooper.startAutoDispatch(); |
| assertEquals(-1, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| verify(mPasspointManager).addOrUpdateProvider( |
| any(PasspointConfiguration.class), anyInt(), eq(TEST_PACKAGE_NAME), anyBoolean(), |
| anyBoolean()); |
| } |
| |
| /** |
| * Verify that the call to getAllMatchingPasspointProfilesForScanResults is not redirected to |
| * specific API getAllMatchingPasspointProfilesForScanResults when the caller doesn't have |
| * NETWORK_SETTINGS permissions and NETWORK_SETUP_WIZARD. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testGetAllMatchingPasspointProfilesForScanResultsWithoutPermissions() { |
| mWifiServiceImpl.getAllMatchingPasspointProfilesForScanResults(new ArrayList<>()); |
| } |
| |
| /** |
| * Verify that the call to getAllMatchingPasspointProfilesForScanResults is redirected to |
| * specific API getAllMatchingPasspointProfilesForScanResults when the caller have |
| * NETWORK_SETTINGS permissions and NETWORK_SETUP_WIZARD. |
| */ |
| @Test |
| public void testGetAllMatchingPasspointProfilesForScanResultsWithPermissions() { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| mWifiServiceImpl.getAllMatchingPasspointProfilesForScanResults(createScanResultList()); |
| mLooper.dispatchAll(); |
| verify(mPasspointManager).getAllMatchingPasspointProfilesForScanResults(any()); |
| } |
| |
| /** |
| * Verify that the call to getAllMatchingPasspointProfilesForScanResults is not redirected to |
| * specific API getAllMatchingPasspointProfilesForScanResults when the caller provider invalid |
| * ScanResult. |
| */ |
| @Test |
| public void testGetAllMatchingPasspointProfilesForScanResultsWithInvalidScanResult() { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| mWifiServiceImpl.getAllMatchingPasspointProfilesForScanResults(new ArrayList<>()); |
| mLooper.dispatchAll(); |
| verify(mPasspointManager, never()).getAllMatchingPasspointProfilesForScanResults(any()); |
| } |
| |
| /** |
| * 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 getMatchingOsuProviders is redirected to specific API |
| * syncGetMatchingOsuProviders when the caller have NETWORK_SETTINGS |
| * permissions and NETWORK_SETUP_WIZARD. |
| */ |
| @Test |
| public void testGetMatchingOsuProvidersWithPermissions() { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| mWifiServiceImpl.getMatchingOsuProviders(createScanResultList()); |
| mLooper.dispatchAll(); |
| verify(mPasspointManager).getMatchingOsuProviders(any()); |
| } |
| |
| /** |
| * Verify that the call to getMatchingOsuProviders is not redirected to specific API |
| * syncGetMatchingOsuProviders when the caller provider invalid ScanResult |
| */ |
| @Test |
| public void testGetMatchingOsuProvidersWithInvalidScanResult() { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| mWifiServiceImpl.getMatchingOsuProviders(new ArrayList<>()); |
| mLooper.dispatchAll(); |
| verify(mPasspointManager, never()).getMatchingOsuProviders(any()); |
| } |
| |
| /** |
| * 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 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 the call to getPasspointConfigurations when the caller doesn't have |
| * NETWORK_SETTINGS and NETWORK_SETUP_WIZARD permissions. |
| */ |
| @Test |
| public void testGetPasspointConfigurationsWithOutPrivilegedPermissions() { |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(false); |
| when(mWifiPermissionsUtil.checkNetworkSetupWizardPermission(anyInt())).thenReturn(false); |
| |
| mLooper.startAutoDispatch(); |
| mWifiServiceImpl.getPasspointConfigurations(TEST_PACKAGE_NAME); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| verify(mPasspointManager).getProviderConfigs(Binder.getCallingUid(), false); |
| } |
| |
| /** |
| * Verify that the call to getPasspointConfigurations when the caller does have |
| * NETWORK_SETTINGS permission. |
| */ |
| @Test |
| public void testGetPasspointConfigurationsWithPrivilegedPermissions() { |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); |
| |
| mLooper.startAutoDispatch(); |
| mWifiServiceImpl.getPasspointConfigurations(TEST_PACKAGE_NAME); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| verify(mPasspointManager).getProviderConfigs(Binder.getCallingUid(), true); |
| } |
| |
| /** |
| * Verify that GetPasspointConfigurations will redirect calls to {@link PasspointManager} |
| * and returning the result that's returned from {@link PasspointManager}. |
| */ |
| @Test |
| public void testGetPasspointConfigurations() throws Exception { |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); |
| |
| // Setup expected configs. |
| List<PasspointConfiguration> expectedConfigs = new ArrayList<>(); |
| PasspointConfiguration config = new PasspointConfiguration(); |
| HomeSp homeSp = new HomeSp(); |
| homeSp.setFqdn("test.com"); |
| config.setHomeSp(homeSp); |
| expectedConfigs.add(config); |
| |
| when(mPasspointManager.getProviderConfigs(anyInt(), anyBoolean())) |
| .thenReturn(expectedConfigs); |
| mLooper.startAutoDispatch(); |
| assertEquals(expectedConfigs, mWifiServiceImpl.getPasspointConfigurations(TEST_PACKAGE)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| reset(mPasspointManager); |
| |
| when(mPasspointManager.getProviderConfigs(anyInt(), anyBoolean())) |
| .thenReturn(new ArrayList<PasspointConfiguration>()); |
| mLooper.startAutoDispatch(); |
| assertTrue(mWifiServiceImpl.getPasspointConfigurations(TEST_PACKAGE).isEmpty()); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| } |
| |
| /** |
| * Verify the call to removePasspointConfigurations when the caller doesn't have |
| * NETWORK_SETTINGS and NETWORK_CARRIER_PROVISIONING permissions. |
| */ |
| @Test |
| public void testRemovePasspointConfigurationWithOutPrivilegedPermissions() { |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(false); |
| when(mWifiPermissionsUtil.checkNetworkCarrierProvisioningPermission(anyInt())).thenReturn( |
| false); |
| |
| mLooper.startAutoDispatch(); |
| mWifiServiceImpl.removePasspointConfiguration(TEST_FQDN, TEST_PACKAGE_NAME); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| verify(mPasspointManager).removeProvider(Binder.getCallingUid(), false, null, |
| TEST_FQDN); |
| } |
| |
| /** |
| * Verify the call to removePasspointConfigurations when the caller does have |
| * NETWORK_CARRIER_PROVISIONING permission. |
| */ |
| @Test |
| public void testRemovePasspointConfigurationWithPrivilegedPermissions() { |
| when(mWifiPermissionsUtil.checkNetworkCarrierProvisioningPermission(anyInt())).thenReturn( |
| true); |
| |
| mLooper.startAutoDispatch(); |
| mWifiServiceImpl.removePasspointConfiguration(TEST_FQDN, TEST_PACKAGE_NAME); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| verify(mPasspointManager).removeProvider(Binder.getCallingUid(), true, null, |
| TEST_FQDN); |
| } |
| |
| /** |
| * 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#restoreSoftApBackupData(byte[])} |
| * is only allowed from callers with the signature only NETWORK_SETTINGS permission. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testRestoreSoftApBackupDataNotApprovedCaller() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| mWifiServiceImpl.restoreSoftApBackupData(null); |
| verify(mSoftApBackupRestore, never()) |
| .retrieveSoftApConfigurationFromBackupData(any(byte[].class)); |
| } |
| |
| /** |
| * Verify that a call to {@link WifiServiceImpl#retrieveSoftApBackupData()} is only allowed from |
| * callers with the signature only NETWORK_SETTINGS permission. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testRetrieveSoftApBackupDataNotApprovedCaller() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| mWifiServiceImpl.retrieveSoftApBackupData(); |
| verify(mSoftApBackupRestore, never()) |
| .retrieveBackupDataFromSoftApConfiguration(any(SoftApConfiguration.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(mWifiSettingsConfigStore).put(WIFI_VERBOSE_LOGGING_ENABLED, true); |
| 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(mWifiSettingsConfigStore, never()).put( |
| WIFI_VERBOSE_LOGGING_ENABLED, anyBoolean()); |
| verify(mClientModeImpl, never()).enableVerboseLogging(anyInt()); |
| } |
| |
| /** |
| * Verify that the CONNECT_NETWORK message received from an app without |
| * one of the privileged permission is rejected with a security exception. |
| */ |
| @Test |
| public void testConnectNetworkWithoutPrivilegedPermission() throws Exception { |
| try { |
| mWifiServiceImpl.connect(mock(WifiConfiguration.class), TEST_NETWORK_ID, |
| mock(Binder.class), |
| mock(IActionListener.class), 0); |
| fail(); |
| } catch (SecurityException e) { |
| verify(mClientModeImpl, never()).connect(any(WifiConfiguration.class), anyInt(), |
| any(Binder.class), any(IActionListener.class), anyInt(), anyInt()); |
| } |
| } |
| |
| /** |
| * Verify that the FORGET_NETWORK message received from an app without |
| * one of the privileged permission is rejected with a security exception. |
| */ |
| @Test |
| public void testForgetNetworkWithoutPrivilegedPermission() throws Exception { |
| try { |
| mWifiServiceImpl.forget(TEST_NETWORK_ID, mock(Binder.class), |
| mock(IActionListener.class), 0); |
| fail(); |
| } catch (SecurityException e) { |
| verify(mClientModeImpl, never()).forget(anyInt(), any(Binder.class), |
| any(IActionListener.class), anyInt(), anyInt()); |
| } |
| } |
| |
| /** |
| * Verify that the SAVE_NETWORK message received from an app without |
| * one of the privileged permission is rejected with a security exception. |
| */ |
| @Test |
| public void testSaveNetworkWithoutPrivilegedPermission() throws Exception { |
| try { |
| mWifiServiceImpl.save(mock(WifiConfiguration.class), mock(Binder.class), |
| mock(IActionListener.class), 0); |
| fail(); |
| } catch (SecurityException e) { |
| verify(mClientModeImpl, never()).save(any(WifiConfiguration.class), |
| any(Binder.class), any(IActionListener.class), anyInt(), anyInt()); |
| } |
| } |
| |
| /** |
| * 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 { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); |
| mWifiServiceImpl.connect(mock(WifiConfiguration.class), TEST_NETWORK_ID, |
| mock(Binder.class), |
| mock(IActionListener.class), 0); |
| verify(mClientModeImpl).connect(any(WifiConfiguration.class), anyInt(), |
| any(Binder.class), any(IActionListener.class), anyInt(), anyInt()); |
| verify(mWifiMetrics).logUserActionEvent(eq(UserActionEvent.EVENT_ADD_OR_UPDATE_NETWORK), |
| anyInt()); |
| } |
| |
| /** |
| * 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 { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); |
| mWifiServiceImpl.save(mock(WifiConfiguration.class), mock(Binder.class), |
| mock(IActionListener.class), 0); |
| verify(mWifiMetrics).logUserActionEvent(eq(UserActionEvent.EVENT_ADD_OR_UPDATE_NETWORK), |
| anyInt()); |
| verify(mClientModeImpl).save(any(WifiConfiguration.class), |
| any(Binder.class), any(IActionListener.class), anyInt(), anyInt()); |
| } |
| |
| /** |
| * Verify that the FORGET_NETWORK message received from an app with |
| * one of the privileged permission is forwarded to ClientModeImpl. |
| */ |
| @Test |
| public void testForgetNetworkWithPrivilegedPermission() throws Exception { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); |
| mWifiServiceImpl.forget(TEST_NETWORK_ID, mock(Binder.class), mock(IActionListener.class), |
| 0); |
| |
| InOrder inOrder = inOrder(mClientModeImpl, mWifiMetrics); |
| inOrder.verify(mWifiMetrics).logUserActionEvent( |
| UserActionEvent.EVENT_FORGET_WIFI, TEST_NETWORK_ID); |
| inOrder.verify(mClientModeImpl).forget(anyInt(), any(Binder.class), |
| any(IActionListener.class), anyInt(), anyInt()); |
| } |
| |
| /** |
| * 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 { |
| when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false); |
| when(mWifiInjector.getPasspointProvisionerHandlerThread()) |
| .thenReturn(mock(HandlerThread.class)); |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| mWifiServiceImpl.handleBootCompleted(); |
| mLooper.dispatchAll(); |
| 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); |
| mLooper.dispatchAll(); |
| |
| // Send a scan request while the device is idle. |
| mLooper.startAutoDispatch(); |
| assertFalse(mWifiServiceImpl.startScan(SCAN_PACKAGE_NAME, TEST_FEATURE_ID)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| // 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); |
| mLooper.dispatchAll(); |
| |
| // 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. |
| mLooper.startAutoDispatch(); |
| assertTrue(mWifiServiceImpl.startScan(SCAN_PACKAGE_NAME, TEST_FEATURE_ID)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| 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. |
| */ |
| @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. |
| */ |
| @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. |
| */ |
| @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 testPackageFullyRemovedBroadcastHandling() throws Exception { |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| argThat((IntentFilter filter) -> |
| filter.hasAction(Intent.ACTION_PACKAGE_FULLY_REMOVED) |
| && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED) |
| && filter.hasAction(Intent.ACTION_PACKAGE_CHANGED))); |
| int uid = TEST_UID; |
| String packageName = TEST_PACKAGE_NAME; |
| doThrow(new PackageManager.NameNotFoundException()).when(mPackageManager) |
| .getApplicationInfo(TEST_PACKAGE_NAME, 0); |
| // 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); |
| mLooper.dispatchAll(); |
| |
| ArgumentCaptor<ApplicationInfo> aiCaptor = ArgumentCaptor.forClass(ApplicationInfo.class); |
| verify(mWifiConfigManager).removeNetworksForApp(aiCaptor.capture()); |
| assertNotNull(aiCaptor.getValue()); |
| assertEquals(uid, aiCaptor.getValue().uid); |
| assertEquals(packageName, aiCaptor.getValue().packageName); |
| |
| verify(mScanRequestProxy).clearScanRequestTimestampsForApp(packageName, uid); |
| verify(mWifiNetworkSuggestionsManager).removeApp(packageName); |
| verify(mClientModeImpl).removeNetworkRequestUserApprovedAccessPointsForApp(packageName); |
| verify(mPasspointManager).removePasspointProviderWithPackage(packageName); |
| } |
| |
| @Test |
| public void testPackageRemovedBroadcastHandling() throws Exception { |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| argThat((IntentFilter filter) -> |
| filter.hasAction(Intent.ACTION_PACKAGE_FULLY_REMOVED) |
| && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED) |
| && filter.hasAction(Intent.ACTION_PACKAGE_CHANGED))); |
| int uid = TEST_UID; |
| String packageName = TEST_PACKAGE_NAME; |
| // Send the broadcast |
| Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED); |
| intent.putExtra(Intent.EXTRA_UID, uid); |
| intent.setData(Uri.fromParts("package", packageName, "")); |
| mBroadcastReceiverCaptor.getValue().onReceive(mContext, intent); |
| mLooper.dispatchAll(); |
| |
| ArgumentCaptor<ApplicationInfo> aiCaptor = ArgumentCaptor.forClass(ApplicationInfo.class); |
| verify(mWifiConfigManager).removeNetworksForApp(aiCaptor.capture()); |
| assertNotNull(aiCaptor.getValue()); |
| assertEquals(uid, aiCaptor.getValue().uid); |
| assertEquals(packageName, aiCaptor.getValue().packageName); |
| |
| verify(mScanRequestProxy).clearScanRequestTimestampsForApp(packageName, uid); |
| verify(mWifiNetworkSuggestionsManager).removeApp(packageName); |
| verify(mClientModeImpl).removeNetworkRequestUserApprovedAccessPointsForApp(packageName); |
| verify(mPasspointManager).removePasspointProviderWithPackage(packageName); |
| } |
| |
| @Test |
| public void testPackageDisableBroadcastHandling() throws Exception { |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| argThat((IntentFilter filter) -> |
| filter.hasAction(Intent.ACTION_PACKAGE_FULLY_REMOVED) |
| && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED) |
| && filter.hasAction(Intent.ACTION_PACKAGE_CHANGED))); |
| int uid = TEST_UID; |
| String packageName = TEST_PACKAGE_NAME; |
| mPackageInfo.applicationInfo = mApplicationInfo; |
| mApplicationInfo.enabled = false; |
| // Send the broadcast |
| Intent intent = new Intent(Intent.ACTION_PACKAGE_CHANGED); |
| intent.putExtra(Intent.EXTRA_UID, uid); |
| intent.setData(Uri.fromParts("package", packageName, "")); |
| mBroadcastReceiverCaptor.getValue().onReceive(mContext, intent); |
| mLooper.dispatchAll(); |
| |
| ArgumentCaptor<ApplicationInfo> aiCaptor = ArgumentCaptor.forClass(ApplicationInfo.class); |
| verify(mWifiConfigManager).removeNetworksForApp(aiCaptor.capture()); |
| assertNotNull(aiCaptor.getValue()); |
| assertEquals(uid, aiCaptor.getValue().uid); |
| assertEquals(packageName, aiCaptor.getValue().packageName); |
| |
| verify(mScanRequestProxy).clearScanRequestTimestampsForApp(packageName, uid); |
| verify(mWifiNetworkSuggestionsManager).removeApp(packageName); |
| verify(mClientModeImpl).removeNetworkRequestUserApprovedAccessPointsForApp(packageName); |
| verify(mPasspointManager).removePasspointProviderWithPackage(packageName); |
| } |
| |
| @Test |
| public void testPackageRemovedBroadcastHandlingWithNoUid() { |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| 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_REMOVED); |
| intent.setData(Uri.fromParts("package", packageName, "")); |
| mBroadcastReceiverCaptor.getValue().onReceive(mContext, intent); |
| |
| verify(mWifiConfigManager, never()).removeNetworksForApp(any()); |
| |
| 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() { |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| 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(mWifiConfigManager, never()).removeNetworksForApp(any()); |
| |
| 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() { |
| when(mWifiInjector.getPasspointProvisionerHandlerThread()) |
| .thenReturn(mock(HandlerThread.class)); |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| mWifiServiceImpl.handleBootCompleted(); |
| mLooper.dispatchAll(); |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| argThat((IntentFilter filter) -> |
| filter.hasAction(Intent.ACTION_USER_REMOVED))); |
| |
| UserHandle userHandle = UserHandle.of(TEST_USER_HANDLE); |
| // Send the broadcast |
| Intent intent = new Intent(Intent.ACTION_USER_REMOVED); |
| intent.putExtra(Intent.EXTRA_USER, userHandle); |
| mBroadcastReceiverCaptor.getValue().onReceive(mContext, intent); |
| mLooper.dispatchAll(); |
| |
| verify(mWifiConfigManager).removeNetworksForUser(userHandle.getIdentifier()); |
| } |
| |
| @Test |
| public void testUserRemovedBroadcastHandlingWithWrongIntentAction() { |
| when(mWifiInjector.getPasspointProvisionerHandlerThread()) |
| .thenReturn(mock(HandlerThread.class)); |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| mWifiServiceImpl.handleBootCompleted(); |
| mLooper.dispatchAll(); |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| argThat((IntentFilter filter) -> |
| filter.hasAction(Intent.ACTION_USER_REMOVED))); |
| |
| UserHandle userHandle = UserHandle.of(TEST_USER_HANDLE); |
| // Send the broadcast with wrong action |
| Intent intent = new Intent(Intent.ACTION_USER_FOREGROUND); |
| intent.putExtra(Intent.EXTRA_USER, userHandle); |
| mBroadcastReceiverCaptor.getValue().onReceive(mContext, intent); |
| |
| verify(mWifiConfigManager, never()).removeNetworksForUser(anyInt()); |
| } |
| |
| 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 createValidWifiApConfiguration() { |
| WifiConfiguration apConfig = new WifiConfiguration(); |
| apConfig.SSID = "TestAp"; |
| apConfig.preSharedKey = "thisIsABadPassword"; |
| apConfig.allowedKeyManagement.set(KeyMgmt.WPA2_PSK); |
| apConfig.apBand = WifiConfiguration.AP_BAND_2GHZ; |
| |
| return apConfig; |
| } |
| |
| private SoftApConfiguration createValidSoftApConfiguration() { |
| return new SoftApConfiguration.Builder() |
| .setSsid("TestAp") |
| .setPassphrase("thisIsABadPassword", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) |
| .setBand(SoftApConfiguration.BAND_2GHZ) |
| .build(); |
| } |
| |
| /** |
| * Verifies that sim state change does not set or reset the country code |
| */ |
| @Test |
| public void testSimStateChangeDoesNotResetCountryCode() { |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| (IntentFilter) argThat((IntentFilter filter) -> |
| filter.hasAction(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED))); |
| |
| int userHandle = TEST_USER_HANDLE; |
| // Send the broadcast |
| Intent intent = new Intent(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED); |
| intent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle); |
| mBroadcastReceiverCaptor.getValue().onReceive(mContext, intent); |
| verifyNoMoreInteractions(mWifiCountryCode); |
| } |
| |
| /** |
| * Verifies that sim state change does not set or reset the country code |
| */ |
| @Test |
| public void testSimStateChangeDoesNotResetCountryCodeForRebroadcastedIntent() { |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| (IntentFilter) argThat((IntentFilter filter) -> |
| filter.hasAction(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED))); |
| |
| int userHandle = TEST_USER_HANDLE; |
| // Send the broadcast |
| Intent intent = new Intent(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED); |
| intent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle); |
| intent.putExtra(TelephonyManager.EXTRA_SIM_STATE, Intent.SIM_STATE_ABSENT); |
| mBroadcastReceiverCaptor.getValue().onReceive(mContext, intent); |
| verifyNoMoreInteractions(mWifiCountryCode); |
| } |
| |
| /** |
| * Verifies that entering airplane mode does not reset country code. |
| */ |
| @Test |
| public void testEnterAirplaneModeNotResetCountryCode() { |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| (IntentFilter) argThat((IntentFilter filter) -> |
| filter.hasAction(Intent.ACTION_AIRPLANE_MODE_CHANGED))); |
| |
| when(mSettingsStore.isAirplaneModeOn()).thenReturn(true); |
| |
| // Send the broadcast |
| Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); |
| mBroadcastReceiverCaptor.getValue().onReceive(mContext, intent); |
| |
| verifyNoMoreInteractions(mWifiCountryCode); |
| } |
| |
| /** |
| * 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 { |
| 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 { |
| 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 { |
| 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 { |
| 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 { |
| 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 network = WifiConfigurationTestUtil.createOpenNetwork(); |
| PasspointConfiguration config = new PasspointConfiguration(); |
| HomeSp homeSp = new HomeSp(); |
| homeSp.setFqdn(fqdn); |
| config.setHomeSp(homeSp); |
| Credential credential = new Credential(); |
| credential.setRealm("example.com"); |
| config.setCredential(credential); |
| |
| mWifiServiceImpl.mClientModeImplChannel = mAsyncChannel; |
| when(mWifiConfigManager.getSavedNetworks(anyInt())) |
| .thenReturn(Arrays.asList(network)); |
| when(mPasspointManager.getProviderConfigs(anyInt(), anyBoolean())) |
| .thenReturn(Arrays.asList(config)); |
| |
| mLooper.startAutoDispatch(); |
| mWifiServiceImpl.factoryReset(TEST_PACKAGE_NAME); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| // Let the final post inside the |factoryReset| method run to completion. |
| mLooper.dispatchAll(); |
| |
| verify(mWifiConfigManager).removeNetwork( |
| network.networkId, Binder.getCallingUid(), TEST_PACKAGE_NAME); |
| verify(mPasspointManager).removeProvider(anyInt(), anyBoolean(), eq(config.getUniqueId()), |
| isNull()); |
| verify(mPasspointManager).clearAnqpRequestsAndFlushCache(); |
| verify(mWifiConfigManager).clearUserTemporarilyDisabledList(); |
| verify(mWifiConfigManager).removeAllEphemeralOrPasspointConfiguredNetworks(); |
| verify(mClientModeImpl).clearNetworkRequestUserApprovedAccessPoints(); |
| verify(mWifiNetworkSuggestionsManager).clear(); |
| verify(mWifiScoreCard).clear(); |
| verify(mWifiHealthMonitor).clear(); |
| verify(mPasspointManager).getProviderConfigs(anyInt(), anyBoolean()); |
| } |
| |
| /** |
| * Verify that a call to factoryReset throws a SecurityException if the caller does not have |
| * the NETWORK_SETTINGS permission. |
| */ |
| @Test |
| public void testFactoryResetWithoutNetworkSettingsPermission() throws Exception { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| try { |
| mWifiServiceImpl.factoryReset(TEST_PACKAGE_NAME); |
| fail(); |
| } catch (SecurityException e) { |
| } |
| verify(mWifiConfigManager, never()).getSavedNetworks(anyInt()); |
| verify(mPasspointManager, never()).getProviderConfigs(anyInt(), anyBoolean()); |
| } |
| |
| /** |
| * Verify that add or update networks is not allowed for apps targeting Q SDK. |
| */ |
| @Test |
| public void testAddOrUpdateNetworkIsNotAllowedForAppsTargetingQSdk() throws Exception { |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mWifiConfigManager.addOrUpdateNetwork(any(), anyInt(), any())).thenReturn( |
| new NetworkUpdateResult(0)); |
| |
| WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); |
| mLooper.startAutoDispatch(); |
| assertEquals(-1, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| verify(mWifiConfigManager, never()).addOrUpdateNetwork(any(), anyInt(), 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 { |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mWifiConfigManager.addOrUpdateNetwork(any(), anyInt(), any())).thenReturn( |
| new NetworkUpdateResult(0)); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(anyString(), |
| eq(Build.VERSION_CODES.Q), anyInt())).thenReturn(true); |
| |
| WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); |
| mLooper.startAutoDispatch(); |
| assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| verify(mWifiConfigManager).addOrUpdateNetwork(any(), anyInt(), any()); |
| verify(mWifiMetrics).incrementNumAddOrUpdateNetworkCalls(); |
| } |
| |
| /** |
| * Verify that add or update networks is allowed for settings app. |
| */ |
| @Test |
| public void testAddOrUpdateNetworkIsAllowedForSettingsApp() throws Exception { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| mApplicationInfo.targetSdkVersion = Build.VERSION_CODES.P; |
| when(mWifiConfigManager.addOrUpdateNetwork(any(), anyInt(), any())).thenReturn( |
| new NetworkUpdateResult(0)); |
| |
| WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); |
| mLooper.startAutoDispatch(); |
| assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| // 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(mWifiConfigManager).addOrUpdateNetwork(any(), anyInt(), any()); |
| verify(mWifiMetrics).incrementNumAddOrUpdateNetworkCalls(); |
| } |
| |
| /** |
| * Verify that add or update networks is allowed for system apps. |
| */ |
| @Test |
| public void testAddOrUpdateNetworkIsAllowedForSystemApp() throws Exception { |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM; |
| when(mWifiConfigManager.addOrUpdateNetwork(any(), anyInt(), any())).thenReturn( |
| new NetworkUpdateResult(0)); |
| |
| WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); |
| mLooper.startAutoDispatch(); |
| assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| verify(mWifiConfigManager).addOrUpdateNetwork(any(), anyInt(), any()); |
| verify(mWifiMetrics).incrementNumAddOrUpdateNetworkCalls(); |
| } |
| |
| /** |
| * Verify that add or update networks is allowed for apps holding system alert permission. |
| */ |
| @Test |
| public void testAddOrUpdateNetworkIsAllowedForAppsWithSystemAlertPermission() throws Exception { |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mWifiConfigManager.addOrUpdateNetwork(any(), anyInt(), any())).thenReturn( |
| new NetworkUpdateResult(0)); |
| |
| when(mWifiPermissionsUtil.checkSystemAlertWindowPermission( |
| Process.myUid(), TEST_PACKAGE_NAME)).thenReturn(true); |
| |
| WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); |
| mLooper.startAutoDispatch(); |
| assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| verify(mWifiPermissionsUtil).checkSystemAlertWindowPermission(anyInt(), anyString()); |
| verify(mWifiConfigManager).addOrUpdateNetwork(any(), anyInt(), any()); |
| verify(mWifiMetrics).incrementNumAddOrUpdateNetworkCalls(); |
| } |
| |
| /** |
| * Verify that add or update networks is allowed for DeviceOwner app. |
| */ |
| @Test |
| public void testAddOrUpdateNetworkIsAllowedForDOApp() throws Exception { |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mWifiPermissionsUtil.isDeviceOwner(Binder.getCallingUid(), TEST_PACKAGE_NAME)) |
| .thenReturn(true); |
| when(mWifiConfigManager.addOrUpdateNetwork(any(), anyInt(), any())).thenReturn( |
| new NetworkUpdateResult(0)); |
| |
| WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); |
| mLooper.startAutoDispatch(); |
| assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| verify(mWifiConfigManager).addOrUpdateNetwork(any(), anyInt(), any()); |
| verify(mWifiMetrics).incrementNumAddOrUpdateNetworkCalls(); |
| } |
| |
| /** |
| * Verify that add or update networks is allowed for ProfileOwner app. |
| */ |
| @Test |
| public void testAddOrUpdateNetworkIsAllowedForPOApp() throws Exception { |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mWifiPermissionsUtil.isProfileOwner(Binder.getCallingUid(), TEST_PACKAGE_NAME)) |
| .thenReturn(true); |
| when(mWifiConfigManager.addOrUpdateNetwork(any(), anyInt(), any())).thenReturn( |
| new NetworkUpdateResult(0)); |
| |
| WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork(); |
| mLooper.startAutoDispatch(); |
| assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| verifyCheckChangePermission(TEST_PACKAGE_NAME); |
| verify(mWifiConfigManager).addOrUpdateNetwork(any(), anyInt(), any()); |
| verify(mWifiMetrics).incrementNumAddOrUpdateNetworkCalls(); |
| } |
| |
| /** |
| * Verify that enableNetwork is allowed for privileged Apps |
| */ |
| @Test |
| public void testEnableNetworkWithDisableOthersAllowedForPrivilegedApps() throws Exception { |
| 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); |
| |
| doAnswer(new MockAnswerUtil.AnswerWithArguments() { |
| public void answer(WifiConfiguration config, int netId, IBinder binder, |
| IActionListener callback, int callbackIdentifier, int callingUid) { |
| try { |
| callback.onSuccess(); // return success |
| } catch (RemoteException e) { } |
| } |
| }).when(mClientModeImpl).connect( |
| isNull(), eq(TEST_NETWORK_ID), any(), any(), anyInt(), anyInt()); |
| |
| assertTrue(mWifiServiceImpl.enableNetwork(TEST_NETWORK_ID, true, TEST_PACKAGE_NAME)); |
| |
| verify(mClientModeImpl).connect(isNull(), eq(TEST_NETWORK_ID), any(), any(), anyInt(), |
| anyInt()); |
| verify(mWifiMetrics).incrementNumEnableNetworkCalls(); |
| } |
| |
| /** |
| * Verify that enableNetwork (with disableOthers=true) is allowed for Apps targeting a SDK |
| * version less than Q |
| */ |
| @Test |
| public void testEnabledNetworkWithDisableOthersAllowedForAppsTargetingBelowQSdk() |
| 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), anyInt())).thenReturn(true); |
| |
| doAnswer(new MockAnswerUtil.AnswerWithArguments() { |
| public void answer(WifiConfiguration config, int netId, IBinder binder, |
| IActionListener callback, int callbackIdentifier, int callingUid) { |
| try { |
| callback.onSuccess(); // return success |
| } catch (RemoteException e) { } |
| } |
| }).when(mClientModeImpl).connect( |
| isNull(), eq(TEST_NETWORK_ID), any(), any(), anyInt(), anyInt()); |
| |
| assertTrue(mWifiServiceImpl.enableNetwork(TEST_NETWORK_ID, true, TEST_PACKAGE_NAME)); |
| |
| verify(mClientModeImpl).connect(isNull(), eq(TEST_NETWORK_ID), any(), any(), anyInt(), |
| anyInt()); |
| verify(mWifiMetrics).incrementNumEnableNetworkCalls(); |
| } |
| |
| /** |
| * Verify that enableNetwork (with disableOthers=false) is allowed for Apps targeting a SDK |
| * version less than Q |
| */ |
| @Test |
| public void testEnabledNetworkWithoutDisableOthersAllowedForAppsTargetingBelowQSdk() |
| 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), anyInt())).thenReturn(true); |
| |
| when(mWifiConfigManager.enableNetwork(anyInt(), anyBoolean(), anyInt(), anyString())) |
| .thenReturn(true); |
| mLooper.startAutoDispatch(); |
| assertTrue(mWifiServiceImpl.enableNetwork(TEST_NETWORK_ID, false, TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| verify(mWifiConfigManager).enableNetwork(eq(TEST_NETWORK_ID), eq(false), |
| eq(Binder.getCallingUid()), eq(TEST_PACKAGE_NAME)); |
| verify(mWifiMetrics).incrementNumEnableNetworkCalls(); |
| } |
| |
| /** |
| * Verify that enableNetwork is not allowed for Apps targeting Q SDK |
| */ |
| @Test |
| public void testEnableNetworkNotAllowedForAppsTargetingQ() throws Exception { |
| 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()).connect(isNull(), anyInt(), any(), any(), anyInt(), |
| anyInt()); |
| verify(mWifiMetrics, never()).incrementNumEnableNetworkCalls(); |
| } |
| |
| /** |
| * Ensure that we invoke {@link WifiNetworkSuggestionsManager} to add network |
| * suggestions. |
| */ |
| @Test |
| public void testAddNetworkSuggestions() { |
| when(mWifiNetworkSuggestionsManager.add(any(), anyInt(), anyString(), |
| nullable(String.class))).thenReturn(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS); |
| mLooper.startAutoDispatch(); |
| assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS, |
| mWifiServiceImpl.addNetworkSuggestions(mock(List.class), TEST_PACKAGE_NAME, |
| TEST_FEATURE_ID)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| when(mWifiNetworkSuggestionsManager.add(any(), anyInt(), anyString(), |
| nullable(String.class))).thenReturn( |
| WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE); |
| mLooper.startAutoDispatch(); |
| assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE, |
| mWifiServiceImpl.addNetworkSuggestions(mock(List.class), TEST_PACKAGE_NAME, |
| TEST_FEATURE_ID)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| verify(mWifiNetworkSuggestionsManager, times(2)).add( |
| any(), eq(Binder.getCallingUid()), eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID)); |
| } |
| |
| /** |
| * Ensure that we don't invoke {@link WifiNetworkSuggestionsManager} to add network |
| * suggestions when the looper sync call times out. |
| */ |
| @Test |
| public void testAddNetworkSuggestionsFailureInRunWithScissors() { |
| mWifiServiceImpl = makeWifiServiceImplWithMockRunnerWhichTimesOut(); |
| |
| mLooper.startAutoDispatch(); |
| assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL, |
| mWifiServiceImpl.addNetworkSuggestions(mock(List.class), TEST_PACKAGE_NAME, |
| TEST_FEATURE_ID)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| verify(mWifiNetworkSuggestionsManager, never()).add(any(), eq(Binder.getCallingUid()), |
| eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID)); |
| } |
| |
| /** |
| * Ensure that we invoke {@link WifiNetworkSuggestionsManager} to remove network |
| * suggestions. |
| */ |
| @Test |
| public void testRemoveNetworkSuggestions() { |
| when(mWifiNetworkSuggestionsManager.remove(any(), anyInt(), anyString())) |
| .thenReturn(WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID); |
| mLooper.startAutoDispatch(); |
| assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID, |
| mWifiServiceImpl.removeNetworkSuggestions(mock(List.class), TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| when(mWifiNetworkSuggestionsManager.remove(any(), anyInt(), anyString())) |
| .thenReturn(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS); |
| mLooper.startAutoDispatch(); |
| assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS, |
| mWifiServiceImpl.removeNetworkSuggestions(mock(List.class), TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| verify(mWifiNetworkSuggestionsManager, times(2)).remove(any(), anyInt(), |
| eq(TEST_PACKAGE_NAME)); |
| } |
| |
| /** |
| * Ensure that we don't invoke {@link WifiNetworkSuggestionsManager} to remove network |
| * suggestions when the looper sync call times out. |
| */ |
| @Test |
| public void testRemoveNetworkSuggestionsFailureInRunWithScissors() { |
| mWifiServiceImpl = makeWifiServiceImplWithMockRunnerWhichTimesOut(); |
| |
| mLooper.startAutoDispatch(); |
| assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL, |
| mWifiServiceImpl.removeNetworkSuggestions(mock(List.class), TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| verify(mWifiNetworkSuggestionsManager, never()).remove(any(), anyInt(), |
| eq(TEST_PACKAGE_NAME)); |
| } |
| |
| /** |
| * Ensure that we invoke {@link WifiNetworkSuggestionsManager} to get network |
| * suggestions. |
| */ |
| @Test |
| public void testGetNetworkSuggestions() { |
| List<WifiNetworkSuggestion> testList = new ArrayList<>(); |
| when(mWifiNetworkSuggestionsManager.get(anyString())).thenReturn(testList); |
| mLooper.startAutoDispatch(); |
| assertEquals(testList, mWifiServiceImpl.getNetworkSuggestions(TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| verify(mWifiNetworkSuggestionsManager).get(eq(TEST_PACKAGE_NAME)); |
| } |
| |
| /** |
| * Ensure that we don't invoke {@link WifiNetworkSuggestionsManager} to get network |
| * suggestions when the looper sync call times out. |
| */ |
| @Test |
| public void testGetNetworkSuggestionsFailureInRunWithScissors() { |
| mWifiServiceImpl = makeWifiServiceImplWithMockRunnerWhichTimesOut(); |
| |
| mLooper.startAutoDispatch(); |
| assertTrue(mWifiServiceImpl.getNetworkSuggestions(TEST_PACKAGE_NAME).isEmpty()); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| verify(mWifiNetworkSuggestionsManager, never()).get(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); |
| mLooper.dispatchAll(); |
| verify(mWifiConfigManager).userTemporarilyDisabledNetwork(anyString(), anyInt()); |
| } |
| |
| /** |
| * 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); |
| mLooper.dispatchAll(); |
| verify(mWifiConfigManager, never()).userTemporarilyDisabledNetwork(anyString(), anyInt()); |
| } |
| |
| /** |
| * Verify getting the factory MAC address. |
| */ |
| @Test |
| public void testGetFactoryMacAddresses() throws Exception { |
| when(mClientModeImpl.getFactoryMacAddress()).thenReturn(TEST_FACTORY_MAC); |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); |
| mLooper.startAutoDispatch(); |
| final String[] factoryMacs = mWifiServiceImpl.getFactoryMacAddresses(); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| 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 { |
| mWifiServiceImpl = makeWifiServiceImplWithMockRunnerWhichTimesOut(); |
| |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); |
| mLooper.startAutoDispatch(); |
| assertArrayEquals(new String[0], mWifiServiceImpl.getFactoryMacAddresses()); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| verify(mClientModeImpl, never()).getFactoryMacAddress(); |
| } |
| |
| /** |
| * Verify getting the factory MAC address returns null when the lower layers fail. |
| */ |
| @Test |
| public void testGetFactoryMacAddressesFail() throws Exception { |
| when(mClientModeImpl.getFactoryMacAddress()).thenReturn(null); |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); |
| mLooper.startAutoDispatch(); |
| assertArrayEquals(new String[0], mWifiServiceImpl.getFactoryMacAddresses()); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| 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 { |
| when(mClientModeImpl.getFactoryMacAddress()).thenReturn(TEST_FACTORY_MAC); |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(false); |
| try { |
| mLooper.startAutoDispatch(); |
| mWifiServiceImpl.getFactoryMacAddresses(); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| 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) |
| .enforceCallingOrSelfPermission( |
| 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() { |
| 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) |
| .enforceCallingOrSelfPermission( |
| 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) |
| .enforceCallingOrSelfPermission( |
| 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 { |
| 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 { |
| 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) |
| .enforceCallingOrSelfPermission( |
| 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() { |
| mWifiServiceImpl.updateWifiUsabilityScore(anyInt(), anyInt(), 15); |
| mLooper.dispatchAll(); |
| verify(mClientModeImpl).updateWifiUsabilityScore(anyInt(), anyInt(), anyInt()); |
| } |
| |
| private void startLohsAndTethering(boolean isApConcurrencySupported) throws Exception { |
| // initialization |
| when(mActiveModeWarden.canRequestMoreSoftApManagers()).thenReturn(isApConcurrencySupported); |
| // For these tests, always use distinct interface names for LOHS and tethered. |
| mLohsInterfaceName = WIFI_IFACE_NAME2; |
| |
| mLooper.startAutoDispatch(); |
| setupLocalOnlyHotspot(); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| reset(mActiveModeWarden); |
| |
| when(mActiveModeWarden.canRequestMoreSoftApManagers()).thenReturn(isApConcurrencySupported); |
| |
| // start tethering |
| mLooper.startAutoDispatch(); |
| boolean tetheringResult = mWifiServiceImpl.startSoftAp(null); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| assertTrue(tetheringResult); |
| verify(mActiveModeWarden).startSoftAp(any()); |
| 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() throws Exception { |
| startLohsAndTethering(false); |
| |
| // verify LOHS got stopped |
| verify(mLohsCallback).onHotspotFailed(anyInt()); |
| verify(mActiveModeWarden).stopSoftAp(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() throws Exception { |
| startLohsAndTethering(true); |
| |
| // verify LOHS didn't get stopped |
| verifyZeroInteractions(ignoreStubs(mLohsCallback)); |
| verify(mActiveModeWarden, never()).stopSoftAp(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) { |
| } |
| } |
| |
| /** |
| * Verifies that configs can be removed. |
| */ |
| @Test |
| public void testRemoveNetworkIsAllowedForAppsTargetingBelowQSdk() { |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| when(mWifiConfigManager.removeNetwork(eq(0), anyInt(), anyString())).thenReturn(true); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(anyString(), |
| eq(Build.VERSION_CODES.Q), anyInt())).thenReturn(true); |
| |
| mLooper.startAutoDispatch(); |
| boolean result = mWifiServiceImpl.removeNetwork(0, TEST_PACKAGE_NAME); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| assertTrue(result); |
| verify(mWifiConfigManager).removeNetwork(anyInt(), anyInt(), anyString()); |
| } |
| |
| /** |
| * Verify that addOrUpdatePasspointConfiguration is allowed for apps targeting below R SDK. |
| */ |
| @Test |
| public void addOrUpdatePasspointConfigIsAllowedForAppsTargetingBelowRSdk() 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.R), anyInt())).thenReturn(true); |
| PasspointConfiguration config = new PasspointConfiguration(); |
| HomeSp homeSp = new HomeSp(); |
| homeSp.setFqdn("test.com"); |
| config.setHomeSp(homeSp); |
| |
| when(mPasspointManager.addOrUpdateProvider( |
| config, Binder.getCallingUid(), TEST_PACKAGE_NAME, false, true)) |
| .thenReturn(true); |
| mLooper.startAutoDispatch(); |
| assertTrue(mWifiServiceImpl.addOrUpdatePasspointConfiguration(config, TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| reset(mPasspointManager); |
| |
| when(mPasspointManager.addOrUpdateProvider( |
| config, Binder.getCallingUid(), TEST_PACKAGE_NAME, false, true)) |
| .thenReturn(false); |
| mLooper.startAutoDispatch(); |
| assertFalse(mWifiServiceImpl.addOrUpdatePasspointConfiguration(config, TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| } |
| |
| /** |
| * Verify that addOrUpdatePasspointConfiguration is not allowed for apps targeting R SDK. |
| */ |
| @Test |
| public void addOrUpdatePasspointConfigIsNotAllowedForAppsTargetingRSdk() throws Exception { |
| doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) |
| .noteOp(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Process.myUid(), TEST_PACKAGE_NAME); |
| PasspointConfiguration config = new PasspointConfiguration(); |
| HomeSp homeSp = new HomeSp(); |
| homeSp.setFqdn("test.com"); |
| config.setHomeSp(homeSp); |
| |
| when(mPasspointManager.addOrUpdateProvider( |
| config, Binder.getCallingUid(), TEST_PACKAGE_NAME, false, true)) |
| .thenReturn(true); |
| mLooper.startAutoDispatch(); |
| assertFalse(mWifiServiceImpl.addOrUpdatePasspointConfiguration(config, TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| verify(mPasspointManager, never()) |
| .addOrUpdateProvider(any(), anyInt(), anyString(), anyBoolean(), anyBoolean()); |
| |
| } |
| |
| /** |
| * Verify that addOrUpdatePasspointConfiguration is allowed for Settings apps. |
| */ |
| @Test |
| public void addOrUpdatePasspointConfigIsAllowedSettingsApp() throws Exception { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| when(mWifiPermissionsUtil.isTargetSdkLessThan(anyString(), |
| eq(Build.VERSION_CODES.R), anyInt())).thenReturn(false); |
| PasspointConfiguration config = new PasspointConfiguration(); |
| HomeSp homeSp = new HomeSp(); |
| homeSp.setFqdn("test.com"); |
| config.setHomeSp(homeSp); |
| |
| when(mPasspointManager.addOrUpdateProvider( |
| config, Binder.getCallingUid(), TEST_PACKAGE_NAME, false, true)) |
| .thenReturn(true); |
| mLooper.startAutoDispatch(); |
| assertTrue(mWifiServiceImpl.addOrUpdatePasspointConfiguration(config, TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| verify(mPasspointManager).addOrUpdateProvider(any(), anyInt(), anyString(), anyBoolean(), |
| anyBoolean()); |
| } |
| |
| /** |
| * Verify that addOrUpdatePasspointConfiguration is allowed for System apps. |
| */ |
| @Test |
| public void addOrUpdatePasspointConfigIsAllowedSystemApp() 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.R), anyInt())).thenReturn(false); |
| mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM; |
| PasspointConfiguration config = new PasspointConfiguration(); |
| HomeSp homeSp = new HomeSp(); |
| homeSp.setFqdn("test.com"); |
| config.setHomeSp(homeSp); |
| |
| when(mPasspointManager.addOrUpdateProvider( |
| config, Binder.getCallingUid(), TEST_PACKAGE_NAME, false, true)) |
| .thenReturn(true); |
| mLooper.startAutoDispatch(); |
| assertTrue(mWifiServiceImpl.addOrUpdatePasspointConfiguration(config, TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| verify(mPasspointManager).addOrUpdateProvider(any(), anyInt(), anyString(), anyBoolean(), |
| anyBoolean()); |
| } |
| |
| /** |
| * Verify that addOrUpdatePasspointConfiguration is allowed for DeviceOwner apps. |
| */ |
| @Test |
| public void addOrUpdatePasspointConfigIsAllowedSystemAlertDOApp() 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.R), anyInt())).thenReturn(false); |
| when(mWifiPermissionsUtil.isDeviceOwner(Binder.getCallingUid(), TEST_PACKAGE_NAME)) |
| .thenReturn(true); |
| PasspointConfiguration config = new PasspointConfiguration(); |
| HomeSp homeSp = new HomeSp(); |
| homeSp.setFqdn("test.com"); |
| config.setHomeSp(homeSp); |
| |
| when(mPasspointManager.addOrUpdateProvider( |
| config, Binder.getCallingUid(), TEST_PACKAGE_NAME, false, true)) |
| .thenReturn(true); |
| mLooper.startAutoDispatch(); |
| assertTrue(mWifiServiceImpl.addOrUpdatePasspointConfiguration(config, TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| verify(mPasspointManager).addOrUpdateProvider(any(), anyInt(), anyString(), anyBoolean(), |
| anyBoolean()); |
| } |
| |
| /** |
| * Verify that addOrUpdatePasspointConfiguration is allowed for ProfileOwner apps. |
| */ |
| @Test |
| public void addOrUpdatePasspointConfigIsAllowedSystemAlertPOApp() 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.R), anyInt())).thenReturn(false); |
| when(mWifiPermissionsUtil.isProfileOwner(Binder.getCallingUid(), TEST_PACKAGE_NAME)) |
| .thenReturn(true); |
| PasspointConfiguration config = new PasspointConfiguration(); |
| HomeSp homeSp = new HomeSp(); |
| homeSp.setFqdn("test.com"); |
| config.setHomeSp(homeSp); |
| |
| when(mPasspointManager.addOrUpdateProvider( |
| config, Binder.getCallingUid(), TEST_PACKAGE_NAME, false, true)) |
| .thenReturn(true); |
| mLooper.startAutoDispatch(); |
| assertTrue(mWifiServiceImpl.addOrUpdatePasspointConfiguration(config, TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| verify(mPasspointManager).addOrUpdateProvider(any(), anyInt(), anyString(), anyBoolean(), |
| anyBoolean()); |
| } |
| |
| /** |
| * Verify that removePasspointConfiguration will redirect calls to {@link PasspointManager} |
| * and returning the result that's returned from {@link PasspointManager}. |
| */ |
| @Test |
| public void removePasspointConfig() throws Exception { |
| when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); |
| |
| String fqdn = "test.com"; |
| when(mPasspointManager.removeProvider(anyInt(), anyBoolean(), isNull(), eq(fqdn))) |
| .thenReturn(true); |
| mLooper.startAutoDispatch(); |
| assertTrue(mWifiServiceImpl.removePasspointConfiguration(fqdn, TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| reset(mPasspointManager); |
| |
| when(mPasspointManager.removeProvider(anyInt(), anyBoolean(), isNull(), eq(fqdn))) |
| .thenReturn(false); |
| mLooper.startAutoDispatch(); |
| assertFalse(mWifiServiceImpl.removePasspointConfiguration(fqdn, TEST_PACKAGE_NAME)); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| } |
| |
| /** |
| * Test that DISABLE_NETWORK returns failure to public API when WifiConfigManager returns |
| * failure. |
| */ |
| @Test |
| public void testDisableNetworkFailureAppBelowQSdk() 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), anyInt())).thenReturn(true); |
| when(mWifiConfigManager.disableNetwork(anyInt(), anyInt(), anyString())).thenReturn(false); |
| |
| mLooper.startAutoDispatch(); |
| boolean succeeded = mWifiServiceImpl.disableNetwork(0, TEST_PACKAGE_NAME); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| assertFalse(succeeded); |
| } |
| |
| @Test |
| public void testAllowAutojoinGlobalFailureNoNetworkSettingsPermission() throws Exception { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| try { |
| mWifiServiceImpl.allowAutojoinGlobal(true); |
| fail("Expected SecurityException"); |
| } catch (SecurityException e) { |
| // Test succeeded |
| } |
| } |
| |
| @Test |
| public void testAllowAutojoinFailureNoNetworkSettingsPermission() throws Exception { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| try { |
| mWifiServiceImpl.allowAutojoin(0, true); |
| fail("Expected SecurityException"); |
| } catch (SecurityException e) { |
| // Test succeeded |
| } |
| } |
| |
| @Test |
| public void testAllowAutojoinOnSuggestionNetwork() { |
| WifiConfiguration config = new WifiConfiguration(); |
| config.allowAutojoin = false; |
| config.fromWifiNetworkSuggestion = true; |
| when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(config); |
| when(mWifiNetworkSuggestionsManager.allowNetworkSuggestionAutojoin(any(), anyBoolean())) |
| .thenReturn(true); |
| mWifiServiceImpl.allowAutojoin(0, true); |
| mLooper.dispatchAll(); |
| verify(mWifiConfigManager).getConfiguredNetwork(0); |
| verify(mWifiNetworkSuggestionsManager).allowNetworkSuggestionAutojoin(any(), anyBoolean()); |
| verify(mWifiConfigManager).allowAutojoin(anyInt(), anyBoolean()); |
| verify(mWifiMetrics).logUserActionEvent(eq(UserActionEvent.EVENT_CONFIGURE_AUTO_CONNECT_ON), |
| anyInt()); |
| } |
| |
| @Test |
| public void testAllowAutojoinOnSavedNetwork() { |
| WifiConfiguration config = new WifiConfiguration(); |
| config.allowAutojoin = false; |
| config.fromWifiNetworkSuggestion = false; |
| config.fromWifiNetworkSpecifier = false; |
| when(mWifiConfigManager.getConfiguredNetwork(0)).thenReturn(config); |
| mWifiServiceImpl.allowAutojoin(0, true); |
| mLooper.dispatchAll(); |
| verify(mWifiConfigManager).getConfiguredNetwork(0); |
| verify(mWifiNetworkSuggestionsManager, never()) |
| .allowNetworkSuggestionAutojoin(any(), anyBoolean()); |
| verify(mWifiConfigManager).allowAutojoin(anyInt(), anyBoolean()); |
| } |
| |
| @Test |
| public void testAllowAutojoinOnWifiNetworkSpecifier() { |
| WifiConfiguration config = new WifiConfiguration(); |
| config.fromWifiNetworkSpecifier = true; |
| when(mWifiConfigManager.getConfiguredNetwork(0)).thenReturn(config); |
| mWifiServiceImpl.allowAutojoin(0, true); |
| mLooper.dispatchAll(); |
| verify(mWifiConfigManager).getConfiguredNetwork(0); |
| verify(mWifiNetworkSuggestionsManager, never()) |
| .allowNetworkSuggestionAutojoin(config, true); |
| verify(mWifiConfigManager, never()).allowAutojoin(0, true); |
| } |
| |
| @Test |
| public void testAllowAutojoinOnSavedPasspointNetwork() { |
| WifiConfiguration config = WifiConfigurationTestUtil.createPasspointNetwork(); |
| when(mWifiConfigManager.getConfiguredNetwork(0)).thenReturn(config); |
| when(mWifiNetworkSuggestionsManager.allowNetworkSuggestionAutojoin(any(), anyBoolean())) |
| .thenReturn(true); |
| mWifiServiceImpl.allowAutojoin(0, true); |
| mLooper.dispatchAll(); |
| verify(mWifiConfigManager).getConfiguredNetwork(0); |
| verify(mWifiNetworkSuggestionsManager, never()) |
| .allowNetworkSuggestionAutojoin(config, true); |
| verify(mWifiConfigManager, never()).allowAutojoin(0, true); |
| } |
| |
| /** |
| * Test that setMacRandomizationSettingPasspointEnabled is protected by NETWORK_SETTINGS |
| * permission. |
| */ |
| @Test |
| public void testSetMacRandomizationSettingPasspointEnabledFailureNoNetworkSettingsPermission() |
| throws Exception { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| try { |
| mWifiServiceImpl.setMacRandomizationSettingPasspointEnabled("TEST_FQDN", true); |
| fail("Expected SecurityException"); |
| } catch (SecurityException e) { |
| // Test succeeded |
| } |
| } |
| |
| /** |
| * Test that setMacRandomizationSettingPasspointEnabled makes the appropriate calls. |
| */ |
| @Test |
| public void testSetMacRandomizationSettingPasspointEnabled() throws Exception { |
| mWifiServiceImpl.setMacRandomizationSettingPasspointEnabled("TEST_FQDN", true); |
| mLooper.dispatchAll(); |
| verify(mPasspointManager).enableMacRandomization("TEST_FQDN", true); |
| } |
| |
| /** |
| * Test that setPasspointMeteredOverride is protected by NETWORK_SETTINGS permission. |
| */ |
| @Test |
| public void testSetPasspointMeteredOverrideFailureNoNetworkSettingsPermission() |
| throws Exception { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| try { |
| mWifiServiceImpl.setPasspointMeteredOverride("TEST_FQDN", METERED_OVERRIDE_METERED); |
| fail("Expected SecurityException"); |
| } catch (SecurityException e) { |
| // Test succeeded |
| } |
| } |
| |
| /** |
| * Test that setPasspointMeteredOverride makes the appropriate calls. |
| */ |
| @Test |
| public void testSetPasspointMeteredOverride() throws Exception { |
| mWifiServiceImpl.setPasspointMeteredOverride("TEST_FQDN", METERED_OVERRIDE_METERED); |
| mLooper.dispatchAll(); |
| verify(mPasspointManager).setMeteredOverride("TEST_FQDN", METERED_OVERRIDE_METERED); |
| } |
| |
| /** |
| * Test handle boot completed sequence. |
| */ |
| @Test |
| public void testHandleBootCompleted() throws Exception { |
| when(mWifiInjector.getPasspointProvisionerHandlerThread()) |
| .thenReturn(mock(HandlerThread.class)); |
| mWifiServiceImpl.handleBootCompleted(); |
| mLooper.dispatchAll(); |
| |
| verify(mPasspointManager).initializeProvisioner(any()); |
| verify(mClientModeImpl).handleBootCompleted(); |
| } |
| |
| /** |
| * Test handle user switch sequence. |
| */ |
| @Test |
| public void testHandleUserSwitch() throws Exception { |
| mWifiServiceImpl.handleUserSwitch(5); |
| mLooper.dispatchAll(); |
| verify(mWifiConfigManager).handleUserSwitch(5); |
| } |
| |
| /** |
| * Test handle user unlock sequence. |
| */ |
| @Test |
| public void testHandleUserUnlock() throws Exception { |
| mWifiServiceImpl.handleUserUnlock(5); |
| mLooper.dispatchAll(); |
| verify(mWifiConfigManager).handleUserUnlock(5); |
| } |
| |
| /** |
| * Test handle user stop sequence. |
| */ |
| @Test |
| public void testHandleUserStop() throws Exception { |
| mWifiServiceImpl.handleUserStop(5); |
| mLooper.dispatchAll(); |
| verify(mWifiConfigManager).handleUserStop(5); |
| } |
| |
| /** |
| * Test register scan result callback without permission. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testRegisterScanResultCallbackWithMissingPermission() throws Exception { |
| doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission( |
| eq(ACCESS_WIFI_STATE), eq("WifiService")); |
| mWifiServiceImpl.registerScanResultsCallback(mScanResultsCallback); |
| } |
| |
| /** |
| * Test unregister scan result callback without permission. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testUnregisterScanResultCallbackWithMissingPermission() throws Exception { |
| doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission( |
| eq(ACCESS_WIFI_STATE), eq("WifiService")); |
| mWifiServiceImpl.unregisterScanResultsCallback(mScanResultsCallback); |
| } |
| |
| /** |
| * Test register scan result callback with illegal argument. |
| */ |
| @Test(expected = IllegalArgumentException.class) |
| public void testRegisterScanResultCallbackWithIllegalArgument() throws Exception { |
| mWifiServiceImpl.registerScanResultsCallback(null); |
| } |
| |
| /** |
| * Test register and unregister callback will go to ScanRequestProxy; |
| */ |
| @Test |
| public void testRegisterUnregisterScanResultCallback() throws Exception { |
| mWifiServiceImpl.registerScanResultsCallback(mScanResultsCallback); |
| mLooper.dispatchAll(); |
| verify(mScanRequestProxy).registerScanResultsCallback(mScanResultsCallback); |
| mWifiServiceImpl.unregisterScanResultsCallback(mScanResultsCallback); |
| mLooper.dispatchAll(); |
| verify(mScanRequestProxy).unregisterScanResultsCallback(mScanResultsCallback); |
| } |
| |
| /** |
| * Test register callback without permission. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testRegisterSuggestionNetworkCallbackWithMissingPermission() { |
| doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission( |
| eq(ACCESS_WIFI_STATE), eq("WifiService")); |
| mWifiServiceImpl.registerSuggestionConnectionStatusListener(mAppBinder, |
| mSuggestionConnectionStatusListener, NETWORK_CALLBACK_ID, TEST_PACKAGE_NAME, |
| TEST_FEATURE_ID); |
| } |
| |
| /** |
| * Test register callback without callback |
| */ |
| @Test(expected = IllegalArgumentException.class) |
| public void testRegisterSuggestionNetworkCallbackWithIllegalArgument() { |
| mWifiServiceImpl.registerSuggestionConnectionStatusListener(mAppBinder, null, |
| NETWORK_CALLBACK_ID, TEST_PACKAGE_NAME, TEST_FEATURE_ID); |
| } |
| |
| /** |
| * Test unregister callback without permission. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testUnregisterSuggestionNetworkCallbackWithMissingPermission() { |
| doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission( |
| eq(ACCESS_WIFI_STATE), eq("WifiService")); |
| mWifiServiceImpl.unregisterSuggestionConnectionStatusListener( |
| NETWORK_CALLBACK_ID, TEST_PACKAGE_NAME); |
| } |
| |
| /** |
| * Test register nad unregister callback will go to WifiNetworkSuggestionManager |
| */ |
| @Test |
| public void testRegisterUnregisterSuggestionNetworkCallback() throws Exception { |
| mWifiServiceImpl.registerSuggestionConnectionStatusListener(mAppBinder, |
| mSuggestionConnectionStatusListener, NETWORK_CALLBACK_ID, TEST_PACKAGE_NAME, |
| TEST_FEATURE_ID); |
| mLooper.dispatchAll(); |
| verify(mWifiNetworkSuggestionsManager).registerSuggestionConnectionStatusListener( |
| eq(mAppBinder), eq(mSuggestionConnectionStatusListener), eq(NETWORK_CALLBACK_ID), |
| eq(TEST_PACKAGE_NAME)); |
| mWifiServiceImpl.unregisterSuggestionConnectionStatusListener(NETWORK_CALLBACK_ID, |
| TEST_PACKAGE_NAME); |
| mLooper.dispatchAll(); |
| verify(mWifiNetworkSuggestionsManager).unregisterSuggestionConnectionStatusListener( |
| eq(NETWORK_CALLBACK_ID), eq(TEST_PACKAGE_NAME)); |
| } |
| |
| |
| /** |
| * Test to verify that the lock mode is verified before dispatching the operation |
| * |
| * Steps: call acquireWifiLock with an invalid lock mode. |
| * Expected: the call should throw an IllegalArgumentException. |
| */ |
| @Test(expected = IllegalArgumentException.class) |
| public void acquireWifiLockShouldThrowExceptionOnInvalidLockMode() throws Exception { |
| final int wifiLockModeInvalid = -1; |
| |
| mWifiServiceImpl.acquireWifiLock(mAppBinder, wifiLockModeInvalid, "", null); |
| } |
| |
| private void setupReportActivityInfo() { |
| WifiLinkLayerStats stats = new WifiLinkLayerStats(); |
| stats.on_time = 1000; |
| stats.tx_time = 1; |
| stats.rx_time = 2; |
| stats.tx_time_per_level = new int[] {3, 4, 5}; |
| stats.on_time_scan = 6; |
| when(mClientModeImpl.syncGetLinkLayerStats(any())).thenReturn(stats); |
| when(mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE)) |
| .thenReturn(7.0); |
| when(mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX)) |
| .thenReturn(8.0); |
| when(mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX)) |
| .thenReturn(9.0); |
| when(mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE)) |
| .thenReturn(10000.0); |
| when(mClock.getElapsedSinceBootMillis()).thenReturn(9999L); |
| } |
| |
| private void validateWifiActivityEnergyInfo(WifiActivityEnergyInfo info) { |
| assertNotNull(info); |
| assertEquals(9999L, info.getTimeSinceBootMillis()); |
| assertEquals(WifiActivityEnergyInfo.STACK_STATE_STATE_IDLE, info.getStackState()); |
| assertEquals(1, info.getControllerTxDurationMillis()); |
| assertEquals(2, info.getControllerRxDurationMillis()); |
| assertEquals(6, info.getControllerScanDurationMillis()); |
| assertEquals(997, info.getControllerIdleDurationMillis()); |
| } |
| |
| /** |
| * Tests that {@link WifiServiceImpl#getWifiActivityEnergyInfoAsync} throws |
| * {@link SecurityException} if the caller doesn't have the necessary permissions. |
| */ |
| @Test(expected = SecurityException.class) |
| public void getWifiActivityEnergyInfoAsyncNoPermission() throws Exception { |
| doThrow(SecurityException.class) |
| .when(mContext).enforceCallingOrSelfPermission(eq(ACCESS_WIFI_STATE), any()); |
| mWifiServiceImpl.getWifiActivityEnergyInfoAsync(mOnWifiActivityEnergyInfoListener); |
| } |
| |
| /** |
| * Tests that {@link WifiServiceImpl#getWifiActivityEnergyInfoAsync} passes null to the listener |
| * if link layer stats is unsupported. |
| */ |
| @Test |
| public void getWifiActivityEnergyInfoAsyncFeatureUnsupported() throws Exception { |
| when(mClientModeImpl.syncGetSupportedFeatures(any())).thenReturn(0L); |
| mWifiServiceImpl.getWifiActivityEnergyInfoAsync(mOnWifiActivityEnergyInfoListener); |
| verify(mOnWifiActivityEnergyInfoListener).onWifiActivityEnergyInfo(null); |
| } |
| |
| /** |
| * Tests that {@link WifiServiceImpl#getWifiActivityEnergyInfoAsync} passes the expected values |
| * to the listener on success. |
| */ |
| @Test |
| public void getWifiActivityEnergyInfoAsyncSuccess() throws Exception { |
| when(mClientModeImpl.syncGetSupportedFeatures(any())).thenReturn(Long.MAX_VALUE); |
| setupReportActivityInfo(); |
| mWifiServiceImpl.getWifiActivityEnergyInfoAsync(mOnWifiActivityEnergyInfoListener); |
| ArgumentCaptor<WifiActivityEnergyInfo> infoCaptor = |
| ArgumentCaptor.forClass(WifiActivityEnergyInfo.class); |
| verify(mOnWifiActivityEnergyInfoListener).onWifiActivityEnergyInfo(infoCaptor.capture()); |
| validateWifiActivityEnergyInfo(infoCaptor.getValue()); |
| } |
| |
| @Test |
| public void testCarrierConfigChangeUpdateSoftApCapability() throws Exception { |
| MockitoSession staticMockSession = mockitoSession() |
| .mockStatic(SubscriptionManager.class) |
| .startMocking(); |
| lenient().when(SubscriptionManager.getActiveDataSubscriptionId()) |
| .thenReturn(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| argThat((IntentFilter filter) -> |
| filter.hasAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED))); |
| |
| // Send the broadcast |
| Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); |
| mBroadcastReceiverCaptor.getValue().onReceive(mContext, intent); |
| mLooper.dispatchAll(); |
| verify(mActiveModeWarden).updateSoftApCapability(any()); |
| staticMockSession.finishMocking(); |
| } |
| |
| @Test |
| public void testPhoneActiveDataSubscriptionIdChangedUpdateSoftApCapability() throws Exception { |
| MockitoSession staticMockSession = mockitoSession() |
| .mockStatic(SubscriptionManager.class) |
| .startMocking(); |
| lenient().when(SubscriptionManager.getActiveDataSubscriptionId()) |
| .thenReturn(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); |
| mWifiServiceImpl.checkAndStartWifi(); |
| mLooper.dispatchAll(); |
| verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| argThat((IntentFilter filter) -> |
| filter.hasAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED))); |
| ArgumentCaptor<PhoneStateListener> phoneStateListenerCaptor = |
| ArgumentCaptor.forClass(PhoneStateListener.class); |
| verify(mTelephonyManager).listen(phoneStateListenerCaptor.capture(), |
| eq(PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE)); |
| mPhoneStateListener = phoneStateListenerCaptor.getValue(); |
| assertNotNull(mPhoneStateListener); |
| mPhoneStateListener.onActiveDataSubscriptionIdChanged(2); |
| mLooper.dispatchAll(); |
| verify(mActiveModeWarden).updateSoftApCapability(any()); |
| staticMockSession.finishMocking(); |
| } |
| |
| /** |
| * Verify that the call to getWifiConfigsForMatchedNetworkSuggestions is not redirected to |
| * specific API getWifiConfigForMatchedNetworkSuggestionsSharedWithUser when the caller doesn't |
| * have NETWORK_SETTINGS permissions and NETWORK_SETUP_WIZARD. |
| */ |
| @Test(expected = SecurityException.class) |
| public void testGetWifiConfigsForMatchedNetworkSuggestionsWithoutPermissions() { |
| mWifiServiceImpl.getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(new ArrayList<>()); |
| } |
| |
| /** |
| * Verify that the call to getWifiConfigsForMatchedNetworkSuggestions is redirected to |
| * specific API getWifiConfigForMatchedNetworkSuggestionsSharedWithUser when the caller |
| * have NETWORK_SETTINGS. |
| */ |
| @Test |
| public void testGetWifiConfigsForMatchedNetworkSuggestionsWithSettingPermissions() { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| mWifiServiceImpl |
| .getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(createScanResultList()); |
| mLooper.dispatchAll(); |
| verify(mWifiNetworkSuggestionsManager) |
| .getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(any()); |
| } |
| |
| /** |
| * Verify that the call to getWifiConfigsForMatchedNetworkSuggestions is redirected to |
| * specific API getWifiConfigForMatchedNetworkSuggestionsSharedWithUser when the caller |
| * have NETWORK_SETUP_WIZARD. |
| */ |
| @Test |
| public void testGetWifiConfigsForMatchedNetworkSuggestionsWithSetupWizardPermissions() { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETUP_WIZARD), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| mWifiServiceImpl |
| .getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(createScanResultList()); |
| mLooper.dispatchAll(); |
| verify(mWifiNetworkSuggestionsManager) |
| .getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(any()); |
| } |
| |
| @Test |
| public void testGetWifiConfigsForMatchedNetworkSuggestionsWithInvalidScanResults() { |
| when(mContext.checkPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); |
| mWifiServiceImpl |
| .getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(new ArrayList<>()); |
| mLooper.dispatchAll(); |
| verify(mWifiNetworkSuggestionsManager, never()) |
| .getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(any()); |
| } |
| |
| /** |
| * Verify that a call to setWifiConnectedNetworkScorer throws a SecurityException if |
| * the caller does not have WIFI_UPDATE_USABILITY_STATS_SCORE permission. |
| */ |
| @Test |
| public void testSetNetworkScorerThrowsSecurityExceptionOnMissingPermissions() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission( |
| eq(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE), |
| eq("WifiService")); |
| try { |
| mWifiServiceImpl.setWifiConnectedNetworkScorer(mAppBinder, mWifiConnectedNetworkScorer); |
| fail("expected SecurityException"); |
| } catch (SecurityException expected) { |
| } |
| } |
| |
| /** |
| * Verify that a call to setWifiConnectedNetworkScorer throws an IllegalArgumentException |
| * if the parameters are not provided. |
| */ |
| @Test |
| public void testSetScorerThrowsIllegalArgumentExceptionOnInvalidArguments() { |
| try { |
| mWifiServiceImpl.setWifiConnectedNetworkScorer(mAppBinder, null); |
| fail("expected IllegalArgumentException"); |
| } catch (IllegalArgumentException expected) { |
| } |
| } |
| |
| /** |
| * Verify that a call to clearWifiConnectedNetworkScorer throws a SecurityException if |
| * the caller does not have WIFI_UPDATE_USABILITY_STATS_SCORE permission. |
| */ |
| @Test |
| public void testClearNetworkScorerThrowsSecurityExceptionOnMissingPermissions() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission( |
| eq(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE), |
| eq("WifiService")); |
| try { |
| mWifiServiceImpl.clearWifiConnectedNetworkScorer(); |
| fail("expected SecurityException"); |
| } catch (SecurityException expected) { |
| } |
| } |
| |
| /** |
| * Verify that setWifiConnectedNetworkScorer sets scorer to {@link WifiScoreReport}. |
| */ |
| @Test |
| public void testSetWifiConnectedNetworkScorerAndVerify() throws Exception { |
| mWifiServiceImpl.setWifiConnectedNetworkScorer(mAppBinder, mWifiConnectedNetworkScorer); |
| mLooper.dispatchAll(); |
| verify(mWifiScoreReport).setWifiConnectedNetworkScorer(mAppBinder, |
| mWifiConnectedNetworkScorer); |
| } |
| |
| /** |
| * Verify that clearWifiConnectedNetworkScorer clears scorer from {@link WifiScoreReport}. |
| */ |
| @Test |
| public void testClearWifiConnectedNetworkScorerAndVerify() throws Exception { |
| mWifiServiceImpl.clearWifiConnectedNetworkScorer(); |
| mLooper.dispatchAll(); |
| verify(mWifiScoreReport).clearWifiConnectedNetworkScorer(); |
| } |
| |
| private long testGetSupportedFeaturesCaseForRtt( |
| long supportedFeaturesFromClientModeImpl, boolean rttDisabled) { |
| when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)).thenReturn( |
| !rttDisabled); |
| when(mClientModeImpl.syncGetSupportedFeatures(any())) |
| .thenReturn(supportedFeaturesFromClientModeImpl); |
| mLooper.startAutoDispatch(); |
| long supportedFeatures = mWifiServiceImpl.getSupportedFeatures(); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| return supportedFeatures; |
| } |
| |
| /** Verifies that syncGetSupportedFeatures() masks out capabilities based on system flags. */ |
| @Test |
| public void syncGetSupportedFeaturesForRtt() { |
| final long featureAware = WifiManager.WIFI_FEATURE_AWARE; |
| final long featureInfra = WifiManager.WIFI_FEATURE_INFRA; |
| final long featureD2dRtt = WifiManager.WIFI_FEATURE_D2D_RTT; |
| final long featureD2apRtt = WifiManager.WIFI_FEATURE_D2AP_RTT; |
| final long featureLongBits = 0x1000000000L; |
| |
| assertEquals(0, testGetSupportedFeaturesCaseForRtt(0, false)); |
| assertEquals(0, testGetSupportedFeaturesCaseForRtt(0, true)); |
| assertEquals(featureAware | featureInfra, |
| testGetSupportedFeaturesCaseForRtt(featureAware | featureInfra, false)); |
| assertEquals(featureAware | featureInfra, |
| testGetSupportedFeaturesCaseForRtt(featureAware | featureInfra, true)); |
| assertEquals(featureInfra | featureD2dRtt, |
| testGetSupportedFeaturesCaseForRtt(featureInfra | featureD2dRtt, false)); |
| assertEquals(featureInfra, |
| testGetSupportedFeaturesCaseForRtt(featureInfra | featureD2dRtt, true)); |
| assertEquals(featureInfra | featureD2apRtt, |
| testGetSupportedFeaturesCaseForRtt(featureInfra | featureD2apRtt, false)); |
| assertEquals(featureInfra, |
| testGetSupportedFeaturesCaseForRtt(featureInfra | featureD2apRtt, true)); |
| assertEquals(featureInfra | featureD2dRtt | featureD2apRtt, |
| testGetSupportedFeaturesCaseForRtt( |
| featureInfra | featureD2dRtt | featureD2apRtt, false)); |
| assertEquals(featureInfra, |
| testGetSupportedFeaturesCaseForRtt( |
| featureInfra | featureD2dRtt | featureD2apRtt, true)); |
| |
| assertEquals(featureLongBits | featureInfra | featureD2dRtt | featureD2apRtt, |
| testGetSupportedFeaturesCaseForRtt( |
| featureLongBits | featureInfra | featureD2dRtt | featureD2apRtt, false)); |
| assertEquals(featureLongBits | featureInfra, |
| testGetSupportedFeaturesCaseForRtt( |
| featureLongBits | featureInfra | featureD2dRtt | featureD2apRtt, true)); |
| } |
| |
| private long testGetSupportedFeaturesCaseForMacRandomization( |
| long supportedFeaturesFromClientModeImpl, boolean apMacRandomizationEnabled, |
| boolean staConnectedMacRandomizationEnabled, boolean p2pMacRandomizationEnabled) { |
| when(mResources.getBoolean( |
| R.bool.config_wifi_connected_mac_randomization_supported)) |
| .thenReturn(staConnectedMacRandomizationEnabled); |
| when(mResources.getBoolean( |
| R.bool.config_wifi_ap_mac_randomization_supported)) |
| .thenReturn(apMacRandomizationEnabled); |
| when(mResources.getBoolean( |
| R.bool.config_wifi_p2p_mac_randomization_supported)) |
| .thenReturn(p2pMacRandomizationEnabled); |
| when(mClientModeImpl.syncGetSupportedFeatures( |
| any())).thenReturn(supportedFeaturesFromClientModeImpl); |
| mLooper.startAutoDispatch(); |
| long supportedFeatures = mWifiServiceImpl.getSupportedFeatures(); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| return supportedFeatures; |
| } |
| |
| /** Verifies that syncGetSupportedFeatures() masks out capabilities based on system flags. */ |
| @Test |
| public void syncGetSupportedFeaturesForMacRandomization() { |
| final long featureStaConnectedMacRandomization = |
| WifiManager.WIFI_FEATURE_CONNECTED_RAND_MAC; |
| final long featureApMacRandomization = |
| WifiManager.WIFI_FEATURE_AP_RAND_MAC; |
| final long featureP2pMacRandomization = |
| WifiManager.WIFI_FEATURE_CONNECTED_RAND_MAC; |
| |
| assertEquals(featureStaConnectedMacRandomization | featureApMacRandomization |
| | featureP2pMacRandomization, |
| testGetSupportedFeaturesCaseForMacRandomization( |
| featureP2pMacRandomization, true, true, true)); |
| // p2p supported by HAL, but disabled by overlay. |
| assertEquals(featureStaConnectedMacRandomization | featureApMacRandomization, |
| testGetSupportedFeaturesCaseForMacRandomization( |
| featureP2pMacRandomization, true, true, false)); |
| assertEquals(featureStaConnectedMacRandomization | featureApMacRandomization, |
| testGetSupportedFeaturesCaseForMacRandomization(0, true, true, false)); |
| } |
| |
| /** |
| * Verifies that syncGetSupportedFeatures() adds capabilities based on interface |
| * combination. |
| */ |
| @Test |
| public void syncGetSupportedFeaturesForStaApConcurrency() { |
| long supportedFeaturesFromClientModeImpl = WifiManager.WIFI_FEATURE_OWE; |
| when(mClientModeImpl.syncGetSupportedFeatures( |
| any())).thenReturn(supportedFeaturesFromClientModeImpl); |
| |
| when(mActiveModeWarden.isStaApConcurrencySupported()) |
| .thenReturn(false); |
| mLooper.startAutoDispatch(); |
| assertEquals(supportedFeaturesFromClientModeImpl, |
| mWifiServiceImpl.getSupportedFeatures()); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| |
| when(mActiveModeWarden.isStaApConcurrencySupported()) |
| .thenReturn(true); |
| mLooper.startAutoDispatch(); |
| assertEquals(supportedFeaturesFromClientModeImpl | WifiManager.WIFI_FEATURE_AP_STA, |
| mWifiServiceImpl.getSupportedFeatures()); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| } |
| |
| @Test |
| public void testSetScanThrottleEnabledWithNetworkSettingsPermission() { |
| doNothing().when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| mWifiServiceImpl.setScanThrottleEnabled(true); |
| mLooper.dispatchAll(); |
| verify(mScanRequestProxy).setScanThrottleEnabled(true); |
| |
| mWifiServiceImpl.setScanThrottleEnabled(false); |
| mLooper.dispatchAll(); |
| verify(mScanRequestProxy).setScanThrottleEnabled(false); |
| } |
| |
| @Test(expected = SecurityException.class) |
| public void testSetScanThrottleEnabledWithNoNetworkSettingsPermission() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| |
| mWifiServiceImpl.setScanThrottleEnabled(true); |
| mLooper.dispatchAll(); |
| verify(mScanRequestProxy, never()).setScanThrottleEnabled(true); |
| } |
| |
| @Test |
| public void testIsScanThrottleEnabled() { |
| when(mScanRequestProxy.isScanThrottleEnabled()).thenReturn(true); |
| mLooper.startAutoDispatch(); |
| assertTrue(mWifiServiceImpl.isScanThrottleEnabled()); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| verify(mScanRequestProxy).isScanThrottleEnabled(); |
| } |
| |
| @Test |
| public void testSetAutoWakeupEnabledWithNetworkSettingsPermission() { |
| doNothing().when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| mWifiServiceImpl.setAutoWakeupEnabled(true); |
| mLooper.dispatchAll(); |
| verify(mWakeupController).setEnabled(true); |
| |
| mWifiServiceImpl.setAutoWakeupEnabled(false); |
| mLooper.dispatchAll(); |
| verify(mWakeupController).setEnabled(false); |
| } |
| |
| @Test(expected = SecurityException.class) |
| public void testSetAutoWakeupEnabledWithNoNetworkSettingsPermission() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| |
| mWifiServiceImpl.setAutoWakeupEnabled(true); |
| mLooper.dispatchAll(); |
| verify(mWakeupController, never()).setEnabled(true); |
| } |
| |
| @Test |
| public void testIsAutoWakeupEnabled() { |
| when(mWakeupController.isEnabled()).thenReturn(true); |
| mLooper.startAutoDispatch(); |
| assertTrue(mWifiServiceImpl.isAutoWakeupEnabled()); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| verify(mWakeupController).isEnabled(); |
| } |
| |
| @Test |
| public void testSetScanAlwaysAvailableWithNetworkSettingsPermission() { |
| doNothing().when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| mWifiServiceImpl.setScanAlwaysAvailable(true); |
| verify(mSettingsStore).handleWifiScanAlwaysAvailableToggled(true); |
| verify(mActiveModeWarden).scanAlwaysModeChanged(); |
| |
| mWifiServiceImpl.setScanAlwaysAvailable(false); |
| verify(mSettingsStore).handleWifiScanAlwaysAvailableToggled(false); |
| verify(mActiveModeWarden, times(2)).scanAlwaysModeChanged(); |
| } |
| |
| @Test(expected = SecurityException.class) |
| public void testSetScanAlwaysAvailableWithNoNetworkSettingsPermission() { |
| doThrow(new SecurityException()).when(mContext) |
| .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS), |
| eq("WifiService")); |
| |
| mWifiServiceImpl.setScanAlwaysAvailable(true); |
| verify(mSettingsStore, never()).handleWifiScanAlwaysAvailableToggled(anyBoolean()); |
| verify(mActiveModeWarden, never()).scanAlwaysModeChanged(); |
| } |
| |
| private List<ScanResult> createScanResultList() { |
| return Collections.singletonList(new ScanResult(WifiSsid.createFromAsciiEncoded(TEST_SSID), |
| TEST_SSID, TEST_BSSID, 1245, 0, TEST_CAP, -78, 2450, 1025, 22, 33, 20, 0, 0, true)); |
| } |
| } |