Merge "WifiConfig corresponding to a PasspointConfiguration is not shared by default"
diff --git a/service/java/com/android/server/wifi/FrameworkFacade.java b/service/java/com/android/server/wifi/FrameworkFacade.java
index 2c16444..31124d5 100644
--- a/service/java/com/android/server/wifi/FrameworkFacade.java
+++ b/service/java/com/android/server/wifi/FrameworkFacade.java
@@ -79,6 +79,17 @@
contentObserver);
}
+ /**
+ * Helper method for classes to unregister a ContentObserver
+ * {@see ContentResolver#unregisterContentObserver(ContentObserver)}.
+ *
+ * @param context
+ * @param contentObserver
+ */
+ public void unregisterContentObserver(Context context, ContentObserver contentObserver) {
+ context.getContentResolver().unregisterContentObserver(contentObserver);
+ }
+
public IBinder getService(String serviceName) {
return ServiceManager.getService(serviceName);
}
diff --git a/service/java/com/android/server/wifi/HalDeviceManager.java b/service/java/com/android/server/wifi/HalDeviceManager.java
index ffc7113..d65f31f 100644
--- a/service/java/com/android/server/wifi/HalDeviceManager.java
+++ b/service/java/com/android/server/wifi/HalDeviceManager.java
@@ -1485,7 +1485,7 @@
for (int type: IFACE_TYPES_BY_PRIORITY) {
if (chipInfo.ifaces[type].length != 0) {
if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType,
- chipInfo.ifaces[ifaceType].length != 0)) {
+ chipInfo.ifaces)) {
if (DBG) {
Log.d(TAG, "Couldn't delete existing type " + type
+ " interfaces for requested type");
@@ -1515,8 +1515,7 @@
}
if (tooManyInterfaces > 0) { // may need to delete some
- if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType,
- chipInfo.ifaces[ifaceType].length != 0)) {
+ if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType, chipInfo.ifaces)) {
if (DBG) {
Log.d(TAG, "Would need to delete some higher priority interfaces");
}
@@ -1592,37 +1591,48 @@
* Returns true if we're allowed to delete the existing interface type for the requested
* interface type.
*
- * Rules:
- * 1. Request for AP or STA will destroy any other interface (except see #4 and #5)
- * 2. Request for P2P will destroy NAN-only
- * 3. Request for NAN will not destroy any interface
- * --
- * 4. No interface will be destroyed for a requested interface of the same type
- * 5. No interface will be destroyed if one of the requested interfaces already exists
+ * Rules - applies in order:
+ *
+ * General rules:
+ * 1. No interface will be destroyed for a requested interface of the same type
+ * 2. No interface will be destroyed if one of the requested interfaces already exists
+ * 3. If there are >1 interface of an existing type, then it is ok to destroy that type
+ * interface
+ *
+ * Type-specific rules (but note that the general rules are appied first):
+ * 4. Request for AP or STA will destroy any other interface
+ * 5. Request for P2P will destroy NAN-only (but will destroy a second STA per #3)
+ * 6. Request for NAN will not destroy any interface (but will destroy a second STA per #3)
+
*/
private boolean allowedToDeleteIfaceTypeForRequestedType(int existingIfaceType,
- int requestedIfaceType, boolean requestedIfaceTypeAlreadyExists) {
- // rule 5
- if (requestedIfaceTypeAlreadyExists) {
- return false;
- }
-
- // rule 4
+ int requestedIfaceType, WifiIfaceInfo[][] currentIfaces) {
+ // rule 1
if (existingIfaceType == requestedIfaceType) {
return false;
}
+ // rule 2
+ if (currentIfaces[requestedIfaceType].length != 0) {
+ return false;
+ }
+
// rule 3
+ if (currentIfaces[existingIfaceType].length > 1) {
+ return true;
+ }
+
+ // rule 6
if (requestedIfaceType == IfaceType.NAN) {
return false;
}
- // rule 2
+ // rule 5
if (requestedIfaceType == IfaceType.P2P) {
return existingIfaceType == IfaceType.NAN;
}
- // rule 1, the requestIfaceType is either AP or STA
+ // rule 4, the requestIfaceType is either AP or STA
return true;
}
diff --git a/service/java/com/android/server/wifi/SavedNetworkEvaluator.java b/service/java/com/android/server/wifi/SavedNetworkEvaluator.java
index 59d4ab2..97f6b6f 100644
--- a/service/java/com/android/server/wifi/SavedNetworkEvaluator.java
+++ b/service/java/com/android/server/wifi/SavedNetworkEvaluator.java
@@ -25,8 +25,6 @@
import com.android.internal.R;
import com.android.server.wifi.util.TelephonyUtil;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
/**
@@ -242,96 +240,83 @@
for (ScanDetail scanDetail : scanDetails) {
ScanResult scanResult = scanDetail.getScanResult();
- int highestScoreOfScanResult = Integer.MIN_VALUE;
- int candidateIdOfScanResult = WifiConfiguration.INVALID_NETWORK_ID;
// One ScanResult can be associated with more than one networks, hence we calculate all
// the scores and use the highest one as the ScanResult's score.
- List<WifiConfiguration> associatedConfigurations = null;
- WifiConfiguration associatedConfiguration =
+ WifiConfiguration network =
mWifiConfigManager.getConfiguredNetworkForScanDetailAndCache(scanDetail);
- if (associatedConfiguration == null) {
+ if (network == null) {
continue;
- } else {
- associatedConfigurations =
- new ArrayList<>(Arrays.asList(associatedConfiguration));
}
- for (WifiConfiguration network : associatedConfigurations) {
- /**
- * Ignore Passpoint and Ephemeral networks. They are configured networks,
- * but without being persisted to the storage. They are evaluated by
- * {@link PasspointNetworkEvaluator} and {@link ScoredNetworkEvaluator}
- * respectively.
- */
- if (network.isPasspoint() || network.isEphemeral()) {
- continue;
- }
+ /**
+ * Ignore Passpoint and Ephemeral networks. They are configured networks,
+ * but without being persisted to the storage. They are evaluated by
+ * {@link PasspointNetworkEvaluator} and {@link ScoredNetworkEvaluator}
+ * respectively.
+ */
+ if (network.isPasspoint() || network.isEphemeral()) {
+ continue;
+ }
- WifiConfiguration.NetworkSelectionStatus status =
- network.getNetworkSelectionStatus();
- status.setSeenInLastQualifiedNetworkSelection(true);
+ WifiConfiguration.NetworkSelectionStatus status =
+ network.getNetworkSelectionStatus();
+ status.setSeenInLastQualifiedNetworkSelection(true);
- if (!status.isNetworkEnabled()) {
- continue;
- } else if (network.BSSID != null && !network.BSSID.equals("any")
- && !network.BSSID.equals(scanResult.BSSID)) {
- // App has specified the only BSSID to connect for this
- // configuration. So only the matching ScanResult can be a candidate.
- localLog("Network " + WifiNetworkSelector.toNetworkString(network)
- + " has specified BSSID " + network.BSSID + ". Skip "
- + scanResult.BSSID);
- continue;
- } else if (TelephonyUtil.isSimConfig(network)
- && !mWifiConfigManager.isSimPresent()) {
- // Don't select if security type is EAP SIM/AKA/AKA' when SIM is not present.
- continue;
- }
+ if (!status.isNetworkEnabled()) {
+ continue;
+ } else if (network.BSSID != null && !network.BSSID.equals("any")
+ && !network.BSSID.equals(scanResult.BSSID)) {
+ // App has specified the only BSSID to connect for this
+ // configuration. So only the matching ScanResult can be a candidate.
+ localLog("Network " + WifiNetworkSelector.toNetworkString(network)
+ + " has specified BSSID " + network.BSSID + ". Skip "
+ + scanResult.BSSID);
+ continue;
+ } else if (TelephonyUtil.isSimConfig(network)
+ && !mWifiConfigManager.isSimPresent()) {
+ // Don't select if security type is EAP SIM/AKA/AKA' when SIM is not present.
+ continue;
+ }
- int score = calculateBssidScore(scanResult, network, currentNetwork, currentBssid,
- scoreHistory);
+ int score = calculateBssidScore(scanResult, network, currentNetwork, currentBssid,
+ scoreHistory);
- // Set candidate ScanResult for all saved networks to ensure that users can
- // override network selection. See WifiNetworkSelector#setUserConnectChoice.
- // TODO(b/36067705): consider alternative designs to push filtering/selecting of
- // user connect choice networks to RecommendedNetworkEvaluator.
- if (score > status.getCandidateScore() || (score == status.getCandidateScore()
- && status.getCandidate() != null
- && scanResult.level > status.getCandidate().level)) {
- mWifiConfigManager.setNetworkCandidateScanResult(
- network.networkId, scanResult, score);
- }
+ // Set candidate ScanResult for all saved networks to ensure that users can
+ // override network selection. See WifiNetworkSelector#setUserConnectChoice.
+ // TODO(b/36067705): consider alternative designs to push filtering/selecting of
+ // user connect choice networks to RecommendedNetworkEvaluator.
+ if (score > status.getCandidateScore() || (score == status.getCandidateScore()
+ && status.getCandidate() != null
+ && scanResult.level > status.getCandidate().level)) {
+ mWifiConfigManager.setNetworkCandidateScanResult(
+ network.networkId, scanResult, score);
+ }
- // If the network is marked to use external scores, or is an open network with
- // curate saved open networks enabled, do not consider it for network selection.
- if (network.useExternalScores) {
- localLog("Network " + WifiNetworkSelector.toNetworkString(network)
- + " has external score.");
- continue;
- }
-
- if (score > highestScoreOfScanResult) {
- highestScoreOfScanResult = score;
- candidateIdOfScanResult = network.networkId;
- }
+ // If the network is marked to use external scores, or is an open network with
+ // curate saved open networks enabled, do not consider it for network selection.
+ if (network.useExternalScores) {
+ localLog("Network " + WifiNetworkSelector.toNetworkString(network)
+ + " has external score.");
+ continue;
}
if (connectableNetworks != null) {
connectableNetworks.add(Pair.create(scanDetail,
- mWifiConfigManager.getConfiguredNetwork(candidateIdOfScanResult)));
+ mWifiConfigManager.getConfiguredNetwork(network.networkId)));
}
- if (highestScoreOfScanResult > highestScore
- || (highestScoreOfScanResult == highestScore
+ if (score > highestScore
+ || (score == highestScore
&& scanResultCandidate != null
&& scanResult.level > scanResultCandidate.level)) {
- highestScore = highestScoreOfScanResult;
+ highestScore = score;
scanResultCandidate = scanResult;
mWifiConfigManager.setNetworkCandidateScanResult(
- candidateIdOfScanResult, scanResultCandidate, highestScore);
+ network.networkId, scanResultCandidate, highestScore);
// Reload the network config with the updated info.
- candidate = mWifiConfigManager.getConfiguredNetwork(candidateIdOfScanResult);
+ candidate = mWifiConfigManager.getConfiguredNetwork(network.networkId);
}
}
diff --git a/service/java/com/android/server/wifi/SoftApManager.java b/service/java/com/android/server/wifi/SoftApManager.java
index 429e3c3..6d5fd27 100644
--- a/service/java/com/android/server/wifi/SoftApManager.java
+++ b/service/java/com/android/server/wifi/SoftApManager.java
@@ -23,21 +23,28 @@
import android.annotation.NonNull;
import android.content.Context;
import android.content.Intent;
+import android.database.ContentObserver;
import android.net.InterfaceConfiguration;
import android.net.wifi.IApInterface;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
+import android.os.Handler;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.UserHandle;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
+import com.android.internal.util.WakeupMessage;
import com.android.server.net.BaseNetworkObserver;
import com.android.server.wifi.WifiNative.SoftApListener;
import com.android.server.wifi.util.ApConfigUtil;
@@ -51,8 +58,15 @@
public class SoftApManager implements ActiveModeManager {
private static final String TAG = "SoftApManager";
- private final Context mContext;
+ // Minimum limit to use for timeout delay if the value from overlay setting is too small.
+ private static final int MIN_SOFT_AP_TIMEOUT_DELAY_MS = 600_000; // 10 minutes
+ @VisibleForTesting
+ public static final String SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG = TAG
+ + " Soft AP Send Message Timeout";
+
+ private final Context mContext;
+ private final FrameworkFacade mFrameworkFacade;
private final WifiNative mWifiNative;
private final String mCountryCode;
@@ -61,8 +75,8 @@
private final Listener mListener;
- private final IApInterface mApInterface;
- private final String mApInterfaceName;
+ private IApInterface mApInterface;
+ private String mApInterfaceName;
private final INetworkManagementService mNwService;
private final WifiApConfigStore mWifiApConfigStore;
@@ -72,8 +86,9 @@
private final int mMode;
private WifiConfiguration mApConfig;
- private int mNumAssociatedStations = 0;
-
+ /**
+ * Listener for soft AP events.
+ */
private final SoftApListener mSoftApListener = new SoftApListener() {
@Override
public void onNumAssociatedStationsChanged(int numStations) {
@@ -82,7 +97,6 @@
}
};
-
/**
* Listener for soft AP state changes.
*/
@@ -97,23 +111,19 @@
public SoftApManager(Context context,
Looper looper,
+ FrameworkFacade framework,
WifiNative wifiNative,
String countryCode,
Listener listener,
- @NonNull IApInterface apInterface,
- @NonNull String ifaceName,
INetworkManagementService nms,
WifiApConfigStore wifiApConfigStore,
@NonNull SoftApModeConfiguration apConfig,
WifiMetrics wifiMetrics) {
- mStateMachine = new SoftApStateMachine(looper);
-
mContext = context;
+ mFrameworkFacade = framework;
mWifiNative = wifiNative;
mCountryCode = countryCode;
mListener = listener;
- mApInterface = apInterface;
- mApInterfaceName = ifaceName;
mNwService = nms;
mWifiApConfigStore = wifiApConfigStore;
mMode = apConfig.getTargetMode();
@@ -124,6 +134,7 @@
mApConfig = config;
}
mWifiMetrics = wifiMetrics;
+ mStateMachine = new SoftApStateMachine(looper);
}
/**
@@ -141,29 +152,6 @@
}
/**
- * Get number of stations associated with this soft AP
- */
- @VisibleForTesting
- public int getNumAssociatedStations() {
- return mNumAssociatedStations;
- }
-
- /**
- * Set number of stations associated with this soft AP
- * @param numStations Number of connected stations
- */
- private void setNumAssociatedStations(int numStations) {
- if (mNumAssociatedStations == numStations) {
- return;
- }
- mNumAssociatedStations = numStations;
- Log.d(TAG, "Number of associated stations changed: " + mNumAssociatedStations);
-
- // TODO:(b/63906412) send it up to settings.
- mWifiMetrics.addSoftApNumAssociatedStationsChangedEvent(mNumAssociatedStations, mMode);
- }
-
- /**
* Update AP state.
* @param newState new AP state
* @param currentState current AP state
@@ -190,6 +178,17 @@
}
/**
+ * Helper function to increment the appropriate setup failure metrics.
+ */
+ private void incrementMetricsForSetupFailure(int failureReason) {
+ if (failureReason == WifiNative.SETUP_FAILURE_HAL) {
+ mWifiMetrics.incrementNumWifiOnFailureDueToHal();
+ } else if (failureReason == WifiNative.SETUP_FAILURE_WIFICOND) {
+ mWifiMetrics.incrementNumWifiOnFailureDueToWificond();
+ }
+ }
+
+ /**
* Start a soft AP instance with the given configuration.
* @param config AP configuration
* @return integer result code
@@ -236,12 +235,11 @@
}
/**
- * Teardown soft AP.
+ * Teardown soft AP and teardown the interface.
*/
private void stopSoftAp() {
if (!mWifiNative.stopSoftAp()) {
- Log.d(TAG, "Soft AP stop failed");
- return;
+ Log.e(TAG, "Soft AP stop failed");
}
Log.d(TAG, "Soft AP is stopped");
}
@@ -253,6 +251,8 @@
public static final int CMD_WIFICOND_BINDER_DEATH = 2;
public static final int CMD_INTERFACE_STATUS_CHANGED = 3;
public static final int CMD_NUM_ASSOCIATED_STATIONS_CHANGED = 4;
+ public static final int CMD_NO_ASSOCIATED_STATIONS_TIMEOUT = 5;
+ public static final int CMD_TIMEOUT_TOGGLE_CHANGED = 6;
private final State mIdleState = new IdleState();
private final State mStartedState = new StartedState();
@@ -300,6 +300,39 @@
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_START:
+ // need to create our interface
+ mApInterface = null;
+ Pair<Integer, IApInterface> statusAndInterface =
+ mWifiNative.setupForSoftApMode(mWifiNative.getInterfaceName());
+ if (statusAndInterface.first == WifiNative.SETUP_SUCCESS) {
+ mApInterface = statusAndInterface.second;
+ } else {
+ Log.e(TAG, "setup failure when creating ap interface.");
+ incrementMetricsForSetupFailure(statusAndInterface.first);
+ }
+ if (mApInterface == null) {
+ Log.e(TAG, "Not starting softap mode without an interface.");
+ updateApState(WifiManager.WIFI_AP_STATE_FAILED,
+ WifiManager.WIFI_AP_STATE_DISABLED,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ mWifiMetrics.incrementSoftApStartResult(
+ false, WifiManager.SAP_START_FAILURE_GENERAL);
+ break;
+ }
+ try {
+ mApInterfaceName = mApInterface.getInterfaceName();
+ } catch (RemoteException e) {
+ // Failed to get the interface name. This is not a good sign and we
+ // should report a failure.
+ Log.e(TAG, "Failed to get the interface name.");
+ updateApState(WifiManager.WIFI_AP_STATE_FAILED,
+ WifiManager.WIFI_AP_STATE_DISABLED,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ mWifiMetrics.incrementSoftApStartResult(
+ false, WifiManager.SAP_START_FAILURE_GENERAL);
+ break;
+ }
+
// first a sanity check on the interface name. If we failed to retrieve it,
// we are going to have a hard time setting up routing.
if (TextUtils.isEmpty(mApInterfaceName)) {
@@ -313,7 +346,6 @@
}
updateApState(WifiManager.WIFI_AP_STATE_ENABLING,
WifiManager.WIFI_AP_STATE_DISABLED, 0);
- setNumAssociatedStations(0);
if (!mWifiNative.registerWificondDeathHandler(mWificondDeathRecipient)) {
updateApState(WifiManager.WIFI_AP_STATE_FAILED,
WifiManager.WIFI_AP_STATE_ENABLING,
@@ -375,6 +407,92 @@
private class StartedState extends State {
private boolean mIfaceIsUp;
+ private int mNumAssociatedStations;
+
+ private boolean mTimeoutEnabled;
+ private int mTimeoutDelay;
+ private WakeupMessage mSoftApTimeoutMessage;
+ private SoftApTimeoutEnabledSettingObserver mSettingObserver;
+
+ /**
+ * Observer for timeout settings changes.
+ */
+ private class SoftApTimeoutEnabledSettingObserver extends ContentObserver {
+ SoftApTimeoutEnabledSettingObserver(Handler handler) {
+ super(handler);
+ }
+
+ public void register() {
+ mFrameworkFacade.registerContentObserver(mContext,
+ Settings.Global.getUriFor(Settings.Global.SOFT_AP_TIMEOUT_ENABLED),
+ true, this);
+ mTimeoutEnabled = getValue();
+ }
+
+ public void unregister() {
+ mFrameworkFacade.unregisterContentObserver(mContext, this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+ mStateMachine.sendMessage(SoftApStateMachine.CMD_TIMEOUT_TOGGLE_CHANGED,
+ getValue() ? 1 : 0);
+ }
+
+ private boolean getValue() {
+ boolean enabled = mFrameworkFacade.getIntegerSetting(mContext,
+ Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1) == 1;
+ return enabled;
+ }
+ }
+
+ private int getConfigSoftApTimeoutDelay() {
+ int delay = mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_soft_ap_timeout_delay);
+ if (delay < MIN_SOFT_AP_TIMEOUT_DELAY_MS) {
+ delay = MIN_SOFT_AP_TIMEOUT_DELAY_MS;
+ Log.w(TAG, "Overriding timeout delay with minimum limit value");
+ }
+ Log.d(TAG, "Timeout delay: " + delay);
+ return delay;
+ }
+
+ private void scheduleTimeoutMessage() {
+ if (!mTimeoutEnabled) {
+ return;
+ }
+ mSoftApTimeoutMessage.schedule(SystemClock.elapsedRealtime() + mTimeoutDelay);
+ Log.d(TAG, "Timeout message scheduled");
+ }
+
+ private void cancelTimeoutMessage() {
+ mSoftApTimeoutMessage.cancel();
+ Log.d(TAG, "Timeout message canceled");
+ }
+
+ /**
+ * Set number of stations associated with this soft AP
+ * @param numStations Number of connected stations
+ */
+ private void setNumAssociatedStations(int numStations) {
+ if (mNumAssociatedStations == numStations) {
+ return;
+ }
+ mNumAssociatedStations = numStations;
+ Log.d(TAG, "Number of associated stations changed: " + mNumAssociatedStations);
+
+ // TODO:(b/63906412) send it up to settings.
+ mWifiMetrics.addSoftApNumAssociatedStationsChangedEvent(mNumAssociatedStations,
+ mMode);
+
+ if (mNumAssociatedStations == 0) {
+ scheduleTimeoutMessage();
+ } else {
+ cancelTimeoutMessage();
+ }
+ }
+
private void onUpChanged(boolean isUp) {
if (isUp == mIfaceIsUp) {
return; // no change
@@ -388,9 +506,7 @@
} else {
// TODO: handle the case where the interface was up, but goes down
}
-
mWifiMetrics.addSoftApUpChangedEvent(isUp, mMode);
- setNumAssociatedStations(0);
}
@Override
@@ -404,6 +520,30 @@
if (config != null) {
onUpChanged(config.isUp());
}
+
+ mTimeoutDelay = getConfigSoftApTimeoutDelay();
+ Handler handler = mStateMachine.getHandler();
+ mSoftApTimeoutMessage = new WakeupMessage(mContext, handler,
+ SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG,
+ SoftApStateMachine.CMD_NO_ASSOCIATED_STATIONS_TIMEOUT);
+ mSettingObserver = new SoftApTimeoutEnabledSettingObserver(handler);
+
+ if (mSettingObserver != null) {
+ mSettingObserver.register();
+ }
+ Log.d(TAG, "Resetting num stations on start");
+ mNumAssociatedStations = 0;
+ scheduleTimeoutMessage();
+ }
+
+ @Override
+ public void exit() {
+ if (mSettingObserver != null) {
+ mSettingObserver.unregister();
+ }
+ Log.d(TAG, "Resetting num stations on stop");
+ mNumAssociatedStations = 0;
+ cancelTimeoutMessage();
}
@Override
@@ -414,8 +554,22 @@
Log.e(TAG, "Invalid number of associated stations: " + message.arg1);
break;
}
+ Log.d(TAG, "Setting num stations on CMD_NUM_ASSOCIATED_STATIONS_CHANGED");
setNumAssociatedStations(message.arg1);
break;
+ case CMD_TIMEOUT_TOGGLE_CHANGED:
+ boolean isEnabled = (message.arg1 == 1);
+ if (mTimeoutEnabled == isEnabled) {
+ break;
+ }
+ mTimeoutEnabled = isEnabled;
+ if (!mTimeoutEnabled) {
+ cancelTimeoutMessage();
+ }
+ if (mTimeoutEnabled && mNumAssociatedStations == 0) {
+ scheduleTimeoutMessage();
+ }
+ break;
case CMD_INTERFACE_STATUS_CHANGED:
if (message.obj != mNetworkObserver) {
// This is from some time before the most recent configuration.
@@ -427,11 +581,21 @@
case CMD_START:
// Already started, ignore this command.
break;
+ case CMD_NO_ASSOCIATED_STATIONS_TIMEOUT:
+ if (!mTimeoutEnabled) {
+ Log.wtf(TAG, "Timeout message received while timeout is disabled."
+ + " Dropping.");
+ break;
+ }
+ if (mNumAssociatedStations != 0) {
+ Log.wtf(TAG, "Timeout message received but has clients. Dropping.");
+ break;
+ }
+ Log.i(TAG, "Timeout message received. Stopping soft AP.");
case CMD_WIFICOND_BINDER_DEATH:
case CMD_STOP:
updateApState(WifiManager.WIFI_AP_STATE_DISABLING,
WifiManager.WIFI_AP_STATE_ENABLED, 0);
- setNumAssociatedStations(0);
stopSoftAp();
if (message.what == CMD_WIFICOND_BINDER_DEATH) {
updateApState(WifiManager.WIFI_AP_STATE_FAILED,
diff --git a/service/java/com/android/server/wifi/VelocityBasedConnectedScore.java b/service/java/com/android/server/wifi/VelocityBasedConnectedScore.java
index 38fd1ef..bfc51f6 100644
--- a/service/java/com/android/server/wifi/VelocityBasedConnectedScore.java
+++ b/service/java/com/android/server/wifi/VelocityBasedConnectedScore.java
@@ -91,15 +91,14 @@
double initialVariance = 9.0 * standardDeviation * standardDeviation;
mFilter.mx = new Matrix(1, new double[]{rssi, 0.0});
mFilter.mP = new Matrix(2, new double[]{initialVariance, 0.0, 0.0, 0.0});
- mLastMillis = millis;
- return;
+ } else {
+ double dt = (millis - mLastMillis) * 0.001;
+ mFilter.mR.put(0, 0, standardDeviation * standardDeviation);
+ setDeltaTimeSeconds(dt);
+ mFilter.predict();
+ mFilter.update(new Matrix(1, new double[]{rssi}));
}
- double dt = (millis - mLastMillis) * 0.001;
- mFilter.mR.put(0, 0, standardDeviation * standardDeviation);
- setDeltaTimeSeconds(dt);
- mFilter.predict();
mLastMillis = millis;
- mFilter.update(new Matrix(1, new double[]{rssi}));
mFilteredRssi = mFilter.mx.get(0, 0);
mEstimatedRateOfRssiChange = mFilter.mx.get(1, 0);
}
diff --git a/service/java/com/android/server/wifi/WakeupConfigStoreData.java b/service/java/com/android/server/wifi/WakeupConfigStoreData.java
new file mode 100644
index 0000000..5775117
--- /dev/null
+++ b/service/java/com/android/server/wifi/WakeupConfigStoreData.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2017 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 android.util.ArraySet;
+
+import com.android.server.wifi.WifiConfigStore.StoreData;
+import com.android.server.wifi.util.XmlUtil;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Config store data for Wifi Wake.
+ */
+public class WakeupConfigStoreData implements StoreData {
+ private static final String TAG = "WakeupConfigStoreData";
+
+ private static final String XML_TAG_IS_ACTIVE = "IsActive";
+ private static final String XML_TAG_NETWORK_SECTION = "Network";
+ private static final String XML_TAG_SSID = "SSID";
+ private static final String XML_TAG_SECURITY = "Security";
+
+ private final DataSource<Boolean> mIsActiveDataSource;
+ private final DataSource<Set<ScanResultMatchInfo>> mNetworkDataSource;
+
+ /**
+ * Interface defining a data source for the store data.
+ *
+ * @param <T> Type of data source
+ */
+ public interface DataSource<T> {
+ /**
+ * Returns the data from the data source.
+ */
+ T getData();
+
+ /**
+ * Updates the data in the data source.
+ *
+ * @param data Data retrieved from the store
+ */
+ void setData(T data);
+ }
+
+ /**
+ * Creates the config store data with its data sources.
+ *
+ * @param isActiveDataSource Data source for isActive
+ * @param networkDataSource Data source for the locked network list
+ */
+ public WakeupConfigStoreData(
+ DataSource<Boolean> isActiveDataSource,
+ DataSource<Set<ScanResultMatchInfo>> networkDataSource) {
+ mIsActiveDataSource = isActiveDataSource;
+ mNetworkDataSource = networkDataSource;
+ }
+
+ @Override
+ public void serializeData(XmlSerializer out, boolean shared)
+ throws XmlPullParserException, IOException {
+ if (shared) {
+ throw new XmlPullParserException("Share data not supported");
+ }
+
+ XmlUtil.writeNextValue(out, XML_TAG_IS_ACTIVE, mIsActiveDataSource.getData());
+
+ for (ScanResultMatchInfo scanResultMatchInfo : mNetworkDataSource.getData()) {
+ writeNetwork(out, scanResultMatchInfo);
+ }
+ }
+
+ /**
+ * Writes a {@link ScanResultMatchInfo} to an XML output stream.
+ *
+ * @param out XML output stream
+ * @param scanResultMatchInfo The ScanResultMatchInfo to serizialize
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ private void writeNetwork(XmlSerializer out, ScanResultMatchInfo scanResultMatchInfo)
+ throws XmlPullParserException, IOException {
+ XmlUtil.writeNextSectionStart(out, XML_TAG_NETWORK_SECTION);
+
+ XmlUtil.writeNextValue(out, XML_TAG_SSID, scanResultMatchInfo.networkSsid);
+ XmlUtil.writeNextValue(out, XML_TAG_SECURITY, scanResultMatchInfo.networkType);
+
+ XmlUtil.writeNextSectionEnd(out, XML_TAG_NETWORK_SECTION);
+ }
+
+ @Override
+ public void deserializeData(XmlPullParser in, int outerTagDepth, boolean shared)
+ throws XmlPullParserException, IOException {
+ if (shared) {
+ throw new XmlPullParserException("Shared data not supported");
+ }
+
+ boolean isActive = (Boolean) XmlUtil.readNextValueWithName(in, XML_TAG_IS_ACTIVE);
+ mIsActiveDataSource.setData(isActive);
+
+ Set<ScanResultMatchInfo> networks = new ArraySet<>();
+ while (XmlUtil.gotoNextSectionWithNameOrEnd(in, XML_TAG_NETWORK_SECTION, outerTagDepth)) {
+ networks.add(parseNetwork(in, outerTagDepth + 1));
+ }
+
+ mNetworkDataSource.setData(networks);
+ }
+
+ /**
+ * Parses a {@link ScanResultMatchInfo} from an XML input stream.
+ *
+ * @param in XML input stream
+ * @param outerTagDepth XML tag depth of the containing section
+ * @return The {@link ScanResultMatchInfo}
+ * @throws IOException
+ * @throws XmlPullParserException
+ */
+ private ScanResultMatchInfo parseNetwork(XmlPullParser in, int outerTagDepth)
+ throws IOException, XmlPullParserException {
+ ScanResultMatchInfo scanResultMatchInfo = new ScanResultMatchInfo();
+ while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
+ String[] valueName = new String[1];
+ Object value = XmlUtil.readCurrentValue(in, valueName);
+ if (valueName[0] == null) {
+ throw new XmlPullParserException("Missing value name");
+ }
+ switch (valueName[0]) {
+ case XML_TAG_SSID:
+ scanResultMatchInfo.networkSsid = (String) value;
+ break;
+ case XML_TAG_SECURITY:
+ scanResultMatchInfo.networkType = (int) value;
+ break;
+ default:
+ throw new XmlPullParserException("Unknown tag under " + TAG + ": "
+ + valueName[0]);
+ }
+ }
+
+ return scanResultMatchInfo;
+ }
+
+ @Override
+ public void resetData(boolean shared) {
+ if (!shared) {
+ mNetworkDataSource.setData(Collections.emptySet());
+ mIsActiveDataSource.setData(false);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return TAG;
+ }
+
+ @Override
+ public boolean supportShareData() {
+ return false;
+ }
+}
diff --git a/service/java/com/android/server/wifi/WakeupController.java b/service/java/com/android/server/wifi/WakeupController.java
index a3c095a..8787bfd 100644
--- a/service/java/com/android/server/wifi/WakeupController.java
+++ b/service/java/com/android/server/wifi/WakeupController.java
@@ -24,6 +24,9 @@
import com.android.internal.annotations.VisibleForTesting;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* WakeupController is responsible managing Auto Wifi.
*
@@ -38,16 +41,26 @@
private final Handler mHandler;
private final FrameworkFacade mFrameworkFacade;
private final ContentObserver mContentObserver;
+ private final WakeupLock mWakeupLock;
+ private final WifiConfigManager mWifiConfigManager;
/** Whether this feature is enabled in Settings. */
private boolean mWifiWakeupEnabled;
+ /** Whether the WakeupController is currently active. */
+ private boolean mIsActive = false;
+
public WakeupController(
Context context,
Looper looper,
+ WakeupLock wakeupLock,
+ WifiConfigManager wifiConfigManager,
+ WifiConfigStore wifiConfigStore,
FrameworkFacade frameworkFacade) {
mContext = context;
mHandler = new Handler(looper);
+ mWakeupLock = wakeupLock;
+ mWifiConfigManager = wifiConfigManager;
mFrameworkFacade = frameworkFacade;
mContentObserver = new ContentObserver(mHandler) {
@Override
@@ -59,6 +72,19 @@
mFrameworkFacade.registerContentObserver(mContext, Settings.Global.getUriFor(
Settings.Global.WIFI_WAKEUP_ENABLED), true, mContentObserver);
mContentObserver.onChange(false /* selfChange */);
+
+ // registering the store data here has the effect of reading the persisted value of the
+ // data sources after system boot finishes
+ WakeupConfigStoreData wakeupConfigStoreData =
+ new WakeupConfigStoreData(new IsActiveDataSource(), mWakeupLock.getDataSource());
+ wifiConfigStore.registerStoreData(wakeupConfigStoreData);
+ }
+
+ private void setActive(boolean isActive) {
+ if (mIsActive != isActive) {
+ mIsActive = isActive;
+ mWifiConfigManager.saveToStore(false /* forceWrite */);
+ }
}
/**
@@ -71,4 +97,26 @@
boolean isEnabled() {
return mWifiWakeupEnabled;
}
+
+ /** Dumps wakeup controller state. */
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("Dump of WakeupController");
+ pw.println("mWifiWakeupEnabled: " + mWifiWakeupEnabled);
+ pw.println("USE_PLATFORM_WIFI_WAKE: " + USE_PLATFORM_WIFI_WAKE);
+ pw.println("mIsActive: " + mIsActive);
+ mWakeupLock.dump(fd, pw, args);
+ }
+
+ private class IsActiveDataSource implements WakeupConfigStoreData.DataSource<Boolean> {
+
+ @Override
+ public Boolean getData() {
+ return mIsActive;
+ }
+
+ @Override
+ public void setData(Boolean data) {
+ mIsActive = data;
+ }
+ }
}
diff --git a/service/java/com/android/server/wifi/WakeupLock.java b/service/java/com/android/server/wifi/WakeupLock.java
index 73cda91..1fcd9f8 100644
--- a/service/java/com/android/server/wifi/WakeupLock.java
+++ b/service/java/com/android/server/wifi/WakeupLock.java
@@ -17,12 +17,16 @@
package com.android.server.wifi;
import android.util.ArrayMap;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
+import java.util.Set;
/**
* A lock to determine whether Auto Wifi can re-enable Wifi.
@@ -31,18 +35,24 @@
*/
public class WakeupLock {
+ private static final String TAG = WakeupLock.class.getSimpleName();
+
@VisibleForTesting
static final int CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT = 3;
- private Map<ScanResultMatchInfo, Integer> mLockedNetworks = new ArrayMap<>();
- // TODO(easchwar) read initial value of mLockedNetworks from file
- public WakeupLock() {
+ private final WifiConfigManager mWifiConfigManager;
+ private final Map<ScanResultMatchInfo, Integer> mLockedNetworks = new ArrayMap<>();
+
+ public WakeupLock(WifiConfigManager wifiConfigManager) {
+ mWifiConfigManager = wifiConfigManager;
}
/**
* Initializes the WakeupLock with the given {@link ScanResultMatchInfo} list.
*
+ * <p>This saves the wakeup lock to the store.
+ *
* @param scanResultList list of ScanResultMatchInfos to start the lock with
*/
public void initialize(Collection<ScanResultMatchInfo> scanResultList) {
@@ -50,17 +60,23 @@
for (ScanResultMatchInfo scanResultMatchInfo : scanResultList) {
mLockedNetworks.put(scanResultMatchInfo, CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT);
}
+
+ Log.d(TAG, "Lock initialized. Number of networks: " + mLockedNetworks.size());
+
+ mWifiConfigManager.saveToStore(false /* forceWrite */);
}
/**
* Updates the lock with the given {@link ScanResultMatchInfo} list.
*
* <p>If a network in the lock is not present in the list, reduce the number of scans
- * required to evict by one. Remove any entries in the list with 0 scans required to evict.
+ * required to evict by one. Remove any entries in the list with 0 scans required to evict. If
+ * any entries in the lock are removed, the store is updated.
*
* @param scanResultList list of present ScanResultMatchInfos to update the lock with
*/
public void update(Collection<ScanResultMatchInfo> scanResultList) {
+ boolean hasChanged = false;
Iterator<Map.Entry<ScanResultMatchInfo, Integer>> it =
mLockedNetworks.entrySet().iterator();
while (it.hasNext()) {
@@ -76,9 +92,13 @@
entry.setValue(entry.getValue() - 1);
if (entry.getValue() <= 0) {
it.remove();
+ hasChanged = true;
}
}
- // TODO(easchwar) write the updated list to file
+
+ if (hasChanged) {
+ mWifiConfigManager.saveToStore(false /* forceWrite */);
+ }
}
/**
@@ -87,4 +107,36 @@
public boolean isEmpty() {
return mLockedNetworks.isEmpty();
}
+
+ /** Returns the data source for the WakeupLock config store data. */
+ public WakeupConfigStoreData.DataSource<Set<ScanResultMatchInfo>> getDataSource() {
+ return new WakeupLockDataSource();
+ }
+
+ /** Dumps wakeup lock contents. */
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("WakeupLock: ");
+ pw.println("Locked networks: " + mLockedNetworks.size());
+ for (Map.Entry<ScanResultMatchInfo, Integer> entry : mLockedNetworks.entrySet()) {
+ pw.println(entry.getKey() + ", scans to evict: " + entry.getValue());
+ }
+ }
+
+ private class WakeupLockDataSource
+ implements WakeupConfigStoreData.DataSource<Set<ScanResultMatchInfo>> {
+
+ @Override
+ public Set<ScanResultMatchInfo> getData() {
+ return mLockedNetworks.keySet();
+ }
+
+ @Override
+ public void setData(Set<ScanResultMatchInfo> data) {
+ mLockedNetworks.clear();
+ for (ScanResultMatchInfo network : data) {
+ mLockedNetworks.put(network, CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT);
+ }
+
+ }
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiCertManager.java b/service/java/com/android/server/wifi/WifiCertManager.java
deleted file mode 100644
index e180f51..0000000
--- a/service/java/com/android/server/wifi/WifiCertManager.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2015 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 android.app.admin.IDevicePolicyManager;
-import android.content.Context;
-import android.os.Environment;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.security.Credentials;
-import android.security.KeyStore;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.server.net.DelayedDiskWrite;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Manager class for affiliated Wifi certificates.
- */
-public class WifiCertManager {
- private static final String TAG = "WifiCertManager";
- private static final String SEP = "\n";
-
- private final Context mContext;
- private final Set<String> mAffiliatedUserOnlyCerts = new HashSet<String>();
- private final String mConfigFile;
-
- private static final String CONFIG_FILE =
- Environment.getDataDirectory() + "/misc/wifi/affiliatedcerts.txt";
-
- private final DelayedDiskWrite mWriter = new DelayedDiskWrite();
-
-
- WifiCertManager(Context context) {
- this(context, CONFIG_FILE);
- }
-
- WifiCertManager(Context context, String configFile) {
- mContext = context;
- mConfigFile = configFile;
- final byte[] bytes = readConfigFile();
- if (bytes == null) {
- // Config file does not exist or empty.
- return;
- }
-
- String[] keys = new String(bytes, StandardCharsets.UTF_8).split(SEP);
- for (String key : keys) {
- mAffiliatedUserOnlyCerts.add(key);
- }
-
- // Remove keys that no longer exist in KeyStore.
- if (mAffiliatedUserOnlyCerts.retainAll(Arrays.asList(listClientCertsForAllUsers()))) {
- writeConfig();
- }
- }
-
- /** @param key Unprefixed cert key to hide from unaffiliated users. */
- public void hideCertFromUnaffiliatedUsers(String key) {
- if (mAffiliatedUserOnlyCerts.add(Credentials.USER_PRIVATE_KEY + key)) {
- writeConfig();
- }
- }
-
- /** @return Prefixed cert keys that are visible to the current user. */
- public String[] listClientCertsForCurrentUser() {
- HashSet<String> results = new HashSet<String>();
-
- String[] keys = listClientCertsForAllUsers();
- if (isAffiliatedUser()) {
- return keys;
- }
-
- for (String key : keys) {
- if (!mAffiliatedUserOnlyCerts.contains(key)) {
- results.add(key);
- }
- }
- return results.toArray(new String[results.size()]);
- }
-
- private void writeConfig() {
- String[] values =
- mAffiliatedUserOnlyCerts.toArray(new String[mAffiliatedUserOnlyCerts.size()]);
- String value = TextUtils.join(SEP, values);
- writeConfigFile(value.getBytes(StandardCharsets.UTF_8));
- }
-
- protected byte[] readConfigFile() {
- byte[] bytes = null;
- try {
- final File file = new File(mConfigFile);
- final long fileSize = file.exists() ? file.length() : 0;
- if (fileSize == 0 || fileSize >= Integer.MAX_VALUE) {
- // Config file is empty/corrupted/non-existing.
- return bytes;
- }
-
- bytes = new byte[(int) file.length()];
- final DataInputStream stream = new DataInputStream(new FileInputStream(file));
- stream.readFully(bytes);
- } catch (IOException e) {
- Log.e(TAG, "readConfigFile: failed to read " + e, e);
- }
- return bytes;
- }
-
- protected void writeConfigFile(byte[] payload) {
- final byte[] data = payload;
- mWriter.write(mConfigFile, new DelayedDiskWrite.Writer() {
- public void onWriteCalled(DataOutputStream out) throws IOException {
- out.write(data, 0, data.length);
- }
- });
- }
-
- protected String[] listClientCertsForAllUsers() {
- return KeyStore.getInstance().list(Credentials.USER_PRIVATE_KEY, UserHandle.myUserId());
- }
-
- protected boolean isAffiliatedUser() {
- IDevicePolicyManager pm = IDevicePolicyManager.Stub.asInterface(
- ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
- boolean result = false;
- try {
- result = pm.isAffiliatedUser();
- } catch (Exception e) {
- Log.e(TAG, "failed to check user affiliation", e);
- }
- return result;
- }
-}
diff --git a/service/java/com/android/server/wifi/WifiController.java b/service/java/com/android/server/wifi/WifiController.java
index 494ce86..dc98595 100644
--- a/service/java/com/android/server/wifi/WifiController.java
+++ b/service/java/com/android/server/wifi/WifiController.java
@@ -93,6 +93,7 @@
/* References to values tracked in WifiService */
private final WifiStateMachine mWifiStateMachine;
+ private final WifiStateMachinePrime mWifiStateMachinePrime;
private final WifiSettingsStore mSettingsStore;
private final WifiLockManager mWifiLockManager;
@@ -143,11 +144,13 @@
private EcmState mEcmState = new EcmState();
WifiController(Context context, WifiStateMachine wsm, WifiSettingsStore wss,
- WifiLockManager wifiLockManager, Looper looper, FrameworkFacade f) {
+ WifiLockManager wifiLockManager, Looper looper, FrameworkFacade f,
+ WifiStateMachinePrime wsmp) {
super(TAG, looper);
mFacade = f;
mContext = context;
mWifiStateMachine = wsm;
+ mWifiStateMachinePrime = wsmp;
mSettingsStore = wss;
mWifiLockManager = wifiLockManager;
@@ -435,7 +438,8 @@
@Override
public void enter() {
mWifiStateMachine.setSupplicantRunning(false);
- // Supplicant can't restart right away, so not the time we switched off
+ mWifiStateMachinePrime.disableWifi();
+ // Supplicant can't restart right away, so note the time we switched off
mDisabledTimestamp = SystemClock.elapsedRealtime();
mDeferredEnableSerialNumber++;
mHaveDeferredEnable = false;
@@ -481,6 +485,7 @@
}
mWifiStateMachine.setHostApRunning((SoftApModeConfiguration) msg.obj,
true);
+ mWifiStateMachinePrime.enterSoftAPMode((SoftApModeConfiguration) msg.obj);
transitionTo(mApEnabledState);
}
break;
@@ -565,8 +570,13 @@
if (msg.arg1 == 1) {
// remeber that we were enabled
mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_ENABLED);
- deferMessage(obtainMessage(msg.what, msg.arg1, 1, msg.obj));
- transitionTo(mApStaDisabledState);
+ mWifiStateMachine.setHostApRunning((SoftApModeConfiguration) msg.obj, true);
+ mWifiStateMachinePrime.enterSoftAPMode((SoftApModeConfiguration) msg.obj);
+ transitionTo(mApEnabledState);
+ // we should just go directly to ApEnabled since we will kill interfaces
+ // from WSMP
+ //deferMessage(obtainMessage(msg.what, msg.arg1, 1, msg.obj));
+ //transitionTo(mApStaDisabledState);
}
break;
default:
@@ -630,8 +640,14 @@
// Before starting tethering, turn off supplicant for scan mode
if (msg.arg1 == 1) {
mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_DISABLED);
- deferMessage(obtainMessage(msg.what, msg.arg1, 1, msg.obj));
- transitionTo(mApStaDisabledState);
+
+ mWifiStateMachine.setHostApRunning((SoftApModeConfiguration) msg.obj, true);
+ mWifiStateMachinePrime.enterSoftAPMode((SoftApModeConfiguration) msg.obj);
+ transitionTo(mApEnabledState);
+ // we should just go directly to ApEnabled since we will kill interfaces
+ // from WSMP
+ //deferMessage(obtainMessage(msg.what, msg.arg1, 1, msg.obj));
+ //transitionTo(mApStaDisabledState);
}
break;
case CMD_DEFERRED_TOGGLE:
@@ -701,22 +717,26 @@
case CMD_AIRPLANE_TOGGLED:
if (mSettingsStore.isAirplaneModeOn()) {
mWifiStateMachine.setHostApRunning(null, false);
+ mWifiStateMachinePrime.disableWifi();
mPendingState = mApStaDisabledState;
}
break;
case CMD_WIFI_TOGGLED:
if (mSettingsStore.isWifiToggleEnabled()) {
mWifiStateMachine.setHostApRunning(null, false);
+ mWifiStateMachinePrime.disableWifi();
mPendingState = mDeviceActiveState;
}
break;
case CMD_SET_AP:
if (msg.arg1 == 0) {
mWifiStateMachine.setHostApRunning(null, false);
+ mWifiStateMachinePrime.disableWifi();
mPendingState = getNextWifiState();
}
break;
case CMD_AP_STOPPED:
+ mWifiStateMachine.setHostApRunning(null, false);
if (mPendingState == null) {
/**
* Stop triggered internally, either tether notification
@@ -736,10 +756,12 @@
case CMD_EMERGENCY_MODE_CHANGED:
if (msg.arg1 == 1) {
mWifiStateMachine.setHostApRunning(null, false);
+ mWifiStateMachinePrime.disableWifi();
mPendingState = mEcmState;
}
break;
case CMD_AP_START_FAILURE:
+ mWifiStateMachine.setHostApRunning(null, false);
transitionTo(getNextWifiState());
break;
default:
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index f14a57f..9c9622c 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -21,7 +21,6 @@
import android.content.Context;
import android.net.NetworkKey;
import android.net.NetworkScoreManager;
-import android.net.wifi.IApInterface;
import android.net.wifi.IWifiScanner;
import android.net.wifi.IWificond;
import android.net.wifi.WifiInfo;
@@ -84,8 +83,8 @@
private final SupplicantP2pIfaceHal mSupplicantP2pIfaceHal;
private final WifiVendorHal mWifiVendorHal;
private final WifiStateMachine mWifiStateMachine;
+ private final WifiStateMachinePrime mWifiStateMachinePrime;
private final WifiSettingsStore mSettingsStore;
- private final WifiCertManager mCertManager;
private final OpenNetworkNotifier mOpenNetworkNotifier;
private final WifiLockManager mLockManager;
private final WifiController mWifiController;
@@ -225,17 +224,23 @@
wifiStateMachineLooper, UserManager.get(mContext),
this, mBackupManagerProxy, mCountryCode, mWifiNative,
new WrongPasswordNotifier(mContext, mFrameworkFacade));
- mCertManager = new WifiCertManager(mContext);
+ IBinder b = mFrameworkFacade.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService networkManagementService =
+ INetworkManagementService.Stub.asInterface(b);
+ mWifiStateMachinePrime = new WifiStateMachinePrime(this, wifiStateMachineLooper,
+ mWifiNative, networkManagementService);
mOpenNetworkNotifier = new OpenNetworkNotifier(mContext,
mWifiStateMachineHandlerThread.getLooper(), mFrameworkFacade, mClock, mWifiMetrics,
mWifiConfigManager, mWifiConfigStore, mWifiStateMachine,
new OpenNetworkRecommender(),
new ConnectToNetworkNotificationBuilder(mContext, mFrameworkFacade));
mWakeupController = new WakeupController(mContext,
- mWifiStateMachineHandlerThread.getLooper(), mFrameworkFacade);
+ mWifiStateMachineHandlerThread.getLooper(), new WakeupLock(mWifiConfigManager),
+ mWifiConfigManager, mWifiConfigStore, mFrameworkFacade);
mLockManager = new WifiLockManager(mContext, BatteryStatsService.getService());
mWifiController = new WifiController(mContext, mWifiStateMachine, mSettingsStore,
- mLockManager, mWifiServiceHandlerThread.getLooper(), mFrameworkFacade);
+ mLockManager, mWifiServiceHandlerThread.getLooper(), mFrameworkFacade,
+ mWifiStateMachinePrime);
mSelfRecovery = new SelfRecovery(mWifiController, mClock);
mWifiLastResortWatchdog = new WifiLastResortWatchdog(mSelfRecovery, mWifiMetrics);
mWifiMulticastLockManager = new WifiMulticastLockManager(mWifiStateMachine,
@@ -300,12 +305,12 @@
return mWifiStateMachine;
}
- public WifiSettingsStore getWifiSettingsStore() {
- return mSettingsStore;
+ public WifiStateMachinePrime getWifiStateMachinePrime() {
+ return mWifiStateMachinePrime;
}
- public WifiCertManager getWifiCertManager() {
- return mCertManager;
+ public WifiSettingsStore getWifiSettingsStore() {
+ return mSettingsStore;
}
public WifiLockManager getWifiLockManager() {
@@ -376,20 +381,15 @@
* @param nmService NetworkManagementService allowing SoftApManager to listen for interface
* changes
* @param listener listener for SoftApManager
- * @param apInterface network interface to start hostapd against
- * @param ifaceName name of the ap interface
* @param config SoftApModeConfiguration object holding the config and mode
* @return an instance of SoftApManager
*/
public SoftApManager makeSoftApManager(INetworkManagementService nmService,
SoftApManager.Listener listener,
- @NonNull IApInterface apInterface,
- @NonNull String ifaceName,
@NonNull SoftApModeConfiguration config) {
- return new SoftApManager(mContext, mWifiServiceHandlerThread.getLooper(),
- mWifiNative, mCountryCode.getCountryCode(),
- listener, apInterface, ifaceName, nmService,
- mWifiApConfigStore, config, mWifiMetrics);
+ return new SoftApManager(mContext, mWifiStateMachineHandlerThread.getLooper(),
+ mFrameworkFacade, mWifiNative, mCountryCode.getCountryCode(), listener,
+ nmService, mWifiApConfigStore, config, mWifiMetrics);
}
/**
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index 2f1b550..3118761 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -152,6 +152,105 @@
}
}
+ /**
+ * TODO(b/69426063): NEW API Surface for interface management. This will eventually
+ * deprecate the other interface management API's above. But, for now there will be
+ * some duplication to ease transition.
+ */
+ /**
+ * Initialize the native modules.
+ *
+ * @return true on success, false otherwise.
+ */
+ public boolean initialize() {
+ return false;
+ }
+
+ /**
+ * Callback to notify when the status of one of the native daemons
+ * (wificond, wpa_supplicant & vendor HAL) changes.
+ */
+ public interface StatusListener {
+ /**
+ * @param allReady Indicates if all the native daemons are ready for operation or not.
+ */
+ void onStatusChanged(boolean allReady);
+ }
+
+ /**
+ * Register a StatusListener to get notified about any status changes from the native daemons.
+ *
+ * It is safe to re-register the same callback object - duplicates are detected and only a
+ * single copy kept.
+ *
+ * @param listener StatusListener listener object.
+ */
+ public void registerStatusListener(@NonNull StatusListener listener) {
+ }
+
+ /**
+ * Callback to notify when the associated interface is destroyed, up or down.
+ */
+ public interface InterfaceCallback {
+ /**
+ * Interface destroyed by HalDeviceManager.
+ *
+ * @param ifaceName Name of the iface.
+ */
+ void onDestroyed(String ifaceName);
+
+ /**
+ * Interface is up.
+ *
+ * @param ifaceName Name of the iface.
+ */
+ void onUp(String ifaceName);
+
+ /**
+ * Interface is down.
+ *
+ * @param ifaceName Name of the iface.
+ */
+ void onDown(String ifaceName);
+ }
+
+ /**
+ * Setup an interface for Client mode operations.
+ *
+ * This method configures an interface in STA mode in all the native daemons
+ * (wificond, wpa_supplicant & vendor HAL).
+ *
+ * @param interfaceCallback Associated callback for notifying status changes for the iface.
+ * @return Returns the name of the allocated interface, will be null on failure.
+ */
+ public String setupInterfaceForClientMode(@NonNull InterfaceCallback interfaceCallback) {
+ return null;
+ }
+
+ /**
+ * Setup an interface for Soft AP mode operations.
+ *
+ * This method configures an interface in AP mode in all the native daemons
+ * (wificond, wpa_supplicant & vendor HAL).
+ *
+ * @param interfaceCallback Associated callback for notifying status changes for the iface.
+ * @return Returns the name of the allocated interface, will be null on failure.
+ */
+ public String setupInterfaceForSoftApMode(@NonNull InterfaceCallback interfaceCallback) {
+ return null;
+ }
+
+ /**
+ * Teardown an interface in Client/AP mode.
+ *
+ * This method tears down the associated interface from all the native daemons
+ * (wificond, wpa_supplicant & vendor HAL).
+ *
+ * @param ifaceName Name of the interface.
+ */
+ public void teardownInterface(@NonNull String ifaceName) {
+ }
+
/********************************************************
* Wificond operations
********************************************************/
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index 8e6a819..2724cb5 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -97,6 +97,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import android.util.MutableInt;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -170,8 +171,6 @@
final WifiSettingsStore mSettingsStore;
/* Logs connection events and some general router and scan stats */
private final WifiMetrics mWifiMetrics;
- /* Manages affiliated certificates for current user */
- private final WifiCertManager mCertManager;
private final WifiInjector mWifiInjector;
/* Backup/Restore Module */
@@ -201,6 +200,18 @@
private final ConcurrentHashMap<String, Integer> mIfaceIpModes;
/**
+ * One of: {@link WifiManager#WIFI_AP_STATE_DISABLED},
+ * {@link WifiManager#WIFI_AP_STATE_DISABLING},
+ * {@link WifiManager#WIFI_AP_STATE_ENABLED},
+ * {@link WifiManager#WIFI_AP_STATE_ENABLING},
+ * {@link WifiManager#WIFI_AP_STATE_FAILED}
+ *
+ * Access/maintenance MUST be done on the wifi service thread
+ */
+ private int mWifiApState = WifiManager.WIFI_AP_STATE_DISABLED;
+
+
+ /**
* Callback for use with LocalOnlyHotspot to unregister requesting applications upon death.
*
* @hide
@@ -433,7 +444,6 @@
mPowerManager = mContext.getSystemService(PowerManager.class);
mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
- mCertManager = mWifiInjector.getWifiCertManager();
mWifiLockManager = mWifiInjector.getWifiLockManager();
mWifiMulticastLockManager = mWifiInjector.getWifiMulticastLockManager();
HandlerThread wifiServiceHandlerThread = mWifiInjector.getWifiServiceHandlerThread();
@@ -790,8 +800,7 @@
}
// If SoftAp is enabled, only Settings is allowed to toggle wifi
- boolean apEnabled =
- mWifiStateMachine.syncGetWifiApState() != WifiManager.WIFI_AP_STATE_DISABLED;
+ boolean apEnabled = mWifiApState != WifiManager.WIFI_AP_STATE_DISABLED;
if (apEnabled && !isFromSettings) {
mLog.info("setWifiEnabled SoftAp not disabled: only Settings can enable wifi").flush();
@@ -863,7 +872,13 @@
public int getWifiApEnabledState() {
enforceAccessPermission();
mLog.info("getWifiApEnabledState uid=%").c(Binder.getCallingUid()).flush();
- return mWifiStateMachine.syncGetWifiApState();
+
+ // hand off work to our handler thread
+ MutableInt apState = new MutableInt(WifiManager.WIFI_AP_STATE_DISABLED);
+ mClientHandler.runWithScissors(() -> {
+ apState.value = mWifiApState;
+ }, 0);
+ return apState.value;
}
/**
@@ -1024,6 +1039,8 @@
/**
* Private method to handle SoftAp state changes
+ *
+ * <p> MUST be called from the WifiStateMachine thread.
*/
private void handleWifiApStateChange(
int currentState, int previousState, int errorCode, String ifaceName, int mode) {
@@ -1032,6 +1049,9 @@
+ " previousState=" + previousState + " errorCode= " + errorCode
+ " ifaceName=" + ifaceName + " mode=" + mode);
+ // update the tracking ap state variable
+ mWifiApState = currentState;
+
// check if we have a failure - since it is possible (worst case scenario where
// WifiController and WifiStateMachine are out of sync wrt modes) to get two FAILED
// notifications in a row, we need to handle this first.
@@ -1733,12 +1753,19 @@
@Override
public WifiInfo getConnectionInfo(String callingPackage) {
enforceAccessPermission();
- mLog.info("getConnectionInfo uid=%").c(Binder.getCallingUid()).flush();
+ int uid = Binder.getCallingUid();
+ mLog.info("getConnectionInfo uid=%").c(uid).flush();
/*
* Make sure we have the latest information, by sending
* a status request to the supplicant.
*/
- return mWifiStateMachine.syncRequestConnectionInfo(callingPackage);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ WifiInfo result = mWifiStateMachine.syncRequestConnectionInfo(callingPackage, uid);
+ return result;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
/**
@@ -2410,38 +2437,6 @@
return mWifiStateMachine.getAggressiveHandover();
}
- @Override
- public void setAllowScansWithTraffic(int enabled) {
- enforceAccessPermission();
- mLog.info("setAllowScansWithTraffic uid=% enabled=%")
- .c(Binder.getCallingUid())
- .c(enabled).flush();
- mWifiStateMachine.setAllowScansWithTraffic(enabled);
- }
-
- @Override
- public int getAllowScansWithTraffic() {
- enforceAccessPermission();
- mLog.info("getAllowScansWithTraffic uid=%").c(Binder.getCallingUid()).flush();
- return mWifiStateMachine.getAllowScansWithTraffic();
- }
-
- @Override
- public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
- enforceChangePermission();
- mLog.info("setEnableAutoJoinWhenAssociated uid=% enabled=%")
- .c(Binder.getCallingUid())
- .c(enabled).flush();
- return mWifiStateMachine.setEnableAutoJoinWhenAssociated(enabled);
- }
-
- @Override
- public boolean getEnableAutoJoinWhenAssociated() {
- enforceAccessPermission();
- mLog.info("getEnableAutoJoinWhenAssociated uid=%").c(Binder.getCallingUid()).flush();
- return mWifiStateMachine.getEnableAutoJoinWhenAssociated();
- }
-
/* Return the Wifi Connection statistics object */
@Override
public WifiConnectionStatistics getConnectionStatistics() {
@@ -2549,14 +2544,6 @@
return sb.toString();
}
- public void hideCertFromUnaffiliatedUsers(String alias) {
- mCertManager.hideCertFromUnaffiliatedUsers(alias);
- }
-
- public String[] listClientCertsForCurrentUser() {
- return mCertManager.listClientCertsForCurrentUser();
- }
-
/**
* Enable/disable WifiConnectivityManager at runtime
*
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index b69d67b..505a09b 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -29,9 +29,7 @@
import static android.telephony.TelephonyManager.CALL_STATE_IDLE;
import static android.telephony.TelephonyManager.CALL_STATE_OFFHOOK;
-import android.Manifest;
import android.app.ActivityManager;
-import android.app.AppGlobals;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
@@ -39,7 +37,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.net.ConnectivityManager;
@@ -60,7 +57,6 @@
import android.net.TrafficStats;
import android.net.dhcp.DhcpClient;
import android.net.ip.IpClient;
-import android.net.wifi.IApInterface;
import android.net.wifi.IClientInterface;
import android.net.wifi.RssiPacketCountInfo;
import android.net.wifi.ScanResult;
@@ -82,7 +78,6 @@
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.p2p.IWifiP2pManager;
import android.os.BatteryStats;
-import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
@@ -128,6 +123,7 @@
import com.android.server.wifi.util.TelephonyUtil.SimAuthRequestData;
import com.android.server.wifi.util.TelephonyUtil.SimAuthResponseData;
import com.android.server.wifi.util.WifiPermissionsUtil;
+import com.android.server.wifi.util.WifiPermissionsWrapper;
import java.io.BufferedReader;
import java.io.FileDescriptor;
@@ -184,7 +180,7 @@
private static final String EXTRA_OSU_PROVIDER = "OsuProvider";
private boolean mVerboseLoggingEnabled = false;
-
+ private final WifiPermissionsWrapper mWifiPermissionsWrapper;
/* debug flag, indicating if handling of ASSOCIATION_REJECT ended up blacklisting
* the corresponding BSSID.
*/
@@ -700,8 +696,6 @@
/* Enable/Disable WifiConnectivityManager */
static final int CMD_ENABLE_WIFI_CONNECTIVITY_MANAGER = BASE + 166;
- /* Enable/Disable AutoJoin when associated */
- static final int CMD_ENABLE_AUTOJOIN_WHEN_ASSOCIATED = BASE + 167;
/* Get all matching Passpoint configurations */
static final int CMD_GET_ALL_MATCHING_CONFIGS = BASE + 168;
@@ -799,8 +793,6 @@
*/
private long mSupplicantScanIntervalMs;
- private boolean mEnableAutoJoinWhenAssociated;
- private int mAlwaysEnableScansWhileAssociated;
private final int mThresholdQualifiedRssi24;
private final int mThresholdQualifiedRssi5;
private final int mThresholdSaturatedRssi24;
@@ -951,6 +943,7 @@
mWifiMonitor = mWifiInjector.getWifiMonitor();
mWifiDiagnostics = mWifiInjector.makeWifiDiagnostics(mWifiNative);
+ mWifiPermissionsWrapper = mWifiInjector.getWifiPermissionsWrapper();
mWifiInfo = new ExtendedWifiInfo();
mSupplicantStateTracker =
@@ -1040,8 +1033,6 @@
com.android.internal.R.string.config_wifi_tcp_buffers);
// Load Device configs
- mEnableAutoJoinWhenAssociated = context.getResources().getBoolean(
- R.bool.config_wifi_framework_enable_associated_network_selection);
mThresholdQualifiedRssi24 = context.getResources().getInteger(
R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz);
mThresholdQualifiedRssi5 = context.getResources().getInteger(
@@ -1280,26 +1271,6 @@
// mWifiConfigManager.trimANQPCache(true);
}
- public void setAllowScansWithTraffic(int enabled) {
- mAlwaysEnableScansWhileAssociated = enabled;
- }
-
- public int getAllowScansWithTraffic() {
- return mAlwaysEnableScansWhileAssociated;
- }
-
- /*
- * Dynamically turn on/off if switching networks while connected is allowd.
- */
- public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
- sendMessage(CMD_ENABLE_AUTOJOIN_WHEN_ASSOCIATED, enabled ? 1 : 0);
- return true;
- }
-
- public boolean getEnableAutoJoinWhenAssociated() {
- return mEnableAutoJoinWhenAssociated;
- }
-
private boolean setRandomMacOui() {
String oui = mContext.getResources().getString(R.string.config_wifi_random_mac_oui);
if (TextUtils.isEmpty(oui)) {
@@ -1704,9 +1675,9 @@
/**
* TODO: doc
*/
- public int syncGetWifiApState() {
- return mWifiApState.get();
- }
+ //public int syncGetWifiApState() {
+ // return mWifiApState.get();
+ //}
/**
* TODO: doc
@@ -1763,20 +1734,18 @@
/**
* Get status information for the current connection, if any.
*
+ * @param callingPackage string indicating the calling package of the caller
+ * @param uid the calling uid
* @return a {@link WifiInfo} object containing information about the current connection
*/
- public WifiInfo syncRequestConnectionInfo(String callingPackage) {
- int uid = Binder.getCallingUid();
+ public WifiInfo syncRequestConnectionInfo(String callingPackage, int uid) {
WifiInfo result = new WifiInfo(mWifiInfo);
- if (uid == Process.myUid()) return result;
boolean hideBssidAndSsid = true;
result.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS);
- IPackageManager packageManager = AppGlobals.getPackageManager();
-
try {
- if (packageManager.checkUidPermission(Manifest.permission.LOCAL_MAC_ADDRESS,
- uid) == PackageManager.PERMISSION_GRANTED) {
+ if (mWifiPermissionsWrapper.getLocalMacAddressPermission(uid)
+ == PackageManager.PERMISSION_GRANTED) {
result.setMacAddress(mWifiInfo.getMacAddress());
}
if (mWifiPermissionsUtil.canAccessScanResults(
@@ -2311,6 +2280,7 @@
} else {
pw.println("mWifiConnectivityManager is not initialized");
}
+ mWifiInjector.getWakeupController().dump(fd, pw, args);
}
public void handleUserSwitch(int userId) {
@@ -2949,6 +2919,7 @@
// Update state
mWifiApState.set(wifiApState);
+ // TODO: when this code is removed, also remove syncGetWifiApStateByName()
if (mVerboseLoggingEnabled) log("setWifiApState: " + syncGetWifiApStateByName());
}
@@ -3279,16 +3250,18 @@
|| stateChangeResult.wifiSsid.toString().isEmpty()) && isLinkDebouncing()) {
return state;
}
- // Network id is only valid when we start connecting
+ // Network id and SSID are only valid when we start connecting
if (SupplicantState.isConnecting(state)) {
mWifiInfo.setNetworkId(lookupFrameworkNetworkId(stateChangeResult.networkId));
+ mWifiInfo.setBSSID(stateChangeResult.BSSID);
+ mWifiInfo.setSSID(stateChangeResult.wifiSsid);
} else {
+ // Reset parameters according to WifiInfo.reset()
mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
+ mWifiInfo.setBSSID(null);
+ mWifiInfo.setSSID(null);
}
- mWifiInfo.setBSSID(stateChangeResult.BSSID);
- mWifiInfo.setSSID(stateChangeResult.wifiSsid);
-
final WifiConfiguration config = getCurrentWifiConfiguration();
if (config != null) {
mWifiInfo.setEphemeral(config.ephemeral);
@@ -4177,6 +4150,9 @@
// Tearing down the client interfaces below is going to stop our supplicant.
mWifiMonitor.stopAllMonitoring();
+ // stop hostapd in case it was running from SoftApMode
+ mWifiNative.stopSoftAp();
+
mWifiNative.deregisterWificondDeathHandler();
mWifiNative.tearDown();
}
@@ -4323,9 +4299,12 @@
transitionTo(mInitialState);
}
break;
+ case CMD_START_AP:
+ // now go directly to softap mode since we handle teardown in WSMP
+ transitionTo(mSoftApState);
+ break;
case CMD_START_SUPPLICANT:
case CMD_STOP_SUPPLICANT:
- case CMD_START_AP:
case CMD_STOP_AP:
case CMD_SET_OPERATIONAL_MODE:
messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
@@ -4475,10 +4454,12 @@
sendMessage(mBufferedScanMsg.remove());
break;
case CMD_START_AP:
- /* Cannot start soft AP while in client mode */
- loge("Failed to start soft AP with a running supplicant");
- setWifiApState(WIFI_AP_STATE_FAILED, WifiManager.SAP_START_FAILURE_GENERAL,
- null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
+ // /* Cannot start soft AP while in client mode */
+ // loge("Failed to start soft AP with a running supplicant");
+ // setWifiApState(WIFI_AP_STATE_FAILED, WifiManager.SAP_START_FAILURE_GENERAL,
+ // null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
+ // now go directly to softap mode since we handle teardown in WSMP
+ transitionTo(mSoftApState);
break;
case CMD_SET_OPERATIONAL_MODE:
mOperationalMode = message.arg1;
@@ -4557,15 +4538,6 @@
case CMD_ENABLE_WIFI_CONNECTIVITY_MANAGER:
mWifiConnectivityManager.enable(message.arg1 == 1 ? true : false);
break;
- case CMD_ENABLE_AUTOJOIN_WHEN_ASSOCIATED:
- final boolean allowed = (message.arg1 > 0);
- boolean old_state = mEnableAutoJoinWhenAssociated;
- mEnableAutoJoinWhenAssociated = allowed;
- if (!old_state && allowed && mScreenOn
- && getCurrentState() == mConnectedState) {
- mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE);
- }
- break;
case CMD_SELECT_TX_POWER_SCENARIO:
int txPowerScenario = message.arg1;
logd("Setting Tx power scenario to " + txPowerScenario);
@@ -4943,6 +4915,7 @@
}
mWifiInfo.reset();
mWifiInfo.setSupplicantState(SupplicantState.DISCONNECTED);
+ setWifiState(WIFI_STATE_DISABLED);
}
@Override
@@ -6981,6 +6954,7 @@
private String mIfaceName;
private int mMode;
+ /*
private class SoftApListener implements SoftApManager.Listener {
@Override
public void onStateChanged(int state, int reason) {
@@ -6993,6 +6967,7 @@
setWifiApState(state, reason, mIfaceName, mMode);
}
}
+ */
@Override
public void enter() {
@@ -7000,6 +6975,7 @@
if (message.what != CMD_START_AP) {
throw new RuntimeException("Illegal transition to SoftApState: " + message);
}
+ /*
SoftApModeConfiguration config = (SoftApModeConfiguration) message.obj;
mMode = config.getTargetMode();
@@ -7033,11 +7009,10 @@
checkAndSetConnectivityInstance();
mSoftApManager = mWifiInjector.makeSoftApManager(mNwService,
new SoftApListener(),
- apInterface,
- mIfaceName,
config);
mSoftApManager.start();
mWifiStateTracker.updateState(WifiStateTracker.SOFT_AP);
+ */
}
@Override
@@ -7056,7 +7031,8 @@
/* Ignore start command when it is starting/started. */
break;
case CMD_STOP_AP:
- mSoftApManager.stop();
+ //mSoftApManager.stop();
+ transitionTo(mInitialState);
break;
case CMD_START_AP_FAILURE:
transitionTo(mInitialState);
diff --git a/service/java/com/android/server/wifi/WifiStateMachinePrime.java b/service/java/com/android/server/wifi/WifiStateMachinePrime.java
index c49b645..2d3aaba 100644
--- a/service/java/com/android/server/wifi/WifiStateMachinePrime.java
+++ b/service/java/com/android/server/wifi/WifiStateMachinePrime.java
@@ -17,14 +17,11 @@
package com.android.server.wifi;
import android.annotation.NonNull;
-import android.net.wifi.IApInterface;
-import android.net.wifi.IWificond;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
-import android.os.RemoteException;
import android.util.Log;
import com.android.internal.util.Protocol;
@@ -47,12 +44,13 @@
private final WifiInjector mWifiInjector;
private final Looper mLooper;
+ private final WifiNative mWifiNative;
private final INetworkManagementService mNMService;
- private IWificond mWificond;
-
private Queue<SoftApModeConfiguration> mApConfigQueue = new ConcurrentLinkedQueue<>();
+ private String mInterfaceName;
+
/* The base for wifi message types */
static final int BASE = Protocol.BASE_WIFI;
@@ -67,22 +65,17 @@
WifiStateMachinePrime(WifiInjector wifiInjector,
Looper looper,
+ WifiNative wifiNative,
INetworkManagementService nmService) {
mWifiInjector = wifiInjector;
mLooper = looper;
+ mWifiNative = wifiNative;
mNMService = nmService;
- // Clean up existing interfaces in wificond.
- // This ensures that the framework and wificond are in a consistent state after a framework
- // restart.
- try {
- mWificond = mWifiInjector.makeWificond();
- if (mWificond != null) {
- mWificond.tearDownInterfaces();
- }
- } catch (RemoteException e) {
- Log.e(TAG, "wificond died during framework startup");
- }
+ mInterfaceName = mWifiNative.getInterfaceName();
+
+ // make sure we do not have leftover state in the event of a restart
+ mWifiNative.tearDown();
}
/**
@@ -211,23 +204,14 @@
return HANDLED;
}
- private void tearDownInterfaces() {
- if (mWificond != null) {
- try {
- mWificond.tearDownInterfaces();
- } catch (RemoteException e) {
- // There is very little we can do here
- Log.e(TAG, "Failed to tear down interfaces via wificond");
- }
- mWificond = null;
- }
- return;
+ private void cleanup() {
+ mWifiNative.disableSupplicant();
+ mWifiNative.tearDown();
}
class ClientModeState extends State {
@Override
public void enter() {
- mWificond = mWifiInjector.makeWificond();
}
@Override
@@ -240,7 +224,7 @@
@Override
public void exit() {
- tearDownInterfaces();
+ cleanup();
}
}
@@ -266,33 +250,18 @@
}
class SoftAPModeState extends State {
- IApInterface mApInterface = null;
- String mIfaceName = null;
@Override
public void enter() {
+ // For now - need to clean up from other mode management in WSM
+ cleanup();
+
final Message message = mModeStateMachine.getCurrentMessage();
if (message.what != ModeStateMachine.CMD_START_SOFT_AP_MODE) {
Log.d(TAG, "Entering SoftAPMode (idle)");
return;
}
- // Continue with setup since we are changing modes
- mApInterface = null;
-
- try {
- mWificond = mWifiInjector.makeWificond();
- mApInterface = mWificond.createApInterface(
- mWifiInjector.getWifiNative().getInterfaceName());
- mIfaceName = mApInterface.getInterfaceName();
- } catch (RemoteException e) {
- initializationFailed(
- "Could not get IApInterface instance or its name from wificond");
- return;
- } catch (NullPointerException e) {
- initializationFailed("wificond failure when initializing softap mode");
- return;
- }
mModeStateMachine.transitionTo(mSoftAPModeActiveState);
}
@@ -310,9 +279,8 @@
// not in active state, nothing to stop.
break;
case CMD_START_AP_FAILURE:
- // remove the saved config for the start attempt
- mApConfigQueue.poll();
- Log.e(TAG, "Failed to start SoftApMode. Wait for next mode command.");
+ // with interface management in softapmanager, no setup failures can be seen
+ // here
break;
case CMD_AP_STOPPED:
Log.d(TAG, "SoftApModeActiveState stopped. Wait for next mode command.");
@@ -325,15 +293,9 @@
@Override
public void exit() {
- tearDownInterfaces();
- }
-
- protected IApInterface getInterface() {
- return mApInterface;
- }
-
- protected String getInterfaceName() {
- return mIfaceName;
+ // while in transition, cleanup is done on entering states. in the future, each
+ // mode will clean up their own state on exit
+ //cleanup();
}
private void initializationFailed(String message) {
@@ -345,8 +307,9 @@
class WifiDisabledState extends State {
@Override
public void enter() {
- // make sure everything is torn down
Log.d(TAG, "Entering WifiDisabledState");
+ // make sure everything is torn down
+ cleanup();
}
@Override
@@ -415,9 +378,8 @@
config = null;
}
this.mActiveModeManager = mWifiInjector.makeSoftApManager(mNMService,
- new SoftApListener(), ((SoftAPModeState) mSoftAPModeState).getInterface(),
- ((SoftAPModeState) mSoftAPModeState).getInterfaceName(), softApModeConfig);
- mActiveModeManager.start();
+ new SoftApListener(), softApModeConfig);
+ this.mActiveModeManager.start();
}
@Override
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java b/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java
index 421d9ac..62cc3ec 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java
@@ -329,8 +329,8 @@
enforceNetworkStackPermission();
}
- if (message != null
- && message.length > mStateManager.getCharacteristics().getMaxServiceNameLength()) {
+ if (message != null && message.length
+ > mStateManager.getCharacteristics().getMaxServiceSpecificInfoLength()) {
throw new IllegalArgumentException(
"Message length longer than supported by device characteristics");
}
diff --git a/service/java/com/android/server/wifi/rtt/RttNative.java b/service/java/com/android/server/wifi/rtt/RttNative.java
index e920310..e085352 100644
--- a/service/java/com/android/server/wifi/rtt/RttNative.java
+++ b/service/java/com/android/server/wifi/rtt/RttNative.java
@@ -206,11 +206,8 @@
for (ResponderConfig responder: request.mRttPeers) {
RttConfig config = new RttConfig();
- if (responder.macAddress.length != config.addr.length) {
- Log.e(TAG, "Invalid configuration: unexpected BSSID length -- " + responder);
- continue;
- }
- System.arraycopy(responder.macAddress, 0, config.addr, 0, config.addr.length);
+ System.arraycopy(responder.macAddress.toByteArray(), 0, config.addr, 0,
+ config.addr.length);
try {
config.type = responder.supports80211mc ? RttType.TWO_SIDED : RttType.ONE_SIDED;
diff --git a/service/java/com/android/server/wifi/rtt/RttService.java b/service/java/com/android/server/wifi/rtt/RttService.java
index 5c2cec1..afffbee 100644
--- a/service/java/com/android/server/wifi/rtt/RttService.java
+++ b/service/java/com/android/server/wifi/rtt/RttService.java
@@ -43,14 +43,14 @@
@Override
public void onStart() {
- Log.i(TAG, "Registering " + Context.WIFI_RTT2_SERVICE);
- publishBinderService(Context.WIFI_RTT2_SERVICE, mImpl);
+ Log.i(TAG, "Registering " + Context.WIFI_RTT_RANGING_SERVICE);
+ publishBinderService(Context.WIFI_RTT_RANGING_SERVICE, mImpl);
}
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
- Log.i(TAG, "Starting " + Context.WIFI_RTT2_SERVICE);
+ Log.i(TAG, "Starting " + Context.WIFI_RTT_RANGING_SERVICE);
WifiInjector wifiInjector = WifiInjector.getInstance();
if (wifiInjector == null) {
diff --git a/service/java/com/android/server/wifi/rtt/RttServiceImpl.java b/service/java/com/android/server/wifi/rtt/RttServiceImpl.java
index ff722ae..3417f74 100644
--- a/service/java/com/android/server/wifi/rtt/RttServiceImpl.java
+++ b/service/java/com/android/server/wifi/rtt/RttServiceImpl.java
@@ -24,6 +24,7 @@
import android.content.pm.PackageManager;
import android.hardware.wifi.V1_0.RttResult;
import android.hardware.wifi.V1_0.RttStatus;
+import android.net.MacAddress;
import android.net.wifi.aware.IWifiAwareMacAddressProvider;
import android.net.wifi.aware.IWifiAwareManager;
import android.net.wifi.rtt.IRttCallback;
@@ -48,8 +49,6 @@
import com.android.server.wifi.Clock;
import com.android.server.wifi.util.WifiPermissionsUtil;
-import libcore.util.HexEncoding;
-
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -350,11 +349,7 @@
private void cancelRanging(RttRequestInfo rri) {
ArrayList<byte[]> macAddresses = new ArrayList<>();
for (ResponderConfig peer : rri.request.mRttPeers) {
- if (peer.macAddress.length != 6) {
- Log.e(TAG, "Invalid configuration: unexpected BSSID length -- " + peer);
- continue;
- }
- macAddresses.add(peer.macAddress);
+ macAddresses.add(peer.macAddress.toByteArray());
}
mRttNative.rangeCancel(rri.cmdId, macAddresses);
@@ -472,7 +467,7 @@
try {
callback.onRangingFailure(RangingResultCallback.STATUS_CODE_FAIL);
} catch (RemoteException e) {
- Log.e(TAG, "RttServiceSynchronized.queueRangingRequest: spamming, callback "
+ Log.e(TAG, "RttServiceSynchronized.queueRangingRequest: spamming, callback "
+ "failed -- " + e);
}
return;
@@ -609,7 +604,7 @@
/**
* Perform pre-execution throttling checks:
* - If all uids in ws are in background then check last execution and block if request is
- * more frequent than permitted
+ * more frequent than permitted
* - If executing (i.e. permitted) then update execution time
*
* Returns true to permit execution, false to abort it.
@@ -735,9 +730,10 @@
+ ", peerIdToMacMap=" + peerIdToMacMap);
}
- for (ResponderConfig rttPeer: request.request.mRttPeers) {
+ for (ResponderConfig rttPeer : request.request.mRttPeers) {
if (rttPeer.peerHandle != null && rttPeer.macAddress == null) {
- rttPeer.macAddress = peerIdToMacMap.get(rttPeer.peerHandle.peerId);
+ rttPeer.macAddress = MacAddress.fromBytes(
+ peerIdToMacMap.get(rttPeer.peerHandle.peerId));
}
}
@@ -799,20 +795,18 @@
*/
private List<RangingResult> postProcessResults(RangingRequest request,
List<RttResult> results) {
- Map<String, RttResult> resultEntries = new HashMap<>();
- for (RttResult result: results) {
- resultEntries.put(new String(HexEncoding.encode(result.addr)), result);
+ Map<MacAddress, RttResult> resultEntries = new HashMap<>();
+ for (RttResult result : results) {
+ resultEntries.put(MacAddress.fromBytes(result.addr), result);
}
List<RangingResult> finalResults = new ArrayList<>(request.mRttPeers.size());
- for (ResponderConfig peer: request.mRttPeers) {
- RttResult resultForRequest = resultEntries.get(
- new String(HexEncoding.encode(peer.macAddress)));
+ for (ResponderConfig peer : request.mRttPeers) {
+ RttResult resultForRequest = resultEntries.get(peer.macAddress);
if (resultForRequest == null) {
if (VDBG) {
- Log.v(TAG, "postProcessResults: missing=" + new String(
- HexEncoding.encode(peer.macAddress)));
+ Log.v(TAG, "postProcessResults: missing=" + peer.macAddress);
}
if (peer.peerHandle == null) {
finalResults.add(
diff --git a/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java b/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
index 72a7a27..9afe061 100644
--- a/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
+++ b/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
@@ -35,7 +35,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -66,28 +65,16 @@
private final Object mSettingsLock = new Object();
- // Next scan settings to apply when the previous scan completes
- private WifiNative.ScanSettings mPendingSingleScanSettings = null;
- private WifiNative.ScanEventHandler mPendingSingleScanEventHandler = null;
-
private ArrayList<ScanDetail> mNativeScanResults;
private WifiScanner.ScanData mLatestSingleScanResult =
new WifiScanner.ScanData(0, 0, new ScanResult[0]);
- // Settings for the currently running scan, null if no scan active
+ // Settings for the currently running single scan, null if no scan active
private LastScanSettings mLastScanSettings = null;
+ // Settings for the currently running pno scan, null if no scan active
+ private LastPnoScanSettings mLastPnoScanSettings = null;
- // Pno related info.
- private WifiNative.PnoSettings mPnoSettings = null;
- private WifiNative.PnoEventHandler mPnoEventHandler;
private final boolean mHwPnoScanSupported;
- private final HwPnoDebouncer mHwPnoDebouncer;
- private final HwPnoDebouncer.Listener mHwPnoDebouncerListener = new HwPnoDebouncer.Listener() {
- public void onPnoScanFailed() {
- Log.e(TAG, "Pno scan failure received");
- reportPnoScanFailure();
- }
- };
/**
* Duration to wait before timing out a scan.
@@ -114,7 +101,6 @@
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mEventHandler = new Handler(looper, this);
mClock = clock;
- mHwPnoDebouncer = new HwPnoDebouncer(mWifiNative, mAlarmManager, mEventHandler, mClock);
// Check if the device supports HW PNO scans.
mHwPnoScanSupported = mContext.getResources().getBoolean(
@@ -131,10 +117,9 @@
@Override
public void cleanup() {
synchronized (mSettingsLock) {
- mPendingSingleScanSettings = null;
- mPendingSingleScanEventHandler = null;
stopHwPnoScan();
mLastScanSettings = null; // finally clear any active scan
+ mLastPnoScanSettings = null; // finally clear any active scan
}
}
@@ -162,14 +147,65 @@
return false;
}
synchronized (mSettingsLock) {
- if (mPendingSingleScanSettings != null
- || (mLastScanSettings != null && mLastScanSettings.singleScanActive)) {
+ if (mLastScanSettings != null) {
Log.w(TAG, "A single scan is already running");
return false;
}
- mPendingSingleScanSettings = settings;
- mPendingSingleScanEventHandler = eventHandler;
- processPendingScans();
+
+ ChannelCollection allFreqs = mChannelHelper.createChannelCollection();
+ boolean reportFullResults = false;
+
+ for (int i = 0; i < settings.num_buckets; ++i) {
+ WifiNative.BucketSettings bucketSettings = settings.buckets[i];
+ if ((bucketSettings.report_events
+ & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
+ reportFullResults = true;
+ }
+ allFreqs.addChannels(bucketSettings);
+ }
+
+ Set<String> hiddenNetworkSSIDSet = new HashSet<>();
+ if (settings.hiddenNetworks != null) {
+ int numHiddenNetworks =
+ Math.min(settings.hiddenNetworks.length, MAX_HIDDEN_NETWORK_IDS_PER_SCAN);
+ for (int i = 0; i < numHiddenNetworks; i++) {
+ hiddenNetworkSSIDSet.add(settings.hiddenNetworks[i].ssid);
+ }
+ }
+ mLastScanSettings = new LastScanSettings(
+ mClock.getElapsedSinceBootMillis(),
+ reportFullResults, allFreqs, eventHandler);
+
+ boolean success = false;
+ Set<Integer> freqs;
+ if (!allFreqs.isEmpty()) {
+ freqs = allFreqs.getScanFreqs();
+ success = mWifiNative.scan(freqs, hiddenNetworkSSIDSet);
+ if (!success) {
+ Log.e(TAG, "Failed to start scan, freqs=" + freqs);
+ }
+ } else {
+ // There is a scan request but no available channels could be scanned for.
+ // We regard it as a scan failure in this case.
+ Log.e(TAG, "Failed to start scan because there is no available channel to scan");
+ }
+ if (success) {
+ if (DBG) {
+ Log.d(TAG, "Starting wifi scan for freqs=" + freqs);
+ }
+
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ mClock.getElapsedSinceBootMillis() + SCAN_TIMEOUT_MS,
+ TIMEOUT_ALARM_TAG, mScanTimeoutListener, mEventHandler);
+ } else {
+ // indicate scan failure async
+ mEventHandler.post(new Runnable() {
+ public void run() {
+ reportScanFailure();
+ }
+ });
+ }
+
return true;
}
}
@@ -204,123 +240,6 @@
private void handleScanTimeout() {
Log.e(TAG, "Timed out waiting for scan result from wificond");
reportScanFailure();
- processPendingScans();
- }
-
- private boolean isDifferentPnoScanSettings(LastScanSettings newScanSettings) {
- return (mLastScanSettings == null || !Arrays.equals(
- newScanSettings.pnoNetworkList, mLastScanSettings.pnoNetworkList));
- }
-
- private void processPendingScans() {
- synchronized (mSettingsLock) {
- // Wait for the active scan result to come back to reschedule other scans,
- // unless if HW pno scan is running. Hw PNO scans are paused it if there
- // are other pending scans,
- if (mLastScanSettings != null && !mLastScanSettings.hwPnoScanActive) {
- return;
- }
-
- ChannelCollection allFreqs = mChannelHelper.createChannelCollection();
- Set<String> hiddenNetworkSSIDSet = new HashSet<>();
- final LastScanSettings newScanSettings =
- new LastScanSettings(mClock.getElapsedSinceBootMillis());
-
- if (mPendingSingleScanSettings != null) {
- boolean reportFullResults = false;
- ChannelCollection singleScanFreqs = mChannelHelper.createChannelCollection();
- for (int i = 0; i < mPendingSingleScanSettings.num_buckets; ++i) {
- WifiNative.BucketSettings bucketSettings =
- mPendingSingleScanSettings.buckets[i];
- if ((bucketSettings.report_events
- & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
- reportFullResults = true;
- }
- singleScanFreqs.addChannels(bucketSettings);
- allFreqs.addChannels(bucketSettings);
- }
- newScanSettings.setSingleScan(reportFullResults, singleScanFreqs,
- mPendingSingleScanEventHandler);
-
- WifiNative.HiddenNetwork[] hiddenNetworks =
- mPendingSingleScanSettings.hiddenNetworks;
- if (hiddenNetworks != null) {
- int numHiddenNetworks =
- Math.min(hiddenNetworks.length, MAX_HIDDEN_NETWORK_IDS_PER_SCAN);
- for (int i = 0; i < numHiddenNetworks; i++) {
- hiddenNetworkSSIDSet.add(hiddenNetworks[i].ssid);
- }
- }
-
- mPendingSingleScanSettings = null;
- mPendingSingleScanEventHandler = null;
- }
-
- if (newScanSettings.singleScanActive) {
- boolean success = false;
- Set<Integer> freqs;
- if (!allFreqs.isEmpty()) {
- pauseHwPnoScan();
- freqs = allFreqs.getScanFreqs();
- success = mWifiNative.scan(freqs, hiddenNetworkSSIDSet);
- if (!success) {
- Log.e(TAG, "Failed to start scan, freqs=" + freqs);
- }
- } else {
- // There is a scan request but no available channels could be scanned for.
- // We regard it as a scan failure in this case.
- Log.e(TAG, "Failed to start scan because there is "
- + "no available channel to scan for");
- }
- if (success) {
- // TODO handle scan timeout
- if (DBG) {
- Log.d(TAG, "Starting wifi scan for freqs=" + freqs
- + ", single=" + newScanSettings.singleScanActive);
- }
- mLastScanSettings = newScanSettings;
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- mClock.getElapsedSinceBootMillis() + SCAN_TIMEOUT_MS,
- TIMEOUT_ALARM_TAG, mScanTimeoutListener, mEventHandler);
- } else {
- // indicate scan failure async
- mEventHandler.post(new Runnable() {
- public void run() {
- if (newScanSettings.singleScanEventHandler != null) {
- newScanSettings.singleScanEventHandler
- .onScanStatus(WifiNative.WIFI_SCAN_FAILED);
- }
- }
- });
- }
- } else if (isHwPnoScanRequired()) {
- newScanSettings.setHwPnoScan(mPnoSettings.networkList, mPnoEventHandler);
- boolean status;
- // If the PNO network list has changed from the previous request, ensure that
- // we bypass the debounce logic and restart PNO scan.
- if (isDifferentPnoScanSettings(newScanSettings)) {
- status = restartHwPnoScan(mPnoSettings);
- } else {
- status = startHwPnoScan(mPnoSettings);
- }
- if (status) {
- mLastScanSettings = newScanSettings;
- } else {
- Log.e(TAG, "Failed to start PNO scan");
- // indicate scan failure async
- mEventHandler.post(new Runnable() {
- public void run() {
- if (mPnoEventHandler != null) {
- mPnoEventHandler.onPnoScanFailed();
- }
- // Clean up PNO state, we don't want to continue PNO scanning.
- mPnoSettings = null;
- mPnoEventHandler = null;
- }
- });
- }
- }
- }
}
@Override
@@ -330,16 +249,13 @@
Log.w(TAG, "Scan failed");
mAlarmManager.cancel(mScanTimeoutListener);
reportScanFailure();
- processPendingScans();
break;
case WifiMonitor.PNO_SCAN_RESULTS_EVENT:
pollLatestScanDataForPno();
- processPendingScans();
break;
case WifiMonitor.SCAN_RESULTS_EVENT:
mAlarmManager.cancel(mScanTimeoutListener);
pollLatestScanData();
- processPendingScans();
break;
default:
// ignore unknown event
@@ -361,21 +277,19 @@
private void reportPnoScanFailure() {
synchronized (mSettingsLock) {
- if (mLastScanSettings != null && mLastScanSettings.hwPnoScanActive) {
- if (mLastScanSettings.pnoScanEventHandler != null) {
- mLastScanSettings.pnoScanEventHandler.onPnoScanFailed();
+ if (mLastPnoScanSettings != null) {
+ if (mLastPnoScanSettings.pnoScanEventHandler != null) {
+ mLastPnoScanSettings.pnoScanEventHandler.onPnoScanFailed();
}
// Clean up PNO state, we don't want to continue PNO scanning.
- mPnoSettings = null;
- mPnoEventHandler = null;
- mLastScanSettings = null;
+ mLastPnoScanSettings = null;
}
}
}
private void pollLatestScanDataForPno() {
synchronized (mSettingsLock) {
- if (mLastScanSettings == null) {
+ if (mLastPnoScanSettings == null) {
// got a scan before we started scanning or after scan was canceled
return;
}
@@ -385,10 +299,8 @@
for (int i = 0; i < mNativeScanResults.size(); ++i) {
ScanResult result = mNativeScanResults.get(i).getScanResult();
long timestamp_ms = result.timestamp / 1000; // convert us -> ms
- if (timestamp_ms > mLastScanSettings.startTime) {
- if (mLastScanSettings.hwPnoScanActive) {
- hwPnoScanResults.add(result);
- }
+ if (timestamp_ms > mLastPnoScanSettings.startTime) {
+ hwPnoScanResults.add(result);
} else {
numFilteredScanResults++;
}
@@ -398,25 +310,11 @@
Log.d(TAG, "Filtering out " + numFilteredScanResults + " pno scan results.");
}
- if (mLastScanSettings.hwPnoScanActive
- && mLastScanSettings.pnoScanEventHandler != null) {
+ if (mLastPnoScanSettings.pnoScanEventHandler != null) {
ScanResult[] pnoScanResultsArray =
hwPnoScanResults.toArray(new ScanResult[hwPnoScanResults.size()]);
- mLastScanSettings.pnoScanEventHandler.onPnoNetworkFound(pnoScanResultsArray);
+ mLastPnoScanSettings.pnoScanEventHandler.onPnoNetworkFound(pnoScanResultsArray);
}
- // On pno scan result event, we are expecting a mLastScanSettings for pno scan.
- // However, if unlikey mLastScanSettings is for single scan, we need this part
- // to protect from leaving WifiSingleScanStateMachine in a forever wait state.
- if (mLastScanSettings.singleScanActive
- && mLastScanSettings.singleScanEventHandler != null) {
- Log.w(TAG, "Polling pno scan result when single scan is active, reporting"
- + " single scan failure");
- mLastScanSettings.singleScanEventHandler
- .onScanStatus(WifiNative.WIFI_SCAN_FAILED);
- }
- // mLastScanSettings is for either single/batched scan or pno scan.
- // We can safely set it to null when pno scan finishes.
- mLastScanSettings = null;
}
}
@@ -445,8 +343,7 @@
ScanResult result = mNativeScanResults.get(i).getScanResult();
long timestamp_ms = result.timestamp / 1000; // convert us -> ms
if (timestamp_ms > mLastScanSettings.startTime) {
- if (mLastScanSettings.singleScanActive
- && mLastScanSettings.singleScanFreqs.containsChannel(
+ if (mLastScanSettings.singleScanFreqs.containsChannel(
result.frequency)) {
singleScanResults.add(result);
}
@@ -458,8 +355,7 @@
Log.d(TAG, "Filtering out " + numFilteredScanResults + " scan results.");
}
- if (mLastScanSettings.singleScanActive
- && mLastScanSettings.singleScanEventHandler != null) {
+ if (mLastScanSettings.singleScanEventHandler != null) {
if (mLastScanSettings.reportSingleScanFullResults) {
for (ScanResult scanResult : singleScanResults) {
// ignore buckets scanned since there is only one bucket for a single scan
@@ -486,20 +382,11 @@
}
private boolean startHwPnoScan(WifiNative.PnoSettings pnoSettings) {
- return mHwPnoDebouncer.startPnoScan(pnoSettings, mHwPnoDebouncerListener);
+ return mWifiNative.startPnoScan(pnoSettings);
}
private void stopHwPnoScan() {
- mHwPnoDebouncer.stopPnoScan();
- }
-
- private void pauseHwPnoScan() {
- mHwPnoDebouncer.forceStopPnoScan();
- }
-
- private boolean restartHwPnoScan(WifiNative.PnoSettings pnoSettings) {
- mHwPnoDebouncer.forceStopPnoScan();
- return mHwPnoDebouncer.startPnoScan(pnoSettings, mHwPnoDebouncerListener);
+ mWifiNative.stopPnoScan();
}
/**
@@ -511,26 +398,27 @@
return (!isConnectedPno & mHwPnoScanSupported);
}
- private boolean isHwPnoScanRequired() {
- synchronized (mSettingsLock) {
- if (mPnoSettings == null) return false;
- return isHwPnoScanRequired(mPnoSettings.isConnected);
- }
- }
-
@Override
public boolean setHwPnoList(WifiNative.PnoSettings settings,
WifiNative.PnoEventHandler eventHandler) {
synchronized (mSettingsLock) {
- if (mPnoSettings != null) {
+ if (mLastPnoScanSettings != null) {
Log.w(TAG, "Already running a PNO scan");
return false;
}
- mPnoEventHandler = eventHandler;
- mPnoSettings = settings;
+ if (!isHwPnoScanRequired(settings.isConnected)) {
+ return false;
+ }
- // For wificond based PNO, we start the scan immediately when we set pno list.
- processPendingScans();
+ if (startHwPnoScan(settings)) {
+ mLastPnoScanSettings = new LastPnoScanSettings(
+ mClock.getElapsedSinceBootMillis(),
+ settings.networkList, eventHandler);
+
+ } else {
+ Log.e(TAG, "Failed to start PNO scan");
+ reportPnoScanFailure();
+ }
return true;
}
}
@@ -538,12 +426,11 @@
@Override
public boolean resetHwPnoList() {
synchronized (mSettingsLock) {
- if (mPnoSettings == null) {
+ if (mLastPnoScanSettings == null) {
Log.w(TAG, "No PNO scan running");
return false;
}
- mPnoEventHandler = null;
- mPnoSettings = null;
+ mLastPnoScanSettings = null;
// For wificond based PNO, we stop the scan immediately when we reset pno list.
stopHwPnoScan();
return true;
@@ -591,204 +478,36 @@
}
private static class LastScanSettings {
- public long startTime;
-
- LastScanSettings(long startTime) {
- this.startTime = startTime;
- }
-
- // Single scan settings
- public boolean singleScanActive = false;
- public boolean reportSingleScanFullResults;
- public ChannelCollection singleScanFreqs;
- public WifiNative.ScanEventHandler singleScanEventHandler;
-
- public void setSingleScan(boolean reportSingleScanFullResults,
+ LastScanSettings(long startTime,
+ boolean reportSingleScanFullResults,
ChannelCollection singleScanFreqs,
WifiNative.ScanEventHandler singleScanEventHandler) {
- singleScanActive = true;
+ this.startTime = startTime;
this.reportSingleScanFullResults = reportSingleScanFullResults;
this.singleScanFreqs = singleScanFreqs;
this.singleScanEventHandler = singleScanEventHandler;
}
- public boolean hwPnoScanActive = false;
- public WifiNative.PnoNetwork[] pnoNetworkList;
- public WifiNative.PnoEventHandler pnoScanEventHandler;
+ public long startTime;
+ public boolean reportSingleScanFullResults;
+ public ChannelCollection singleScanFreqs;
+ public WifiNative.ScanEventHandler singleScanEventHandler;
- public void setHwPnoScan(
+ }
+
+ private static class LastPnoScanSettings {
+ LastPnoScanSettings(long startTime,
WifiNative.PnoNetwork[] pnoNetworkList,
WifiNative.PnoEventHandler pnoScanEventHandler) {
- hwPnoScanActive = true;
+ this.startTime = startTime;
this.pnoNetworkList = pnoNetworkList;
this.pnoScanEventHandler = pnoScanEventHandler;
}
+
+ public long startTime;
+ public WifiNative.PnoNetwork[] pnoNetworkList;
+ public WifiNative.PnoEventHandler pnoScanEventHandler;
+
}
- /**
- * HW PNO Debouncer is used to debounce PNO requests. This guards against toggling the PNO
- * state too often which is not handled very well by some drivers.
- * Note: This is not thread safe!
- */
- public static class HwPnoDebouncer {
- public static final String PNO_DEBOUNCER_ALARM_TAG = TAG + "Pno Monitor";
- private static final int MINIMUM_PNO_GAP_MS = 5 * 1000;
-
- private final WifiNative mWifiNative;
- private final AlarmManager mAlarmManager;
- private final Handler mEventHandler;
- private final Clock mClock;
- private long mLastPnoChangeTimeStamp = -1L;
- private boolean mExpectedPnoState = false;
- private boolean mCurrentPnoState = false;;
- private boolean mWaitForTimer = false;
- private Listener mListener;
- private WifiNative.PnoSettings mPnoSettings;
-
- /**
- * Interface used to indicate PNO scan notifications.
- */
- public interface Listener {
- /**
- * Used to indicate a delayed PNO scan request failure.
- */
- void onPnoScanFailed();
- }
-
- public HwPnoDebouncer(WifiNative wifiNative, AlarmManager alarmManager,
- Handler eventHandler, Clock clock) {
- mWifiNative = wifiNative;
- mAlarmManager = alarmManager;
- mEventHandler = eventHandler;
- mClock = clock;
- }
-
- /**
- * Enable PNO state in wificond
- */
- private boolean startPnoScanInternal() {
- if (mCurrentPnoState) {
- if (DBG) Log.d(TAG, "PNO state is already enable");
- return true;
- }
- if (mPnoSettings == null) {
- Log.e(TAG, "PNO state change to enable failed, no available Pno settings");
- return false;
- }
- mLastPnoChangeTimeStamp = mClock.getElapsedSinceBootMillis();
- Log.d(TAG, "Remove all networks from supplicant before starting PNO scan");
- mWifiNative.removeAllNetworks();
- if (mWifiNative.startPnoScan(mPnoSettings)) {
- Log.d(TAG, "Changed PNO state from " + mCurrentPnoState + " to enable");
- mCurrentPnoState = true;
- return true;
- } else {
- Log.e(TAG, "PNO state change to enable failed");
- mCurrentPnoState = false;
- }
- return false;
- }
-
- /**
- * Disable PNO state in wificond
- */
- private boolean stopPnoScanInternal() {
- if (!mCurrentPnoState) {
- if (DBG) Log.d(TAG, "PNO state is already disable");
- return true;
- }
- mLastPnoChangeTimeStamp = mClock.getElapsedSinceBootMillis();
- if (mWifiNative.stopPnoScan()) {
- Log.d(TAG, "Changed PNO state from " + mCurrentPnoState + " to disable");
- mCurrentPnoState = false;
- return true;
- } else {
- Log.e(TAG, "PNO state change to disable failed");
- mCurrentPnoState = false;
- }
- return false;
- }
-
- private final AlarmManager.OnAlarmListener mAlarmListener =
- new AlarmManager.OnAlarmListener() {
- public void onAlarm() {
- if (DBG) Log.d(TAG, "PNO timer expired, expected state " + mExpectedPnoState);
- if (mExpectedPnoState) {
- if (!startPnoScanInternal()) {
- if (mListener != null) {
- mListener.onPnoScanFailed();
- }
- }
- } else {
- stopPnoScanInternal();
- }
- mWaitForTimer = false;
- }
- };
-
- /**
- * Enable/Disable PNO state. This method will debounce PNO scan requests.
- * @param enable boolean indicating whether PNO is being enabled or disabled.
- */
- private boolean setPnoState(boolean enable) {
- boolean isSuccess = true;
- mExpectedPnoState = enable;
- if (!mWaitForTimer) {
- long timeDifference = mClock.getElapsedSinceBootMillis() - mLastPnoChangeTimeStamp;
- if (timeDifference >= MINIMUM_PNO_GAP_MS) {
- if (enable) {
- isSuccess = startPnoScanInternal();
- } else {
- isSuccess = stopPnoScanInternal();
- }
- } else {
- long alarmTimeout = MINIMUM_PNO_GAP_MS - timeDifference;
- Log.d(TAG, "Start PNO timer with delay " + alarmTimeout);
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- mClock.getElapsedSinceBootMillis() + alarmTimeout,
- PNO_DEBOUNCER_ALARM_TAG,
- mAlarmListener, mEventHandler);
- mWaitForTimer = true;
- }
- }
- return isSuccess;
- }
-
- /**
- * Start PNO scan
- */
- public boolean startPnoScan(WifiNative.PnoSettings pnoSettings, Listener listener) {
- if (DBG) Log.d(TAG, "Starting PNO scan");
- mListener = listener;
- mPnoSettings = pnoSettings;
- if (!setPnoState(true)) {
- mListener = null;
- return false;
- }
- return true;
- }
-
- /**
- * Stop PNO scan
- */
- public void stopPnoScan() {
- if (DBG) Log.d(TAG, "Stopping PNO scan");
- setPnoState(false);
- mListener = null;
- }
-
- /**
- * Force stop PNO scanning. This method will bypass the debounce logic and stop PNO
- * scan immediately.
- */
- public void forceStopPnoScan() {
- if (DBG) Log.d(TAG, "Force stopping Pno scan");
- // Cancel the debounce timer and stop PNO scan.
- if (mWaitForTimer) {
- mAlarmManager.cancel(mAlarmListener);
- mWaitForTimer = false;
- }
- stopPnoScanInternal();
- }
- }
}
diff --git a/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java b/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
index d3c072f..4ae7d13 100644
--- a/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
+++ b/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
@@ -22,7 +22,6 @@
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.net.NetworkScoreManager;
-import android.os.Binder;
import android.os.RemoteException;
import android.os.UserManager;
import android.provider.Settings;
@@ -202,24 +201,19 @@
* current user.
*/
private boolean isCurrentProfile(int uid) {
- final long token = Binder.clearCallingIdentity();
- try {
- int currentUser = mWifiPermissionsWrapper.getCurrentUser();
- int callingUserId = mWifiPermissionsWrapper.getCallingUserId(uid);
- if (callingUserId == currentUser) {
- return true;
- } else {
- List<UserInfo> userProfiles = mUserManager.getProfiles(currentUser);
- for (UserInfo user : userProfiles) {
- if (user.id == callingUserId) {
- return true;
- }
+ int currentUser = mWifiPermissionsWrapper.getCurrentUser();
+ int callingUserId = mWifiPermissionsWrapper.getCallingUserId(uid);
+ if (callingUserId == currentUser) {
+ return true;
+ } else {
+ List<UserInfo> userProfiles = mUserManager.getProfiles(currentUser);
+ for (UserInfo user : userProfiles) {
+ if (user.id == callingUserId) {
+ return true;
}
}
- return false;
- } finally {
- Binder.restoreCallingIdentity(token);
}
+ return false;
}
/**
diff --git a/service/java/com/android/server/wifi/util/WifiPermissionsWrapper.java b/service/java/com/android/server/wifi/util/WifiPermissionsWrapper.java
index 6fde01e..84aacdf 100644
--- a/service/java/com/android/server/wifi/util/WifiPermissionsWrapper.java
+++ b/service/java/com/android/server/wifi/util/WifiPermissionsWrapper.java
@@ -108,4 +108,16 @@
return AppGlobals.getPackageManager().checkUidPermission(
Manifest.permission.CHANGE_WIFI_STATE, uid);
}
+
+ /**
+ * Determines if the caller has local mac address permission.
+ *
+ * @param uid to check the permission for
+ * @return int representation of success or denied
+ * @throws RemoteException
+ */
+ public int getLocalMacAddressPermission(int uid) throws RemoteException {
+ return AppGlobals.getPackageManager().checkUidPermission(
+ Manifest.permission.LOCAL_MAC_ADDRESS, uid);
+ }
}
diff --git a/tests/wifitests/Android.mk b/tests/wifitests/Android.mk
index 11e508d..b5c5844 100644
--- a/tests/wifitests/Android.mk
+++ b/tests/wifitests/Android.mk
@@ -68,7 +68,9 @@
android.test.runner \
wifi-service \
services \
- android.hidl.manager-V1.0-java
+ android.hidl.manager-V1.0-java \
+ android.test.base \
+ android.test.mock
# These must be explicitly included because they are not normally accessible
# from apps.
diff --git a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
index 18a1f8f..4290ada 100644
--- a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
@@ -17,7 +17,6 @@
package com.android.server.wifi;
import static com.android.server.wifi.HalDeviceManager.START_HAL_RETRY_TIMES;
-import static com.android.server.wifi.HalDeviceManager.getName;
import static junit.framework.Assert.assertEquals;
@@ -589,6 +588,48 @@
TestChipV2.CHIP_MODE_ID, 1);
}
+ // TestChipV3
+
+ /**
+ * Validate creation of STA interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateStaInterfaceNoInitModeTestChipV3() throws Exception {
+ // Note: we expected 2 available callbacks since we now have 2 STAs possible. So
+ // we get callback 1 after creating the first STA (since we can create another STA),
+ // and we get callback 2 after destroying the first STA (since we can create another STA -
+ // as expected).
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV3(), IfaceType.STA, "sta0",
+ TestChipV3.CHIP_MODE_ID, 2);
+ }
+
+ /**
+ * Validate creation of AP interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateApInterfaceNoInitModeTestChipV3() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV3(), IfaceType.AP, "ap0",
+ TestChipV3.CHIP_MODE_ID, 1);
+ }
+
+ /**
+ * Validate creation of P2P interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateP2pInterfaceNoInitModeTestChipV3() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV3(), IfaceType.P2P, "p2p0",
+ TestChipV3.CHIP_MODE_ID, 1);
+ }
+
+ /**
+ * Validate creation of NAN interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateNanInterfaceNoInitModeTestChipV3() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV3(), IfaceType.NAN, "nan0",
+ TestChipV3.CHIP_MODE_ID, 1);
+ }
+
//////////////////////////////////////////////////////////////////////////////////////
// TestChipV1 Specific Tests
//////////////////////////////////////////////////////////////////////////////////////
@@ -982,8 +1023,9 @@
*/
@Test
public void testP2pAndNanInteractionsTestChipV1() throws Exception {
- runP2pAndNanExclusiveInteractionsTestChip(new TestChipV1(), false,
- TestChipV1.STA_CHIP_MODE_ID);
+ // staAvailCallbacks=0: there is no second STA so will never get available callback after
+ // first is created.
+ runP2pAndNanExclusiveInteractionsTestChip(new TestChipV1(), 0, TestChipV1.STA_CHIP_MODE_ID);
}
/**
@@ -1298,7 +1340,9 @@
*/
@Test
public void testP2pAndNanInteractionsTestChipV2() throws Exception {
- runP2pAndNanExclusiveInteractionsTestChip(new TestChipV2(), true, TestChipV2.CHIP_MODE_ID);
+ // staAvailCallbacks=5: after every substantial change will get a callback since second
+ // STA is always available.
+ runP2pAndNanExclusiveInteractionsTestChip(new TestChipV2(), 5, TestChipV2.CHIP_MODE_ID);
}
/**
@@ -1351,6 +1395,273 @@
assertEquals(correctResults, results);
}
+ //////////////////////////////////////////////////////////////////////////////////////
+ // TestChipV3 Specific Tests
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Validate a flow sequence for test chip 3:
+ * - create STA
+ * - create P2P
+ * - request NAN: failure
+ * - create AP: should tear down P2P first
+ * - create STA: will get refused
+ * - create AP: will get refused
+ * - request P2P: failure
+ * - tear down AP
+ * - create STA
+ * - create STA: will get refused
+ * - create NAN: should tear down last created STA
+ * - create STA: will get refused
+ */
+ @Test
+ public void testInterfaceCreationFlowTestChipV3() throws Exception {
+ TestChipV3 chipMock = new TestChipV3();
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ InterfaceDestroyedListener staDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
+ InterfaceDestroyedListener staDestroyedListener2 = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener staAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InterfaceDestroyedListener apDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener apAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InterfaceDestroyedListener p2pDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener p2pAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InterfaceDestroyedListener nanDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener nanAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InOrder inOrderStaAvail = inOrder(staAvailListener);
+ InOrder inOrderApAvail = inOrder(apAvailListener);
+ InOrder inOrderP2pAvail = inOrder(p2pAvailListener);
+ InOrder inOrderNanAvail = inOrder(nanAvailListener);
+
+ // register listeners for interface availability
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staAvailListener,
+ mHandler);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.AP, apAvailListener, mHandler);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.P2P, p2pAvailListener,
+ mHandler);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.NAN, nanAvailListener,
+ mHandler);
+ mTestLooper.dispatchAll();
+
+ inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+
+ // create STA
+ when(mClock.getUptimeSinceBootMillis()).thenReturn(15L);
+ IWifiIface staIface = validateInterfaceSequence(chipMock,
+ false, // chipModeValid
+ -1000, // chipModeId (only used if chipModeValid is true)
+ IfaceType.STA, // ifaceTypeToCreate
+ "sta0", // ifaceName
+ TestChipV3.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ staDestroyedListener, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("STA interface wasn't created", staIface, IsNull.notNullValue());
+
+ inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+
+ // create P2P
+ IWifiIface p2pIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV3.CHIP_MODE_ID, // chipModeId
+ IfaceType.P2P, // ifaceTypeToCreate
+ "p2p0", // ifaceName
+ TestChipV3.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ p2pDestroyedListener, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("P2P interface wasn't created", p2pIface, IsNull.notNullValue());
+
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+
+ // request NAN: should fail
+ IWifiIface nanIface = mDut.createNanIface(null, null);
+ collector.checkThat("NAN should not be created", nanIface, IsNull.nullValue());
+
+ // create AP: will destroy P2P
+ IWifiIface apIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV3.CHIP_MODE_ID, // chipModeId
+ IfaceType.AP, // ifaceTypeToCreate
+ "ap0", // ifaceName
+ TestChipV3.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ apDestroyedListener, // destroyedListener
+ null, // availableListener (already registered)
+ new InterfaceDestroyedListenerWithIfaceName("p2p0", p2pDestroyedListener)
+ );
+ collector.checkThat("AP interface wasn't created", apIface, IsNull.notNullValue());
+ verify(chipMock.chip).removeP2pIface("p2p0");
+
+ // request STA2: should fail
+ IWifiIface staIface2 = mDut.createStaIface(null, null);
+ collector.checkThat("STA2 should not be created", staIface2, IsNull.nullValue());
+
+ // request AP2: should fail
+ IWifiIface apIface2 = mDut.createApIface(null, null);
+ collector.checkThat("AP2 should not be created", apIface2, IsNull.nullValue());
+
+ // request P2P: should fail
+ p2pIface = mDut.createP2pIface(null, null);
+ collector.checkThat("P2P should not be created", p2pIface, IsNull.nullValue());
+
+ // tear down AP
+ mDut.removeIface(apIface);
+ mTestLooper.dispatchAll();
+
+ inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+ verify(chipMock.chip).removeApIface("ap0");
+ verify(apDestroyedListener).onDestroyed(getName(apIface));
+
+ // create STA2: using a later clock
+ when(mClock.getUptimeSinceBootMillis()).thenReturn(20L);
+ staIface2 = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV3.CHIP_MODE_ID, // chipModeId
+ IfaceType.STA, // ifaceTypeToCreate
+ "sta1", // ifaceName
+ TestChipV3.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ staDestroyedListener2, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("STA 2 interface wasn't created", staIface2, IsNull.notNullValue());
+
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+
+ // request STA3: should fail
+ IWifiIface staIface3 = mDut.createStaIface(null, null);
+ collector.checkThat("STA3 should not be created", staIface3, IsNull.nullValue());
+
+ // create NAN: should destroy the last created STA (STA2)
+ nanIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV3.CHIP_MODE_ID, // chipModeId
+ IfaceType.NAN, // ifaceTypeToCreate
+ "nan0", // ifaceName
+ TestChipV3.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ nanDestroyedListener, // destroyedListener
+ null, // availableListener (already registered)
+ new InterfaceDestroyedListenerWithIfaceName(
+ getName(staIface2), staDestroyedListener2)
+ );
+ collector.checkThat("NAN interface wasn't created", nanIface, IsNull.notNullValue());
+
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ verify(chipMock.chip).removeStaIface("sta1");
+ verify(staDestroyedListener2).onDestroyed(getName(staIface2));
+
+ // request STA2: should fail
+ staIface2 = mDut.createStaIface(null, null);
+ collector.checkThat("STA2 should not be created", staIface2, IsNull.nullValue());
+
+ verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener,
+ staDestroyedListener2, apDestroyedListener, p2pDestroyedListener,
+ nanDestroyedListener, staAvailListener, apAvailListener, p2pAvailListener,
+ nanAvailListener, staAvailListener, apAvailListener, p2pAvailListener,
+ nanAvailListener);
+ }
+
+ /**
+ * Validate P2P and NAN interactions. Expect:
+ * - STA created
+ * - NAN created
+ * - When P2P requested:
+ * - NAN torn down
+ * - P2P created
+ * - NAN creation refused
+ * - When P2P destroyed:
+ * - get nan available listener
+ * - Can create NAN when requested
+ */
+ @Test
+ public void testP2pAndNanInteractionsTestChipV3() throws Exception {
+ // staAvailCallbacks=2: only get callback (for second STA) when P2P or NAN are down.
+ runP2pAndNanExclusiveInteractionsTestChip(new TestChipV3(), 2, TestChipV3.CHIP_MODE_ID);
+ }
+
+ /**
+ * Validate that the getSupportedIfaceTypes API works when requesting for all chips.
+ */
+ @Test
+ public void testGetSupportedIfaceTypesAllTestChipV3() throws Exception {
+ TestChipV3 chipMock = new TestChipV3();
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ // try API
+ Set<Integer> results = mDut.getSupportedIfaceTypes();
+
+ // verify results
+ Set<Integer> correctResults = new HashSet<>();
+ correctResults.add(IfaceType.AP);
+ correctResults.add(IfaceType.STA);
+ correctResults.add(IfaceType.P2P);
+ correctResults.add(IfaceType.NAN);
+
+ assertEquals(correctResults, results);
+ }
+
+ /**
+ * Validate that the getSupportedIfaceTypes API works when requesting for a specific chip.
+ */
+ @Test
+ public void testGetSupportedIfaceTypesOneChipTestChipV3() throws Exception {
+ TestChipV3 chipMock = new TestChipV3();
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ // try API
+ Set<Integer> results = mDut.getSupportedIfaceTypes(chipMock.chip);
+
+ // verify results
+ Set<Integer> correctResults = new HashSet<>();
+ correctResults.add(IfaceType.AP);
+ correctResults.add(IfaceType.STA);
+ correctResults.add(IfaceType.P2P);
+ correctResults.add(IfaceType.NAN);
+
+ assertEquals(correctResults, results);
+ }
+
///////////////////////////////////////////////////////////////////////////////////////
// utilities
///////////////////////////////////////////////////////////////////////////////////////
@@ -1480,7 +1791,7 @@
* line of NAN and P2P being exclusive).
*/
public void runP2pAndNanExclusiveInteractionsTestChip(ChipMockBase chipMock,
- boolean duplicateStas, int onlyChipMode) throws Exception {
+ int staAvailCallbacks, int onlyChipMode) throws Exception {
chipMock.initialize();
mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
mManagerStatusListenerMock);
@@ -1567,9 +1878,9 @@
nanAvailListener // availableListener
);
- if (duplicateStas) {
+ if (staAvailCallbacks != 0) {
// if there are duplicate STAs then expect an available callback for each step above
- verify(staAvailListener, times(5)).onAvailableForRequest();
+ verify(staAvailListener, times(staAvailCallbacks)).onAvailableForRequest();
}
verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener, staAvailListener,
@@ -2149,4 +2460,72 @@
.getAvailableModes(any(IWifiChip.getAvailableModesCallback.class));
}
}
+
+ // test chip configuration V3:
+ // mode:
+ // STA + (STA || AP)
+ // STA + (NAN || P2P)
+ private class TestChipV3 extends ChipMockBase {
+ // only mode (different number from any in other TestChips so can catch test errors)
+ static final int CHIP_MODE_ID = 7;
+
+ void initialize() throws Exception {
+ super.initialize();
+
+ // chip Id configuration
+ ArrayList<Integer> chipIds;
+ chipId = 15;
+ chipIds = new ArrayList<>();
+ chipIds.add(chipId);
+ doAnswer(new GetChipIdsAnswer(mStatusOk, chipIds)).when(mWifiMock).getChipIds(
+ any(IWifi.getChipIdsCallback.class));
+
+ doAnswer(new GetChipAnswer(mStatusOk, chip)).when(mWifiMock).getChip(eq(15),
+ any(IWifi.getChipCallback.class));
+
+ // initialize dummy chip modes
+ IWifiChip.ChipMode cm;
+ IWifiChip.ChipIfaceCombination cic;
+ IWifiChip.ChipIfaceCombinationLimit cicl;
+
+ // Mode 0 (only one): 1xSTA + 1x{STA,AP}, 1xSTA + 1x{P2P,NAN}
+ availableModes = new ArrayList<>();
+ cm = new IWifiChip.ChipMode();
+ cm.id = CHIP_MODE_ID;
+
+ cic = new IWifiChip.ChipIfaceCombination();
+
+ cicl = new IWifiChip.ChipIfaceCombinationLimit();
+ cicl.maxIfaces = 1;
+ cicl.types.add(IfaceType.STA);
+ cic.limits.add(cicl);
+
+ cicl = new IWifiChip.ChipIfaceCombinationLimit();
+ cicl.maxIfaces = 1;
+ cicl.types.add(IfaceType.STA);
+ cicl.types.add(IfaceType.AP);
+ cic.limits.add(cicl);
+
+ cm.availableCombinations.add(cic);
+
+ cic = new IWifiChip.ChipIfaceCombination();
+
+ cicl = new IWifiChip.ChipIfaceCombinationLimit();
+ cicl.maxIfaces = 1;
+ cicl.types.add(IfaceType.STA);
+ cic.limits.add(cicl);
+
+ cicl = new IWifiChip.ChipIfaceCombinationLimit();
+ cicl.maxIfaces = 1;
+ cicl.types.add(IfaceType.P2P);
+ cicl.types.add(IfaceType.NAN);
+ cic.limits.add(cicl);
+
+ cm.availableCombinations.add(cic);
+ availableModes.add(cm);
+
+ doAnswer(new GetAvailableModesAnswer(this)).when(chip)
+ .getAvailableModes(any(IWifiChip.getAvailableModesCallback.class));
+ }
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
index cda9cf5..93db347 100644
--- a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
@@ -33,17 +33,26 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;
+import android.app.test.TestAlarmManager;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
+import android.database.ContentObserver;
import android.net.InterfaceConfiguration;
+import android.net.Uri;
import android.net.wifi.IApInterface;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.INetworkManagementService;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.os.test.TestLooper;
+import android.provider.Settings;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Pair;
+import com.android.internal.R;
+import com.android.internal.util.WakeupMessage;
import com.android.server.net.BaseNetworkObserver;
import org.junit.Before;
@@ -77,11 +86,16 @@
private final WifiConfiguration mDefaultApConfig = createDefaultApConfig();
+ private ContentObserver mContentObserver;
+ private TestLooper mLooper;
+ private TestAlarmManager mAlarmManager;
+
@Mock Context mContext;
- TestLooper mLooper;
+ @Mock Resources mResources;
@Mock WifiNative mWifiNative;
@Mock SoftApManager.Listener mListener;
@Mock InterfaceConfiguration mInterfaceConfiguration;
+ @Mock FrameworkFacade mFrameworkFacade;
@Mock IApInterface mApInterface;
@Mock INetworkManagementService mNmService;
@Mock WifiApConfigStore mWifiApConfigStore;
@@ -104,6 +118,15 @@
when(mWifiNative.startSoftAp(any(), any())).thenReturn(true);
when(mWifiNative.stopSoftAp()).thenReturn(true);
when(mWifiNative.registerWificondDeathHandler(any())).thenReturn(true);
+
+ when(mFrameworkFacade.getIntegerSetting(
+ mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(1);
+ mAlarmManager = new TestAlarmManager();
+ when(mContext.getSystemService(Context.ALARM_SERVICE))
+ .thenReturn(mAlarmManager.getAlarmManager());
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mResources.getInteger(R.integer.config_wifi_framework_soft_ap_timeout_delay))
+ .thenReturn(600000);
}
private WifiConfiguration createDefaultApConfig() {
@@ -118,11 +141,10 @@
}
SoftApManager newSoftApManager = new SoftApManager(mContext,
mLooper.getLooper(),
+ mFrameworkFacade,
mWifiNative,
TEST_COUNTRY_CODE,
mListener,
- mApInterface,
- TEST_INTERFACE_NAME,
mNmService,
mWifiApConfigStore,
config,
@@ -184,16 +206,21 @@
/** Tests softap startup if default config fails to load. **/
@Test
public void startSoftApDefaultConfigFailedToLoad() throws Exception {
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mApInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
+ when(mApInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+
when(mWifiApConfigStore.getApConfiguration()).thenReturn(null);
SoftApModeConfiguration nullApConfig =
new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
SoftApManager newSoftApManager = new SoftApManager(mContext,
mLooper.getLooper(),
+ mFrameworkFacade,
mWifiNative,
TEST_COUNTRY_CODE,
mListener,
- mApInterface,
- TEST_INTERFACE_NAME,
mNmService,
mWifiApConfigStore,
nullApConfig,
@@ -217,6 +244,324 @@
}
/**
+ * Test that failure to create the SoftApInterface increments the corresponding metrics and
+ * proper state updates are sent out.
+ */
+ @Test
+ public void testSetupForSoftApModeHalFailureIncrementsMetrics() throws Exception {
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(TEST_INTERFACE_NAME))
+ .thenReturn(Pair.create(WifiNative.SETUP_FAILURE_HAL, null));
+
+ SoftApModeConfiguration config = new SoftApModeConfiguration(
+ WifiManager.IFACE_IP_MODE_TETHERED, new WifiConfiguration());
+
+ when(mWifiApConfigStore.getApConfiguration()).thenReturn(null);
+ SoftApModeConfiguration nullApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mFrameworkFacade,
+ mWifiNative,
+ TEST_COUNTRY_CODE,
+ mListener,
+ mNmService,
+ mWifiApConfigStore,
+ nullApConfig,
+ mWifiMetrics);
+ mLooper.dispatchAll();
+ newSoftApManager.start();
+ mLooper.dispatchAll();
+ verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ checkApStateChangedBroadcast(intentCaptor.getValue(), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_DISABLED, WifiManager.SAP_START_FAILURE_GENERAL, null,
+ nullApConfig.getTargetMode());
+
+ verify(mWifiMetrics).incrementNumWifiOnFailureDueToHal();
+ }
+
+ /**
+ * Test that failure to create the SoftApInterface due to a wificond error increments
+ * the corresponding metrics and proper state updates are sent out.
+ */
+ @Test
+ public void testSetupForSoftApModeWificondFailureIncrementsMetrics() throws Exception {
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(TEST_INTERFACE_NAME))
+ .thenReturn(Pair.create(WifiNative.SETUP_FAILURE_WIFICOND, null));
+
+ SoftApModeConfiguration config = new SoftApModeConfiguration(
+ WifiManager.IFACE_IP_MODE_TETHERED, new WifiConfiguration());
+
+ when(mWifiApConfigStore.getApConfiguration()).thenReturn(null);
+ SoftApModeConfiguration nullApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mFrameworkFacade,
+ mWifiNative,
+ TEST_COUNTRY_CODE,
+ mListener,
+ mNmService,
+ mWifiApConfigStore,
+ nullApConfig,
+ mWifiMetrics);
+ mLooper.dispatchAll();
+ newSoftApManager.start();
+ mLooper.dispatchAll();
+ verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ checkApStateChangedBroadcast(intentCaptor.getValue(), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_DISABLED, WifiManager.SAP_START_FAILURE_GENERAL, null,
+ nullApConfig.getTargetMode());
+
+ verify(mWifiMetrics).incrementNumWifiOnFailureDueToWificond();
+ }
+
+ /**
+ * Test that failure to retrieve the SoftApInterface increments the corresponding metrics
+ * and proper state updates are sent out.
+ */
+ @Test
+ public void testSetupForSoftApModeNullApInterfaceFailureIncrementsMetrics() throws Exception {
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, null));
+
+ SoftApModeConfiguration config = new SoftApModeConfiguration(
+ WifiManager.IFACE_IP_MODE_TETHERED, new WifiConfiguration());
+
+ when(mWifiApConfigStore.getApConfiguration()).thenReturn(null);
+ SoftApModeConfiguration nullApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mFrameworkFacade,
+ mWifiNative,
+ TEST_COUNTRY_CODE,
+ mListener,
+ mNmService,
+ mWifiApConfigStore,
+ nullApConfig,
+ mWifiMetrics);
+ mLooper.dispatchAll();
+ newSoftApManager.start();
+ mLooper.dispatchAll();
+ verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ checkApStateChangedBroadcast(intentCaptor.getValue(), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_DISABLED, WifiManager.SAP_START_FAILURE_GENERAL, null,
+ nullApConfig.getTargetMode());
+
+ verify(mWifiMetrics).incrementSoftApStartResult(false,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ }
+
+ /**
+ * Test that an empty SoftApInterface name is detected as a failure and increments the
+ * corresponding metrics and proper state updates are sent out.
+ */
+ @Test
+ public void testSetupForSoftApModeEmptyInterfaceNameFailureIncrementsMetrics()
+ throws Exception {
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mApInterface.getInterfaceName()).thenReturn("");
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
+
+ SoftApModeConfiguration config = new SoftApModeConfiguration(
+ WifiManager.IFACE_IP_MODE_TETHERED, new WifiConfiguration());
+
+ when(mWifiApConfigStore.getApConfiguration()).thenReturn(null);
+ SoftApModeConfiguration nullApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mFrameworkFacade,
+ mWifiNative,
+ TEST_COUNTRY_CODE,
+ mListener,
+ mNmService,
+ mWifiApConfigStore,
+ nullApConfig,
+ mWifiMetrics);
+ mLooper.dispatchAll();
+ newSoftApManager.start();
+ mLooper.dispatchAll();
+ verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ checkApStateChangedBroadcast(intentCaptor.getValue(), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_DISABLED, WifiManager.SAP_START_FAILURE_GENERAL, "",
+ nullApConfig.getTargetMode());
+
+ verify(mWifiMetrics).incrementSoftApStartResult(false,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ }
+
+ /**
+ * Test that catching a RemoteException when retrieving the SoftApInterface name
+ * is detected as a failure and increments the corresponding metrics and proper
+ * state updates are sent out.
+ */
+ @Test
+ public void testSetupForSoftApModeInterfaceNameRemoteExceptionFailureIncrementsMetrics()
+ throws Exception {
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ doThrow(new RemoteException()).when(mApInterface).getInterfaceName();
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
+
+ SoftApModeConfiguration config = new SoftApModeConfiguration(
+ WifiManager.IFACE_IP_MODE_TETHERED, new WifiConfiguration());
+
+ when(mWifiApConfigStore.getApConfiguration()).thenReturn(null);
+ SoftApModeConfiguration nullApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mFrameworkFacade,
+ mWifiNative,
+ TEST_COUNTRY_CODE,
+ mListener,
+ mNmService,
+ mWifiApConfigStore,
+ nullApConfig,
+ mWifiMetrics);
+ mLooper.dispatchAll();
+ newSoftApManager.start();
+ mLooper.dispatchAll();
+ verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ checkApStateChangedBroadcast(intentCaptor.getValue(), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_DISABLED, WifiManager.SAP_START_FAILURE_GENERAL, null,
+ nullApConfig.getTargetMode());
+
+ verify(mWifiMetrics).incrementSoftApStartResult(false,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ }
+
+
+ /**
+ * Tests that the generic error is propagated and properly reported when starting softap and we
+ * cannot register a wificond death handler.
+ */
+ @Test
+ public void startSoftApFailRegisterWificondDeathHandlerGeneralError() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+ config.apBand = WifiConfiguration.AP_BAND_5GHZ;
+ config.SSID = TEST_SSID;
+ SoftApModeConfiguration softApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mApInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
+
+ when(mWifiNative.registerWificondDeathHandler(any())).thenReturn(false);
+
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mFrameworkFacade,
+ mWifiNative,
+ null,
+ mListener,
+ mNmService,
+ mWifiApConfigStore,
+ softApConfig,
+ mWifiMetrics);
+ mLooper.dispatchAll();
+ newSoftApManager.start();
+ mLooper.dispatchAll();
+
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext, times(2)).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ List<Intent> capturedIntents = intentCaptor.getAllValues();
+ checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_ENABLING,
+ WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME,
+ softApConfig.getTargetMode());
+ checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_ENABLING, WifiManager.SAP_START_FAILURE_GENERAL, TEST_INTERFACE_NAME,
+ softApConfig.getTargetMode());
+ verify(mWifiMetrics).incrementSoftApStartResult(false,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ }
+
+ /**
+ * Tests that the generic error is propagated and properly reported when starting softap and we
+ * catch a RemoteException when attempting to register a NetworkObserver.
+ */
+ @Test
+ public void startSoftApFailNetworkObserverRemoteExceptionGeneralError() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+ config.apBand = WifiConfiguration.AP_BAND_5GHZ;
+ config.SSID = TEST_SSID;
+ SoftApModeConfiguration softApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mApInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
+
+ doThrow(new RemoteException()).when(mNmService).registerObserver(any());
+
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mFrameworkFacade,
+ mWifiNative,
+ null,
+ mListener,
+ mNmService,
+ mWifiApConfigStore,
+ softApConfig,
+ mWifiMetrics);
+ mLooper.dispatchAll();
+ newSoftApManager.start();
+ mLooper.dispatchAll();
+
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext, times(2)).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ List<Intent> capturedIntents = intentCaptor.getAllValues();
+ checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_ENABLING,
+ WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME,
+ softApConfig.getTargetMode());
+ checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_ENABLING, WifiManager.SAP_START_FAILURE_GENERAL, TEST_INTERFACE_NAME,
+ softApConfig.getTargetMode());
+ // we do once on enter of idle, and another after the failure
+ verify(mWifiNative, times(2)).deregisterWificondDeathHandler();
+ verify(mNmService).unregisterObserver(any());
+ verify(mWifiMetrics).incrementSoftApStartResult(false,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ }
+
+ /**
* Tests that the generic error is propagated and properly reported when starting softap and the
* specified channel cannot be used.
*/
@@ -228,15 +573,19 @@
SoftApModeConfiguration softApConfig =
new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mApInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
+
when(mWifiNative.isHalStarted()).thenReturn(true);
SoftApManager newSoftApManager = new SoftApManager(mContext,
mLooper.getLooper(),
+ mFrameworkFacade,
mWifiNative,
null,
mListener,
- mApInterface,
- TEST_INTERFACE_NAME,
mNmService,
mWifiApConfigStore,
softApConfig,
@@ -273,13 +622,18 @@
when(mWifiNative.isHalStarted()).thenReturn(true);
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mApInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
+
+
SoftApManager newSoftApManager = new SoftApManager(mContext,
mLooper.getLooper(),
+ mFrameworkFacade,
mWifiNative,
TEST_COUNTRY_CODE,
mListener,
- mApInterface,
- TEST_INTERFACE_NAME,
mNmService,
mWifiApConfigStore,
softApConfig,
@@ -307,15 +661,19 @@
@Test
public void startSoftApApInterfaceFailedToStart() throws Exception {
when(mWifiNative.startSoftAp(any(), any())).thenReturn(false);
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
+
SoftApModeConfiguration softApModeConfig =
new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, mDefaultApConfig);
+
SoftApManager newSoftApManager = new SoftApManager(mContext,
mLooper.getLooper(),
+ mFrameworkFacade,
mWifiNative,
TEST_COUNTRY_CODE,
mListener,
- mApInterface,
- TEST_INTERFACE_NAME,
mNmService,
mWifiApConfigStore,
softApModeConfig,
@@ -415,30 +773,11 @@
mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(
TEST_NUM_CONNECTED_CLIENTS);
mLooper.dispatchAll();
- assertEquals(TEST_NUM_CONNECTED_CLIENTS, mSoftApManager.getNumAssociatedStations());
verify(mWifiMetrics).addSoftApNumAssociatedStationsChangedEvent(TEST_NUM_CONNECTED_CLIENTS,
apConfig.getTargetMode());
}
@Test
- public void handlesNumAssociatedStationsWhenNotStarted() throws Exception {
- SoftApModeConfiguration apConfig =
- new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
- startSoftApAndVerifyEnabled(apConfig);
- mSoftApManager.stop();
- mLooper.dispatchAll();
-
- mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(
- TEST_NUM_CONNECTED_CLIENTS);
- mLooper.dispatchAll();
- /* Verify numAssociatedStations is not updated when soft AP is not started */
- assertEquals(0, mSoftApManager.getNumAssociatedStations());
- verify(mWifiMetrics).addSoftApUpChangedEvent(false, apConfig.getTargetMode());
- verify(mWifiMetrics, never()).addSoftApNumAssociatedStationsChangedEvent(
- TEST_NUM_CONNECTED_CLIENTS, apConfig.getTargetMode());
- }
-
- @Test
public void handlesInvalidNumAssociatedStations() throws Exception {
SoftApModeConfiguration apConfig =
new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
@@ -449,41 +788,155 @@
/* Invalid values should be ignored */
mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(-1);
mLooper.dispatchAll();
- assertEquals(TEST_NUM_CONNECTED_CLIENTS, mSoftApManager.getNumAssociatedStations());
verify(mWifiMetrics, times(1)).addSoftApNumAssociatedStationsChangedEvent(
TEST_NUM_CONNECTED_CLIENTS, apConfig.getTargetMode());
}
@Test
- public void resetsNumAssociatedStationsWhenStopped() throws Exception {
+ public void schedulesTimeoutTimerOnStart() throws Exception {
SoftApModeConfiguration apConfig =
new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
startSoftApAndVerifyEnabled(apConfig);
- mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(
- TEST_NUM_CONNECTED_CLIENTS);
- mSoftApManager.stop();
- mLooper.dispatchAll();
- assertEquals(0, mSoftApManager.getNumAssociatedStations());
- verify(mWifiMetrics).addSoftApUpChangedEvent(false, apConfig.getTargetMode());
+ // Verify timer is scheduled
+ verify(mAlarmManager.getAlarmManager()).setExact(anyInt(), anyLong(),
+ eq(mSoftApManager.SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG), any(), any());
}
@Test
- public void resetsNumAssociatedStationsOnFailure() throws Exception {
+ public void cancelsTimeoutTimerOnStop() throws Exception {
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+ mSoftApManager.stop();
+ mLooper.dispatchAll();
+
+ // Verify timer is canceled
+ verify(mAlarmManager.getAlarmManager()).cancel(any(WakeupMessage.class));
+ }
+
+ @Test
+ public void cancelsTimeoutTimerOnNewClientsConnect() throws Exception {
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+ mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(
+ TEST_NUM_CONNECTED_CLIENTS);
+ mLooper.dispatchAll();
+
+ // Verify timer is canceled
+ verify(mAlarmManager.getAlarmManager()).cancel(any(WakeupMessage.class));
+ }
+
+ @Test
+ public void schedulesTimeoutTimerWhenAllClientsDisconnect() throws Exception {
SoftApModeConfiguration apConfig =
new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
startSoftApAndVerifyEnabled(apConfig);
mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(
TEST_NUM_CONNECTED_CLIENTS);
- /* Force soft AP to fail */
- mDeathListenerCaptor.getValue().onDeath();
mLooper.dispatchAll();
- verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED,
- WifiManager.SAP_START_FAILURE_GENERAL);
+ // Verify timer is canceled at this point
+ verify(mAlarmManager.getAlarmManager()).cancel(any(WakeupMessage.class));
- assertEquals(0, mSoftApManager.getNumAssociatedStations());
- verify(mWifiMetrics).addSoftApUpChangedEvent(false, apConfig.getTargetMode());
+ mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(0);
+ mLooper.dispatchAll();
+ // Verify timer is scheduled again
+ verify(mAlarmManager.getAlarmManager(), times(2)).setExact(anyInt(), anyLong(),
+ eq(mSoftApManager.SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG), any(), any());
+ }
+
+ @Test
+ public void stopsSoftApOnTimeoutMessage() throws Exception {
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+
+ mAlarmManager.dispatch(mSoftApManager.SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG);
+ mLooper.dispatchAll();
+
+ verify(mWifiNative).stopSoftAp();
+ }
+
+ @Test
+ public void cancelsTimeoutTimerOnTimeoutToggleChangeWhenNoClients() throws Exception {
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+
+ when(mFrameworkFacade.getIntegerSetting(
+ mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(0);
+ mContentObserver.onChange(false);
+ mLooper.dispatchAll();
+
+ // Verify timer is canceled
+ verify(mAlarmManager.getAlarmManager()).cancel(any(WakeupMessage.class));
+ }
+
+ @Test
+ public void schedulesTimeoutTimerOnTimeoutToggleChangeWhenNoClients() throws Exception {
+ // start with timeout toggle disabled
+ when(mFrameworkFacade.getIntegerSetting(
+ mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(0);
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+
+ when(mFrameworkFacade.getIntegerSetting(
+ mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(1);
+ mContentObserver.onChange(false);
+ mLooper.dispatchAll();
+
+ // Verify timer is scheduled
+ verify(mAlarmManager.getAlarmManager()).setExact(anyInt(), anyLong(),
+ eq(mSoftApManager.SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG), any(), any());
+ }
+
+ @Test
+ public void doesNotScheduleTimeoutTimerOnStartWhenTimeoutIsDisabled() throws Exception {
+ // start with timeout toggle disabled
+ when(mFrameworkFacade.getIntegerSetting(
+ mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(0);
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+
+ // Verify timer is not scheduled
+ verify(mAlarmManager.getAlarmManager(), never()).setExact(anyInt(), anyLong(),
+ eq(mSoftApManager.SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG), any(), any());
+ }
+
+ @Test
+ public void doesNotScheduleTimeoutTimerWhenAllClientsDisconnectButTimeoutIsDisabled()
+ throws Exception {
+ // start with timeout toggle disabled
+ when(mFrameworkFacade.getIntegerSetting(
+ mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(0);
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+ // add some clients
+ mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(
+ TEST_NUM_CONNECTED_CLIENTS);
+ mLooper.dispatchAll();
+ // remove all clients
+ mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(0);
+ mLooper.dispatchAll();
+ // Verify timer is not scheduled
+ verify(mAlarmManager.getAlarmManager(), never()).setExact(anyInt(), anyLong(),
+ eq(mSoftApManager.SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG), any(), any());
+ }
+
+ @Test
+ public void unregistersSettingsObserverOnStop() throws Exception {
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+ mSoftApManager.stop();
+ mLooper.dispatchAll();
+
+ verify(mFrameworkFacade).unregisterContentObserver(eq(mContext), eq(mContentObserver));
}
/** Starts soft AP and verifies that it is enabled successfully. */
@@ -506,8 +959,15 @@
expectedConfig = new WifiConfiguration(config);
}
+ ArgumentCaptor<ContentObserver> observerCaptor = ArgumentCaptor.forClass(
+ ContentObserver.class);
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mApInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
+
mSoftApManager.start();
mLooper.dispatchAll();
order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLING, 0);
@@ -530,8 +990,10 @@
checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_ENABLED,
WIFI_AP_STATE_ENABLING, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME,
softApConfig.getTargetMode());
- assertEquals(0, mSoftApManager.getNumAssociatedStations());
verify(mWifiMetrics).addSoftApUpChangedEvent(true, softApConfig.mTargetMode);
+ verify(mFrameworkFacade).registerContentObserver(eq(mContext), any(Uri.class), eq(true),
+ observerCaptor.capture());
+ mContentObserver = observerCaptor.getValue();
}
/** Verifies that soft AP was not disabled. */
diff --git a/tests/wifitests/src/com/android/server/wifi/WakeupConfigStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/WakeupConfigStoreDataTest.java
new file mode 100644
index 0000000..6db9cf5
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/WakeupConfigStoreDataTest.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2017 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 org.mockito.Mockito.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.util.Xml;
+
+import com.android.internal.util.FastXmlSerializer;
+
+import com.google.android.collect.Sets;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Unit tests for {@link WakeupConfigStoreData}.
+ */
+public class WakeupConfigStoreDataTest {
+
+ @Mock private WakeupConfigStoreData.DataSource<Boolean> mActiveDataSource;
+ @Mock private WakeupConfigStoreData.DataSource<Set<ScanResultMatchInfo>> mNetworkDataSource;
+
+ private WakeupConfigStoreData mWakeupConfigData;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mWakeupConfigData = new WakeupConfigStoreData(mActiveDataSource, mNetworkDataSource);
+ }
+
+ /**
+ * Helper function for serializing configuration data to a XML block.
+ *
+ * @param shared Flag indicating serializing shared or user configurations
+ * @return byte[] of the XML data
+ */
+ private byte[] serializeData(boolean shared) throws Exception {
+ final XmlSerializer out = new FastXmlSerializer();
+ final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ out.setOutput(outputStream, StandardCharsets.UTF_8.name());
+ mWakeupConfigData.serializeData(out, shared);
+ out.flush();
+ return outputStream.toByteArray();
+ }
+
+ /**
+ * Helper function for parsing configuration data from a XML block.
+ *
+ * @param data XML data to parse from
+ * @param shared Flag indicating parsing of shared or user configurations
+ */
+ private void deserializeData(byte[] data, boolean shared) throws Exception {
+ final XmlPullParser in = Xml.newPullParser();
+ final ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
+ in.setInput(inputStream, StandardCharsets.UTF_8.name());
+ mWakeupConfigData.deserializeData(in, in.getDepth(), shared);
+ }
+
+ /**
+ * Verify that a XmlPullParserException will be thrown when attempting to serialize data
+ * to the share store.
+ */
+ @Test(expected = XmlPullParserException.class)
+ public void serializeShareDataThrowsException() throws Exception {
+ serializeData(true /* shared */);
+ }
+
+ /**
+ * Verify that a XmlPullParserException will be thrown when attempting to deserialize
+ * data from the share store.
+ */
+ @Test(expected = XmlPullParserException.class)
+ public void deserializeShareDataThrowsException() throws Exception {
+ deserializeData(new byte[0], true /* shared */);
+ }
+
+ /**
+ * Can correctly serialize and deserialize the empty set case.
+ */
+ @Test
+ public void deserializeSerializedData_emptySet() throws Exception {
+ Set<ScanResultMatchInfo> networks = Collections.emptySet();
+ boolean isActive = false;
+
+ when(mActiveDataSource.getData()).thenReturn(isActive);
+ when(mNetworkDataSource.getData()).thenReturn(networks);
+
+ byte[] bytes = serializeData(false /* shared */);
+ deserializeData(bytes, false /* shared */);
+
+ verify(mActiveDataSource).setData(eq(isActive));
+ verify(mNetworkDataSource).setData(eq(networks));
+ }
+
+ /**
+ * Can correctly serialize and deserialize a standard working case.
+ */
+ @Test
+ public void deserializeSerializedData() throws Exception {
+ ScanResultMatchInfo network1 = new ScanResultMatchInfo();
+ network1.networkSsid = "ssid 1";
+ network1.networkType = 0;
+
+ ScanResultMatchInfo network2 = new ScanResultMatchInfo();
+ network2.networkSsid = ",.23;4@, .#,%(,";
+ network2.networkType = 1;
+
+ ScanResultMatchInfo network3 = new ScanResultMatchInfo();
+ network3.networkSsid = "";
+ network3.networkType = 2;
+
+ Set<ScanResultMatchInfo> networks = Sets.newArraySet(network1, network2, network3);
+ boolean isActive = true;
+
+ when(mActiveDataSource.getData()).thenReturn(isActive);
+ when(mNetworkDataSource.getData()).thenReturn(networks);
+
+ byte[] bytes = serializeData(false /* shared */);
+ deserializeData(bytes, false /* shared */);
+
+ verify(mActiveDataSource).setData(eq(isActive));
+ verify(mNetworkDataSource).setData(eq(networks));
+ }
+
+ /**
+ * Verify that reset data wipes the data sources.
+ */
+ @Test
+ public void resetDataWipesDataSources() {
+ mWakeupConfigData.resetData(false /* shared */);
+
+ verify(mActiveDataSource).setData(false);
+ verify(mNetworkDataSource).setData(eq(Collections.emptySet()));
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java b/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java
index 742c520..5e45570 100644
--- a/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java
@@ -18,6 +18,8 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -29,12 +31,18 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintWriter;
+
/**
* Unit tests for {@link WakeupController}.
*/
public class WakeupControllerTest {
@Mock private Context mContext;
+ @Mock private WakeupLock mWakeupLock;
+ @Mock private WifiConfigManager mWifiConfigManager;
+ @Mock private WifiConfigStore mWifiConfigStore;
@Mock private FrameworkFacade mFrameworkFacade;
private TestLooper mLooper;
@@ -47,6 +55,11 @@
mLooper = new TestLooper();
}
+ private WakeupController newWakeupController() {
+ return new WakeupController(mContext, mLooper.getLooper(), mWakeupLock, mWifiConfigManager,
+ mWifiConfigStore, mFrameworkFacade);
+ }
+
/**
* Verify WakeupController is enabled when the settings toggle is true.
*/
@@ -54,8 +67,7 @@
public void verifyEnabledWhenToggledOn() {
when(mFrameworkFacade.getIntegerSetting(mContext,
Settings.Global.WIFI_WAKEUP_ENABLED, 0)).thenReturn(1);
- mWakeupController = new WakeupController(mContext, mLooper.getLooper(),
- mFrameworkFacade);
+ mWakeupController = newWakeupController();
assertTrue(mWakeupController.isEnabled());
}
@@ -67,9 +79,30 @@
public void verifyDisabledWhenToggledOff() {
when(mFrameworkFacade.getIntegerSetting(mContext,
Settings.Global.WIFI_WAKEUP_ENABLED, 0)).thenReturn(0);
- mWakeupController = new WakeupController(mContext, mLooper.getLooper(),
- mFrameworkFacade);
+ mWakeupController = newWakeupController();
assertFalse(mWakeupController.isEnabled());
}
+
+ /**
+ * Verify WakeupController registers its store data with the WifiConfigStore on construction.
+ */
+ @Test
+ public void registersWakeupConfigStoreData() {
+ mWakeupController = newWakeupController();
+ verify(mWifiConfigStore).registerStoreData(any(WakeupConfigStoreData.class));
+ }
+
+ /**
+ * Verify that dump calls also dump the state of the WakeupLock.
+ */
+ @Test
+ public void dumpIncludesWakeupLock() {
+ mWakeupController = newWakeupController();
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ PrintWriter writer = new PrintWriter(stream);
+ mWakeupController.dump(null, writer, null);
+
+ verify(mWakeupLock).dump(null, writer, null);
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java b/tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java
index bad9e3a..7144ecf 100644
--- a/tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java
@@ -18,9 +18,13 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.*;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.util.Arrays;
import java.util.Collection;
@@ -35,6 +39,8 @@
private static final String SSID_1 = "ssid1";
private static final String SSID_2 = "ssid2";
+ @Mock private WifiConfigManager mWifiConfigManager;
+
private ScanResultMatchInfo mNetwork1;
private ScanResultMatchInfo mNetwork2;
private WakeupLock mWakeupLock;
@@ -44,6 +50,8 @@
*/
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
mNetwork1 = new ScanResultMatchInfo();
mNetwork1.networkSsid = SSID_1;
mNetwork1.networkType = ScanResultMatchInfo.NETWORK_TYPE_OPEN;
@@ -52,7 +60,7 @@
mNetwork2.networkSsid = SSID_2;
mNetwork2.networkType = ScanResultMatchInfo.NETWORK_TYPE_EAP;
- mWakeupLock = new WakeupLock();
+ mWakeupLock = new WakeupLock(mWifiConfigManager);
}
/**
@@ -69,6 +77,18 @@
}
/**
+ * Updates the lock enough times to evict any networks not passed in.
+ *
+ * <p>It calls update {@link WakeupLock#CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT} times with
+ * the given network list. It does not make any assertions about the state of the lock.
+ */
+ private void updateEnoughTimesToEvictWithoutAsserts(Collection<ScanResultMatchInfo> networks) {
+ for (int i = 0; i < WakeupLock.CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT; i++) {
+ mWakeupLock.update(networks);
+ }
+ }
+
+ /**
* Verify that the WakeupLock is not empty immediately after being initialized with networks.
*/
@Test
@@ -161,4 +181,34 @@
updateEnoughTimesToEvictWithAsserts(Collections.singletonList(mNetwork2));
assertTrue(mWakeupLock.isEmpty());
}
+
+ /**
+ * Verify that initializing the lock persists the SSID list to the config store.
+ */
+ @Test
+ public void initializeShouldSaveSsidsToStore() {
+ mWakeupLock.initialize(Collections.singletonList(mNetwork1));
+ verify(mWifiConfigManager).saveToStore(eq(false));
+ }
+
+ /**
+ * Verify that update saves to store if the lock changes.
+ */
+ @Test
+ public void updateShouldOnlySaveIfLockChanges() {
+ mWakeupLock.initialize(Collections.singletonList(mNetwork1));
+ updateEnoughTimesToEvictWithoutAsserts(Collections.emptyList());
+
+ // need exactly 2 invocations: 1 for initialize, 1 for successful update
+ verify(mWifiConfigManager, times(2)).saveToStore(eq(false));
+ }
+
+ /**
+ * Verify that update does not save to store if the lock does not change.
+ */
+ @Test
+ public void updateShouldNotSaveIfLockDoesNotChange() {
+ mWakeupLock.update(Collections.singletonList(mNetwork1));
+ verify(mWifiConfigManager, never()).saveToStore(anyBoolean());
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiCertManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiCertManagerTest.java
deleted file mode 100644
index b123d80..0000000
--- a/tests/wifitests/src/com/android/server/wifi/WifiCertManagerTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * 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 org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-
-import android.content.Context;
-import android.os.UserHandle;
-import android.security.Credentials;
-import android.security.KeyStore;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.mockito.Mock;
-
-import java.io.File;
-import java.util.Arrays;
-import java.util.HashSet;
-
-/**
- * Unit tests for {@link com.android.server.wifi.WifiCertManager}.
- */
-@SmallTest
-public class WifiCertManagerTest {
- private static final String TAG = "WifiCertManagerTest";
- private byte[] mConfig;
- private String mConfigFile = "";
-
- @Mock private Context mContext;
- @Rule public TemporaryFolder mTempFolder = new TemporaryFolder();
-
- public WifiCertManagerTest() {
- mConfig = null;
- }
-
- @Before
- public void setUp() {
- try {
- File configFile = mTempFolder.newFile();
- mConfigFile = configFile.getAbsolutePath();
- configFile.delete();
- } catch (Exception e) {
- Log.e(TAG, "Failed to construct test", e);
- }
- }
-
- /**
- * This class is created to avoid mocking file system and KeyStore.
- */
- private class TestWifiCertManager extends WifiCertManager {
- private boolean mAffiliatedUser;
-
- public TestWifiCertManager(Context context) {
- super(context, mConfigFile);
- mAffiliatedUser = false;
- }
-
- protected String[] listClientCertsForAllUsers() {
- String prefix = Credentials.USER_PRIVATE_KEY;
- String mockAnswer[] = {prefix + "abc", prefix + "def", prefix + "ghi"};
- return mockAnswer;
- }
-
- protected byte[] readConfigFile() {
- return mConfig;
- }
-
- protected void writeConfigFile(byte[] payload) {
- mConfig = payload;
- }
-
- protected boolean isAffiliatedUser() {
- return mAffiliatedUser;
- }
-
- public void setAffiliatedUser(boolean value) {
- mAffiliatedUser = value;
- }
- }
-
- // TODO: b/69555027 - determine if test can be removed. for now, disable failing test
- public void testEmptyConfigFile() {
- WifiCertManager certManager = new WifiCertManager(mContext, mConfigFile);
- final String[] expected =
- KeyStore.getInstance().list(
- Credentials.USER_PRIVATE_KEY, UserHandle.myUserId());
- assertArrayEquals(expected, certManager.listClientCertsForCurrentUser());
- }
-
- @Test
- public void testOperations() {
- TestWifiCertManager certManager = new TestWifiCertManager(mContext);
- final HashSet<String> expected1 = new HashSet<>();
- String prefix = Credentials.USER_PRIVATE_KEY;
- expected1.add(prefix + "abc");
- expected1.add(prefix + "def");
- expected1.add(prefix + "ghi");
-
- final HashSet<String> expected2 = new HashSet<>();
- expected2.add(prefix + "abc");
-
- certManager.setAffiliatedUser(false);
- assertEquals(expected1,
- new HashSet<>(Arrays.asList(certManager.listClientCertsForCurrentUser())));
-
- certManager.hideCertFromUnaffiliatedUsers("def");
- certManager.hideCertFromUnaffiliatedUsers("ghi");
- assertEquals(expected2,
- new HashSet<>(Arrays.asList(certManager.listClientCertsForCurrentUser())));
-
- certManager.setAffiliatedUser(true);
- assertEquals(expected1,
- new HashSet<>(Arrays.asList(certManager.listClientCertsForCurrentUser())));
-
- TestWifiCertManager certManager2 = new TestWifiCertManager(mContext);
- certManager2.setAffiliatedUser(false);
- assertEquals(expected2,
- new HashSet<>(Arrays.asList(certManager2.listClientCertsForCurrentUser())));
-
- certManager2.setAffiliatedUser(true);
- assertEquals(expected1,
- new HashSet<>(Arrays.asList(certManager2.listClientCertsForCurrentUser())));
- }
-}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiControllerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiControllerTest.java
index c7b6180..9d5054e 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiControllerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiControllerTest.java
@@ -88,6 +88,7 @@
@Mock FrameworkFacade mFacade;
@Mock WifiSettingsStore mSettingsStore;
@Mock WifiStateMachine mWifiStateMachine;
+ @Mock WifiStateMachinePrime mWifiStateMachinePrime;
@Mock WifiLockManager mWifiLockManager;
@Mock ContentResolver mContentResolver;
@@ -110,7 +111,8 @@
ArgumentCaptor.forClass(ContentObserver.class);
mWifiController = new WifiController(mContext, mWifiStateMachine,
- mSettingsStore, mWifiLockManager, mLooper.getLooper(), mFacade);
+ mSettingsStore, mWifiLockManager, mLooper.getLooper(), mFacade,
+ mWifiStateMachinePrime);
verify(mFacade, times(3)).registerContentObserver(eq(mContext), any(Uri.class), eq(false),
observerCaptor.capture());
@@ -367,7 +369,8 @@
when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class));
mWifiController = new WifiController(mContext, mWifiStateMachine,
- mSettingsStore, mWifiLockManager, mLooper.getLooper(), mFacade);
+ mSettingsStore, mWifiLockManager, mLooper.getLooper(), mFacade,
+ mWifiStateMachinePrime);
mWifiController.start();
mLooper.dispatchAll();
@@ -457,11 +460,13 @@
public void testRestartWifiStackDoesNotExitAPMode() throws Exception {
mWifiController.obtainMessage(CMD_SET_AP, 1).sendToTarget();
mLooper.dispatchAll();
+ verify(mWifiStateMachinePrime).enterSoftAPMode(any());
assertEquals("ApEnabledState", getCurrentState().getName());
reset(mWifiStateMachine);
mWifiController.sendMessage(CMD_RESTART_WIFI);
mLooper.dispatchAll();
verifyZeroInteractions(mWifiStateMachine);
+ verify(mWifiStateMachinePrime, never()).disableWifi();
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
index ea81d53..d0a482e 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
@@ -31,6 +31,7 @@
import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
import static android.provider.Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
@@ -45,6 +46,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
@@ -370,10 +372,11 @@
/**
* Verify that wifi can be enabled by a caller with WIFI_STATE_CHANGE permission when wifi is
* off (no hotspot, no airplane mode).
+ *
+ * Note: hotspot is disabled by default
*/
@Test
public void testSetWifiEnabledSuccess() throws Exception {
- when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true);
when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true));
@@ -385,7 +388,6 @@
*/
@Test
public void testSetWifiEnabledNoToggle() throws Exception {
- when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(false);
assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true));
verify(mWifiController, never()).sendMessage(eq(CMD_WIFI_TOGGLED));
@@ -402,7 +404,6 @@
eq("WifiService"));
when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true);
- verify(mWifiStateMachine, never()).syncGetWifiApState();
}
/**
@@ -441,7 +442,17 @@
*/
@Test
public void testSetWifiEnabledFromNetworkSettingsHolderWhenApEnabled() throws Exception {
- when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_ENABLED);
+ when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false);
+ when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
+ mWifiServiceImpl.checkAndStartWifi();
+
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
+ (IntentFilter) argThat(new IntentFilterMatcher()));
+
+ TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext,
+ WIFI_AP_STATE_ENABLED, WIFI_AP_STATE_ENABLING, SAP_START_FAILURE_GENERAL,
+ WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY);
+
when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true);
when(mContext.checkPermission(
eq(android.Manifest.permission.NETWORK_SETTINGS), anyInt(), anyInt()))
@@ -456,7 +467,17 @@
*/
@Test
public void testSetWifiEnabledFromAppFailsWhenApEnabled() throws Exception {
- when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_ENABLED);
+ when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false);
+ when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
+ mWifiServiceImpl.checkAndStartWifi();
+
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
+ (IntentFilter) argThat(new IntentFilterMatcher()));
+
+ TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext,
+ WIFI_AP_STATE_ENABLED, WIFI_AP_STATE_ENABLING, SAP_START_FAILURE_GENERAL,
+ WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY);
+
when(mContext.checkPermission(
eq(android.Manifest.permission.NETWORK_SETTINGS), anyInt(), anyInt()))
.thenReturn(PackageManager.PERMISSION_DENIED);
@@ -472,7 +493,6 @@
*/
@Test
public void testSetWifiDisabledSuccess() throws Exception {
- when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
when(mSettingsStore.handleWifiToggled(eq(false))).thenReturn(true);
assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false));
verify(mWifiController).sendMessage(eq(CMD_WIFI_TOGGLED));
@@ -483,7 +503,6 @@
*/
@Test
public void testSetWifiDisabledNoToggle() throws Exception {
- when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
when(mSettingsStore.handleWifiToggled(eq(false))).thenReturn(false);
assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false));
verify(mWifiController, never()).sendMessage(eq(CMD_WIFI_TOGGLED));
@@ -495,7 +514,6 @@
*/
@Test(expected = SecurityException.class)
public void testSetWifiDisabledWithoutPermission() throws Exception {
- when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
doThrow(new SecurityException()).when(mContext)
.enforceCallingOrSelfPermission(eq(android.Manifest.permission.CHANGE_WIFI_STATE),
eq("WifiService"));
@@ -560,6 +578,58 @@
}
/**
+ * Ensure we return the proper variable for the softap state after getting an AP state change
+ * broadcast.
+ */
+ @Test
+ public void testGetWifiApEnabled() {
+ // set up WifiServiceImpl with a live thread for testing
+ HandlerThread serviceHandlerThread = new HandlerThread("ServiceHandlerThreadForTest");
+ serviceHandlerThread.start();
+ when(mWifiInjector.getWifiServiceHandlerThread()).thenReturn(serviceHandlerThread);
+ mWifiServiceImpl = new WifiServiceImpl(mContext, mWifiInjector, mAsyncChannel);
+ mWifiServiceImpl.setWifiHandlerLogForTest(mLog);
+
+ // ap should be disabled when wifi hasn't been started
+ assertEquals(WifiManager.WIFI_AP_STATE_DISABLED, mWifiServiceImpl.getWifiApEnabledState());
+
+ when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false);
+ when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
+ mWifiServiceImpl.checkAndStartWifi();
+ mLooper.dispatchAll();
+
+ // ap should be disabled initially
+ assertEquals(WifiManager.WIFI_AP_STATE_DISABLED, mWifiServiceImpl.getWifiApEnabledState());
+
+ // send an ap state change to verify WifiServiceImpl is updated
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
+ (IntentFilter) argThat(new IntentFilterMatcher()));
+
+ TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext,
+ WIFI_AP_STATE_FAILED, WIFI_AP_STATE_DISABLED, SAP_START_FAILURE_GENERAL,
+ WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY);
+ mLooper.dispatchAll();
+
+ assertEquals(WifiManager.WIFI_AP_STATE_FAILED, mWifiServiceImpl.getWifiApEnabledState());
+ }
+
+ /**
+ * Ensure we do not allow unpermitted callers to get the wifi ap state.
+ */
+ @Test
+ public void testGetWifiApEnabledPermissionDenied() {
+ // we should not be able to get the state
+ doThrow(new SecurityException()).when(mContext)
+ .enforceCallingOrSelfPermission(eq(android.Manifest.permission.ACCESS_WIFI_STATE),
+ eq("WifiService"));
+
+ try {
+ mWifiServiceImpl.getWifiApEnabledState();
+ fail("expected SecurityException");
+ } catch (SecurityException expected) { }
+ }
+
+ /**
* Make sure we do not start wifi if System services have to be restarted to decrypt the device.
*/
@Test
@@ -591,7 +661,6 @@
when(mSettingsStore.handleWifiToggled(true)).thenReturn(true);
when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
when(mWifiStateMachine.syncGetWifiState()).thenReturn(WIFI_STATE_DISABLED);
- when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
when(mContext.getPackageName()).thenReturn(ANDROID_SYSTEM_PACKAGE);
mWifiServiceImpl.checkAndStartWifi();
verify(mWifiController).start();
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachinePrimeTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachinePrimeTest.java
index 2e26769..0c5db44 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachinePrimeTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachinePrimeTest.java
@@ -19,8 +19,6 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;
-import android.net.wifi.IApInterface;
-import android.net.wifi.IWificond;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.INetworkManagementService;
@@ -56,8 +54,6 @@
@Mock WifiNative mWifiNative;
@Mock WifiApConfigStore mWifiApConfigStore;
TestLooper mLooper;
- @Mock IWificond mWificond;
- @Mock IApInterface mApInterface;
@Mock INetworkManagementService mNMService;
@Mock SoftApManager mSoftApManager;
SoftApManager.Listener mSoftApListener;
@@ -76,11 +72,15 @@
when(mWifiInjector.getWifiNative()).thenReturn(mWifiNative);
when(mWifiNative.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
mWifiStateMachinePrime = createWifiStateMachinePrime();
+
+ // creating a new WSMP cleans up any existing interfaces, check and reset expectations
+ verifyCleanupCalled();
+ reset(mWifiNative);
}
private WifiStateMachinePrime createWifiStateMachinePrime() {
- when(mWifiInjector.makeWificond()).thenReturn(null);
- return new WifiStateMachinePrime(mWifiInjector, mLooper.getLooper(), mNMService);
+ return new WifiStateMachinePrime(mWifiInjector, mLooper.getLooper(),
+ mWifiNative, mNMService);
}
/**
@@ -103,47 +103,46 @@
*/
private void enterSoftApActiveMode(SoftApModeConfiguration softApConfig) throws Exception {
String fromState = mWifiStateMachinePrime.getCurrentMode();
- when(mWifiInjector.makeWificond()).thenReturn(mWificond);
- when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(mApInterface);
- when(mApInterface.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
doAnswer(
new Answer<Object>() {
public SoftApManager answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
assertEquals(mNMService, (INetworkManagementService) args[0]);
mSoftApListener = (SoftApManager.Listener) args[1];
- assertEquals(mApInterface, (IApInterface) args[2]);
- assertEquals(WIFI_IFACE_NAME, (String) args[3]);
- assertEquals(softApConfig, (SoftApModeConfiguration) args[4]);
+ assertEquals(softApConfig, (SoftApModeConfiguration) args[2]);
return mSoftApManager;
}
}).when(mWifiInjector).makeSoftApManager(any(INetworkManagementService.class),
any(SoftApManager.Listener.class),
- any(IApInterface.class),
- anyString(),
any());
mWifiStateMachinePrime.enterSoftAPMode(softApConfig);
mLooper.dispatchAll();
Log.e("WifiStateMachinePrimeTest", "check fromState: " + fromState);
if (!fromState.equals(WIFI_DISABLED_STATE_STRING)) {
- verify(mWificond).tearDownInterfaces();
+ verifyCleanupCalled();
}
assertEquals(SOFT_AP_MODE_ACTIVE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
verify(mSoftApManager).start();
}
+ private void verifyCleanupCalled() {
+ // for now, this is a single call, but make a helper to avoid adding any additional cleanup
+ // checks
+ verify(mWifiNative, atLeastOnce()).tearDown();
+ }
+
/**
- * Test that when a new instance of WifiStateMachinePrime is created, any existing interfaces in
- * the retrieved Wificond instance are cleaned up.
+ * Test that when a new instance of WifiStateMachinePrime is created, any existing
+ * resources in WifiNative are cleaned up.
* Expectations: When the new WifiStateMachinePrime instance is created a call to
- * Wificond.tearDownInterfaces() is made.
+ * WifiNative.tearDown() is made.
*/
@Test
- public void testWificondExistsOnStartup() throws Exception {
- when(mWifiInjector.makeWificond()).thenReturn(mWificond);
+ public void testCleanupOnStart() throws Exception {
WifiStateMachinePrime testWifiStateMachinePrime =
- new WifiStateMachinePrime(mWifiInjector, mLooper.getLooper(), mNMService);
- verify(mWificond).tearDownInterfaces();
+ new WifiStateMachinePrime(mWifiInjector, mLooper.getLooper(),
+ mWifiNative, mNMService);
+ verifyCleanupCalled();
}
/**
@@ -157,12 +156,10 @@
/**
* Test that WifiStateMachinePrime properly enters the SoftApModeActiveState from another state.
- * Expectations: When going from one state to another, any interfaces that are still up are torn
- * down.
+ * Expectations: When going from one state to another, cleanup will be called
*/
@Test
public void testEnterSoftApModeFromDifferentState() throws Exception {
- when(mWifiInjector.makeWificond()).thenReturn(mWificond);
mWifiStateMachinePrime.enterClientMode();
mLooper.dispatchAll();
assertEquals(CLIENT_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
@@ -179,7 +176,7 @@
mWifiStateMachinePrime.disableWifi();
mLooper.dispatchAll();
verify(mSoftApManager).stop();
- verify(mWificond).tearDownInterfaces();
+ verifyCleanupCalled();
assertEquals(WIFI_DISABLED_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
@@ -188,16 +185,15 @@
*/
@Test
public void testDisableWifiFromSoftApModeState() throws Exception {
- // Use a failure getting wificond to stay in the SoftAPModeState
- when(mWifiInjector.makeWificond()).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode(
- new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
+ enterSoftApActiveMode();
+ // now inject failure through the SoftApManager.Listener
+ mSoftApListener.onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, 0);
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
mWifiStateMachinePrime.disableWifi();
mLooper.dispatchAll();
- // mWificond will be null due to this test, no call to tearDownInterfaces here.
+ verifyCleanupCalled();
assertEquals(WIFI_DISABLED_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
@@ -213,54 +209,24 @@
mWifiStateMachinePrime.enterClientMode();
mLooper.dispatchAll();
verify(mSoftApManager).stop();
- verify(mWificond).tearDownInterfaces();
+ verifyCleanupCalled();
assertEquals(CLIENT_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
/**
- * Test that we do not attempt to enter SoftApModeActiveState when we cannot get a reference to
- * wificond.
- * Expectations: After a failed attempt to get wificond from WifiInjector, we should remain in
- * the SoftApModeState.
- */
- @Test
- public void testWificondNullWhenSwitchingToApMode() throws Exception {
- when(mWifiInjector.makeWificond()).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode(
- new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
- mLooper.dispatchAll();
- assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
- }
-
- /**
- * Test that we do not attempt to enter SoftApModeActiveState when we cannot get an ApInterface
- * from wificond.
- * Expectations: After a failed attempt to get an ApInterface from WifiInjector, we should
- * remain in the SoftApModeState.
- */
- @Test
- public void testAPInterfaceFailedWhenSwitchingToApMode() throws Exception {
- when(mWifiInjector.makeWificond()).thenReturn(mWificond);
- when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode(
- new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
- mLooper.dispatchAll();
- assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
- }
-
- /**
* Test that we do enter the SoftApModeActiveState if we are already in the SoftApModeState.
* Expectations: We should exit the current SoftApModeState and re-enter before successfully
* entering the SoftApModeActiveState.
*/
@Test
public void testEnterSoftApModeActiveWhenAlreadyInSoftApMode() throws Exception {
- when(mWifiInjector.makeWificond()).thenReturn(mWificond);
- when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode(
- new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
+ enterSoftApActiveMode();
+ // now inject failure through the SoftApManager.Listener
+ mSoftApListener.onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, 0);
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
+ // clear the first call to start SoftApManager
+ reset(mSoftApManager);
enterSoftApActiveMode();
}
@@ -324,56 +290,12 @@
}
/**
- * Test that the proper config is used if a prior attempt fails without using the config.
- * Expectations: A call to start softap with a null config fails, but a second call has a set
- * config - this second call should use the correct config.
- */
- @Test
- public void testNullApModeConfigFails() throws Exception {
- when(mWifiInjector.makeWificond()).thenReturn(mWificond);
- when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode(
- new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
- mLooper.dispatchAll();
- assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
- WifiConfiguration config = new WifiConfiguration();
- config.SSID = "ThisIsAConfig";
- SoftApModeConfiguration softApConfig =
- new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
- enterSoftApActiveMode(softApConfig);
- }
-
- /**
- * Test that a failed call to start softap with a valid config does not persist the ap
- * configuration to the WifiApConfigStore.
- *
- * Expectations: A call to start SoftAPMode with a config should not write out the config if we
- * did not create a SoftApManager.
- */
- @Test
- public void testValidConfigIsSavedOnFailureToStart() throws Exception {
- when(mWifiInjector.makeWificond()).thenReturn(null);
- when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore);
- WifiConfiguration config = new WifiConfiguration();
- config.SSID = "ThisIsAConfig";
- SoftApModeConfiguration softApConfig =
- new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
- mWifiStateMachinePrime.enterSoftAPMode(softApConfig);
- mLooper.dispatchAll();
- assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
- verify(mWifiApConfigStore, never()).setApConfiguration(eq(config));
- }
-
- /**
- * Thest that two calls to switch to SoftAPMode in succession ends up with the correct config.
+ * Test that two calls to switch to SoftAPMode in succession ends up with the correct config.
*
* Expectation: we should end up in SoftAPMode state configured with the second config.
*/
@Test
public void testStartSoftApModeTwiceWithTwoConfigs() throws Exception {
- when(mWifiInjector.makeWificond()).thenReturn(mWificond);
- when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(mApInterface);
- when(mApInterface.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore);
WifiConfiguration config1 = new WifiConfiguration();
config1.SSID = "ThisIsAConfig";
@@ -386,14 +308,10 @@
when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
any(SoftApManager.Listener.class),
- any(IApInterface.class),
- anyString(),
eq(softApConfig1)))
.thenReturn(mSoftApManager);
when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
any(SoftApManager.Listener.class),
- any(IApInterface.class),
- anyString(),
eq(softApConfig2)))
.thenReturn(mSoftApManager);
@@ -406,12 +324,12 @@
/**
* Test that we safely disable wifi if it is already disabled.
- * Expectations: We should not interact with wificond since we should have already cleaned up
+ * Expectations: We should not interact with WifiNative since we should have already cleaned up
* everything.
*/
@Test
public void disableWifiWhenAlreadyOff() throws Exception {
- verifyNoMoreInteractions(mWificond);
+ verifyNoMoreInteractions(mWifiNative);
mWifiStateMachinePrime.disableWifi();
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
index ad5aa43..5208c74 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
@@ -16,18 +16,6 @@
package com.android.server.wifi;
-import static android.net.wifi.WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE;
-import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_FAILURE_REASON;
-import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
-import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
-import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
-import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
-import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
-import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
-import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
-
-import static com.android.server.wifi.LocalOnlyHotspotRequestInfo.HOTSPOT_NO_ERROR;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -52,7 +40,6 @@
import android.net.NetworkRequest;
import android.net.dhcp.DhcpClient;
import android.net.ip.IpClient;
-import android.net.wifi.IApInterface;
import android.net.wifi.IClientInterface;
import android.net.wifi.IWificond;
import android.net.wifi.ScanResult;
@@ -106,6 +93,7 @@
import com.android.server.wifi.hotspot2.PasspointProvisioningTestUtil;
import com.android.server.wifi.p2p.WifiP2pServiceImpl;
import com.android.server.wifi.util.WifiPermissionsUtil;
+import com.android.server.wifi.util.WifiPermissionsWrapper;
import org.junit.After;
import org.junit.Before;
@@ -152,6 +140,7 @@
private static final int WPS_FRAMEWORK_NETWORK_ID = 10;
private static final String DEFAULT_TEST_SSID = "\"GoogleGuest\"";
private static final String OP_PACKAGE_NAME = "com.xxx";
+ private static final int TEST_UID = Process.SYSTEM_UID + 1000;
private long mBinderToken;
@@ -353,7 +342,6 @@
@Mock PropertyService mPropertyService;
@Mock BuildProperties mBuildProperties;
@Mock IWificond mWificond;
- @Mock IApInterface mApInterface;
@Mock IClientInterface mClientInterface;
@Mock IBinder mPackageManagerBinder;
@Mock WifiConfigManager mWifiConfigManager;
@@ -373,6 +361,8 @@
@Mock ConnectivityManager mConnectivityManager;
@Mock IProvisioningCallback mProvisioningCallback;
@Mock HandlerThread mWifiServiceHandlerThread;
+ @Mock WifiPermissionsWrapper mWifiPermissionsWrapper;
+ @Mock WakeupController mWakeupController;
public WifiStateMachineTest() throws Exception {
}
@@ -403,11 +393,10 @@
when(mWifiInjector.getWifiScanner()).thenReturn(mWifiScanner);
when(mWifiInjector.makeWifiConnectivityManager(any(WifiInfo.class), anyBoolean()))
.thenReturn(mWifiConnectivityManager);
- when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
- mSoftApManagerListenerCaptor.capture(),
- any(IApInterface.class), anyString(),
- any(SoftApModeConfiguration.class)))
- .thenReturn(mSoftApManager);
+ //when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
+ // mSoftApManagerListenerCaptor.capture(),
+ // any(SoftApModeConfiguration.class)))
+ // .thenReturn(mSoftApManager);
when(mWifiInjector.getPasspointManager()).thenReturn(mPasspointManager);
when(mWifiInjector.getWifiStateTracker()).thenReturn(mWifiStateTracker);
when(mWifiInjector.getWifiMonitor()).thenReturn(mWifiMonitor);
@@ -418,12 +407,14 @@
when(mWifiInjector.getClock()).thenReturn(mClock);
when(mWifiServiceHandlerThread.getLooper()).thenReturn(mLooper.getLooper());
when(mWifiInjector.getWifiServiceHandlerThread()).thenReturn(mWifiServiceHandlerThread);
+ when(mWifiInjector.getWifiPermissionsWrapper()).thenReturn(mWifiPermissionsWrapper);
+ when(mWifiInjector.getWakeupController()).thenReturn(mWakeupController);
when(mWifiNative.setupForClientMode(WIFI_IFACE_NAME))
.thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mClientInterface));
- when(mWifiNative.setupForSoftApMode(WIFI_IFACE_NAME))
- .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
- when(mApInterface.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
+ //when(mWifiNative.setupForSoftApMode(WIFI_IFACE_NAME))
+ // .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
+ //when(mApInterface.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
when(mWifiNative.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
when(mWifiNative.enableSupplicant()).thenReturn(true);
when(mWifiNative.disableSupplicant()).thenReturn(true);
@@ -464,6 +455,8 @@
}).when(mTelephonyManager).listen(any(PhoneStateListener.class), anyInt());
when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true);
+ when(mWifiPermissionsWrapper.getLocalMacAddressPermission(anyInt()))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
initializeWsm();
mOsuProvider = PasspointProvisioningTestUtil.generateOsuProvider(true);
@@ -570,21 +563,6 @@
assertEquals("DisconnectedState", getCurrentState().getName());
}
- private void checkApStateChangedBroadcast(Intent intent, int expectedCurrentState,
- int expectedPrevState, int expectedErrorCode, String expectedIfaceName,
- int expectedMode) {
- int currentState = intent.getIntExtra(EXTRA_WIFI_AP_STATE, WIFI_AP_STATE_DISABLED);
- int prevState = intent.getIntExtra(EXTRA_PREVIOUS_WIFI_AP_STATE, WIFI_AP_STATE_DISABLED);
- int errorCode = intent.getIntExtra(EXTRA_WIFI_AP_FAILURE_REASON, HOTSPOT_NO_ERROR);
- String ifaceName = intent.getStringExtra(EXTRA_WIFI_AP_INTERFACE_NAME);
- int mode = intent.getIntExtra(EXTRA_WIFI_AP_MODE, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
- assertEquals(expectedCurrentState, currentState);
- assertEquals(expectedPrevState, prevState);
- assertEquals(expectedErrorCode, errorCode);
- assertEquals(expectedIfaceName, ifaceName);
- assertEquals(expectedMode, mode);
- }
-
private void loadComponentsInApMode(int mode) throws Exception {
SoftApModeConfiguration config = new SoftApModeConfiguration(mode, new WifiConfiguration());
mWsm.setHostApRunning(config, true);
@@ -592,20 +570,8 @@
assertEquals("SoftApState", getCurrentState().getName());
- verify(mWifiNative).setupForSoftApMode(WIFI_IFACE_NAME);
- verify(mSoftApManager).start();
-
- // get the SoftApManager.Listener and trigger some updates
- SoftApManager.Listener listener = mSoftApManagerListenerCaptor.getValue();
- listener.onStateChanged(WIFI_AP_STATE_ENABLING, 0);
- assertEquals(WIFI_AP_STATE_ENABLING, mWsm.syncGetWifiApState());
- listener.onStateChanged(WIFI_AP_STATE_ENABLED, 0);
- assertEquals(WIFI_AP_STATE_ENABLED, mWsm.syncGetWifiApState());
- listener.onStateChanged(WIFI_AP_STATE_DISABLING, 0);
- assertEquals(WIFI_AP_STATE_DISABLING, mWsm.syncGetWifiApState());
- // note, this will trigger a mode change when TestLooper is dispatched
- listener.onStateChanged(WIFI_AP_STATE_DISABLED, 0);
- assertEquals(WIFI_AP_STATE_DISABLED, mWsm.syncGetWifiApState());
+ verify(mWifiNative, never()).setupForSoftApMode(WIFI_IFACE_NAME);
+ verify(mSoftApManager, never()).start();
}
private void setupMockWpsPbc() throws Exception {
@@ -2193,6 +2159,16 @@
assertEquals(sBSSID1, wifiInfo.getBSSID());
assertEquals(sFreq1, wifiInfo.getFrequency());
assertEquals(SupplicantState.COMPLETED, wifiInfo.getSupplicantState());
+
+ mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
+ new StateChangeResult(0, sWifiSsid, sBSSID1, SupplicantState.DISCONNECTED));
+ mLooper.dispatchAll();
+
+ wifiInfo = mWsm.getWifiInfo();
+ assertEquals(null, wifiInfo.getBSSID());
+ assertEquals(WifiSsid.NONE, wifiInfo.getSSID());
+ assertEquals(WifiConfiguration.INVALID_NETWORK_ID, wifiInfo.getNetworkId());
+ assertEquals(SupplicantState.DISCONNECTED, wifiInfo.getSupplicantState());
}
/**
@@ -2288,56 +2264,29 @@
}
/**
- * Test that the process uid has full wifiInfo access.
- * Also tests that {@link WifiStateMachine#syncRequestConnectionInfo(String)} always
- * returns a copy of WifiInfo.
- */
- @Test
- public void testConnectedIdsAreVisibleFromOwnUid() throws Exception {
- assertEquals(Process.myUid(), Binder.getCallingUid());
- WifiInfo wifiInfo = mWsm.getWifiInfo();
- wifiInfo.setBSSID(sBSSID);
- wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(sSSID));
-
- connect();
- WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
-
- assertNotEquals(wifiInfo, connectionInfo);
- assertEquals(wifiInfo.getSSID(), connectionInfo.getSSID());
- assertEquals(wifiInfo.getBSSID(), connectionInfo.getBSSID());
- }
-
- /**
* Test that connected SSID and BSSID are not exposed to an app that does not have the
* appropriate permissions.
* Also tests that {@link WifiStateMachine#syncRequestConnectionInfo(String)} always
* returns a copy of WifiInfo.
*/
@Test
- public void testConnectedIdsAreHiddenFromRandomApp() throws Exception {
- int actualUid = Binder.getCallingUid();
- int fakeUid = Process.myUid() + 100000;
- assertNotEquals(actualUid, fakeUid);
- BinderUtil.setUid(fakeUid);
- try {
- WifiInfo wifiInfo = mWsm.getWifiInfo();
+ public void testConnectedIdsAreHiddenFromAppWithoutPermission() throws Exception {
+ WifiInfo wifiInfo = mWsm.getWifiInfo();
- // Get into a connected state, with known BSSID and SSID
- connect();
- assertEquals(sBSSID, wifiInfo.getBSSID());
- assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
+ // Get into a connected state, with known BSSID and SSID
+ connect();
+ assertEquals(sBSSID, wifiInfo.getBSSID());
+ assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
- when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(fakeUid), anyInt()))
- .thenReturn(false);
+ when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(TEST_UID), anyInt()))
+ .thenReturn(false);
- WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
+ WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName(),
+ TEST_UID);
- assertNotEquals(wifiInfo, connectionInfo);
- assertEquals(WifiSsid.NONE, connectionInfo.getSSID());
- assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getBSSID());
- } finally {
- BinderUtil.setUid(actualUid);
- }
+ assertNotEquals(wifiInfo, connectionInfo);
+ assertEquals(WifiSsid.NONE, connectionInfo.getSSID());
+ assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getBSSID());
}
/**
@@ -2348,29 +2297,48 @@
*/
@Test
public void testConnectedIdsAreHiddenOnSecurityException() throws Exception {
- int actualUid = Binder.getCallingUid();
- int fakeUid = Process.myUid() + 100000;
- assertNotEquals(actualUid, fakeUid);
- BinderUtil.setUid(fakeUid);
- try {
- WifiInfo wifiInfo = mWsm.getWifiInfo();
+ WifiInfo wifiInfo = mWsm.getWifiInfo();
- // Get into a connected state, with known BSSID and SSID
- connect();
- assertEquals(sBSSID, wifiInfo.getBSSID());
- assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
+ // Get into a connected state, with known BSSID and SSID
+ connect();
+ assertEquals(sBSSID, wifiInfo.getBSSID());
+ assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
- when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(fakeUid), anyInt()))
- .thenThrow(new SecurityException());
+ when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(TEST_UID), anyInt()))
+ .thenThrow(new SecurityException());
- WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
+ WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName(),
+ TEST_UID);
- assertNotEquals(wifiInfo, connectionInfo);
- assertEquals(WifiSsid.NONE, connectionInfo.getSSID());
- assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getBSSID());
- } finally {
- BinderUtil.setUid(actualUid);
- }
+ assertNotEquals(wifiInfo, connectionInfo);
+ assertEquals(WifiSsid.NONE, connectionInfo.getSSID());
+ assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getBSSID());
+ }
+
+ /**
+ * Test that connected SSID and BSSID are exposed to system server
+ */
+ @Test
+ public void testConnectedIdsAreVisibleFromSystemServer() throws Exception {
+ when(mWifiPermissionsWrapper.getLocalMacAddressPermission(anyInt()))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+ WifiInfo wifiInfo = mWsm.getWifiInfo();
+ // Get into a connected state, with known BSSID and SSID
+ connect();
+ assertEquals(sBSSID, wifiInfo.getBSSID());
+ assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
+
+ when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(TEST_UID), anyInt()))
+ .thenReturn(true);
+
+ WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName(),
+ TEST_UID);
+
+ assertNotEquals(wifiInfo, connectionInfo);
+ assertEquals(wifiInfo.getSSID(), connectionInfo.getSSID());
+ assertEquals(wifiInfo.getBSSID(), connectionInfo.getBSSID());
+ assertEquals(wifiInfo.getMacAddress(), connectionInfo.getMacAddress());
}
/**
@@ -2379,30 +2347,24 @@
*/
@Test
public void testConnectedIdsAreVisibleFromPermittedApp() throws Exception {
- int actualUid = Binder.getCallingUid();
- int fakeUid = Process.myUid() + 100000;
- BinderUtil.setUid(fakeUid);
- try {
- WifiInfo wifiInfo = mWsm.getWifiInfo();
+ WifiInfo wifiInfo = mWsm.getWifiInfo();
- // Get into a connected state, with known BSSID and SSID
- connect();
- assertEquals(sBSSID, wifiInfo.getBSSID());
- assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
+ // Get into a connected state, with known BSSID and SSID
+ connect();
+ assertEquals(sBSSID, wifiInfo.getBSSID());
+ assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
- when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(fakeUid), anyInt()))
- .thenReturn(true);
+ when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(TEST_UID), anyInt()))
+ .thenReturn(true);
- WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
+ WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName(),
+ TEST_UID);
- assertNotEquals(wifiInfo, connectionInfo);
- assertEquals(wifiInfo.getSSID(), connectionInfo.getSSID());
- assertEquals(wifiInfo.getBSSID(), connectionInfo.getBSSID());
- // Access to our MAC address uses a different permission, make sure it is not granted
- assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getMacAddress());
- } finally {
- BinderUtil.setUid(actualUid);
- }
+ assertNotEquals(wifiInfo, connectionInfo);
+ assertEquals(wifiInfo.getSSID(), connectionInfo.getSSID());
+ assertEquals(wifiInfo.getBSSID(), connectionInfo.getBSSID());
+ // Access to our MAC address uses a different permission, make sure it is not granted
+ assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getMacAddress());
}
/**
@@ -2477,40 +2439,6 @@
}
/**
- * Test that failure to start HAL in AP mode increments the corresponding metrics.
- */
- @Test
- public void testSetupForSoftApModeHalFailureIncrementsMetrics() throws Exception {
- when(mWifiNative.setupForSoftApMode(WIFI_IFACE_NAME))
- .thenReturn(Pair.create(WifiNative.SETUP_FAILURE_HAL, null));
-
- SoftApModeConfiguration config = new SoftApModeConfiguration(
- WifiManager.IFACE_IP_MODE_TETHERED, new WifiConfiguration());
- mWsm.setHostApRunning(config, true);
- mLooper.dispatchAll();
-
- verify(mWifiNative).setupForSoftApMode(WIFI_IFACE_NAME);
- verify(mWifiMetrics).incrementNumWifiOnFailureDueToHal();
- }
-
- /**
- * Test that failure to start HAL in AP mode increments the corresponding metrics.
- */
- @Test
- public void testSetupForSoftApModeWificondFailureIncrementsMetrics() throws Exception {
- when(mWifiNative.setupForSoftApMode(WIFI_IFACE_NAME))
- .thenReturn(Pair.create(WifiNative.SETUP_FAILURE_WIFICOND, null));
-
- SoftApModeConfiguration config = new SoftApModeConfiguration(
- WifiManager.IFACE_IP_MODE_TETHERED, new WifiConfiguration());
- mWsm.setHostApRunning(config, true);
- mLooper.dispatchAll();
-
- verify(mWifiNative).setupForSoftApMode(WIFI_IFACE_NAME);
- verify(mWifiMetrics).incrementNumWifiOnFailureDueToWificond();
- }
-
- /**
* Test that failure to start HAL in client mode increments the corresponding metrics.
*/
@Test
@@ -2827,4 +2755,15 @@
currentConfig.networkId = lastSelectedNetworkId - 1;
assertFalse(mWsm.shouldEvaluateWhetherToSendExplicitlySelected(currentConfig));
}
+
+ /**
+ * Verify that WSM dump includes WakeupController.
+ */
+ @Test
+ public void testDumpShouldDumpWakeupController() {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ PrintWriter writer = new PrintWriter(stream);
+ mWsm.dump(null, writer, null);
+ verify(mWakeupController).dump(null, writer, null);
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java b/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java
index 51fed83..5043c85 100644
--- a/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java
@@ -35,12 +35,11 @@
import android.hardware.wifi.V1_0.RttType;
import android.hardware.wifi.V1_0.WifiStatus;
import android.hardware.wifi.V1_0.WifiStatusCode;
+import android.net.MacAddress;
import android.net.wifi.rtt.RangingRequest;
import com.android.server.wifi.HalDeviceManager;
-import libcore.util.HexEncoding;
-
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -118,19 +117,19 @@
RttConfig rttConfig = halRequest.get(0);
collector.checkThat("entry 0: MAC", rttConfig.addr,
- equalTo(HexEncoding.decode("000102030400".toCharArray(), false)));
+ equalTo(MacAddress.fromString("00:01:02:03:04:00").toByteArray()));
collector.checkThat("entry 0: MAC", rttConfig.type, equalTo(RttType.TWO_SIDED));
collector.checkThat("entry 0: MAC", rttConfig.peer, equalTo(RttPeerType.AP));
rttConfig = halRequest.get(1);
collector.checkThat("entry 1: MAC", rttConfig.addr,
- equalTo(HexEncoding.decode("0A0B0C0D0E00".toCharArray(), false)));
+ equalTo(MacAddress.fromString("0A:0B:0C:0D:0E:00").toByteArray()));
collector.checkThat("entry 1: MAC", rttConfig.type, equalTo(RttType.ONE_SIDED));
collector.checkThat("entry 1: MAC", rttConfig.peer, equalTo(RttPeerType.AP));
rttConfig = halRequest.get(2);
collector.checkThat("entry 2: MAC", rttConfig.addr,
- equalTo(HexEncoding.decode("080908070605".toCharArray(), false)));
+ equalTo(MacAddress.fromString("08:09:08:07:06:05").toByteArray()));
collector.checkThat("entry 2: MAC", rttConfig.type, equalTo(RttType.TWO_SIDED));
collector.checkThat("entry 2: MAC", rttConfig.peer, equalTo(RttPeerType.NAN));
@@ -164,8 +163,8 @@
public void testRangeCancel() throws Exception {
int cmdId = 66;
ArrayList<byte[]> macAddresses = new ArrayList<>();
- byte[] mac1 = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
- byte[] mac2 = { 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
+ byte[] mac1 = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+ byte[] mac2 = {0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
macAddresses.add(mac1);
macAddresses.add(mac2);
@@ -212,7 +211,7 @@
collector.checkThat("status", rttResult.status,
equalTo(RttStatus.SUCCESS));
collector.checkThat("mac", rttResult.addr,
- equalTo(HexEncoding.decode("05060708090A".toCharArray(), false)));
+ equalTo(MacAddress.fromString("05:06:07:08:09:0A").toByteArray()));
collector.checkThat("distanceCm", rttResult.distanceInMm, equalTo(1500));
collector.checkThat("timestamp", rttResult.timeStampInUs, equalTo(666L));
diff --git a/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java
index ee8c15f..7e71069 100644
--- a/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java
@@ -46,6 +46,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.wifi.V1_0.RttResult;
+import android.net.MacAddress;
import android.net.wifi.aware.IWifiAwareMacAddressProvider;
import android.net.wifi.aware.IWifiAwareManager;
import android.net.wifi.aware.PeerHandle;
@@ -68,8 +69,6 @@
import com.android.server.wifi.Clock;
import com.android.server.wifi.util.WifiPermissionsUtil;
-import libcore.util.HexEncoding;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -261,9 +260,9 @@
PeerHandle peerHandle2 = new PeerHandle(1023);
request.mRttPeers.add(ResponderConfig.fromWifiAwarePeerHandleWithDefaults(peerHandle1));
request.mRttPeers.add(ResponderConfig.fromWifiAwarePeerHandleWithDefaults(peerHandle2));
- Map<Integer, byte[]> peerHandleToMacMap = new HashMap<>();
- byte[] macAwarePeer1 = HexEncoding.decode("AABBCCDDEEFF".toCharArray(), false);
- byte[] macAwarePeer2 = HexEncoding.decode("BBBBBBEEEEEE".toCharArray(), false);
+ Map<Integer, MacAddress> peerHandleToMacMap = new HashMap<>();
+ MacAddress macAwarePeer1 = MacAddress.fromString("AA:BB:CC:DD:EE:FF");
+ MacAddress macAwarePeer2 = MacAddress.fromString("BB:BB:BB:EE:EE:EE");
peerHandleToMacMap.put(peerHandle1.peerId, macAwarePeer1);
peerHandleToMacMap.put(peerHandle2.peerId, macAwarePeer2);
@@ -431,11 +430,11 @@
(ArrayList) mListCaptor.capture());
RangingRequest request0 = requests[0];
assertEquals(request0.mRttPeers.size(), mListCaptor.getValue().size());
- assertArrayEquals(HexEncoding.decode("000102030400".toCharArray(), false),
+ assertArrayEquals(MacAddress.fromString("00:01:02:03:04:00").toByteArray(),
(byte[]) mListCaptor.getValue().get(0));
- assertArrayEquals(HexEncoding.decode("0A0B0C0D0E00".toCharArray(), false),
+ assertArrayEquals(MacAddress.fromString("0A:0B:0C:0D:0E:00").toByteArray(),
(byte[]) mListCaptor.getValue().get(1));
- assertArrayEquals(HexEncoding.decode("080908070605".toCharArray(), false),
+ assertArrayEquals(MacAddress.fromString("08:09:08:07:06:05").toByteArray(),
(byte[]) mListCaptor.getValue().get(2));
}
@@ -1103,9 +1102,9 @@
private class AwareTranslatePeerHandlesToMac extends MockAnswerUtil.AnswerWithArguments {
private int mExpectedUid;
- private Map<Integer, byte[]> mPeerIdToMacMap;
+ private Map<Integer, MacAddress> mPeerIdToMacMap;
- AwareTranslatePeerHandlesToMac(int expectedUid, Map<Integer, byte[]> peerIdToMacMap) {
+ AwareTranslatePeerHandlesToMac(int expectedUid, Map<Integer, MacAddress> peerIdToMacMap) {
mExpectedUid = expectedUid;
mPeerIdToMacMap = peerIdToMacMap;
}
@@ -1115,7 +1114,7 @@
Map<Integer, byte[]> result = new HashMap<>();
for (Integer peerId: peerIds) {
- byte[] mac = mPeerIdToMacMap.get(peerId);
+ byte[] mac = mPeerIdToMacMap.get(peerId).toByteArray();
if (mac == null) {
continue;
}
diff --git a/tests/wifitests/src/com/android/server/wifi/rtt/RttTestUtils.java b/tests/wifitests/src/com/android/server/wifi/rtt/RttTestUtils.java
index db3cd17..ec56322 100644
--- a/tests/wifitests/src/com/android/server/wifi/rtt/RttTestUtils.java
+++ b/tests/wifitests/src/com/android/server/wifi/rtt/RttTestUtils.java
@@ -18,14 +18,13 @@
import android.hardware.wifi.V1_0.RttResult;
import android.hardware.wifi.V1_0.RttStatus;
+import android.net.MacAddress;
import android.net.wifi.ScanResult;
import android.net.wifi.rtt.RangingRequest;
import android.net.wifi.rtt.RangingResult;
import android.net.wifi.rtt.ResponderConfig;
import android.util.Pair;
-import libcore.util.HexEncoding;
-
import java.util.ArrayList;
import java.util.List;
@@ -66,7 +65,7 @@
scan1.setFlag(ScanResult.FLAG_80211mc_RESPONDER);
ScanResult scan2 = new ScanResult();
scan2.BSSID = "0A:0B:0C:0D:0E:" + String.format("%02d", lastMacByte);
- byte[] mac1 = HexEncoding.decode("080908070605".toCharArray(), false);
+ MacAddress mac1 = MacAddress.fromString("08:09:08:07:06:05");
builder.addAccessPoint(scan1);
builder.addAccessPoint(scan2);
@@ -107,13 +106,13 @@
}
} else {
results.add(new RangingResult(RangingResult.STATUS_SUCCESS,
- HexEncoding.decode("100102030405".toCharArray(), false), rangeCmBase++,
+ MacAddress.fromString("10:01:02:03:04:05"), rangeCmBase++,
rangeStdDevCmBase++, rssiBase++, rangeTimestampBase++));
results.add(new RangingResult(RangingResult.STATUS_SUCCESS,
- HexEncoding.decode("1A0B0C0D0E0F".toCharArray(), false), rangeCmBase++,
+ MacAddress.fromString("1A:0B:0C:0D:0E:0F"), rangeCmBase++,
rangeStdDevCmBase++, rssiBase++, rangeTimestampBase++));
results.add(new RangingResult(RangingResult.STATUS_SUCCESS,
- HexEncoding.decode("080908070605".toCharArray(), false), rangeCmBase++,
+ MacAddress.fromString("08:09:08:07:06:05"), rangeCmBase++,
rangeStdDevCmBase++, rssiBase++, rangeTimestampBase++));
halResults.add(getMatchingRttResult(results.get(0), null));
halResults.add(getMatchingRttResult(results.get(1), null));
@@ -123,12 +122,13 @@
return new Pair<>(halResults, results);
}
- private static RttResult getMatchingRttResult(RangingResult rangingResult, byte[] overrideMac) {
+ private static RttResult getMatchingRttResult(RangingResult rangingResult,
+ MacAddress overrideMac) {
RttResult rttResult = new RttResult();
rttResult.status = rangingResult.getStatus() == RangingResult.STATUS_SUCCESS
? RttStatus.SUCCESS : RttStatus.FAILURE;
- System.arraycopy(overrideMac == null ? rangingResult.getMacAddress() : overrideMac, 0,
- rttResult.addr, 0, 6);
+ System.arraycopy(overrideMac == null ? rangingResult.getMacAddress().toByteArray()
+ : overrideMac.toByteArray(), 0, rttResult.addr, 0, 6);
rttResult.distanceInMm = rangingResult.getDistanceMm();
rttResult.distanceSdInMm = rangingResult.getDistanceStdDevMm();
rttResult.rssi = rangingResult.getRssi();
diff --git a/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java b/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java
index 4ffc66d..5b797e8 100644
--- a/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java
@@ -16,12 +16,35 @@
package com.android.server.wifi.scanner;
-import static com.android.server.wifi.ScanTestUtil.*;
+import static com.android.server.wifi.ScanTestUtil.NativeScanSettingsBuilder;
+import static com.android.server.wifi.ScanTestUtil.assertNativePnoSettingsEquals;
+import static com.android.server.wifi.ScanTestUtil.assertNativeScanSettingsEquals;
+import static com.android.server.wifi.ScanTestUtil.assertScanDatasEquals;
+import static com.android.server.wifi.ScanTestUtil.assertScanResultsEquals;
+import static com.android.server.wifi.ScanTestUtil.channelsToSpec;
+import static com.android.server.wifi.ScanTestUtil.computeSingleScanNativeSettings;
+import static com.android.server.wifi.ScanTestUtil.createRequest;
+import static com.android.server.wifi.ScanTestUtil.createSingleScanNativeSettingsForChannels;
import static com.android.server.wifi.scanner.WifiScanningServiceImpl.WifiSingleScanStateMachine
.CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS;
-import static org.junit.Assert.*;
-import static org.mockito.Mockito.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.argThat;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+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.when;
import android.app.test.MockAnswerUtil.AnswerWithArguments;
import android.app.test.TestAlarmManager;
@@ -63,11 +86,11 @@
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
-import org.mockito.compat.CapturingMatcher;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -161,14 +184,35 @@
return messageCaptor.getValue();
}
+ private static class ConditionalMessageCaptor implements ArgumentMatcher<Message> {
+ private Message mLastValue;
+ private final int mWhat;
+
+ private ConditionalMessageCaptor(int what) {
+ mWhat = what;
+ }
+
+ public Message getLastValue() {
+ assertNotNull("Nothing captured yet", mLastValue);
+
+ return mLastValue;
+ }
+
+ public boolean matches(Message message) {
+ boolean isMatch = message.what == mWhat;
+
+ if (isMatch) {
+ mLastValue = message;
+ }
+
+ return isMatch;
+ }
+ }
+
private static Message verifyHandleMessageAndGetMessage(InOrder order, Handler handler,
final int what) {
- CapturingMatcher<Message> messageMatcher = new CapturingMatcher<Message>() {
- public boolean matchesObject(Object argument) {
- Message message = (Message) argument;
- return message.what == what;
- }
- };
+ ConditionalMessageCaptor messageMatcher = new ConditionalMessageCaptor(what);
+
order.verify(handler).handleMessage(argThat(messageMatcher));
return messageMatcher.getLastValue();
}
diff --git a/tests/wifitests/src/com/android/server/wifi/scanner/WificondPnoScannerTest.java b/tests/wifitests/src/com/android/server/wifi/scanner/WificondPnoScannerTest.java
index 73ea143..15dfccc 100644
--- a/tests/wifitests/src/com/android/server/wifi/scanner/WificondPnoScannerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/scanner/WificondPnoScannerTest.java
@@ -17,7 +17,6 @@
package com.android.server.wifi.scanner;
import static com.android.server.wifi.ScanTestUtil.NativeScanSettingsBuilder;
-import static com.android.server.wifi.ScanTestUtil.assertScanDataEquals;
import static com.android.server.wifi.ScanTestUtil.setupMockChannels;
import static org.junit.Assert.*;
@@ -45,7 +44,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.Arrays;
import java.util.Set;
/**
@@ -104,89 +102,6 @@
}
/**
- * Verify that we pause & resume HW PNO scan when a single scan is scheduled and invokes the
- * OnPnoNetworkFound callback when the scan results are received.
- */
- @Test
- public void pauseResumeHwDisconnectedPnoScanForSingleScan() {
- createScannerWithHwPnoScanSupport();
-
- WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
- WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false);
- WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
- WifiNative.ScanSettings settings = createDummyScanSettings(false);
- ScanResults scanResults = createDummyScanResults(false);
-
- InOrder order = inOrder(eventHandler, mWifiNative);
- // Start PNO scan
- startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
- // Start single scan
- assertTrue(mScanner.startSingleScan(settings, eventHandler));
- // Verify that the PNO scan was paused and single scan runs successfully
- expectSuccessfulSingleScanWithHwPnoEnabled(order, eventHandler,
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ), scanResults);
- verifyNoMoreInteractions(eventHandler);
-
- order = inOrder(pnoEventHandler, mWifiNative);
- // Resume PNO scan after the single scan results are received and PNO monitor debounce
- // alarm fires.
- assertTrue("dispatch pno monitor alarm",
- mAlarmManager.dispatch(
- WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
- assertEquals("dispatch message after alarm", 1, mLooper.dispatchAll());
- // Now verify that PNO scan is resumed successfully
- expectSuccessfulHwDisconnectedPnoScan(order, pnoSettings, pnoEventHandler, scanResults);
- verifyNoMoreInteractions(pnoEventHandler);
- }
-
- /**
- * Verify that the HW PNO delayed failure cleans up the scan settings cleanly.
- * 1. Start Hw PNO.
- * 2. Start Single Scan which should pause PNO scan.
- * 3. Fail the PNO scan resume and verify that the OnPnoScanFailed callback is invoked.
- * 4. Now restart a new PNO scan to ensure that the failure was cleanly handled.
- */
- @Test
- public void delayedHwDisconnectedPnoScanFailure() {
- createScannerWithHwPnoScanSupport();
-
- WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
- WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false);
- WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
- WifiNative.ScanSettings settings = createDummyScanSettings(false);
- ScanResults scanResults = createDummyScanResults(false);
-
- InOrder order = inOrder(eventHandler, mWifiNative);
- // Start PNO scan
- startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
- // Start single scan
- assertTrue(mScanner.startSingleScan(settings, eventHandler));
- // Verify that the PNO scan was paused and single scan runs successfully
- expectSuccessfulSingleScanWithHwPnoEnabled(order, eventHandler,
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ), scanResults);
- verifyNoMoreInteractions(eventHandler);
-
- // Fail the PNO resume and check that the OnPnoScanFailed callback is invoked.
- order = inOrder(pnoEventHandler, mWifiNative);
- when(mWifiNative.startPnoScan(any(WifiNative.PnoSettings.class))).thenReturn(false);
- assertTrue("dispatch pno monitor alarm",
- mAlarmManager.dispatch(
- WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
- assertEquals("dispatch message after alarm", 1, mLooper.dispatchAll());
- order.verify(pnoEventHandler).onPnoScanFailed();
- verifyNoMoreInteractions(pnoEventHandler);
-
- // Add a new PNO scan request
- startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
- assertTrue("dispatch pno monitor alarm",
- mAlarmManager.dispatch(
- WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
- assertEquals("dispatch message after alarm", 1, mLooper.dispatchAll());
- expectSuccessfulHwDisconnectedPnoScan(order, pnoSettings, pnoEventHandler, scanResults);
- verifyNoMoreInteractions(pnoEventHandler);
- }
-
- /**
* Verify that the HW PNO scan stop failure still resets the PNO scan state.
* 1. Start Hw PNO.
* 2. Stop Hw PNO scan which raises a stop command to WifiNative which is failed.
@@ -205,17 +120,11 @@
// Fail the PNO stop.
when(mWifiNative.stopPnoScan()).thenReturn(false);
assertTrue(mScanner.resetHwPnoList());
- assertTrue("dispatch pno monitor alarm",
- mAlarmManager.dispatch(
- WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
mLooper.dispatchAll();
verify(mWifiNative).stopPnoScan();
// Add a new PNO scan request and ensure it runs successfully.
startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
- assertTrue("dispatch pno monitor alarm",
- mAlarmManager.dispatch(
- WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
mLooper.dispatchAll();
InOrder order = inOrder(pnoEventHandler, mWifiNative);
ScanResults scanResults = createDummyScanResults(false);
@@ -223,84 +132,6 @@
verifyNoMoreInteractions(pnoEventHandler);
}
- /**
- * Verify that the HW PNO scan is forcefully stopped (bypass debounce logic) and restarted when
- * settings change.
- * 1. Start Hw PNO.
- * 2. Stop Hw PNO .
- * 3. Now restart a new PNO scan with different settings.
- * 4. Ensure that the stop was issued before we start again.
- */
- @Test
- public void forceRestartHwDisconnectedPnoScanWhenSettingsChange() {
- createScannerWithHwPnoScanSupport();
-
- WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
- WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false);
- InOrder order = inOrder(pnoEventHandler, mWifiNative);
-
- // Start PNO scan
- startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
- expectHwDisconnectedPnoScanStart(order, pnoSettings);
-
- // Stop PNO now. This should trigger the debounce timer and not stop PNO.
- assertTrue(mScanner.resetHwPnoList());
- assertTrue(mAlarmManager.isPending(
- WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
- order.verify(mWifiNative, never()).stopPnoScan();
-
- // Now restart PNO scan with an extra network in settings.
- pnoSettings.networkList =
- Arrays.copyOf(pnoSettings.networkList, pnoSettings.networkList.length + 1);
- pnoSettings.networkList[pnoSettings.networkList.length - 1] =
- createDummyPnoNetwork("ssid_pno_new");
- startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
-
- // This should bypass the debounce timer and stop PNO scan immediately and then start
- // a new debounce timer for the start.
- order.verify(mWifiNative).stopPnoScan();
-
- // Trigger the debounce timer and ensure we start PNO scan again.
- mAlarmManager.dispatch(WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG);
- mLooper.dispatchAll();
- order.verify(mWifiNative).startPnoScan(pnoSettings);
- }
-
- /**
- * Verify that the HW PNO scan is not forcefully stopped (bypass debounce logic) when
- * settings don't change.
- * 1. Start Hw PNO.
- * 2. Stop Hw PNO .
- * 3. Now restart a new PNO scan with same settings.
- * 4. Ensure that the stop was never issued.
- */
- @Test
- public void noForceRestartHwDisconnectedPnoScanWhenNoSettingsChange() {
- createScannerWithHwPnoScanSupport();
-
- WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
- WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false);
- InOrder order = inOrder(pnoEventHandler, mWifiNative);
-
- // Start PNO scan
- startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
- expectHwDisconnectedPnoScanStart(order, pnoSettings);
-
- // Stop PNO now. This should trigger the debounce timer and not stop PNO.
- assertTrue(mScanner.resetHwPnoList());
- assertTrue(mAlarmManager.isPending(
- WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
- order.verify(mWifiNative, never()).stopPnoScan();
-
- // Now restart PNO scan with the same settings.
- startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
-
- // Trigger the debounce timer and ensure that we neither stop/start.
- mLooper.dispatchAll();
- order.verify(mWifiNative, never()).startPnoScan(any(WifiNative.PnoSettings.class));
- order.verify(mWifiNative, never()).stopPnoScan();
- }
-
private void createScannerWithHwPnoScanSupport() {
mResources.setBoolean(R.bool.config_wifi_background_scan_support, true);
mScanner = new WificondScannerImpl(mContext, mWifiNative, mWifiMonitor,
@@ -389,27 +220,4 @@
order.verify(eventHandler).onPnoNetworkFound(scanResults.getRawScanResults());
}
- /**
- * Verify that the single scan results were delivered and that the PNO scan was paused and
- * resumed either side of it.
- */
- private void expectSuccessfulSingleScanWithHwPnoEnabled(InOrder order,
- WifiNative.ScanEventHandler eventHandler, Set<Integer> expectedScanFreqs,
- ScanResults scanResults) {
- // Pause PNO scan first
- order.verify(mWifiNative).stopPnoScan();
-
- order.verify(mWifiNative).scan(eq(expectedScanFreqs), any(Set.class));
-
- when(mWifiNative.getPnoScanResults()).thenReturn(scanResults.getScanDetailArrayList());
- when(mWifiNative.getScanResults()).thenReturn(scanResults.getScanDetailArrayList());
-
- // Notify scan has finished
- mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT);
- assertEquals("dispatch message after results event", 1, mLooper.dispatchAll());
-
- order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
- assertScanDataEquals(scanResults.getScanData(), mScanner.getLatestSingleScanResults());
- }
-
}