summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJimmy Chen <jimmycmchen@google.com>2019-08-29 18:17:27 +0800
committerJimmy Chen <jimmycmchen@google.com>2019-09-26 10:45:28 +0800
commit5eb739cfd72ffe47b0a5dc48f7f646b238628293 (patch)
tree6ecdde2d3e86ec9911a01b1b979bc5bcbff13444
parent111e4e3a6f5dd590dd354a55ea06a0320a42b99c (diff)
wifi: store PMK cache in Android framework
Supplicant network is cleared after disconnection and PMK cache is cleared as well. Android framework needs to store existing PMK cache and passes it to supplicant on demand. Bug: 36505680 Test: atest FrameworksNetTests Test: connect EAP access point and verify PMK cache works correctly. Change-Id: I2b7ea1ae6e90e3a3ae19933bf60a3ee61925ba9f
-rw-r--r--service/java/com/android/server/wifi/SupplicantStaIfaceHal.java414
-rw-r--r--service/java/com/android/server/wifi/SupplicantStaNetworkHal.java26
-rw-r--r--service/java/com/android/server/wifi/WifiConnectivityHelper.java9
-rw-r--r--service/java/com/android/server/wifi/WifiConnectivityManager.java1
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java2
-rw-r--r--service/java/com/android/server/wifi/WifiNative.java9
-rw-r--r--tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java344
-rw-r--r--tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkHalTest.java39
8 files changed, 723 insertions, 121 deletions
diff --git a/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java b/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java
index 75aef2a82..0d37e98d7 100644
--- a/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java
+++ b/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java
@@ -79,6 +79,7 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
@@ -109,6 +110,8 @@ public class SupplicantStaIfaceHal {
public static final String INIT_SERVICE_NAME = "wpa_supplicant";
@VisibleForTesting
public static final long WAIT_FOR_DEATH_TIMEOUT_MS = 50L;
+ @VisibleForTesting
+ static final String PMK_CACHE_EXPIRATION_ALARM_TAG = "PMK_CACHE_EXPIRATION_TIMER";
/**
* Regex pattern for extracting the wps device type bytes.
* Matches a strings like the following: "<categ>-<OUI>-<subcateg>";
@@ -127,6 +130,8 @@ public class SupplicantStaIfaceHal {
new HashMap<>();
private HashMap<String, SupplicantStaNetworkHal> mCurrentNetworkRemoteHandles = new HashMap<>();
private HashMap<String, WifiConfiguration> mCurrentNetworkLocalConfigs = new HashMap<>();
+ @VisibleForTesting
+ HashMap<Integer, PmkCacheStoreData> mPmkCacheEntries = new HashMap<>();
private SupplicantDeathEventHandler mDeathEventHandler;
private ServiceManagerDeathRecipient mServiceManagerDeathRecipient;
private SupplicantDeathRecipient mSupplicantDeathRecipient;
@@ -137,6 +142,7 @@ public class SupplicantStaIfaceHal {
private final PropertyService mPropertyService;
private final Handler mEventHandler;
private DppEventCallback mDppCallback = null;
+ private final Clock mClock;
private final IServiceNotification mServiceNotificationCallback =
new IServiceNotification.Stub() {
@@ -179,12 +185,25 @@ public class SupplicantStaIfaceHal {
}
}
+ @VisibleForTesting
+ static class PmkCacheStoreData {
+ public long expirationTimeInSec;
+ public ArrayList<Byte> data;
+
+ PmkCacheStoreData(long timeInSec, ArrayList<Byte> serializedData) {
+ expirationTimeInSec = timeInSec;
+ data = serializedData;
+ }
+ }
+
public SupplicantStaIfaceHal(Context context, WifiMonitor monitor,
- PropertyService propertyService, Handler handler) {
+ PropertyService propertyService, Handler handler,
+ Clock clock) {
mContext = context;
mWifiMonitor = monitor;
mPropertyService = propertyService;
mEventHandler = handler;
+ mClock = clock;
mServiceManagerDeathRecipient = new ServiceManagerDeathRecipient();
mSupplicantDeathRecipient = new SupplicantDeathRecipient();
@@ -313,6 +332,94 @@ public class SupplicantStaIfaceHal {
}
}
+ private boolean trySetupStaIfaceV1_3(@NonNull String ifaceName,
+ @NonNull ISupplicantStaIface iface) throws RemoteException {
+ if (!isV1_3()) return false;
+
+ SupplicantStaIfaceHalCallbackV1_3 callbackV13 =
+ new SupplicantStaIfaceHalCallbackV1_3(ifaceName);
+ if (!registerCallbackV1_3(getStaIfaceMockableV1_3(iface), callbackV13)) {
+ throw new RemoteException("Init StaIface V1_3 failed.");
+ }
+ /* keep this in a store to avoid recycling by garbage collector. */
+ mISupplicantStaIfaceCallbacks.put(ifaceName, callbackV13);
+ return true;
+ }
+
+ private boolean trySetupStaIfaceV1_2(@NonNull String ifaceName,
+ @NonNull ISupplicantStaIface iface) throws RemoteException {
+ if (!isV1_2()) return false;
+
+ /* try newer version fist. */
+ if (trySetupStaIfaceV1_3(ifaceName, iface)) {
+ logd("Newer HAL is found, skip V1_2 remaining init flow.");
+ return true;
+ }
+
+ SupplicantStaIfaceHalCallbackV1_2 callbackV12 =
+ new SupplicantStaIfaceHalCallbackV1_2(ifaceName);
+ if (!registerCallbackV1_2(getStaIfaceMockableV1_2(iface), callbackV12)) {
+ throw new RemoteException("Init StaIface V1_2 failed.");
+ }
+ /* keep this in a store to avoid recycling by garbage collector. */
+ mISupplicantStaIfaceCallbacks.put(ifaceName, callbackV12);
+ return true;
+ }
+
+ private boolean trySetupStaIfaceV1_1(@NonNull String ifaceName,
+ @NonNull ISupplicantStaIface iface) throws RemoteException {
+ if (!isV1_1()) return false;
+
+ /* try newer version fist. */
+ if (trySetupStaIfaceV1_2(ifaceName, iface)) {
+ logd("Newer HAL is found, skip V1_1 remaining init flow.");
+ return true;
+ }
+
+ SupplicantStaIfaceHalCallbackV1_1 callbackV11 =
+ new SupplicantStaIfaceHalCallbackV1_1(ifaceName);
+ if (!registerCallbackV1_1(getStaIfaceMockableV1_1(iface), callbackV11)) {
+ throw new RemoteException("Init StaIface V1_1 failed.");
+ }
+ /* keep this in a store to avoid recycling by garbage collector. */
+ mISupplicantStaIfaceCallbacks.put(ifaceName, callbackV11);
+ return true;
+ }
+
+ /**
+ * Helper function to set up StaIface with different HAL version.
+ *
+ * This helper function would try newer version recursively.
+ * Once the latest version is found, it would register the callback
+ * of the latest version and skip unnecessary older HAL init flow.
+ *
+ * New version callback will be extended from the older one, as a result,
+ * older callback is always created regardless of the latest version.
+ *
+ * Uprev steps:
+ * 1. add new helper function trySetupStaIfaceV1_Y.
+ * 2. call newly added function in trySetupStaIfaceV1_X (X should be Y-1).
+ */
+ private ISupplicantStaIface setupStaIface(@NonNull String ifaceName,
+ @NonNull ISupplicantIface ifaceHwBinder) throws RemoteException {
+ /* Prepare base type for later cast. */
+ ISupplicantStaIface iface = getStaIfaceMockable(ifaceHwBinder);
+
+ /* try newer version first. */
+ if (trySetupStaIfaceV1_1(ifaceName, iface)) {
+ logd("Newer HAL is found, skip V1_0 remaining init flow.");
+ return iface;
+ }
+
+ SupplicantStaIfaceHalCallback callback = new SupplicantStaIfaceHalCallback(ifaceName);
+ if (!registerCallback(iface, callback)) {
+ throw new RemoteException("Init StaIface V1_0 failed.");
+ }
+ /* keep this in a store to avoid recycling by garbage collector. */
+ mISupplicantStaIfaceCallbacks.put(ifaceName, callback);
+ return iface;
+ }
+
/**
* Setup a STA interface for the specified iface name.
*
@@ -333,43 +440,15 @@ public class SupplicantStaIfaceHal {
Log.e(TAG, "setupIface got null iface");
return false;
}
- SupplicantStaIfaceHalCallback callback = new SupplicantStaIfaceHalCallback(ifaceName);
- if (isV1_2()) {
- android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface iface =
- getStaIfaceMockableV1_2(ifaceHwBinder);
-
- SupplicantStaIfaceHalCallbackV1_1 callbackV11 =
- new SupplicantStaIfaceHalCallbackV1_1(ifaceName, callback);
-
- SupplicantStaIfaceHalCallbackV1_2 callbackV12 =
- new SupplicantStaIfaceHalCallbackV1_2(callbackV11);
-
- if (!registerCallbackV1_2(iface, callbackV12)) {
- return false;
- }
- mISupplicantStaIfaces.put(ifaceName, iface);
- mISupplicantStaIfaceCallbacks.put(ifaceName, callbackV11);
- } else if (isV1_1()) {
- android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface iface =
- getStaIfaceMockableV1_1(ifaceHwBinder);
- SupplicantStaIfaceHalCallbackV1_1 callbackV1_1 =
- new SupplicantStaIfaceHalCallbackV1_1(ifaceName, callback);
-
- if (!registerCallbackV1_1(iface, callbackV1_1)) {
- return false;
- }
- mISupplicantStaIfaces.put(ifaceName, iface);
- mISupplicantStaIfaceCallbacks.put(ifaceName, callbackV1_1);
- } else {
- ISupplicantStaIface iface = getStaIfaceMockable(ifaceHwBinder);
-
- if (!registerCallback(iface, callback)) {
- return false;
- }
+ try {
+ ISupplicantStaIface iface = setupStaIface(ifaceName, ifaceHwBinder);
mISupplicantStaIfaces.put(ifaceName, iface);
- mISupplicantStaIfaceCallbacks.put(ifaceName, callback);
+ } catch (RemoteException e) {
+ loge("setup StaIface failed: " + e.toString());
+ return false;
}
+
return true;
}
@@ -732,6 +811,14 @@ public class SupplicantStaIfaceHal {
}
}
+ protected android.hardware.wifi.supplicant.V1_3.ISupplicantStaIface
+ getStaIfaceMockableV1_3(ISupplicantIface iface) {
+ synchronized (mLock) {
+ return android.hardware.wifi.supplicant.V1_3.ISupplicantStaIface
+ .asInterface(iface.asBinder());
+ }
+ }
+
/**
* Uses the IServiceManager to check if the device is running V1_1 of the HAL from the VINTF for
* the device.
@@ -752,6 +839,16 @@ public class SupplicantStaIfaceHal {
android.hardware.wifi.supplicant.V1_2.ISupplicant.kInterfaceName);
}
+ /**
+ * Uses the IServiceManager to check if the device is running V1_3 of the HAL from the VINTF for
+ * the device.
+ * @return true if supported, false otherwise.
+ */
+ private boolean isV1_3() {
+ return checkHalVersionByInterfaceName(
+ android.hardware.wifi.supplicant.V1_3.ISupplicant.kInterfaceName);
+ }
+
private boolean checkHalVersionByInterfaceName(String interfaceName) {
if (interfaceName == null) {
return false;
@@ -882,7 +979,22 @@ public class SupplicantStaIfaceHal {
}
SupplicantStaNetworkHal networkHandle =
checkSupplicantStaNetworkAndLogFailure(ifaceName, "connectToNetwork");
- if (networkHandle == null || !networkHandle.select()) {
+ if (networkHandle == null) {
+ loge("No valid remote network handle for network configuration: "
+ + config.configKey());
+ return false;
+ }
+
+ PmkCacheStoreData pmkData = mPmkCacheEntries.get(config.networkId);
+ if (pmkData != null
+ && pmkData.expirationTimeInSec > mClock.getElapsedSinceBootMillis() / 1000) {
+ logi("Set PMK cache for config id " + config.networkId);
+ if (!networkHandle.setPmkCache(pmkData.data)) {
+ loge("Set PMK cache failed.");
+ }
+ }
+
+ if (!networkHandle.select()) {
loge("Failed to select network configuration: " + config.configKey());
return false;
}
@@ -944,6 +1056,20 @@ public class SupplicantStaIfaceHal {
}
/**
+ * Clean HAL cached data for |networkId| in the framework.
+ *
+ * @param networkId network id of the network to be removed from supplicant.
+ */
+ public void removeNetworkCachedData(int networkId) {
+ synchronized (mLock) {
+ logd("Remove cached HAL data for config id " + networkId);
+ if (mPmkCacheEntries.remove(networkId) != null) {
+ updatePmkCacheExpiration();
+ }
+ }
+ }
+
+ /**
* Remove all networks from supplicant
*
* @param ifaceName Name of the interface.
@@ -1273,6 +1399,23 @@ public class SupplicantStaIfaceHal {
}
}
+ private boolean registerCallbackV1_3(
+ android.hardware.wifi.supplicant.V1_3.ISupplicantStaIface iface,
+ android.hardware.wifi.supplicant.V1_3.ISupplicantStaIfaceCallback callback) {
+ synchronized (mLock) {
+ String methodStr = "registerCallback_1_3";
+
+ if (iface == null) return false;
+ try {
+ SupplicantStatus status = iface.registerCallback_1_3(callback);
+ return checkStatusAndLogFailure(status, methodStr);
+ } catch (RemoteException e) {
+ handleRemoteException(e, methodStr);
+ return false;
+ }
+ }
+ }
+
/**
* @return a list of SupplicantNetworkID ints for all networks controlled by supplicant, returns
* null if the call fails
@@ -2703,10 +2846,11 @@ public class SupplicantStaIfaceHal {
private String mIfaceName;
private SupplicantStaIfaceHalCallback mCallbackV1_0;
- SupplicantStaIfaceHalCallbackV1_1(@NonNull String ifaceName,
- @NonNull SupplicantStaIfaceHalCallback callback) {
+ SupplicantStaIfaceHalCallbackV1_1(@NonNull String ifaceName) {
mIfaceName = ifaceName;
- mCallbackV1_0 = callback;
+ // Create an older callback for function delegation,
+ // and it would cascadingly create older one.
+ mCallbackV1_0 = new SupplicantStaIfaceHalCallback(mIfaceName);
}
@Override
@@ -2814,11 +2958,14 @@ public class SupplicantStaIfaceHal {
private class SupplicantStaIfaceHalCallbackV1_2 extends
android.hardware.wifi.supplicant.V1_2.ISupplicantStaIfaceCallback.Stub {
+ private String mIfaceName;
private SupplicantStaIfaceHalCallbackV1_1 mCallbackV1_1;
- SupplicantStaIfaceHalCallbackV1_2(
- @NonNull SupplicantStaIfaceHalCallbackV1_1 callback) {
- mCallbackV1_1 = callback;
+ SupplicantStaIfaceHalCallbackV1_2(@NonNull String ifaceName) {
+ mIfaceName = ifaceName;
+ // Create an older callback for function delegation,
+ // and it would cascadingly create older one.
+ mCallbackV1_1 = new SupplicantStaIfaceHalCallbackV1_1(mIfaceName);
}
@Override
@@ -2993,6 +3140,189 @@ public class SupplicantStaIfaceHal {
}
}
+ private class SupplicantStaIfaceHalCallbackV1_3 extends
+ android.hardware.wifi.supplicant.V1_3.ISupplicantStaIfaceCallback.Stub {
+ private String mIfaceName;
+ private SupplicantStaIfaceHalCallbackV1_2 mCallbackV12;
+
+ SupplicantStaIfaceHalCallbackV1_3(@NonNull String ifaceName) {
+ mIfaceName = ifaceName;
+ // Create an older callback for function delegation,
+ // and it would cascadingly create older one.
+ mCallbackV12 = new SupplicantStaIfaceHalCallbackV1_2(mIfaceName);
+ }
+
+ @Override
+ public void onNetworkAdded(int id) {
+ mCallbackV12.onNetworkAdded(id);
+ }
+
+ @Override
+ public void onNetworkRemoved(int id) {
+ mCallbackV12.onNetworkRemoved(id);
+ }
+
+ @Override
+ public void onStateChanged(int newState, byte[/* 6 */] bssid, int id,
+ ArrayList<Byte> ssid) {
+ mCallbackV12.onStateChanged(newState, bssid, id, ssid);
+ }
+
+ @Override
+ public void onAnqpQueryDone(byte[/* 6 */] bssid,
+ ISupplicantStaIfaceCallback.AnqpData data,
+ ISupplicantStaIfaceCallback.Hs20AnqpData hs20Data) {
+ mCallbackV12.onAnqpQueryDone(bssid, data, hs20Data);
+ }
+
+ @Override
+ public void onHs20IconQueryDone(byte[/* 6 */] bssid, String fileName,
+ ArrayList<Byte> data) {
+ mCallbackV12.onHs20IconQueryDone(bssid, fileName, data);
+ }
+
+ @Override
+ public void onHs20SubscriptionRemediation(byte[/* 6 */] bssid,
+ byte osuMethod, String url) {
+ mCallbackV12.onHs20SubscriptionRemediation(bssid, osuMethod, url);
+ }
+
+ @Override
+ public void onHs20DeauthImminentNotice(byte[/* 6 */] bssid, int reasonCode,
+ int reAuthDelayInSec, String url) {
+ mCallbackV12.onHs20DeauthImminentNotice(bssid, reasonCode, reAuthDelayInSec, url);
+ }
+
+ @Override
+ public void onDisconnected(byte[/* 6 */] bssid, boolean locallyGenerated,
+ int reasonCode) {
+ mCallbackV12.onDisconnected(bssid, locallyGenerated, reasonCode);
+ }
+
+ @Override
+ public void onAssociationRejected(byte[/* 6 */] bssid, int statusCode,
+ boolean timedOut) {
+ mCallbackV12.onAssociationRejected(bssid, statusCode, timedOut);
+ }
+
+ @Override
+ public void onAuthenticationTimeout(byte[/* 6 */] bssid) {
+ mCallbackV12.onAuthenticationTimeout(bssid);
+ }
+
+ @Override
+ public void onBssidChanged(byte reason, byte[/* 6 */] bssid) {
+ mCallbackV12.onBssidChanged(reason, bssid);
+ }
+
+ @Override
+ public void onEapFailure() {
+ mCallbackV12.onEapFailure();
+ }
+
+ @Override
+ public void onEapFailure_1_1(int code) {
+ mCallbackV12.onEapFailure_1_1(code);
+ }
+
+ @Override
+ public void onWpsEventSuccess() {
+ mCallbackV12.onWpsEventSuccess();
+ }
+
+ @Override
+ public void onWpsEventFail(byte[/* 6 */] bssid, short configError, short errorInd) {
+ mCallbackV12.onWpsEventFail(bssid, configError, errorInd);
+ }
+
+ @Override
+ public void onWpsEventPbcOverlap() {
+ mCallbackV12.onWpsEventPbcOverlap();
+ }
+
+ @Override
+ public void onExtRadioWorkStart(int id) {
+ mCallbackV12.onExtRadioWorkStart(id);
+ }
+
+ @Override
+ public void onExtRadioWorkTimeout(int id) {
+ mCallbackV12.onExtRadioWorkTimeout(id);
+ }
+
+ @Override
+ public void onDppSuccessConfigReceived(ArrayList<Byte> ssid, String password,
+ byte[] psk, int securityAkm) {
+ mCallbackV12.onDppSuccessConfigReceived(
+ ssid, password, psk, securityAkm);
+ }
+
+ @Override
+ public void onDppSuccessConfigSent() {
+ mCallbackV12.onDppSuccessConfigSent();
+ }
+
+ @Override
+ public void onDppProgress(int code) {
+ mCallbackV12.onDppProgress(code);
+ }
+
+ @Override
+ public void onDppFailure(int code) {
+ mCallbackV12.onDppFailure(code);
+ }
+
+ @Override
+ public void onPmkCacheAdded(long expirationTimeInSec, ArrayList<Byte> serializedEntry) {
+ WifiConfiguration curConfig = getCurrentNetworkLocalConfig(mIfaceName);
+ mPmkCacheEntries.put(
+ curConfig.networkId,
+ new PmkCacheStoreData(expirationTimeInSec, serializedEntry));
+ logCallback("onPmkCacheAdded: update pmk cache for config id " + curConfig.networkId);
+
+ updatePmkCacheExpiration();
+ }
+ }
+
+ private void updatePmkCacheExpiration() {
+ synchronized (mLock) {
+ mEventHandler.removeCallbacksAndMessages(PMK_CACHE_EXPIRATION_ALARM_TAG);
+
+ long elapseTimeInSecond = mClock.getElapsedSinceBootMillis() / 1000;
+ long nextUpdateTimeInSecond = Long.MAX_VALUE;
+ logd("Update PMK cache expiration at " + elapseTimeInSecond);
+
+ Iterator<Map.Entry<Integer, PmkCacheStoreData>> iter =
+ mPmkCacheEntries.entrySet().iterator();
+ while (iter.hasNext()) {
+ Map.Entry<Integer, PmkCacheStoreData> entry = iter.next();
+ if (entry.getValue().expirationTimeInSec <= elapseTimeInSecond) {
+ logd("Config " + entry.getKey() + " PMK is expired.");
+ iter.remove();
+ } else if (entry.getValue().expirationTimeInSec <= 0) {
+ logd("Config " + entry.getKey() + " PMK expiration time is invalid.");
+ iter.remove();
+ } else if (nextUpdateTimeInSecond > entry.getValue().expirationTimeInSec) {
+ nextUpdateTimeInSecond = entry.getValue().expirationTimeInSec;
+ }
+ }
+
+ // No need to arrange next update since there is no valid PMK in the cache.
+ if (nextUpdateTimeInSecond == Long.MAX_VALUE) {
+ return;
+ }
+
+ logd("PMK cache next expiration time: " + nextUpdateTimeInSecond);
+ long delayedTimeInMs = (nextUpdateTimeInSecond - elapseTimeInSecond) * 1000;
+ mEventHandler.postDelayed(
+ () -> {
+ updatePmkCacheExpiration();
+ },
+ PMK_CACHE_EXPIRATION_ALARM_TAG,
+ (delayedTimeInMs > 0) ? delayedTimeInMs : 0);
+ }
+ }
+
private static void logd(String s) {
Log.d(TAG, s);
}
diff --git a/service/java/com/android/server/wifi/SupplicantStaNetworkHal.java b/service/java/com/android/server/wifi/SupplicantStaNetworkHal.java
index d68feba4b..5cff0dd07 100644
--- a/service/java/com/android/server/wifi/SupplicantStaNetworkHal.java
+++ b/service/java/com/android/server/wifi/SupplicantStaNetworkHal.java
@@ -3067,6 +3067,32 @@ public class SupplicantStaNetworkHal {
}
}
+ /** See ISupplicantStaNetwork.hal for documentation */
+ public boolean setPmkCache(ArrayList<Byte> serializedEntry) {
+ synchronized (mLock) {
+ final String methodStr = "setPmkCache";
+ if (!checkISupplicantStaNetworkAndLogFailure(methodStr)) return false;
+
+ try {
+ android.hardware.wifi.supplicant.V1_3.ISupplicantStaNetwork
+ iSupplicantStaNetworkV13;
+
+ iSupplicantStaNetworkV13 = getV1_3StaNetwork();
+ if (iSupplicantStaNetworkV13 != null) {
+ SupplicantStatus status = iSupplicantStaNetworkV13
+ .setPmkCache(serializedEntry);
+ return checkStatusAndLogFailure(status, methodStr);
+ } else {
+ Log.e(TAG, "Cannot get ISupplicantStaNetwork V1.3");
+ return false;
+ }
+ } catch (RemoteException e) {
+ handleRemoteException(e, methodStr);
+ return false;
+ }
+ }
+ }
+
/**
* Retrieve the NFC token for this network.
*
diff --git a/service/java/com/android/server/wifi/WifiConnectivityHelper.java b/service/java/com/android/server/wifi/WifiConnectivityHelper.java
index 833c6962f..982feebaf 100644
--- a/service/java/com/android/server/wifi/WifiConnectivityHelper.java
+++ b/service/java/com/android/server/wifi/WifiConnectivityHelper.java
@@ -172,4 +172,13 @@ public class WifiConnectivityHelper {
public void removeNetworkIfCurrent(int networkId) {
mWifiNative.removeNetworkIfCurrent(mWifiNative.getClientInterfaceName(), networkId);
}
+
+ /**
+ * Clean HAL cached data for |networkId| in the framework.
+ *
+ * @param networkId network id of the network to be removed from supplicant.
+ */
+ public void removeNetworkCachedData(int networkId) {
+ mWifiNative.removeNetworkCachedData(networkId);
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java
index ea1268200..b73798c3f 100644
--- a/service/java/com/android/server/wifi/WifiConnectivityManager.java
+++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java
@@ -544,6 +544,7 @@ public class WifiConnectivityManager {
}
@Override
public void onNetworkRemoved(WifiConfiguration config) {
+ mConnectivityHelper.removeNetworkCachedData(config.networkId);
updatePnoScan();
}
@Override
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 2a2c28da9..edc9bc0f5 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -210,7 +210,7 @@ public class WifiInjector {
mHalDeviceManager = new HalDeviceManager(mClock, wifiHandler);
mWifiVendorHal = new WifiVendorHal(mHalDeviceManager, wifiHandler);
mSupplicantStaIfaceHal = new SupplicantStaIfaceHal(
- mContext, mWifiMonitor, mPropertyService, wifiHandler);
+ mContext, mWifiMonitor, mPropertyService, wifiHandler, mClock);
mHostapdHal = new HostapdHal(mContext, wifiHandler);
mWificondControl = new WificondControl(this, mWifiMonitor, mCarrierNetworkConfig,
(AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE),
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index 23e7f0cab..fc7dbfca0 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -2304,6 +2304,15 @@ public class WifiNative {
mSupplicantStaIfaceHal.removeNetworkIfCurrent(ifaceName, networkId);
}
+ /**
+ * Clean HAL cached data for |networkId|.
+ *
+ * @param networkId network id of the network to be removed from supplicant.
+ */
+ public void removeNetworkCachedData(int networkId) {
+ mSupplicantStaIfaceHal.removeNetworkCachedData(networkId);
+ }
+
/*
* DPP
*/
diff --git a/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java b/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java
index a6ed016e4..759935a2b 100644
--- a/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java
@@ -24,6 +24,7 @@ import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
@@ -38,6 +39,7 @@ import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -70,6 +72,7 @@ import android.text.TextUtils;
import androidx.test.filters.SmallTest;
+import com.android.server.wifi.SupplicantStaIfaceHal.PmkCacheStoreData;
import com.android.server.wifi.hotspot2.AnqpEvent;
import com.android.server.wifi.hotspot2.IconEvent;
import com.android.server.wifi.hotspot2.WnmData;
@@ -111,22 +114,27 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
private static final String ICON_FILE_NAME = "blahblah";
private static final int ICON_FILE_SIZE = 72;
private static final String HS20_URL = "http://blahblah";
+ private static final long PMK_CACHE_EXPIRATION_IN_SEC = 1024;
private @Mock IServiceManager mServiceManagerMock;
private @Mock ISupplicant mISupplicantMock;
private android.hardware.wifi.supplicant.V1_1.ISupplicant mISupplicantMockV1_1;
private android.hardware.wifi.supplicant.V1_2.ISupplicant mISupplicantMockV1_2;
+ private android.hardware.wifi.supplicant.V1_3.ISupplicant mISupplicantMockV13;
private @Mock ISupplicantIface mISupplicantIfaceMock;
private @Mock ISupplicantStaIface mISupplicantStaIfaceMock;
private @Mock android.hardware.wifi.supplicant.V1_1.ISupplicantStaIface
mISupplicantStaIfaceMockV1_1;
private @Mock android.hardware.wifi.supplicant.V1_2.ISupplicantStaIface
mISupplicantStaIfaceMockV1_2;
+ private @Mock android.hardware.wifi.supplicant.V1_3.ISupplicantStaIface
+ mISupplicantStaIfaceMockV13;
private @Mock Context mContext;
private @Mock WifiMonitor mWifiMonitor;
private @Mock PropertyService mPropertyService;
private @Mock SupplicantStaNetworkHal mSupplicantStaNetworkMock;
private @Mock WifiNative.SupplicantDeathEventHandler mSupplicantHalDeathHandler;
+ private @Mock Clock mClock;
SupplicantStatus mStatusSuccess;
SupplicantStatus mStatusFailure;
@@ -139,7 +147,10 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
mISupplicantStaIfaceCallbackV1_1;
android.hardware.wifi.supplicant.V1_2.ISupplicantStaIfaceCallback
mISupplicantStaIfaceCallbackV1_2;
+ android.hardware.wifi.supplicant.V1_3.ISupplicantStaIfaceCallback
+ mISupplicantStaIfaceCallbackV13 = null;
private TestLooper mLooper = new TestLooper();
+ private Handler mHandler = null;
private SupplicantStaIfaceHal mDut;
private ArgumentCaptor<IHwBinder.DeathRecipient> mServiceManagerDeathCaptor =
ArgumentCaptor.forClass(IHwBinder.DeathRecipient.class);
@@ -154,7 +165,8 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
private class SupplicantStaIfaceHalSpy extends SupplicantStaIfaceHal {
SupplicantStaIfaceHalSpy() {
- super(mContext, mWifiMonitor, mPropertyService, new Handler(mLooper.getLooper()));
+ super(mContext, mWifiMonitor, mPropertyService,
+ mHandler, mClock);
}
@Override
@@ -191,6 +203,14 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
}
@Override
+ protected android.hardware.wifi.supplicant.V1_3.ISupplicantStaIface
+ getStaIfaceMockableV1_3(ISupplicantIface iface) {
+ return (mISupplicantMockV13 != null)
+ ? mISupplicantStaIfaceMockV13
+ : null;
+ }
+
+ @Override
protected SupplicantStaNetworkHal getStaNetworkMockable(
@NonNull String ifaceName,
ISupplicantStaNetwork iSupplicantStaNetwork) {
@@ -211,7 +231,6 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
mIfaceInfoList.add(mStaIface0);
mIfaceInfoList.add(mStaIface1);
mIfaceInfoList.add(mP2pIface);
-
when(mServiceManagerMock.getTransport(anyString(), anyString()))
.thenReturn(IServiceManager.Transport.EMPTY);
when(mServiceManagerMock.linkToDeath(any(IHwBinder.DeathRecipient.class),
@@ -220,6 +239,7 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
any(IServiceNotification.Stub.class))).thenReturn(true);
when(mISupplicantMock.linkToDeath(any(IHwBinder.DeathRecipient.class),
anyLong())).thenReturn(true);
+ mHandler = spy(new Handler(mLooper.getLooper()));
mDut = new SupplicantStaIfaceHalSpy();
}
@@ -274,10 +294,7 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
*/
@Test
public void testInitialize_successV1_1() throws Exception {
- when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_1.ISupplicant
- .kInterfaceName), anyString()))
- .thenReturn(IServiceManager.Transport.HWBINDER);
- mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ setupMocksForHalV1_1();
executeAndValidateInitializationSequenceV1_1(false, false);
}
@@ -287,27 +304,27 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
*/
@Test
public void testInitialize_successV1_2() throws Exception {
- when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_2.ISupplicant
- .kInterfaceName), anyString()))
- .thenReturn(IServiceManager.Transport.HWBINDER);
- mISupplicantMockV1_2 = mock(android.hardware.wifi.supplicant.V1_2.ISupplicant.class);
- when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_1.ISupplicant
- .kInterfaceName), anyString()))
- .thenReturn(IServiceManager.Transport.HWBINDER);
- mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ setupMocksForHalV1_2();
executeAndValidateInitializationSequenceV1_2();
}
/**
+ * Sunny day scenario for SupplicantStaIfaceHal initialization
+ * Asserts successful initialization
+ */
+ @Test
+ public void testInitialize_successV1_3() throws Exception {
+ setupMocksForHalV1_3();
+ executeAndValidateInitializationSequenceV1_3();
+ }
+
+ /**
* Tests the initialization flow, with a RemoteException occurring when 'getInterface' is called
* Ensures initialization fails.
*/
@Test
public void testInitialize_remoteExceptionFailureV1_1() throws Exception {
- when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_1.ISupplicant
- .kInterfaceName), anyString()))
- .thenReturn(IServiceManager.Transport.HWBINDER);
- mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ setupMocksForHalV1_1();
executeAndValidateInitializationSequenceV1_1(true, false);
}
@@ -317,10 +334,7 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
*/
@Test
public void testInitialize_nullInterfaceFailureV1_1() throws Exception {
- when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_1.ISupplicant
- .kInterfaceName), anyString()))
- .thenReturn(IServiceManager.Transport.HWBINDER);
- mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ setupMocksForHalV1_1();
executeAndValidateInitializationSequenceV1_1(false, true);
}
@@ -347,10 +361,7 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
*/
@Test
public void testDuplicateSetupIfaceV1_1_Fails() throws Exception {
- when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_1.ISupplicant
- .kInterfaceName), anyString()))
- .thenReturn(IServiceManager.Transport.HWBINDER);
- mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ setupMocksForHalV1_1();
executeAndValidateInitializationSequenceV1_1(false, false);
// Trying setting up the wlan0 interface again & ensure it fails.
@@ -1459,10 +1470,7 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
*/
@Test
public void testStartDaemonV1_1() throws Exception {
- when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_1.ISupplicant
- .kInterfaceName), anyString()))
- .thenReturn(IServiceManager.Transport.HWBINDER);
- mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ setupMocksForHalV1_1();
executeAndValidateInitializationSequenceV1_1(false, false);
assertTrue(mDut.startDaemon());
@@ -1485,10 +1493,7 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
*/
@Test
public void testTerminateV1_1() throws Exception {
- when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_1.ISupplicant
- .kInterfaceName), anyString()))
- .thenReturn(IServiceManager.Transport.HWBINDER);
- mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ setupMocksForHalV1_1();
executeAndValidateInitializationSequenceV1_1(false, false);
mDut.terminate();
@@ -1514,10 +1519,7 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
*/
@Test
public void testGetKeyMgmtCapabilitiesOldHal() throws Exception {
- when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_1.ISupplicant
- .kInterfaceName), anyString()))
- .thenReturn(IServiceManager.Transport.HWBINDER);
- mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ setupMocksForHalV1_1();
executeAndValidateInitializationSequenceV1_1(false, false);
@@ -1529,14 +1531,7 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
*/
@Test
public void testGetKeyMgmtCapabilitiesWpa3Sae() throws Exception {
- when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_2.ISupplicant
- .kInterfaceName), anyString()))
- .thenReturn(IServiceManager.Transport.HWBINDER);
- mISupplicantMockV1_2 = mock(android.hardware.wifi.supplicant.V1_2.ISupplicant.class);
- when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_1.ISupplicant
- .kInterfaceName), anyString()))
- .thenReturn(IServiceManager.Transport.HWBINDER);
- mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ setupMocksForHalV1_2();
executeAndValidateInitializationSequenceV1_2();
@@ -1554,14 +1549,7 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
*/
@Test
public void testGetKeyMgmtCapabilitiesWpa3SuiteB() throws Exception {
- when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_2.ISupplicant
- .kInterfaceName), anyString()))
- .thenReturn(IServiceManager.Transport.HWBINDER);
- mISupplicantMockV1_2 = mock(android.hardware.wifi.supplicant.V1_2.ISupplicant.class);
- when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_1.ISupplicant
- .kInterfaceName), anyString()))
- .thenReturn(IServiceManager.Transport.HWBINDER);
- mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ setupMocksForHalV1_2();
executeAndValidateInitializationSequenceV1_2();
@@ -1580,14 +1568,7 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
*/
@Test
public void testGetKeyMgmtCapabilitiesOwe() throws Exception {
- when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_2.ISupplicant
- .kInterfaceName), anyString()))
- .thenReturn(IServiceManager.Transport.HWBINDER);
- mISupplicantMockV1_2 = mock(android.hardware.wifi.supplicant.V1_2.ISupplicant.class);
- when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_1.ISupplicant
- .kInterfaceName), anyString()))
- .thenReturn(IServiceManager.Transport.HWBINDER);
- mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ setupMocksForHalV1_2();
executeAndValidateInitializationSequenceV1_2();
@@ -1605,14 +1586,7 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
*/
@Test
public void testGetKeyMgmtCapabilitiesOweAndSae() throws Exception {
- when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_2.ISupplicant
- .kInterfaceName), anyString()))
- .thenReturn(IServiceManager.Transport.HWBINDER);
- mISupplicantMockV1_2 = mock(android.hardware.wifi.supplicant.V1_2.ISupplicant.class);
- when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_1.ISupplicant
- .kInterfaceName), anyString()))
- .thenReturn(IServiceManager.Transport.HWBINDER);
- mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ setupMocksForHalV1_2();
executeAndValidateInitializationSequenceV1_2();
@@ -1632,14 +1606,7 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
*/
@Test
public void testGetKeyMgmtCapabilitiesDpp() throws Exception {
- when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_2.ISupplicant
- .kInterfaceName), anyString()))
- .thenReturn(IServiceManager.Transport.HWBINDER);
- mISupplicantMockV1_2 = mock(android.hardware.wifi.supplicant.V1_2.ISupplicant.class);
- when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_1.ISupplicant
- .kInterfaceName), anyString()))
- .thenReturn(IServiceManager.Transport.HWBINDER);
- mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ setupMocksForHalV1_2();
executeAndValidateInitializationSequenceV1_2();
@@ -1666,6 +1633,94 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
assertFalse(mDut.startDppEnrolleeInitiator(WLAN0_IFACE_NAME, 3, 14));
}
+ /**
+ * Test adding PMK cache entry to the supplicant.
+ */
+ @Test
+ public void testSetPmkSuccess() throws Exception {
+ int testFrameworkNetworkId = 9;
+ long testStartSeconds = PMK_CACHE_EXPIRATION_IN_SEC / 2;
+ WifiConfiguration config = new WifiConfiguration();
+ config.networkId = testFrameworkNetworkId;
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ PmkCacheStoreData pmkCacheData =
+ new PmkCacheStoreData(PMK_CACHE_EXPIRATION_IN_SEC, new ArrayList<Byte>());
+ mDut.mPmkCacheEntries.put(testFrameworkNetworkId, pmkCacheData);
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(testStartSeconds * 1000L);
+
+ setupMocksForHalV1_3();
+ setupMocksForPmkCache();
+ setupMocksForConnectSequence(false);
+
+ executeAndValidateInitializationSequenceV1_3();
+ assertTrue(mDut.connectToNetwork(WLAN0_IFACE_NAME, config));
+
+ verify(mSupplicantStaNetworkMock).setPmkCache(eq(pmkCacheData.data));
+ verify(mISupplicantStaIfaceCallbackV13)
+ .onPmkCacheAdded(eq(PMK_CACHE_EXPIRATION_IN_SEC), eq(pmkCacheData.data));
+ // there is only one cache entry, the next expiration alarm should be the same as
+ // its expiration time.
+ verify(mHandler).postDelayed(
+ /* private listener */ any(),
+ eq(SupplicantStaIfaceHal.PMK_CACHE_EXPIRATION_ALARM_TAG),
+ eq((PMK_CACHE_EXPIRATION_IN_SEC - testStartSeconds) * 1000));
+ }
+
+ /**
+ * Test adding PMK cache entry is not called if there is no
+ * valid PMK cache for a corresponding configuratoin.
+ */
+ @Test
+ public void testAddPmkEntryNotCalledIfNoPmkCache() throws Exception {
+ int testFrameworkNetworkId = 9;
+ long testStartSeconds = PMK_CACHE_EXPIRATION_IN_SEC / 2;
+ WifiConfiguration config = new WifiConfiguration();
+ config.networkId = testFrameworkNetworkId;
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(testStartSeconds * 1000L);
+
+ setupMocksForHalV1_3();
+ setupMocksForPmkCache();
+ setupMocksForConnectSequence(false);
+ executeAndValidateInitializationSequenceV1_3();
+ assertTrue(mDut.connectToNetwork(WLAN0_IFACE_NAME, config));
+
+ verify(mSupplicantStaNetworkMock, never()).setPmkCache(any(ArrayList.class));
+ verify(mISupplicantStaIfaceCallbackV13, never()).onPmkCacheAdded(
+ anyLong(), any(ArrayList.class));
+ verify(mHandler, never()).postDelayed(
+ /* private listener */ any(),
+ eq(SupplicantStaIfaceHal.PMK_CACHE_EXPIRATION_ALARM_TAG),
+ anyLong());
+ }
+
+ /**
+ * Test adding PMK cache entry returns faliure if HAL version is less than 1_3
+ */
+ @Test
+ public void testAddPmkEntryIsOmittedWithOldHal() throws Exception {
+ int testFrameworkNetworkId = 9;
+ long testStartSeconds = PMK_CACHE_EXPIRATION_IN_SEC / 2;
+ WifiConfiguration config = new WifiConfiguration();
+ config.networkId = testFrameworkNetworkId;
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ PmkCacheStoreData pmkCacheData =
+ new PmkCacheStoreData(PMK_CACHE_EXPIRATION_IN_SEC, new ArrayList<Byte>());
+ mDut.mPmkCacheEntries.put(testFrameworkNetworkId, pmkCacheData);
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(testStartSeconds * 1000L);
+
+ setupMocksForConnectSequence(false);
+ executeAndValidateInitializationSequence();
+ assertTrue(mDut.connectToNetwork(WLAN0_IFACE_NAME, config));
+
+ verify(mSupplicantStaNetworkMock).setPmkCache(eq(pmkCacheData.data));
+ assertNull(mISupplicantStaIfaceCallbackV13);
+ verify(mHandler, never()).postDelayed(
+ /* private listener */ any(),
+ eq(SupplicantStaIfaceHal.PMK_CACHE_EXPIRATION_ALARM_TAG),
+ anyLong());
+ }
+
private WifiConfiguration createTestWifiConfiguration() {
WifiConfiguration config = new WifiConfiguration();
config.networkId = SUPPLICANT_NETWORK_ID;
@@ -1917,6 +1972,60 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
// any(ISupplicant.getInterfaceCallback.class));
}
+ /**
+ * Calls.initialize(), mocking various call back answers and verifying flow, asserting for the
+ * expected result. Verifies if ISupplicantStaIface manager is initialized or reset.
+ * Each of the arguments will cause a different failure mode when set true.
+ */
+ private void executeAndValidateInitializationSequenceV1_3()
+ throws Exception {
+ // Setup callback mock answers
+ doAnswer(new GetAddInterfaceAnswerV1_3(false))
+ .when(mISupplicantMockV1_1).addInterface(any(ISupplicant.IfaceInfo.class),
+ any(android.hardware.wifi.supplicant.V1_1.ISupplicant
+ .addInterfaceCallback.class));
+
+ /** Callback registration */
+ doAnswer(new MockAnswerUtil.AnswerWithArguments() {
+ public SupplicantStatus answer(
+ android.hardware.wifi.supplicant.V1_3.ISupplicantStaIfaceCallback cb)
+ throws RemoteException {
+ mISupplicantStaIfaceCallbackV13 = spy(cb);
+ return mStatusSuccess;
+ }
+ }).when(mISupplicantStaIfaceMockV13)
+ .registerCallback_1_3(
+ any(android.hardware.wifi.supplicant.V1_3.ISupplicantStaIfaceCallback
+ .class));
+
+ mInOrder = inOrder(mServiceManagerMock, mISupplicantMock, mISupplicantMockV1_1,
+ mISupplicantStaIfaceMockV13, mWifiMonitor);
+ // Initialize SupplicantStaIfaceHal, should call serviceManager.registerForNotifications
+ assertTrue(mDut.initialize());
+ // verify: service manager initialization sequence
+ mInOrder.verify(mServiceManagerMock).linkToDeath(mServiceManagerDeathCaptor.capture(),
+ anyLong());
+ mInOrder.verify(mServiceManagerMock).registerForNotifications(
+ eq(ISupplicant.kInterfaceName), eq(""), mServiceNotificationCaptor.capture());
+ // act: cause the onRegistration(...) callback to execute
+ mServiceNotificationCaptor.getValue().onRegistration(ISupplicant.kInterfaceName, "", true);
+
+ assertTrue(mDut.isInitializationComplete());
+ assertTrue(mDut.setupIface(WLAN0_IFACE_NAME));
+ mInOrder.verify(mISupplicantMock).linkToDeath(mSupplicantDeathCaptor.capture(),
+ anyLong());
+ // verify: addInterface is called
+ mInOrder.verify(mISupplicantMockV1_1)
+ .addInterface(any(ISupplicant.IfaceInfo.class),
+ any(android.hardware.wifi.supplicant.V1_1.ISupplicant
+ .addInterfaceCallback.class));
+
+ mInOrder.verify(mISupplicantStaIfaceMockV13)
+ .registerCallback_1_3(
+ any(android.hardware.wifi.supplicant.V1_3.ISupplicantStaIfaceCallback
+ .class));
+ }
+
private SupplicantStatus createSupplicantStatus(int code) {
SupplicantStatus status = new SupplicantStatus();
status.code = code;
@@ -1997,6 +2106,24 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
}
}
+ private class GetAddInterfaceAnswerV1_3 extends MockAnswerUtil.AnswerWithArguments {
+ boolean mGetNullInterface;
+
+ GetAddInterfaceAnswerV1_3(boolean getNullInterface) {
+ mGetNullInterface = getNullInterface;
+ }
+
+ public void answer(ISupplicant.IfaceInfo iface,
+ android.hardware.wifi.supplicant.V1_3.ISupplicant
+ .addInterfaceCallback cb) {
+ if (mGetNullInterface) {
+ cb.onValues(mStatusSuccess, null);
+ } else {
+ cb.onValues(mStatusSuccess, mISupplicantIfaceMock);
+ }
+ }
+ }
+
/**
* Setup mocks for connect sequence.
*/
@@ -2125,4 +2252,65 @@ public class SupplicantStaIfaceHalTest extends WifiBaseTest {
verify(mISupplicantStaIfaceMock).reassociate();
}
}
+
+ /**
+ * Helper function to set up Hal cascadingly.
+ */
+ private void setupMocksForHalV1_1() throws Exception {
+ // V1_0 is set up by default, no need to do it.
+ when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_1.ISupplicant
+ .kInterfaceName), anyString()))
+ .thenReturn(IServiceManager.Transport.HWBINDER);
+ mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ }
+
+ private void setupMocksForHalV1_2() throws Exception {
+ setupMocksForHalV1_1();
+ when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_2.ISupplicant
+ .kInterfaceName), anyString()))
+ .thenReturn(IServiceManager.Transport.HWBINDER);
+ mISupplicantMockV1_2 = mock(android.hardware.wifi.supplicant.V1_2.ISupplicant.class);
+ }
+
+ private void setupMocksForHalV1_3() throws Exception {
+ setupMocksForHalV1_2();
+ when(mServiceManagerMock.getTransport(eq(android.hardware.wifi.supplicant.V1_3.ISupplicant
+ .kInterfaceName), anyString()))
+ .thenReturn(IServiceManager.Transport.HWBINDER);
+ mISupplicantMockV13 = mock(android.hardware.wifi.supplicant.V1_3.ISupplicant.class);
+ }
+
+ private void setupMocksForPmkCache() throws Exception {
+ /** Callback registration */
+ doAnswer(new MockAnswerUtil.AnswerWithArguments() {
+ public SupplicantStatus answer(
+ android.hardware.wifi.supplicant.V1_3.ISupplicantStaIfaceCallback cb)
+ throws RemoteException {
+ mISupplicantStaIfaceCallbackV13 = cb;
+ return mStatusSuccess;
+ }
+ }).when(mISupplicantStaIfaceMockV13)
+ .registerCallback_1_3(
+ any(android.hardware.wifi.supplicant.V1_3.ISupplicantStaIfaceCallback
+ .class));
+
+ doAnswer(new MockAnswerUtil.AnswerWithArguments() {
+ public boolean answer(WifiConfiguration config, Map<String, String> networkExtra)
+ throws Exception {
+ config.networkId = SUPPLICANT_NETWORK_ID;
+ return true;
+ }
+ }).when(mSupplicantStaNetworkMock)
+ .loadWifiConfiguration(any(WifiConfiguration.class), any(Map.class));
+
+ doAnswer(new MockAnswerUtil.AnswerWithArguments() {
+ public boolean answer(ArrayList<Byte> serializedData)
+ throws Exception {
+ mISupplicantStaIfaceCallbackV13.onPmkCacheAdded(
+ PMK_CACHE_EXPIRATION_IN_SEC, serializedData);
+ return true;
+ }
+ }).when(mSupplicantStaNetworkMock)
+ .setPmkCache(any(ArrayList.class));
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkHalTest.java b/tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkHalTest.java
index 302ac2183..101331868 100644
--- a/tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkHalTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/SupplicantStaNetworkHalTest.java
@@ -19,6 +19,7 @@ import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Matchers.eq;
@@ -972,6 +973,35 @@ public class SupplicantStaNetworkHalTest extends WifiBaseTest {
assertEquals(ANONYMOUS_IDENTITY, mSupplicantNetwork.fetchEapAnonymousIdentity());
}
+ /** Verifies that setPmkCache can set PMK cache
+ *
+ */
+ public void testSetPmkCache() {
+ WifiConfiguration config = WifiConfigurationTestUtil.createEapNetwork();
+ config.enterpriseConfig =
+ WifiConfigurationTestUtil.createTLSWifiEnterpriseConfigWithNonePhase2();
+ assertTrue(mSupplicantNetwork.saveWifiConfiguration(config));
+
+ ArrayList<Byte> serializedData = new ArrayList<>();
+ assertTrue(mSupplicantNetwork.setPmkCache(serializedData));
+ assertEquals(serializedData, mSupplicantVariables.serializedPmkCache);
+ }
+
+ /**
+ * Tests PMK cache is not set on HAL v1.2 or lower
+ */
+ @Test
+ public void testSetPmkCacheHal1_2OrLower() throws Exception {
+ WifiConfiguration config = WifiConfigurationTestUtil.createEapNetwork();
+ config.enterpriseConfig =
+ WifiConfigurationTestUtil.createTLSWifiEnterpriseConfigWithNonePhase2();
+ assertTrue(mSupplicantNetwork.saveWifiConfiguration(config));
+
+ ArrayList<Byte> serializedData = new ArrayList<>();
+ assertFalse(mSupplicantNetwork.setPmkCache(serializedData));
+ assertNull(mSupplicantVariables.serializedPmkCache);
+ }
+
/**
* Sets up the HIDL interface mock with all the setters/getter values.
* Note: This only sets up the mock to return success on all methods.
@@ -1545,6 +1575,14 @@ public class SupplicantStaNetworkHalTest extends WifiBaseTest {
.getOcsp(any(android.hardware.wifi.supplicant.V1_3.ISupplicantStaNetwork
.getOcspCallback.class));
+ /** PMK cache */
+ doAnswer(new AnswerWithArguments() {
+ public SupplicantStatus answer(ArrayList<Byte> serializedData) throws RemoteException {
+ mSupplicantVariables.serializedPmkCache = serializedData;
+ return mStatusSuccess;
+ }
+ }).when(mISupplicantStaNetworkV13).setPmkCache(any(ArrayList.class));
+
}
private SupplicantStatus createSupplicantStatus(int code) {
@@ -1609,5 +1647,6 @@ public class SupplicantStaNetworkHalTest extends WifiBaseTest {
public String eapDomainSuffixMatch;
public boolean eapProactiveKeyCaching;
public int ocsp;
+ public ArrayList<Byte> serializedPmkCache;
}
}