[DO NOT MERGE]wifi: scan enhancement

Bug: 282660969
Test: unit test & manual test

Change-Id: I2b306b4d1793bffc3b0227043fd774018ba4e675
Merged-In: I2f9cdb638dcb1f98113f39b60a96b0d1e8b22d8c
Merged-In: I85b8c1e94d6270006cce866e13a1879f55161cd1
This commit is contained in:
Les Lee
2023-04-06 22:14:08 +08:00
parent 0da8b900cb
commit 190061b796
4 changed files with 650 additions and 1 deletions

View File

@@ -0,0 +1,318 @@
/*
* Copyright (C) 2023 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 android.net.wifi.nl80211;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlarmManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
/**
* @hide
*/
public class InstantWifi {
private static final String INSTANT_WIFI_TAG = "InstantWifi";
private static final int OVERRIDED_SCAN_CONNECTION_TIMEOUT_MS = 1000;
private static final int WIFI_NETWORK_EXPIRED_MS = 7 * 24 * 60 * 60 * 1000; // a week
private static final String NO_CONNECTION_TIMEOUT_ALARM_TAG =
INSTANT_WIFI_TAG + " No Connection Timeout";
private Context mContext;
private AlarmManager mAlarmManager;
private Handler mEventHandler;
private ConnectivityManager mConnectivityManager;
private WifiManager mWifiManager;
private PowerManager mPowerManager;
private long mLastWifiOnSinceBootMs;
private long mLastScreenOnSinceBootMs;
private boolean mIsWifiConnected = false;
private boolean mScreenOn = false;
private boolean mWifiEnabled = false;
private boolean mIsNoConnectionAlarmSet = false;
private ArrayList<WifiNetwork> mConnectedWifiNetworkList = new ArrayList<>();
private AlarmManager.OnAlarmListener mNoConnectionTimeoutCallback =
new AlarmManager.OnAlarmListener() {
public void onAlarm() {
Log.i(INSTANT_WIFI_TAG, "Timed out waiting for wifi connection");
mIsNoConnectionAlarmSet = false;
mWifiManager.startScan();
}
};
public InstantWifi(Context context, AlarmManager alarmManager, Handler eventHandler) {
mContext = context;
mAlarmManager = alarmManager;
mEventHandler = eventHandler;
mWifiManager = mContext.getSystemService(WifiManager.class);
mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
mConnectivityManager.registerNetworkCallback(
new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build(), new WifiNetworkCallback());
// System power service was initialized before wifi nl80211 service.
mPowerManager = mContext.getSystemService(PowerManager.class);
IntentFilter screenEventfilter = new IntentFilter();
screenEventfilter.addAction(Intent.ACTION_SCREEN_ON);
screenEventfilter.addAction(Intent.ACTION_SCREEN_OFF);
mContext.registerReceiver(
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_SCREEN_ON)) {
if (!mScreenOn) {
mLastScreenOnSinceBootMs = getMockableElapsedRealtime();
}
mScreenOn = true;
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
mScreenOn = false;
}
Log.d(INSTANT_WIFI_TAG, "mScreenOn is changed to " + mScreenOn);
}
}, screenEventfilter, null, mEventHandler);
mScreenOn = mPowerManager.isInteractive();
mContext.registerReceiver(
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN);
mWifiEnabled = state == WifiManager.WIFI_STATE_ENABLED;
if (mWifiEnabled) {
mLastWifiOnSinceBootMs = getMockableElapsedRealtime();
}
Log.d(INSTANT_WIFI_TAG, "mWifiEnabled is changed to " + mWifiEnabled);
}
},
new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION),
null, mEventHandler);
}
@VisibleForTesting
protected long getMockableElapsedRealtime() {
return SystemClock.elapsedRealtime();
}
private class WifiNetwork {
private final int mNetId;
private Set<Integer> mConnectedFrequencies = new HashSet<Integer>();
private int[] mLastTwoConnectedFrequencies = new int[2];
private long mLastConnectedTimeMillis;
WifiNetwork(int netId) {
mNetId = netId;
}
public int getNetId() {
return mNetId;
}
public boolean addConnectedFrequency(int channelFrequency) {
mLastConnectedTimeMillis = getMockableElapsedRealtime();
if (mLastTwoConnectedFrequencies[0] != channelFrequency
&& mLastTwoConnectedFrequencies[1] != channelFrequency) {
mLastTwoConnectedFrequencies[0] = mLastTwoConnectedFrequencies[1];
mLastTwoConnectedFrequencies[1] = channelFrequency;
}
return mConnectedFrequencies.add(channelFrequency);
}
public Set<Integer> getConnectedFrequencies() {
return mConnectedFrequencies;
}
public int[] getLastTwoConnectedFrequencies() {
if ((getMockableElapsedRealtime() - mLastConnectedTimeMillis)
> WIFI_NETWORK_EXPIRED_MS) {
return new int[0];
}
return mLastTwoConnectedFrequencies;
}
public long getLastConnectedTimeMillis() {
return mLastConnectedTimeMillis;
}
}
private class WifiNetworkCallback extends NetworkCallback {
@Override
public void onAvailable(@NonNull Network network) {
}
@Override
public void onCapabilitiesChanged(Network network,
NetworkCapabilities networkCapabilities) {
if (networkCapabilities != null && network != null) {
WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo();
if (wifiInfo == null || mWifiManager == null) {
return;
}
WifiConfiguration config = mWifiManager.getPrivilegedConnectedNetwork();
if (config == null) {
return;
}
final int currentNetworkId = config.networkId;
final int connectecFrequency = wifiInfo.getFrequency();
if (connectecFrequency < 0 || currentNetworkId < 0) {
return;
}
mIsWifiConnected = true;
if (mIsNoConnectionAlarmSet) {
mAlarmManager.cancel(mNoConnectionTimeoutCallback);
}
Log.d(INSTANT_WIFI_TAG, "Receive Wifi is connected, freq = " + connectecFrequency
+ " and currentNetworkId : " + currentNetworkId
+ ", wifiinfo = " + wifiInfo);
boolean isExist = false;
for (WifiNetwork wifiNetwork : mConnectedWifiNetworkList) {
if (wifiNetwork.getNetId() == currentNetworkId) {
if (wifiNetwork.addConnectedFrequency(connectecFrequency)) {
Log.d(INSTANT_WIFI_TAG, "Update connected frequency: "
+ connectecFrequency + " to Network currentNetworkId : "
+ currentNetworkId);
}
isExist = true;
}
}
if (!isExist) {
WifiNetwork currentNetwork = new WifiNetwork(currentNetworkId);
currentNetwork.addConnectedFrequency(connectecFrequency);
if (mConnectedWifiNetworkList.size() < 5) {
mConnectedWifiNetworkList.add(currentNetwork);
} else {
ArrayList<WifiNetwork> lastConnectedWifiNetworkList = new ArrayList<>();
WifiNetwork legacyNetwork = mConnectedWifiNetworkList.get(0);
for (WifiNetwork connectedNetwork : mConnectedWifiNetworkList) {
if (connectedNetwork.getNetId() == legacyNetwork.getNetId()) {
continue;
}
// Keep the used recently network in the last connected list
if (connectedNetwork.getLastConnectedTimeMillis()
> legacyNetwork.getLastConnectedTimeMillis()) {
lastConnectedWifiNetworkList.add(connectedNetwork);
} else {
lastConnectedWifiNetworkList.add(legacyNetwork);
legacyNetwork = connectedNetwork;
}
}
mConnectedWifiNetworkList = lastConnectedWifiNetworkList;
}
}
}
}
@Override
public void onLost(@NonNull Network network) {
mIsWifiConnected = false;
}
}
/**
* Returns whether or not the scan freqs should be overrided by using predicted channels.
*/
public boolean isUsePredictedScanningChannels() {
if (mIsWifiConnected || mConnectedWifiNetworkList.size() == 0
|| !mWifiManager.isWifiEnabled() || !mPowerManager.isInteractive()) {
return false;
}
if (!mWifiEnabled || !mScreenOn) {
Log.d(INSTANT_WIFI_TAG, "WiFi/Screen State mis-match, run instant Wifi anyway!");
return true;
}
return (((getMockableElapsedRealtime() - mLastWifiOnSinceBootMs)
< OVERRIDED_SCAN_CONNECTION_TIMEOUT_MS)
|| ((getMockableElapsedRealtime() - mLastScreenOnSinceBootMs)
< OVERRIDED_SCAN_CONNECTION_TIMEOUT_MS));
}
/**
* Overrides the frequenies in SingleScanSetting
*
* @param settings the SingleScanSettings will be overrided.
* @param freqs new frequencies of SingleScanSettings
*/
@Nullable
public void overrideFreqsForSingleScanSettingsIfNecessary(
@Nullable SingleScanSettings settings, @Nullable Set<Integer> freqs) {
if (!isUsePredictedScanningChannels() || settings == null || freqs == null
|| freqs.size() == 0) {
return;
}
if (settings.channelSettings == null) {
settings.channelSettings = new ArrayList<>();
} else {
settings.channelSettings.clear();
}
for (int freq : freqs) {
if (freq > 0) {
ChannelSettings channel = new ChannelSettings();
channel.frequency = freq;
settings.channelSettings.add(channel);
}
}
// Monitor connection after last override scan request.
if (mIsNoConnectionAlarmSet) {
mAlarmManager.cancel(mNoConnectionTimeoutCallback);
}
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
getMockableElapsedRealtime() + OVERRIDED_SCAN_CONNECTION_TIMEOUT_MS,
NO_CONNECTION_TIMEOUT_ALARM_TAG, mNoConnectionTimeoutCallback, mEventHandler);
mIsNoConnectionAlarmSet = true;
}
/**
* Returns the predicted scanning chcnnels set.
*/
@NonNull
public Set<Integer> getPredictedScanningChannels() {
Set<Integer> predictedScanChannels = new HashSet<>();
if (!isUsePredictedScanningChannels()) {
Log.d(INSTANT_WIFI_TAG, "Drop, size: " + mConnectedWifiNetworkList.size());
return predictedScanChannels;
}
for (WifiNetwork network : mConnectedWifiNetworkList) {
for (int connectedFrequency : network.getLastTwoConnectedFrequencies()) {
if (connectedFrequency > 0) {
predictedScanChannels.add(connectedFrequency);
Log.d(INSTANT_WIFI_TAG, "Add channel: " + connectedFrequency
+ " to predicted channel");
}
}
}
return predictedScanChannels;
}
}

