1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.net.wifi.nl80211; 17 18 import static org.junit.Assert.assertEquals; 19 import static org.junit.Assert.assertFalse; 20 import static org.junit.Assert.assertTrue; 21 import static org.mockito.ArgumentMatchers.argThat; 22 import static org.mockito.ArgumentMatchers.eq; 23 import static org.mockito.Mockito.any; 24 import static org.mockito.Mockito.anyInt; 25 import static org.mockito.Mockito.anyLong; 26 import static org.mockito.Mockito.doNothing; 27 import static org.mockito.Mockito.doReturn; 28 import static org.mockito.Mockito.mock; 29 import static org.mockito.Mockito.never; 30 import static org.mockito.Mockito.verify; 31 import static org.mockito.Mockito.when; 32 33 import android.app.AlarmManager; 34 import android.app.test.TestAlarmManager; 35 import android.content.BroadcastReceiver; 36 import android.content.Context; 37 import android.content.Intent; 38 import android.content.IntentFilter; 39 import android.net.ConnectivityManager; 40 import android.net.ConnectivityManager.NetworkCallback; 41 import android.net.Network; 42 import android.net.NetworkCapabilities; 43 import android.net.wifi.WifiConfiguration; 44 import android.net.wifi.WifiInfo; 45 import android.net.wifi.WifiManager; 46 import android.os.Handler; 47 import android.os.IPowerManager; 48 import android.os.IThermalService; 49 import android.os.PowerManager; 50 import android.os.test.TestLooper; 51 52 import androidx.test.filters.SmallTest; 53 54 import org.junit.Before; 55 import org.junit.Test; 56 import org.mockito.ArgumentCaptor; 57 import org.mockito.Mock; 58 import org.mockito.MockitoAnnotations; 59 60 import java.util.HashSet; 61 import java.util.Set; 62 63 /** 64 * Unit tests for {@link android.net.wifi.nl80211.InstantWifi}. 65 */ 66 @SmallTest 67 public class InstantWifiTest { 68 @Mock private Context mContext; 69 @Mock private ConnectivityManager mMockConnectivityManager; 70 @Mock private WifiManager mMockWifiManager; 71 @Mock private Network mMockWifiNetwork; 72 @Mock private WifiInfo mMockWifiInfo; 73 @Mock private WifiConfiguration mMockWifiConfiguration; 74 @Mock private IPowerManager mPowerManagerService; 75 private InstantWifi mInstantWifi; 76 private TestLooper mLooper; 77 private Handler mHandler; 78 private TestAlarmManager mTestAlarmManager; 79 private AlarmManager mAlarmManager; 80 private PowerManager mMockPowerManager; 81 82 private final ArgumentCaptor<NetworkCallback> mWifiNetworkCallbackCaptor = 83 ArgumentCaptor.forClass(NetworkCallback.class); 84 private final ArgumentCaptor<BroadcastReceiver> mScreenBroadcastReceiverCaptor = 85 ArgumentCaptor.forClass(BroadcastReceiver.class); 86 private final ArgumentCaptor<BroadcastReceiver> mWifiStateBroadcastReceiverCaptor = 87 ArgumentCaptor.forClass(BroadcastReceiver.class); 88 89 private static final int TEST_NETWORK_ID = 1; 90 private static final int TEST_24G_FREQUENCY = 2412; 91 private static final int TEST_5G_FREQUENCY = 5745; 92 private long mTimeOffsetMs = 0; 93 94 private class InstantWifiSpy extends InstantWifi { InstantWifiSpy(Context context, AlarmManager alarmManager, Handler handler)95 InstantWifiSpy(Context context, AlarmManager alarmManager, Handler handler) { 96 super(context, alarmManager, handler); 97 } 98 99 @Override getMockableElapsedRealtime()100 protected long getMockableElapsedRealtime() { 101 return mTimeOffsetMs; 102 } 103 } 104 105 @Before setUp()106 public void setUp() throws Exception { 107 MockitoAnnotations.initMocks(this); 108 109 mLooper = new TestLooper(); 110 mHandler = new Handler(mLooper.getLooper()); 111 112 mTestAlarmManager = new TestAlarmManager(); 113 mAlarmManager = mTestAlarmManager.getAlarmManager(); 114 when(mContext.getSystemServiceName(AlarmManager.class)).thenReturn(Context.ALARM_SERVICE); 115 when(mContext.getSystemService(AlarmManager.class)).thenReturn(mAlarmManager); 116 when(mContext.getSystemServiceName(WifiManager.class)).thenReturn(Context.WIFI_SERVICE); 117 when(mContext.getSystemService(WifiManager.class)).thenReturn(mMockWifiManager); 118 when(mContext.getSystemServiceName(ConnectivityManager.class)) 119 .thenReturn(Context.CONNECTIVITY_SERVICE); 120 when(mContext.getSystemService(ConnectivityManager.class)) 121 .thenReturn(mMockConnectivityManager); 122 mMockPowerManager = new PowerManager(mContext, mPowerManagerService, 123 mock(IThermalService.class), mHandler); 124 when(mContext.getSystemServiceName(PowerManager.class)).thenReturn(Context.POWER_SERVICE); 125 when(mContext.getSystemService(PowerManager.class)).thenReturn(mMockPowerManager); 126 when(mPowerManagerService.isInteractive()).thenReturn(true); 127 128 doReturn(mMockWifiInfo).when(mMockWifiInfo).makeCopy(anyLong()); 129 mTimeOffsetMs = 0; 130 mInstantWifi = new InstantWifiSpy(mContext, mAlarmManager, mHandler); 131 verifyInstantWifiInitialization(); 132 } 133 verifyInstantWifiInitialization()134 private void verifyInstantWifiInitialization() { 135 verify(mMockConnectivityManager).registerNetworkCallback(any(), 136 mWifiNetworkCallbackCaptor.capture()); 137 verify(mContext).registerReceiver(mScreenBroadcastReceiverCaptor.capture(), 138 argThat((IntentFilter filter) -> 139 filter.hasAction(Intent.ACTION_SCREEN_ON) 140 && filter.hasAction(Intent.ACTION_SCREEN_OFF)), eq(null), any()); 141 142 verify(mContext).registerReceiver(mWifiStateBroadcastReceiverCaptor.capture(), 143 argThat((IntentFilter filter) -> 144 filter.hasAction(WifiManager.WIFI_STATE_CHANGED_ACTION)), eq(null), any()); 145 } 146 mockWifiConnectedEvent(int networkId, int connectedFrequency)147 private void mockWifiConnectedEvent(int networkId, int connectedFrequency) { 148 // Send wifi connected event 149 NetworkCapabilities mockWifiNetworkCapabilities = 150 new NetworkCapabilities.Builder().setTransportInfo(mMockWifiInfo).build(); 151 mMockWifiConfiguration.networkId = networkId; 152 when(mMockWifiManager.getPrivilegedConnectedNetwork()).thenReturn(mMockWifiConfiguration); 153 when(mMockWifiInfo.getFrequency()).thenReturn(connectedFrequency); 154 mWifiNetworkCallbackCaptor.getValue().onCapabilitiesChanged(mMockWifiNetwork, 155 mockWifiNetworkCapabilities); 156 mLooper.dispatchAll(); 157 } 158 mockWifiOnScreenOnBroadcast(boolean isWifiOn, boolean isScreenOn)159 private void mockWifiOnScreenOnBroadcast(boolean isWifiOn, boolean isScreenOn) 160 throws Exception { 161 // Send Wifi On broadcast 162 Intent wifiOnIntent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 163 wifiOnIntent.putExtra(WifiManager.EXTRA_WIFI_STATE, 164 isWifiOn ? WifiManager.WIFI_STATE_ENABLED : WifiManager.WIFI_STATE_DISABLED); 165 mWifiStateBroadcastReceiverCaptor.getValue().onReceive(mContext, wifiOnIntent); 166 mLooper.dispatchAll(); 167 // Send Screen On broadcast 168 Intent screenOnIntent = 169 new Intent(isScreenOn ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF); 170 mScreenBroadcastReceiverCaptor.getValue().onReceive(mContext, screenOnIntent); 171 mLooper.dispatchAll(); 172 when(mMockWifiManager.isWifiEnabled()).thenReturn(isWifiOn); 173 when(mPowerManagerService.isInteractive()).thenReturn(isScreenOn); 174 } 175 176 @Test testisUsePredictedScanningChannels()177 public void testisUsePredictedScanningChannels() throws Exception { 178 assertFalse(mInstantWifi.isUsePredictedScanningChannels()); 179 mockWifiOnScreenOnBroadcast(true /* isWifiOn */, false /* isScreenOn */); 180 assertFalse(mInstantWifi.isUsePredictedScanningChannels()); 181 mockWifiOnScreenOnBroadcast(false /* isWifiOn */, true /* isScreenOn */); 182 assertFalse(mInstantWifi.isUsePredictedScanningChannels()); 183 mockWifiOnScreenOnBroadcast(true /* isWifiOn */, true /* isScreenOn */); 184 assertFalse(mInstantWifi.isUsePredictedScanningChannels()); 185 // Send wifi connected event 186 mockWifiConnectedEvent(TEST_NETWORK_ID, TEST_24G_FREQUENCY); 187 assertFalse(mInstantWifi.isUsePredictedScanningChannels()); 188 // Send wifi disconnect 189 mWifiNetworkCallbackCaptor.getValue().onLost(mMockWifiNetwork); 190 assertTrue(mInstantWifi.isUsePredictedScanningChannels()); 191 // Shift time to make it expired 192 mTimeOffsetMs = 1100; 193 assertFalse(mInstantWifi.isUsePredictedScanningChannels()); 194 } 195 196 @Test testGetPredictedScanningChannels()197 public void testGetPredictedScanningChannels() throws Exception { 198 mockWifiOnScreenOnBroadcast(true /* isWifiOn */, true /* isScreenOn */); 199 // Send wifi connected event on T0 200 mockWifiConnectedEvent(TEST_NETWORK_ID, TEST_24G_FREQUENCY); 201 // Send wifi disconnect 202 mWifiNetworkCallbackCaptor.getValue().onLost(mMockWifiNetwork); 203 assertTrue(mInstantWifi.isUsePredictedScanningChannels()); 204 assertTrue(mInstantWifi.getPredictedScanningChannels().contains(TEST_24G_FREQUENCY)); 205 mTimeOffsetMs += 1000; // T1 = 1000 ms 206 // Send wifi connected event 207 mockWifiConnectedEvent(TEST_NETWORK_ID + 1, TEST_5G_FREQUENCY); 208 // Send wifi disconnect 209 mWifiNetworkCallbackCaptor.getValue().onLost(mMockWifiNetwork); 210 // isUsePredictedScanningChannels is false since wifi on & screen on is expired 211 assertFalse(mInstantWifi.isUsePredictedScanningChannels()); 212 // Override the Wifi On & Screen on time 213 mockWifiOnScreenOnBroadcast(true /* isWifiOn */, true /* isScreenOn */); 214 assertTrue(mInstantWifi.getPredictedScanningChannels().contains(TEST_5G_FREQUENCY)); 215 mTimeOffsetMs += 7 * 24 * 60 * 60 * 1000; // Make T0 expired 216 // Override the Wifi On & Screen on time 217 mockWifiOnScreenOnBroadcast(true /* isWifiOn */, true /* isScreenOn */); 218 assertFalse(mInstantWifi.getPredictedScanningChannels().contains(TEST_24G_FREQUENCY)); 219 assertTrue(mInstantWifi.getPredictedScanningChannels().contains(TEST_5G_FREQUENCY)); 220 } 221 222 @Test testOverrideFreqsForSingleScanSettings()223 public void testOverrideFreqsForSingleScanSettings() throws Exception { 224 mockWifiOnScreenOnBroadcast(true /* isWifiOn */, true /* isScreenOn */); 225 // Send wifi connected event 226 mockWifiConnectedEvent(TEST_NETWORK_ID, TEST_24G_FREQUENCY); 227 assertFalse(mInstantWifi.isUsePredictedScanningChannels()); 228 // Send wifi disconnect 229 mWifiNetworkCallbackCaptor.getValue().onLost(mMockWifiNetwork); 230 assertTrue(mInstantWifi.isUsePredictedScanningChannels()); 231 232 final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor = 233 ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class); 234 doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(), 235 alarmListenerCaptor.capture(), any()); 236 Set<Integer> testFreqs = Set.of( 237 TEST_24G_FREQUENCY, TEST_5G_FREQUENCY); 238 SingleScanSettings testSingleScanSettings = new SingleScanSettings(); 239 mInstantWifi.overrideFreqsForSingleScanSettingsIfNecessary( 240 testSingleScanSettings, new HashSet<Integer>()); 241 mInstantWifi.overrideFreqsForSingleScanSettingsIfNecessary( 242 testSingleScanSettings, null); 243 mInstantWifi.overrideFreqsForSingleScanSettingsIfNecessary(null, null); 244 verify(mAlarmManager, never()).set(anyInt(), anyLong(), any(), any(), any()); 245 mInstantWifi.overrideFreqsForSingleScanSettingsIfNecessary(testSingleScanSettings, 246 testFreqs); 247 verify(mAlarmManager).set(anyInt(), anyLong(), any(), any(), any()); 248 Set<Integer> overridedFreqs = new HashSet<Integer>(); 249 for (ChannelSettings channel : testSingleScanSettings.channelSettings) { 250 overridedFreqs.add(channel.frequency); 251 } 252 assertEquals(testFreqs, overridedFreqs); 253 alarmListenerCaptor.getValue().onAlarm(); 254 verify(mMockWifiManager).startScan(); 255 } 256 } 257