View File

@@ -105,6 +105,8 @@ public class WifiNl80211Manager {
// Cached wificond binder handlers.
private IWificond mWificond;
private Context mContext;
private InstantWifi mInstantWifi;
private WificondEventHandler mWificondEventHandler = new WificondEventHandler();
private HashMap<String, IClientInterface> mClientInterfaces = new HashMap<>();
private HashMap<String, IApInterface> mApInterfaces = new HashMap<>();
@@ -172,6 +174,12 @@ public class WifiNl80211Manager {
void onPnoRequestFailed();
}
/** @hide */
@VisibleForTesting
protected InstantWifi getInstantWifiMockable() {
return mInstantWifi;
}
/** @hide */
@VisibleForTesting
public class WificondEventHandler extends IWificondEventCallback.Stub {
@@ -419,6 +427,7 @@ public class WifiNl80211Manager {
public WifiNl80211Manager(Context context) {
mAlarmManager = context.getSystemService(AlarmManager.class);
mEventHandler = new Handler(context.getMainLooper());
mContext = context;
}
/**
@@ -434,6 +443,7 @@ public class WifiNl80211Manager {
if (mWificond == null) {
Log.e(TAG, "Failed to get reference to wificond");
}
mContext = context;
}
/** @hide */
@@ -441,6 +451,7 @@ public class WifiNl80211Manager {
public WifiNl80211Manager(Context context, IWificond wificond) {
this(context);
mWificond = wificond;
mContext = context;
}
/** @hide */
@@ -744,6 +755,9 @@ public class WifiNl80211Manager {
Log.e(TAG, "Failed to refresh wificond scanner due to remote exception");
}
if (getInstantWifiMockable() == null) {
mInstantWifi = new InstantWifi(mContext, mAlarmManager, mEventHandler);
}
return true;
}
@@ -1071,6 +1085,10 @@ public class WifiNl80211Manager {
if (settings == null) {
return false;
}
if (getInstantWifiMockable() != null) {
getInstantWifiMockable().overrideFreqsForSingleScanSettingsIfNecessary(settings,
getInstantWifiMockable().getPredictedScanningChannels());
}
try {
return scannerImpl.scan(settings);
} catch (RemoteException e1) {
@@ -1115,6 +1133,10 @@ public class WifiNl80211Manager {
if (settings == null) {
return WifiScanner.REASON_INVALID_ARGS;
}
if (getInstantWifiMockable() != null) {
getInstantWifiMockable().overrideFreqsForSingleScanSettingsIfNecessary(settings,
getInstantWifiMockable().getPredictedScanningChannels());
}
try {
int status = scannerImpl.scanRequest(settings);
return toFrameworkScanStatusCode(status);

View File

@@ -0,0 +1,256 @@
/*
* Copyright (C) 2023 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 android.net.wifi.nl80211;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.AlarmManager;
import android.app.test.TestAlarmManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.IPowerManager;
import android.os.IThermalService;
import android.os.PowerManager;
import android.os.test.TestLooper;
import androidx.test.filters.SmallTest;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.HashSet;
import java.util.Set;
/**
* Unit tests for {@link android.net.wifi.nl80211.InstantWifi}.
*/
@SmallTest
public class InstantWifiTest {
@Mock private Context mContext;
@Mock private ConnectivityManager mMockConnectivityManager;
@Mock private WifiManager mMockWifiManager;
@Mock private Network mMockWifiNetwork;
@Mock private WifiInfo mMockWifiInfo;
@Mock private WifiConfiguration mMockWifiConfiguration;
@Mock private IPowerManager mPowerManagerService;
private InstantWifi mInstantWifi;
private TestLooper mLooper;
private Handler mHandler;
private TestAlarmManager mTestAlarmManager;
private AlarmManager mAlarmManager;
private PowerManager mMockPowerManager;
private final ArgumentCaptor<NetworkCallback> mWifiNetworkCallbackCaptor =
ArgumentCaptor.forClass(NetworkCallback.class);
private final ArgumentCaptor<BroadcastReceiver> mScreenBroadcastReceiverCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
private final ArgumentCaptor<BroadcastReceiver> mWifiStateBroadcastReceiverCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
private static final int TEST_NETWORK_ID = 1;
private static final int TEST_24G_FREQUENCY = 2412;
private static final int TEST_5G_FREQUENCY = 5745;
private long mTimeOffsetMs = 0;
private class InstantWifiSpy extends InstantWifi {
InstantWifiSpy(Context context, AlarmManager alarmManager, Handler handler) {
super(context, alarmManager, handler);
}
@Override
protected long getMockableElapsedRealtime() {
return mTimeOffsetMs;
}
}
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mLooper = new TestLooper();
mHandler = new Handler(mLooper.getLooper());
mTestAlarmManager = new TestAlarmManager();
mAlarmManager = mTestAlarmManager.getAlarmManager();
when(mContext.getSystemServiceName(AlarmManager.class)).thenReturn(Context.ALARM_SERVICE);
when(mContext.getSystemService(AlarmManager.class)).thenReturn(mAlarmManager);
when(mContext.getSystemServiceName(WifiManager.class)).thenReturn(Context.WIFI_SERVICE);
when(mContext.getSystemService(WifiManager.class)).thenReturn(mMockWifiManager);
when(mContext.getSystemServiceName(ConnectivityManager.class))
.thenReturn(Context.CONNECTIVITY_SERVICE);
when(mContext.getSystemService(ConnectivityManager.class))
.thenReturn(mMockConnectivityManager);
mMockPowerManager = new PowerManager(mContext, mPowerManagerService,
mock(IThermalService.class), mHandler);
when(mContext.getSystemServiceName(PowerManager.class)).thenReturn(Context.POWER_SERVICE);
when(mContext.getSystemService(PowerManager.class)).thenReturn(mMockPowerManager);
when(mPowerManagerService.isInteractive()).thenReturn(true);
doReturn(mMockWifiInfo).when(mMockWifiInfo).makeCopy(anyLong());
mTimeOffsetMs = 0;
mInstantWifi = new InstantWifiSpy(mContext, mAlarmManager, mHandler);
verifyInstantWifiInitialization();
}
private void verifyInstantWifiInitialization() {
verify(mMockConnectivityManager).registerNetworkCallback(any(),
mWifiNetworkCallbackCaptor.capture());
verify(mContext).registerReceiver(mScreenBroadcastReceiverCaptor.capture(),
argThat((IntentFilter filter) ->
filter.hasAction(Intent.ACTION_SCREEN_ON)
&& filter.hasAction(Intent.ACTION_SCREEN_OFF)), eq(null), any());
verify(mContext).registerReceiver(mWifiStateBroadcastReceiverCaptor.capture(),
argThat((IntentFilter filter) ->
filter.hasAction(WifiManager.WIFI_STATE_CHANGED_ACTION)), eq(null), any());
}
private void mockWifiConnectedEvent(int networkId, int connectedFrequency) {
// Send wifi connected event
NetworkCapabilities mockWifiNetworkCapabilities =
new NetworkCapabilities.Builder().setTransportInfo(mMockWifiInfo).build();
mMockWifiConfiguration.networkId = networkId;
when(mMockWifiManager.getPrivilegedConnectedNetwork()).thenReturn(mMockWifiConfiguration);
when(mMockWifiInfo.getFrequency()).thenReturn(connectedFrequency);
mWifiNetworkCallbackCaptor.getValue().onCapabilitiesChanged(mMockWifiNetwork,
mockWifiNetworkCapabilities);
mLooper.dispatchAll();
}
private void mockWifiOnScreenOnBroadcast(boolean isWifiOn, boolean isScreenOn)
throws Exception {
// Send Wifi On broadcast
Intent wifiOnIntent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
wifiOnIntent.putExtra(WifiManager.EXTRA_WIFI_STATE,
isWifiOn ? WifiManager.WIFI_STATE_ENABLED : WifiManager.WIFI_STATE_DISABLED);
mWifiStateBroadcastReceiverCaptor.getValue().onReceive(mContext, wifiOnIntent);
mLooper.dispatchAll();
// Send Screen On broadcast
Intent screenOnIntent =
new Intent(isScreenOn ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF);
mScreenBroadcastReceiverCaptor.getValue().onReceive(mContext, screenOnIntent);
mLooper.dispatchAll();
when(mMockWifiManager.isWifiEnabled()).thenReturn(isWifiOn);
when(mPowerManagerService.isInteractive()).thenReturn(isScreenOn);
}
@Test
public void testisUsePredictedScanningChannels() throws Exception {
assertFalse(mInstantWifi.isUsePredictedScanningChannels());
mockWifiOnScreenOnBroadcast(true /* isWifiOn */, false /* isScreenOn */);
assertFalse(mInstantWifi.isUsePredictedScanningChannels());
mockWifiOnScreenOnBroadcast(false /* isWifiOn */, true /* isScreenOn */);
assertFalse(mInstantWifi.isUsePredictedScanningChannels());
mockWifiOnScreenOnBroadcast(true /* isWifiOn */, true /* isScreenOn */);
assertFalse(mInstantWifi.isUsePredictedScanningChannels());
// Send wifi connected event
mockWifiConnectedEvent(TEST_NETWORK_ID, TEST_24G_FREQUENCY);
assertFalse(mInstantWifi.isUsePredictedScanningChannels());
// Send wifi disconnect
mWifiNetworkCallbackCaptor.getValue().onLost(mMockWifiNetwork);
assertTrue(mInstantWifi.isUsePredictedScanningChannels());
// Shift time to make it expired
mTimeOffsetMs = 1100;
assertFalse(mInstantWifi.isUsePredictedScanningChannels());
}
@Test
public void testGetPredictedScanningChannels() throws Exception {
mockWifiOnScreenOnBroadcast(true /* isWifiOn */, true /* isScreenOn */);
// Send wifi connected event on T0
mockWifiConnectedEvent(TEST_NETWORK_ID, TEST_24G_FREQUENCY);
// Send wifi disconnect
mWifiNetworkCallbackCaptor.getValue().onLost(mMockWifiNetwork);
assertTrue(mInstantWifi.isUsePredictedScanningChannels());
assertTrue(mInstantWifi.getPredictedScanningChannels().contains(TEST_24G_FREQUENCY));
mTimeOffsetMs += 1000; // T1 = 1000 ms
// Send wifi connected event
mockWifiConnectedEvent(TEST_NETWORK_ID + 1, TEST_5G_FREQUENCY);
// Send wifi disconnect
mWifiNetworkCallbackCaptor.getValue().onLost(mMockWifiNetwork);
// isUsePredictedScanningChannels is false since wifi on & screen on is expired
assertFalse(mInstantWifi.isUsePredictedScanningChannels());
// Override the Wifi On & Screen on time
mockWifiOnScreenOnBroadcast(true /* isWifiOn */, true /* isScreenOn */);
assertTrue(mInstantWifi.getPredictedScanningChannels().contains(TEST_5G_FREQUENCY));
mTimeOffsetMs += 7 * 24 * 60 * 60 * 1000; // Make T0 expired
// Override the Wifi On & Screen on time
mockWifiOnScreenOnBroadcast(true /* isWifiOn */, true /* isScreenOn */);
assertFalse(mInstantWifi.getPredictedScanningChannels().contains(TEST_24G_FREQUENCY));
assertTrue(mInstantWifi.getPredictedScanningChannels().contains(TEST_5G_FREQUENCY));
}
@Test
public void testOverrideFreqsForSingleScanSettings() throws Exception {
mockWifiOnScreenOnBroadcast(true /* isWifiOn */, true /* isScreenOn */);
// Send wifi connected event
mockWifiConnectedEvent(TEST_NETWORK_ID, TEST_24G_FREQUENCY);
assertFalse(mInstantWifi.isUsePredictedScanningChannels());
// Send wifi disconnect
mWifiNetworkCallbackCaptor.getValue().onLost(mMockWifiNetwork);
assertTrue(mInstantWifi.isUsePredictedScanningChannels());
final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor =
ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
alarmListenerCaptor.capture(), any());
Set<Integer> testFreqs = Set.of(
TEST_24G_FREQUENCY, TEST_5G_FREQUENCY);
SingleScanSettings testSingleScanSettings = new SingleScanSettings();
mInstantWifi.overrideFreqsForSingleScanSettingsIfNecessary(
testSingleScanSettings, new HashSet<Integer>());
mInstantWifi.overrideFreqsForSingleScanSettingsIfNecessary(
testSingleScanSettings, null);
mInstantWifi.overrideFreqsForSingleScanSettingsIfNecessary(null, null);
verify(mAlarmManager, never()).set(anyInt(), anyLong(), any(), any(), any());
mInstantWifi.overrideFreqsForSingleScanSettingsIfNecessary(testSingleScanSettings,
testFreqs);
verify(mAlarmManager).set(anyInt(), anyLong(), any(), any(), any());
Set<Integer> overridedFreqs = new HashSet<Integer>();
for (ChannelSettings channel : testSingleScanSettings.channelSettings) {
overridedFreqs.add(channel.frequency);
}
assertEquals(testFreqs, overridedFreqs);
alarmListenerCaptor.getValue().onAlarm();
verify(mMockWifiManager).startScan();
}
}

View File

@@ -18,6 +18,7 @@ package android.net.wifi.nl80211;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -26,6 +27,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
@@ -37,6 +39,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.AlarmManager;
import android.app.test.MockAnswerUtil.AnswerWithArguments;
import android.app.test.TestAlarmManager;
import android.content.Context;
import android.net.MacAddress;
@@ -104,6 +107,9 @@ public class WifiNl80211ManagerTest {
private WifiNl80211Manager.CountryCodeChangedListener mCountryCodeChangedListener2;
@Mock
private Context mContext;
@Mock
private InstantWifi mMockInstantWifi;
private TestLooper mLooper;
private TestAlarmManager mTestAlarmManager;
private AlarmManager mAlarmManager;
@@ -167,6 +173,17 @@ public class WifiNl80211ManagerTest {
0x00, 0x00
};
private class WifiNl80211ManagerSpy extends WifiNl80211Manager {
WifiNl80211ManagerSpy(Context context, IWificond wificond) {
super(context, wificond);
}
@Override
protected InstantWifi getInstantWifiMockable() {
return mMockInstantWifi;
}
}
@Before
public void setUp() throws Exception {
// Setup mocks for successful WificondControl operation. Failure case mocks should be
@@ -181,6 +198,8 @@ public class WifiNl80211ManagerTest {
mLooper = new TestLooper();
when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
doNothing().when(mMockInstantWifi).overrideFreqsForSingleScanSettingsIfNecessary(
any(), any());
when(mWificond.asBinder()).thenReturn(mWifiCondBinder);
when(mClientInterface.getWifiScannerImpl()).thenReturn(mWifiScannerImpl);
when(mWificond.createClientInterface(any())).thenReturn(mClientInterface);
@@ -189,7 +208,7 @@ public class WifiNl80211ManagerTest {
when(mWificond.tearDownApInterface(any())).thenReturn(true);
when(mClientInterface.getWifiScannerImpl()).thenReturn(mWifiScannerImpl);
when(mClientInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
mWificondControl = new WifiNl80211Manager(mContext, mWificond);
mWificondControl = new WifiNl80211ManagerSpy(mContext, mWificond);
mWificondEventHandler = mWificondControl.getWificondEventHandler();
assertEquals(true,
mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME, Runnable::run,
@@ -1159,6 +1178,40 @@ public class WifiNl80211ManagerTest {
verify(mWificond).notifyCountryCodeChanged();
}
@Test
public void testInstantWifi() throws Exception {
doAnswer(new AnswerWithArguments() {
public void answer(SingleScanSettings settings, Set<Integer> freqs) {
if (settings.channelSettings == null) {
settings.channelSettings = new ArrayList<>();
} else {
settings.channelSettings.clear();
}
for (int freq : freqs) {
if (freq > 0) {
ChannelSettings channel = new ChannelSettings();
channel.frequency = freq;
settings.channelSettings.add(channel);
}
}
}
}).when(mMockInstantWifi).overrideFreqsForSingleScanSettingsIfNecessary(
any(), any());
Set<Integer> testPredictedChannelsSet = Set.of(2412, 5745);
assertNotEquals(testPredictedChannelsSet, SCAN_FREQ_SET);
when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(true);
when(mMockInstantWifi.getPredictedScanningChannels()).thenReturn(testPredictedChannelsSet);
// Trigger scan to check scan settings are changed
assertTrue(mWificondControl.startScan(
TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_POWER,
SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST));
verify(mMockInstantWifi).getPredictedScanningChannels();
verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
IWifiScannerImpl.SCAN_TYPE_LOW_POWER,
testPredictedChannelsSet, SCAN_HIDDEN_NETWORK_SSID_LIST, false, null)));
}
// Create a ArgumentMatcher which captures a SingleScanSettings parameter and checks if it
// matches the provided frequency set and ssid set.
private class ScanMatcher implements ArgumentMatcher<SingleScanSettings> {