am dcf7577b: am d32033b8: am 8b41627f: Fix a race in WifiNative objects
* commit 'dcf7577b0243059412c5508c79cbbbf6734cb555':
Fix a race in WifiNative objects
diff --git a/service/Android.mk b/service/Android.mk
old mode 100755
new mode 100644
index 971c983..f325782
--- a/service/Android.mk
+++ b/service/Android.mk
@@ -16,7 +16,7 @@
ifneq ($(TARGET_BUILD_PDK), true)
-# Make HAL stub library
+# Make HAL stub library 1
# ============================================================
include $(CLEAR_VARS)
@@ -36,6 +36,27 @@
include $(BUILD_STATIC_LIBRARY)
+# Make HAL stub library 2
+# ============================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_REQUIRED_MODULES :=
+
+LOCAL_CFLAGS += -Wno-unused-parameter
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/jni \
+ external/libnl-headers \
+ $(call include-path-for, libhardware_legacy)/hardware_legacy
+
+LOCAL_SRC_FILES := \
+ lib/wifi_hal_stub.cpp
+
+LOCAL_MODULE := libwifi-hal-stub
+
+include $(BUILD_STATIC_LIBRARY)
+
# set correct hal library path
# ============================================================
LIB_WIFI_HAL := libwifi-hal
@@ -43,9 +64,7 @@
ifeq ($(BOARD_WLAN_DEVICE), bcmdhd)
LIB_WIFI_HAL := libwifi-hal-bcm
else ifeq ($(BOARD_WLAN_DEVICE), qcwcn)
- # this is commented because none of the nexus devices
- # that sport Qualcomm's wifi have support for HAL
- # LIB_WIFI_HAL := libwifi-hal-qcom
+ LIB_WIFI_HAL := libwifi-hal-qcom
else ifeq ($(BOARD_WLAN_DEVICE), mrvl)
# this is commented because none of the nexus devices
# that sport Marvell's wifi have support for HAL
@@ -55,35 +74,6 @@
LIB_WIFI_HAL := libwifi-hal-mt66xx
endif
-# Build the HalUtil
-# ============================================================
-
-include $(CLEAR_VARS)
-
-LOCAL_REQUIRED_MODULES := libandroid_runtime libhardware_legacy
-
-LOCAL_CFLAGS += -Wno-unused-parameter
-
-LOCAL_C_INCLUDES += \
- $(call include-path-for, libhardware)/hardware \
- $(call include-path-for, libhardware_legacy)/hardware_legacy \
- libcore/include
-
-LOCAL_SHARED_LIBRARIES += \
- libcutils \
- libnl \
- libandroid_runtime \
- libutils
-
-LOCAL_STATIC_LIBRARIES += $(LIB_WIFI_HAL)
-
-LOCAL_SRC_FILES := \
- tools/halutil/halutil.cpp
-
-LOCAL_MODULE := halutil
-
-include $(BUILD_EXECUTABLE)
-
# Make the JNI part
# ============================================================
include $(CLEAR_VARS)
@@ -105,8 +95,10 @@
libhardware \
libhardware_legacy \
libandroid_runtime \
- libnl
+ libnl \
+ libdl
+LOCAL_STATIC_LIBRARIES += libwifi-hal-stub
LOCAL_STATIC_LIBRARIES += $(LIB_WIFI_HAL)
LOCAL_SRC_FILES := \
@@ -129,7 +121,7 @@
LOCAL_JNI_SHARED_LIBRARIES := libandroid_runtime
LOCAL_JAVA_LIBRARIES := bouncycastle conscrypt services
-LOCAL_STATIC_JAVA_LIBRARIES := ksoap2
+LOCAL_STATIC_JAVA_LIBRARIES := ksoap2 android-support-v4
LOCAL_REQUIRED_MODULES := services
LOCAL_MODULE_TAGS :=
LOCAL_MODULE := wifi-service
diff --git a/service/java/com/android/server/wifi/ConfigurationMap.java b/service/java/com/android/server/wifi/ConfigurationMap.java
new file mode 100644
index 0000000..0fb56ea
--- /dev/null
+++ b/service/java/com/android/server/wifi/ConfigurationMap.java
@@ -0,0 +1,146 @@
+package com.android.server.wifi;
+
+import android.net.wifi.WifiConfiguration;
+import android.util.Log;
+
+import com.android.server.wifi.hotspot2.Utils;
+import com.android.server.wifi.hotspot2.pps.HomeSP;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+public class ConfigurationMap {
+ private final Map<Integer, WifiConfiguration> mPerID = new HashMap<>();
+ private final Map<Integer, WifiConfiguration> mPerConfigKey = new HashMap<>();
+ private final Map<String, Integer> mPerFQDN = new HashMap<>();
+
+ // RW methods:
+ public WifiConfiguration put(int netid, WifiConfiguration config) {
+ WifiConfiguration current = mPerID.put(netid, config);
+ mPerConfigKey.put(config.configKey().hashCode(), config); // This is ridiculous...
+ if (config.FQDN != null && config.FQDN.length() > 0) {
+ mPerFQDN.put(config.FQDN, netid);
+ }
+ return current;
+ }
+
+ public void populatePasspointData(Collection<HomeSP> homeSPs, WifiNative wifiNative) {
+ mPerFQDN.clear();
+
+ for (HomeSP homeSp : homeSPs) {
+ String fqdn = homeSp.getFQDN();
+ Log.d(WifiConfigStore.TAG, "Looking for " + fqdn);
+ for (WifiConfiguration config : mPerID.values()) {
+ Log.d(WifiConfigStore.TAG, "Testing " + config.SSID);
+
+ String id_str = Utils.unquote(wifiNative.getNetworkVariable(
+ config.networkId, WifiConfigStore.idStringVarName));
+ if (id_str != null && id_str.equals(fqdn) && config.enterpriseConfig != null) {
+ Log.d(WifiConfigStore.TAG, "Matched " + id_str + " with " + config.networkId);
+ config.FQDN = fqdn;
+ config.providerFriendlyName = homeSp.getFriendlyName();
+
+ HashSet<Long> roamingConsortiumIds = homeSp.getRoamingConsortiums();
+ config.roamingConsortiumIds = new long[roamingConsortiumIds.size()];
+ int i = 0;
+ for (long id : roamingConsortiumIds) {
+ config.roamingConsortiumIds[i] = id;
+ i++;
+ }
+ IMSIParameter imsiParameter = homeSp.getCredential().getImsi();
+ config.enterpriseConfig.setPlmn(
+ imsiParameter != null ? imsiParameter.toString() : null);
+ config.enterpriseConfig.setRealm(homeSp.getCredential().getRealm());
+ mPerFQDN.put(fqdn, config.networkId);
+ }
+ }
+ }
+
+ Log.d(WifiConfigStore.TAG, "loaded " + mPerFQDN.size() + " passpoint configs");
+ }
+
+ public WifiConfiguration remove(int netID) {
+ WifiConfiguration config = mPerID.remove(netID);
+ if (config == null) {
+ return null;
+ }
+ mPerConfigKey.remove(config.configKey().hashCode());
+
+ Iterator<Map.Entry<String, Integer>> entries = mPerFQDN.entrySet().iterator();
+ while (entries.hasNext()) {
+ if (entries.next().getValue() == netID) {
+ entries.remove();
+ break;
+ }
+ }
+ return config;
+ }
+
+ public void clear() {
+ mPerID.clear();
+ mPerConfigKey.clear();
+ mPerFQDN.clear();
+ }
+
+ // RO methods:
+ public WifiConfiguration get(int netid) {
+ return mPerID.get(netid);
+ }
+
+ public int size() {
+ return mPerID.size();
+ }
+
+ public boolean isEmpty() {
+ return mPerID.size() == 0;
+ }
+
+ public WifiConfiguration getByFQDN(String fqdn) {
+ Integer id = mPerFQDN.get(fqdn);
+ return id != null ? mPerID.get(id) : null;
+ }
+
+ public WifiConfiguration getByConfigKey(String key) {
+ if (key == null) {
+ return null;
+ }
+ for (WifiConfiguration config : mPerID.values()) {
+ if (config.configKey().equals(key)) {
+ return config;
+ }
+ }
+ return null;
+ }
+
+ public WifiConfiguration getByConfigKeyID(int id) {
+ return mPerConfigKey.get(id);
+ }
+
+ public Collection<WifiConfiguration> getEnabledNetworks() {
+ List<WifiConfiguration> list = new ArrayList<>();
+ for (WifiConfiguration config : mPerID.values()) {
+ if (config.status != WifiConfiguration.Status.DISABLED) {
+ list.add(config);
+ }
+ }
+ return list;
+ }
+
+ public WifiConfiguration getEphemeral(String ssid) {
+ for (WifiConfiguration config : mPerID.values()) {
+ if (ssid.equals(config.SSID) && config.ephemeral) {
+ return config;
+ }
+ }
+ return null;
+ }
+
+ public Collection<WifiConfiguration> values() {
+ return mPerID.values();
+ }
+}
diff --git a/service/java/com/android/server/wifi/IMSIParameter.java b/service/java/com/android/server/wifi/IMSIParameter.java
new file mode 100644
index 0000000..deea870
--- /dev/null
+++ b/service/java/com/android/server/wifi/IMSIParameter.java
@@ -0,0 +1,102 @@
+package com.android.server.wifi;
+
+import java.io.IOException;
+
+public class IMSIParameter {
+ private final String mImsi;
+ private final boolean mPrefix;
+
+ public IMSIParameter(String imsi, boolean prefix) {
+ mImsi = imsi;
+ mPrefix = prefix;
+ }
+
+ public IMSIParameter(String imsi) throws IOException {
+ if (imsi == null || imsi.length() == 0) {
+ throw new IOException("Bad IMSI: '" + imsi + "'");
+ }
+
+ int nonDigit;
+ char stopChar = '\0';
+ for (nonDigit = 0; nonDigit < imsi.length(); nonDigit++) {
+ stopChar = imsi.charAt(nonDigit);
+ if (stopChar < '0' || stopChar > '9') {
+ break;
+ }
+ }
+
+ if (nonDigit == imsi.length()) {
+ mImsi = imsi;
+ mPrefix = false;
+ }
+ else if (nonDigit == imsi.length()-1 && stopChar == '*') {
+ mImsi = imsi.substring(0, nonDigit);
+ mPrefix = true;
+ }
+ else {
+ throw new IOException("Bad IMSI: '" + imsi + "'");
+ }
+ }
+
+ public boolean matches(String fullIMSI) {
+ if (mPrefix) {
+ return mImsi.regionMatches(false, 0, fullIMSI, 0, mImsi.length());
+ }
+ else {
+ return mImsi.equals(fullIMSI);
+ }
+ }
+
+ public boolean matchesMccMnc(String mccMnc) {
+ if (mPrefix) {
+ // For a prefix match, the entire prefix must match the mcc+mnc
+ return mImsi.regionMatches(false, 0, mccMnc, 0, mImsi.length());
+ }
+ else {
+ // For regular match, the entire length of mcc+mnc must match this IMSI
+ return mImsi.regionMatches(false, 0, mccMnc, 0, mccMnc.length());
+ }
+ }
+
+ public boolean isPrefix() {
+ return mPrefix;
+ }
+
+ public String getImsi() {
+ return mImsi;
+ }
+
+ public int prefixLength() {
+ return mImsi.length();
+ }
+
+ @Override
+ public boolean equals(Object thatObject) {
+ if (this == thatObject) {
+ return true;
+ }
+ else if (thatObject == null || getClass() != thatObject.getClass()) {
+ return false;
+ }
+
+ IMSIParameter that = (IMSIParameter) thatObject;
+ return mPrefix == that.mPrefix && mImsi.equals(that.mImsi);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = mImsi != null ? mImsi.hashCode() : 0;
+ result = 31 * result + (mPrefix ? 1 : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ if (mPrefix) {
+ return mImsi + '*';
+ }
+ else {
+ return mImsi;
+ }
+ }
+}
diff --git a/service/java/com/android/server/wifi/RttService.java b/service/java/com/android/server/wifi/RttService.java
index c447e28..cc7f549 100644
--- a/service/java/com/android/server/wifi/RttService.java
+++ b/service/java/com/android/server/wifi/RttService.java
@@ -28,8 +28,9 @@
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
+import android.Manifest;
-class RttService extends SystemService {
+public final class RttService extends SystemService {
public static final boolean DBG = true;
@@ -144,6 +145,16 @@
Integer key;
ClientInfo ci;
RttManager.RttParams[] params;
+
+ @Override
+ public String toString() {
+ String str = getClass().getName() + "@" + Integer.toHexString(hashCode());
+ if(this.key != null) {
+ return str + " key: " + this.key;
+ } else {
+ return str + " key: " + " , null";
+ }
+ }
}
private class ClientInfo {
@@ -198,12 +209,14 @@
}
void reportAborted(int key) {
- mChannel.sendMessage(RttManager.CMD_OP_ABORTED, key);
- mRequests.remove(key);
+ mChannel.sendMessage(RttManager.CMD_OP_ABORTED, 0, key);
+ //All Queued RTT request will be cleaned
+ cleanup();
}
void cleanup() {
mRequests.clear();
+ mRequestQueue.clear();
}
}
@@ -271,20 +284,32 @@
transitionTo(mRequestPendingState);
break;
case RttManager.CMD_OP_START_RANGING: {
- RttManager.ParcelableRttParams params =
- (RttManager.ParcelableRttParams)msg.obj;
- if (params == null) {
- replyFailed(msg,
- RttManager.REASON_INVALID_REQUEST, "No params");
- } else if (ci.addRttRequest(msg.arg2, params) == false) {
- replyFailed(msg,
- RttManager.REASON_INVALID_REQUEST, "Unspecified");
- } else {
- sendMessage(CMD_ISSUE_NEXT_REQUEST);
- }
+ //check permission
+ if(DBG) Log.d(TAG, "UID is: " + msg.sendingUid);
+ if (!enforcePermissionCheck(msg)) {
+ Log.e(TAG, "UID: " + msg.sendingUid + " has no" +
+ " LOCATION_HARDWARE Permission");
+ break;
}
+
+ RttManager.ParcelableRttParams params =
+ (RttManager.ParcelableRttParams)msg.obj;
+ if (params == null) {
+ replyFailed(msg,
+ RttManager.REASON_INVALID_REQUEST, "No params");
+ } else if (ci.addRttRequest(msg.arg2, params) == false) {
+ replyFailed(msg,
+ RttManager.REASON_INVALID_REQUEST, "Unspecified");
+ } else {
+ sendMessage(CMD_ISSUE_NEXT_REQUEST);
+ }
+ }
break;
case RttManager.CMD_OP_STOP_RANGING:
+ if(!enforcePermissionCheck(msg)) {
+ break;
+ }
+
for (Iterator<RttRequest> it = mRequestQueue.iterator();
it.hasNext(); ) {
RttRequest request = it.next();
@@ -312,6 +337,7 @@
case CMD_DRIVER_UNLOADED:
if (mOutstandingRequest != null) {
WifiNative.cancelRtt(mOutstandingRequest.params);
+ if (DBG) Log.d(TAG, "abort key: " + mOutstandingRequest.key);
mOutstandingRequest.ci.reportAborted(mOutstandingRequest.key);
mOutstandingRequest = null;
}
@@ -323,23 +349,38 @@
if (mOutstandingRequest == null) {
transitionTo(mEnabledState);
}
+ if(mOutstandingRequest != null) {
+ if (DBG) Log.d(TAG, "new mOutstandingRequest.key is: " +
+ mOutstandingRequest.key);
+ } else {
+ if (DBG) Log.d(TAG,
+ "CMD_ISSUE_NEXT_REQUEST: mOutstandingRequest =null ");
+ }
} else {
/* just wait; we'll issue next request after
* current one is finished */
- if (DBG) Log.d(TAG, "Ignoring CMD_ISSUE_NEXT_REQUEST");
+ if (DBG) Log.d(TAG, "Current mOutstandingRequest.key is: " +
+ mOutstandingRequest.key);
+ if (DBG) Log.d(TAG, "Ignoring CMD_ISSUE_NEXT_REQUEST");
}
break;
case CMD_RTT_RESPONSE:
- if (DBG) Log.d(TAG, "Received an RTT response");
+ if (DBG) Log.d(TAG, "Received an RTT response from: " + msg.arg2);
mOutstandingRequest.ci.reportResult(
mOutstandingRequest, (RttManager.RttResult[])msg.obj);
mOutstandingRequest = null;
sendMessage(CMD_ISSUE_NEXT_REQUEST);
break;
case RttManager.CMD_OP_STOP_RANGING:
+ if(!enforcePermissionCheck(msg)) {
+ Log.e(TAG, "UID: " + msg.sendingUid + " has no " +
+ "LOCATION_HARDWARE Permission");
+ break;
+ }
+
if (mOutstandingRequest != null
&& msg.arg2 == mOutstandingRequest.key) {
- if (DBG) Log.d(TAG, "Cancelling ongoing RTT");
+ if (DBG) Log.d(TAG, "Cancelling ongoing RTT of: " + msg.arg2);
WifiNative.cancelRtt(mOutstandingRequest.params);
mOutstandingRequest.ci.reportAborted(mOutstandingRequest.key);
mOutstandingRequest = null;
@@ -390,6 +431,17 @@
}
}
+ boolean enforcePermissionCheck(Message msg) {
+ try {
+ mContext.enforcePermission(Manifest.permission.LOCATION_HARDWARE,
+ -1, msg.sendingUid, "LocationRTT");
+ } catch (SecurityException e) {
+ replyFailed(msg,RttManager.REASON_PERMISSION_DENIED, "No params");
+ return false;
+ }
+ return true;
+ }
+
private WifiNative.RttEventHandler mEventHandler = new WifiNative.RttEventHandler() {
@Override
public void onRttResults(RttManager.RttResult[] result) {
@@ -401,12 +453,15 @@
RttRequest request = null;
while (mRequestQueue.isEmpty() == false) {
request = mRequestQueue.remove();
- if (WifiNative.requestRtt(request.params, mEventHandler)) {
- if (DBG) Log.d(TAG, "Issued next RTT request");
- return request;
- } else {
- request.ci.reportFailed(request,
- RttManager.REASON_UNSPECIFIED, "Failed to start");
+ if(request != null) {
+ if (WifiNative.requestRtt(request.params, mEventHandler)) {
+ if (DBG) Log.d(TAG, "Issued next RTT request with key: " + request.key);
+ return request;
+ } else {
+ Log.e(TAG, "Fail to issue key at native layer");
+ request.ci.reportFailed(request,
+ RttManager.REASON_UNSPECIFIED, "Failed to start");
+ }
}
}
@@ -414,6 +469,10 @@
if (DBG) Log.d(TAG, "No more requests left");
return null;
}
+ @Override
+ public RttManager.RttCapabilities getRttCapabilities() {
+ return WifiNative.getRttCapabilities();
+ }
}
private static final String TAG = "RttService";
@@ -442,4 +501,6 @@
mImpl.startService(getContext());
}
}
+
+
}
diff --git a/service/java/com/android/server/wifi/SIMAccessor.java b/service/java/com/android/server/wifi/SIMAccessor.java
new file mode 100644
index 0000000..e446436
--- /dev/null
+++ b/service/java/com/android/server/wifi/SIMAccessor.java
@@ -0,0 +1,32 @@
+package com.android.server.wifi;
+
+import android.content.Context;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SIMAccessor {
+ private final TelephonyManager mTelephonyManager;
+ private final SubscriptionManager mSubscriptionManager;
+
+ public SIMAccessor(Context context) {
+ mTelephonyManager = TelephonyManager.from(context);
+ mSubscriptionManager = SubscriptionManager.from(context);
+ }
+
+ public List<String> getMatchingImsis(IMSIParameter mccMnc) {
+ if (mccMnc == null) {
+ return null;
+ }
+ List<String> imsis = new ArrayList<>();
+ for (int subId : mSubscriptionManager.getActiveSubscriptionIdList()) {
+ String imsi = mTelephonyManager.getSubscriberId(subId);
+ if (mccMnc.matches(imsi)) {
+ imsis.add(imsi);
+ }
+ }
+ return imsis.isEmpty() ? null : imsis;
+ }
+}
diff --git a/service/java/com/android/server/wifi/ScanDetail.java b/service/java/com/android/server/wifi/ScanDetail.java
new file mode 100644
index 0000000..868a192
--- /dev/null
+++ b/service/java/com/android/server/wifi/ScanDetail.java
@@ -0,0 +1,157 @@
+package com.android.server.wifi;
+
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiSsid;
+
+import com.android.server.wifi.anqp.ANQPElement;
+import com.android.server.wifi.anqp.Constants;
+import com.android.server.wifi.anqp.HSFriendlyNameElement;
+import com.android.server.wifi.anqp.VenueNameElement;
+import com.android.server.wifi.hotspot2.NetworkDetail;
+import com.android.server.wifi.hotspot2.PasspointMatch;
+import com.android.server.wifi.hotspot2.PasspointMatchInfo;
+import com.android.server.wifi.hotspot2.Utils;
+import com.android.server.wifi.hotspot2.pps.HomeSP;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class ScanDetail {
+ private final ScanResult mScanResult;
+ private volatile NetworkDetail mNetworkDetail;
+ private final Map<HomeSP, PasspointMatch> mMatches;
+ private long mSeen = 0;
+
+ public ScanDetail(NetworkDetail networkDetail, WifiSsid wifiSsid, String BSSID,
+ String caps, int level, int frequency, long tsf) {
+ mNetworkDetail = networkDetail;
+ mScanResult = new ScanResult(wifiSsid, BSSID, caps, level, frequency, tsf );
+ mSeen = System.currentTimeMillis();
+ //mScanResult.seen = mSeen;
+ mScanResult.channelWidth = networkDetail.getChannelWidth();
+ mScanResult.centerFreq0 = networkDetail.getCenterfreq0();
+ mScanResult.centerFreq1 = networkDetail.getCenterfreq1();
+ if (networkDetail.is80211McResponderSupport())
+ mScanResult.setFlag(ScanResult.FLAG_80211mc_RESPONDER);
+ mMatches = null;
+ }
+
+ public ScanDetail(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency,
+ long tsf, long seen) {
+ mNetworkDetail = null;
+ mScanResult = new ScanResult(wifiSsid, BSSID, caps, level, frequency, tsf );
+ mSeen = seen;
+ //mScanResult.seen = mSeen;
+ mScanResult.channelWidth = 0;
+ mScanResult.centerFreq0 = 0;
+ mScanResult.centerFreq1 = 0;
+ mScanResult.flags = 0;
+ mMatches = null;
+ }
+
+ private ScanDetail(ScanResult scanResult, NetworkDetail networkDetail,
+ Map<HomeSP, PasspointMatch> matches) {
+ mScanResult = scanResult;
+ mNetworkDetail = networkDetail;
+ mMatches = matches;
+ }
+
+ public void updateResults(NetworkDetail networkDetail, int level, WifiSsid wssid, String ssid,
+ String flags, int freq, long tsf) {
+ mScanResult.level = level;
+ mScanResult.wifiSsid = wssid;
+ // Keep existing API
+ mScanResult.SSID = ssid;
+ mScanResult.capabilities = flags;
+ mScanResult.frequency = freq;
+ mScanResult.timestamp = tsf;
+ mSeen = System.currentTimeMillis();
+ //mScanResult.seen = mSeen;
+ mScanResult.channelWidth = networkDetail.getChannelWidth();
+ mScanResult.centerFreq0 = networkDetail.getCenterfreq0();
+ mScanResult.centerFreq1 = networkDetail.getCenterfreq1();
+ if (networkDetail.is80211McResponderSupport())
+ mScanResult.setFlag(ScanResult.FLAG_80211mc_RESPONDER);
+ if (networkDetail.isInterworking())
+ mScanResult.setFlag(ScanResult.FLAG_PASSPOINT_NETWORK);
+ }
+
+ public void propagateANQPInfo(Map<Constants.ANQPElementType, ANQPElement> anqpElements) {
+ if (anqpElements.isEmpty()) {
+ return;
+ }
+ mNetworkDetail = mNetworkDetail.complete(anqpElements);
+ HSFriendlyNameElement fne = (HSFriendlyNameElement)anqpElements.get(
+ Constants.ANQPElementType.HSFriendlyName);
+ // !!! Match with language
+ if (fne != null && !fne.getNames().isEmpty()) {
+ mScanResult.venueName = fne.getNames().get(0).getText();
+ } else {
+ VenueNameElement vne =
+ (((VenueNameElement)anqpElements.get(Constants.ANQPElementType.ANQPVenueName)));
+ if (vne != null && !vne.getNames().isEmpty()) {
+ mScanResult.venueName = vne.getNames().get(0).getText();
+ }
+ }
+ }
+
+ public ScanResult getScanResult() {
+ return mScanResult;
+ }
+
+ public NetworkDetail getNetworkDetail() {
+ return mNetworkDetail;
+ }
+
+ public String getSSID() {
+ return mNetworkDetail == null ? mScanResult.SSID : mNetworkDetail.getSSID();
+ }
+
+ public String getBSSIDString() {
+ return mNetworkDetail == null ? mScanResult.BSSID : mNetworkDetail.getBSSIDString();
+ }
+
+ public String toKeyString() {
+ NetworkDetail networkDetail = mNetworkDetail;
+ if (networkDetail != null) {
+ return networkDetail.toKeyString();
+ }
+ else {
+ return String.format("'%s':%012x", mScanResult.BSSID, Utils.parseMac(mScanResult.BSSID));
+ }
+ }
+
+ public long getSeen() {
+ return mSeen;
+ }
+
+ public long setSeen() {
+ mSeen = System.currentTimeMillis();
+ mScanResult.seen = mSeen;
+ return mSeen;
+ }
+
+ public List<PasspointMatchInfo> getMatchList() {
+ if (mMatches == null || mMatches.isEmpty()) {
+ return null;
+ }
+
+ List<PasspointMatchInfo> list = new ArrayList<>();
+ for (Map.Entry<HomeSP, PasspointMatch> entry : mMatches.entrySet()) {
+ new PasspointMatchInfo(entry.getValue(), this, entry.getKey());
+ }
+ return list;
+ }
+
+ @Override
+ public String toString() {
+ try {
+ return String.format("'%s'/%012x",
+ mScanResult.SSID, Utils.parseMac(mScanResult.BSSID));
+ }
+ catch (IllegalArgumentException iae) {
+ return String.format("'%s'/----", mScanResult.BSSID);
+ }
+ }
+}
diff --git a/service/java/com/android/server/wifi/ScanDetailCache.java b/service/java/com/android/server/wifi/ScanDetailCache.java
new file mode 100644
index 0000000..d246c55
--- /dev/null
+++ b/service/java/com/android/server/wifi/ScanDetailCache.java
@@ -0,0 +1,300 @@
+
+package com.android.server.wifi;
+
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.util.Log;
+import android.os.SystemClock;
+
+import com.android.server.wifi.ScanDetail;
+import com.android.server.wifi.hotspot2.PasspointMatch;
+import com.android.server.wifi.hotspot2.PasspointMatchInfo;
+import com.android.server.wifi.hotspot2.pps.HomeSP;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+class ScanDetailCache {
+
+ private static final String TAG = "ScanDetailCache";
+
+ private WifiConfiguration mConfig;
+ private HashMap<String, ScanDetail> mMap;
+ private HashMap<String, PasspointMatchInfo> mPasspointMatches;
+ private static boolean DBG=false;
+ ScanDetailCache(WifiConfiguration config) {
+ mConfig = config;
+ mMap = new HashMap();
+ mPasspointMatches = new HashMap();
+ }
+
+ void put(ScanDetail scanDetail) {
+ put(scanDetail, null, null);
+ }
+
+ void put(ScanDetail scanDetail, PasspointMatch match, HomeSP homeSp) {
+
+ mMap.put(scanDetail.getBSSIDString(), scanDetail);
+
+ if (match != null && homeSp != null) {
+ mPasspointMatches.put(scanDetail.getBSSIDString(),
+ new PasspointMatchInfo(match, scanDetail, homeSp));
+ }
+ }
+
+ ScanResult get(String bssid) {
+ ScanDetail scanDetail = getScanDetail(bssid);
+ return scanDetail == null ? null : scanDetail.getScanResult();
+ }
+
+ ScanDetail getScanDetail(String bssid) {
+ return mMap.get(bssid);
+ }
+
+ void remove(String bssid) {
+ mMap.remove(bssid);
+ }
+
+ int size() {
+ return mMap.size();
+ }
+
+ boolean isEmpty() {
+ return size() == 0;
+ }
+
+ ScanDetail getFirst() {
+ Iterator<ScanDetail> it = mMap.values().iterator();
+ return it.hasNext() ? it.next() : null;
+ }
+
+ Collection<String> keySet() {
+ return mMap.keySet();
+ }
+
+ Collection<ScanDetail> values() {
+ return mMap.values();
+ }
+
+ public void trim(int num) {
+ int currentSize = mMap.size();
+ if (currentSize <= num) {
+ return; // Nothing to trim
+ }
+ ArrayList<ScanDetail> list = new ArrayList<ScanDetail>(mMap.values());
+ if (list.size() != 0) {
+ // Sort by descending timestamp
+ Collections.sort(list, new Comparator() {
+ public int compare(Object o1, Object o2) {
+ ScanDetail a = (ScanDetail) o1;
+ ScanDetail b = (ScanDetail) o2;
+ if (a.getSeen() > b.getSeen()) {
+ return 1;
+ }
+ if (a.getSeen() < b.getSeen()) {
+ return -1;
+ }
+ return a.getBSSIDString().compareTo(b.getBSSIDString());
+ }
+ });
+ }
+ for (int i = 0; i < currentSize - num ; i++) {
+ // Remove oldest results from scan cache
+ ScanDetail result = list.get(i);
+ mMap.remove(result.getBSSIDString());
+ mPasspointMatches.remove(result.getBSSIDString());
+ }
+ }
+
+ /* @hide */
+ private ArrayList<ScanDetail> sort() {
+ ArrayList<ScanDetail> list = new ArrayList<ScanDetail>(mMap.values());
+ if (list.size() != 0) {
+ Collections.sort(list, new Comparator() {
+ public int compare(Object o1, Object o2) {
+ ScanResult a = ((ScanDetail)o1).getScanResult();
+ ScanResult b = ((ScanDetail)o2).getScanResult();
+ if (a.numIpConfigFailures > b.numIpConfigFailures) {
+ return 1;
+ }
+ if (a.numIpConfigFailures < b.numIpConfigFailures) {
+ return -1;
+ }
+ if (a.seen > b.seen) {
+ return -1;
+ }
+ if (a.seen < b.seen) {
+ return 1;
+ }
+ if (a.level > b.level) {
+ return -1;
+ }
+ if (a.level < b.level) {
+ return 1;
+ }
+ return a.BSSID.compareTo(b.BSSID);
+ }
+ });
+ }
+ return list;
+ }
+
+ public WifiConfiguration.Visibility getVisibilityByRssi(long age) {
+ WifiConfiguration.Visibility status = new WifiConfiguration.Visibility();
+
+ long now_ms = System.currentTimeMillis();
+ long now_elapsed_ms = SystemClock.elapsedRealtime();
+ for(ScanDetail scanDetail : values()) {
+ ScanResult result = scanDetail.getScanResult();
+ if (scanDetail.getSeen() == 0)
+ continue;
+
+ if (result.is5GHz()) {
+ //strictly speaking: [4915, 5825]
+ //number of known BSSID on 5GHz band
+ status.num5 = status.num5 + 1;
+ } else if (result.is24GHz()) {
+ //strictly speaking: [2412, 2482]
+ //number of known BSSID on 2.4Ghz band
+ status.num24 = status.num24 + 1;
+ }
+
+ if (result.timestamp != 0) {
+ if (DBG) {
+ Log.e("getVisibilityByRssi", " considering " + result.SSID + " " + result.BSSID
+ + " elapsed=" + now_elapsed_ms + " timestamp=" + result.timestamp
+ + " age = " + age);
+ }
+ if ((now_elapsed_ms - (result.timestamp/1000)) > age) continue;
+ } else {
+ // This check the time at which we have received the scan result from supplicant
+ if ((now_ms - result.seen) > age) continue;
+ }
+
+ if (result.is5GHz()) {
+ if (result.level > status.rssi5) {
+ status.rssi5 = result.level;
+ status.age5 = result.seen;
+ status.BSSID5 = result.BSSID;
+ }
+ } else if (result.is24GHz()) {
+ if (result.level > status.rssi24) {
+ status.rssi24 = result.level;
+ status.age24 = result.seen;
+ status.BSSID24 = result.BSSID;
+ }
+ }
+ }
+
+ return status;
+ }
+
+ public WifiConfiguration.Visibility getVisibilityByPasspointMatch(long age) {
+
+ long now_ms = System.currentTimeMillis();
+ PasspointMatchInfo pmiBest24 = null, pmiBest5 = null;
+
+ for(PasspointMatchInfo pmi : mPasspointMatches.values()) {
+ ScanDetail scanDetail = pmi.getScanDetail();
+ if (scanDetail == null) continue;
+ ScanResult result = scanDetail.getScanResult();
+ if (result == null) continue;
+
+ if (scanDetail.getSeen() == 0)
+ continue;
+
+ if ((now_ms - result.seen) > age) continue;
+
+ if (result.is5GHz()) {
+ if (pmiBest5 == null || pmiBest5.compareTo(pmi) < 0) {
+ pmiBest5 = pmi;
+ }
+ } else if (result.is24GHz()) {
+ if (pmiBest24 == null || pmiBest24.compareTo(pmi) < 0) {
+ pmiBest24 = pmi;
+ }
+ }
+ }
+
+ WifiConfiguration.Visibility status = new WifiConfiguration.Visibility();
+ String logMsg = "Visiblity by passpoint match returned ";
+ if (pmiBest5 != null) {
+ ScanResult result = pmiBest5.getScanDetail().getScanResult();
+ status.rssi5 = result.level;
+ status.age5 = result.seen;
+ status.BSSID5 = result.BSSID;
+ logMsg += "5 GHz BSSID of " + result.BSSID;
+ }
+ if (pmiBest24 != null) {
+ ScanResult result = pmiBest24.getScanDetail().getScanResult();
+ status.rssi24 = result.level;
+ status.age24 = result.seen;
+ status.BSSID24 = result.BSSID;
+ logMsg += "2.4 GHz BSSID of " + result.BSSID;
+ }
+
+ Log.d(TAG, logMsg);
+
+ return status;
+ }
+
+ public WifiConfiguration.Visibility getVisibility(long age) {
+ if (mConfig.isPasspoint()) {
+ return getVisibilityByPasspointMatch(age);
+ } else {
+ return getVisibilityByRssi(age);
+ }
+ }
+
+
+
+ @Override
+ public String toString() {
+ StringBuilder sbuf = new StringBuilder();
+ sbuf.append("Scan Cache: ").append('\n');
+
+ ArrayList<ScanDetail> list = sort();
+ long now_ms = System.currentTimeMillis();
+ if (list.size() > 0) {
+ for (ScanDetail scanDetail : list) {
+ ScanResult result = scanDetail.getScanResult();
+ long milli = now_ms - scanDetail.getSeen();
+ long ageSec = 0;
+ long ageMin = 0;
+ long ageHour = 0;
+ long ageMilli = 0;
+ long ageDay = 0;
+ if (now_ms > scanDetail.getSeen() && scanDetail.getSeen() > 0) {
+ ageMilli = milli % 1000;
+ ageSec = (milli / 1000) % 60;
+ ageMin = (milli / (60*1000)) % 60;
+ ageHour = (milli / (60*60*1000)) % 24;
+ ageDay = (milli / (24*60*60*1000));
+ }
+ sbuf.append("{").append(result.BSSID).append(",").append(result.frequency);
+ sbuf.append(",").append(String.format("%3d", result.level));
+ if (result.autoJoinStatus > 0) {
+ sbuf.append(",st=").append(result.autoJoinStatus);
+ }
+ if (ageSec > 0 || ageMilli > 0) {
+ sbuf.append(String.format(",%4d.%02d.%02d.%02d.%03dms", ageDay,
+ ageHour, ageMin, ageSec, ageMilli));
+ }
+ if (result.numIpConfigFailures > 0) {
+ sbuf.append(",ipfail=");
+ sbuf.append(result.numIpConfigFailures);
+ }
+ sbuf.append("} ");
+ }
+ sbuf.append('\n');
+ }
+
+ return sbuf.toString();
+ }
+
+}
diff --git a/service/java/com/android/server/wifi/WifiApConfigStore.java b/service/java/com/android/server/wifi/WifiApConfigStore.java
index eb35db8..ed5ddf7 100644
--- a/service/java/com/android/server/wifi/WifiApConfigStore.java
+++ b/service/java/com/android/server/wifi/WifiApConfigStore.java
@@ -37,6 +37,7 @@
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.UUID;
/**
@@ -51,7 +52,7 @@
private static final String AP_CONFIG_FILE = Environment.getDataDirectory() +
"/misc/wifi/softap.conf";
- private static final int AP_CONFIG_FILE_VERSION = 1;
+ private static final int AP_CONFIG_FILE_VERSION = 2;
private State mDefaultState = new DefaultState();
private State mInactiveState = new InactiveState();
@@ -59,6 +60,7 @@
private WifiConfiguration mWifiApConfig = null;
private AsyncChannel mReplyChannel = new AsyncChannel();
+ public ArrayList <Integer> allowed2GChannel = null;
WifiApConfigStore(Context context, Handler target) {
super(TAG, target.getLooper());
@@ -69,6 +71,17 @@
addState(mActiveState, mDefaultState);
setInitialState(mInactiveState);
+ String ap2GChannelListStr = (mContext.getResources().getString(
+ R.string.config_wifi_framework_sap_2G_channel_list));
+ Log.d(TAG, "2G band allowed channels are:" + ap2GChannelListStr);
+
+ if (ap2GChannelListStr != null) {
+ allowed2GChannel = new ArrayList<Integer>();
+ String channelList[] = ap2GChannelListStr.split(",");
+ for (String tmp : channelList) {
+ allowed2GChannel.add(Integer.parseInt(tmp));
+ }
+ }
}
public static WifiApConfigStore makeWifiApConfigStore(Context context, Handler target) {
@@ -100,9 +113,9 @@
public boolean processMessage(Message message) {
switch (message.what) {
case WifiStateMachine.CMD_SET_AP_CONFIG:
- WifiConfiguration config = (WifiConfiguration) message.obj;
+ WifiConfiguration config = (WifiConfiguration)message.obj;
if (config.SSID != null) {
- mWifiApConfig = (WifiConfiguration) message.obj;
+ mWifiApConfig = config;
transitionTo(mActiveState);
} else {
Log.e(TAG, "Try to setup AP config without SSID: " + message);
@@ -150,17 +163,24 @@
AP_CONFIG_FILE)));
int version = in.readInt();
- if (version != 1) {
+ if ((version != 1) && (version != 2)) {
Log.e(TAG, "Bad version on hotspot configuration file, set defaults");
setDefaultApConfiguration();
return;
}
config.SSID = in.readUTF();
+
+ if (version >= 2) {
+ config.apBand = in.readInt();
+ config.apChannel = in.readInt();
+ }
+
int authType = in.readInt();
config.allowedKeyManagement.set(authType);
if (authType != KeyMgmt.NONE) {
config.preSharedKey = in.readUTF();
}
+
mWifiApConfig = config;
} catch (IOException ignore) {
setDefaultApConfiguration();
@@ -185,6 +205,8 @@
out.writeInt(AP_CONFIG_FILE_VERSION);
out.writeUTF(config.SSID);
+ out.writeInt(config.apBand);
+ out.writeInt(config.apChannel);
int authType = config.getAuthType();
out.writeInt(authType);
if(authType != KeyMgmt.NONE) {
diff --git a/service/java/com/android/server/wifi/WifiAutoJoinController.java b/service/java/com/android/server/wifi/WifiAutoJoinController.java
index c7da179..a1a9a82 100644
--- a/service/java/com/android/server/wifi/WifiAutoJoinController.java
+++ b/service/java/com/android/server/wifi/WifiAutoJoinController.java
@@ -20,17 +20,23 @@
import android.net.NetworkKey;
import android.net.NetworkScoreManager;
import android.net.WifiKey;
-import android.net.wifi.*;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.os.SystemClock;
-import android.provider.Settings;
+import android.net.wifi.WifiConnectionStatistics;
import android.os.Process;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
+import android.os.SystemClock;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
import java.util.ArrayList;
-import java.util.Iterator;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
/**
@@ -59,12 +65,13 @@
private String mCurrentConfigurationKey = null; //used by autojoin
- private HashMap<String, ScanResult> scanResultCache =
- new HashMap<String, ScanResult>();
+ private final HashMap<String, ScanDetail> scanResultCache = new HashMap<>();
private WifiConnectionStatistics mWifiConnectionStatistics;
- /** Whether to allow connections to untrusted networks. */
+ /**
+ * Whether to allow connections to untrusted networks.
+ */
private boolean mAllowUntrustedConnections = false;
/* For debug purpose only: if the scored override a score */
@@ -75,7 +82,9 @@
// Lose some temporary blacklisting after 30 minutes
private final static long loseBlackListSoftMilli = 1000 * 60 * 30;
- /** @see android.provider.Settings.Global#WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS */
+ /**
+ * @see android.provider.Settings.Global#WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS
+ */
private static final long DEFAULT_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS = 1000 * 60; // 1 minute
public static final int AUTO_JOIN_IDLE = 0;
@@ -85,6 +94,8 @@
public static final int HIGH_THRESHOLD_MODIFIER = 5;
+ public static final int MAX_RSSI_DELTA = 50;
+
// Below are AutoJoin wide parameters indicating if we should be aggressive before joining
// weak network. Note that we cannot join weak network that are going to be marked as unanted by
// ConnectivityService because this will trigger link flapping.
@@ -123,7 +134,7 @@
}
void enableVerboseLogging(int verbose) {
- if (verbose > 0 ) {
+ if (verbose > 0) {
DBG = true;
VDBG = true;
} else {
@@ -134,7 +145,6 @@
/**
* Flush out scan results older than mScanResultMaximumAge
- *
*/
private void ageScanResultsOut(int delay) {
if (delay <= 0) {
@@ -146,18 +156,67 @@
+ Integer.valueOf(scanResultCache.size()) + " now " + Long.valueOf(milli));
}
- Iterator<HashMap.Entry<String,ScanResult>> iter = scanResultCache.entrySet().iterator();
+ Iterator<HashMap.Entry<String, ScanDetail>> iter = scanResultCache.entrySet().iterator();
while (iter.hasNext()) {
- HashMap.Entry<String,ScanResult> entry = iter.next();
- ScanResult result = entry.getValue();
-
- if ((result.seen + delay) < milli) {
+ HashMap.Entry<String, ScanDetail> entry = iter.next();
+ ScanDetail scanDetail = entry.getValue();
+ if ((scanDetail.getSeen() + delay) < milli) {
iter.remove();
}
}
}
- int addToScanCache(List<ScanResult> scanList) {
+
+ void averageRssiAndRemoveFromCache(ScanResult result) {
+ // Fetch the previous instance for this result
+ ScanDetail sd = scanResultCache.get(result.BSSID);
+ if (sd != null) {
+ ScanResult sr = sd.getScanResult();
+ if (mWifiConfigStore.scanResultRssiLevelPatchUp != 0
+ && result.level == 0
+ && sr.level < -20) {
+ // A 'zero' RSSI reading is most likely a chip problem which returns
+ // an unknown RSSI, hence ignore it
+ result.level = sr.level;
+ }
+
+ // If there was a previous cache result for this BSSID, average the RSSI values
+ result.averageRssi(sr.level, sr.seen, mScanResultMaximumAge);
+
+ // Remove the previous Scan Result - this is not necessary
+ scanResultCache.remove(result.BSSID);
+ } else if (mWifiConfigStore.scanResultRssiLevelPatchUp != 0 && result.level == 0) {
+ // A 'zero' RSSI reading is most likely a chip problem which returns
+ // an unknown RSSI, hence initialize it to a sane value
+ result.level = mWifiConfigStore.scanResultRssiLevelPatchUp;
+ }
+ }
+
+ void addToUnscoredNetworks(ScanResult result, List<NetworkKey> unknownScanResults) {
+ WifiKey wkey;
+ // Quoted SSIDs are the only one valid at this stage
+ try {
+ wkey = new WifiKey("\"" + result.SSID + "\"", result.BSSID);
+ } catch (IllegalArgumentException e) {
+ logDbg("AutoJoinController: received badly encoded SSID=[" + result.SSID +
+ "] ->skipping this network");
+ wkey = null;
+ }
+ if (wkey != null) {
+ NetworkKey nkey = new NetworkKey(wkey);
+ //if we don't know this scan result then request a score from the scorer
+ unknownScanResults.add(nkey);
+ }
+ if (VDBG) {
+ String cap = "";
+ if (result.capabilities != null)
+ cap = result.capabilities;
+ logDbg(result.SSID + " " + result.BSSID + " rssi="
+ + result.level + " cap " + cap + " tsf " + result.timestamp + " is not scored");
+ }
+ }
+
+ int addToScanCache(List<ScanDetail> scanList) {
int numScanResultsKnown = 0; // Record number of scan results we knew about
WifiConfiguration associatedConfig = null;
boolean didAssociate = false;
@@ -165,56 +224,24 @@
ArrayList<NetworkKey> unknownScanResults = new ArrayList<NetworkKey>();
- for(ScanResult result: scanList) {
+ for (ScanDetail scanDetail : scanList) {
+ ScanResult result = scanDetail.getScanResult();
if (result.SSID == null) continue;
- // Make sure we record the last time we saw this result
- result.seen = System.currentTimeMillis();
-
- // Fetch the previous instance for this result
- ScanResult sr = scanResultCache.get(result.BSSID);
- if (sr != null) {
- if (mWifiConfigStore.scanResultRssiLevelPatchUp != 0
- && result.level == 0
- && sr.level < -20) {
- // A 'zero' RSSI reading is most likely a chip problem which returns
- // an unknown RSSI, hence ignore it
- result.level = sr.level;
- }
-
- // If there was a previous cache result for this BSSID, average the RSSI values
- result.averageRssi(sr.level, sr.seen, mScanResultMaximumAge);
-
- // Remove the previous Scan Result - this is not necessary
- scanResultCache.remove(result.BSSID);
- } else if (mWifiConfigStore.scanResultRssiLevelPatchUp != 0 && result.level == 0) {
- // A 'zero' RSSI reading is most likely a chip problem which returns
- // an unknown RSSI, hence initialize it to a sane value
- result.level = mWifiConfigStore.scanResultRssiLevelPatchUp;
+ if (VDBG) {
+ logDbg(" addToScanCache " + result.SSID + " " + result.BSSID
+ + " tsf=" + result.timestamp
+ + " now= " + now + " uptime=" + SystemClock.uptimeMillis()
+ + " elapsed=" + SystemClock.elapsedRealtime());
}
+ // Make sure we record the last time we saw this result
+ scanDetail.setSeen();
+
+ averageRssiAndRemoveFromCache(result);
+
if (!mNetworkScoreCache.isScoredNetwork(result)) {
- WifiKey wkey;
- // Quoted SSIDs are the only one valid at this stage
- try {
- wkey = new WifiKey("\"" + result.SSID + "\"", result.BSSID);
- } catch (IllegalArgumentException e) {
- logDbg("AutoJoinController: received badly encoded SSID=[" + result.SSID +
- "] ->skipping this network");
- wkey = null;
- }
- if (wkey != null) {
- NetworkKey nkey = new NetworkKey(wkey);
- //if we don't know this scan result then request a score from the scorer
- unknownScanResults.add(nkey);
- }
- if (VDBG) {
- String cap = "";
- if (result.capabilities != null)
- cap = result.capabilities;
- logDbg(result.SSID + " " + result.BSSID + " rssi="
- + result.level + " cap " + cap + " is not scored");
- }
+ addToUnscoredNetworks(result, unknownScanResults);
} else {
if (VDBG) {
String cap = "";
@@ -227,29 +254,15 @@
}
// scanResultCache.put(result.BSSID, new ScanResult(result));
- scanResultCache.put(result.BSSID, result);
+ scanResultCache.put(result.BSSID, scanDetail);
// Add this BSSID to the scanResultCache of a Saved WifiConfiguration
- didAssociate = mWifiConfigStore.updateSavedNetworkHistory(result);
+ didAssociate = mWifiConfigStore.updateSavedNetworkHistory(scanDetail);
// If not successful, try to associate this BSSID to an existing Saved WifiConfiguration
if (!didAssociate) {
// We couldn't associate the scan result to a Saved WifiConfiguration
// Hence it is untrusted
result.untrusted = true;
- associatedConfig = mWifiConfigStore.associateWithConfiguration(result);
- if (associatedConfig != null && associatedConfig.SSID != null) {
- if (VDBG) {
- logDbg("addToScanCache save associated config "
- + associatedConfig.SSID + " with " + result.SSID
- + " status " + associatedConfig.autoJoinStatus
- + " reason " + associatedConfig.disableReason
- + " tsp " + associatedConfig.blackListTimestamp
- + " was " + (now - associatedConfig.blackListTimestamp));
- }
- mWifiStateMachine.sendMessage(
- WifiStateMachine.CMD_AUTO_SAVE_NETWORK, associatedConfig);
- didAssociate = true;
- }
} else {
// If the scan result has been blacklisted fir 18 hours -> unblacklist
if ((now - result.blackListTimestamp) > loseBlackListHardMilli) {
@@ -258,7 +271,7 @@
}
if (didAssociate) {
numScanResultsKnown++;
- result.isAutoJoinCandidate ++;
+ result.isAutoJoinCandidate++;
} else {
result.isAutoJoinCandidate = 0;
}
@@ -279,26 +292,26 @@
void logDbg(String message, boolean stackTrace) {
if (stackTrace) {
- Log.e(TAG, message + " stack:"
+ Log.d(TAG, message + " stack:"
+ Thread.currentThread().getStackTrace()[2].getMethodName() + " - "
+ Thread.currentThread().getStackTrace()[3].getMethodName() + " - "
+ Thread.currentThread().getStackTrace()[4].getMethodName() + " - "
+ Thread.currentThread().getStackTrace()[5].getMethodName());
} else {
- Log.e(TAG, message);
+ Log.d(TAG, message);
}
}
// Called directly from WifiStateMachine
int newSupplicantResults(boolean doAutoJoin) {
int numScanResultsKnown;
- List<ScanResult> scanList = mWifiStateMachine.getScanResultsListNoCopyUnsync();
+ List<ScanDetail> scanList = mWifiStateMachine.getScanResultsListNoCopyUnsync();
numScanResultsKnown = addToScanCache(scanList);
ageScanResultsOut(mScanResultMaximumAge);
if (DBG) {
logDbg("newSupplicantResults size=" + Integer.valueOf(scanResultCache.size())
- + " known=" + numScanResultsKnown + " "
- + doAutoJoin);
+ + " known=" + numScanResultsKnown + " "
+ + doAutoJoin);
}
if (doAutoJoin) {
attemptAutoJoin();
@@ -316,7 +329,7 @@
* results as normal.
*/
void newHalScanResults() {
- List<ScanResult> scanList = null;//mWifiScanner.syncGetScanResultsList();
+ List<ScanDetail> scanList = null;//mWifiScanner.syncGetScanResultsList();
String akm = WifiParser.parse_akm(null, null);
logDbg(akm);
addToScanCache(scanList);
@@ -326,7 +339,7 @@
}
/**
- * network link quality changed, called directly from WifiTrafficPoller,
+ * network link quality changed, called directly from WifiTrafficPoller,
* or by listening to Link Quality intent
*/
void linkQualitySignificantChange() {
@@ -350,7 +363,7 @@
if (currentNetwork == null) {
// Return any absurdly high score, if we are not connected there is no current
// network to...
- return 1000;
+ return 1000;
}
if (candidate.configKey(true).equals(currentNetwork.configKey(true))) {
@@ -375,7 +388,7 @@
// above RSSI/scorer based selection of linked configuration (+/- 50)
// by reducing order by -100
order = order - 100;
- if (VDBG) {
+ if (VDBG) {
logDbg(" ...and prefers -100 " + currentNetwork.configKey()
+ " over " + candidate.configKey()
+ " because it is the last selected -> "
@@ -388,7 +401,7 @@
// above RSSI/scorer based selection of linked configuration (+/- 50)
// by increasing order by +100
order = order + 100;
- if (VDBG) {
+ if (VDBG) {
logDbg(" ...and prefers +100 " + candidate.configKey()
+ " over " + currentNetwork.configKey()
+ " because it is the last selected -> "
@@ -408,7 +421,7 @@
*
* @param netId
* @param userTriggered : if the update come from WiFiManager
- * @param connect : if the update includes a connect
+ * @param connect : if the update includes a connect
*/
public void updateConfigurationHistory(int netId, boolean userTriggered, boolean connect) {
WifiConfiguration selected = mWifiConfigStore.getWifiConfiguration(netId);
@@ -472,30 +485,17 @@
continue;
}
- // Compare RSSI values so as to evaluate the strength of the user preference
- int order = compareWifiConfigurationsRSSI(config, selected, null);
-
- if (order < -30) {
- // Selected configuration is worse than the visible configuration
- // hence register a strong choice so as autojoin cannot override this
- // for instance, the user has select a network
- // with 1 bar over a network with 3 bars...
- choice = 60;
- } else if (order < -20) {
- choice = 50;
- } else if (order < -10) {
- choice = 40;
- } else if (order < 20) {
- // Selected configuration is about same or has a slightly better RSSI
- // hence register a weaker choice, here a difference of at least +/-30 in
- // RSSI comparison triggered by autoJoin will override the choice
- choice = 30;
- } else {
- // Selected configuration is better than the visible configuration
- // hence we do not know if the user prefers this configuration strongly
- choice = 20;
+ // If the selection was made while config was visible with reasonably good RSSI
+ // then register the user preference, else ignore
+ if (config.visibility == null ||
+ (config.visibility.rssi24 < mWifiConfigStore.thresholdBadRssi24.get()
+ && config.visibility.rssi5 < mWifiConfigStore.thresholdBadRssi5.get())
+ ) {
+ continue;
}
+ choice = MAX_RSSI_DELTA + 10; // Make sure the choice overrides the RSSI diff
+
// The selected configuration was preferred over a recently seen config
// hence remember the user's choice:
// add the recently seen config to the selected's connectChoices array
@@ -508,11 +508,6 @@
+ " over " + config.configKey(true)
+ " choice " + Integer.toString(choice));
- Integer currentChoice = selected.connectChoices.get(config.configKey(true));
- if (currentChoice != null) {
- // User has made this choice multiple time in a row, so bump up a lot
- choice += currentChoice.intValue();
- }
// Add the visible config to the selected's connect choice list
selected.connectChoices.put(config.configKey(true), choice);
@@ -525,21 +520,21 @@
config.connectChoices.remove(selected.configKey(true));
if (selected.linkedConfigurations != null) {
- // Remove the selected's linked configuration from the
- // recently seen config's connectChoice list
- for (String key : selected.linkedConfigurations.keySet()) {
- config.connectChoices.remove(key);
- }
+ // Remove the selected's linked configuration from the
+ // recently seen config's connectChoice list
+ for (String key : selected.linkedConfigurations.keySet()) {
+ config.connectChoices.remove(key);
+ }
}
}
}
if (found == false) {
- // We haven't found the configuration that the user just selected in our
- // scan cache.
- // In that case we will need a new scan before attempting to connect to this
- // configuration anyhow and thus we can process the scan results then.
- logDbg("updateConfigurationHistory try to connect to an old network!! : "
- + selected.configKey());
+ // We haven't found the configuration that the user just selected in our
+ // scan cache.
+ // In that case we will need a new scan before attempting to connect to this
+ // configuration anyhow and thus we can process the scan results then.
+ logDbg("updateConfigurationHistory try to connect to an old network!! : "
+ + selected.configKey());
}
if (selected.connectChoices != null) {
@@ -556,39 +551,44 @@
}
}
- int getConnectChoice(WifiConfiguration source, WifiConfiguration target) {
- Integer choice = null;
+ int getConnectChoice(WifiConfiguration source, WifiConfiguration target, boolean strict) {
+ int choice = 0;
if (source == null || target == null) {
return 0;
}
if (source.connectChoices != null
&& source.connectChoices.containsKey(target.configKey(true))) {
- choice = source.connectChoices.get(target.configKey(true));
+ Integer val = source.connectChoices.get(target.configKey(true));
+ if (val != null) {
+ choice = val;
+ }
} else if (source.linkedConfigurations != null) {
for (String key : source.linkedConfigurations.keySet()) {
WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(key);
if (config != null) {
if (config.connectChoices != null) {
- choice = config.connectChoices.get(target.configKey(true));
+ Integer val = config.connectChoices.get(target.configKey(true));
+ if (val != null) {
+ choice = val;
+ }
}
}
}
}
- if (choice == null) {
- //We didn't find the connect choice
- return 0;
- } else {
- if (choice.intValue() < 0) {
- choice = 20; // Compatibility with older files
- }
- return choice.intValue();
+ if (!strict && choice == 0) {
+ // We didn't find the connect choice; fallback to some default choices
+ int sourceScore = getSecurityScore(source);
+ int targetScore = getSecurityScore(target);
+ choice = sourceScore - targetScore;
}
+
+ return choice;
}
- int compareWifiConfigurationsFromVisibility(WifiConfiguration a, int aRssiBoost,
- WifiConfiguration b, int bRssiBoost) {
+ int compareWifiConfigurationsFromVisibility(WifiConfiguration.Visibility a, int aRssiBoost,
+ String dbgA, WifiConfiguration.Visibility b, int bRssiBoost, String dbgB) {
int aRssiBoost5 = 0; // 5GHz RSSI boost to apply for purpose band selection (5GHz pref)
int bRssiBoost5 = 0; // 5GHz RSSI boost to apply for purpose band selection (5GHz pref)
@@ -606,17 +606,17 @@
* This implements band preference where we prefer 5GHz if RSSI5 is good enough, whereas
* we prefer 2.4GHz otherwise.
*/
- aRssiBoost5 = rssiBoostFrom5GHzRssi(a.visibility.rssi5, a.configKey() + "->");
- bRssiBoost5 = rssiBoostFrom5GHzRssi(b.visibility.rssi5, b.configKey() + "->");
+ aRssiBoost5 = rssiBoostFrom5GHzRssi(a.rssi5, dbgA + "->");
+ bRssiBoost5 = rssiBoostFrom5GHzRssi(b.rssi5, dbgB + "->");
// Select which band to use for a
- if (a.visibility.rssi5 + aRssiBoost5 > a.visibility.rssi24) {
+ if (a.rssi5 + aRssiBoost5 > a.rssi24) {
// Prefer a's 5GHz
aPrefers5GHz = true;
}
// Select which band to use for b
- if (b.visibility.rssi5 + bRssiBoost5 > b.visibility.rssi24) {
+ if (b.rssi5 + bRssiBoost5 > b.rssi24) {
// Prefer b's 5GHz
bPrefers5GHz = true;
}
@@ -626,13 +626,13 @@
// If both a and b are on 5GHz then we don't apply the 5GHz RSSI boost to either
// one, but directly compare the RSSI values, this improves stability,
// since the 5GHz RSSI boost can introduce large fluctuations
- aScore = a.visibility.rssi5 + aRssiBoost;
+ aScore = a.rssi5 + aRssiBoost;
} else {
// If only a is on 5GHz, then apply the 5GHz preference boost to a
- aScore = a.visibility.rssi5 + aRssiBoost + aRssiBoost5;
+ aScore = a.rssi5 + aRssiBoost + aRssiBoost5;
}
} else {
- aScore = a.visibility.rssi24 + aRssiBoost;
+ aScore = a.rssi24 + aRssiBoost;
}
if (bPrefers5GHz) {
@@ -640,29 +640,30 @@
// If both a and b are on 5GHz then we don't apply the 5GHz RSSI boost to either
// one, but directly compare the RSSI values, this improves stability,
// since the 5GHz RSSI boost can introduce large fluctuations
- bScore = b.visibility.rssi5 + bRssiBoost;
+ bScore = b.rssi5 + bRssiBoost;
} else {
// If only b is on 5GHz, then apply the 5GHz preference boost to b
- bScore = b.visibility.rssi5 + bRssiBoost + bRssiBoost5;
+ bScore = b.rssi5 + bRssiBoost + bRssiBoost5;
}
} else {
- bScore = b.visibility.rssi24 + bRssiBoost;
+ bScore = b.rssi24 + bRssiBoost;
}
+
if (VDBG) {
- logDbg(" " + a.configKey() + " is5=" + aPrefers5GHz + " score=" + aScore
- + " " + b.configKey() + " is5=" + bPrefers5GHz + " score=" + bScore);
+ logDbg(" " + dbgA + " is5=" + aPrefers5GHz + " score=" + aScore
+ + " " + dbgB + " is5=" + bPrefers5GHz + " score=" + bScore);
}
// Debug only, record RSSI comparison parameters
- if (a.visibility != null) {
- a.visibility.score = aScore;
- a.visibility.currentNetworkBoost = aRssiBoost;
- a.visibility.bandPreferenceBoost = aRssiBoost5;
+ if (a != null) {
+ a.score = aScore;
+ a.currentNetworkBoost = aRssiBoost;
+ a.bandPreferenceBoost = aRssiBoost5;
}
- if (b.visibility != null) {
- b.visibility.score = bScore;
- b.visibility.currentNetworkBoost = bRssiBoost;
- b.visibility.bandPreferenceBoost = bRssiBoost5;
+ if (b != null) {
+ b.score = bScore;
+ b.currentNetworkBoost = bRssiBoost;
+ b.bandPreferenceBoost = bRssiBoost5;
}
// Compare a and b
@@ -686,9 +687,6 @@
int aRssiBoost = 0;
int bRssiBoost = 0;
- int scoreA;
- int scoreB;
-
// Retrieve the visibility
WifiConfiguration.Visibility astatus = a.visibility;
WifiConfiguration.Visibility bstatus = b.visibility;
@@ -707,23 +705,25 @@
}
}
- if (VDBG) {
+ if (VDBG) {
logDbg(" compareWifiConfigurationsRSSI: " + a.configKey()
- + " rssi=" + Integer.toString(astatus.rssi24)
- + "," + Integer.toString(astatus.rssi5)
- + " boost=" + Integer.toString(aRssiBoost)
- + " " + b.configKey() + " rssi="
- + Integer.toString(bstatus.rssi24) + ","
- + Integer.toString(bstatus.rssi5)
- + " boost=" + Integer.toString(bRssiBoost)
+ + " rssi=" + Integer.toString(astatus.rssi24)
+ + "," + Integer.toString(astatus.rssi5)
+ + " boost=" + Integer.toString(aRssiBoost)
+ + " " + b.configKey() + " rssi="
+ + Integer.toString(bstatus.rssi24) + ","
+ + Integer.toString(bstatus.rssi5)
+ + " boost=" + Integer.toString(bRssiBoost)
);
}
- order = compareWifiConfigurationsFromVisibility(a, aRssiBoost, b, bRssiBoost);
+ order = compareWifiConfigurationsFromVisibility(
+ a.visibility, aRssiBoost, a.configKey(),
+ b.visibility, bRssiBoost, b.configKey());
- // Normalize the order to [-50, +50]
- if (order > 50) order = 50;
- else if (order < -50) order = -50;
+ // Normalize the order to [-50, +50] = [ -MAX_RSSI_DELTA, MAX_RSSI_DELTA]
+ if (order > MAX_RSSI_DELTA) order = MAX_RSSI_DELTA;
+ else if (order < -MAX_RSSI_DELTA) order = -MAX_RSSI_DELTA;
if (VDBG) {
String prefer = " = ";
@@ -750,64 +750,85 @@
/**
* b/18490330 only use scorer for untrusted networks
- *
- int compareWifiConfigurationsWithScorer(WifiConfiguration a, WifiConfiguration b) {
-
- boolean aIsActive = false;
- boolean bIsActive = false;
-
- // Apply Hysteresis : boost RSSI of current configuration before
- // looking up the score
- if (null != mCurrentConfigurationKey) {
- if (a.configKey().equals(mCurrentConfigurationKey)) {
- aIsActive = true;
- } else if (b.configKey().equals(mCurrentConfigurationKey)) {
- bIsActive = true;
- }
- }
- int scoreA = getConfigNetworkScore(a, mScanResultAutoJoinAge, aIsActive);
- int scoreB = getConfigNetworkScore(b, mScanResultAutoJoinAge, bIsActive);
-
- // Both configurations need to have a score for the scorer to be used
- // ...and the scores need to be different:-)
- if (scoreA == WifiNetworkScoreCache.INVALID_NETWORK_SCORE
- || scoreB == WifiNetworkScoreCache.INVALID_NETWORK_SCORE) {
- if (VDBG) {
- logDbg(" compareWifiConfigurationsWithScorer no-scores: "
- + a.configKey()
- + " "
- + b.configKey());
- }
- return 0;
- }
-
- if (VDBG) {
- String prefer = " = ";
- if (scoreA < scoreB) {
- prefer = " < ";
- } if (scoreA > scoreB) {
- prefer = " > ";
- }
- logDbg(" compareWifiConfigurationsWithScorer " + a.configKey()
- + " rssi=(" + a.visibility.rssi24
- + "," + a.visibility.rssi5
- + ") num=(" + a.visibility.num24
- + "," + a.visibility.num5 + ")"
- + " sc=" + scoreA
- + prefer + b.configKey()
- + " rssi=(" + b.visibility.rssi24
- + "," + b.visibility.rssi5
- + ") num=(" + b.visibility.num24
- + "," + b.visibility.num5 + ")"
- + " sc=" + scoreB
- + " -> " + Integer.toString(scoreB - scoreA));
- }
-
- // If scoreA > scoreB, the comparison is descending hence the return value is negative
- return scoreB - scoreA;
- }
+ * <p/>
+ * int compareWifiConfigurationsWithScorer(WifiConfiguration a, WifiConfiguration b) {
+ * <p/>
+ * boolean aIsActive = false;
+ * boolean bIsActive = false;
+ * <p/>
+ * // Apply Hysteresis : boost RSSI of current configuration before
+ * // looking up the score
+ * if (null != mCurrentConfigurationKey) {
+ * if (a.configKey().equals(mCurrentConfigurationKey)) {
+ * aIsActive = true;
+ * } else if (b.configKey().equals(mCurrentConfigurationKey)) {
+ * bIsActive = true;
+ * }
+ * }
+ * int scoreA = getConfigNetworkScore(a, mScanResultAutoJoinAge, aIsActive);
+ * int scoreB = getConfigNetworkScore(b, mScanResultAutoJoinAge, bIsActive);
+ * <p/>
+ * // Both configurations need to have a score for the scorer to be used
+ * // ...and the scores need to be different:-)
+ * if (scoreA == WifiNetworkScoreCache.INVALID_NETWORK_SCORE
+ * || scoreB == WifiNetworkScoreCache.INVALID_NETWORK_SCORE) {
+ * if (VDBG) {
+ * logDbg(" compareWifiConfigurationsWithScorer no-scores: "
+ * + a.configKey()
+ * + " "
+ * + b.configKey());
+ * }
+ * return 0;
+ * }
+ * <p/>
+ * if (VDBG) {
+ * String prefer = " = ";
+ * if (scoreA < scoreB) {
+ * prefer = " < ";
+ * } if (scoreA > scoreB) {
+ * prefer = " > ";
+ * }
+ * logDbg(" compareWifiConfigurationsWithScorer " + a.configKey()
+ * + " rssi=(" + a.visibility.rssi24
+ * + "," + a.visibility.rssi5
+ * + ") num=(" + a.visibility.num24
+ * + "," + a.visibility.num5 + ")"
+ * + " sc=" + scoreA
+ * + prefer + b.configKey()
+ * + " rssi=(" + b.visibility.rssi24
+ * + "," + b.visibility.rssi5
+ * + ") num=(" + b.visibility.num24
+ * + "," + b.visibility.num5 + ")"
+ * + " sc=" + scoreB
+ * + " -> " + Integer.toString(scoreB - scoreA));
+ * }
+ * <p/>
+ * // If scoreA > scoreB, the comparison is descending hence the return value is negative
+ * return scoreB - scoreA;
+ * }
*/
+ int getSecurityScore(WifiConfiguration config) {
+
+ if (TextUtils.isEmpty(config.SSID) == false) {
+ if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP)
+ || config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)
+ || config.allowedKeyManagement.get(KeyMgmt.WPA2_PSK)) {
+ /* enterprise or PSK networks get highest score */
+ return 100;
+ } else if (config.allowedKeyManagement.get(KeyMgmt.NONE)) {
+ /* open networks have lowest score */
+ return 33;
+ }
+ } else if (TextUtils.isEmpty(config.FQDN) == false) {
+ /* passpoint networks have medium preference */
+ return 66;
+ }
+
+ /* bad network */
+ return 0;
+ }
+
int compareWifiConfigurations(WifiConfiguration a, WifiConfiguration b) {
int order = 0;
boolean linked = false;
@@ -845,7 +866,7 @@
if (!linked) {
int choice;
- choice = getConnectChoice(a, b);
+ choice = getConnectChoice(a, b, false);
if (choice > 0) {
// a is of higher priority - descending
order = order - choice;
@@ -861,7 +882,7 @@
}
}
- choice = getConnectChoice(b, a);
+ choice = getConnectChoice(b, a, false);
if (choice > 0) {
// a is of lower priority - ascending
order = order + choice;
@@ -948,13 +969,13 @@
return 0;
}
if (rssi
- > mWifiConfigStore.bandPreferenceBoostThreshold5) {
+ > mWifiConfigStore.bandPreferenceBoostThreshold5.get()) {
// Boost by 2 dB for each point
// Start boosting at -65
// Boost by 20 if above -55
// Boost by 40 if abore -45
int boost = mWifiConfigStore.bandPreferenceBoostFactor5
- *(rssi - mWifiConfigStore.bandPreferenceBoostThreshold5);
+ * (rssi - mWifiConfigStore.bandPreferenceBoostThreshold5.get());
if (boost > 50) {
// 50 dB boost allows jumping from 2.4 to 5GHz
// consistently
@@ -967,38 +988,43 @@
}
if (rssi
- < mWifiConfigStore.bandPreferencePenaltyThreshold5) {
+ < mWifiConfigStore.bandPreferencePenaltyThreshold5.get()) {
// penalize if < -75
int boost = mWifiConfigStore.bandPreferencePenaltyFactor5
- *(rssi - mWifiConfigStore.bandPreferencePenaltyThreshold5);
+ * (rssi - mWifiConfigStore.bandPreferencePenaltyThreshold5.get());
return boost;
}
return 0;
}
- /**
- * attemptRoam() function implements the core of the same SSID switching algorithm
- *
- * Run thru all recent scan result of a WifiConfiguration and select the
- * best one.
- */
+
+ /**
+ * attemptRoam() function implements the core of the same SSID switching algorithm
+ * <p/>
+ * Run thru all recent scan result of a WifiConfiguration and select the
+ * best one.
+ */
public ScanResult attemptRoam(ScanResult a,
WifiConfiguration current, int age, String currentBSSID) {
if (current == null) {
- if (VDBG) {
+ if (VDBG) {
logDbg("attemptRoam not associated");
}
return a;
}
- if (current.scanResultCache == null) {
- if (VDBG) {
+
+ ScanDetailCache scanDetailCache =
+ mWifiConfigStore.getScanDetailCache(current);
+
+ if (scanDetailCache == null) {
+ if (VDBG) {
logDbg("attemptRoam no scan cache");
}
return a;
}
- if (current.scanResultCache.size() > 6) {
- if (VDBG) {
+ if (scanDetailCache.size() > 6) {
+ if (VDBG) {
logDbg("attemptRoam scan cache size "
- + current.scanResultCache.size() + " --> bail");
+ + scanDetailCache.size() + " --> bail");
}
// Implement same SSID roaming only for configurations
// that have less than 4 BSSIDs
@@ -1006,7 +1032,7 @@
}
if (current.BSSID != null && !current.BSSID.equals("any")) {
- if (DBG) {
+ if (DBG) {
logDbg("attemptRoam() BSSID is set "
+ current.BSSID + " -> bail");
}
@@ -1017,13 +1043,14 @@
// relative strength of 5 and 2.4 GHz BSSIDs
long nowMs = System.currentTimeMillis();
- for (ScanResult b : current.scanResultCache.values()) {
+ for (ScanDetail sd : scanDetailCache.values()) {
+ ScanResult b = sd.getScanResult();
int bRssiBoost5 = 0;
int aRssiBoost5 = 0;
int bRssiBoost = 0;
int aRssiBoost = 0;
- if ((b.seen == 0) || (b.BSSID == null)
- || ((nowMs - b.seen) > age)
+ if ((sd.getSeen() == 0) || (b.BSSID == null)
+ || ((nowMs - sd.getSeen()) > age)
|| b.autoJoinStatus != ScanResult.ENABLED
|| b.numIpConfigFailures > 8) {
continue;
@@ -1038,10 +1065,10 @@
if (b.numIpConfigFailures < (a.numIpConfigFailures - 1)) {
// Prefer a BSSID that doesn't have less number of Ip config failures
logDbg("attemptRoam: "
- + b.BSSID + " rssi=" + b.level + " ipfail=" +b.numIpConfigFailures
+ + b.BSSID + " rssi=" + b.level + " ipfail=" + b.numIpConfigFailures
+ " freq=" + b.frequency
+ " > "
- + a.BSSID + " rssi=" + a.level + " ipfail=" +a.numIpConfigFailures
+ + a.BSSID + " rssi=" + a.level + " ipfail=" + a.numIpConfigFailures
+ " freq=" + a.frequency);
a = b;
continue;
@@ -1050,14 +1077,14 @@
// Apply hysteresis: we favor the currentBSSID by giving it a boost
if (currentBSSID != null && currentBSSID.equals(b.BSSID)) {
// Reduce the benefit of hysteresis if RSSI <= -75
- if (b.level <= mWifiConfigStore.bandPreferencePenaltyThreshold5) {
+ if (b.level <= mWifiConfigStore.bandPreferencePenaltyThreshold5.get()) {
bRssiBoost = mWifiConfigStore.associatedHysteresisLow;
} else {
bRssiBoost = mWifiConfigStore.associatedHysteresisHigh;
}
}
if (currentBSSID != null && currentBSSID.equals(a.BSSID)) {
- if (a.level <= mWifiConfigStore.bandPreferencePenaltyThreshold5) {
+ if (a.level <= mWifiConfigStore.bandPreferencePenaltyThreshold5.get()) {
// Reduce the benefit of hysteresis if RSSI <= -75
aRssiBoost = mWifiConfigStore.associatedHysteresisLow;
} else {
@@ -1082,9 +1109,9 @@
aRssiBoost5 = rssiBoostFrom5GHzRssi(a.level + aRssiBoost, a.BSSID);
}
- if (VDBG) {
+ if (VDBG) {
String comp = " < ";
- if (b.level + bRssiBoost + bRssiBoost5 > a.level +aRssiBoost + aRssiBoost5) {
+ if (b.level + bRssiBoost + bRssiBoost5 > a.level + aRssiBoost + aRssiBoost5) {
comp = " > ";
}
logDbg("attemptRoam: "
@@ -1097,13 +1124,13 @@
// Compare the RSSIs after applying the hysteresis boost and the 5GHz
// boost if applicable
- if (b.level + bRssiBoost + bRssiBoost5 > a.level +aRssiBoost + aRssiBoost5) {
+ if (b.level + bRssiBoost + bRssiBoost5 > a.level + aRssiBoost + aRssiBoost5) {
// b is the better BSSID
a = b;
}
}
if (a != null) {
- if (VDBG) {
+ if (VDBG) {
StringBuilder sb = new StringBuilder();
sb.append("attemptRoam: " + current.configKey() +
" Found " + a.BSSID + " rssi=" + a.level + " freq=" + a.frequency);
@@ -1119,9 +1146,9 @@
/**
* getNetworkScore()
- *
+ * <p/>
* if scorer is present, get the network score of a WifiConfiguration
- *
+ * <p/>
* Note: this should be merge with setVisibility
*
* @param config
@@ -1136,7 +1163,8 @@
}
return WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
}
- if (config.scanResultCache == null) {
+
+ if (mWifiConfigStore.getScanDetailCache(config) == null) {
if (VDBG) {
logDbg(" getConfigNetworkScore for " + config.configKey()
+ " -> no scan cache");
@@ -1150,8 +1178,9 @@
int startScore = -10000;
// Run thru all cached scan results
- for (ScanResult result : config.scanResultCache.values()) {
- if ((nowMs - result.seen) < age) {
+ for (ScanDetail sd : mWifiConfigStore.getScanDetailCache(config).values()) {
+ ScanResult result = sd.getScanResult();
+ if ((nowMs - sd.getSeen()) < age) {
int sc = mNetworkScoreCache.getNetworkScore(result, isActive);
if (sc > startScore) {
startScore = sc;
@@ -1204,8 +1233,9 @@
// Otherwise, we stop here if the currently selected network has a score. If it doesn't, we
// keep going - it could be that another BSSID is in range (has been seen recently) which
// has a score, even if the one we're immediately connected to doesn't.
- ScanResult currentScanResult = mWifiStateMachine.getCurrentScanResult();
- boolean currentNetworkHasScoreCurve = mNetworkScoreCache.hasScoreCurve(currentScanResult);
+ ScanResult currentScanResult = mWifiStateMachine.getCurrentScanResult();
+ boolean currentNetworkHasScoreCurve = currentScanResult != null
+ && mNetworkScoreCache.hasScoreCurve(currentScanResult);
if (ephemeralOutOfRangeTimeoutMs <= 0 || currentNetworkHasScoreCurve) {
if (DBG) {
if (currentNetworkHasScoreCurve) {
@@ -1218,14 +1248,16 @@
return currentNetworkHasScoreCurve;
}
- if (config.scanResultCache == null || config.scanResultCache.isEmpty()) {
+ if (mWifiConfigStore.getScanDetailCache(config) == null
+ || mWifiConfigStore.getScanDetailCache(config).isEmpty()) {
return false;
}
long currentTimeMs = System.currentTimeMillis();
- for (ScanResult result : config.scanResultCache.values()) {
- if (currentTimeMs > result.seen
- && currentTimeMs - result.seen < ephemeralOutOfRangeTimeoutMs
+ for (ScanDetail sd : mWifiConfigStore.getScanDetailCache(config).values()) {
+ ScanResult result = sd.getScanResult();
+ if (currentTimeMs > sd.getSeen()
+ && currentTimeMs - sd.getSeen() < ephemeralOutOfRangeTimeoutMs
&& mNetworkScoreCache.hasScoreCurve(result)) {
if (DBG) {
logDbg("Found scored BSSID, keeping network: " + result.BSSID);
@@ -1240,6 +1272,163 @@
return false;
}
+ // After WifiStateMachine ask the supplicant to associate or reconnect
+ // we might still obtain scan results from supplicant
+ // however the supplicant state in the mWifiInfo and supplicant state tracker
+ // are updated when we get the supplicant state change message which can be
+ // processed after the SCAN_RESULT message, so at this point the framework doesn't
+ // know that supplicant is ASSOCIATING.
+ // A good fix for this race condition would be for the WifiStateMachine to add
+ // a new transient state where it expects to get the supplicant message indicating
+ // that it started the association process and within which critical operations
+ // like autojoin should be deleted.
+
+ // This transient state would remove the need for the roam Wathchdog which
+ // basically does that.
+
+ // At the moment, we just query the supplicant state synchronously with the
+ // mWifiNative.status() command, which allow us to know that
+ // supplicant has started association process, even though we didnt yet get the
+ // SUPPLICANT_STATE_CHANGE message.
+
+ private static final List<String> ASSOC_STATES = Arrays.asList(
+ "ASSOCIATING",
+ "ASSOCIATED",
+ "FOUR_WAY_HANDSHAKE",
+ "GROUP_KEY_HANDSHAKE");
+
+ private int getNetID(String wpaStatus) {
+ if (VDBG) {
+ logDbg("attemptAutoJoin() status=" + wpaStatus);
+ }
+
+ try {
+ int id = WifiConfiguration.INVALID_NETWORK_ID;
+ String state = null;
+ BufferedReader br = new BufferedReader(new StringReader(wpaStatus));
+ String line;
+ while ((line = br.readLine()) != null) {
+ int split = line.indexOf('=');
+ if (split < 0) {
+ continue;
+ }
+
+ String name = line.substring(0, split);
+ if (name.equals("id")) {
+ try {
+ id = Integer.parseInt(line.substring(split + 1));
+ if (state != null) {
+ break;
+ }
+ } catch (NumberFormatException nfe) {
+ return WifiConfiguration.INVALID_NETWORK_ID;
+ }
+ } else if (name.equals("wpa_state")) {
+ state = line.substring(split + 1);
+ if (ASSOC_STATES.contains(state)) {
+ return WifiConfiguration.INVALID_NETWORK_ID;
+ } else if (id >= 0) {
+ break;
+ }
+ }
+ }
+ return id;
+ } catch (IOException ioe) {
+ return WifiConfiguration.INVALID_NETWORK_ID; // Won't happen
+ }
+ }
+
+ private boolean setCurrentConfigurationKey(WifiConfiguration currentConfig,
+ int supplicantNetId) {
+ if (currentConfig != null) {
+ if (supplicantNetId != currentConfig.networkId
+ // https://b.corp.google.com/issue?id=16484607
+ // mark this condition as an error only if the mismatched networkId are valid
+ && supplicantNetId != WifiConfiguration.INVALID_NETWORK_ID
+ && currentConfig.networkId != WifiConfiguration.INVALID_NETWORK_ID) {
+ logDbg("attemptAutoJoin() ERROR wpa_supplicant out of sync nid="
+ + Integer.toString(supplicantNetId) + " WifiStateMachine="
+ + Integer.toString(currentConfig.networkId));
+ mWifiStateMachine.disconnectCommand();
+ return false;
+ } else if (currentConfig.ephemeral && (!mAllowUntrustedConnections ||
+ !haveRecentlySeenScoredBssid(currentConfig))) {
+ // The current connection is untrusted (the framework added it), but we're either
+ // no longer allowed to connect to such networks, the score has been nullified
+ // since we connected, or the scored BSSID has gone out of range.
+ // Drop the current connection and perform the rest of autojoin.
+ logDbg("attemptAutoJoin() disconnecting from unwanted ephemeral network");
+ mWifiStateMachine.disconnectCommand(Process.WIFI_UID,
+ mAllowUntrustedConnections ? 1 : 0);
+ return false;
+ } else {
+ mCurrentConfigurationKey = currentConfig.configKey();
+ return true;
+ }
+ } else {
+ // If not invalid, then maybe in the process of associating, skip this attempt
+ return supplicantNetId == WifiConfiguration.INVALID_NETWORK_ID;
+ }
+ }
+
+ private void updateBlackListStatus(WifiConfiguration config, long now) {
+ // Wait for 5 minutes before reenabling config that have known,
+ // repeated connection or DHCP failures
+ if (config.disableReason == WifiConfiguration.DISABLED_DHCP_FAILURE
+ || config.disableReason
+ == WifiConfiguration.DISABLED_ASSOCIATION_REJECT
+ || config.disableReason
+ == WifiConfiguration.DISABLED_AUTH_FAILURE) {
+ if (config.blackListTimestamp == 0
+ || (config.blackListTimestamp > now)) {
+ // Sanitize the timestamp
+ config.blackListTimestamp = now;
+ }
+ if ((now - config.blackListTimestamp) >
+ mWifiConfigStore.wifiConfigBlacklistMinTimeMilli) {
+ // Re-enable the WifiConfiguration
+ config.status = WifiConfiguration.Status.ENABLED;
+
+ // Reset the blacklist condition
+ config.numConnectionFailures = 0;
+ config.numIpConfigFailures = 0;
+ config.numAuthFailures = 0;
+ config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
+
+ config.dirty = true;
+ } else {
+ if (VDBG) {
+ long delay = mWifiConfigStore.wifiConfigBlacklistMinTimeMilli
+ - (now - config.blackListTimestamp);
+ logDbg("attemptautoJoin " + config.configKey()
+ + " dont unblacklist yet, waiting for "
+ + delay + " ms");
+ }
+ }
+ }
+ // Avoid networks disabled because of AUTH failure altogether
+ if (DBG) {
+ logDbg("attemptAutoJoin skip candidate due to auto join status "
+ + Integer.toString(config.autoJoinStatus) + " key "
+ + config.configKey(true)
+ + " reason " + config.disableReason);
+ }
+ }
+
+ boolean underSoftThreshold(WifiConfiguration config) {
+ return config.visibility.rssi24 < mWifiConfigStore.thresholdUnblacklistThreshold24Soft.get()
+ && config.visibility.rssi5 < mWifiConfigStore.thresholdUnblacklistThreshold5Soft.get();
+ }
+
+ boolean underHardThreshold(WifiConfiguration config) {
+ return config.visibility.rssi24 < mWifiConfigStore.thresholdUnblacklistThreshold24Hard.get()
+ && config.visibility.rssi5 < mWifiConfigStore.thresholdUnblacklistThreshold5Hard.get();
+ }
+
+ boolean underThreshold(WifiConfiguration config, int rssi24, int rssi5) {
+ return config.visibility.rssi24 < rssi24 && config.visibility.rssi5 < rssi5;
+ }
+
/**
* attemptAutoJoin() function implements the core of the a network switching algorithm
* Return false if no acceptable networks were found.
@@ -1249,79 +1438,32 @@
didOverride = false;
didBailDueToWeakRssi = false;
int networkSwitchType = AUTO_JOIN_IDLE;
+ int age = mScanResultAutoJoinAge;
long now = System.currentTimeMillis();
String lastSelectedConfiguration = mWifiConfigStore.getLastSelectedConfiguration();
-
+ if (lastSelectedConfiguration != null) {
+ age = 14000;
+ }
// Reset the currentConfiguration Key, and set it only if WifiStateMachine and
// supplicant agree
mCurrentConfigurationKey = null;
WifiConfiguration currentConfiguration = mWifiStateMachine.getCurrentWifiConfiguration();
WifiConfiguration candidate = null;
-
// Obtain the subset of recently seen networks
List<WifiConfiguration> list =
- mWifiConfigStore.getRecentConfiguredNetworks(mScanResultAutoJoinAge, false);
+ mWifiConfigStore.getRecentConfiguredNetworks(age, false);
if (list == null) {
- if (VDBG) logDbg("attemptAutoJoin nothing known=" +
- mWifiConfigStore.getconfiguredNetworkSize());
+ if (VDBG) logDbg("attemptAutoJoin nothing known=" +
+ mWifiConfigStore.getConfiguredNetworksSize());
return false;
}
// Find the currently connected network: ask the supplicant directly
- String val = mWifiNative.status(true);
- String status[] = val.split("\\r?\\n");
- if (VDBG) {
- logDbg("attemptAutoJoin() status=" + val + " split="
- + Integer.toString(status.length));
- }
+ int supplicantNetId = getNetID(mWifiNative.status(true));
- int supplicantNetId = -1;
- for (String key : status) {
- if (key.regionMatches(0, "id=", 0, 3)) {
- int idx = 3;
- supplicantNetId = 0;
- while (idx < key.length()) {
- char c = key.charAt(idx);
-
- if ((c >= 0x30) && (c <= 0x39)) {
- supplicantNetId *= 10;
- supplicantNetId += c - 0x30;
- idx++;
- } else {
- break;
- }
- }
- } else if (key.contains("wpa_state=ASSOCIATING")
- || key.contains("wpa_state=ASSOCIATED")
- || key.contains("wpa_state=FOUR_WAY_HANDSHAKE")
- || key.contains("wpa_state=GROUP_KEY_HANDSHAKE")) {
- if (DBG) {
- logDbg("attemptAutoJoin: bail out due to sup state " + key);
- }
- // After WifiStateMachine ask the supplicant to associate or reconnect
- // we might still obtain scan results from supplicant
- // however the supplicant state in the mWifiInfo and supplicant state tracker
- // are updated when we get the supplicant state change message which can be
- // processed after the SCAN_RESULT message, so at this point the framework doesn't
- // know that supplicant is ASSOCIATING.
- // A good fix for this race condition would be for the WifiStateMachine to add
- // a new transient state where it expects to get the supplicant message indicating
- // that it started the association process and within which critical operations
- // like autojoin should be deleted.
-
- // This transient state would remove the need for the roam Wathchdog which
- // basically does that.
-
- // At the moment, we just query the supplicant state synchronously with the
- // mWifiNative.status() command, which allow us to know that
- // supplicant has started association process, even though we didnt yet get the
- // SUPPLICANT_STATE_CHANGE message.
- return false;
- }
- }
if (DBG) {
String conf = "";
String last = "";
@@ -1336,35 +1478,8 @@
+ " ---> suppNetId=" + Integer.toString(supplicantNetId));
}
- if (currentConfiguration != null) {
- if (supplicantNetId != currentConfiguration.networkId
- // https://b.corp.google.com/issue?id=16484607
- // mark this condition as an error only if the mismatched networkId are valid
- && supplicantNetId != WifiConfiguration.INVALID_NETWORK_ID
- && currentConfiguration.networkId != WifiConfiguration.INVALID_NETWORK_ID) {
- logDbg("attemptAutoJoin() ERROR wpa_supplicant out of sync nid="
- + Integer.toString(supplicantNetId) + " WifiStateMachine="
- + Integer.toString(currentConfiguration.networkId));
- mWifiStateMachine.disconnectCommand();
- return false;
- } else if (currentConfiguration.ephemeral && (!mAllowUntrustedConnections ||
- !haveRecentlySeenScoredBssid(currentConfiguration))) {
- // The current connection is untrusted (the framework added it), but we're either
- // no longer allowed to connect to such networks, the score has been nullified
- // since we connected, or the scored BSSID has gone out of range.
- // Drop the current connection and perform the rest of autojoin.
- logDbg("attemptAutoJoin() disconnecting from unwanted ephemeral network");
- mWifiStateMachine.disconnectCommand(Process.WIFI_UID,
- mAllowUntrustedConnections ? 1 : 0);
- return false;
- } else {
- mCurrentConfigurationKey = currentConfiguration.configKey();
- }
- } else {
- if (supplicantNetId != WifiConfiguration.INVALID_NETWORK_ID) {
- // Maybe in the process of associating, skip this attempt
- return false;
- }
+ if (!setCurrentConfigurationKey(currentConfiguration, supplicantNetId)) {
+ return false;
}
int currentNetId = -1;
@@ -1384,48 +1499,17 @@
continue;
}
- if (config.autoJoinStatus >=
- WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) {
- // Wait for 5 minutes before reenabling config that have known,
- // repeated connection or DHCP failures
- if (config.disableReason == WifiConfiguration.DISABLED_DHCP_FAILURE
- || config.disableReason
- == WifiConfiguration.DISABLED_ASSOCIATION_REJECT
- || config.disableReason
- == WifiConfiguration.DISABLED_AUTH_FAILURE) {
- if (config.blackListTimestamp == 0
- || (config.blackListTimestamp > now)) {
- // Sanitize the timestamp
- config.blackListTimestamp = now;
- }
- if ((now - config.blackListTimestamp) >
- mWifiConfigStore.wifiConfigBlacklistMinTimeMilli) {
- // Re-enable the WifiConfiguration
- config.status = WifiConfiguration.Status.ENABLED;
+ if (config.autoJoinStatus >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) {
+ updateBlackListStatus(config, now);
+ continue;
+ }
- // Reset the blacklist condition
- config.numConnectionFailures = 0;
- config.numIpConfigFailures = 0;
- config.numAuthFailures = 0;
- config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
-
- config.dirty = true;
- } else {
- if (VDBG) {
- long delay = mWifiConfigStore.wifiConfigBlacklistMinTimeMilli
- - (now - config.blackListTimestamp);
- logDbg("attemptautoJoin " + config.configKey()
- + " dont unblacklist yet, waiting for "
- + delay + " ms");
- }
- }
- }
- // Avoid networks disabled because of AUTH failure altogether
+ if (config.userApproved == WifiConfiguration.USER_PENDING ||
+ config.userApproved == WifiConfiguration.USER_BANNED) {
if (DBG) {
- logDbg("attemptAutoJoin skip candidate due to auto join status "
- + Integer.toString(config.autoJoinStatus) + " key "
- + config.configKey(true)
- + " reason " + config.disableReason);
+ logDbg("attemptAutoJoin skip candidate due to user approval status "
+ + WifiConfiguration.userApprovedAsString(config.userApproved) + " key "
+ + config.configKey(true));
}
continue;
}
@@ -1450,42 +1534,29 @@
}
}
+ if (config.visibility == null) {
+ continue;
+ }
+
// Try to unblacklist based on good visibility
- if (config.visibility.rssi5 < mWifiConfigStore.thresholdUnblacklistThreshold5Soft
- && config.visibility.rssi24
- < mWifiConfigStore.thresholdUnblacklistThreshold24Soft) {
+ if (underSoftThreshold(config)) {
if (DBG) {
- logDbg("attemptAutoJoin do not unblacklist due to low visibility "
- + config.autoJoinStatus
- + " key " + config.configKey(true)
- + " rssi=(" + config.visibility.rssi24
- + "," + config.visibility.rssi5
- + ") num=(" + config.visibility.num24
- + "," + config.visibility.num5 + ")");
+ logDbg("attemptAutoJoin do not unblacklist due to low visibility " +
+ config.configKey() + " status=" + config.autoJoinStatus);
}
- } else if (config.visibility.rssi5 < mWifiConfigStore.thresholdUnblacklistThreshold5Hard
- && config.visibility.rssi24
- < mWifiConfigStore.thresholdUnblacklistThreshold24Hard) {
+ } else if (underHardThreshold(config)) {
// If the network is simply temporary disabled, don't allow reconnect until
// RSSI becomes good enough
config.setAutoJoinStatus(config.autoJoinStatus - 1);
if (DBG) {
- logDbg("attemptAutoJoin good candidate seen, bumped soft -> status="
- + config.autoJoinStatus
- + " " + config.configKey(true) + " rssi=("
- + config.visibility.rssi24 + "," + config.visibility.rssi5
- + ") num=(" + config.visibility.num24
- + "," + config.visibility.num5 + ")");
+ logDbg("attemptAutoJoin good candidate seen, bumped soft -> status=" +
+ config.configKey() + " status=" + config.autoJoinStatus);
}
} else {
config.setAutoJoinStatus(config.autoJoinStatus - 3);
if (DBG) {
- logDbg("attemptAutoJoin good candidate seen, bumped hard -> status="
- + config.autoJoinStatus
- + " " + config.configKey(true) + " rssi=("
- + config.visibility.rssi24 + "," + config.visibility.rssi5
- + ") num=(" + config.visibility.num24
- + "," + config.visibility.num5 + ")");
+ logDbg("attemptAutoJoin good candidate seen, bumped hard -> status=" +
+ config.configKey() + " status=" + config.autoJoinStatus);
}
}
@@ -1493,12 +1564,8 @@
WifiConfiguration.AUTO_JOIN_TEMPORARY_DISABLED) {
// Network is blacklisted, skip
if (DBG) {
- logDbg("attemptAutoJoin skip blacklisted -> status="
- + config.autoJoinStatus
- + " " + config.configKey(true) + " rssi=("
- + config.visibility.rssi24 + "," + config.visibility.rssi5
- + ") num=(" + config.visibility.num24
- + "," + config.visibility.num5 + ")");
+ logDbg("attemptAutoJoin skip blacklisted -> status=" +
+ config.configKey() + " status=" + config.autoJoinStatus);
}
continue;
}
@@ -1517,10 +1584,6 @@
isLastSelected = true;
}
- if (config.visibility == null) {
- continue;
- }
-
if (config.lastRoamingFailure != 0
&& currentConfiguration != null
&& (lastSelectedConfiguration == null
@@ -1544,17 +1607,12 @@
}
int boost = config.autoJoinUseAggressiveJoinAttemptThreshold + weakRssiBailCount;
- if ((config.visibility.rssi5 + boost)
- < mWifiConfigStore.thresholdInitialAutoJoinAttemptMin5RSSI
- && (config.visibility.rssi24 + boost)
- < mWifiConfigStore.thresholdInitialAutoJoinAttemptMin24RSSI) {
+ if (underThreshold(config,
+ mWifiConfigStore.thresholdInitialAutoJoinAttemptMin24RSSI.get() - boost,
+ mWifiConfigStore.thresholdInitialAutoJoinAttemptMin5RSSI.get() - boost)) {
+
if (DBG) {
- logDbg("attemptAutoJoin skip due to low visibility -> status="
- + config.autoJoinStatus
- + " key " + config.configKey(true) + " rssi="
- + config.visibility.rssi24 + ", " + config.visibility.rssi5
- + " num=" + config.visibility.num24
- + ", " + config.visibility.num5);
+ logDbg("attemptAutoJoin skip due to low visibility " + config.configKey());
}
// Don't try to autojoin a network that is too far but
@@ -1572,6 +1630,7 @@
}
}
}
+ // NOTE: If this condition is updated, update NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN.
if (config.numNoInternetAccessReports > 0
&& !isLastSelected
&& !config.validatedInternetAccess) {
@@ -1601,11 +1660,15 @@
if (candidate == null) {
candidate = config;
} else {
- if (VDBG) {
+ if (VDBG) {
logDbg("attemptAutoJoin will compare candidate " + candidate.configKey()
+ " with " + config.configKey());
}
+
int order = compareWifiConfigurations(candidate, config);
+ if (VDBG) {
+ logDbg("attemptAutoJoin compareWifiConfigurations returned " + order);
+ }
// The lastSelectedConfiguration is the configuration the user has manually selected
// thru WifiPicker, or that a 3rd party app asked us to connect to via the
@@ -1619,7 +1682,7 @@
// above RSSI/scorer based selection of linked configuration (+/- 50)
// by reducing order by -100
order = order - 100;
- if (VDBG) {
+ if (VDBG) {
logDbg(" ...and prefers -100 " + candidate.configKey()
+ " over " + config.configKey()
+ " because it is the last selected -> "
@@ -1632,7 +1695,7 @@
// above RSSI/scorer based selection of linked configuration (+/- 50)
// by increasing order by +100
order = order + 100;
- if (VDBG) {
+ if (VDBG) {
logDbg(" ...and prefers +100 " + config.configKey()
+ " over " + candidate.configKey()
+ " because it is the last selected -> "
@@ -1660,10 +1723,11 @@
long nowMs = System.currentTimeMillis();
int currentScore = -10000;
// The untrusted network with highest score
- ScanResult untrustedCandidate = null;
+ ScanDetail untrustedCandidate = null;
// Look for untrusted scored network only if the current candidate is bad
if (isBadCandidate(rssi24, rssi5)) {
- for (ScanResult result : scanResultCache.values()) {
+ for (ScanDetail scanDetail : scanResultCache.values()) {
+ ScanResult result = scanDetail.getScanResult();
// We look only at untrusted networks with a valid SSID
// A trusted result would have been looked at thru it's Wificonfiguration
if (TextUtils.isEmpty(result.SSID) || !result.untrusted ||
@@ -1686,13 +1750,13 @@
&& score > currentScore) {
// Highest score: Select this candidate
currentScore = score;
- untrustedCandidate = result;
+ untrustedCandidate = scanDetail;
if (VDBG) {
logDbg("AutoJoinController: found untrusted candidate "
+ result.SSID
- + " RSSI=" + result.level
- + " freq=" + result.frequency
- + " score=" + score);
+ + " RSSI=" + result.level
+ + " freq=" + result.frequency
+ + " score=" + score);
}
}
}
@@ -1705,6 +1769,7 @@
mWifiConfigStore.wifiConfigurationFromScanResult(untrustedCandidate);
candidate.allowedKeyManagement.set(KeyMgmt.NONE);
candidate.ephemeral = true;
+ candidate.dirty = true;
}
}
@@ -1716,7 +1781,7 @@
&& currentConfiguration == null
&& didBailDueToWeakRssi
&& (mWifiConfigStore.lastUnwantedNetworkDisconnectTimestamp == 0
- || lastUnwanted > (1000 * 60 * 60 * 24 * 7))
+ || lastUnwanted > (1000 * 60 * 60 * 24 * 7))
) {
// We are bailing out of autojoin although we are seeing a weak configuration, and
// - we didn't find another valid candidate
@@ -1751,7 +1816,7 @@
+ candidate.configKey()
+ current
+ " linked=" + (currentConfiguration != null
- && currentConfiguration.isLinked(candidate))
+ && currentConfiguration.isLinked(candidate))
+ " : delta="
+ Integer.toString(networkDelta) + " "
+ doSwitch);
@@ -1762,7 +1827,7 @@
* if user is currently streaming voice traffic,
* then we should not be allowed to switch regardless of the delta
*/
- if (mWifiStateMachine.shouldSwitchNetwork(networkDelta)) {
+ if (mWifiStateMachine.shouldSwitchNetwork(networkDelta)) { // !!! JNo: Here!
if (mStaStaSupported) {
logDbg("mStaStaSupported --> error do nothing now ");
} else {
@@ -1818,39 +1883,16 @@
}
}
mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_CONNECT,
- candidate.networkId, networkSwitchType, candidate);
+ candidate.networkId, networkSwitchType, candidate);
found = true;
}
}
- if (networkSwitchType == AUTO_JOIN_IDLE) {
+ if (networkSwitchType == AUTO_JOIN_IDLE && !mWifiConfigStore.enableHalBasedPno.get()) {
String currentBSSID = mWifiStateMachine.getCurrentBSSID();
// Attempt same WifiConfiguration roaming
ScanResult roamCandidate =
attemptRoam(null, currentConfiguration, mScanResultAutoJoinAge, currentBSSID);
- /**
- * TODO: (post L initial release)
- * consider handling linked configurations roaming (i.e. extended Roaming)
- * thru the attemptRoam function which makes use of the RSSI roaming threshold.
- * At the moment, extended roaming is only handled thru the attemptAutoJoin()
- * function which compare configurations.
- *
- * The advantage of making use of attemptRoam function is that this function
- * will looks at all the BSSID of each configurations, instead of only looking
- * at WifiConfiguration.visibility which keeps trackonly of the RSSI/band of the
- * two highest BSSIDs.
- */
- // Attempt linked WifiConfiguration roaming
- /* if (currentConfiguration != null
- && currentConfiguration.linkedConfigurations != null) {
- for (String key : currentConfiguration.linkedConfigurations.keySet()) {
- WifiConfiguration link = mWifiConfigStore.getWifiConfiguration(key);
- if (link != null) {
- roamCandidate = attemptRoam(roamCandidate, link, mScanResultAutoJoinAge,
- currentBSSID);
- }
- }
- }*/
if (roamCandidate != null && currentBSSID != null
&& currentBSSID.equals(roamCandidate.BSSID)) {
roamCandidate = null;
@@ -1867,12 +1909,87 @@
mWifiConnectionStatistics.numAutoRoamAttempt++;
mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_ROAM,
- currentConfiguration.networkId, 1, roamCandidate);
+ currentConfiguration.networkId, 1, roamCandidate);
found = true;
}
}
if (VDBG) logDbg("Done attemptAutoJoin status=" + Integer.toString(networkSwitchType));
return found;
}
+
+ private void logDenial(String reason, WifiConfiguration config) {
+ if (!DBG) {
+ return;
+ }
+ logDbg(reason + config.toString());
+ }
+
+ WifiConfiguration getWifiConfiguration(WifiNative.WifiPnoNetwork network) {
+ if (network.configKey != null) {
+ return mWifiConfigStore.getWifiConfiguration(network.configKey);
+ }
+ return null;
+ }
+
+ ArrayList<WifiNative.WifiPnoNetwork> getPnoList(WifiConfiguration current) {
+ int size = -1;
+ ArrayList<WifiNative.WifiPnoNetwork> list = new ArrayList<WifiNative.WifiPnoNetwork>();
+
+ if (mWifiConfigStore.mCachedPnoList != null) {
+ size = mWifiConfigStore.mCachedPnoList.size();
+ }
+
+ if (DBG) {
+ String s = "";
+ if (current != null) {
+ s = " for: " + current.configKey();
+ }
+ Log.e(TAG, " get Pno List total size:" + size + s);
+ }
+ if (current != null) {
+ String configKey = current.configKey();
+ /**
+ * If we are currently associated to a WifiConfiguration then include
+ * only those networks that have a higher priority
+ */
+ for (WifiNative.WifiPnoNetwork network : mWifiConfigStore.mCachedPnoList) {
+ WifiConfiguration config = getWifiConfiguration(network);
+ if (config == null) {
+ continue;
+ }
+ if (config.autoJoinStatus
+ >= WifiConfiguration.AUTO_JOIN_DISABLED_NO_CREDENTIALS) {
+ continue;
+ }
+
+ if (!configKey.equals(network.configKey)) {
+ int choice = getConnectChoice(config, current, true);
+ if (choice > 0) {
+ // config is of higher priority
+ if (DBG) {
+ Log.e(TAG, " Pno List adding:" + network.configKey
+ + " choice " + choice);
+ }
+ list.add(network);
+ network.rssi_threshold = mWifiConfigStore.thresholdGoodRssi24.get();
+ }
+ }
+ }
+ } else {
+ for (WifiNative.WifiPnoNetwork network : mWifiConfigStore.mCachedPnoList) {
+ WifiConfiguration config = getWifiConfiguration(network);
+ if (config == null) {
+ continue;
+ }
+ if (config.autoJoinStatus
+ >= WifiConfiguration.AUTO_JOIN_DISABLED_NO_CREDENTIALS) {
+ continue;
+ }
+ list.add(network);
+ network.rssi_threshold = mWifiConfigStore.thresholdGoodRssi24.get();
+ }
+ }
+ return list;
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java
index 94752d3..652899e 100644
--- a/service/java/com/android/server/wifi/WifiConfigStore.java
+++ b/service/java/com/android/server/wifi/WifiConfigStore.java
@@ -16,32 +16,34 @@
package com.android.server.wifi;
+import android.app.AppGlobals;
+import android.app.admin.DeviceAdminInfo;
+import android.app.admin.DevicePolicyManagerInternal;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.net.IpConfiguration;
import android.net.IpConfiguration.IpAssignment;
import android.net.IpConfiguration.ProxySettings;
-import android.net.LinkAddress;
import android.net.NetworkInfo.DetailedState;
import android.net.ProxyInfo;
-import android.net.RouteInfo;
import android.net.StaticIpConfiguration;
+import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiConfiguration.Status;
-import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
-
import android.net.wifi.WifiEnterpriseConfig;
+import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiSsid;
import android.net.wifi.WpsInfo;
import android.net.wifi.WpsResult;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiInfo;
-
import android.os.Environment;
import android.os.FileObserver;
import android.os.Process;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
@@ -53,12 +55,24 @@
import android.util.Log;
import android.util.SparseArray;
+import com.android.server.LocalServices;
+import com.android.internal.R;
import com.android.server.net.DelayedDiskWrite;
import com.android.server.net.IpConfigStore;
-import com.android.internal.R;
+import com.android.server.wifi.anqp.ANQPElement;
+import com.android.server.wifi.anqp.Constants;
+import com.android.server.wifi.hotspot2.ANQPData;
+import com.android.server.wifi.hotspot2.AnqpCache;
+import com.android.server.wifi.hotspot2.NetworkDetail;
+import com.android.server.wifi.hotspot2.PasspointMatch;
+import com.android.server.wifi.hotspot2.SupplicantBridge;
+import com.android.server.wifi.hotspot2.Utils;
+import com.android.server.wifi.hotspot2.omadm.MOManager;
+import com.android.server.wifi.hotspot2.pps.Credential;
+import com.android.server.wifi.hotspot2.pps.HomeSP;
-import java.io.BufferedReader;
import java.io.BufferedInputStream;
+import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
@@ -69,19 +83,31 @@
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
-import java.math.BigInteger;
-import java.net.InetAddress;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
-import java.text.SimpleDateFormat;
-import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import java.util.*;
-import java.util.zip.Checksum;
import java.util.zip.CRC32;
+import java.util.zip.Checksum;
+
+import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
+
/**
* This class provides the API to manage configured
@@ -131,16 +157,17 @@
public class WifiConfigStore extends IpConfigStore {
private Context mContext;
- private static final String TAG = "WifiConfigStore";
+ public static final String TAG = "WifiConfigStore";
private static final boolean DBG = true;
private static boolean VDBG = false;
private static boolean VVDBG = false;
private static final String SUPPLICANT_CONFIG_FILE = "/data/misc/wifi/wpa_supplicant.conf";
+ private static final String SUPPLICANT_CONFIG_FILE_BACKUP = SUPPLICANT_CONFIG_FILE + ".tmp";
+ private static final String PPS_FILE = "/data/misc/wifi/PerProviderSubscription.conf";
/* configured networks with network id as the key */
- private HashMap<Integer, WifiConfiguration> mConfiguredNetworks =
- new HashMap<Integer, WifiConfiguration>();
+ private final ConfigurationMap mConfiguredNetworks = new ConfigurationMap();
/* A network id is a unique identifier for a network configured in the
* supplicant. Network ids are generated when the supplicant reads
@@ -149,8 +176,9 @@
* that is generated from SSID and security type of the network. A mapping
* from the generated unique id to network id of the network is needed to
* map supplicant config to IP configuration. */
- private HashMap<Integer, Integer> mNetworkIds =
- new HashMap<Integer, Integer>();
+
+ /* Stores a map of NetworkId to ScanCache */
+ private HashMap<Integer, ScanDetailCache> mScanDetailCaches;
/**
* Framework keeps a list of (the CRC32 hashes of) all SSIDs that where deleted by user,
@@ -180,176 +208,159 @@
"/misc/wifi/autojoinconfig.txt";
/* Network History Keys */
- private static final String SSID_KEY = "SSID: ";
- private static final String CONFIG_KEY = "CONFIG: ";
- private static final String CHOICE_KEY = "CHOICE: ";
- private static final String LINK_KEY = "LINK: ";
- private static final String BSSID_KEY = "BSSID: ";
- private static final String BSSID_KEY_END = "/BSSID: ";
- private static final String RSSI_KEY = "RSSI: ";
- private static final String FREQ_KEY = "FREQ: ";
- private static final String DATE_KEY = "DATE: ";
- private static final String MILLI_KEY = "MILLI: ";
- private static final String BLACKLIST_MILLI_KEY = "BLACKLIST_MILLI: ";
- private static final String NETWORK_ID_KEY = "ID: ";
- private static final String PRIORITY_KEY = "PRIORITY: ";
- private static final String DEFAULT_GW_KEY = "DEFAULT_GW: ";
- private static final String AUTH_KEY = "AUTH: ";
- private static final String SEPARATOR_KEY = "\n";
- private static final String STATUS_KEY = "AUTO_JOIN_STATUS: ";
- private static final String BSSID_STATUS_KEY = "BSSID_STATUS: ";
- private static final String SELF_ADDED_KEY = "SELF_ADDED: ";
- private static final String FAILURE_KEY = "FAILURE: ";
- private static final String DID_SELF_ADD_KEY = "DID_SELF_ADD: ";
- private static final String PEER_CONFIGURATION_KEY = "PEER_CONFIGURATION: ";
- private static final String CREATOR_UID_KEY = "CREATOR_UID_KEY: ";
- private static final String CONNECT_UID_KEY = "CONNECT_UID_KEY: ";
- private static final String UPDATE_UID_KEY = "UPDATE_UID: ";
- private static final String SUPPLICANT_STATUS_KEY = "SUP_STATUS: ";
- private static final String SUPPLICANT_DISABLE_REASON_KEY = "SUP_DIS_REASON: ";
- private static final String FQDN_KEY = "FQDN: ";
- private static final String NUM_CONNECTION_FAILURES_KEY = "CONNECT_FAILURES: ";
- private static final String NUM_IP_CONFIG_FAILURES_KEY = "IP_CONFIG_FAILURES: ";
- private static final String NUM_AUTH_FAILURES_KEY = "AUTH_FAILURES: ";
- private static final String SCORER_OVERRIDE_KEY = "SCORER_OVERRIDE: ";
- private static final String SCORER_OVERRIDE_AND_SWITCH_KEY = "SCORER_OVERRIDE_AND_SWITCH: ";
- private static final String VALIDATED_INTERNET_ACCESS_KEY = "VALIDATED_INTERNET_ACCESS: ";
- private static final String NO_INTERNET_ACCESS_REPORTS_KEY = "NO_INTERNET_ACCESS_REPORTS : ";
- private static final String EPHEMERAL_KEY = "EPHEMERAL: ";
- private static final String NUM_ASSOCIATION_KEY = "NUM_ASSOCIATION: ";
- private static final String DELETED_CRC32_KEY = "DELETED_CRC32: ";
- private static final String DELETED_EPHEMERAL_KEY = "DELETED_EPHEMERAL: ";
+ private static final String SSID_KEY = "SSID";
+ private static final String CONFIG_KEY = "CONFIG";
+ private static final String CHOICE_KEY = "CHOICE";
+ private static final String LINK_KEY = "LINK";
+ private static final String BSSID_KEY = "BSSID";
+ private static final String BSSID_KEY_END = "/BSSID";
+ private static final String RSSI_KEY = "RSSI";
+ private static final String FREQ_KEY = "FREQ";
+ private static final String DATE_KEY = "DATE";
+ private static final String MILLI_KEY = "MILLI";
+ private static final String BLACKLIST_MILLI_KEY = "BLACKLIST_MILLI";
+ private static final String NETWORK_ID_KEY = "ID";
+ private static final String PRIORITY_KEY = "PRIORITY";
+ private static final String DEFAULT_GW_KEY = "DEFAULT_GW";
+ private static final String AUTH_KEY = "AUTH";
+ private static final String STATUS_KEY = "AUTO_JOIN_STATUS";
+ private static final String BSSID_STATUS_KEY = "BSSID_STATUS";
+ private static final String SELF_ADDED_KEY = "SELF_ADDED";
+ private static final String FAILURE_KEY = "FAILURE";
+ private static final String DID_SELF_ADD_KEY = "DID_SELF_ADD";
+ private static final String PEER_CONFIGURATION_KEY = "PEER_CONFIGURATION";
+ private static final String CREATOR_UID_KEY = "CREATOR_UID_KEY";
+ private static final String CONNECT_UID_KEY = "CONNECT_UID_KEY";
+ private static final String UPDATE_UID_KEY = "UPDATE_UID";
+ private static final String SUPPLICANT_STATUS_KEY = "SUP_STATUS";
+ private static final String SUPPLICANT_DISABLE_REASON_KEY = "SUP_DIS_REASON";
+ private static final String FQDN_KEY = "FQDN";
+ private static final String NUM_CONNECTION_FAILURES_KEY = "CONNECT_FAILURES";
+ private static final String NUM_IP_CONFIG_FAILURES_KEY = "IP_CONFIG_FAILURES";
+ private static final String NUM_AUTH_FAILURES_KEY = "AUTH_FAILURES";
+ private static final String SCORER_OVERRIDE_KEY = "SCORER_OVERRIDE";
+ private static final String SCORER_OVERRIDE_AND_SWITCH_KEY = "SCORER_OVERRIDE_AND_SWITCH";
+ private static final String VALIDATED_INTERNET_ACCESS_KEY = "VALIDATED_INTERNET_ACCESS";
+ private static final String NO_INTERNET_ACCESS_REPORTS_KEY = "NO_INTERNET_ACCESS_REPORTS";
+ private static final String EPHEMERAL_KEY = "EPHEMERAL";
+ private static final String NUM_ASSOCIATION_KEY = "NUM_ASSOCIATION";
+ private static final String DELETED_CRC32_KEY = "DELETED_CRC32";
+ private static final String DELETED_EPHEMERAL_KEY = "DELETED_EPHEMERAL";
+ private static final String JOIN_ATTEMPT_BOOST_KEY = "JOIN_ATTEMPT_BOOST";
+ private static final String CREATOR_NAME_KEY = "CREATOR_NAME";
+ private static final String UPDATE_NAME_KEY = "UPDATE_NAME";
+ private static final String USER_APPROVED_KEY = "USER_APPROVED";
+ private static final String CREATION_TIME_KEY = "CREATION_TIME";
+ private static final String UPDATE_TIME_KEY = "UPDATE_TIME";
- private static final String JOIN_ATTEMPT_BOOST_KEY = "JOIN_ATTEMPT_BOOST: ";
+ private static final String SEPARATOR = ": ";
+ private static final String NL = "\n";
+
private static final String THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_5G_KEY
- = "THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_5G: ";
+ = "THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_5G";
private static final String THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_24G_KEY
- = "THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_24G: ";
+ = "THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_24G";
private static final String THRESHOLD_UNBLACKLIST_HARD_5G_KEY
- = "THRESHOLD_UNBLACKLIST_HARD_5G: ";
+ = "THRESHOLD_UNBLACKLIST_HARD_5G";
private static final String THRESHOLD_UNBLACKLIST_SOFT_5G_KEY
- = "THRESHOLD_UNBLACKLIST_SOFT_5G: ";
+ = "THRESHOLD_UNBLACKLIST_SOFT_5G";
private static final String THRESHOLD_UNBLACKLIST_HARD_24G_KEY
- = "THRESHOLD_UNBLACKLIST_HARD_24G: ";
+ = "THRESHOLD_UNBLACKLIST_HARD_24G";
private static final String THRESHOLD_UNBLACKLIST_SOFT_24G_KEY
- = "THRESHOLD_UNBLACKLIST_SOFT_24G: ";
+ = "THRESHOLD_UNBLACKLIST_SOFT_24G";
private static final String THRESHOLD_GOOD_RSSI_5_KEY
- = "THRESHOLD_GOOD_RSSI_5: ";
+ = "THRESHOLD_GOOD_RSSI_5";
private static final String THRESHOLD_LOW_RSSI_5_KEY
- = "THRESHOLD_LOW_RSSI_5: ";
+ = "THRESHOLD_LOW_RSSI_5";
private static final String THRESHOLD_BAD_RSSI_5_KEY
- = "THRESHOLD_BAD_RSSI_5: ";
+ = "THRESHOLD_BAD_RSSI_5";
private static final String THRESHOLD_GOOD_RSSI_24_KEY
- = "THRESHOLD_GOOD_RSSI_24: ";
+ = "THRESHOLD_GOOD_RSSI_24";
private static final String THRESHOLD_LOW_RSSI_24_KEY
- = "THRESHOLD_LOW_RSSI_24: ";
+ = "THRESHOLD_LOW_RSSI_24";
private static final String THRESHOLD_BAD_RSSI_24_KEY
- = "THRESHOLD_BAD_RSSI_24: ";
+ = "THRESHOLD_BAD_RSSI_24";
private static final String THRESHOLD_MAX_TX_PACKETS_FOR_NETWORK_SWITCHING_KEY
- = "THRESHOLD_MAX_TX_PACKETS_FOR_NETWORK_SWITCHING: ";
+ = "THRESHOLD_MAX_TX_PACKETS_FOR_NETWORK_SWITCHING";
private static final String THRESHOLD_MAX_RX_PACKETS_FOR_NETWORK_SWITCHING_KEY
- = "THRESHOLD_MAX_RX_PACKETS_FOR_NETWORK_SWITCHING: ";
+ = "THRESHOLD_MAX_RX_PACKETS_FOR_NETWORK_SWITCHING";
private static final String THRESHOLD_MAX_TX_PACKETS_FOR_FULL_SCANS_KEY
- = "THRESHOLD_MAX_TX_PACKETS_FOR_FULL_SCANS: ";
+ = "THRESHOLD_MAX_TX_PACKETS_FOR_FULL_SCANS";
private static final String THRESHOLD_MAX_RX_PACKETS_FOR_FULL_SCANS_KEY
- = "THRESHOLD_MAX_RX_PACKETS_FOR_FULL_SCANS: ";
+ = "THRESHOLD_MAX_RX_PACKETS_FOR_FULL_SCANS";
private static final String THRESHOLD_MAX_TX_PACKETS_FOR_PARTIAL_SCANS_KEY
- = "THRESHOLD_MAX_TX_PACKETS_FOR_PARTIAL_SCANS: ";
+ = "THRESHOLD_MAX_TX_PACKETS_FOR_PARTIAL_SCANS";
private static final String THRESHOLD_MAX_RX_PACKETS_FOR_PARTIAL_SCANS_KEY
- = "THRESHOLD_MAX_RX_PACKETS_FOR_PARTIAL_SCANS: ";
+ = "THRESHOLD_MAX_RX_PACKETS_FOR_PARTIAL_SCANS";
private static final String MAX_NUM_ACTIVE_CHANNELS_FOR_PARTIAL_SCANS_KEY
- = "MAX_NUM_ACTIVE_CHANNELS_FOR_PARTIAL_SCANS: ";
+ = "MAX_NUM_ACTIVE_CHANNELS_FOR_PARTIAL_SCANS";
private static final String MAX_NUM_PASSIVE_CHANNELS_FOR_PARTIAL_SCANS_KEY
- = "MAX_NUM_PASSIVE_CHANNELS_FOR_PARTIAL_SCANS: ";
+ = "MAX_NUM_PASSIVE_CHANNELS_FOR_PARTIAL_SCANS";
private static final String A_BAND_PREFERENCE_RSSI_THRESHOLD_LOW_KEY =
- "A_BAND_PREFERENCE_RSSI_THRESHOLD_LOW: ";
+ "A_BAND_PREFERENCE_RSSI_THRESHOLD_LOW";
private static final String A_BAND_PREFERENCE_RSSI_THRESHOLD_KEY =
- "A_BAND_PREFERENCE_RSSI_THRESHOLD: ";
+ "A_BAND_PREFERENCE_RSSI_THRESHOLD";
private static final String G_BAND_PREFERENCE_RSSI_THRESHOLD_KEY =
- "G_BAND_PREFERENCE_RSSI_THRESHOLD: ";
+ "G_BAND_PREFERENCE_RSSI_THRESHOLD";
private static final String ENABLE_AUTOJOIN_WHILE_ASSOCIATED_KEY
= "ENABLE_AUTOJOIN_WHILE_ASSOCIATED: ";
private static final String ASSOCIATED_PARTIAL_SCAN_PERIOD_KEY
- = "ASSOCIATED_PARTIAL_SCAN_PERIOD: ";
+ = "ASSOCIATED_PARTIAL_SCAN_PERIOD";
private static final String ASSOCIATED_FULL_SCAN_BACKOFF_KEY
- = "ASSOCIATED_FULL_SCAN_BACKOFF_PERIOD: ";
+ = "ASSOCIATED_FULL_SCAN_BACKOFF_PERIOD";
private static final String ALWAYS_ENABLE_SCAN_WHILE_ASSOCIATED_KEY
- = "ALWAYS_ENABLE_SCAN_WHILE_ASSOCIATED: ";
+ = "ALWAYS_ENABLE_SCAN_WHILE_ASSOCIATED";
private static final String ONLY_LINK_SAME_CREDENTIAL_CONFIGURATIONS_KEY
- = "ONLY_LINK_SAME_CREDENTIAL_CONFIGURATIONS: ";
+ = "ONLY_LINK_SAME_CREDENTIAL_CONFIGURATIONS";
private static final String ENABLE_FULL_BAND_SCAN_WHEN_ASSOCIATED_KEY
- = "ENABLE_FULL_BAND_SCAN_WHEN_ASSOCIATED: ";
+ = "ENABLE_FULL_BAND_SCAN_WHEN_ASSOCIATED";
+
+ private static final String ENABLE_HAL_BASED_PNO
+ = "ENABLE_HAL_BASED_PNO";
// The three below configurations are mainly for power stats and CPU usage tracking
// allowing to incrementally disable framework features
- private static final String ENABLE_AUTO_JOIN_SCAN_WHILE_ASSOCIATED_KEY
- = "ENABLE_AUTO_JOIN_SCAN_WHILE_ASSOCIATED: ";
private static final String ENABLE_AUTO_JOIN_WHILE_ASSOCIATED_KEY
- = "ENABLE_AUTO_JOIN_WHILE_ASSOCIATED: ";
+ = "ENABLE_AUTO_JOIN_WHILE_ASSOCIATED";
private static final String ENABLE_CHIP_WAKE_UP_WHILE_ASSOCIATED_KEY
- = "ENABLE_CHIP_WAKE_UP_WHILE_ASSOCIATED: ";
+ = "ENABLE_CHIP_WAKE_UP_WHILE_ASSOCIATED";
private static final String ENABLE_RSSI_POLL_WHILE_ASSOCIATED_KEY
- = "ENABLE_RSSI_POLL_WHILE_ASSOCIATED_KEY: ";
+ = "ENABLE_RSSI_POLL_WHILE_ASSOCIATED_KEY";
+
+ public static final String idStringVarName = "id_str";
// The Wifi verbose log is provided as a way to persist the verbose logging settings
// for testing purpose.
// It is not intended for normal use.
private static final String WIFI_VERBOSE_LOGS_KEY
- = "WIFI_VERBOSE_LOGS: ";
+ = "WIFI_VERBOSE_LOGS";
// As we keep deleted PSK WifiConfiguration for a while, the PSK of
// those deleted WifiConfiguration is set to this random unused PSK
private static final String DELETED_CONFIG_PSK = "Mjkd86jEMGn79KhKll298Uu7-deleted";
- public boolean enableAutoJoinScanWhenAssociated = true;
- public boolean enableAutoJoinWhenAssociated = true;
- public boolean enableChipWakeUpWhenAssociated = true;
- public boolean enableRssiPollWhenAssociated = true;
-
- public int maxTxPacketForNetworkSwitching = 40;
- public int maxRxPacketForNetworkSwitching = 80;
-
public int maxTxPacketForFullScans = 8;
public int maxRxPacketForFullScans = 16;
public int maxTxPacketForPartialScans = 40;
public int maxRxPacketForPartialScans = 80;
- public boolean enableFullBandScanWhenAssociated = true;
-
- public int thresholdInitialAutoJoinAttemptMin5RSSI
- = WifiConfiguration.INITIAL_AUTO_JOIN_ATTEMPT_MIN_5;
- public int thresholdInitialAutoJoinAttemptMin24RSSI
- = WifiConfiguration.INITIAL_AUTO_JOIN_ATTEMPT_MIN_24;
-
- public int thresholdBadRssi5 = WifiConfiguration.BAD_RSSI_5;
- public int thresholdLowRssi5 = WifiConfiguration.LOW_RSSI_5;
- public int thresholdGoodRssi5 = WifiConfiguration.GOOD_RSSI_5;
- public int thresholdBadRssi24 = WifiConfiguration.BAD_RSSI_24;
- public int thresholdLowRssi24 = WifiConfiguration.LOW_RSSI_24;
- public int thresholdGoodRssi24 = WifiConfiguration.GOOD_RSSI_24;
-
- public int associatedFullScanBackoff = 12; // Will be divided by 8 by WifiStateMachine
public int associatedFullScanMaxIntervalMilli = 300000;
- public int associatedPartialScanPeriodMilli;
-
// Sane value for roam blacklisting (not switching to a network if already associated)
// 2 days
public int networkSwitchingBlackListPeriodMilli = 2 * 24 * 60 * 60 * 1000;
public int bandPreferenceBoostFactor5 = 5; // Boost by 5 dB per dB above threshold
public int bandPreferencePenaltyFactor5 = 2; // Penalize by 2 dB per dB below threshold
- public int bandPreferencePenaltyThreshold5 = WifiConfiguration.G_BAND_PREFERENCE_RSSI_THRESHOLD;
- public int bandPreferenceBoostThreshold5 = WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD;
public int badLinkSpeed24 = 6;
public int badLinkSpeed5 = 12;
@@ -367,22 +378,8 @@
public int associatedHysteresisHigh = +14;
public int associatedHysteresisLow = +8;
- public int thresholdUnblacklistThreshold5Hard
- = WifiConfiguration.UNBLACKLIST_THRESHOLD_5_HARD;
- public int thresholdUnblacklistThreshold5Soft
- = WifiConfiguration.UNBLACKLIST_THRESHOLD_5_SOFT;
- public int thresholdUnblacklistThreshold24Hard
- = WifiConfiguration.UNBLACKLIST_THRESHOLD_24_HARD;
- public int thresholdUnblacklistThreshold24Soft
- = WifiConfiguration.UNBLACKLIST_THRESHOLD_24_SOFT;
- public int enableVerboseLogging = 0;
boolean showNetworks = true; // TODO set this back to false, used for debugging 17516271
- public int alwaysEnableScansWhileAssociated = 0;
-
- public int maxNumActiveChannelsForPartialScans = 6;
- public int maxNumPassiveChannelsForPartialScans = 2;
-
public boolean roamOnAny = false;
public boolean onlyLinkSameCredentialConfigurations = true;
@@ -395,6 +392,51 @@
public static final int maxNumScanCacheEntries = 128;
+ public final AtomicBoolean enableHalBasedPno = new AtomicBoolean(true);
+ public final AtomicBoolean enableSsidWhitelist = new AtomicBoolean(true);
+ public final AtomicBoolean enableAutoJoinWhenAssociated = new AtomicBoolean(true);
+ public final AtomicBoolean enableFullBandScanWhenAssociated = new AtomicBoolean(true);
+ public final AtomicBoolean enableChipWakeUpWhenAssociated = new AtomicBoolean(true);
+ public final AtomicBoolean enableRssiPollWhenAssociated = new AtomicBoolean(true);
+ public final AtomicInteger thresholdInitialAutoJoinAttemptMin5RSSI =
+ new AtomicInteger(WifiConfiguration.INITIAL_AUTO_JOIN_ATTEMPT_MIN_5);
+ public final AtomicInteger thresholdInitialAutoJoinAttemptMin24RSSI =
+ new AtomicInteger(WifiConfiguration.INITIAL_AUTO_JOIN_ATTEMPT_MIN_24);
+ public final AtomicInteger thresholdUnblacklistThreshold5Hard
+ = new AtomicInteger(WifiConfiguration.UNBLACKLIST_THRESHOLD_5_HARD);
+ public final AtomicInteger thresholdUnblacklistThreshold5Soft
+ = new AtomicInteger(WifiConfiguration.UNBLACKLIST_THRESHOLD_5_SOFT);
+ public final AtomicInteger thresholdUnblacklistThreshold24Hard
+ = new AtomicInteger(WifiConfiguration.UNBLACKLIST_THRESHOLD_24_HARD);
+ public final AtomicInteger thresholdUnblacklistThreshold24Soft
+ = new AtomicInteger(WifiConfiguration.UNBLACKLIST_THRESHOLD_24_SOFT);
+ public final AtomicInteger thresholdGoodRssi5 =
+ new AtomicInteger(WifiConfiguration.GOOD_RSSI_5);
+ public final AtomicInteger thresholdLowRssi5 = new AtomicInteger(WifiConfiguration.LOW_RSSI_5);
+ public final AtomicInteger thresholdBadRssi5 = new AtomicInteger(WifiConfiguration.BAD_RSSI_5);
+ public final AtomicInteger thresholdGoodRssi24 =
+ new AtomicInteger(WifiConfiguration.GOOD_RSSI_24);
+ public final AtomicInteger thresholdLowRssi24 = new AtomicInteger(WifiConfiguration.LOW_RSSI_24);
+ public final AtomicInteger thresholdBadRssi24 = new AtomicInteger(WifiConfiguration.BAD_RSSI_24);
+ public final AtomicInteger maxTxPacketForNetworkSwitching = new AtomicInteger(40);
+ public final AtomicInteger maxRxPacketForNetworkSwitching = new AtomicInteger(80);
+ public final AtomicInteger enableVerboseLogging = new AtomicInteger(0);
+ public final AtomicInteger bandPreferenceBoostThreshold5 =
+ new AtomicInteger(WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD);
+ public final AtomicInteger associatedFullScanBackoff =
+ new AtomicInteger(12); // Will be divided by 8 by WifiStateMachine
+ public final AtomicInteger bandPreferencePenaltyThreshold5 =
+ new AtomicInteger(WifiConfiguration.G_BAND_PREFERENCE_RSSI_THRESHOLD);
+ public final AtomicInteger alwaysEnableScansWhileAssociated = new AtomicInteger(0);
+ public final AtomicInteger maxNumPassiveChannelsForPartialScans = new AtomicInteger(2);
+ public final AtomicInteger maxNumActiveChannelsForPartialScans = new AtomicInteger(6);
+ public final AtomicInteger wifiDisconnectedShortScanIntervalMilli = new AtomicInteger(15000);
+ public final AtomicInteger wifiDisconnectedLongScanIntervalMilli = new AtomicInteger(120000);
+ public final AtomicInteger wifiAssociatedShortScanIntervalMilli = new AtomicInteger(20000);
+ public final AtomicInteger wifiAssociatedLongScanIntervalMilli = new AtomicInteger(180000);
+
+ private static final Map<String, Object> sKeyMap = new HashMap<>();
+
/**
* Regex pattern for extracting a connect choice.
* Matches a strings like the following:
@@ -426,7 +468,9 @@
WifiEnterpriseConfig.PASSWORD_KEY, WifiEnterpriseConfig.CLIENT_CERT_KEY,
WifiEnterpriseConfig.CA_CERT_KEY, WifiEnterpriseConfig.SUBJECT_MATCH_KEY,
WifiEnterpriseConfig.ENGINE_KEY, WifiEnterpriseConfig.ENGINE_ID_KEY,
- WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY };
+ WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY,
+ WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY
+ };
/**
@@ -460,9 +504,70 @@
*/
private String lastSelectedConfiguration = null;
- WifiConfigStore(Context c, WifiNative wn) {
+ /**
+ * Cached PNO list, it is updated when WifiConfiguration changes due to user input.
+ */
+ ArrayList<WifiNative.WifiPnoNetwork> mCachedPnoList
+ = new ArrayList<WifiNative.WifiPnoNetwork>();
+
+ /*
+ * BSSID blacklist, i.e. list of BSSID we want to avoid
+ */
+ HashSet<String> mBssidBlacklist = new HashSet<String>();
+
+ /*
+ * Lost config list, whenever we read a config from networkHistory.txt that was not in
+ * wpa_supplicant.conf
+ */
+ HashSet<String> mLostConfigsDbg = new HashSet<String>();
+
+ private final AnqpCache mAnqpCache;
+ private final SupplicantBridge mSupplicantBridge;
+ private final MOManager mMOManager;
+ private final SIMAccessor mSIMAccessor;
+
+ private WifiStateMachine mWifiStateMachine;
+
+ WifiConfigStore(Context c, WifiStateMachine w, WifiNative wn) {
mContext = c;
mWifiNative = wn;
+ mWifiStateMachine = w;
+
+ // A map for value setting in readAutoJoinConfig() - replacing the replicated code.
+ sKeyMap.put(ENABLE_AUTO_JOIN_WHILE_ASSOCIATED_KEY, enableAutoJoinWhenAssociated);
+ sKeyMap.put(ENABLE_FULL_BAND_SCAN_WHEN_ASSOCIATED_KEY, enableFullBandScanWhenAssociated);
+ sKeyMap.put(ENABLE_CHIP_WAKE_UP_WHILE_ASSOCIATED_KEY, enableChipWakeUpWhenAssociated);
+ sKeyMap.put(ENABLE_RSSI_POLL_WHILE_ASSOCIATED_KEY, enableRssiPollWhenAssociated);
+ sKeyMap.put(THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_5G_KEY, thresholdInitialAutoJoinAttemptMin5RSSI);
+ sKeyMap.put(THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_24G_KEY, thresholdInitialAutoJoinAttemptMin24RSSI);
+ sKeyMap.put(THRESHOLD_UNBLACKLIST_HARD_5G_KEY, thresholdUnblacklistThreshold5Hard);
+ sKeyMap.put(THRESHOLD_UNBLACKLIST_SOFT_5G_KEY, thresholdUnblacklistThreshold5Soft);
+ sKeyMap.put(THRESHOLD_UNBLACKLIST_HARD_24G_KEY, thresholdUnblacklistThreshold24Hard);
+ sKeyMap.put(THRESHOLD_UNBLACKLIST_SOFT_24G_KEY, thresholdUnblacklistThreshold24Soft);
+ sKeyMap.put(THRESHOLD_GOOD_RSSI_5_KEY, thresholdGoodRssi5);
+ sKeyMap.put(THRESHOLD_LOW_RSSI_5_KEY, thresholdLowRssi5);
+ sKeyMap.put(THRESHOLD_BAD_RSSI_5_KEY, thresholdBadRssi5);
+ sKeyMap.put(THRESHOLD_GOOD_RSSI_24_KEY, thresholdGoodRssi24);
+ sKeyMap.put(THRESHOLD_LOW_RSSI_24_KEY, thresholdLowRssi24);
+ sKeyMap.put(THRESHOLD_BAD_RSSI_24_KEY, thresholdBadRssi24);
+ sKeyMap.put(THRESHOLD_MAX_TX_PACKETS_FOR_NETWORK_SWITCHING_KEY, maxTxPacketForNetworkSwitching);
+ sKeyMap.put(THRESHOLD_MAX_RX_PACKETS_FOR_NETWORK_SWITCHING_KEY, maxRxPacketForNetworkSwitching);
+ sKeyMap.put(THRESHOLD_MAX_TX_PACKETS_FOR_FULL_SCANS_KEY, maxTxPacketForNetworkSwitching);
+ sKeyMap.put(THRESHOLD_MAX_RX_PACKETS_FOR_FULL_SCANS_KEY, maxRxPacketForNetworkSwitching);
+ sKeyMap.put(THRESHOLD_MAX_TX_PACKETS_FOR_PARTIAL_SCANS_KEY, maxTxPacketForNetworkSwitching);
+ sKeyMap.put(THRESHOLD_MAX_RX_PACKETS_FOR_PARTIAL_SCANS_KEY, maxRxPacketForNetworkSwitching);
+ sKeyMap.put(WIFI_VERBOSE_LOGS_KEY, enableVerboseLogging);
+ sKeyMap.put(A_BAND_PREFERENCE_RSSI_THRESHOLD_KEY, bandPreferenceBoostThreshold5);
+ sKeyMap.put(ASSOCIATED_PARTIAL_SCAN_PERIOD_KEY, wifiAssociatedShortScanIntervalMilli);
+ sKeyMap.put(ASSOCIATED_PARTIAL_SCAN_PERIOD_KEY, wifiAssociatedShortScanIntervalMilli);
+
+ sKeyMap.put(ASSOCIATED_FULL_SCAN_BACKOFF_KEY, associatedFullScanBackoff);
+ sKeyMap.put(G_BAND_PREFERENCE_RSSI_THRESHOLD_KEY, bandPreferencePenaltyThreshold5);
+ sKeyMap.put(ALWAYS_ENABLE_SCAN_WHILE_ASSOCIATED_KEY, alwaysEnableScansWhileAssociated);
+ sKeyMap.put(MAX_NUM_PASSIVE_CHANNELS_FOR_PARTIAL_SCANS_KEY, maxNumPassiveChannelsForPartialScans);
+ sKeyMap.put(MAX_NUM_ACTIVE_CHANNELS_FOR_PARTIAL_SCANS_KEY, maxNumActiveChannelsForPartialScans);
+ sKeyMap.put(ENABLE_HAL_BASED_PNO, enableHalBasedPno);
+ sKeyMap.put(ENABLE_HAL_BASED_PNO, enableSsidWhitelist);
if (showNetworks) {
mLocalLog = mWifiNative.getLocalLog();
@@ -473,20 +578,25 @@
mFileObserver = null;
}
- associatedPartialScanPeriodMilli = mContext.getResources().getInteger(
- R.integer.config_wifi_framework_associated_scan_interval);
- loge("associatedPartialScanPeriodMilli set to " + associatedPartialScanPeriodMilli);
+ wifiAssociatedShortScanIntervalMilli.set(mContext.getResources().getInteger(
+ R.integer.config_wifi_associated_short_scan_interval));
+ wifiAssociatedLongScanIntervalMilli.set(mContext.getResources().getInteger(
+ R.integer.config_wifi_associated_short_scan_interval));
+ wifiDisconnectedShortScanIntervalMilli.set(mContext.getResources().getInteger(
+ R.integer.config_wifi_disconnected_short_scan_interval));
+ wifiDisconnectedLongScanIntervalMilli.set(mContext.getResources().getInteger(
+ R.integer.config_wifi_disconnected_long_scan_interval));
onlyLinkSameCredentialConfigurations = mContext.getResources().getBoolean(
R.bool.config_wifi_only_link_same_credential_configurations);
- maxNumActiveChannelsForPartialScans = mContext.getResources().getInteger(
- R.integer.config_wifi_framework_associated_partial_scan_max_num_active_channels);
- maxNumPassiveChannelsForPartialScans = mContext.getResources().getInteger(
- R.integer.config_wifi_framework_associated_partial_scan_max_num_passive_channels);
+ maxNumActiveChannelsForPartialScans.set(mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_associated_partial_scan_max_num_active_channels));
+ maxNumPassiveChannelsForPartialScans.set(mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_associated_partial_scan_max_num_passive_channels));
associatedFullScanMaxIntervalMilli = mContext.getResources().getInteger(
R.integer.config_wifi_framework_associated_full_scan_max_interval);
- associatedFullScanBackoff = mContext.getResources().getInteger(
- R.integer.config_wifi_framework_associated_full_scan_backoff);
+ associatedFullScanBackoff.set(mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_associated_full_scan_backoff));
enableLinkDebouncing = mContext.getResources().getBoolean(
R.bool.config_wifi_enable_disconnection_debounce);
@@ -498,28 +608,28 @@
bandPreferencePenaltyFactor5 = mContext.getResources().getInteger(
R.integer.config_wifi_framework_5GHz_preference_penalty_factor);
- bandPreferencePenaltyThreshold5 = mContext.getResources().getInteger(
- R.integer.config_wifi_framework_5GHz_preference_penalty_threshold);
- bandPreferenceBoostThreshold5 = mContext.getResources().getInteger(
- R.integer.config_wifi_framework_5GHz_preference_boost_threshold);
+ bandPreferencePenaltyThreshold5.set(mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_5GHz_preference_penalty_threshold));
+ bandPreferenceBoostThreshold5.set(mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_5GHz_preference_boost_threshold));
associatedHysteresisHigh = mContext.getResources().getInteger(
R.integer.config_wifi_framework_current_association_hysteresis_high);
associatedHysteresisLow = mContext.getResources().getInteger(
R.integer.config_wifi_framework_current_association_hysteresis_low);
- thresholdBadRssi5 = mContext.getResources().getInteger(
- R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz);
- thresholdLowRssi5 = mContext.getResources().getInteger(
- R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz);
- thresholdGoodRssi5 = mContext.getResources().getInteger(
- R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz);
- thresholdBadRssi24 = mContext.getResources().getInteger(
- R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz);
- thresholdLowRssi24 = mContext.getResources().getInteger(
- R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz);
- thresholdGoodRssi24 = mContext.getResources().getInteger(
- R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz);
+ thresholdBadRssi5.set(mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz));
+ thresholdLowRssi5.set(mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz));
+ thresholdGoodRssi5.set(mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz));
+ thresholdBadRssi24.set(mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz));
+ thresholdLowRssi24.set(mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz));
+ thresholdGoodRssi24.set(mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz));
enableWifiCellularHandoverUserTriggeredAdjustment = mContext.getResources().getBoolean(
R.bool.config_wifi_framework_cellular_handover_enable_user_triggered_adjustment);
@@ -540,12 +650,8 @@
wifiConfigBlacklistMinTimeMilli = mContext.getResources().getInteger(
R.integer.config_wifi_framework_network_black_list_min_time_milli);
-
- enableAutoJoinScanWhenAssociated = mContext.getResources().getBoolean(
- R.bool.config_wifi_framework_enable_associated_autojoin_scan);
-
- enableAutoJoinWhenAssociated = mContext.getResources().getBoolean(
- R.bool.config_wifi_framework_enable_associated_network_selection);
+ enableAutoJoinWhenAssociated.set(mContext.getResources().getBoolean(
+ R.bool.config_wifi_framework_enable_associated_network_selection));
currentNetworkBoost = mContext.getResources().getInteger(
R.integer.config_wifi_framework_current_network_boost);
@@ -555,10 +661,33 @@
networkSwitchingBlackListPeriodMilli = mContext.getResources().getInteger(
R.integer.config_wifi_network_switching_blacklist_time);
+
+ enableHalBasedPno.set(mContext.getResources().getBoolean(
+ R.bool.config_wifi_hal_pno_enable));
+
+ enableSsidWhitelist.set(mContext.getResources().getBoolean(
+ R.bool.config_wifi_ssid_white_list_enable));
+ if (!enableHalBasedPno.get() && enableSsidWhitelist.get()) {
+ enableSsidWhitelist.set(false);
+ }
+
+ boolean hs2on = mContext.getResources().getBoolean(R.bool.config_wifi_hotspot2_enabled);
+ Log.d(Utils.hs2LogTag(getClass()), "Passpoint is " + (hs2on ? "enabled" : "disabled"));
+
+ mMOManager = new MOManager(new File(PPS_FILE), hs2on);
+ mAnqpCache = new AnqpCache();
+ mSupplicantBridge = new SupplicantBridge(mWifiNative, this);
+ mScanDetailCaches = new HashMap<>();
+
+ mSIMAccessor = new SIMAccessor(mContext);
+ }
+
+ public void trimANQPCache(boolean all) {
+ mAnqpCache.clear(all, DBG);
}
void enableVerboseLogging(int verbose) {
- enableVerboseLogging = verbose;
+ enableVerboseLogging.set(verbose);
if (verbose > 0) {
VDBG = true;
showNetworks = true;
@@ -602,7 +731,8 @@
return mConfiguredNetworks.size();
}
- private List<WifiConfiguration> getConfiguredNetworks(Map<String, String> pskMap) {
+ private List<WifiConfiguration>
+ getConfiguredNetworks(Map<String, String> pskMap) {
List<WifiConfiguration> networks = new ArrayList<>();
for(WifiConfiguration config : mConfiguredNetworks.values()) {
WifiConfiguration newConfig = new WifiConfiguration(config);
@@ -627,6 +757,19 @@
}
/**
+ * This function returns all configuration, and is used for cebug and creating bug reports.
+ */
+ private List<WifiConfiguration>
+ getAllConfiguredNetworks() {
+ List<WifiConfiguration> networks = new ArrayList<>();
+ for(WifiConfiguration config : mConfiguredNetworks.values()) {
+ WifiConfiguration newConfig = new WifiConfiguration(config);
+ networks.add(newConfig);
+ }
+ return networks;
+ }
+
+ /**
* Fetch the list of currently configured networks
* @return List of networks
*/
@@ -644,6 +787,25 @@
}
/**
+ * Find matching network for this scanResult
+ */
+ WifiConfiguration getMatchingConfig(ScanResult scanResult) {
+
+ for (Map.Entry entry : mScanDetailCaches.entrySet()) {
+ Integer netId = (Integer) entry.getKey();
+ ScanDetailCache cache = (ScanDetailCache) entry.getValue();
+ WifiConfiguration config = getWifiConfiguration(netId);
+ if (config == null)
+ continue;
+ if (cache.get(scanResult.BSSID) != null) {
+ return config;
+ }
+ }
+
+ return null;
+ }
+
+ /**
* Fetch the preSharedKeys for all networks.
* @return a map from Ssid to preSharedKey.
*/
@@ -651,12 +813,6 @@
return readNetworkVariablesFromSupplicantFile("psk");
}
- int getconfiguredNetworkSize() {
- if (mConfiguredNetworks == null)
- return 0;
- return mConfiguredNetworks.size();
- }
-
/**
* Fetch the list of currently configured networks that were recently seen
*
@@ -674,7 +830,11 @@
}
// Calculate the RSSI for scan results that are more recent than milli
- config.setVisibility(milli);
+ ScanDetailCache cache = getScanDetailCache(config);
+ if (cache == null) {
+ continue;
+ }
+ config.setVisibility(cache.getVisibility(milli));
if (config.visibility == null) {
continue;
}
@@ -696,14 +856,15 @@
*/
void updateConfiguration(WifiInfo info) {
WifiConfiguration config = getWifiConfiguration(info.getNetworkId());
- if (config != null && config.scanResultCache != null) {
- ScanResult result = config.scanResultCache.get(info.getBSSID());
- if (result != null) {
+ if (config != null && getScanDetailCache(config) != null) {
+ ScanDetail scanDetail = getScanDetailCache(config).getScanDetail(info.getBSSID());
+ if (scanDetail != null) {
+ ScanResult result = scanDetail.getScanResult();
long previousSeen = result.seen;
int previousRssi = result.level;
// Update the scan result
- result.seen = System.currentTimeMillis();
+ scanDetail.setSeen();
result.level = info.getRssi();
// Average the RSSI value
@@ -725,8 +886,6 @@
* @return Wificonfiguration
*/
WifiConfiguration getWifiConfiguration(int netId) {
- if (mConfiguredNetworks == null)
- return null;
return mConfiguredNetworks.get(netId);
}
@@ -735,16 +894,7 @@
* @return Wificonfiguration
*/
WifiConfiguration getWifiConfiguration(String key) {
- if (key == null)
- return null;
- int hash = key.hashCode();
- if (mNetworkIds == null)
- return null;
- Integer n = mNetworkIds.get(hash);
- if (n == null)
- return null;
- int netId = n.intValue();
- return getWifiConfiguration(netId);
+ return mConfiguredNetworks.getByConfigKey(key);
}
/**
@@ -786,6 +936,7 @@
config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
} else {
loge("Enable network failed on " + config.networkId);
+
}
}
}
@@ -796,6 +947,26 @@
}
}
+ private boolean setNetworkPriorityNative(int netId, int priority) {
+ return mWifiNative.setNetworkVariable(netId,
+ WifiConfiguration.priorityVarName, Integer.toString(priority));
+ }
+
+ private boolean setSSIDNative(int netId, String ssid) {
+ return mWifiNative.setNetworkVariable(netId, WifiConfiguration.ssidVarName,
+ encodeSSID(ssid));
+ }
+
+ public boolean updateLastConnectUid(WifiConfiguration config, int uid) {
+ if (config != null) {
+ if (config.lastConnectUid != uid) {
+ config.lastConnectUid = uid;
+ config.dirty = true;
+ return true;
+ }
+ }
+ return false;
+ }
/**
* Selects the specified network for connection. This involves
@@ -806,34 +977,61 @@
* a call to enableAllNetworks() needs to be issued upon a connection
* or a failure event from supplicant
*
- * @param netId network to select for connection
+ * @param config network to select for connection
+ * @param updatePriorities makes config highest priority network
* @return false if the network id is invalid
*/
- boolean selectNetwork(int netId) {
- if (VDBG) localLog("selectNetwork", netId);
- if (netId == INVALID_NETWORK_ID) return false;
+ boolean selectNetwork(WifiConfiguration config, boolean updatePriorities, int uid) {
+ if (VDBG) localLog("selectNetwork", config.networkId);
+ if (config.networkId == INVALID_NETWORK_ID) return false;
// Reset the priority of each network at start or if it goes too high.
if (mLastPriority == -1 || mLastPriority > 1000000) {
- for(WifiConfiguration config : mConfiguredNetworks.values()) {
- if (config.networkId != INVALID_NETWORK_ID) {
- config.priority = 0;
- addOrUpdateNetworkNative(config, -1);
+ for(WifiConfiguration config2 : mConfiguredNetworks.values()) {
+ if (updatePriorities) {
+ if (config2.networkId != INVALID_NETWORK_ID) {
+ config2.priority = 0;
+ setNetworkPriorityNative(config2.networkId, config.priority);
+ }
}
}
mLastPriority = 0;
}
// Set to the highest priority and save the configuration.
- WifiConfiguration config = new WifiConfiguration();
- config.networkId = netId;
- config.priority = ++mLastPriority;
+ if (updatePriorities) {
+ config.priority = ++mLastPriority;
+ setNetworkPriorityNative(config.networkId, config.priority);
+ buildPnoList();
+ }
- addOrUpdateNetworkNative(config, -1);
- mWifiNative.saveConfig();
+ if (config.isPasspoint()) {
+ /* need to slap on the SSID of selected bssid to work */
+ if (getScanDetailCache(config).size() != 0) {
+ ScanDetail result = getScanDetailCache(config).getFirst();
+ if (result == null) {
+ loge("Could not find scan result for " + config.BSSID);
+ } else {
+ log("Setting SSID for " + config.networkId + " to" + result.getSSID());
+ setSSIDNative(config.networkId, result.getSSID());
+ config.SSID = result.getSSID();
+ }
+
+ } else {
+ loge("Could not find bssid for " + config);
+ }
+ }
+
+ if (updatePriorities)
+ mWifiNative.saveConfig();
+ else
+ mWifiNative.selectNetwork(config.networkId);
+
+ updateLastConnectUid(config, uid);
+ writeKnownNetworkHistory(false);
/* Enable the given network while disabling all other networks */
- enableNetworkWithoutBroadcast(netId, true);
+ enableNetworkWithoutBroadcast(config.networkId, true);
/* Avoid saving the config & sending a broadcast to prevent settings
* from displaying a disabled list of networks */
@@ -922,11 +1120,11 @@
if (info != null
&& info.getBSSID() != null
&& ScanResult.is5GHz(info.getFrequency())
- && info.getRssi() > (bandPreferenceBoostThreshold5 + 3)) {
+ && info.getRssi() > (bandPreferenceBoostThreshold5.get() + 3)) {
WifiConfiguration config = getWifiConfiguration(info.getNetworkId());
if (config != null) {
- if (config.scanResultCache != null) {
- ScanResult result = config.scanResultCache.get(info.getBSSID());
+ if (getScanDetailCache(config) != null) {
+ ScanResult result = getScanDetailCache(config).get(info.getBSSID());
if (result != null) {
result.setAutoJoinStatus(ScanResult.AUTO_ROAM_DISABLED + 1);
}
@@ -1017,16 +1215,13 @@
return null;
}
- WifiConfiguration foundConfig = null;
+ WifiConfiguration foundConfig = mConfiguredNetworks.getEphemeral(SSID);
mDeletedEphemeralSSIDs.add(SSID);
loge("Forget ephemeral SSID " + SSID + " num=" + mDeletedEphemeralSSIDs.size());
- for (WifiConfiguration config : mConfiguredNetworks.values()) {
- if (SSID.equals(config.SSID) && config.ephemeral) {
- loge("Found ephemeral config in disableEphemeralNetwork: " + config.networkId);
- foundConfig = config;
- }
+ if (foundConfig != null) {
+ loge("Found ephemeral config in disableEphemeralNetwork: " + foundConfig.networkId);
}
// Force a write, because the mDeletedEphemeralSSIDs list has changed even though the
@@ -1045,13 +1240,18 @@
boolean forgetNetwork(int netId) {
if (showNetworks) localLog("forgetNetwork", netId);
+ WifiConfiguration config = mConfiguredNetworks.get(netId);
boolean remove = removeConfigAndSendBroadcastIfNeeded(netId);
if (!remove) {
//success but we dont want to remove the network from supplicant conf file
return true;
}
if (mWifiNative.removeNetwork(netId)) {
+ if (config != null && config.isPasspoint()) {
+ writePasspointConfigs(config.FQDN, null);
+ }
mWifiNative.saveConfig();
+ writeKnownNetworkHistory(true);
return true;
} else {
loge("Failed to remove network " + netId);
@@ -1074,6 +1274,14 @@
Log.e(TAG, " key=" + config.configKey() + " netId=" + Integer.toString(config.networkId)
+ " uid=" + Integer.toString(config.creatorUid)
+ "/" + Integer.toString(config.lastUpdateUid));
+
+ if (config.isPasspoint()) {
+ /* create a temporary SSID with providerFriendlyName */
+ Long csum = getChecksum(config.FQDN);
+ config.SSID = csum.toString();
+ config.enterpriseConfig.setDomainSuffixMatch(config.FQDN);
+ }
+
NetworkUpdateResult result = addOrUpdateNetworkNative(config, uid);
if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
WifiConfiguration conf = mConfiguredNetworks.get(result.getNetworkId());
@@ -1083,9 +1291,103 @@
WifiManager.CHANGE_REASON_CONFIG_CHANGE);
}
}
+
return result.getNetworkId();
}
+
+ /**
+ * Get the Wifi PNO list
+ *
+ * @return list of WifiNative.WifiPnoNetwork
+ */
+ private void buildPnoList() {
+ mCachedPnoList = new ArrayList<WifiNative.WifiPnoNetwork>();
+
+ ArrayList<WifiConfiguration> sortedWifiConfigurations
+ = new ArrayList<WifiConfiguration>(getConfiguredNetworks());
+ Log.e(TAG, "buildPnoList sortedWifiConfigurations size " + sortedWifiConfigurations.size());
+ if (sortedWifiConfigurations.size() != 0) {
+ // Sort by descending priority
+ Collections.sort(sortedWifiConfigurations, new Comparator<WifiConfiguration>() {
+ public int compare(WifiConfiguration a, WifiConfiguration b) {
+ return a.priority >= b.priority ? 1 : -1;
+ }
+ });
+ }
+
+ for (WifiConfiguration config : sortedWifiConfigurations) {
+ // Initialize the RSSI threshold with sane value:
+ // Use the 2.4GHz threshold since most WifiConfigurations are dual bands
+ // There is very little penalty with triggering too soon, i.e. if PNO finds a network
+ // that has an RSSI too low for us to attempt joining it.
+ int threshold = thresholdInitialAutoJoinAttemptMin24RSSI.get();
+ Log.e(TAG, "found sortedWifiConfigurations : " + config.configKey());
+ WifiNative.WifiPnoNetwork network = mWifiNative.new WifiPnoNetwork(config, threshold);
+ mCachedPnoList.add(network);
+ }
+ }
+
+ String[] getWhiteListedSsids(WifiConfiguration config) {
+ int num_ssids = 0;
+ String nonQuoteSSID;
+ int length;
+ if (enableSsidWhitelist.get() == false)
+ return null;
+ List<String> list = new ArrayList<String>();
+ if (config == null)
+ return null;
+ if (config.linkedConfigurations == null) {
+ return null;
+ }
+ if (config.SSID == null || TextUtils.isEmpty(config.SSID)) {
+ return null;
+ }
+ for (String configKey : config.linkedConfigurations.keySet()) {
+
+ // Sanity check that the linked configuration is still valid
+ WifiConfiguration link = getWifiConfiguration(configKey);
+ if (link == null) {
+ continue;
+ }
+
+ if (link.autoJoinStatus != WifiConfiguration.AUTO_JOIN_ENABLED) {
+ continue;
+ }
+
+ if (link.hiddenSSID == true) {
+ continue;
+ }
+
+ if (link.SSID == null || TextUtils.isEmpty(link.SSID)) {
+ continue;
+ }
+
+ length = link.SSID.length();
+ if (length > 2 && (link.SSID.charAt(0) == '"') && link.SSID.charAt(length - 1) == '"') {
+ nonQuoteSSID = link.SSID.substring(1, length - 1);
+ } else {
+ nonQuoteSSID = link.SSID;
+ }
+
+ list.add(nonQuoteSSID);
+ }
+
+ if (list.size() != 0) {
+ length = config.SSID.length();
+ if (length > 2 && (config.SSID.charAt(0) == '"')
+ && config.SSID.charAt(length - 1) == '"') {
+ nonQuoteSSID = config.SSID.substring(1, length - 1);
+ } else {
+ nonQuoteSSID = config.SSID;
+ }
+
+ list.add(nonQuoteSSID);
+ }
+
+ return (String[])list.toArray(new String[0]);
+ }
+
/**
* Remove a network. Note that there is no saveConfig operation.
* This function is retained for compatibility with the public
@@ -1097,13 +1399,24 @@
*/
boolean removeNetwork(int netId) {
if (showNetworks) localLog("removeNetwork", netId);
+ WifiConfiguration config = mConfiguredNetworks.get(netId);
boolean ret = mWifiNative.removeNetwork(netId);
if (ret) {
removeConfigAndSendBroadcastIfNeeded(netId);
+ if (config != null && config.isPasspoint()) {
+ writePasspointConfigs(config.FQDN, null);
+ }
}
return ret;
}
+
+ static private Long getChecksum(String source) {
+ Checksum csum = new CRC32();
+ csum.update(source.getBytes(), 0, source.getBytes().length);
+ return csum.getValue();
+ }
+
private boolean removeConfigAndSendBroadcastIfNeeded(int netId) {
WifiConfiguration config = mConfiguredNetworks.get(netId);
if (config != null) {
@@ -1126,20 +1439,23 @@
|| config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
if (!TextUtils.isEmpty(config.SSID)) {
/* Remember that we deleted this PSK SSID */
- Checksum csum = new CRC32();
if (config.SSID != null) {
- csum.update(config.SSID.getBytes(), 0, config.SSID.getBytes().length);
- mDeletedSSIDs.add(csum.getValue());
+ Long csum = getChecksum(config.SSID);
+ mDeletedSSIDs.add(csum);
+ loge("removeNetwork " + Integer.toString(netId)
+ + " key=" + config.configKey()
+ + " config.id=" + Integer.toString(config.networkId)
+ + " crc=" + csum);
+ } else {
+ loge("removeNetwork " + Integer.toString(netId)
+ + " key=" + config.configKey()
+ + " config.id=" + Integer.toString(config.networkId));
}
- loge("removeNetwork " + Integer.toString(netId)
- + " key=" + config.configKey()
- + " config.id=" + Integer.toString(config.networkId)
- + " crc=" + csum.getValue());
}
}
mConfiguredNetworks.remove(netId);
- mNetworkIds.remove(configKey(config));
+ mScanDetailCaches.remove(netId);
writeIpAndProxyConfigurations();
sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_REMOVED);
@@ -1148,6 +1464,57 @@
return true;
}
+ /*
+ * Remove all networks associated with an application
+ *
+ * @param packageName name of the package of networks to remove
+ * @return {@code true} if all networks removed successfully, {@code false} otherwise
+ */
+ boolean removeNetworksForApp(ApplicationInfo app) {
+ if (app == null || app.packageName == null) {
+ return false;
+ }
+
+ boolean success = true;
+
+ WifiConfiguration [] copiedConfigs =
+ mConfiguredNetworks.values().toArray(new WifiConfiguration[0]);
+ for (WifiConfiguration config : copiedConfigs) {
+ if (app.uid != config.creatorUid || !app.packageName.equals(config.creatorName)) {
+ continue;
+ }
+ if (showNetworks) {
+ localLog("Removing network " + config.SSID
+ + ", application \"" + app.packageName + "\" uninstalled"
+ + " from user " + UserHandle.getUserId(app.uid));
+ }
+ success &= removeNetwork(config.networkId);
+ }
+
+ mWifiNative.saveConfig();
+
+ return success;
+ }
+
+ boolean removeNetworksForUser(int userId) {
+ boolean success = true;
+
+ WifiConfiguration[] copiedConfigs =
+ mConfiguredNetworks.values().toArray(new WifiConfiguration[0]);
+ for (WifiConfiguration config : copiedConfigs) {
+ if (userId != UserHandle.getUserId(config.creatorUid)) {
+ continue;
+ }
+ success &= removeNetwork(config.networkId);
+ if (showNetworks) {
+ localLog("Removing network " + config.SSID
+ + ", user " + userId + " removed");
+ }
+ }
+
+ return success;
+ }
+
/**
* Enable a network. Note that there is no saveConfig operation.
* This function is retained for compatibility with the public
@@ -1157,15 +1524,17 @@
* @param netId network to be enabled
* @return {@code true} if it succeeds, {@code false} otherwise
*/
- boolean enableNetwork(int netId, boolean disableOthers) {
+ boolean enableNetwork(int netId, boolean disableOthers, int uid) {
boolean ret = enableNetworkWithoutBroadcast(netId, disableOthers);
if (disableOthers) {
- if (VDBG) localLog("enableNetwork(disableOthers=true) ", netId);
+ if (VDBG) localLog("enableNetwork(disableOthers=true, uid=" + uid + ") ", netId);
+ updateLastConnectUid(getWifiConfiguration(netId), uid);
+ writeKnownNetworkHistory(false);
sendConfiguredNetworksChangedBroadcast();
} else {
if (VDBG) localLog("enableNetwork(disableOthers=false) ", netId);
- WifiConfiguration enabledNetwork = null;
- synchronized(mConfiguredNetworks) {
+ WifiConfiguration enabledNetwork;
+ synchronized(mConfiguredNetworks) { // !!! Useless synchronization!
enabledNetwork = mConfiguredNetworks.get(netId);
}
// check just in case the network was removed by someone else.
@@ -1192,14 +1561,12 @@
void disableAllNetworks() {
if (VDBG) localLog("disableAllNetworks");
boolean networkDisabled = false;
- for(WifiConfiguration config : mConfiguredNetworks.values()) {
- if(config != null && config.status != Status.DISABLED) {
- if(mWifiNative.disableNetwork(config.networkId)) {
- networkDisabled = true;
- config.status = Status.DISABLED;
- } else {
- loge("Disable network failed on " + config.networkId);
- }
+ for (WifiConfiguration enabled : mConfiguredNetworks.getEnabledNetworks()) {
+ if(mWifiNative.disableNetwork(enabled.networkId)) {
+ networkDisabled = true;
+ enabled.status = Status.DISABLED;
+ } else {
+ loge("Disable network failed on " + enabled.networkId);
}
}
@@ -1213,7 +1580,11 @@
* @return {@code true} if it succeeds, {@code false} otherwise
*/
boolean disableNetwork(int netId) {
- return disableNetwork(netId, WifiConfiguration.DISABLED_UNKNOWN_REASON);
+ boolean ret = disableNetwork(netId, WifiConfiguration.DISABLED_UNKNOWN_REASON);
+ if (ret) {
+ mWifiStateMachine.registerNetworkDisabled(netId);
+ }
+ return ret;
}
/**
@@ -1359,7 +1730,7 @@
/**
* Fetch the proxy properties for a given network id
- * @param network id
+ * @param netId id
* @return ProxyInfo for the network id
*/
ProxyInfo getProxyProperties(int netId) {
@@ -1372,7 +1743,7 @@
/**
* Return if the specified network is using static IP
- * @param network id
+ * @param netId id
* @return {@code true} if using static ip for netId
*/
boolean isUsingStaticIp(int netId) {
@@ -1383,6 +1754,11 @@
return false;
}
+ boolean isEphemeral(int netId) {
+ WifiConfiguration config = mConfiguredNetworks.get(netId);
+ return config != null && config.ephemeral;
+ }
+
/**
* Should be called when a single network configuration is made.
* @param network The network configuration that changed.
@@ -1414,7 +1790,6 @@
mLastPriority = 0;
mConfiguredNetworks.clear();
- mNetworkIds.clear();
int last_id = -1;
boolean done = false;
@@ -1474,12 +1849,11 @@
config.setIpAssignment(IpAssignment.DHCP);
config.setProxySettings(ProxySettings.NONE);
- if (mNetworkIds.containsKey(configKey(config))) {
+ if (mConfiguredNetworks.getByConfigKey(config.configKey()) != null) {
// That SSID is already known, just ignore this duplicate entry
if (showNetworks) localLog("discarded duplicate network ", config.networkId);
- } else if(config.isValid()){
+ } else if(WifiServiceImpl.isValid(config)){
mConfiguredNetworks.put(config.networkId, config);
- mNetworkIds.put(configKey(config), config.networkId);
if (showNetworks) localLog("loaded configured network", config.networkId);
} else {
if (showNetworks) log("Ignoring loaded configured for network " + config.networkId
@@ -1490,40 +1864,48 @@
done = (lines.length == 1);
}
+ readPasspointConfig();
readIpAndProxyConfigurations();
readNetworkHistory();
readAutoJoinConfig();
+ buildPnoList();
+
sendConfiguredNetworksChangedBroadcast();
- if (showNetworks) localLog("loadConfiguredNetworks loaded " + mNetworkIds.size() + " networks");
+ if (showNetworks) localLog("loadConfiguredNetworks loaded " + mConfiguredNetworks.size() + " networks");
- if (mNetworkIds.size() == 0) {
- // no networks? Lets log if the wpa_supplicant.conf file contents
- BufferedReader reader = null;
+ if (mConfiguredNetworks.isEmpty()) {
+ // no networks? Lets log if the file contents
+ logKernelTime();
+ logContents(SUPPLICANT_CONFIG_FILE);
+ logContents(SUPPLICANT_CONFIG_FILE_BACKUP);
+ logContents(networkHistoryConfigFile);
+ }
+ }
+
+ private void logContents(String file) {
+ localLog("--- Begin " + file + " ---", true);
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new FileReader(file));
+ for (String line = reader.readLine(); line != null; line = reader.readLine()) {
+ localLog(line, true);
+ }
+ } catch (FileNotFoundException e) {
+ localLog("Could not open " + file + ", " + e, true);
+ } catch (IOException e) {
+ localLog("Could not read " + file + ", " + e, true);
+ } finally {
try {
- reader = new BufferedReader(new FileReader(SUPPLICANT_CONFIG_FILE));
- if (DBG) {
- localLog("--- Begin wpa_supplicant.conf Contents ---", true);
- for (String line = reader.readLine(); line != null; line = reader.readLine()) {
- localLog(line, true);
- }
- localLog("--- End wpa_supplicant.conf Contents ---", true);
+ if (reader != null) {
+ reader.close();
}
- } catch (FileNotFoundException e) {
- localLog("Could not open " + SUPPLICANT_CONFIG_FILE + ", " + e, true);
} catch (IOException e) {
- localLog("Could not read " + SUPPLICANT_CONFIG_FILE + ", " + e, true);
- } finally {
- try {
- if (reader != null) {
- reader.close();
- }
- } catch (IOException e) {
- // Just ignore the fact that we couldn't close
- }
+ // Just ignore the fact that we couldn't close
}
}
+ localLog("--- End " + file + " Contents ---", true);
}
private Map<String, String> readNetworkVariablesFromSupplicantFile(String key) {
@@ -1627,6 +2009,37 @@
return false;
}
+ void readPasspointConfig() {
+
+ List<HomeSP> homeSPs;
+ try {
+ homeSPs = mMOManager.loadAllSPs();
+ } catch (IOException e) {
+ loge("Could not read " + PPS_FILE + " : " + e);
+ return;
+ }
+
+ mConfiguredNetworks.populatePasspointData(homeSPs, mWifiNative);
+ }
+
+ public void writePasspointConfigs(final String fqdn, final HomeSP homeSP) {
+ mWriter.write(PPS_FILE, new DelayedDiskWrite.Writer() {
+ @Override
+ public void onWriteCalled(DataOutputStream out) throws IOException {
+ try {
+ if (homeSP != null) {
+ mMOManager.addSP(homeSP);
+ }
+ else {
+ mMOManager.removeSP(fqdn);
+ }
+ } catch (IOException e) {
+ loge("Could not write " + PPS_FILE + " : " + e);
+ }
+ }
+ }, false);
+ }
+
public void writeKnownNetworkHistory(boolean force) {
boolean needUpdate = force;
@@ -1675,7 +2088,7 @@
+ " nid:" + Integer.toString(config.networkId));
}
- if (config.isValid() == false)
+ if (!WifiServiceImpl.isValid(config))
continue;
if (config.SSID == null) {
@@ -1687,133 +2100,142 @@
if (VDBG) {
loge("writeKnownNetworkHistory write config " + config.configKey());
}
- out.writeUTF(CONFIG_KEY + config.configKey() + SEPARATOR_KEY);
+ out.writeUTF(CONFIG_KEY + SEPARATOR + config.configKey() + NL);
- out.writeUTF(SSID_KEY + config.SSID + SEPARATOR_KEY);
- out.writeUTF(FQDN_KEY + config.FQDN + SEPARATOR_KEY);
-
- out.writeUTF(PRIORITY_KEY + Integer.toString(config.priority) + SEPARATOR_KEY);
- out.writeUTF(STATUS_KEY + Integer.toString(config.autoJoinStatus)
- + SEPARATOR_KEY);
- out.writeUTF(SUPPLICANT_STATUS_KEY + Integer.toString(config.status)
- + SEPARATOR_KEY);
- out.writeUTF(SUPPLICANT_DISABLE_REASON_KEY
- + Integer.toString(config.disableReason)
- + SEPARATOR_KEY);
- out.writeUTF(NETWORK_ID_KEY + Integer.toString(config.networkId)
- + SEPARATOR_KEY);
- out.writeUTF(SELF_ADDED_KEY + Boolean.toString(config.selfAdded)
- + SEPARATOR_KEY);
- out.writeUTF(DID_SELF_ADD_KEY + Boolean.toString(config.didSelfAdd)
- + SEPARATOR_KEY);
- out.writeUTF(NO_INTERNET_ACCESS_REPORTS_KEY
- + Integer.toString(config.numNoInternetAccessReports)
- + SEPARATOR_KEY);
- out.writeUTF(VALIDATED_INTERNET_ACCESS_KEY
- + Boolean.toString(config.validatedInternetAccess)
- + SEPARATOR_KEY);
- out.writeUTF(EPHEMERAL_KEY
- + Boolean.toString(config.ephemeral)
- + SEPARATOR_KEY);
- if (config.peerWifiConfiguration != null) {
- out.writeUTF(PEER_CONFIGURATION_KEY + config.peerWifiConfiguration
- + SEPARATOR_KEY);
+ if (config.SSID != null) {
+ out.writeUTF(SSID_KEY + SEPARATOR + config.SSID + NL);
}
- out.writeUTF(NUM_CONNECTION_FAILURES_KEY
- + Integer.toString(config.numConnectionFailures)
- + SEPARATOR_KEY);
- out.writeUTF(NUM_AUTH_FAILURES_KEY
- + Integer.toString(config.numAuthFailures)
- + SEPARATOR_KEY);
- out.writeUTF(NUM_IP_CONFIG_FAILURES_KEY
- + Integer.toString(config.numIpConfigFailures)
- + SEPARATOR_KEY);
- out.writeUTF(SCORER_OVERRIDE_KEY + Integer.toString(config.numScorerOverride)
- + SEPARATOR_KEY);
- out.writeUTF(SCORER_OVERRIDE_AND_SWITCH_KEY
- + Integer.toString(config.numScorerOverrideAndSwitchedNetwork)
- + SEPARATOR_KEY);
- out.writeUTF(NUM_ASSOCIATION_KEY
- + Integer.toString(config.numAssociation)
- + SEPARATOR_KEY);
- out.writeUTF(JOIN_ATTEMPT_BOOST_KEY
- + Integer.toString(config.autoJoinUseAggressiveJoinAttemptThreshold)
- + SEPARATOR_KEY);
- //out.writeUTF(BLACKLIST_MILLI_KEY + Long.toString(config.blackListTimestamp)
- // + SEPARATOR_KEY);
- out.writeUTF(CREATOR_UID_KEY + Integer.toString(config.creatorUid)
- + SEPARATOR_KEY);
- out.writeUTF(CONNECT_UID_KEY + Integer.toString(config.lastConnectUid)
- + SEPARATOR_KEY);
- out.writeUTF(UPDATE_UID_KEY + Integer.toString(config.lastUpdateUid)
- + SEPARATOR_KEY);
+ if (config.FQDN != null) {
+ out.writeUTF(FQDN_KEY + SEPARATOR + config.FQDN + NL);
+ }
+
+ out.writeUTF(PRIORITY_KEY + SEPARATOR +
+ Integer.toString(config.priority) + NL);
+ out.writeUTF(STATUS_KEY + SEPARATOR +
+ Integer.toString(config.autoJoinStatus) + NL);
+ out.writeUTF(SUPPLICANT_STATUS_KEY + SEPARATOR +
+ Integer.toString(config.status) + NL);
+ out.writeUTF(SUPPLICANT_DISABLE_REASON_KEY + SEPARATOR +
+ Integer.toString(config.disableReason) + NL);
+ out.writeUTF(NETWORK_ID_KEY + SEPARATOR +
+ Integer.toString(config.networkId) + NL);
+ out.writeUTF(SELF_ADDED_KEY + SEPARATOR +
+ Boolean.toString(config.selfAdded) + NL);
+ out.writeUTF(DID_SELF_ADD_KEY + SEPARATOR +
+ Boolean.toString(config.didSelfAdd) + NL);
+ out.writeUTF(NO_INTERNET_ACCESS_REPORTS_KEY + SEPARATOR +
+ Integer.toString(config.numNoInternetAccessReports) + NL);
+ out.writeUTF(VALIDATED_INTERNET_ACCESS_KEY + SEPARATOR +
+ Boolean.toString(config.validatedInternetAccess) + NL);
+ out.writeUTF(EPHEMERAL_KEY + SEPARATOR +
+ Boolean.toString(config.ephemeral) + NL);
+ if (config.creationTime != null) {
+ out.writeUTF(CREATION_TIME_KEY + SEPARATOR + config.creationTime + NL);
+ }
+ if (config.updateTime != null) {
+ out.writeUTF(UPDATE_TIME_KEY + SEPARATOR + config.updateTime + NL);
+ }
+ if (config.peerWifiConfiguration != null) {
+ out.writeUTF(PEER_CONFIGURATION_KEY + SEPARATOR +
+ config.peerWifiConfiguration + NL);
+ }
+ out.writeUTF(NUM_CONNECTION_FAILURES_KEY + SEPARATOR +
+ Integer.toString(config.numConnectionFailures) + NL);
+ out.writeUTF(NUM_AUTH_FAILURES_KEY + SEPARATOR +
+ Integer.toString(config.numAuthFailures) + NL);
+ out.writeUTF(NUM_IP_CONFIG_FAILURES_KEY + SEPARATOR +
+ Integer.toString(config.numIpConfigFailures) + NL);
+ out.writeUTF(SCORER_OVERRIDE_KEY + SEPARATOR +
+ Integer.toString(config.numScorerOverride) + NL);
+ out.writeUTF(SCORER_OVERRIDE_AND_SWITCH_KEY + SEPARATOR +
+ Integer.toString(config.numScorerOverrideAndSwitchedNetwork) + NL);
+ out.writeUTF(NUM_ASSOCIATION_KEY + SEPARATOR +
+ Integer.toString(config.numAssociation) + NL);
+ out.writeUTF(JOIN_ATTEMPT_BOOST_KEY + SEPARATOR +
+ Integer.toString(config.autoJoinUseAggressiveJoinAttemptThreshold)+ NL);
+ //out.writeUTF(BLACKLIST_MILLI_KEY + SEPARATOR +
+ // Long.toString(config.blackListTimestamp) + NL);
+ out.writeUTF(CREATOR_UID_KEY + SEPARATOR +
+ Integer.toString(config.creatorUid) + NL);
+ out.writeUTF(CONNECT_UID_KEY + SEPARATOR +
+ Integer.toString(config.lastConnectUid) + NL);
+ out.writeUTF(UPDATE_UID_KEY + SEPARATOR +
+ Integer.toString(config.lastUpdateUid) + NL);
+ out.writeUTF(CREATOR_NAME_KEY + SEPARATOR +
+ config.creatorName + NL);
+ out.writeUTF(UPDATE_NAME_KEY + SEPARATOR +
+ config.lastUpdateName + NL);
+ out.writeUTF(USER_APPROVED_KEY + SEPARATOR +
+ Integer.toString(config.userApproved) + NL);
String allowedKeyManagementString =
makeString(config.allowedKeyManagement,
WifiConfiguration.KeyMgmt.strings);
- out.writeUTF(AUTH_KEY + allowedKeyManagementString + SEPARATOR_KEY);
+ out.writeUTF(AUTH_KEY + SEPARATOR +
+ allowedKeyManagementString + NL);
if (config.connectChoices != null) {
for (String key : config.connectChoices.keySet()) {
Integer choice = config.connectChoices.get(key);
- out.writeUTF(CHOICE_KEY + key + "="
- + choice.toString() + SEPARATOR_KEY);
+ out.writeUTF(CHOICE_KEY + SEPARATOR +
+ key + "=" + choice.toString() + NL);
}
}
if (config.linkedConfigurations != null) {
- loge("writeKnownNetworkHistory write linked "
+ log("writeKnownNetworkHistory write linked "
+ config.linkedConfigurations.size());
for (String key : config.linkedConfigurations.keySet()) {
- out.writeUTF(LINK_KEY + key + SEPARATOR_KEY);
+ out.writeUTF(LINK_KEY + SEPARATOR + key + NL);
}
}
String macAddress = config.defaultGwMacAddress;
if (macAddress != null) {
- out.writeUTF(DEFAULT_GW_KEY + macAddress + SEPARATOR_KEY);
+ out.writeUTF(DEFAULT_GW_KEY + SEPARATOR + macAddress + NL);
}
- if (config.scanResultCache != null) {
- for (ScanResult result : config.scanResultCache.values()) {
- out.writeUTF(BSSID_KEY + result.BSSID + SEPARATOR_KEY);
+ if (getScanDetailCache(config) != null) {
+ for (ScanDetail scanDetail : getScanDetailCache(config).values()) {
+ ScanResult result = scanDetail.getScanResult();
+ out.writeUTF(BSSID_KEY + SEPARATOR +
+ result.BSSID + NL);
- out.writeUTF(FREQ_KEY + Integer.toString(result.frequency)
- + SEPARATOR_KEY);
+ out.writeUTF(FREQ_KEY + SEPARATOR +
+ Integer.toString(result.frequency) + NL);
- out.writeUTF(RSSI_KEY + Integer.toString(result.level)
- + SEPARATOR_KEY);
+ out.writeUTF(RSSI_KEY + SEPARATOR +
+ Integer.toString(result.level) + NL);
- out.writeUTF(BSSID_STATUS_KEY
- + Integer.toString(result.autoJoinStatus)
- + SEPARATOR_KEY);
+ out.writeUTF(BSSID_STATUS_KEY + SEPARATOR +
+ Integer.toString(result.autoJoinStatus) + NL);
//if (result.seen != 0) {
- // out.writeUTF(MILLI_KEY + Long.toString(result.seen)
- // + SEPARATOR_KEY);
+ // out.writeUTF(MILLI_KEY + SEPARATOR + Long.toString(result.seen)
+ // + NL);
//}
- out.writeUTF(BSSID_KEY_END + SEPARATOR_KEY);
+ out.writeUTF(BSSID_KEY_END + NL);
}
}
if (config.lastFailure != null) {
- out.writeUTF(FAILURE_KEY + config.lastFailure + SEPARATOR_KEY);
+ out.writeUTF(FAILURE_KEY + SEPARATOR + config.lastFailure + NL);
}
- out.writeUTF(SEPARATOR_KEY);
+ out.writeUTF(NL);
// Add extra blank lines for clarity
- out.writeUTF(SEPARATOR_KEY);
- out.writeUTF(SEPARATOR_KEY);
+ out.writeUTF(NL);
+ out.writeUTF(NL);
}
if (mDeletedSSIDs != null && mDeletedSSIDs.size() > 0) {
for (Long i : mDeletedSSIDs) {
out.writeUTF(DELETED_CRC32_KEY);
out.writeUTF(String.valueOf(i));
- out.writeUTF(SEPARATOR_KEY);
+ out.writeUTF(NL);
}
}
if (mDeletedEphemeralSSIDs != null && mDeletedEphemeralSSIDs.size() > 0) {
for (String ssid : mDeletedEphemeralSSIDs) {
out.writeUTF(DELETED_EPHEMERAL_KEY);
out.writeUTF(ssid);
- out.writeUTF(SEPARATOR_KEY);
+ out.writeUTF(NL);
}
}
}
@@ -1857,720 +2279,279 @@
if (showNetworks) {
localLog("readNetworkHistory() path:" + networkHistoryConfigFile);
}
- DataInputStream in = null;
- try {
- in = new DataInputStream(new BufferedInputStream(new FileInputStream(
- networkHistoryConfigFile)));
+
+ try (DataInputStream in =
+ new DataInputStream(new BufferedInputStream(
+ new FileInputStream(networkHistoryConfigFile)))) {
+
+ String bssid = null;
+ String ssid = null;
+
+ int freq = 0;
+ int status = 0;
+ long seen = 0;
+ int rssi = WifiConfiguration.INVALID_RSSI;
+ String caps = null;
+
WifiConfiguration config = null;
while (true) {
- int id = -1;
- String key = in.readUTF();
- String bssid = null;
- String ssid = null;
+ String line = in.readUTF();
+ if (line == null) {
+ break;
+ }
+ int colon = line.indexOf(':');
+ if (colon < 0) {
+ continue;
+ }
- int freq = 0;
- int status = 0;
- long seen = 0;
- int rssi = WifiConfiguration.INVALID_RSSI;
- String caps = null;
- if (key.startsWith(CONFIG_KEY)) {
+ String key = line.substring(0, colon).trim();
+ String value = line.substring(colon + 1).trim();
- if (config != null) {
- config = null;
- }
- String configKey = key.replace(CONFIG_KEY, "");
- configKey = configKey.replace(SEPARATOR_KEY, "");
- // get the networkId for that config Key
- Integer n = mNetworkIds.get(configKey.hashCode());
+ if (key.equals(CONFIG_KEY)) {
+
+ config = mConfiguredNetworks.getByConfigKey(value);
+
// skip reading that configuration data
// since we don't have a corresponding network ID
- if (n == null) {
- localLog("readNetworkHistory didnt find netid for hash="
- + Integer.toString(configKey.hashCode())
- + " key: " + configKey);
- continue;
- }
- config = mConfiguredNetworks.get(n);
if (config == null) {
- localLog("readNetworkHistory didnt find config for netid="
- + n.toString()
- + " key: " + configKey);
- }
- status = 0;
- ssid = null;
- bssid = null;
- freq = 0;
- seen = 0;
- rssi = WifiConfiguration.INVALID_RSSI;
- caps = null;
+ localLog("readNetworkHistory didnt find netid for hash="
+ + Integer.toString(value.hashCode())
+ + " key: " + value);
+ mLostConfigsDbg.add(value);
+ continue;
+ } else {
+ // After an upgrade count old connections as owned by system
+ if (config.creatorName == null || config.lastUpdateName == null) {
+ config.creatorName =
+ mContext.getPackageManager().getNameForUid(Process.SYSTEM_UID);
+ config.lastUpdateName = config.creatorName;
+ if (DBG) Log.w(TAG, "Upgrading network " + config.networkId
+ + " to " + config.creatorName);
+ }
+ }
} else if (config != null) {
- if (key.startsWith(SSID_KEY)) {
- ssid = key.replace(SSID_KEY, "");
- ssid = ssid.replace(SEPARATOR_KEY, "");
- if (config.SSID != null && !config.SSID.equals(ssid)) {
- loge("Error parsing network history file, mismatched SSIDs");
- config = null; //error
- ssid = null;
- } else {
- config.SSID = ssid;
- }
- }
-
- if (key.startsWith(FQDN_KEY)) {
- String fqdn = key.replace(FQDN_KEY, "");
- fqdn = fqdn.replace(SEPARATOR_KEY, "");
- config.FQDN = fqdn;
- }
-
- if (key.startsWith(DEFAULT_GW_KEY)) {
- String gateway = key.replace(DEFAULT_GW_KEY, "");
- gateway = gateway.replace(SEPARATOR_KEY, "");
- config.defaultGwMacAddress = gateway;
- }
-
- if (key.startsWith(STATUS_KEY)) {
- String st = key.replace(STATUS_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- config.autoJoinStatus = Integer.parseInt(st);
- }
-
- if (key.startsWith(SUPPLICANT_DISABLE_REASON_KEY)) {
- String reason = key.replace(SUPPLICANT_DISABLE_REASON_KEY, "");
- reason = reason.replace(SEPARATOR_KEY, "");
- config.disableReason = Integer.parseInt(reason);
- }
-
- if (key.startsWith(SELF_ADDED_KEY)) {
- String selfAdded = key.replace(SELF_ADDED_KEY, "");
- selfAdded = selfAdded.replace(SEPARATOR_KEY, "");
- config.selfAdded = Boolean.parseBoolean(selfAdded);
- }
-
- if (key.startsWith(DID_SELF_ADD_KEY)) {
- String didSelfAdd = key.replace(DID_SELF_ADD_KEY, "");
- didSelfAdd = didSelfAdd.replace(SEPARATOR_KEY, "");
- config.didSelfAdd = Boolean.parseBoolean(didSelfAdd);
- }
-
- if (key.startsWith(NO_INTERNET_ACCESS_REPORTS_KEY)) {
- String access = key.replace(NO_INTERNET_ACCESS_REPORTS_KEY, "");
- access = access.replace(SEPARATOR_KEY, "");
- config.numNoInternetAccessReports = Integer.parseInt(access);
- }
-
- if (key.startsWith(VALIDATED_INTERNET_ACCESS_KEY)) {
- String access = key.replace(VALIDATED_INTERNET_ACCESS_KEY, "");
- access = access.replace(SEPARATOR_KEY, "");
- config.validatedInternetAccess = Boolean.parseBoolean(access);
- }
-
- if (key.startsWith(EPHEMERAL_KEY)) {
- String access = key.replace(EPHEMERAL_KEY, "");
- access = access.replace(SEPARATOR_KEY, "");
- config.ephemeral = Boolean.parseBoolean(access);
- }
-
- if (key.startsWith(CREATOR_UID_KEY)) {
- String uid = key.replace(CREATOR_UID_KEY, "");
- uid = uid.replace(SEPARATOR_KEY, "");
- config.creatorUid = Integer.parseInt(uid);
- }
-
- if (key.startsWith(BLACKLIST_MILLI_KEY)) {
- String milli = key.replace(BLACKLIST_MILLI_KEY, "");
- milli = milli.replace(SEPARATOR_KEY, "");
- config.blackListTimestamp = Long.parseLong(milli);
- }
-
- if (key.startsWith(NUM_CONNECTION_FAILURES_KEY)) {
- String num = key.replace(NUM_CONNECTION_FAILURES_KEY, "");
- num = num.replace(SEPARATOR_KEY, "");
- config.numConnectionFailures = Integer.parseInt(num);
- }
-
- if (key.startsWith(NUM_IP_CONFIG_FAILURES_KEY)) {
- String num = key.replace(NUM_IP_CONFIG_FAILURES_KEY, "");
- num = num.replace(SEPARATOR_KEY, "");
- config.numIpConfigFailures = Integer.parseInt(num);
- }
-
- if (key.startsWith(NUM_AUTH_FAILURES_KEY)) {
- String num = key.replace(NUM_AUTH_FAILURES_KEY, "");
- num = num.replace(SEPARATOR_KEY, "");
- config.numIpConfigFailures = Integer.parseInt(num);
- }
-
- if (key.startsWith(SCORER_OVERRIDE_KEY)) {
- String num = key.replace(SCORER_OVERRIDE_KEY, "");
- num = num.replace(SEPARATOR_KEY, "");
- config.numScorerOverride = Integer.parseInt(num);
- }
-
- if (key.startsWith(SCORER_OVERRIDE_AND_SWITCH_KEY)) {
- String num = key.replace(SCORER_OVERRIDE_AND_SWITCH_KEY, "");
- num = num.replace(SEPARATOR_KEY, "");
- config.numScorerOverrideAndSwitchedNetwork = Integer.parseInt(num);
- }
-
- if (key.startsWith(NUM_ASSOCIATION_KEY)) {
- String num = key.replace(NUM_ASSOCIATION_KEY, "");
- num = num.replace(SEPARATOR_KEY, "");
- config.numAssociation = Integer.parseInt(num);
- }
-
- if (key.startsWith(JOIN_ATTEMPT_BOOST_KEY)) {
- String num = key.replace(JOIN_ATTEMPT_BOOST_KEY, "");
- num = num.replace(SEPARATOR_KEY, "");
- config.autoJoinUseAggressiveJoinAttemptThreshold = Integer.parseInt(num);
- }
-
- if (key.startsWith(CONNECT_UID_KEY)) {
- String uid = key.replace(CONNECT_UID_KEY, "");
- uid = uid.replace(SEPARATOR_KEY, "");
- config.lastConnectUid = Integer.parseInt(uid);
- }
-
- if (key.startsWith(UPDATE_UID_KEY)) {
- String uid = key.replace(UPDATE_UID_KEY, "");
- uid = uid.replace(SEPARATOR_KEY, "");
- config.lastUpdateUid = Integer.parseInt(uid);
- }
-
- if (key.startsWith(FAILURE_KEY)) {
- config.lastFailure = key.replace(FAILURE_KEY, "");
- config.lastFailure = config.lastFailure.replace(SEPARATOR_KEY, "");
- }
-
- if (key.startsWith(PEER_CONFIGURATION_KEY)) {
- config.peerWifiConfiguration = key.replace(PEER_CONFIGURATION_KEY, "");
- config.peerWifiConfiguration =
- config.peerWifiConfiguration.replace(SEPARATOR_KEY, "");
- }
-
- if (key.startsWith(CHOICE_KEY)) {
- String choiceStr = key.replace(CHOICE_KEY, "");
- choiceStr = choiceStr.replace(SEPARATOR_KEY, "");
- String configKey = "";
- int choice = 0;
- Matcher match = mConnectChoice.matcher(choiceStr);
- if (!match.find()) {
- if (DBG) Log.d(TAG, "WifiConfigStore: connectChoice: " +
- " Couldnt match pattern : " + choiceStr);
- } else {
- configKey = match.group(1);
- try {
- choice = Integer.parseInt(match.group(2));
- } catch (NumberFormatException e) {
- choice = 0;
+ switch (key) {
+ case SSID_KEY:
+ if (config.isPasspoint()) {
+ break;
}
- if (choice > 0) {
- if (config.connectChoices == null) {
- config.connectChoices = new HashMap<String, Integer>();
+ ssid = value;
+ if (config.SSID != null && !config.SSID.equals(ssid)) {
+ loge("Error parsing network history file, mismatched SSIDs");
+ config = null; //error
+ ssid = null;
+ } else {
+ config.SSID = ssid;
+ }
+ break;
+ case FQDN_KEY:
+ // Check for literal 'null' to be backwards compatible.
+ config.FQDN = value.equals("null") ? null : value;
+ break;
+ case DEFAULT_GW_KEY:
+ config.defaultGwMacAddress = value;
+ break;
+ case STATUS_KEY:
+ config.autoJoinStatus = Integer.parseInt(value);
+ break;
+ case SUPPLICANT_DISABLE_REASON_KEY:
+ config.disableReason = Integer.parseInt(value);
+ break;
+ case SELF_ADDED_KEY:
+ config.selfAdded = Boolean.parseBoolean(value);
+ break;
+ case DID_SELF_ADD_KEY:
+ config.didSelfAdd = Boolean.parseBoolean(value);
+ break;
+ case NO_INTERNET_ACCESS_REPORTS_KEY:
+ config.numNoInternetAccessReports = Integer.parseInt(value);
+ break;
+ case VALIDATED_INTERNET_ACCESS_KEY:
+ config.validatedInternetAccess = Boolean.parseBoolean(value);
+ break;
+ case CREATION_TIME_KEY:
+ config.creationTime = value;
+ break;
+ case UPDATE_TIME_KEY:
+ config.updateTime = value;
+ break;
+ case EPHEMERAL_KEY:
+ config.ephemeral = Boolean.parseBoolean(value);
+ break;
+ case CREATOR_UID_KEY:
+ config.creatorUid = Integer.parseInt(value);
+ break;
+ case BLACKLIST_MILLI_KEY:
+ config.blackListTimestamp = Long.parseLong(value);
+ break;
+ case NUM_CONNECTION_FAILURES_KEY:
+ config.numConnectionFailures = Integer.parseInt(value);
+ break;
+ case NUM_IP_CONFIG_FAILURES_KEY:
+ config.numIpConfigFailures = Integer.parseInt(value);
+ break;
+ case NUM_AUTH_FAILURES_KEY:
+ config.numIpConfigFailures = Integer.parseInt(value);
+ break;
+ case SCORER_OVERRIDE_KEY:
+ config.numScorerOverride = Integer.parseInt(value);
+ break;
+ case SCORER_OVERRIDE_AND_SWITCH_KEY:
+ config.numScorerOverrideAndSwitchedNetwork = Integer.parseInt(value);
+ break;
+ case NUM_ASSOCIATION_KEY:
+ config.numAssociation = Integer.parseInt(value);
+ break;
+ case JOIN_ATTEMPT_BOOST_KEY:
+ config.autoJoinUseAggressiveJoinAttemptThreshold =
+ Integer.parseInt(value);
+ break;
+ case CONNECT_UID_KEY:
+ config.lastConnectUid = Integer.parseInt(value);
+ break;
+ case UPDATE_UID_KEY:
+ config.lastUpdateUid = Integer.parseInt(value);
+ break;
+ case FAILURE_KEY:
+ config.lastFailure = value;
+ break;
+ case PEER_CONFIGURATION_KEY:
+ config.peerWifiConfiguration = value;
+ break;
+ case CHOICE_KEY:
+ String configKey = "";
+ int choice = 0;
+ Matcher match = mConnectChoice.matcher(value);
+ if (!match.find()) {
+ if (DBG) Log.d(TAG, "WifiConfigStore: connectChoice: " +
+ " Couldnt match pattern : " + value);
+ } else {
+ configKey = match.group(1);
+ try {
+ choice = Integer.parseInt(match.group(2));
+ } catch (NumberFormatException e) {
+ choice = 0;
}
- config.connectChoices.put(configKey, choice);
+ if (choice > 0) {
+ if (config.connectChoices == null) {
+ config.connectChoices = new HashMap<>();
+ }
+ config.connectChoices.put(configKey, choice);
+ }
}
- }
- }
-
- if (key.startsWith(LINK_KEY)) {
- String configKey = key.replace(LINK_KEY, "");
- configKey = configKey.replace(SEPARATOR_KEY, "");
- if (config.linkedConfigurations == null) {
- config.linkedConfigurations = new HashMap<String, Integer>();
- }
- if (config.linkedConfigurations != null) {
- config.linkedConfigurations.put(configKey, -1);
- }
- }
-
- if (key.startsWith(BSSID_KEY)) {
- if (key.startsWith(BSSID_KEY)) {
- bssid = key.replace(BSSID_KEY, "");
- bssid = bssid.replace(SEPARATOR_KEY, "");
+ break;
+ case LINK_KEY:
+ if (config.linkedConfigurations == null) {
+ config.linkedConfigurations = new HashMap<>();
+ }
+ else {
+ config.linkedConfigurations.put(value, -1);
+ }
+ break;
+ case BSSID_KEY:
+ status = 0;
+ ssid = null;
+ bssid = null;
freq = 0;
seen = 0;
rssi = WifiConfiguration.INVALID_RSSI;
caps = "";
- status = 0;
- }
-
- if (key.startsWith(RSSI_KEY)) {
- String lvl = key.replace(RSSI_KEY, "");
- lvl = lvl.replace(SEPARATOR_KEY, "");
- rssi = Integer.parseInt(lvl);
- }
-
- if (key.startsWith(BSSID_STATUS_KEY)) {
- String st = key.replace(BSSID_STATUS_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- status = Integer.parseInt(st);
- }
-
- if (key.startsWith(FREQ_KEY)) {
- String channel = key.replace(FREQ_KEY, "");
- channel = channel.replace(SEPARATOR_KEY, "");
- freq = Integer.parseInt(channel);
- }
-
- if (key.startsWith(DATE_KEY)) {
- /*
- * when reading the configuration from file we don't update the date
- * so as to avoid reading back stale or non-sensical data that would
- * depend on network time.
- * The date of a WifiConfiguration should only come from actual scan result.
- *
- String s = key.replace(FREQ_KEY, "");
- seen = Integer.getInteger(s);
- */
- }
-
- if (key.startsWith(BSSID_KEY_END)) {
+ break;
+ case RSSI_KEY:
+ rssi = Integer.parseInt(value);
+ break;
+ case BSSID_STATUS_KEY:
+ status = Integer.parseInt(value);
+ break;
+ case FREQ_KEY:
+ freq = Integer.parseInt(value);
+ break;
+ case DATE_KEY:
+ /*
+ * when reading the configuration from file we don't update the date
+ * so as to avoid reading back stale or non-sensical data that would
+ * depend on network time.
+ * The date of a WifiConfiguration should only come from actual scan result.
+ *
+ String s = key.replace(FREQ_KEY, "");
+ seen = Integer.getInteger(s);
+ */
+ break;
+ case BSSID_KEY_END:
if ((bssid != null) && (ssid != null)) {
- if (config.scanResultCache == null) {
- config.scanResultCache = new HashMap<String, ScanResult>();
+ if (getScanDetailCache(config) != null) {
+ WifiSsid wssid = WifiSsid.createFromAsciiEncoded(ssid);
+ ScanDetail scanDetail = new ScanDetail(wssid, bssid,
+ caps, rssi, freq, (long) 0, seen);
+ getScanDetailCache(config).put(scanDetail);
+ scanDetail.getScanResult().autoJoinStatus = status;
}
- WifiSsid wssid = WifiSsid.createFromAsciiEncoded(ssid);
- ScanResult result = new ScanResult(wssid, bssid,
- caps, rssi, freq, (long) 0);
- result.seen = seen;
- config.scanResultCache.put(bssid, result);
- result.autoJoinStatus = status;
}
- }
-
- if (key.startsWith(DELETED_CRC32_KEY)) {
- String crc = key.replace(DELETED_CRC32_KEY, "");
- Long c = Long.parseLong(crc);
- mDeletedSSIDs.add(c);
- }
- if (key.startsWith(DELETED_EPHEMERAL_KEY)) {
- String s = key.replace(DELETED_EPHEMERAL_KEY, "");
- if (!TextUtils.isEmpty(s)) {
- s = s.replace(SEPARATOR_KEY, "");
- mDeletedEphemeralSSIDs.add(s);
+ break;
+ case DELETED_CRC32_KEY:
+ mDeletedSSIDs.add(Long.parseLong(value));
+ break;
+ case DELETED_EPHEMERAL_KEY:
+ if (!TextUtils.isEmpty(value)) {
+ mDeletedEphemeralSSIDs.add(value);
}
- }
+ break;
+ case CREATOR_NAME_KEY:
+ config.creatorName = value;
+ break;
+ case UPDATE_NAME_KEY:
+ config.lastUpdateName = value;
+ break;
+ case USER_APPROVED_KEY:
+ config.userApproved = Integer.parseInt(value);
+ break;
}
}
}
- } catch (EOFException ignore) {
- if (in != null) {
- try {
- in.close();
- } catch (Exception e) {
- loge("readNetworkHistory: Error reading file" + e);
- }
- }
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "readNetworkHistory: failed to read, revert to default, " + e, e);
+ } catch (EOFException e) {
+ // do nothing
} catch (IOException e) {
- loge("readNetworkHistory: No config file, revert to default" + e);
- }
-
- if(in!=null) {
- try {
- in.close();
- } catch (Exception e) {
- loge("readNetworkHistory: Error closing file" + e);
- }
+ Log.e(TAG, "readNetworkHistory: No config file, revert to default, " + e, e);
}
}
private void readAutoJoinConfig() {
- BufferedReader reader = null;
- try {
-
- reader = new BufferedReader(new FileReader(autoJoinConfigFile));
-
+ try (BufferedReader reader = new BufferedReader(new FileReader(autoJoinConfigFile))) {
for (String key = reader.readLine(); key != null; key = reader.readLine()) {
- if (key != null) {
- Log.d(TAG, "readAutoJoinConfig line: " + key);
- }
- if (key.startsWith(ENABLE_AUTO_JOIN_WHILE_ASSOCIATED_KEY)) {
- String st = key.replace(ENABLE_AUTO_JOIN_WHILE_ASSOCIATED_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- enableAutoJoinWhenAssociated = Integer.parseInt(st) != 0;
- Log.d(TAG,"readAutoJoinConfig: enabled = " + enableAutoJoinWhenAssociated);
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
+ Log.d(TAG, "readAutoJoinConfig line: " + key);
+
+ int split = key.indexOf(':');
+ if (split < 0) {
+ continue;
}
- if (key.startsWith(ENABLE_FULL_BAND_SCAN_WHEN_ASSOCIATED_KEY)) {
- String st = key.replace(ENABLE_FULL_BAND_SCAN_WHEN_ASSOCIATED_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- enableFullBandScanWhenAssociated = Integer.parseInt(st) != 0;
- Log.d(TAG,"readAutoJoinConfig: enableFullBandScanWhenAssociated = "
- + enableFullBandScanWhenAssociated);
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
+ String name = key.substring(0, split);
+ Object reference = sKeyMap.get(name);
+ if (reference == null) {
+ continue;
}
- if (key.startsWith(ENABLE_AUTO_JOIN_SCAN_WHILE_ASSOCIATED_KEY)) {
- String st = key.replace(ENABLE_AUTO_JOIN_SCAN_WHILE_ASSOCIATED_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- enableAutoJoinScanWhenAssociated = Integer.parseInt(st) != 0;
- Log.d(TAG,"readAutoJoinConfig: enabled = "
- + enableAutoJoinScanWhenAssociated);
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
-
- if (key.startsWith(ENABLE_CHIP_WAKE_UP_WHILE_ASSOCIATED_KEY)) {
- String st = key.replace(ENABLE_CHIP_WAKE_UP_WHILE_ASSOCIATED_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- enableChipWakeUpWhenAssociated = Integer.parseInt(st) != 0;
- Log.d(TAG,"readAutoJoinConfig: enabled = "
- + enableChipWakeUpWhenAssociated);
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
-
- if (key.startsWith(ENABLE_RSSI_POLL_WHILE_ASSOCIATED_KEY)) {
- String st = key.replace(ENABLE_RSSI_POLL_WHILE_ASSOCIATED_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- enableRssiPollWhenAssociated = Integer.parseInt(st) != 0;
- Log.d(TAG,"readAutoJoinConfig: enabled = "
- + enableRssiPollWhenAssociated);
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
-
- if (key.startsWith(THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_5G_KEY)) {
- String st =
- key.replace(THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_5G_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- thresholdInitialAutoJoinAttemptMin5RSSI = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: thresholdInitialAutoJoinAttemptMin5RSSI = "
- + Integer.toString(thresholdInitialAutoJoinAttemptMin5RSSI));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
-
- if (key.startsWith(THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_24G_KEY)) {
- String st =
- key.replace(THRESHOLD_INITIAL_AUTO_JOIN_ATTEMPT_RSSI_MIN_24G_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- thresholdInitialAutoJoinAttemptMin24RSSI = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: thresholdInitialAutoJoinAttemptMin24RSSI = "
- + Integer.toString(thresholdInitialAutoJoinAttemptMin24RSSI));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
-
- if (key.startsWith(THRESHOLD_UNBLACKLIST_HARD_5G_KEY)) {
- String st = key.replace(THRESHOLD_UNBLACKLIST_HARD_5G_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- thresholdUnblacklistThreshold5Hard = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: thresholdUnblacklistThreshold5Hard = "
- + Integer.toString(thresholdUnblacklistThreshold5Hard));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
- if (key.startsWith(THRESHOLD_UNBLACKLIST_SOFT_5G_KEY)) {
- String st = key.replace(THRESHOLD_UNBLACKLIST_SOFT_5G_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- thresholdUnblacklistThreshold5Soft = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: thresholdUnblacklistThreshold5Soft = "
- + Integer.toString(thresholdUnblacklistThreshold5Soft));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
- if (key.startsWith(THRESHOLD_UNBLACKLIST_HARD_24G_KEY)) {
- String st = key.replace(THRESHOLD_UNBLACKLIST_HARD_24G_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- thresholdUnblacklistThreshold24Hard = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: thresholdUnblacklistThreshold24Hard = "
- + Integer.toString(thresholdUnblacklistThreshold24Hard));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
- if (key.startsWith(THRESHOLD_UNBLACKLIST_SOFT_24G_KEY)) {
- String st = key.replace(THRESHOLD_UNBLACKLIST_SOFT_24G_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- thresholdUnblacklistThreshold24Soft = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: thresholdUnblacklistThreshold24Soft = "
- + Integer.toString(thresholdUnblacklistThreshold24Soft));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
-
- if (key.startsWith(THRESHOLD_GOOD_RSSI_5_KEY)) {
- String st = key.replace(THRESHOLD_GOOD_RSSI_5_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- thresholdGoodRssi5 = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: thresholdGoodRssi5 = "
- + Integer.toString(thresholdGoodRssi5));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
- if (key.startsWith(THRESHOLD_LOW_RSSI_5_KEY)) {
- String st = key.replace(THRESHOLD_LOW_RSSI_5_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- thresholdLowRssi5 = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: thresholdLowRssi5 = "
- + Integer.toString(thresholdLowRssi5));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
- if (key.startsWith(THRESHOLD_BAD_RSSI_5_KEY)) {
- String st = key.replace(THRESHOLD_BAD_RSSI_5_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- thresholdBadRssi5 = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: thresholdBadRssi5 = "
- + Integer.toString(thresholdBadRssi5));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
-
- if (key.startsWith(THRESHOLD_GOOD_RSSI_24_KEY)) {
- String st = key.replace(THRESHOLD_GOOD_RSSI_24_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- thresholdGoodRssi24 = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: thresholdGoodRssi24 = "
- + Integer.toString(thresholdGoodRssi24));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
- if (key.startsWith(THRESHOLD_LOW_RSSI_24_KEY)) {
- String st = key.replace(THRESHOLD_LOW_RSSI_24_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- thresholdLowRssi24 = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: thresholdLowRssi24 = "
- + Integer.toString(thresholdLowRssi24));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
- if (key.startsWith(THRESHOLD_BAD_RSSI_24_KEY)) {
- String st = key.replace(THRESHOLD_BAD_RSSI_24_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- thresholdBadRssi24 = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: thresholdBadRssi24 = "
- + Integer.toString(thresholdBadRssi24));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
-
- if (key.startsWith(THRESHOLD_MAX_TX_PACKETS_FOR_NETWORK_SWITCHING_KEY)) {
- String st = key.replace(THRESHOLD_MAX_TX_PACKETS_FOR_NETWORK_SWITCHING_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- maxTxPacketForNetworkSwitching = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: maxTxPacketForNetworkSwitching = "
- + Integer.toString(maxTxPacketForNetworkSwitching));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
- if (key.startsWith(THRESHOLD_MAX_RX_PACKETS_FOR_NETWORK_SWITCHING_KEY)) {
- String st = key.replace(THRESHOLD_MAX_RX_PACKETS_FOR_NETWORK_SWITCHING_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- maxRxPacketForNetworkSwitching = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: maxRxPacketForNetworkSwitching = "
- + Integer.toString(maxRxPacketForNetworkSwitching));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
-
- if (key.startsWith(THRESHOLD_MAX_TX_PACKETS_FOR_FULL_SCANS_KEY)) {
- String st = key.replace(THRESHOLD_MAX_TX_PACKETS_FOR_FULL_SCANS_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- maxTxPacketForNetworkSwitching = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: maxTxPacketForFullScans = "
- + Integer.toString(maxTxPacketForFullScans));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
- if (key.startsWith(THRESHOLD_MAX_RX_PACKETS_FOR_FULL_SCANS_KEY)) {
- String st = key.replace(THRESHOLD_MAX_RX_PACKETS_FOR_FULL_SCANS_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- maxRxPacketForNetworkSwitching = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: maxRxPacketForFullScans = "
- + Integer.toString(maxRxPacketForFullScans));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
-
- if (key.startsWith(THRESHOLD_MAX_TX_PACKETS_FOR_PARTIAL_SCANS_KEY)) {
- String st = key.replace(THRESHOLD_MAX_TX_PACKETS_FOR_PARTIAL_SCANS_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- maxTxPacketForNetworkSwitching = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: maxTxPacketForPartialScans = "
- + Integer.toString(maxTxPacketForPartialScans));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
- if (key.startsWith(THRESHOLD_MAX_RX_PACKETS_FOR_PARTIAL_SCANS_KEY)) {
- String st = key.replace(THRESHOLD_MAX_RX_PACKETS_FOR_PARTIAL_SCANS_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- maxRxPacketForNetworkSwitching = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: maxRxPacketForPartialScans = "
- + Integer.toString(maxRxPacketForPartialScans));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
-
- if (key.startsWith(WIFI_VERBOSE_LOGS_KEY)) {
- String st = key.replace(WIFI_VERBOSE_LOGS_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- enableVerboseLogging = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: enable verbose logs = "
- + Integer.toString(enableVerboseLogging));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
- if (key.startsWith(A_BAND_PREFERENCE_RSSI_THRESHOLD_KEY)) {
- String st = key.replace(A_BAND_PREFERENCE_RSSI_THRESHOLD_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- bandPreferenceBoostThreshold5 = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: bandPreferenceBoostThreshold5 = "
- + Integer.toString(bandPreferenceBoostThreshold5));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
- if (key.startsWith(ASSOCIATED_PARTIAL_SCAN_PERIOD_KEY)) {
- String st = key.replace(ASSOCIATED_PARTIAL_SCAN_PERIOD_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- associatedPartialScanPeriodMilli = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: associatedScanPeriod = "
- + Integer.toString(associatedPartialScanPeriodMilli));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
- if (key.startsWith(ASSOCIATED_FULL_SCAN_BACKOFF_KEY)) {
- String st = key.replace(ASSOCIATED_FULL_SCAN_BACKOFF_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- associatedFullScanBackoff = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: associatedFullScanBackoff = "
- + Integer.toString(associatedFullScanBackoff));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
- if (key.startsWith(G_BAND_PREFERENCE_RSSI_THRESHOLD_KEY)) {
- String st = key.replace(G_BAND_PREFERENCE_RSSI_THRESHOLD_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- bandPreferencePenaltyThreshold5 = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: bandPreferencePenaltyThreshold5 = "
- + Integer.toString(bandPreferencePenaltyThreshold5));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
- if (key.startsWith(ALWAYS_ENABLE_SCAN_WHILE_ASSOCIATED_KEY)) {
- String st = key.replace(ALWAYS_ENABLE_SCAN_WHILE_ASSOCIATED_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- alwaysEnableScansWhileAssociated = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: alwaysEnableScansWhileAssociated = "
- + Integer.toString(alwaysEnableScansWhileAssociated));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
- if (key.startsWith(MAX_NUM_PASSIVE_CHANNELS_FOR_PARTIAL_SCANS_KEY)) {
- String st = key.replace(MAX_NUM_PASSIVE_CHANNELS_FOR_PARTIAL_SCANS_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- maxNumPassiveChannelsForPartialScans = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: maxNumPassiveChannelsForPartialScans = "
- + Integer.toString(maxNumPassiveChannelsForPartialScans));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
- if (key.startsWith(MAX_NUM_ACTIVE_CHANNELS_FOR_PARTIAL_SCANS_KEY)) {
- String st = key.replace(MAX_NUM_ACTIVE_CHANNELS_FOR_PARTIAL_SCANS_KEY, "");
- st = st.replace(SEPARATOR_KEY, "");
- try {
- maxNumActiveChannelsForPartialScans = Integer.parseInt(st);
- Log.d(TAG,"readAutoJoinConfig: maxNumActiveChannelsForPartialScans = "
- + Integer.toString(maxNumActiveChannelsForPartialScans));
- } catch (NumberFormatException e) {
- Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
- }
- }
- }
- } catch (EOFException ignore) {
- if (reader != null) {
try {
- reader.close();
- reader = null;
- } catch (Exception e) {
- loge("readAutoJoinStatus: Error closing file" + e);
+ int value = Integer.parseInt(key.substring(split+1).trim());
+ if (reference.getClass() == AtomicBoolean.class) {
+ ((AtomicBoolean)reference).set(value != 0);
+ }
+ else {
+ ((AtomicInteger)reference).set(value);
+ }
+ Log.d(TAG,"readAutoJoinConfig: " + name + " = " + value);
}
- }
- } catch (FileNotFoundException ignore) {
- if (reader != null) {
- try {
- reader.close();
- reader = null;
- } catch (Exception e) {
- loge("readAutoJoinStatus: Error closing file" + e);
+ catch (NumberFormatException nfe) {
+ Log.d(TAG,"readAutoJoinConfig: incorrect format :" + key);
}
}
} catch (IOException e) {
loge("readAutoJoinStatus: Error parsing configuration" + e);
}
-
- if (reader!=null) {
- try {
- reader.close();
- } catch (Exception e) {
- loge("readAutoJoinStatus: Error closing file" + e);
- }
- }
}
@@ -2595,8 +2576,8 @@
for (int i = 0; i < networks.size(); i++) {
int id = networks.keyAt(i);
- WifiConfiguration config = mConfiguredNetworks.get(mNetworkIds.get(id));
-
+ WifiConfiguration config = mConfiguredNetworks.getByConfigKeyID(id);
+ // This is the only place the map is looked up through a (dangerous) hash-value!
if (config == null || config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED ||
config.ephemeral) {
@@ -2615,9 +2596,8 @@
* and that can confuses the supplicant because it uses space charaters as delimiters
*/
- private String encodeSSID(String str){
- String tmp = removeDoubleQuotes(str);
- return String.format("%x", new BigInteger(1, tmp.getBytes(Charset.forName("UTF-8"))));
+ public static String encodeSSID(String str){
+ return Utils.toHex(removeDoubleQuotes(str).getBytes(StandardCharsets.UTF_8));
}
private NetworkUpdateResult addOrUpdateNetworkNative(WifiConfiguration config, int uid) {
@@ -2628,27 +2608,23 @@
*/
if (VDBG) localLog("addOrUpdateNetworkNative " + config.getPrintableSsid());
+ if (config.isPasspoint() && !mMOManager.isEnabled()) {
+ Log.e(TAG, "Passpoint is not enabled");
+ return new NetworkUpdateResult(INVALID_NETWORK_ID);
+ }
int netId = config.networkId;
boolean newNetwork = false;
// networkId of INVALID_NETWORK_ID means we want to create a new network
if (netId == INVALID_NETWORK_ID) {
- Integer savedNetId = mNetworkIds.get(configKey(config));
- // Check if either we have a network Id or a WifiConfiguration
- // matching the one we are trying to add.
- if (savedNetId == null) {
- for (WifiConfiguration test : mConfiguredNetworks.values()) {
- if (test.configKey().equals(config.configKey())) {
- savedNetId = test.networkId;
- loge("addOrUpdateNetworkNative " + config.configKey()
- + " was found, but no network Id");
- break;
- }
- }
- }
- if (savedNetId != null) {
- netId = savedNetId;
+ WifiConfiguration savedConfig = mConfiguredNetworks.getByConfigKey(config.configKey());
+ if (savedConfig != null) {
+ netId = savedConfig.networkId;
} else {
+ if (mMOManager.getHomeSP(config.FQDN) != null) {
+ loge("addOrUpdateNetworkNative passpoint " + config.FQDN
+ + " was found, but no network Id");
+ }
newNetwork = true;
netId = mWifiNative.addNetwork();
if (netId < 0) {
@@ -2673,8 +2649,18 @@
break setVariables;
}
+ if (config.isPasspoint()) {
+ if (!mWifiNative.setNetworkVariable(
+ netId,
+ idStringVarName,
+ '"' + config.FQDN + '"')) {
+ loge("failed to set id_str: " + config.FQDN);
+ break setVariables;
+ }
+ }
+
if (config.BSSID != null) {
- loge("Setting BSSID for " + config.configKey() + " to " + config.BSSID);
+ log("Setting BSSID for " + config.configKey() + " to " + config.BSSID);
if (!mWifiNative.setNetworkVariable(
netId,
WifiConfiguration.bssidVarName,
@@ -2862,6 +2848,11 @@
// No need to try to set an obfuscated password, which will fail
continue;
}
+ if (key.equals(WifiEnterpriseConfig.REALM_KEY)
+ || key.equals(WifiEnterpriseConfig.PLMN_KEY)) {
+ // No need to save realm or PLMN in supplicant
+ continue;
+ }
if (!mWifiNative.setNetworkVariable(
netId,
key,
@@ -2907,15 +2898,54 @@
currentConfig.lastConnectUid = config.lastConnectUid;
currentConfig.lastUpdateUid = config.lastUpdateUid;
currentConfig.creatorUid = config.creatorUid;
+ currentConfig.creatorName = config.creatorName;
+ currentConfig.lastUpdateName = config.lastUpdateName;
currentConfig.peerWifiConfiguration = config.peerWifiConfiguration;
+ currentConfig.FQDN = config.FQDN;
+ currentConfig.providerFriendlyName = config.providerFriendlyName;
+ currentConfig.roamingConsortiumIds = config.roamingConsortiumIds;
+ currentConfig.validatedInternetAccess = config.validatedInternetAccess;
+ currentConfig.numNoInternetAccessReports = config.numNoInternetAccessReports;
+ currentConfig.updateTime = config.updateTime;
+ currentConfig.creationTime = config.creationTime;
}
if (DBG) {
- loge("created new config netId=" + Integer.toString(netId)
- + " uid=" + Integer.toString(currentConfig.creatorUid));
+ log("created new config netId=" + Integer.toString(netId)
+ + " uid=" + Integer.toString(currentConfig.creatorUid)
+ + " name=" + currentConfig.creatorName);
}
}
- if (uid >= 0) {
+ /* save HomeSP object for passpoint networks */
+ HomeSP homeSP = null;
+
+ if (config.isPasspoint()) {
+ try {
+ Credential credential =
+ new Credential(config.enterpriseConfig, mKeyStore, !newNetwork);
+ HashSet<Long> roamingConsortiumIds = new HashSet<Long>();
+ for (Long roamingConsortiumId : config.roamingConsortiumIds) {
+ roamingConsortiumIds.add(roamingConsortiumId);
+ }
+
+ homeSP = new HomeSP(Collections.<String, Long>emptyMap(), config.FQDN,
+ roamingConsortiumIds, Collections.<String>emptySet(),
+ Collections.<Long>emptySet(), Collections.<Long>emptyList(),
+ config.providerFriendlyName, null, credential);
+
+ log("created a homeSP object for " + config.networkId + ":" + config.SSID);
+
+ /* fix enterprise config properties for passpoint */
+ currentConfig.enterpriseConfig.setRealm(config.enterpriseConfig.getRealm());
+ currentConfig.enterpriseConfig.setPlmn(config.enterpriseConfig.getPlmn());
+ }
+ catch (IOException ioe) {
+ Log.e(TAG, "Failed to create Passpoint config: " + ioe);
+ return new NetworkUpdateResult(INVALID_NETWORK_ID);
+ }
+ }
+
+ if (uid != WifiConfiguration.UNKNOWN_UID) {
if (newNetwork) {
currentConfig.creatorUid = uid;
} else {
@@ -2923,8 +2953,18 @@
}
}
+ // For debug, record the time the configuration was modified
+ StringBuilder sb = new StringBuilder();
+ sb.append("time=");
+ Calendar c = Calendar.getInstance();
+ c.setTimeInMillis(System.currentTimeMillis());
+ sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
+
if (newNetwork) {
currentConfig.dirty = true;
+ currentConfig.creationTime = sb.toString();
+ } else {
+ currentConfig.updateTime = sb.toString();
}
if (currentConfig.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED) {
@@ -2934,7 +2974,7 @@
currentConfig.selfAdded = false;
currentConfig.didSelfAdd = false;
if (DBG) {
- loge("remove deleted status netId=" + Integer.toString(netId)
+ log("remove deleted status netId=" + Integer.toString(netId)
+ " " + currentConfig.configKey());
}
}
@@ -2948,26 +2988,59 @@
currentConfig.ephemeral) {
// Make the config non-ephemeral since the user just explicitly clicked it.
currentConfig.ephemeral = false;
- if (DBG) loge("remove ephemeral status netId=" + Integer.toString(netId)
+ if (DBG) log("remove ephemeral status netId=" + Integer.toString(netId)
+ " " + currentConfig.configKey());
}
- if (DBG) loge("will read network variables netId=" + Integer.toString(netId));
+ if (VDBG) log("will read network variables netId=" + Integer.toString(netId));
readNetworkVariables(currentConfig);
+ // Persist configuration paramaters that are not saved by supplicant.
+ if (config.lastUpdateName != null) {
+ currentConfig.lastUpdateName = config.lastUpdateName;
+ }
+ if (config.lastUpdateUid != WifiConfiguration.UNKNOWN_UID) {
+ currentConfig.lastUpdateUid = config.lastUpdateUid;
+ }
+
mConfiguredNetworks.put(netId, currentConfig);
- mNetworkIds.put(configKey(currentConfig), netId);
NetworkUpdateResult result = writeIpAndProxyConfigurationsOnChange(currentConfig, config);
result.setIsNewNetwork(newNetwork);
result.setNetworkId(netId);
+ if (homeSP != null) {
+ writePasspointConfigs(null, homeSP);
+ }
writeKnownNetworkHistory(false);
return result;
}
+ public WifiConfiguration getWifiConfigForHomeSP(HomeSP homeSP) {
+ WifiConfiguration config = mConfiguredNetworks.getByFQDN(homeSP.getFQDN());
+ if (config == null) {
+ Log.e(TAG, "Could not find network for homeSP " + homeSP.getFQDN());
+ }
+ return config;
+ }
+
+ private HomeSP getHomeSPForConfig(WifiConfiguration config) {
+ WifiConfiguration storedConfig = mConfiguredNetworks.get(config.networkId);
+ return storedConfig != null && storedConfig.isPasspoint() ?
+ mMOManager.getHomeSP(storedConfig.FQDN) : null;
+ }
+
+ public ScanDetailCache getScanDetailCache(WifiConfiguration config) {
+ if (config == null) return null;
+ ScanDetailCache cache = mScanDetailCaches.get(config.networkId);
+ if (cache == null && config.networkId != WifiConfiguration.INVALID_NETWORK_ID) {
+ cache = new ScanDetailCache(config);
+ mScanDetailCaches.put(config.networkId, cache);
+ }
+ return cache;
+ }
/**
* This function run thru the Saved WifiConfigurations and check if some should be linked.
@@ -2975,7 +3048,7 @@
*/
public void linkConfiguration(WifiConfiguration config) {
- if (config.scanResultCache != null && config.scanResultCache.size() > 6) {
+ if (getScanDetailCache(config) != null && getScanDetailCache(config).size() > 6) {
// Ignore configurations with large number of BSSIDs
return;
}
@@ -3000,7 +3073,8 @@
continue;
}
- if (link.scanResultCache != null && link.scanResultCache.size() > 6) {
+ ScanDetailCache linkedScanDetailCache = getScanDetailCache(link);
+ if (linkedScanDetailCache != null && linkedScanDetailCache.size() > 6) {
// Ignore configurations with large number of BSSIDs
continue;
}
@@ -3019,10 +3093,11 @@
// hoping that WifiConfigurations are indeed behind the same gateway.
// once both WifiConfiguration have been tried and thus once both efault gateways
// are known we will revisit the choice of linking them
- if ((config.scanResultCache != null) && (config.scanResultCache.size() <= 6)
- && (link.scanResultCache != null) && (link.scanResultCache.size() <= 6)) {
- for (String abssid : config.scanResultCache.keySet()) {
- for (String bbssid : link.scanResultCache.keySet()) {
+ if ((getScanDetailCache(config) != null)
+ && (getScanDetailCache(config).size() <= 6)) {
+
+ for (String abssid : getScanDetailCache(config).keySet()) {
+ for (String bbssid : linkedScanDetailCache.keySet()) {
if (VVDBG) {
loge("linkConfiguration try to link due to DBDC BSSID match "
+ link.SSID +
@@ -3052,8 +3127,8 @@
if (doLink) {
if (VDBG) {
- loge("linkConfiguration: will link " + link.configKey()
- + " and " + config.configKey());
+ loge("linkConfiguration: will link " + link.configKey()
+ + " and " + config.configKey());
}
if (link.linkedConfigurations == null) {
link.linkedConfigurations = new HashMap<String, Integer>();
@@ -3092,139 +3167,6 @@
}
}
- /*
- * We try to link a scan result with a WifiConfiguration for which SSID and
- * key management dont match,
- * for instance, we try identify the 5GHz SSID of a DBDC AP,
- * even though we know only of the 2.4GHz
- *
- * Obviously, this function is not optimal since it is used to compare every scan
- * result with every Saved WifiConfiguration, with a string.equals operation.
- * As a speed up, might be better to implement the mConfiguredNetworks store as a
- * <String, WifiConfiguration> object instead of a <Integer, WifiConfiguration> object
- * so as to speed this up. Also to prevent the tiny probability of hash collision.
- *
- */
- public WifiConfiguration associateWithConfiguration(ScanResult result) {
- boolean doNotAdd = false;
- String configKey = WifiConfiguration.configKey(result);
- if (configKey == null) {
- if (DBG) loge("associateWithConfiguration(): no config key " );
- return null;
- }
-
- // Need to compare with quoted string
- String SSID = "\"" + result.SSID + "\"";
-
- if (VVDBG) {
- loge("associateWithConfiguration(): try " + configKey);
- }
-
- Checksum csum = new CRC32();
- csum.update(SSID.getBytes(), 0, SSID.getBytes().length);
- if (mDeletedSSIDs.contains(csum.getValue())) {
- doNotAdd = true;
- }
-
- WifiConfiguration config = null;
- for (WifiConfiguration link : mConfiguredNetworks.values()) {
- boolean doLink = false;
-
- if (link.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED || link.selfAdded ||
- link.ephemeral) {
- if (VVDBG) loge("associateWithConfiguration(): skip selfadd " + link.configKey() );
- // Make sure we dont associate the scan result to a deleted config
- continue;
- }
-
- if (!link.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
- if (VVDBG) loge("associateWithConfiguration(): skip non-PSK " + link.configKey() );
- // Make sure we dont associate the scan result to a non-PSK config
- continue;
- }
-
- if (configKey.equals(link.configKey())) {
- if (VVDBG) loge("associateWithConfiguration(): found it!!! " + configKey );
- return link; // Found it exactly
- }
-
- if (!doNotAdd && (link.scanResultCache != null) && (link.scanResultCache.size() <= 6)) {
- for (String bssid : link.scanResultCache.keySet()) {
- if (result.BSSID.regionMatches(true, 0, bssid, 0, 16)
- && SSID.regionMatches(false, 0, link.SSID, 0, 4)) {
- // If first 16 ascii characters of BSSID matches, and first 3
- // characters of SSID match, we assume this is a home setup
- // and thus we will try to transfer the password from the known
- // BSSID/SSID to the recently found BSSID/SSID
-
- // If (VDBG)
- // loge("associateWithConfiguration OK " );
- doLink = true;
- break;
- }
- }
- }
-
- if (doLink) {
- // Try to make a non verified WifiConfiguration, but only if the original
- // configuration was not self already added
- if (VDBG) {
- loge("associateWithConfiguration: try to create " +
- result.SSID + " and associate it with: " + link.SSID
- + " key " + link.configKey());
- }
- config = wifiConfigurationFromScanResult(result);
- if (config != null) {
- config.selfAdded = true;
- config.didSelfAdd = true;
- config.dirty = true;
- config.peerWifiConfiguration = link.configKey();
- if (config.allowedKeyManagement.equals(link.allowedKeyManagement) &&
- config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
- if (VDBG && config != null) {
- loge("associateWithConfiguration: got a config from beacon"
- + config.SSID + " key " + config.configKey());
- }
- // Transfer the credentials from the configuration we are linking from
- String psk = readNetworkVariableFromSupplicantFile(link.SSID, "psk");
- if (psk != null) {
- config.preSharedKey = psk;
- if (VDBG) {
- if (config.preSharedKey != null)
- loge(" transfer PSK : " + config.preSharedKey);
- }
-
- // Link configurations
- if (link.linkedConfigurations == null) {
- link.linkedConfigurations = new HashMap<String, Integer>();
- }
- if (config.linkedConfigurations == null) {
- config.linkedConfigurations = new HashMap<String, Integer>();
- }
- link.linkedConfigurations.put(config.configKey(), Integer.valueOf(1));
- config.linkedConfigurations.put(link.configKey(), Integer.valueOf(1));
-
- // Carry over the Ip configuration
- if (link.getIpConfiguration() != null) {
- config.setIpConfiguration(link.getIpConfiguration());
- }
- } else {
- config = null;
- }
- } else {
- config = null;
- }
- if (config != null) break;
- }
- if (VDBG && config != null) {
- loge("associateWithConfiguration: success, created: " + config.SSID
- + " key " + config.configKey());
- }
- }
- }
- return config;
- }
-
public HashSet<Integer> makeChannelList(WifiConfiguration config, int age, boolean restrict) {
if (config == null)
return null;
@@ -3233,7 +3175,7 @@
HashSet<Integer> channels = new HashSet<Integer>();
//get channels for this configuration, if there are at least 2 BSSIDs
- if (config.scanResultCache == null && config.linkedConfigurations == null) {
+ if (getScanDetailCache(config) == null && config.linkedConfigurations == null) {
return null;
}
@@ -3242,8 +3184,8 @@
dbg.append("makeChannelList age=" + Integer.toString(age)
+ " for " + config.configKey()
+ " max=" + maxNumActiveChannelsForPartialScans);
- if (config.scanResultCache != null) {
- dbg.append(" bssids=" + config.scanResultCache.size());
+ if (getScanDetailCache(config) != null) {
+ dbg.append(" bssids=" + getScanDetailCache(config).size());
}
if (config.linkedConfigurations != null) {
dbg.append(" linked=" + config.linkedConfigurations.size());
@@ -3252,10 +3194,11 @@
}
int numChannels = 0;
- if (config.scanResultCache != null && config.scanResultCache.size() > 0) {
- for (ScanResult result : config.scanResultCache.values()) {
+ if (getScanDetailCache(config) != null && getScanDetailCache(config).size() > 0) {
+ for (ScanDetail scanDetail : getScanDetailCache(config).values()) {
+ ScanResult result = scanDetail.getScanResult();
//TODO : cout active and passive channels separately
- if (numChannels > maxNumActiveChannelsForPartialScans) {
+ if (numChannels > maxNumActiveChannelsForPartialScans.get()) {
break;
}
if (VDBG) {
@@ -3276,16 +3219,17 @@
WifiConfiguration linked = getWifiConfiguration(key);
if (linked == null)
continue;
- if (linked.scanResultCache == null) {
+ if (getScanDetailCache(linked) == null) {
continue;
}
- for (ScanResult result : linked.scanResultCache.values()) {
+ for (ScanDetail scanDetail : getScanDetailCache(linked).values()) {
+ ScanResult result = scanDetail.getScanResult();
if (VDBG) {
loge("has link: " + result.BSSID
+ " freq=" + Integer.toString(result.frequency)
+ " age=" + Long.toString(now_ms - result.seen));
}
- if (numChannels > maxNumActiveChannelsForPartialScans) {
+ if (numChannels > maxNumActiveChannelsForPartialScans.get()) {
break;
}
if (((now_ms - result.seen) < age)/*||(!restrict || result.is24GHz())*/) {
@@ -3298,15 +3242,214 @@
return channels;
}
+ private Map<HomeSP, PasspointMatch> matchPasspointNetworks(ScanDetail scanDetail) {
+ if (!mMOManager.isConfigured()) {
+ return null;
+ }
+ NetworkDetail networkDetail = scanDetail.getNetworkDetail();
+ if (!networkDetail.hasInterworking()) {
+ return null;
+ }
+ updateAnqpCache(scanDetail, networkDetail.getANQPElements());
+
+ Map<HomeSP, PasspointMatch> matches = matchNetwork(scanDetail, true);
+ Log.d(Utils.hs2LogTag(getClass()), scanDetail.getSSID() +
+ " pass 1 matches: " + toMatchString(matches));
+ return matches;
+ }
+
+ private Map<HomeSP, PasspointMatch> matchNetwork(ScanDetail scanDetail, boolean query) {
+ NetworkDetail networkDetail = scanDetail.getNetworkDetail();
+
+ ANQPData anqpData = mAnqpCache.getEntry(networkDetail);
+
+ Map<Constants.ANQPElementType, ANQPElement> anqpElements =
+ anqpData != null ? anqpData.getANQPElements() : null;
+
+ boolean queried = !query;
+ Collection<HomeSP> homeSPs = mMOManager.getLoadedSPs().values();
+ Map<HomeSP, PasspointMatch> matches = new HashMap<>(homeSPs.size());
+ Log.d(Utils.hs2LogTag(getClass()), "match nwk " + scanDetail.toKeyString() +
+ ", anqp " + ( anqpData != null ? "present" : "missing" ) +
+ ", query " + query + ", home sps: " + homeSPs.size());
+
+ for (HomeSP homeSP : homeSPs) {
+ PasspointMatch match = homeSP.match(networkDetail, anqpElements, mSIMAccessor);
+
+ Log.d(Utils.hs2LogTag(getClass()), " -- " +
+ homeSP.getFQDN() + ": match " + match + ", queried " + queried);
+
+ if (match == PasspointMatch.Incomplete && !queried) {
+ if (mAnqpCache.initiate(networkDetail)) {
+ mSupplicantBridge.startANQP(scanDetail);
+ }
+ queried = true;
+ }
+ matches.put(homeSP, match);
+ }
+ return matches;
+ }
+
+ public void notifyANQPDone(Long bssid, boolean success) {
+ mSupplicantBridge.notifyANQPDone(bssid, success);
+ }
+
+ public void notifyANQPResponse(ScanDetail scanDetail,
+ Map<Constants.ANQPElementType, ANQPElement> anqpElements) {
+
+ updateAnqpCache(scanDetail, anqpElements);
+ if (anqpElements == null || anqpElements.isEmpty()) {
+ return;
+ }
+ scanDetail.propagateANQPInfo(anqpElements);
+
+ Map<HomeSP, PasspointMatch> matches = matchNetwork(scanDetail, false);
+ Log.d(Utils.hs2LogTag(getClass()), scanDetail.getSSID() +
+ " pass 2 matches: " + toMatchString(matches));
+
+ cacheScanResultForPasspointConfigs(scanDetail, matches);
+ }
+
+
+ private void updateAnqpCache(ScanDetail scanDetail,
+ Map<Constants.ANQPElementType,ANQPElement> anqpElements)
+ {
+ NetworkDetail networkDetail = scanDetail.getNetworkDetail();
+
+ if (anqpElements == null) {
+ // Try to pull cached data if query failed.
+ ANQPData data = mAnqpCache.getEntry(networkDetail);
+ if (data != null) {
+ scanDetail.propagateANQPInfo(data.getANQPElements());
+ }
+ return;
+ }
+
+ mAnqpCache.update(networkDetail, anqpElements);
+ }
+
+ private static String toMatchString(Map<HomeSP, PasspointMatch> matches) {
+ StringBuilder sb = new StringBuilder();
+ for (Map.Entry<HomeSP, PasspointMatch> entry : matches.entrySet()) {
+ sb.append(' ').append(entry.getKey().getFQDN()).append("->").append(entry.getValue());
+ }
+ return sb.toString();
+ }
+
+ private void cacheScanResultForPasspointConfigs(ScanDetail scanDetail,
+ Map<HomeSP,PasspointMatch> matches) {
+
+ for (Map.Entry<HomeSP, PasspointMatch> entry : matches.entrySet()) {
+ PasspointMatch match = entry.getValue();
+ if (match == PasspointMatch.HomeProvider || match == PasspointMatch.RoamingProvider) {
+ WifiConfiguration config = getWifiConfigForHomeSP(entry.getKey());
+ if (config != null) {
+ cacheScanResultForConfig(config, scanDetail, entry.getValue());
+ } else {
+ Log.w(Utils.hs2LogTag(getClass()), "Failed to find config for '" +
+ entry.getKey().getFQDN() + "'");
+ /* perhaps the configuration was deleted?? */
+ }
+ }
+ }
+ }
+
+ private void cacheScanResultForConfig(
+ WifiConfiguration config, ScanDetail scanDetail, PasspointMatch passpointMatch) {
+
+ ScanResult scanResult = scanDetail.getScanResult();
+
+ if (config.autoJoinStatus >= WifiConfiguration.AUTO_JOIN_DELETED) {
+ if (VVDBG) {
+ loge("updateSavedNetworkHistory(): found a deleted, skip it... "
+ + config.configKey());
+ }
+ // The scan result belongs to a deleted config:
+ // - increment numConfigFound to remember that we found a config
+ // matching for this scan result
+ // - dont do anything since the config was deleted, just skip...
+ return;
+ }
+
+ ScanDetailCache scanDetailCache = getScanDetailCache(config);
+ if (scanDetailCache == null) {
+ Log.w(TAG, "Could not allocate scan cache for " + config.SSID);
+ return;
+ }
+
+ // Adding a new BSSID
+ ScanResult result = scanDetailCache.get(scanResult.BSSID);
+ if (result != null) {
+ // transfer the black list status
+ scanResult.autoJoinStatus = result.autoJoinStatus;
+ scanResult.blackListTimestamp = result.blackListTimestamp;
+ scanResult.numIpConfigFailures = result.numIpConfigFailures;
+ scanResult.numConnection = result.numConnection;
+ scanResult.isAutoJoinCandidate = result.isAutoJoinCandidate;
+ }
+
+ if (config.ephemeral) {
+ // For an ephemeral Wi-Fi config, the ScanResult should be considered
+ // untrusted.
+ scanResult.untrusted = true;
+ }
+
+ if (scanDetailCache.size() > (maxNumScanCacheEntries + 64)) {
+ long now_dbg = 0;
+ if (VVDBG) {
+ loge(" Will trim config " + config.configKey()
+ + " size " + scanDetailCache.size());
+
+ for (ScanDetail sd : scanDetailCache.values()) {
+ loge(" " + sd.getBSSIDString() + " " + sd.getSeen());
+ }
+ now_dbg = SystemClock.elapsedRealtimeNanos();
+ }
+ // Trim the scan result cache to maxNumScanCacheEntries entries max
+ // Since this operation is expensive, make sure it is not performed
+ // until the cache has grown significantly above the trim treshold
+ scanDetailCache.trim(maxNumScanCacheEntries);
+ if (VVDBG) {
+ long diff = SystemClock.elapsedRealtimeNanos() - now_dbg;
+ loge(" Finished trimming config, time(ns) " + diff);
+ for (ScanDetail sd : scanDetailCache.values()) {
+ loge(" " + sd.getBSSIDString() + " " + sd.getSeen());
+ }
+ }
+ }
+
+ // Add the scan result to this WifiConfiguration
+ if (passpointMatch != null)
+ scanDetailCache.put(scanDetail, passpointMatch, getHomeSPForConfig(config));
+ else
+ scanDetailCache.put(scanDetail);
+
+ // Since we added a scan result to this configuration, re-attempt linking
+ linkConfiguration(config);
+ }
+
+
// Update the WifiConfiguration database with the new scan result
// A scan result can be associated to multiple WifiConfigurations
- public boolean updateSavedNetworkHistory(ScanResult scanResult) {
+ public boolean updateSavedNetworkHistory(ScanDetail scanDetail) {
+
+ ScanResult scanResult = scanDetail.getScanResult();
+ NetworkDetail networkDetail = scanDetail.getNetworkDetail();
+
int numConfigFound = 0;
if (scanResult == null)
return false;
String SSID = "\"" + scanResult.SSID + "\"";
+ if (networkDetail.hasInterworking()) {
+ Map<HomeSP, PasspointMatch> matches = matchPasspointNetworks(scanDetail);
+ if (matches != null) {
+ cacheScanResultForPasspointConfigs(scanDetail, matches);
+ return matches.size() != 0;
+ }
+ }
+
for (WifiConfiguration config : mConfiguredNetworks.values()) {
boolean found = false;
@@ -3344,70 +3487,7 @@
if (found) {
numConfigFound ++;
-
- if (config.autoJoinStatus >= WifiConfiguration.AUTO_JOIN_DELETED) {
- if (VVDBG) {
- loge("updateSavedNetworkHistory(): found a deleted, skip it... "
- + config.configKey());
- }
- // The scan result belongs to a deleted config:
- // - increment numConfigFound to remember that we found a config
- // matching for this scan result
- // - dont do anything since the config was deleted, just skip...
- continue;
- }
-
- if (config.scanResultCache == null) {
- config.scanResultCache = new HashMap<String, ScanResult>();
- }
-
- // Adding a new BSSID
- ScanResult result = config.scanResultCache.get(scanResult.BSSID);
- if (result == null) {
- config.dirty = true;
- } else {
- // transfer the black list status
- scanResult.autoJoinStatus = result.autoJoinStatus;
- scanResult.blackListTimestamp = result.blackListTimestamp;
- scanResult.numIpConfigFailures = result.numIpConfigFailures;
- scanResult.numConnection = result.numConnection;
- scanResult.isAutoJoinCandidate = result.isAutoJoinCandidate;
- }
-
- if (config.ephemeral) {
- // For an ephemeral Wi-Fi config, the ScanResult should be considered
- // untrusted.
- scanResult.untrusted = true;
- }
-
- if (config.scanResultCache.size() > (maxNumScanCacheEntries + 64)) {
- long now_dbg = 0;
- if (VVDBG) {
- loge(" Will trim config " + config.configKey()
- + " size " + config.scanResultCache.size());
-
- for (ScanResult r : config.scanResultCache.values()) {
- loge(" " + result.BSSID + " " + result.seen);
- }
- now_dbg = SystemClock.elapsedRealtimeNanos();
- }
- // Trim the scan result cache to maxNumScanCacheEntries entries max
- // Since this operation is expensive, make sure it is not performed
- // until the cache has grown significantly above the trim treshold
- config.trimScanResultsCache(maxNumScanCacheEntries);
- if (VVDBG) {
- long diff = SystemClock.elapsedRealtimeNanos() - now_dbg;
- loge(" Finished trimming config, time(ns) " + diff);
- for (ScanResult r : config.scanResultCache.values()) {
- loge(" " + r.BSSID + " " + r.seen);
- }
- }
- }
-
- // Add the scan result to this WifiConfiguration
- config.scanResultCache.put(scanResult.BSSID, scanResult);
- // Since we added a scan result to this configuration, re-attempt linking
- linkConfiguration(config);
+ cacheScanResultForConfig(config, scanDetail, null);
}
if (VDBG && found) {
@@ -3418,7 +3498,7 @@
loge(" got known scan result " +
scanResult.BSSID + " key : "
+ config.configKey() + " num: " +
- Integer.toString(config.scanResultCache.size())
+ Integer.toString(getScanDetailCache(config).size())
+ " rssi=" + Integer.toString(scanResult.level)
+ " freq=" + Integer.toString(scanResult.frequency)
+ status);
@@ -3609,70 +3689,20 @@
config.preSharedKey = null;
}
- value = mWifiNative.getNetworkVariable(config.networkId,
- WifiConfiguration.Protocol.varName);
- if (!TextUtils.isEmpty(value)) {
- String vals[] = value.split(" ");
- for (String val : vals) {
- int index =
- lookupString(val, WifiConfiguration.Protocol.strings);
- if (0 <= index) {
- config.allowedProtocols.set(index);
- }
- }
- }
+ readNetworkBitsetVariable(config.networkId, config.allowedProtocols,
+ WifiConfiguration.Protocol.varName, WifiConfiguration.Protocol.strings);
- value = mWifiNative.getNetworkVariable(config.networkId,
- WifiConfiguration.KeyMgmt.varName);
- if (!TextUtils.isEmpty(value)) {
- String vals[] = value.split(" ");
- for (String val : vals) {
- int index =
- lookupString(val, WifiConfiguration.KeyMgmt.strings);
- if (0 <= index) {
- config.allowedKeyManagement.set(index);
- }
- }
- }
+ readNetworkBitsetVariable(config.networkId, config.allowedKeyManagement,
+ WifiConfiguration.KeyMgmt.varName, WifiConfiguration.KeyMgmt.strings);
- value = mWifiNative.getNetworkVariable(config.networkId,
- WifiConfiguration.AuthAlgorithm.varName);
- if (!TextUtils.isEmpty(value)) {
- String vals[] = value.split(" ");
- for (String val : vals) {
- int index =
- lookupString(val, WifiConfiguration.AuthAlgorithm.strings);
- if (0 <= index) {
- config.allowedAuthAlgorithms.set(index);
- }
- }
- }
+ readNetworkBitsetVariable(config.networkId, config.allowedAuthAlgorithms,
+ WifiConfiguration.AuthAlgorithm.varName, WifiConfiguration.AuthAlgorithm.strings);
- value = mWifiNative.getNetworkVariable(config.networkId,
- WifiConfiguration.PairwiseCipher.varName);
- if (!TextUtils.isEmpty(value)) {
- String vals[] = value.split(" ");
- for (String val : vals) {
- int index =
- lookupString(val, WifiConfiguration.PairwiseCipher.strings);
- if (0 <= index) {
- config.allowedPairwiseCiphers.set(index);
- }
- }
- }
+ readNetworkBitsetVariable(config.networkId, config.allowedPairwiseCiphers,
+ WifiConfiguration.PairwiseCipher.varName, WifiConfiguration.PairwiseCipher.strings);
- value = mWifiNative.getNetworkVariable(config.networkId,
- WifiConfiguration.GroupCipher.varName);
- if (!TextUtils.isEmpty(value)) {
- String vals[] = value.split(" ");
- for (String val : vals) {
- int index =
- lookupString(val, WifiConfiguration.GroupCipher.strings);
- if (0 <= index) {
- config.allowedGroupCiphers.set(index);
- }
- }
- }
+ readNetworkBitsetVariable(config.networkId, config.allowedGroupCiphers,
+ WifiConfiguration.GroupCipher.varName, WifiConfiguration.GroupCipher.strings);
if (config.enterpriseConfig == null) {
config.enterpriseConfig = new WifiEnterpriseConfig();
@@ -3746,7 +3776,9 @@
/* return the allowed key management based on a scan result */
- public WifiConfiguration wifiConfigurationFromScanResult(ScanResult result) {
+ public WifiConfiguration wifiConfigurationFromScanResult(ScanDetail scanDetail) {
+
+ ScanResult result = scanDetail.getScanResult();
WifiConfiguration config = new WifiConfiguration();
config.SSID = "\"" + result.SSID + "\"";
@@ -3771,10 +3803,7 @@
config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
}
- config.scanResultCache = new HashMap<String, ScanResult>();
- if (config.scanResultCache == null)
- return null;
- config.scanResultCache.put(result.BSSID, result);
+ /* getScanDetailCache(config).put(scanDetail); */
return config;
}
@@ -3790,16 +3819,26 @@
pw.println("Dump of WifiConfigStore");
pw.println("mLastPriority " + mLastPriority);
pw.println("Configured networks");
- for (WifiConfiguration conf : getConfiguredNetworks()) {
+ for (WifiConfiguration conf : getAllConfiguredNetworks()) {
pw.println(conf);
}
pw.println();
-
+ if (mLostConfigsDbg != null && mLostConfigsDbg.size() > 0) {
+ pw.println("LostConfigs: ");
+ for (String s : mLostConfigsDbg) {
+ pw.println(s);
+ }
+ }
if (mLocalLog != null) {
pw.println("WifiConfigStore - Log Begin ----");
mLocalLog.dump(fd, pw, args);
pw.println("WifiConfigStore - Log End ----");
}
+ if (mMOManager.isConfigured()) {
+ pw.println("Begin dump of ANQP Cache");
+ mAnqpCache.dump(pw);
+ pw.println("End dump of ANQP Cache");
+ }
}
public String getConfigFile() {
@@ -3821,6 +3860,14 @@
}
}
+ private void logKernelTime() {
+ long kernelTimeMs = System.nanoTime()/(1000*1000);
+ StringBuilder builder = new StringBuilder();
+ builder.append("kernel time = ").append(kernelTimeMs/1000).append(".").append
+ (kernelTimeMs%1000).append("\n");
+ localLog(builder.toString());
+ }
+
protected void log(String s) {
Log.d(TAG, s);
}
@@ -3842,7 +3889,7 @@
}
WifiConfiguration config;
- synchronized(mConfiguredNetworks) {
+ synchronized(mConfiguredNetworks) { // !!! Useless synchronization
config = mConfiguredNetworks.get(netId);
}
@@ -3928,6 +3975,112 @@
return false;
}
+ boolean isNetworkConfigured(WifiConfiguration config) {
+ // Check if either we have a network Id or a WifiConfiguration
+ // matching the one we are trying to add.
+
+ if(config.networkId != INVALID_NETWORK_ID) {
+ return (mConfiguredNetworks.get(config.networkId) != null);
+ }
+
+ return (mConfiguredNetworks.getByConfigKey(config.configKey()) != null);
+ }
+
+ /**
+ * Checks if uid has access to modify the configuration corresponding to networkId.
+ *
+ * Factors involved in modifiability of a config are as follows.
+ * If uid is a Device Owner app then it has full control over the device, including WiFi
+ * configs.
+ * If the modification is only for administrative annotation (e.g. when connecting) or the
+ * config is not lockdown eligible (currently that means any config not last updated by the DO)
+ * then the creator of config or an app holding OVERRIDE_CONFIG_WIFI can modify the config.
+ * If the config is lockdown eligible and the modification is substantial (not annotation)
+ * then the requirement to be able to modify the config by the uid is as follows:
+ * a) the uid has to hold OVERRIDE_CONFIG_WIFI and
+ * b) the lockdown feature should be disabled.
+ */
+ boolean canModifyNetwork(int uid, int networkId, boolean onlyAnnotate) {
+ WifiConfiguration config = mConfiguredNetworks.get(networkId);
+
+ if (config == null) {
+ loge("canModifyNetwork: cannot find config networkId " + networkId);
+ return false;
+ }
+
+ final DevicePolicyManagerInternal dpmi = LocalServices.getService(
+ DevicePolicyManagerInternal.class);
+
+ final boolean isUidDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(uid,
+ DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+
+ if (isUidDeviceOwner) {
+ // Device Owner has full control over the device, including WiFi Configs
+ return true;
+ }
+
+ final boolean isCreator = (config.creatorUid == uid);
+
+ if (onlyAnnotate) {
+ return isCreator || checkConfigOverridePermission(uid);
+ }
+
+ // Check if device has DPM capability. If it has and dpmi is still null, then we
+ // treat this case with suspicion and bail out.
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)
+ && dpmi == null) {
+ return false;
+ }
+
+ // WiFi config lockdown related logic. At this point we know uid NOT to be a Device Owner.
+
+ final boolean isConfigEligibleForLockdown = dpmi != null && dpmi.isActiveAdminWithPolicy(
+ config.creatorUid, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ if (!isConfigEligibleForLockdown) {
+ return isCreator || checkConfigOverridePermission(uid);
+ }
+
+ final ContentResolver resolver = mContext.getContentResolver();
+ final boolean isLockdownFeatureEnabled = Settings.Global.getInt(resolver,
+ Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0) != 0;
+ return !isLockdownFeatureEnabled && checkConfigOverridePermission(uid);
+ }
+
+ /**
+ * Checks if uid has access to modify config.
+ */
+ boolean canModifyNetwork(int uid, WifiConfiguration config, boolean onlyAnnotate) {
+ if (config == null) {
+ loge("canModifyNetowrk recieved null configuration");
+ return false;
+ }
+
+ // Resolve the correct network id.
+ int netid;
+ if (config.networkId != INVALID_NETWORK_ID){
+ netid = config.networkId;
+ } else {
+ WifiConfiguration test = mConfiguredNetworks.getByConfigKey(config.configKey());
+ if (test == null) {
+ return false;
+ } else {
+ netid = test.networkId;
+ }
+ }
+
+ return canModifyNetwork(uid, netid, onlyAnnotate);
+ }
+
+ boolean checkConfigOverridePermission(int uid) {
+ try {
+ return (AppGlobals.getPackageManager().checkUidPermission(
+ android.Manifest.permission.OVERRIDE_WIFI_CONFIG, uid)
+ == PackageManager.PERMISSION_GRANTED);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
/** called when CS ask WiFistateMachine to disconnect the current network
* because the score is bad.
*/
@@ -3962,16 +4115,17 @@
// Look for the BSSID in our config store
for (WifiConfiguration config : mConfiguredNetworks.values()) {
- if (config.scanResultCache != null) {
- for (ScanResult result: config.scanResultCache.values()) {
- if (result.BSSID.equals(BSSID)) {
+ if (getScanDetailCache(config) != null) {
+ for (ScanDetail scanDetail : getScanDetailCache(config).values()) {
+ if (scanDetail.getBSSIDString().equals(BSSID)) {
if (enable) {
- result.setAutoJoinStatus(ScanResult.ENABLED);
+ scanDetail.getScanResult().setAutoJoinStatus(ScanResult.ENABLED);
} else {
// Black list the BSSID we were trying to join
// so as the Roam state machine
// doesn't pick it up over and over
- result.setAutoJoinStatus(ScanResult.AUTO_ROAM_DISABLED);
+ scanDetail.getScanResult().setAutoJoinStatus(
+ ScanResult.AUTO_ROAM_DISABLED);
found = true;
}
}
@@ -3987,20 +4141,48 @@
DEFAULT_MAX_DHCP_RETRIES);
}
+ void clearBssidBlacklist() {
+ if (!mWifiStateMachine.useHalBasedAutoJoinOffload()) {
+ if(DBG) {
+ Log.d(TAG, "No blacklist allowed without epno enabled");
+ }
+ return;
+ }
+ mBssidBlacklist = new HashSet<String>();
+ mWifiNative.clearBlacklist();
+ mWifiNative.setBssidBlacklist(null);
+ }
+
+ void blackListBssid(String BSSID) {
+ if (!mWifiStateMachine.useHalBasedAutoJoinOffload()) {
+ if(DBG) {
+ Log.d(TAG, "No blacklist allowed without epno enabled");
+ }
+ return;
+ }
+ if (BSSID == null)
+ return;
+ mBssidBlacklist.add(BSSID);
+ // Blacklist at wpa_supplicant
+ mWifiNative.addToBlacklist(BSSID);
+ // Blacklist at firmware
+ String list[] = new String[mBssidBlacklist.size()];
+ int count = 0;
+ for (String bssid : mBssidBlacklist) {
+ list[count++] = bssid;
+ }
+ mWifiNative.setBssidBlacklist(list);
+ }
+
void handleSSIDStateChange(int netId, boolean enabled, String message, String BSSID) {
WifiConfiguration config = mConfiguredNetworks.get(netId);
if (config != null) {
if (enabled) {
- loge("SSID re-enabled for " + config.configKey() +
+ loge("Ignoring SSID re-enabled from supplicant: " + config.configKey() +
" had autoJoinStatus=" + Integer.toString(config.autoJoinStatus)
+ " self added " + config.selfAdded + " ephemeral " + config.ephemeral);
- //TODO: http://b/16381983 Fix Wifi Network Blacklisting
- //TODO: really I don't know if re-enabling is right but we
- //TODO: should err on the side of trying to connect
- //TODO: even if the attempt will fail
- if (config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) {
- config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
- }
+ //We should not re-enable the BSSID based on Supplicant reanable.
+ // Framework will re-enable it after its own blacklist timer expires
} else {
loge("SSID temp disabled for " + config.configKey() +
" had autoJoinStatus=" + Integer.toString(config.autoJoinStatus)
@@ -4059,8 +4241,8 @@
// Also blacklist the BSSId if we find it
ScanResult result = null;
String bssidDbg = "";
- if (config.scanResultCache != null && BSSID != null) {
- result = config.scanResultCache.get(BSSID);
+ if (getScanDetailCache(config) != null && BSSID != null) {
+ result = getScanDetailCache(config).get(BSSID);
}
if (result != null) {
result.numIpConfigFailures ++;
@@ -4130,7 +4312,7 @@
ret = putCertInKeyStore(userCertName, config.getClientCertificate());
if (ret == false) {
// Remove private key installed
- mKeyStore.delKey(privKeyName, Process.WIFI_UID);
+ mKeyStore.delete(privKeyName, Process.WIFI_UID);
return ret;
}
}
@@ -4140,7 +4322,7 @@
if (ret == false) {
if (config.getClientCertificate() != null) {
// Remove client key+cert
- mKeyStore.delKey(privKeyName, Process.WIFI_UID);
+ mKeyStore.delete(privKeyName, Process.WIFI_UID);
mKeyStore.delete(userCertName, Process.WIFI_UID);
}
return ret;
@@ -4179,7 +4361,7 @@
// a valid client certificate is configured
if (!TextUtils.isEmpty(client)) {
if (DBG) Log.d(TAG, "removing client private key and user cert");
- mKeyStore.delKey(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID);
+ mKeyStore.delete(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID);
mKeyStore.delete(Credentials.USER_CERTIFICATE + client, Process.WIFI_UID);
}
@@ -4269,4 +4451,18 @@
}
}
+ private void readNetworkBitsetVariable(int netId, BitSet variable, String varName,
+ String[] strings) {
+ String value = mWifiNative.getNetworkVariable(netId, varName);
+ if (!TextUtils.isEmpty(value)) {
+ variable.clear();
+ String vals[] = value.split(" ");
+ for (String val : vals) {
+ int index = lookupString(val, strings);
+ if (0 <= index) {
+ variable.set(index);
+ }
+ }
+ }
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiController.java b/service/java/com/android/server/wifi/WifiController.java
index 8f36cb7..3b41e3b 100644
--- a/service/java/com/android/server/wifi/WifiController.java
+++ b/service/java/com/android/server/wifi/WifiController.java
@@ -114,6 +114,7 @@
static final int CMD_SET_AP = BASE + 10;
static final int CMD_DEFERRED_TOGGLE = BASE + 11;
static final int CMD_USER_PRESENT = BASE + 12;
+ static final int CMD_AP_START_FAILURE = BASE + 13;
private DefaultState mDefaultState = new DefaultState();
private StaEnabledState mStaEnabledState = new StaEnabledState();
@@ -172,6 +173,7 @@
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_DEVICE_IDLE);
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
mContext.registerReceiver(
new BroadcastReceiver() {
@Override
@@ -182,6 +184,14 @@
} else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
WifiManager.EXTRA_NETWORK_INFO);
+ } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
+ int state = intent.getIntExtra(
+ WifiManager.EXTRA_WIFI_AP_STATE,
+ WifiManager.WIFI_AP_STATE_FAILED);
+ if(state == WifiManager.WIFI_AP_STATE_FAILED) {
+ loge(TAG + "SoftAP start failed");
+ sendMessage(CMD_AP_START_FAILURE);
+ }
}
}
},
@@ -371,6 +381,7 @@
case CMD_WIFI_TOGGLED:
case CMD_AIRPLANE_TOGGLED:
case CMD_EMERGENCY_MODE_CHANGED:
+ case CMD_AP_START_FAILURE:
break;
case CMD_USER_PRESENT:
mFirstUserSignOnSeen = true;
@@ -398,6 +409,7 @@
mDisabledTimestamp = SystemClock.elapsedRealtime();
mDeferredEnableSerialNumber++;
mHaveDeferredEnable = false;
+ mWifiStateMachine.clearANQPCache();
}
@Override
public boolean processMessage(Message msg) {
@@ -519,6 +531,7 @@
mDisabledTimestamp = SystemClock.elapsedRealtime();
mDeferredEnableSerialNumber++;
mHaveDeferredEnable = false;
+ mWifiStateMachine.clearANQPCache();
}
@Override
@@ -607,6 +620,12 @@
transitionTo(mApStaDisabledState);
}
break;
+ case CMD_AP_START_FAILURE:
+ if(!mSettingsStore.isScanAlwaysAvailable()) {
+ transitionTo(mApStaDisabledState);
+ } else {
+ transitionTo(mStaDisabledWithScanState);
+ }
default:
return NOT_HANDLED;
}
diff --git a/service/java/com/android/server/wifi/WifiLogger.java b/service/java/com/android/server/wifi/WifiLogger.java
new file mode 100644
index 0000000..8add779
--- /dev/null
+++ b/service/java/com/android/server/wifi/WifiLogger.java
@@ -0,0 +1,450 @@
+/*
+ * Copyright (C) 2010 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 com.android.internal.app.IBatteryStats;
+import com.android.internal.util.Protocol;
+
+import android.support.v4.util.CircularArray;
+import android.util.Base64;
+import android.util.LocalLog;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.zip.Deflater;
+
+/**
+ * Tracks various logs for framework
+ */
+class WifiLogger {
+
+ private static final String TAG = "WifiLogger";
+ private static final boolean DBG = false;
+
+ /** log level flags; keep these consistent with wifi_logger.h */
+
+ /** No logs whatsoever */
+ public static final int VERBOSE_NO_LOG = 0;
+ /** No logs whatsoever */
+ public static final int VERBOSE_NORMAL_LOG = 1;
+ /** Be careful since this one can affect performance and power */
+ public static final int VERBOSE_LOG_WITH_WAKEUP = 2;
+ /** Be careful since this one can affect performance and power and memory */
+ public static final int VERBOSE_DETAILED_LOG_WITH_WAKEUP = 3;
+
+ /** ring buffer flags; keep these consistent with wifi_logger.h */
+ public static final int RING_BUFFER_FLAG_HAS_BINARY_ENTRIES = 0x00000001;
+ public static final int RING_BUFFER_FLAG_HAS_ASCII_ENTRIES = 0x00000002;
+ public static final int RING_BUFFER_FLAG_HAS_PER_PACKET_ENTRIES = 0x00000004;
+
+ /** various reason codes */
+ public static final int REPORT_REASON_NONE = 0;
+ public static final int REPORT_REASON_ASSOC_FAILURE = 1;
+ public static final int REPORT_REASON_AUTH_FAILURE = 2;
+ public static final int REPORT_REASON_AUTOROAM_FAILURE = 3;
+ public static final int REPORT_REASON_DHCP_FAILURE = 4;
+ public static final int REPORT_REASON_UNEXPECTED_DISCONNECT = 5;
+ public static final int REPORT_REASON_SCAN_FAILURE = 6;
+ public static final int REPORT_REASON_USER_ACTION = 7;
+
+ /** number of ring buffer entries to cache */
+ public static final int MAX_RING_BUFFERS = 10;
+
+ /** number of bug reports to hold */
+ public static final int MAX_BUG_REPORTS = 4;
+
+ /** number of alerts to hold */
+ public static final int MAX_ALERT_REPORTS = 1;
+
+ /** minimum wakeup interval for each of the log levels */
+ private static final int MinWakeupIntervals[] = new int[] { 0, 3600, 60, 10 };
+ /** minimum buffer size for each of the log levels */
+ private static final int MinBufferSizes[] = new int[] { 0, 16384, 16384, 65536 };
+
+ private int mLogLevel = VERBOSE_NO_LOG;
+ private String mFirmwareVersion;
+ private String mDriverVersion;
+ private int mSupportedFeatureSet;
+ private WifiNative.RingBufferStatus[] mRingBuffers;
+ private WifiNative.RingBufferStatus mPerPacketRingBuffer;
+ private WifiStateMachine mWifiStateMachine;
+
+ public WifiLogger(WifiStateMachine wifiStateMachine) {
+ mWifiStateMachine = wifiStateMachine;
+ }
+
+ public synchronized void startLogging(boolean verboseEnabled) {
+ mFirmwareVersion = WifiNative.getFirmwareVersion();
+ mDriverVersion = WifiNative.getDriverVersion();
+ mSupportedFeatureSet = WifiNative.getSupportedLoggerFeatureSet();
+
+ if (mLogLevel == VERBOSE_NO_LOG)
+ WifiNative.setLoggingEventHandler(mHandler);
+
+ if (verboseEnabled) {
+ mLogLevel = VERBOSE_LOG_WITH_WAKEUP;
+ } else {
+ mLogLevel = VERBOSE_NORMAL_LOG;
+ }
+ if (mRingBuffers == null) {
+ if (fetchRingBuffers()) {
+ startLoggingAllExceptPerPacketBuffers();
+ }
+ }
+ }
+
+ public synchronized void startPacketLog() {
+ if (mPerPacketRingBuffer != null) {
+ startLoggingRingBuffer(mPerPacketRingBuffer);
+ } else {
+ if (DBG) Log.d(TAG, "There is no per packet ring buffer");
+ }
+ }
+
+ public synchronized void stopPacketLog() {
+ if (mPerPacketRingBuffer != null) {
+ stopLoggingRingBuffer(mPerPacketRingBuffer);
+ } else {
+ if (DBG) Log.d(TAG, "There is no per packet ring buffer");
+ }
+ }
+
+ public synchronized void stopLogging() {
+ if (mLogLevel != VERBOSE_NO_LOG) {
+ //resetLogHandler only can be used when you terminate all logging since all handler will
+ //be removed. This also stop alert logging
+ if(!WifiNative.resetLogHandler()) {
+ Log.e(TAG, "Fail to reset log handler");
+ } else {
+ if (DBG) Log.d(TAG,"Reset log handler");
+ }
+ stopLoggingAllBuffers();
+ mRingBuffers = null;
+ mLogLevel = VERBOSE_NO_LOG;
+ }
+ }
+
+ public synchronized void captureBugReportData(int reason) {
+ BugReport report = captureBugreport(reason, true);
+ mLastBugReports.addLast(report);
+ }
+
+ public synchronized void captureAlertData(int errorCode, byte[] alertData) {
+ BugReport report = captureBugreport(errorCode, /* captureFWDump = */ true);
+ report.alertData = alertData;
+ mLastAlerts.addLast(report);
+ }
+
+ public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("Chipset information :-----------------------------------------------");
+ pw.println("FW Version is: " + mFirmwareVersion);
+ pw.println("Driver Version is: " + mDriverVersion);
+ pw.println("Supported Feature set: " + mSupportedFeatureSet);
+
+ for (int i = 0; i < mLastAlerts.size(); i++) {
+ pw.println("--------------------------------------------------------------------");
+ pw.println("Alert dump " + i);
+ pw.print(mLastAlerts.get(i));
+ pw.println("--------------------------------------------------------------------");
+ }
+
+ for (int i = 0; i < mLastBugReports.size(); i++) {
+ pw.println("--------------------------------------------------------------------");
+ pw.println("Bug dump " + i);
+ pw.print(mLastBugReports.get(i));
+ pw.println("--------------------------------------------------------------------");
+ }
+
+ pw.println("--------------------------------------------------------------------");
+ }
+
+ /* private methods and data */
+ private static class BugReport {
+ long systemTimeMs;
+ long kernelTimeNanos;
+ int errorCode;
+ HashMap<String, byte[][]> ringBuffers = new HashMap();
+ byte[] fwMemoryDump;
+ byte[] alertData;
+
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+
+ Calendar c = Calendar.getInstance();
+ c.setTimeInMillis(systemTimeMs);
+ builder.append("system time = ").append(
+ String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)).append("\n");
+
+ long kernelTimeMs = kernelTimeNanos/(1000*1000);
+ builder.append("kernel time = ").append(kernelTimeMs/1000).append(".").append
+ (kernelTimeMs%1000).append("\n");
+
+ if (alertData == null)
+ builder.append("reason = ").append(errorCode).append("\n");
+ else {
+ builder.append("errorCode = ").append(errorCode);
+ builder.append("data \n");
+ builder.append(compressToBase64(alertData)).append("\n");
+ }
+
+ for (HashMap.Entry<String, byte[][]> e : ringBuffers.entrySet()) {
+ String ringName = e.getKey();
+ byte[][] buffers = e.getValue();
+ builder.append("ring-buffer = ").append(ringName).append("\n");
+
+ int size = 0;
+ for (int i = 0; i < buffers.length; i++) {
+ size += buffers[i].length;
+ }
+
+ byte[] buffer = new byte[size];
+ int index = 0;
+ for (int i = 0; i < buffers.length; i++) {
+ System.arraycopy(buffers[i], 0, buffer, index, buffers[i].length);
+ index += buffers[i].length;
+ }
+
+ builder.append(compressToBase64(buffer));
+ builder.append("\n");
+ }
+
+ if (fwMemoryDump != null) {
+ builder.append("FW Memory dump \n");
+ builder.append(compressToBase64(fwMemoryDump));
+ }
+
+ return builder.toString();
+ }
+ }
+
+ static class LimitedCircularArray<E> {
+ private CircularArray<E> mArray;
+ private int mMax;
+ LimitedCircularArray(int max) {
+ mArray = new CircularArray<E>();
+ mMax = max;
+ }
+
+ public final void addLast(E e) {
+ if (mArray.size() >= mMax)
+ mArray.popFirst();
+ mArray.addLast(e);
+ }
+
+ public final int size() {
+ return mArray.size();
+ }
+
+ public final E get(int i) {
+ return mArray.get(i);
+ }
+ }
+
+ private final LimitedCircularArray<BugReport> mLastAlerts =
+ new LimitedCircularArray<BugReport>(MAX_ALERT_REPORTS);
+ private final LimitedCircularArray<BugReport> mLastBugReports =
+ new LimitedCircularArray<BugReport>(MAX_BUG_REPORTS);
+ private final HashMap<String, LimitedCircularArray<byte[]>> mRingBufferData = new HashMap();
+
+ private final WifiNative.WifiLoggerEventHandler mHandler =
+ new WifiNative.WifiLoggerEventHandler() {
+ @Override
+ public void onRingBufferData(WifiNative.RingBufferStatus status, byte[] buffer) {
+ WifiLogger.this.onRingBufferData(status, buffer);
+ }
+
+ @Override
+ public void onWifiAlert(int errorCode, byte[] buffer) {
+ WifiLogger.this.onWifiAlert(errorCode, buffer);
+ }
+ };
+
+ synchronized void onRingBufferData(WifiNative.RingBufferStatus status, byte[] buffer) {
+ LimitedCircularArray<byte[]> ring = mRingBufferData.get(status.name);
+ if (ring != null) {
+ ring.addLast(buffer);
+ }
+ }
+
+ synchronized void onWifiAlert(int errorCode, byte[] buffer) {
+ if (mWifiStateMachine != null) {
+ mWifiStateMachine.sendMessage(
+ WifiStateMachine.CMD_FIRMWARE_ALERT, errorCode, 0, buffer);
+ }
+ }
+
+ private boolean fetchRingBuffers() {
+ if (mRingBuffers != null) return true;
+
+ mRingBuffers = WifiNative.getRingBufferStatus();
+ if (mRingBuffers != null) {
+ for (WifiNative.RingBufferStatus buffer : mRingBuffers) {
+ if (DBG) Log.d(TAG, "RingBufferStatus is: \n" + buffer.name);
+ if (mRingBufferData.containsKey(buffer.name) == false) {
+ mRingBufferData.put(buffer.name,
+ new LimitedCircularArray<byte[]>(MAX_RING_BUFFERS));
+ }
+ if ((buffer.flag & RING_BUFFER_FLAG_HAS_PER_PACKET_ENTRIES) != 0) {
+ mPerPacketRingBuffer = buffer;
+ }
+ }
+ } else {
+ Log.e(TAG, "no ring buffers found");
+ }
+
+ return mRingBuffers != null;
+ }
+
+ private boolean startLoggingAllExceptPerPacketBuffers() {
+
+ if (mRingBuffers == null) {
+ if (DBG) Log.d(TAG, "No ring buffers to log anything!");
+ return false;
+ }
+
+ for (WifiNative.RingBufferStatus buffer : mRingBuffers){
+
+ if ((buffer.flag & RING_BUFFER_FLAG_HAS_PER_PACKET_ENTRIES) != 0) {
+ /* skip per-packet-buffer */
+ if (DBG) Log.d(TAG, "skipped per packet logging ring " + buffer.name);
+ continue;
+ }
+
+ startLoggingRingBuffer(buffer);
+ }
+
+ return true;
+ }
+
+ private boolean startLoggingRingBuffer(WifiNative.RingBufferStatus buffer) {
+
+ int minInterval = MinWakeupIntervals[mLogLevel];
+ int minDataSize = MinBufferSizes[mLogLevel];
+
+ if (WifiNative.startLoggingRingBuffer(
+ mLogLevel, 0, minInterval, minDataSize, buffer.name) == false) {
+ if (DBG) Log.e(TAG, "Could not start logging ring " + buffer.name);
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean stopLoggingRingBuffer(WifiNative.RingBufferStatus buffer) {
+ if (WifiNative.startLoggingRingBuffer(0, 0, 0, 0, buffer.name) == false) {
+ if (DBG) Log.e(TAG, "Could not stop logging ring " + buffer.name);
+ }
+ return true;
+ }
+
+ private boolean stopLoggingAllBuffers() {
+ if (mRingBuffers != null) {
+ for (WifiNative.RingBufferStatus buffer : mRingBuffers) {
+ stopLoggingRingBuffer(buffer);
+ }
+ }
+ return true;
+ }
+
+ private boolean getAllRingBufferData() {
+ if (mRingBuffers == null) {
+ Log.e(TAG, "Not ring buffers available to collect data!");
+ return false;
+ }
+
+ for (WifiNative.RingBufferStatus element : mRingBuffers){
+ boolean result = WifiNative.getRingBufferData(element.name);
+ if (!result) {
+ Log.e(TAG, "Fail to get ring buffer data of: " + element.name);
+ return false;
+ }
+ }
+
+ Log.d(TAG, "getAllRingBufferData Successfully!");
+ return true;
+ }
+
+ private BugReport captureBugreport(int errorCode, boolean captureFWDump) {
+ BugReport report = new BugReport();
+ report.errorCode = errorCode;
+ report.systemTimeMs = System.currentTimeMillis();
+ report.kernelTimeNanos = System.nanoTime();
+
+ if (mRingBuffers != null) {
+ for (WifiNative.RingBufferStatus buffer : mRingBuffers) {
+ /* this will push data in mRingBuffers */
+ WifiNative.getRingBufferData(buffer.name);
+ LimitedCircularArray<byte[]> data = mRingBufferData.get(buffer.name);
+ byte[][] buffers = new byte[data.size()][];
+ for (int i = 0; i < data.size(); i++) {
+ buffers[i] = data.get(i).clone();
+ }
+ report.ringBuffers.put(buffer.name, buffers);
+ }
+ }
+
+ if (captureFWDump) {
+ report.fwMemoryDump = WifiNative.getFwMemoryDump();
+ }
+ return report;
+ }
+
+ private static String compressToBase64(byte[] input) {
+ String result;
+ //compress
+ Deflater compressor = new Deflater();
+ compressor.setLevel(Deflater.BEST_COMPRESSION);
+ compressor.setInput(input);
+ compressor.finish();
+ ByteArrayOutputStream bos = new ByteArrayOutputStream(input.length);
+ final byte[] buf = new byte[1024];
+
+ while (!compressor.finished()) {
+ int count = compressor.deflate(buf);
+ bos.write(buf, 0, count);
+ }
+
+ try {
+ compressor.end();
+ bos.close();
+ } catch (IOException e) {
+ Log.e(TAG, "ByteArrayOutputStream close error");
+ result = android.util.Base64.encodeToString(input, Base64.DEFAULT);
+ return result;
+ }
+
+ byte[] compressed = bos.toByteArray();
+ if (DBG) {
+ Log.d(TAG," length is:" + (compressed == null? "0" : compressed.length));
+ }
+
+ //encode
+ result = android.util.Base64.encodeToString(
+ compressed.length < input.length ? compressed : input , Base64.DEFAULT);
+
+ if (DBG) {
+ Log.d(TAG, "FwMemoryDump length is :" + result.length());
+ }
+
+ return result;
+ }
+}
diff --git a/service/java/com/android/server/wifi/WifiMonitor.java b/service/java/com/android/server/wifi/WifiMonitor.java
index c0aa2f6..9758d57 100644
--- a/service/java/com/android/server/wifi/WifiMonitor.java
+++ b/service/java/com/android/server/wifi/WifiMonitor.java
@@ -27,10 +27,11 @@
import android.net.wifi.p2p.WifiP2pProvDiscEvent;
import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
import android.os.Message;
-import android.os.SystemClock;
import android.text.TextUtils;
+import android.util.LocalLog;
import android.util.Log;
+import com.android.server.wifi.hotspot2.Utils;
import com.android.server.wifi.p2p.WifiP2pServiceImpl.P2pStatus;
import com.android.internal.util.Protocol;
@@ -66,9 +67,10 @@
private static final int ASSOC_REJECT = 9;
private static final int SSID_TEMP_DISABLE = 10;
private static final int SSID_REENABLE = 11;
- private static final int BSS_ADDED = 12;
- private static final int BSS_REMOVED = 13;
+ private static final int BSS_ADDED = 12;
+ private static final int BSS_REMOVED = 13;
private static final int UNKNOWN = 14;
+ private static final int SCAN_FAILED = 15;
/** All events coming from the supplicant start with this prefix */
private static final String EVENT_PREFIX_STR = "CTRL-EVENT-";
@@ -158,6 +160,13 @@
/**
* <pre>
+ * CTRL-EVENT-SCAN-FAILED ret=code[ retry=1]
+ * </pre>
+ */
+ private static final String SCAN_FAILED_STR = "SCAN-FAILED";
+
+ /**
+ * <pre>
* CTRL-EVENT-LINK-SPEED x Mb/s
* </pre>
* {@code x} is the link speed in Mb/sec.
@@ -189,6 +198,10 @@
*/
private static final String EAP_AUTH_FAILURE_STR = "EAP authentication failed";
+ /* EAP authentication timeout events */
+ private static final String AUTH_EVENT_PREFIX_STR = "Authentication with";
+ private static final String AUTH_TIMEOUT_STR = "timed out.";
+
/**
* This indicates an assoc reject event
*/
@@ -277,6 +290,19 @@
Pattern.compile("SIM-([0-9]*):GSM-AUTH((:[0-9a-f]+)+) needed for SSID (.+)");
/**
+ * Regex pattern for extracting an external 3G sim authentication request from a string.
+ * Matches a strings like the following:<pre>
+ * CTRL-REQ-SIM-<network id>:UMTS-AUTH:<RAND>:<AUTN> needed for SSID <SSID>
+ * This pattern should find
+ * 1 - id
+ * 2 - Rand
+ * 3 - Autn
+ * 4 - SSID
+ */
+ private static Pattern mRequestUmtsAuthPattern =
+ Pattern.compile("SIM-([0-9]*):UMTS-AUTH:([0-9a-f]+):([0-9a-f]+) needed for SSID (.+)");
+
+ /**
* Regex pattern for extracting SSIDs from request identity string.
* Matches a strings like the following:<pre>
* CTRL-REQ-IDENTITY-xx:Identity needed for SSID XXXX</pre>
@@ -396,6 +422,7 @@
private static final String AP_STA_CONNECTED_STR = "AP-STA-CONNECTED";
/* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 */
private static final String AP_STA_DISCONNECTED_STR = "AP-STA-DISCONNECTED";
+ private static final String ANQP_DONE_STR = "ANQP-QUERY-DONE";
/* Supplicant events reported to a state machine */
private static final int BASE = Protocol.BASE_WIFI_MONITOR;
@@ -436,6 +463,8 @@
/* Request SIM Auth */
public static final int SUP_REQUEST_SIM_AUTH = BASE + 16;
+ public static final int SCAN_FAILED_EVENT = BASE + 17;
+
/* P2P events */
public static final int P2P_DEVICE_FOUND_EVENT = BASE + 21;
public static final int P2P_DEVICE_LOST_EVENT = BASE + 22;
@@ -462,6 +491,7 @@
/* Indicates assoc reject event */
public static final int ASSOCIATION_REJECTION_EVENT = BASE + 43;
+ public static final int ANQP_DONE_EVENT = BASE + 44;
/* hotspot 2.0 ANQP events */
public static final int GAS_QUERY_START_EVENT = BASE + 51;
@@ -569,8 +599,8 @@
if (mWifiNative.connectToSupplicant()) {
m.mMonitoring = true;
m.mStateMachine.sendMessage(SUP_CONNECTION_EVENT);
- new MonitorThread(mWifiNative, this).start();
mConnected = true;
+ new MonitorThread(mWifiNative, this).start();
break;
}
if (connectTries++ < 5) {
@@ -579,7 +609,6 @@
} catch (InterruptedException ignore) {
}
} else {
- mIfaceMap.remove(iface);
m.mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
Log.e(TAG, "startMonitoring(" + iface + ") failed!");
break;
@@ -633,6 +662,7 @@
private synchronized boolean dispatchEvent(String eventStr) {
String iface;
+ // IFNAME=wlan0 ANQP-QUERY-DONE addr=18:cf:5e:26:a4:88 result=SUCCESS
if (eventStr.startsWith("IFNAME=")) {
int space = eventStr.indexOf(' ');
if (space != -1) {
@@ -705,6 +735,7 @@
private static class MonitorThread extends Thread {
private final WifiNative mWifiNative;
private final WifiMonitorSingleton mWifiMonitorSingleton;
+ private final LocalLog mLocalLog = WifiNative.getLocalLog();
public MonitorThread(WifiNative wifiNative, WifiMonitorSingleton wifiMonitorSingleton) {
super("WifiMonitor");
@@ -713,13 +744,23 @@
}
public void run() {
+ if (DBG) {
+ Log.d(TAG, "MonitorThread start with mConnected=" +
+ mWifiMonitorSingleton.mConnected);
+ }
//noinspection InfiniteLoopStatement
for (;;) {
+ if (!mWifiMonitorSingleton.mConnected) {
+ if (DBG) Log.d(TAG, "MonitorThread exit because mConnected is false");
+ break;
+ }
String eventStr = mWifiNative.waitForEvent();
- // Skip logging the common but mostly uninteresting scan-results event
- if (DBG && eventStr.indexOf(SCAN_RESULTS_STR) == -1) {
- Log.d(TAG, "Event [" + eventStr + "]");
+ // Skip logging the common but mostly uninteresting events
+ if (eventStr.indexOf(BSS_ADDED_STR) == -1
+ && eventStr.indexOf(BSS_REMOVED_STR) == -1) {
+ if (DBG) Log.d(TAG, "Event [" + eventStr + "]");
+ mLocalLog.log("Event [" + eventStr + "]");
}
if (mWifiMonitorSingleton.dispatchEvent(eventStr)) {
@@ -764,13 +805,20 @@
handleP2pEvents(eventStr);
} else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) {
handleHostApEvents(eventStr);
- } else if (eventStr.startsWith(GAS_QUERY_PREFIX_STR)) {
+ } else if (eventStr.startsWith(ANQP_DONE_STR)) {
+ try {
+ handleAnqpResult(eventStr);
+ }
+ catch (IllegalArgumentException iae) {
+ Log.e(TAG, "Bad ANQP event string: '" + eventStr + "': " + iae);
+ }
+ } else if (eventStr.startsWith(GAS_QUERY_PREFIX_STR)) { // !!! clean >>End
handleGasQueryEvents(eventStr);
} else if (eventStr.startsWith(RX_HS20_ANQP_ICON_STR)) {
if (mStateMachine2 != null)
mStateMachine2.sendMessage(RX_HS20_ANQP_ICON_EVENT,
eventStr.substring(RX_HS20_ANQP_ICON_STR_LEN + 1));
- } else if (eventStr.startsWith(HS20_PREFIX_STR)) {
+ } else if (eventStr.startsWith(HS20_PREFIX_STR)) { // !!! <<End
handleHs20Events(eventStr);
} else if (eventStr.startsWith(REQUEST_PREFIX_STR)) {
handleRequests(eventStr);
@@ -778,6 +826,9 @@
handleTargetBSSIDEvent(eventStr);
} else if (eventStr.startsWith(ASSOCIATED_WITH_STR)) {
handleAssociatedBSSIDEvent(eventStr);
+ } else if (eventStr.startsWith(AUTH_EVENT_PREFIX_STR) &&
+ eventStr.endsWith(AUTH_TIMEOUT_STR)) {
+ mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
} else {
if (DBG) Log.w(TAG, "couldn't identify event type - " + eventStr);
}
@@ -806,6 +857,8 @@
event = STATE_CHANGE;
else if (eventName.equals(SCAN_RESULTS_STR))
event = SCAN_RESULTS;
+ else if (eventName.equals(SCAN_FAILED_STR))
+ event = SCAN_FAILED;
else if (eventName.equals(LINK_SPEED_STR))
event = LINK_SPEED;
else if (eventName.equals(TERMINATING_STR))
@@ -824,8 +877,7 @@
event = BSS_ADDED;
} else if (eventName.equals(BSS_REMOVED_STR)) {
event = BSS_REMOVED;
- }
- else
+ } else
event = UNKNOWN;
String eventData = eventStr;
@@ -958,6 +1010,10 @@
mStateMachine.sendMessage(SCAN_RESULTS_EVENT);
break;
+ case SCAN_FAILED:
+ mStateMachine.sendMessage(SCAN_FAILED_EVENT);
+ break;
+
case UNKNOWN:
if (DBG) {
logDbg("handleEvent unknown: " + Integer.toString(event) + " " + remainder);
@@ -1053,14 +1109,34 @@
return err;
}
+ WifiP2pDevice getWifiP2pDevice(String dataString) {
+ try {
+ WifiP2pDevice device = new WifiP2pDevice(dataString);
+ return device;
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ }
+
+ WifiP2pGroup getWifiP2pGroup(String dataString) {
+ try {
+ WifiP2pGroup group = new WifiP2pGroup(dataString);
+ return group;
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ }
+
/**
* Handle p2p events
*/
private void handleP2pEvents(String dataString) {
if (dataString.startsWith(P2P_DEVICE_FOUND_STR)) {
- mStateMachine.sendMessage(P2P_DEVICE_FOUND_EVENT, new WifiP2pDevice(dataString));
+ WifiP2pDevice device = getWifiP2pDevice(dataString);
+ if (device != null) mStateMachine.sendMessage(P2P_DEVICE_FOUND_EVENT, device);
} else if (dataString.startsWith(P2P_DEVICE_LOST_STR)) {
- mStateMachine.sendMessage(P2P_DEVICE_LOST_EVENT, new WifiP2pDevice(dataString));
+ WifiP2pDevice device = getWifiP2pDevice(dataString);
+ if (device != null) mStateMachine.sendMessage(P2P_DEVICE_LOST_EVENT, device);
} else if (dataString.startsWith(P2P_FIND_STOPPED_STR)) {
mStateMachine.sendMessage(P2P_FIND_STOPPED_EVENT);
} else if (dataString.startsWith(P2P_GO_NEG_REQUEST_STR)) {
@@ -1075,9 +1151,11 @@
} else if (dataString.startsWith(P2P_GROUP_FORMATION_FAILURE_STR)) {
mStateMachine.sendMessage(P2P_GROUP_FORMATION_FAILURE_EVENT, p2pError(dataString));
} else if (dataString.startsWith(P2P_GROUP_STARTED_STR)) {
- mStateMachine.sendMessage(P2P_GROUP_STARTED_EVENT, new WifiP2pGroup(dataString));
+ WifiP2pGroup group = getWifiP2pGroup(dataString);
+ if (group != null) mStateMachine.sendMessage(P2P_GROUP_STARTED_EVENT, group);
} else if (dataString.startsWith(P2P_GROUP_REMOVED_STR)) {
- mStateMachine.sendMessage(P2P_GROUP_REMOVED_EVENT, new WifiP2pGroup(dataString));
+ WifiP2pGroup group = getWifiP2pGroup(dataString);
+ if (group != null) mStateMachine.sendMessage(P2P_GROUP_REMOVED_EVENT, group);
} else if (dataString.startsWith(P2P_INVITATION_RECEIVED_STR)) {
mStateMachine.sendMessage(P2P_INVITATION_RECEIVED_EVENT,
new WifiP2pGroup(dataString));
@@ -1121,6 +1199,38 @@
}
}
+ private static final String ADDR_STRING = "addr=";
+ private static final String RESULT_STRING = "result=";
+
+ // ANQP-QUERY-DONE addr=18:cf:5e:26:a4:88 result=SUCCESS
+
+ private void handleAnqpResult(String eventStr) {
+ int addrPos = eventStr.indexOf(ADDR_STRING);
+ int resPos = eventStr.indexOf(RESULT_STRING);
+ if (addrPos < 0 || resPos < 0) {
+ throw new IllegalArgumentException("Unexpected ANQP result notification");
+ }
+ int eoaddr = eventStr.indexOf(' ', addrPos + ADDR_STRING.length());
+ if (eoaddr < 0) {
+ eoaddr = eventStr.length();
+ }
+ int eoresult = eventStr.indexOf(' ', resPos + RESULT_STRING.length());
+ if (eoresult < 0) {
+ eoresult = eventStr.length();
+ }
+
+ try {
+ long bssid = Utils.parseMac(eventStr.substring(addrPos + ADDR_STRING.length(), eoaddr));
+ int result = eventStr.substring(
+ resPos + RESULT_STRING.length(), eoresult).equalsIgnoreCase("success") ? 1 : 0;
+
+ mStateMachine.sendMessage(ANQP_DONE_EVENT, result, 0, bssid);
+ }
+ catch (IllegalArgumentException iae) {
+ Log.e(TAG, "Bad MAC address in ANQP response: " + iae.getMessage());
+ }
+ }
+
/**
* Handle ANQP events
*/
@@ -1209,14 +1319,23 @@
}
mStateMachine.sendMessage(SUP_REQUEST_IDENTITY, eventLogCounter, reason, SSID);
} else if (requestName.startsWith(SIM_STR)) {
- Matcher match = mRequestGsmAuthPattern.matcher(requestName);
- if (match.find()) {
- WifiStateMachine.SimAuthRequestData data =
- new WifiStateMachine.SimAuthRequestData();
- data.networkId = Integer.parseInt(match.group(1));
+ Matcher matchGsm = mRequestGsmAuthPattern.matcher(requestName);
+ Matcher matchUmts = mRequestUmtsAuthPattern.matcher(requestName);
+ WifiStateMachine.SimAuthRequestData data =
+ new WifiStateMachine.SimAuthRequestData();
+ if (matchGsm.find()) {
+ data.networkId = Integer.parseInt(matchGsm.group(1));
data.protocol = WifiEnterpriseConfig.Eap.SIM;
- data.ssid = match.group(4);
- data.challenges = match.group(2).split(":");
+ data.ssid = matchGsm.group(4);
+ data.data = matchGsm.group(2).split(":");
+ mStateMachine.sendMessage(SUP_REQUEST_SIM_AUTH, data);
+ } else if (matchUmts.find()) {
+ data.networkId = Integer.parseInt(matchUmts.group(1));
+ data.protocol = WifiEnterpriseConfig.Eap.AKA;
+ data.ssid = matchUmts.group(4);
+ data.data = new String[2];
+ data.data[0] = matchUmts.group(2);
+ data.data[1] = matchUmts.group(3);
mStateMachine.sendMessage(SUP_REQUEST_SIM_AUTH, data);
} else {
Log.e(TAG, "couldn't parse SIM auth request - " + requestName);
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index e8c501c..899529d 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -19,21 +19,35 @@
import android.net.wifi.BatchedScanSettings;
import android.net.wifi.RttManager;
import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiLinkLayerStats;
+import android.net.wifi.WifiManager;
import android.net.wifi.WifiScanner;
+import android.net.wifi.RttManager;
+import android.net.wifi.WifiSsid;
import android.net.wifi.WpsInfo;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pGroup;
+import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
+import android.net.wifi.WifiEnterpriseConfig;
import android.os.SystemClock;
import android.text.TextUtils;
-import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
+import android.util.Base64;
import android.util.LocalLog;
import android.util.Log;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
-
+import java.util.zip.Deflater;
+import libcore.util.HexEncoding;
/**
* Native calls for bring up/shut down of the supplicant daemon and for
* sending requests to the supplicant daemon
@@ -65,6 +79,10 @@
private boolean mSuspendOptEnabled = false;
+ private static final int EID_HT_OPERATION = 61;
+ private static final int EID_VHT_OPERATION = 192;
+ private static final int EID_EXTENDED_CAPS = 127;
+ private static final int RTT_RESP_ENABLE_BIT = 70;
/* Register native functions */
static {
@@ -122,12 +140,12 @@
}
}
- private static final LocalLog mLocalLog = new LocalLog(1024);
+ private static final LocalLog mLocalLog = new LocalLog(16384);
// hold mLock before accessing mCmdIdLock
private static int sCmdId;
- public LocalLog getLocalLog() {
+ public static LocalLog getLocalLog() {
return mLocalLog;
}
@@ -171,6 +189,16 @@
}
}
+ private boolean doBooleanCommandWithoutLogging(String command) {
+ if (DBG) Log.d(mTAG, "doBooleanCommandWithoutLogging: " + command);
+ synchronized (mLock) {
+ int cmdId = getNewCmdIdLocked();
+ boolean result = doBooleanCommandNative(mInterfacePrefix + command);
+ if (DBG) Log.d(mTAG, command + ": returned " + result);
+ return result;
+ }
+ }
+
private int doIntCommand(String command) {
if (DBG) Log.d(mTAG, "doInt: " + command);
synchronized (mLock) {
@@ -267,7 +295,12 @@
public boolean setNetworkVariable(int netId, String name, String value) {
if (TextUtils.isEmpty(name) || TextUtils.isEmpty(value)) return false;
- return doBooleanCommand("SET_NETWORK " + netId + " " + name + " " + value);
+ if (name.equals(WifiConfiguration.pskVarName)
+ || name.equals(WifiEnterpriseConfig.PASSWORD_KEY)) {
+ return doBooleanCommandWithoutLogging("SET_NETWORK " + netId + " " + name + " " + value);
+ } else {
+ return doBooleanCommand("SET_NETWORK " + netId + " " + name + " " + value);
+ }
}
public String getNetworkVariable(int netId, String name) {
@@ -308,6 +341,11 @@
return doBooleanCommand("DISABLE_NETWORK " + netId);
}
+ public boolean selectNetwork(int netId) {
+ if (DBG) logDbg("selectNetwork nid=" + Integer.toString(netId));
+ return doBooleanCommand("SELECT_NETWORK " + netId);
+ }
+
public boolean reconnect() {
if (DBG) logDbg("RECONNECT ");
return doBooleanCommand("RECONNECT");
@@ -345,6 +383,8 @@
return null;
}
+
+
/**
* Format of results:
* =================
@@ -361,9 +401,29 @@
* RANGE=ALL gets all scan results
* RANGE=ID- gets results from ID
* MASK=<N> see wpa_supplicant/src/common/wpa_ctrl.h for details
+ * 0 0 1 0 2
+ * WPA_BSS_MASK_MESH_SCAN | WPA_BSS_MASK_DELIM | WPA_BSS_MASK_WIFI_DISPLAY
+ * 0 0 0 1 1 -> 9
+ * WPA_BSS_MASK_INTERNETW | WPA_BSS_MASK_P2P_SCAN | WPA_BSS_MASK_WPS_SCAN | WPA_BSS_MASK_SSID
+ * 1 0 0 1 9 -> d
+ * WPA_BSS_MASK_FLAGS | WPA_BSS_MASK_IE | WPA_BSS_MASK_AGE | WPA_BSS_MASK_TSF
+ * 1 0 0 0 8
+ * WPA_BSS_MASK_LEVEL | WPA_BSS_MASK_NOISE | WPA_BSS_MASK_QUAL | WPA_BSS_MASK_CAPABILITIES
+ * 0 1 1 1 7
+ * WPA_BSS_MASK_BEACON_INT | WPA_BSS_MASK_FREQ | WPA_BSS_MASK_BSSID | WPA_BSS_MASK_ID
+ *
+ * WPA_BSS_MASK_INTERNETW adds ANQP info (ctrl_iface:4151-4176)
+ *
+ * ctrl_iface.c:wpa_supplicant_ctrl_iface_process:7884
+ * wpa_supplicant_ctrl_iface_bss:4315
+ * print_bss_info
*/
public String scanResults(int sid) {
- return doStringCommandWithoutLogging("BSS RANGE=" + sid + "- MASK=0x21987");
+ return doStringCommandWithoutLogging("BSS RANGE=" + sid + "- MASK=0x29d87");
+ }
+
+ public String doCustomCommand(String command) {
+ return doStringCommand(command);
}
/**
@@ -510,22 +570,24 @@
&& doBooleanCommand("DRIVER RXFILTER-START");
}
- public int getBand() {
- String ret = doStringCommand("DRIVER GETBAND");
- if (!TextUtils.isEmpty(ret)) {
- //reply is "BAND X" where X is the band
- String[] tokens = ret.split(" ");
- try {
- if (tokens.length == 2) return Integer.parseInt(tokens[1]);
- } catch (NumberFormatException e) {
- return -1;
- }
- }
- return -1;
- }
-
+ /**
+ * Set the operational frequency band
+ * @param band One of
+ * {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
+ * {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ},
+ * {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ},
+ * @return {@code true} if the operation succeeded, {@code false} otherwise
+ */
public boolean setBand(int band) {
- return doBooleanCommand("DRIVER SETBAND " + band);
+ String bandstr;
+
+ if (band == WifiManager.WIFI_FREQUENCY_BAND_5GHZ)
+ bandstr = "5G";
+ else if (band == WifiManager.WIFI_FREQUENCY_BAND_2GHZ)
+ bandstr = "2G";
+ else
+ bandstr = "AUTO";
+ return doBooleanCommand("SET SETBAND " + bandstr);
}
/**
@@ -586,15 +648,20 @@
}
public boolean setCountryCode(String countryCode) {
- return doBooleanCommand("DRIVER COUNTRY " + countryCode.toUpperCase(Locale.ROOT));
+ if (countryCode != null)
+ return doBooleanCommand("DRIVER COUNTRY " + countryCode.toUpperCase(Locale.ROOT));
+ else
+ return doBooleanCommand("DRIVER COUNTRY");
}
- public void enableBackgroundScan(boolean enable) {
+ public boolean enableBackgroundScan(boolean enable) {
+ boolean ret;
if (enable) {
- doBooleanCommand("SET pno 1");
+ ret = doBooleanCommand("SET pno 1");
} else {
- doBooleanCommand("SET pno 0");
+ ret = doBooleanCommand("SET pno 0");
}
+ return ret;
}
public void enableAutoConnect(boolean enable) {
@@ -697,9 +764,10 @@
}
}
- public boolean simAuthResponse(int id, String response) {
+ public boolean simAuthResponse(int id, String type, String response) {
+ // with type = GSM-AUTH, UMTS-AUTH or UMTS-AUTS
synchronized (mLock) {
- return doBooleanCommand("CTRL-RSP-SIM-" + id + ":GSM-AUTH" + response);
+ return doBooleanCommand("CTRL-RSP-SIM-" + id + ":" + type + response);
}
}
@@ -1138,379 +1206,6 @@
return doBooleanCommand("ANQP_GET " + bssid + " " + subtypes);
}
- /* WIFI HAL support */
-
- private static final String TAG = "WifiNative-HAL";
- private static long sWifiHalHandle = 0; /* used by JNI to save wifi_handle */
- private static long[] sWifiIfaceHandles = null; /* used by JNI to save interface handles */
- private static int sWlan0Index = -1;
- private static int sP2p0Index = -1;
-
- private static boolean sHalIsStarted = false;
- private static boolean sHalFailed = false;
-
- private static native boolean startHalNative();
- private static native void stopHalNative();
- private static native void waitForHalEventNative();
-
- private static class MonitorThread extends Thread {
- public void run() {
- Log.i(TAG, "Waiting for HAL events mWifiHalHandle=" + Long.toString(sWifiHalHandle));
- waitForHalEventNative();
- }
- }
-
- synchronized public static boolean startHal() {
- Log.i(TAG, "startHal");
- synchronized (mLock) {
- if (sHalIsStarted)
- return true;
- if (sHalFailed)
- return false;
- if (startHalNative() && (getInterfaces() != 0) && (sWlan0Index != -1)) {
- new MonitorThread().start();
- sHalIsStarted = true;
- return true;
- } else {
- Log.i(TAG, "Could not start hal");
- sHalIsStarted = false;
- sHalFailed = true;
- return false;
- }
- }
- }
-
- synchronized public static void stopHal() {
- stopHalNative();
- }
-
- private static native int getInterfacesNative();
-
- synchronized public static int getInterfaces() {
- synchronized (mLock) {
- if (sWifiIfaceHandles == null) {
- int num = getInterfacesNative();
- int wifi_num = 0;
- for (int i = 0; i < num; i++) {
- String name = getInterfaceNameNative(i);
- Log.i(TAG, "interface[" + i + "] = " + name);
- if (name.equals("wlan0")) {
- sWlan0Index = i;
- wifi_num++;
- } else if (name.equals("p2p0")) {
- sP2p0Index = i;
- wifi_num++;
- }
- }
- return wifi_num;
- } else {
- return sWifiIfaceHandles.length;
- }
- }
- }
-
- private static native String getInterfaceNameNative(int index);
- synchronized public static String getInterfaceName(int index) {
- return getInterfaceNameNative(index);
- }
-
- public static class ScanCapabilities {
- public int max_scan_cache_size; // in number of scan results??
- public int max_scan_buckets;
- public int max_ap_cache_per_scan;
- public int max_rssi_sample_size;
- public int max_scan_reporting_threshold; // in number of scan results??
- public int max_hotlist_aps;
- public int max_significant_wifi_change_aps;
- }
-
- public static boolean getScanCapabilities(ScanCapabilities capabilities) {
- return getScanCapabilitiesNative(sWlan0Index, capabilities);
- }
-
- private static native boolean getScanCapabilitiesNative(
- int iface, ScanCapabilities capabilities);
-
- private static native boolean startScanNative(int iface, int id, ScanSettings settings);
- private static native boolean stopScanNative(int iface, int id);
- private static native ScanResult[] getScanResultsNative(int iface, boolean flush);
- private static native WifiLinkLayerStats getWifiLinkLayerStatsNative(int iface);
-
- public static class ChannelSettings {
- int frequency;
- int dwell_time_ms;
- boolean passive;
- }
-
- public static class BucketSettings {
- int bucket;
- int band;
- int period_ms;
- int report_events;
- int num_channels;
- ChannelSettings channels[];
- }
-
- public static class ScanSettings {
- int base_period_ms;
- int max_ap_per_scan;
- int report_threshold;
- int num_buckets;
- BucketSettings buckets[];
- }
-
- public static interface ScanEventHandler {
- void onScanResultsAvailable();
- void onFullScanResult(ScanResult fullScanResult);
- void onSingleScanComplete();
- void onScanPaused();
- void onScanRestarted();
- }
-
- synchronized static void onScanResultsAvailable(int id) {
- if (sScanEventHandler != null) {
- sScanEventHandler.onScanResultsAvailable();
- }
- }
-
- /* scan status, keep these values in sync with gscan.h */
- private static int WIFI_SCAN_BUFFER_FULL = 0;
- private static int WIFI_SCAN_COMPLETE = 1;
-
- synchronized static void onScanStatus(int status) {
- Log.i(TAG, "Got a scan status changed event, status = " + status);
-
- if (status == WIFI_SCAN_BUFFER_FULL) {
- /* we have a separate event to take care of this */
- } else if (status == WIFI_SCAN_COMPLETE) {
- if (sScanEventHandler != null) {
- sScanEventHandler.onSingleScanComplete();
- }
- }
- }
-
- synchronized static void onFullScanResult(int id, ScanResult result, byte bytes[]) {
- if (DBG) Log.i(TAG, "Got a full scan results event, ssid = " + result.SSID + ", " +
- "num = " + bytes.length);
-
- if (sScanEventHandler == null) {
- return;
- }
-
- int num = 0;
- for (int i = 0; i < bytes.length; ) {
- int type = bytes[i] & 0xFF;
- int len = bytes[i + 1] & 0xFF;
-
- if (i + len + 2 > bytes.length) {
- Log.w(TAG, "bad length " + len + " of IE " + type + " from " + result.BSSID);
- Log.w(TAG, "ignoring the rest of the IEs");
- break;
- }
- num++;
- i += len + 2;
- if (DBG) Log.i(TAG, "bytes[" + i + "] = [" + type + ", " + len + "]" + ", " +
- "next = " + i);
- }
-
- ScanResult.InformationElement elements[] = new ScanResult.InformationElement[num];
- for (int i = 0, index = 0; i < num; i++) {
- int type = bytes[index] & 0xFF;
- int len = bytes[index + 1] & 0xFF;
- if (DBG) Log.i(TAG, "index = " + index + ", type = " + type + ", len = " + len);
- ScanResult.InformationElement elem = new ScanResult.InformationElement();
- elem.id = type;
- elem.bytes = new byte[len];
- for (int j = 0; j < len; j++) {
- elem.bytes[j] = bytes[index + j + 2];
- }
- elements[i] = elem;
- index += (len + 2);
- }
-
- result.informationElements = elements;
- sScanEventHandler.onFullScanResult(result);
- }
-
- private static int sScanCmdId = 0;
- private static ScanEventHandler sScanEventHandler;
- private static ScanSettings sScanSettings;
-
- synchronized public static boolean startScan(
- ScanSettings settings, ScanEventHandler eventHandler) {
- synchronized (mLock) {
-
- if (sScanCmdId != 0) {
- stopScan();
- } else if (sScanSettings != null || sScanEventHandler != null) {
- /* current scan is paused; no need to stop it */
- }
-
- sScanCmdId = getNewCmdIdLocked();
-
- sScanSettings = settings;
- sScanEventHandler = eventHandler;
-
- if (startScanNative(sWlan0Index, sScanCmdId, settings) == false) {
- sScanEventHandler = null;
- sScanSettings = null;
- return false;
- }
-
- return true;
- }
- }
-
- synchronized public static void stopScan() {
- synchronized (mLock) {
- stopScanNative(sWlan0Index, sScanCmdId);
- sScanSettings = null;
- sScanEventHandler = null;
- sScanCmdId = 0;
- }
- }
-
- synchronized public static void pauseScan() {
- synchronized (mLock) {
- if (sScanCmdId != 0 && sScanSettings != null && sScanEventHandler != null) {
- Log.d(TAG, "Pausing scan");
- stopScanNative(sWlan0Index, sScanCmdId);
- sScanCmdId = 0;
- sScanEventHandler.onScanPaused();
- }
- }
- }
-
- synchronized public static void restartScan() {
- synchronized (mLock) {
- if (sScanCmdId == 0 && sScanSettings != null && sScanEventHandler != null) {
- Log.d(TAG, "Restarting scan");
- startScan(sScanSettings, sScanEventHandler);
- sScanEventHandler.onScanRestarted();
- }
- }
- }
-
- synchronized public static ScanResult[] getScanResults() {
- synchronized (mLock) {
- return getScanResultsNative(sWlan0Index, /* flush = */ false);
- }
- }
-
- public static interface HotlistEventHandler {
- void onHotlistApFound (ScanResult[]result);
- }
-
- private static int sHotlistCmdId = 0;
- private static HotlistEventHandler sHotlistEventHandler;
-
- private native static boolean setHotlistNative(int iface, int id,
- WifiScanner.HotlistSettings settings);
- private native static boolean resetHotlistNative(int iface, int id);
-
- synchronized public static boolean setHotlist(WifiScanner.HotlistSettings settings,
- HotlistEventHandler eventHandler) {
- synchronized (mLock) {
- if (sHotlistCmdId != 0) {
- return false;
- } else {
- sHotlistCmdId = getNewCmdIdLocked();
- }
-
- sHotlistEventHandler = eventHandler;
- if (setHotlistNative(sWlan0Index, sScanCmdId, settings) == false) {
- sHotlistEventHandler = null;
- return false;
- }
-
- return true;
- }
- }
-
- synchronized public static void resetHotlist() {
- synchronized (mLock) {
- if (sHotlistCmdId != 0) {
- resetHotlistNative(sWlan0Index, sHotlistCmdId);
- sHotlistCmdId = 0;
- sHotlistEventHandler = null;
- }
- }
- }
-
- synchronized public static void onHotlistApFound(int id, ScanResult[] results) {
- synchronized (mLock) {
- if (sHotlistCmdId != 0) {
- sHotlistEventHandler.onHotlistApFound(results);
- } else {
- /* this can happen because of race conditions */
- Log.d(TAG, "Ignoring hotlist AP found change");
- }
- }
- }
-
- public static interface SignificantWifiChangeEventHandler {
- void onChangesFound(ScanResult[] result);
- }
-
- private static SignificantWifiChangeEventHandler sSignificantWifiChangeHandler;
- private static int sSignificantWifiChangeCmdId;
-
- private static native boolean trackSignificantWifiChangeNative(
- int iface, int id, WifiScanner.WifiChangeSettings settings);
- private static native boolean untrackSignificantWifiChangeNative(int iface, int id);
-
- synchronized public static boolean trackSignificantWifiChange(
- WifiScanner.WifiChangeSettings settings, SignificantWifiChangeEventHandler handler) {
- synchronized (mLock) {
- if (sSignificantWifiChangeCmdId != 0) {
- return false;
- } else {
- sSignificantWifiChangeCmdId = getNewCmdIdLocked();
- }
-
- sSignificantWifiChangeHandler = handler;
- if (trackSignificantWifiChangeNative(sWlan0Index, sScanCmdId, settings) == false) {
- sSignificantWifiChangeHandler = null;
- return false;
- }
-
- return true;
- }
- }
-
- synchronized static void untrackSignificantWifiChange() {
- synchronized (mLock) {
- if (sSignificantWifiChangeCmdId != 0) {
- untrackSignificantWifiChangeNative(sWlan0Index, sSignificantWifiChangeCmdId);
- sSignificantWifiChangeCmdId = 0;
- sSignificantWifiChangeHandler = null;
- }
- }
- }
-
- synchronized static void onSignificantWifiChange(int id, ScanResult[] results) {
- synchronized (mLock) {
- if (sSignificantWifiChangeCmdId != 0) {
- sSignificantWifiChangeHandler.onChangesFound(results);
- } else {
- /* this can happen because of race conditions */
- Log.d(TAG, "Ignoring significant wifi change");
- }
- }
- }
-
- synchronized public static WifiLinkLayerStats getWifiLinkLayerStats(String iface) {
- // TODO: use correct iface name to Index translation
- if (iface == null) return null;
- synchronized (mLock) {
- if (!sHalIsStarted)
- startHal();
- if (sHalIsStarted)
- return getWifiLinkLayerStatsNative(sWlan0Index);
- }
- return null;
- }
-
/*
* NFC-related calls
*/
@@ -1534,9 +1229,594 @@
return doBooleanCommand("NFC_REPORT_HANDOVER RESP P2P " + requestMessage + " 00");
}
+ /* WIFI HAL support */
+
+ private static final String TAG = "WifiNative-HAL";
+ private static long sWifiHalHandle = 0; /* used by JNI to save wifi_handle */
+ private static long[] sWifiIfaceHandles = null; /* used by JNI to save interface handles */
+ private static int sWlan0Index = -1;
+ private static int sP2p0Index = -1;
+ private static MonitorThread sThread;
+ private static final int STOP_HAL_TIMEOUT_MS = 1000;
+
+ private static native boolean startHalNative();
+ private static native void stopHalNative();
+ private static native void waitForHalEventNative();
+
+ private static class MonitorThread extends Thread {
+ public void run() {
+ Log.i(TAG, "Waiting for HAL events mWifiHalHandle=" + Long.toString(sWifiHalHandle));
+ waitForHalEventNative();
+ }
+ }
+
+ synchronized public static boolean startHal() {
+
+ String debugLog = "startHal stack: ";
+ java.lang.StackTraceElement[] elements = Thread.currentThread().getStackTrace();
+ for (int i = 2; i < elements.length && i <= 7; i++ ) {
+ debugLog = debugLog + " - " + elements[i].getMethodName();
+ }
+
+ mLocalLog.log(debugLog);
+
+ synchronized (mLock) {
+ if (startHalNative() && (getInterfaces() != 0) && (sWlan0Index != -1)) {
+ sThread = new MonitorThread();
+ sThread.start();
+ return true;
+ } else {
+ if (DBG) mLocalLog.log("Could not start hal");
+ Log.e(TAG, "Could not start hal");
+ return false;
+ }
+ }
+ }
+
+ synchronized public static void stopHal() {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ stopHalNative();
+ try {
+ sThread.join(STOP_HAL_TIMEOUT_MS);
+ Log.d(TAG, "HAL event thread stopped successfully");
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Could not stop HAL cleanly");
+ }
+ sThread = null;
+ sWifiHalHandle = 0;
+ sWifiIfaceHandles = null;
+ sWlan0Index = -1;
+ sP2p0Index = -1;
+ }
+ }
+ }
+
+ public static boolean isHalStarted() {
+ return (sWifiHalHandle != 0);
+ }
+ private static native int getInterfacesNative();
+
+ synchronized public static int getInterfaces() {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ if (sWifiIfaceHandles == null) {
+ int num = getInterfacesNative();
+ int wifi_num = 0;
+ for (int i = 0; i < num; i++) {
+ String name = getInterfaceNameNative(i);
+ Log.i(TAG, "interface[" + i + "] = " + name);
+ if (name.equals("wlan0")) {
+ sWlan0Index = i;
+ wifi_num++;
+ } else if (name.equals("p2p0")) {
+ sP2p0Index = i;
+ wifi_num++;
+ }
+ }
+ return wifi_num;
+ } else {
+ return sWifiIfaceHandles.length;
+ }
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ private static native String getInterfaceNameNative(int index);
+ synchronized public static String getInterfaceName(int index) {
+ return getInterfaceNameNative(index);
+ }
+
+ public static class ScanCapabilities {
+ public int max_scan_cache_size; // in number of scan results??
+ public int max_scan_buckets;
+ public int max_ap_cache_per_scan;
+ public int max_rssi_sample_size;
+ public int max_scan_reporting_threshold; // in number of scan results??
+ public int max_hotlist_bssids;
+ public int max_significant_wifi_change_aps;
+ }
+
+ synchronized public static boolean getScanCapabilities(ScanCapabilities capabilities) {
+ synchronized (mLock) {
+ return isHalStarted() && getScanCapabilitiesNative(sWlan0Index, capabilities);
+ }
+ }
+
+ private static native boolean getScanCapabilitiesNative(
+ int iface, ScanCapabilities capabilities);
+
+ private static native boolean startScanNative(int iface, int id, ScanSettings settings);
+ private static native boolean stopScanNative(int iface, int id);
+ private static native WifiScanner.ScanData[] getScanResultsNative(int iface, boolean flush);
+ private static native WifiLinkLayerStats getWifiLinkLayerStatsNative(int iface);
+ private static native void setWifiLinkLayerStatsNative(int iface, int enable);
+
+ public static class ChannelSettings {
+ int frequency;
+ int dwell_time_ms;
+ boolean passive;
+ }
+
+ public static class BucketSettings {
+ int bucket;
+ int band;
+ int period_ms;
+ int report_events;
+ int num_channels;
+ ChannelSettings channels[];
+ }
+
+ public static class ScanSettings {
+ int base_period_ms;
+ int max_ap_per_scan;
+ int report_threshold_percent;
+ int report_threshold_num_scans;
+ int num_buckets;
+ BucketSettings buckets[];
+ }
+
+ public static interface ScanEventHandler {
+ void onScanResultsAvailable();
+ void onFullScanResult(ScanResult fullScanResult);
+ void onScanStatus();
+ void onScanPaused(WifiScanner.ScanData[] data);
+ void onScanRestarted();
+ }
+
+ synchronized static void onScanResultsAvailable(int id) {
+ if (sScanEventHandler != null) {
+ sScanEventHandler.onScanResultsAvailable();
+ }
+ }
+
+ /* scan status, keep these values in sync with gscan.h */
+ private static int WIFI_SCAN_BUFFER_FULL = 0;
+ private static int WIFI_SCAN_COMPLETE = 1;
+
+ synchronized static void onScanStatus(int status) {
+ if (status == WIFI_SCAN_BUFFER_FULL) {
+ /* we have a separate event to take care of this */
+ } else if (status == WIFI_SCAN_COMPLETE) {
+ if (sScanEventHandler != null) {
+ sScanEventHandler.onScanStatus();
+ }
+ }
+ }
+
+ public static WifiSsid createWifiSsid (byte[] rawSsid) {
+ String ssidHexString = String.valueOf(HexEncoding.encode(rawSsid));
+
+ if (ssidHexString == null) {
+ return null;
+ }
+
+ WifiSsid wifiSsid = WifiSsid.createFromHex(ssidHexString);
+
+ return wifiSsid;
+ }
+
+ public static String ssidConvert(byte[] rawSsid) {
+ String ssid;
+
+ CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
+ try {
+ CharBuffer decoded = decoder.decode(ByteBuffer.wrap(rawSsid));
+ ssid = decoded.toString();
+ } catch (CharacterCodingException cce) {
+ ssid = null;
+ }
+
+ if (ssid == null) {
+ ssid = new String(rawSsid, StandardCharsets.ISO_8859_1);
+ }
+
+ return ssid;
+ }
+
+ public static boolean setSsid(byte[] rawSsid, ScanResult result) {
+ if (rawSsid == null || rawSsid.length == 0 || result == null) {
+ return false;
+ }
+
+ result.SSID = ssidConvert(rawSsid);
+ result.wifiSsid = createWifiSsid(rawSsid);
+ return true;
+ }
+
+ static void populateScanResult(ScanResult result, byte bytes[], String dbg) {
+ int num = 0;
+ if (bytes == null) return;
+ if (dbg == null) dbg = "";
+ for (int i = 0; i < bytes.length - 1; ) {
+ int type = bytes[i] & 0xFF;
+ int len = bytes[i + 1] & 0xFF;
+ if (i + len + 2 > bytes.length) {
+ Log.w(TAG, dbg + "bad length " + len + " of IE " + type + " from " + result.BSSID);
+ Log.w(TAG, dbg + "ignoring the rest of the IEs");
+ break;
+ }
+ num++;
+ if (DBG) Log.i(TAG, dbg + "bytes[" + i + "] = [" + type + ", " + len + "]" + ", " +
+ "next = " + (i + len + 2));
+ i += len + 2;
+ }
+
+ int secondChanelOffset = 0;
+ byte channelMode = 0;
+ byte centerFreqIndex1 = 0;
+ byte centerFreqIndex2 = 0;
+
+ boolean is80211McRTTResponder = false;
+
+ ScanResult.InformationElement elements[] = new ScanResult.InformationElement[num];
+ for (int i = 0, index = 0; i < num; i++) {
+ int type = bytes[index] & 0xFF;
+ int len = bytes[index + 1] & 0xFF;
+ if (DBG) Log.i(TAG, dbg + "index = " + index + ", type = " + type + ", len = " + len);
+ ScanResult.InformationElement elem = new ScanResult.InformationElement();
+ elem.id = type;
+ elem.bytes = new byte[len];
+ for (int j = 0; j < len; j++) {
+ elem.bytes[j] = bytes[index + j + 2];
+ }
+ elements[i] = elem;
+ int inforStart = index + 2;
+ index += (len + 2);
+
+ if(type == EID_HT_OPERATION) {
+ secondChanelOffset = bytes[inforStart + 1] & 0x3;
+ } else if(type == EID_VHT_OPERATION) {
+ channelMode = bytes[inforStart];
+ centerFreqIndex1 = bytes[inforStart + 1];
+ centerFreqIndex2 = bytes[inforStart + 2];
+ } else if (type == EID_EXTENDED_CAPS) {
+ int tempIndex = RTT_RESP_ENABLE_BIT / 8;
+ byte offset = RTT_RESP_ENABLE_BIT % 8;
+
+ if(len < tempIndex + 1) {
+ is80211McRTTResponder = false;
+ } else {
+ if ((bytes[inforStart + tempIndex] & ((byte)0x1 << offset)) != 0) {
+ is80211McRTTResponder = true;
+ } else {
+ is80211McRTTResponder = false;
+ }
+ }
+ }
+ }
+
+ if (is80211McRTTResponder) {
+ result.setFlag(ScanResult.FLAG_80211mc_RESPONDER);
+ } else {
+ result.clearFlag(ScanResult.FLAG_80211mc_RESPONDER);
+ }
+
+ //handle RTT related information
+ if (channelMode != 0) {
+ // 80 or 160 MHz
+ result.channelWidth = channelMode + 1;
+
+ //convert channel index to frequency in MHz, channel 36 is 5180MHz
+ result.centerFreq0 = (centerFreqIndex1 - 36) * 5 + 5180;
+
+ if(channelMode > 1) { //160MHz
+ result.centerFreq1 = (centerFreqIndex2 - 36) * 5 + 5180;
+ } else {
+ result.centerFreq1 = 0;
+ }
+ } else {
+ //20 or 40 MHz
+ if (secondChanelOffset != 0) {//40MHz
+ result.channelWidth = 1;
+ if (secondChanelOffset == 1) {
+ result.centerFreq0 = result.frequency + 20;
+ } else if (secondChanelOffset == 3) {
+ result.centerFreq0 = result.frequency - 20;
+ } else {
+ result.centerFreq0 = 0;
+ Log.e(TAG, dbg + ": Error on secondChanelOffset");
+ }
+ } else {
+ result.centerFreq0 = 0;
+ result.centerFreq1 = 0;
+ }
+ result.centerFreq1 = 0;
+ }
+ if(DBG) {
+ Log.d(TAG, dbg + "SSID: " + result.SSID + " ChannelWidth is: " + result.channelWidth +
+ " PrimaryFreq: " + result.frequency +" mCenterfreq0: " + result.centerFreq0 +
+ " mCenterfreq1: " + result.centerFreq1 + (is80211McRTTResponder ?
+ "Support RTT reponder: " : "Do not support RTT responder"));
+ }
+
+ result.informationElements = elements;
+ }
+
+ synchronized static void onFullScanResult(int id, ScanResult result, byte bytes[]) {
+ if (DBG) Log.i(TAG, "Got a full scan results event, ssid = " + result.SSID + ", " +
+ "num = " + bytes.length);
+
+ if (sScanEventHandler == null) {
+ return;
+ }
+ populateScanResult(result, bytes, " onFullScanResult ");
+
+ sScanEventHandler.onFullScanResult(result);
+ }
+
+ private static int sScanCmdId = 0;
+ private static ScanEventHandler sScanEventHandler;
+ private static ScanSettings sScanSettings;
+
+ synchronized public static boolean startScan(
+ ScanSettings settings, ScanEventHandler eventHandler) {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+
+ if (sScanCmdId != 0) {
+ stopScan();
+ } else if (sScanSettings != null || sScanEventHandler != null) {
+ /* current scan is paused; no need to stop it */
+ }
+
+ sScanCmdId = getNewCmdIdLocked();
+
+ sScanSettings = settings;
+ sScanEventHandler = eventHandler;
+
+ if (startScanNative(sWlan0Index, sScanCmdId, settings) == false) {
+ sScanEventHandler = null;
+ sScanSettings = null;
+ sScanCmdId = 0;
+ return false;
+ }
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ synchronized public static void stopScan() {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ stopScanNative(sWlan0Index, sScanCmdId);
+ sScanSettings = null;
+ sScanEventHandler = null;
+ sScanCmdId = 0;
+ }
+ }
+ }
+
+ synchronized public static void pauseScan() {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ if (sScanCmdId != 0 && sScanSettings != null && sScanEventHandler != null) {
+ Log.d(TAG, "Pausing scan");
+ WifiScanner.ScanData scanData[] = getScanResultsNative(sWlan0Index, true);
+ stopScanNative(sWlan0Index, sScanCmdId);
+ sScanCmdId = 0;
+ sScanEventHandler.onScanPaused(scanData);
+ }
+ }
+ }
+ }
+
+ synchronized public static void restartScan() {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ if (sScanCmdId == 0 && sScanSettings != null && sScanEventHandler != null) {
+ Log.d(TAG, "Restarting scan");
+ ScanEventHandler handler = sScanEventHandler;
+ ScanSettings settings = sScanSettings;
+ if (startScan(sScanSettings, sScanEventHandler)) {
+ sScanEventHandler.onScanRestarted();
+ } else {
+ /* we are still paused; don't change state */
+ sScanEventHandler = handler;
+ sScanSettings = settings;
+ }
+ }
+ }
+ }
+ }
+
+ synchronized public static WifiScanner.ScanData[] getScanResults(boolean flush) {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ return getScanResultsNative(sWlan0Index, flush);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ public static interface HotlistEventHandler {
+ void onHotlistApFound (ScanResult[] result);
+ void onHotlistApLost (ScanResult[] result);
+ }
+
+ private static int sHotlistCmdId = 0;
+ private static HotlistEventHandler sHotlistEventHandler;
+
+ private native static boolean setHotlistNative(int iface, int id,
+ WifiScanner.HotlistSettings settings);
+ private native static boolean resetHotlistNative(int iface, int id);
+
+ synchronized public static boolean setHotlist(WifiScanner.HotlistSettings settings,
+ HotlistEventHandler eventHandler) {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ if (sHotlistCmdId != 0) {
+ return false;
+ } else {
+ sHotlistCmdId = getNewCmdIdLocked();
+ }
+
+ sHotlistEventHandler = eventHandler;
+ if (setHotlistNative(sWlan0Index, sHotlistCmdId, settings) == false) {
+ sHotlistEventHandler = null;
+ return false;
+ }
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ synchronized public static void resetHotlist() {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ if (sHotlistCmdId != 0) {
+ resetHotlistNative(sWlan0Index, sHotlistCmdId);
+ sHotlistCmdId = 0;
+ sHotlistEventHandler = null;
+ }
+ }
+ }
+ }
+
+ synchronized public static void onHotlistApFound(int id, ScanResult[] results) {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ if (sHotlistCmdId != 0) {
+ sHotlistEventHandler.onHotlistApFound(results);
+ } else {
+ /* this can happen because of race conditions */
+ Log.d(TAG, "Ignoring hotlist AP found event");
+ }
+ }
+ }
+ }
+
+ synchronized public static void onHotlistApLost(int id, ScanResult[] results) {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ if (sHotlistCmdId != 0) {
+ sHotlistEventHandler.onHotlistApLost(results);
+ } else {
+ /* this can happen because of race conditions */
+ Log.d(TAG, "Ignoring hotlist AP lost event");
+ }
+ }
+ }
+ }
+
+ public static interface SignificantWifiChangeEventHandler {
+ void onChangesFound(ScanResult[] result);
+ }
+
+ private static SignificantWifiChangeEventHandler sSignificantWifiChangeHandler;
+ private static int sSignificantWifiChangeCmdId;
+
+ private static native boolean trackSignificantWifiChangeNative(
+ int iface, int id, WifiScanner.WifiChangeSettings settings);
+ private static native boolean untrackSignificantWifiChangeNative(int iface, int id);
+
+ synchronized public static boolean trackSignificantWifiChange(
+ WifiScanner.WifiChangeSettings settings, SignificantWifiChangeEventHandler handler) {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ if (sSignificantWifiChangeCmdId != 0) {
+ return false;
+ } else {
+ sSignificantWifiChangeCmdId = getNewCmdIdLocked();
+ }
+
+ sSignificantWifiChangeHandler = handler;
+ if (trackSignificantWifiChangeNative(sWlan0Index, sScanCmdId, settings) == false) {
+ sSignificantWifiChangeHandler = null;
+ return false;
+ }
+
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+ }
+
+ synchronized static void untrackSignificantWifiChange() {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ if (sSignificantWifiChangeCmdId != 0) {
+ untrackSignificantWifiChangeNative(sWlan0Index, sSignificantWifiChangeCmdId);
+ sSignificantWifiChangeCmdId = 0;
+ sSignificantWifiChangeHandler = null;
+ }
+ }
+ }
+ }
+
+ synchronized static void onSignificantWifiChange(int id, ScanResult[] results) {
+ synchronized (mLock) {
+ if (sSignificantWifiChangeCmdId != 0) {
+ sSignificantWifiChangeHandler.onChangesFound(results);
+ } else {
+ /* this can happen because of race conditions */
+ Log.d(TAG, "Ignoring significant wifi change");
+ }
+ }
+ }
+
+ synchronized public static WifiLinkLayerStats getWifiLinkLayerStats(String iface) {
+ // TODO: use correct iface name to Index translation
+ if (iface == null) return null;
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ return getWifiLinkLayerStatsNative(sWlan0Index);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ synchronized public static void setWifiLinkLayerStats(String iface, int enable) {
+ if (iface == null) return;
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ setWifiLinkLayerStatsNative(sWlan0Index, enable);
+ }
+ }
+ }
+
public static native int getSupportedFeatureSetNative(int iface);
synchronized public static int getSupportedFeatureSet() {
- return getSupportedFeatureSetNative(sWlan0Index);
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ return getSupportedFeatureSetNative(sWlan0Index);
+ } else {
+ Log.d(TAG, "Failing getSupportedFeatureset because HAL isn't started");
+ return 0;
+ }
+ }
}
/* Rtt related commands/events */
@@ -1553,7 +1833,7 @@
sRttEventHandler.onRttResults(results);
sRttCmdId = 0;
} else {
- Log.d(TAG, "Received event for unknown cmd = " + id + ", current id = " + sRttCmdId);
+ Log.d(TAG, "RTT Received event for unknown cmd = " + id + ", current id = " + sRttCmdId);
}
}
@@ -1565,25 +1845,39 @@
synchronized public static boolean requestRtt(
RttManager.RttParams[] params, RttEventHandler handler) {
synchronized (mLock) {
- if (sRttCmdId != 0) {
- return false;
+ if (isHalStarted()) {
+ if (sRttCmdId != 0) {
+ Log.v("TAG", "Last one is still under measurement!");
+ return false;
+ } else {
+ sRttCmdId = getNewCmdIdLocked();
+ }
+ sRttEventHandler = handler;
+ Log.v(TAG, "native issue RTT request");
+ return requestRangeNative(sWlan0Index, sRttCmdId, params);
} else {
- sRttCmdId = getNewCmdIdLocked();
+ return false;
}
- sRttEventHandler = handler;
- return requestRangeNative(sWlan0Index, sRttCmdId, params);
}
}
synchronized public static boolean cancelRtt(RttManager.RttParams[] params) {
synchronized(mLock) {
- if (sRttCmdId == 0) {
- return false;
- }
+ if (isHalStarted()) {
+ if (sRttCmdId == 0) {
+ return false;
+ }
- if (cancelRangeRequestNative(sWlan0Index, sRttCmdId, params)) {
- sRttEventHandler = null;
- return true;
+ sRttCmdId = 0;
+
+ if (cancelRangeRequestNative(sWlan0Index, sRttCmdId, params)) {
+ sRttEventHandler = null;
+ Log.v(TAG, "RTT cancel Request Successfully");
+ return true;
+ } else {
+ Log.e(TAG, "RTT cancel Request failed");
+ return false;
+ }
} else {
return false;
}
@@ -1594,7 +1888,7 @@
synchronized public static boolean setScanningMacOui(byte[] oui) {
synchronized (mLock) {
- if (startHal()) {
+ if (isHalStarted()) {
return setScanningMacOuiNative(sWlan0Index, oui);
} else {
return false;
@@ -1607,11 +1901,494 @@
synchronized public static int [] getChannelsForBand(int band) {
synchronized (mLock) {
- if (startHal()) {
+ if (isHalStarted()) {
return getChannelsForBandNative(sWlan0Index, band);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ private static native boolean isGetChannelsForBandSupportedNative();
+ synchronized public static boolean isGetChannelsForBandSupported(){
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ return isGetChannelsForBandSupportedNative();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ private static native boolean setDfsFlagNative(int iface, boolean dfsOn);
+ synchronized public static boolean setDfsFlag(boolean dfsOn) {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ return setDfsFlagNative(sWlan0Index, dfsOn);
+ } else {
+ return false;
+ }
+ }
+ }
+
+ private static native boolean toggleInterfaceNative(int on);
+ synchronized public static boolean toggleInterface(int on) {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ return toggleInterfaceNative(0);
+ } else {
+ return false;
+ }
+ }
+ }
+
+ private static native RttManager.RttCapabilities getRttCapabilitiesNative(int iface);
+ synchronized public static RttManager.RttCapabilities getRttCapabilities() {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ return getRttCapabilitiesNative(sWlan0Index);
+ }else {
+ return null;
+ }
+ }
+ }
+
+ private static native boolean setCountryCodeHalNative(int iface, String CountryCode);
+ synchronized public static boolean setCountryCodeHal( String CountryCode) {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ return setCountryCodeHalNative(sWlan0Index, CountryCode);
+ } else {
+ return false;
+ }
+ }
+ }
+
+ /* Rtt related commands/events */
+ public abstract class TdlsEventHandler {
+ abstract public void onTdlsStatus(String macAddr, int status, int reason);
+ }
+
+ private static TdlsEventHandler sTdlsEventHandler;
+
+ private static native boolean enableDisableTdlsNative(int iface, boolean enable,
+ String macAddr);
+ synchronized public static boolean enableDisableTdls(boolean enable, String macAdd,
+ TdlsEventHandler tdlsCallBack) {
+ synchronized (mLock) {
+ sTdlsEventHandler = tdlsCallBack;
+ return enableDisableTdlsNative(sWlan0Index, enable, macAdd);
+ }
+ }
+
+ // Once TDLS per mac and event feature is implemented, this class definition should be
+ // moved to the right place, like WifiManager etc
+ public static class TdlsStatus {
+ int channel;
+ int global_operating_class;
+ int state;
+ int reason;
+ }
+ private static native TdlsStatus getTdlsStatusNative(int iface, String macAddr);
+ synchronized public static TdlsStatus getTdlsStatus (String macAdd) {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ return getTdlsStatusNative(sWlan0Index, macAdd);
} else {
return null;
}
}
}
+
+ //ToFix: Once TDLS per mac and event feature is implemented, this class definition should be
+ // moved to the right place, like WifiStateMachine etc
+ public static class TdlsCapabilities {
+ /* Maximum TDLS session number can be supported by the Firmware and hardware */
+ int maxConcurrentTdlsSessionNumber;
+ boolean isGlobalTdlsSupported;
+ boolean isPerMacTdlsSupported;
+ boolean isOffChannelTdlsSupported;
+ }
+
+
+
+ private static native TdlsCapabilities getTdlsCapabilitiesNative(int iface);
+ synchronized public static TdlsCapabilities getTdlsCapabilities () {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ return getTdlsCapabilitiesNative(sWlan0Index);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ synchronized private static boolean onTdlsStatus(String macAddr, int status, int reason) {
+ if (sTdlsEventHandler == null) {
+ return false;
+ } else {
+ sTdlsEventHandler.onTdlsStatus(macAddr, status, reason);
+ return true;
+ }
+ }
+
+ //---------------------------------------------------------------------------------
+
+ /* Wifi Logger commands/events */
+
+ public static native boolean startLogging(int iface);
+
+ public static interface WifiLoggerEventHandler {
+ void onRingBufferData(RingBufferStatus status, byte[] buffer);
+ void onWifiAlert(int errorCode, byte[] buffer);
+ }
+
+ private static WifiLoggerEventHandler sWifiLoggerEventHandler = null;
+
+ private static void onRingBufferData(RingBufferStatus status, byte[] buffer) {
+ if (sWifiLoggerEventHandler != null)
+ sWifiLoggerEventHandler.onRingBufferData(status, buffer);
+ }
+
+ private static void onWifiAlert(byte[] buffer, int errorCode) {
+ if (sWifiLoggerEventHandler != null)
+ sWifiLoggerEventHandler.onWifiAlert(errorCode, buffer);
+ }
+
+ private static int sLogCmdId = -1;
+ private static native boolean setLoggingEventHandlerNative(int iface, int id);
+ synchronized public static boolean setLoggingEventHandler(WifiLoggerEventHandler handler) {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ int oldId = sLogCmdId;
+ sLogCmdId = getNewCmdIdLocked();
+ if (!setLoggingEventHandlerNative(sWlan0Index, sLogCmdId)) {
+ sLogCmdId = oldId;
+ return false;
+ }
+ sWifiLoggerEventHandler = handler;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ private static native boolean startLoggingRingBufferNative(int iface, int verboseLevel,
+ int flags, int minIntervalSec ,int minDataSize, String ringName);
+ synchronized public static boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxInterval,
+ int minDataSize, String ringName){
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ return startLoggingRingBufferNative(sWlan0Index, verboseLevel, flags, maxInterval,
+ minDataSize, ringName);
+ } else {
+ return false;
+ }
+ }
+ }
+
+ private static native int getSupportedLoggerFeatureSetNative(int iface);
+ synchronized public static int getSupportedLoggerFeatureSet() {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ return getSupportedLoggerFeatureSetNative(sWlan0Index);
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ private static native boolean resetLogHandlerNative(int iface, int id);
+ synchronized public static boolean resetLogHandler() {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ if (sLogCmdId == -1) {
+ Log.e(TAG,"Can not reset handler Before set any handler");
+ return false;
+ }
+ sWifiLoggerEventHandler = null;
+ if (resetLogHandlerNative(sWlan0Index, sLogCmdId)) {
+ sLogCmdId = -1;
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ }
+
+ private static native String getDriverVersionNative(int iface);
+ synchronized public static String getDriverVersion() {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ return getDriverVersionNative(sWlan0Index);
+ } else {
+ return "";
+ }
+ }
+ }
+
+
+ private static native String getFirmwareVersionNative(int iface);
+ synchronized public static String getFirmwareVersion() {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ return getFirmwareVersionNative(sWlan0Index);
+ } else {
+ return "";
+ }
+ }
+ }
+
+ public static class RingBufferStatus{
+ String name;
+ int flag;
+ int ringBufferId;
+ int ringBufferByteSize;
+ int verboseLevel;
+ int writtenBytes;
+ int readBytes;
+ int writtenRecords;
+
+ @Override
+ public String toString() {
+ return "name: " + name + " flag: " + flag + " ringBufferId: " + ringBufferId +
+ " ringBufferByteSize: " +ringBufferByteSize + " verboseLevel: " +verboseLevel +
+ " writtenBytes: " + writtenBytes + " readBytes: " + readBytes +
+ " writtenRecords: " + writtenRecords;
+ }
+ }
+
+ private static native RingBufferStatus[] getRingBufferStatusNative(int iface);
+ synchronized public static RingBufferStatus[] getRingBufferStatus() {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ return getRingBufferStatusNative(sWlan0Index);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ private static native boolean getRingBufferDataNative(int iface, String ringName);
+ synchronized public static boolean getRingBufferData(String ringName) {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ return getRingBufferDataNative(sWlan0Index, ringName);
+ } else {
+ return false;
+ }
+ }
+ }
+
+ static private byte[] mFwMemoryDump;
+ private static void onWifiFwMemoryAvailable(byte[] buffer) {
+ mFwMemoryDump = buffer;
+ if (DBG) {
+ Log.d(TAG, "onWifiFwMemoryAvailable is called and buffer length is: " +
+ (buffer == null ? 0 : buffer.length));
+ }
+ }
+
+ private static native boolean getFwMemoryDumpNative(int iface);
+ synchronized public static byte[] getFwMemoryDump() {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ if(getFwMemoryDumpNative(sWlan0Index)) {
+ byte[] fwMemoryDump = mFwMemoryDump;
+ mFwMemoryDump = null;
+ return fwMemoryDump;
+ } else {
+ return null;
+ }
+ }
+
+ return null;
+ }
+ }
+
+ //---------------------------------------------------------------------------------
+ /* Configure ePNO */
+
+ public class WifiPnoNetwork {
+ String SSID;
+ int rssi_threshold;
+ int flags;
+ int auth;
+ String configKey; // kept for reference
+
+ WifiPnoNetwork(WifiConfiguration config, int threshold) {
+ if (config.SSID == null) {
+ this.SSID = "";
+ this.flags = 1;
+ } else {
+ this.SSID = config.SSID;
+ }
+ this.rssi_threshold = threshold;
+ if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)) {
+ auth |= 2;
+ } else if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP) ||
+ config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X)) {
+ auth |= 4;
+ } else if (config.wepKeys[0] != null) {
+ auth |= 1;
+ } else {
+ auth |= 1;
+ }
+// auth = 0;
+ flags |= 6; //A and G
+ configKey = config.configKey();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sbuf = new StringBuilder();
+ sbuf.append(this.SSID);
+ sbuf.append(" flags=").append(this.flags);
+ sbuf.append(" rssi=").append(this.rssi_threshold);
+ sbuf.append(" auth=").append(this.auth);
+ return sbuf.toString();
+ }
+ }
+
+ public static interface WifiPnoEventHandler {
+ void onPnoNetworkFound(ScanResult results[]);
+ }
+
+ private static WifiPnoEventHandler sWifiPnoEventHandler;
+
+ private static int sPnoCmdId = 0;
+
+ private native static boolean setPnoListNative(int iface, int id, WifiPnoNetwork list[]);
+
+ synchronized public static boolean setPnoList(WifiPnoNetwork list[],
+ WifiPnoEventHandler eventHandler) {
+ Log.e(TAG, "setPnoList cmd " + sPnoCmdId);
+
+ synchronized (mLock) {
+ if (isHalStarted()) {
+
+ sPnoCmdId = getNewCmdIdLocked();
+
+ sWifiPnoEventHandler = eventHandler;
+ if (setPnoListNative(sWlan0Index, sPnoCmdId, list)) {
+ return true;
+ }
+ }
+
+ sWifiPnoEventHandler = null;
+ return false;
+ }
+ }
+
+ synchronized public static void onPnoNetworkFound(int id, ScanResult[] results) {
+
+ if (results == null) {
+ Log.e(TAG, "onPnoNetworkFound null results");
+ return;
+
+ }
+ Log.d(TAG, "WifiNative.onPnoNetworkFound result " + results.length);
+
+ //Log.e(TAG, "onPnoNetworkFound length " + results.length);
+ //return;
+ for (int i=0; i<results.length; i++) {
+ Log.e(TAG, "onPnoNetworkFound SSID " + results[i].SSID
+ + " " + results[i].level + " " + results[i].frequency);
+
+ populateScanResult(results[i], results[i].bytes, "onPnoNetworkFound ");
+ results[i].wifiSsid = WifiSsid.createFromAsciiEncoded(results[i].SSID);
+ }
+ synchronized (mLock) {
+ if (sPnoCmdId != 0 && sWifiPnoEventHandler != null) {
+ sWifiPnoEventHandler.onPnoNetworkFound(results);
+ } else {
+ /* this can happen because of race conditions */
+ Log.d(TAG, "Ignoring Pno Network found event");
+ }
+ }
+ }
+
+ public class WifiLazyRoamParams {
+ int A_band_boost_threshold;
+ int A_band_penalty_threshold;
+ int A_band_boost_factor;
+ int A_band_penalty_factor;
+ int A_band_max_boost;
+ int lazy_roam_hysteresis;
+ int alert_roam_rssi_trigger;
+
+ WifiLazyRoamParams() {
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sbuf = new StringBuilder();
+ sbuf.append(" A_band_boost_threshold=").append(this.A_band_boost_threshold);
+ sbuf.append(" A_band_penalty_threshold=").append(this.A_band_penalty_threshold);
+ sbuf.append(" A_band_boost_factor=").append(this.A_band_boost_factor);
+ sbuf.append(" A_band_penalty_factor=").append(this.A_band_penalty_factor);
+ sbuf.append(" A_band_max_boost=").append(this.A_band_max_boost);
+ sbuf.append(" lazy_roam_hysteresis=").append(this.lazy_roam_hysteresis);
+ sbuf.append(" alert_roam_rssi_trigger=").append(this.alert_roam_rssi_trigger);
+ return sbuf.toString();
+ }
+ }
+
+ private native static boolean setLazyRoamNative(int iface, int id,
+ boolean enabled, WifiLazyRoamParams param);
+
+ synchronized public static boolean setLazyRoam(boolean enabled, WifiLazyRoamParams params) {
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ sPnoCmdId = getNewCmdIdLocked();
+ return setLazyRoamNative(sWlan0Index, sPnoCmdId, enabled, params);
+ } else {
+ return false;
+ }
+ }
+ }
+
+ private native static boolean setBssidBlacklistNative(int iface, int id,
+ String list[]);
+
+ synchronized public static boolean setBssidBlacklist(String list[]) {
+ int size = 0;
+ if (list != null) {
+ size = list.length;
+ }
+ Log.e(TAG, "setBssidBlacklist cmd " + sPnoCmdId + " size " + size);
+
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ sPnoCmdId = getNewCmdIdLocked();
+ return setBssidBlacklistNative(sWlan0Index, sPnoCmdId, list);
+ } else {
+ return false;
+ }
+ }
+ }
+
+ private native static boolean setSsidWhitelistNative(int iface, int id, String list[]);
+
+ synchronized public static boolean setSsidWhitelist(String list[]) {
+ int size = 0;
+ if (list != null) {
+ size = list.length;
+ }
+ Log.e(TAG, "setSsidWhitelist cmd " + sPnoCmdId + " size " + size);
+
+ synchronized (mLock) {
+ if (isHalStarted()) {
+ sPnoCmdId = getNewCmdIdLocked();
+
+ return setSsidWhitelistNative(sWlan0Index, sPnoCmdId, list);
+ } else {
+ return false;
+ }
+ }
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiNetworkScoreCache.java b/service/java/com/android/server/wifi/WifiNetworkScoreCache.java
index 0a7df0b..cf14c5f 100644
--- a/service/java/com/android/server/wifi/WifiNetworkScoreCache.java
+++ b/service/java/com/android/server/wifi/WifiNetworkScoreCache.java
@@ -139,7 +139,7 @@
}
private String buildNetworkKey(ScoredNetwork network) {
- if (network.networkKey == null) return null;
+ if (network == null || network.networkKey == null) return null;
if (network.networkKey.wifiKey == null) return null;
if (network.networkKey.type == NetworkKey.TYPE_WIFI) {
String key = network.networkKey.wifiKey.ssid;
@@ -153,7 +153,7 @@
}
private String buildNetworkKey(ScanResult result) {
- if (result.SSID == null) {
+ if (result == null || result.SSID == null) {
return null;
}
StringBuilder key = new StringBuilder("\"");
diff --git a/service/java/com/android/server/wifi/WifiNotificationController.java b/service/java/com/android/server/wifi/WifiNotificationController.java
index 20d64c9..406a764 100644
--- a/service/java/com/android/server/wifi/WifiNotificationController.java
+++ b/service/java/com/android/server/wifi/WifiNotificationController.java
@@ -65,7 +65,7 @@
/**
* The Notification object given to the NotificationManager.
*/
- private Notification mNotification;
+ private Notification.Builder mNotificationBuilder;
/**
* Whether the notification is being shown, as set by us. That is, if the
* user cancels the notification, we will not receive the callback so this
@@ -229,31 +229,32 @@
return;
}
- if (mNotification == null) {
- // Cache the Notification object.
- mNotification = new Notification();
- mNotification.when = 0;
- mNotification.icon = ICON_NETWORKS_AVAILABLE;
- mNotification.flags = Notification.FLAG_AUTO_CANCEL;
- mNotification.contentIntent = TaskStackBuilder.create(mContext)
- .addNextIntentWithParentStack(
- new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK))
- .getPendingIntent(0, 0, null, UserHandle.CURRENT);
+ if (mNotificationBuilder == null) {
+ // Cache the Notification builder object.
+ mNotificationBuilder = new Notification.Builder(mContext)
+ .setWhen(0)
+ .setSmallIcon(ICON_NETWORKS_AVAILABLE)
+ .setAutoCancel(true)
+ .setContentIntent(TaskStackBuilder.create(mContext)
+ .addNextIntentWithParentStack(
+ new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK))
+ .getPendingIntent(0, 0, null, UserHandle.CURRENT))
+ .setColor(mContext.getResources().getColor(
+ com.android.internal.R.color.system_notification_accent_color));
}
CharSequence title = mContext.getResources().getQuantityText(
com.android.internal.R.plurals.wifi_available, numNetworks);
CharSequence details = mContext.getResources().getQuantityText(
com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
- mNotification.tickerText = title;
- mNotification.color = mContext.getResources().getColor(
- com.android.internal.R.color.system_notification_accent_color);
- mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent);
+ mNotificationBuilder.setTicker(title);
+ mNotificationBuilder.setContentTitle(title);
+ mNotificationBuilder.setContentText(details);
mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS;
- notificationManager.notifyAsUser(null, ICON_NETWORKS_AVAILABLE, mNotification,
- UserHandle.ALL);
+ notificationManager.notifyAsUser(null, ICON_NETWORKS_AVAILABLE,
+ mNotificationBuilder.build(), UserHandle.ALL);
} else {
notificationManager.cancelAsUser(null, ICON_NETWORKS_AVAILABLE, UserHandle.ALL);
}
diff --git a/service/java/com/android/server/wifi/WifiScanningServiceImpl.java b/service/java/com/android/server/wifi/WifiScanningServiceImpl.java
index 6dacfb4..8f2cd3b 100644
--- a/service/java/com/android/server/wifi/WifiScanningServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiScanningServiceImpl.java
@@ -16,18 +16,24 @@
package com.android.server.wifi;
+import android.Manifest;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.net.wifi.IWifiScanner;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiScanner;
+import android.net.wifi.WifiScanner.BssidInfo;
+import android.net.wifi.WifiScanner.ChannelSpec;
+import android.net.wifi.WifiScanner.ScanData;
import android.net.wifi.WifiScanner.ScanSettings;
import android.net.wifi.WifiSsid;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
@@ -36,13 +42,16 @@
import android.os.Messenger;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.WorkSource;
+import android.util.LocalLog;
import android.util.Log;
-import android.util.Slog;
+import com.android.internal.app.IBatteryStats;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
import com.android.internal.util.StateMachine;
import com.android.internal.util.State;
+import com.android.server.am.BatteryStatsService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -51,26 +60,49 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.List;
import java.util.Map;
public class WifiScanningServiceImpl extends IWifiScanner.Stub {
private static final String TAG = "WifiScanningService";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
+ private static final boolean VDBG = false;
+
private static final int INVALID_KEY = 0; // same as WifiScanner
private static final int MIN_PERIOD_PER_CHANNEL_MS = 200; // DFS needs 120 ms
+ private static final int UNKNOWN_PID = -1;
+
+ private static final LocalLog mLocalLog = new LocalLog(1024);
+
+ private static void localLog(String message) {
+ mLocalLog.log(message);
+ }
+
+ private static void logw(String message) {
+ Log.w(TAG, message);
+ mLocalLog.log(message);
+ }
+
+ private static void loge(String message) {
+ Log.e(TAG, message);
+ mLocalLog.log(message);
+ }
@Override
public Messenger getMessenger() {
- return new Messenger(mClientHandler);
+ if (mClientHandler != null) {
+ return new Messenger(mClientHandler);
+ } else {
+ loge("WifiScanningServiceImpl trying to get messenger w/o initialization");
+ return null;
+ }
}
@Override
public Bundle getAvailableChannels(int band) {
- WifiScanner.ChannelSpec channelSpecs[] = getChannelsForBand(band);
+ ChannelSpec channelSpecs[] = getChannelsForBand(band);
ArrayList<Integer> list = new ArrayList<Integer>(channelSpecs.length);
- for (WifiScanner.ChannelSpec channelSpec : channelSpecs) {
+ for (ChannelSpec channelSpec : channelSpecs) {
list.add(channelSpec.frequency);
}
Bundle b = new Bundle();
@@ -78,10 +110,11 @@
return b;
}
- private void enforceConnectivityInternalPermission() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.CONNECTIVITY_INTERNAL,
- "WifiScanningServiceImpl");
+ private void enforceLocationHardwarePermission(int uid) {
+ mContext.enforcePermission(
+ Manifest.permission.LOCATION_HARDWARE,
+ UNKNOWN_PID, uid,
+ "LocationHardware");
}
private class ClientHandler extends Handler {
@@ -93,50 +126,53 @@
@Override
public void handleMessage(Message msg) {
- if (DBG) Log.d(TAG, "ClientHandler got" + msg);
+ if (DBG) localLog("ClientHandler got" + msg);
switch (msg.what) {
case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
- if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
- AsyncChannel c = (AsyncChannel) msg.obj;
- if (DBG) Slog.d(TAG, "New client listening to asynchronous messages: " +
- msg.replyTo);
- ClientInfo cInfo = new ClientInfo(c, msg.replyTo);
- mClients.put(msg.replyTo, cInfo);
- } else {
- Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
- }
- return;
- case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
- if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
- Slog.e(TAG, "Send failed, client connection lost");
- } else {
- if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
- }
- if (DBG) Slog.d(TAG, "closing client " + msg.replyTo);
- ClientInfo ci = mClients.remove(msg.replyTo);
- if (ci != null) { /* can be null if send failed above */
- ci.cleanup();
+ if (msg.arg1 != AsyncChannel.STATUS_SUCCESSFUL) {
+ loge("Client connection failure, error=" + msg.arg1);
}
return;
case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
AsyncChannel ac = new AsyncChannel();
ac.connect(mContext, this, msg.replyTo);
+ if (DBG) localLog("New client connected : " + msg.sendingUid + msg.replyTo);
+ ClientInfo cInfo = new ClientInfo(msg.sendingUid, ac, msg.replyTo);
+ mClients.put(msg.replyTo, cInfo);
+ return;
+ case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
+ if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
+ loge("Send failed, client connection lost");
+ } else {
+ if (DBG) localLog("Client connection lost with reason: " + msg.arg1);
+ }
+ if (DBG) localLog("closing client " + msg.replyTo);
+ ClientInfo ci = mClients.remove(msg.replyTo);
+ if (ci != null) { /* can be null if send failed above */
+ if (DBG) localLog("closing client " + ci.mUid);
+ ci.cleanup();
+ }
return;
}
- ClientInfo ci = mClients.get(msg.replyTo);
- if (ci == null) {
- Slog.e(TAG, "Could not find client info for message " + msg.replyTo);
- replyFailed(msg, WifiScanner.REASON_INVALID_LISTENER, "Could not find listener");
+ try {
+ enforceLocationHardwarePermission(msg.sendingUid);
+ } catch (SecurityException e) {
+ localLog("failed to authorize app: " + e);
+ replyFailed(msg, WifiScanner.REASON_NOT_AUTHORIZED, "Not authorized");
return;
}
- try {
- enforceConnectivityInternalPermission();
- } catch (SecurityException e) {
- replyFailed(msg, WifiScanner.REASON_NOT_AUTHORIZED, "Not authorized");
+ if (msg.what == WifiScanner.CMD_GET_SCAN_RESULTS) {
+ mStateMachine.sendMessage(Message.obtain(msg));
+ return;
+ }
+ ClientInfo ci = mClients.get(msg.replyTo);
+ if (ci == null) {
+ loge("Could not find client info for message " + msg.replyTo);
+ replyFailed(msg, WifiScanner.REASON_INVALID_LISTENER, "Could not find listener");
return;
}
@@ -144,6 +180,8 @@
WifiScanner.CMD_SCAN,
WifiScanner.CMD_START_BACKGROUND_SCAN,
WifiScanner.CMD_STOP_BACKGROUND_SCAN,
+ WifiScanner.CMD_START_SINGLE_SCAN,
+ WifiScanner.CMD_STOP_SINGLE_SCAN,
WifiScanner.CMD_SET_HOTLIST,
WifiScanner.CMD_RESET_HOTLIST,
WifiScanner.CMD_CONFIGURE_WIFI_CHANGE,
@@ -173,10 +211,13 @@
private static final int CMD_DRIVER_UNLOADED = BASE + 7;
private static final int CMD_SCAN_PAUSED = BASE + 8;
private static final int CMD_SCAN_RESTARTED = BASE + 9;
+ private static final int CMD_STOP_SCAN_INTERNAL = BASE + 10;
private Context mContext;
private WifiScanningStateMachine mStateMachine;
private ClientHandler mClientHandler;
+ private IBatteryStats mBatteryStats;
+ private final WifiNative.ScanCapabilities mScanCapabilities = new WifiNative.ScanCapabilities();
WifiScanningServiceImpl() { }
@@ -193,6 +234,7 @@
mClientHandler = new ClientHandler(thread.getLooper());
mStateMachine = new WifiScanningStateMachine(thread.getLooper());
mWifiChangeStateMachine = new WifiChangeStateMachine(thread.getLooper());
+ mBatteryStats = BatteryStatsService.getService();
mContext.registerReceiver(
new BroadcastReceiver() {
@@ -200,7 +242,7 @@
public void onReceive(Context context, Intent intent) {
int state = intent.getIntExtra(
WifiManager.EXTRA_SCAN_AVAILABLE, WifiManager.WIFI_STATE_DISABLED);
- if (DBG) Log.d(TAG, "SCAN_AVAILABLE : " + state);
+ if (DBG) localLog("SCAN_AVAILABLE : " + state);
if (state == WifiManager.WIFI_STATE_ENABLED) {
mStateMachine.sendMessage(CMD_DRIVER_LOADED);
} else if (state == WifiManager.WIFI_STATE_DISABLED) {
@@ -236,62 +278,67 @@
@Override
public void onScanResultsAvailable() {
- if (DBG) Log.d(TAG, "onScanResultAvailable event received");
+ if (DBG) localLog("onScanResultAvailable event received");
sendMessage(CMD_SCAN_RESULTS_AVAILABLE);
}
@Override
- public void onSingleScanComplete() {
- if (DBG) Log.d(TAG, "onSingleScanComplete event received");
+ public void onScanStatus() {
+ if (DBG) localLog("onScanStatus event received");
sendMessage(CMD_SCAN_RESULTS_AVAILABLE);
}
@Override
public void onFullScanResult(ScanResult fullScanResult) {
- if (DBG) Log.d(TAG, "Full scanresult received");
+ if (DBG) localLog("Full scanresult received");
sendMessage(CMD_FULL_SCAN_RESULTS, 0, 0, fullScanResult);
}
@Override
- public void onScanPaused() {
- sendMessage(CMD_SCAN_PAUSED);
+ public void onScanPaused(ScanData scanData[]) {
+ sendMessage(CMD_SCAN_PAUSED, scanData);
}
@Override
public void onScanRestarted() {
+ if (DBG) localLog("onScanRestarted() event received");
sendMessage(CMD_SCAN_RESTARTED);
}
@Override
public void onHotlistApFound(ScanResult[] results) {
- if (DBG) Log.d(TAG, "HotlistApFound event received");
+ if (DBG) localLog("HotlistApFound event received");
sendMessage(CMD_HOTLIST_AP_FOUND, 0, 0, results);
}
@Override
+ public void onHotlistApLost(ScanResult[] results) {
+ if (DBG) localLog("HotlistApLost event received");
+ sendMessage(CMD_HOTLIST_AP_LOST, 0, 0, results);
+ }
+
+ @Override
public void onChangesFound(ScanResult[] results) {
- if (DBG) Log.d(TAG, "onWifiChangesFound event received");
+ if (DBG) localLog("onWifiChangesFound event received");
sendMessage(CMD_WIFI_CHANGE_DETECTED, 0, 0, results);
}
class DefaultState extends State {
@Override
public void enter() {
- if (DBG) Log.d(TAG, "DefaultState");
+ if (DBG) localLog("DefaultState");
}
@Override
public boolean processMessage(Message msg) {
- if (DBG) Log.d(TAG, "DefaultState got" + msg);
+ if (DBG) localLog("DefaultState got" + msg);
ClientInfo ci = mClients.get(msg.replyTo);
switch (msg.what) {
case CMD_DRIVER_LOADED:
- if (WifiNative.startHal() && WifiNative.getInterfaces() != 0) {
- WifiNative.ScanCapabilities capabilities =
- new WifiNative.ScanCapabilities();
- if (WifiNative.getScanCapabilities(capabilities)) {
+ if (WifiNative.getInterfaces() != 0) {
+ if (WifiNative.getScanCapabilities(mScanCapabilities)) {
transitionTo(mStartedState);
} else {
loge("could not get scan capabilities");
@@ -303,20 +350,23 @@
case WifiScanner.CMD_SCAN:
case WifiScanner.CMD_START_BACKGROUND_SCAN:
case WifiScanner.CMD_STOP_BACKGROUND_SCAN:
+ case WifiScanner.CMD_START_SINGLE_SCAN:
+ case WifiScanner.CMD_STOP_SINGLE_SCAN:
case WifiScanner.CMD_SET_HOTLIST:
case WifiScanner.CMD_RESET_HOTLIST:
case WifiScanner.CMD_CONFIGURE_WIFI_CHANGE:
case WifiScanner.CMD_START_TRACKING_CHANGE:
case WifiScanner.CMD_STOP_TRACKING_CHANGE:
+ case WifiScanner.CMD_GET_SCAN_RESULTS:
replyFailed(msg, WifiScanner.REASON_UNSPECIFIED, "not available");
break;
case CMD_SCAN_RESULTS_AVAILABLE:
- if (DBG) log("ignored scan results available event");
+ if (DBG) localLog("ignored scan results available event");
break;
case CMD_FULL_SCAN_RESULTS:
- if (DBG) log("ignored full scan result event");
+ if (DBG) localLog("ignored full scan result event");
break;
default:
@@ -331,13 +381,13 @@
@Override
public void enter() {
- if (DBG) Log.d(TAG, "StartedState");
+ if (DBG) localLog("StartedState");
}
@Override
public boolean processMessage(Message msg) {
- if (DBG) Log.d(TAG, "StartedState got" + msg);
+ if (DBG) localLog("StartedState got" + msg);
ClientInfo ci = mClients.get(msg.replyTo);
@@ -350,7 +400,7 @@
break;
case WifiScanner.CMD_START_BACKGROUND_SCAN:
if (addScanRequest(ci, msg.arg2, (ScanSettings) msg.obj)) {
- replySucceeded(msg, null);
+ replySucceeded(msg);
} else {
replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
}
@@ -359,18 +409,33 @@
removeScanRequest(ci, msg.arg2);
break;
case WifiScanner.CMD_GET_SCAN_RESULTS:
- replySucceeded(msg, getScanResults(ci));
+ reportScanResults();
+ replySucceeded(msg);
+ break;
+ case WifiScanner.CMD_START_SINGLE_SCAN:
+ if (addSingleScanRequest(ci, msg.arg2, (ScanSettings) msg.obj)) {
+ replySucceeded(msg);
+ } else {
+ replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
+ }
+ break;
+ case WifiScanner.CMD_STOP_SINGLE_SCAN:
+ removeScanRequest(ci, msg.arg2);
+ break;
+ case CMD_STOP_SCAN_INTERNAL:
+ localLog("Removing single shot scan");
+ removeScanRequest((ClientInfo) msg.obj, msg.arg2);
break;
case WifiScanner.CMD_SET_HOTLIST:
setHotlist(ci, msg.arg2, (WifiScanner.HotlistSettings) msg.obj);
- replySucceeded(msg, null);
+ replySucceeded(msg);
break;
case WifiScanner.CMD_RESET_HOTLIST:
resetHotlist(ci, msg.arg2);
break;
case WifiScanner.CMD_START_TRACKING_CHANGE:
trackWifiChanges(ci, msg.arg2);
- replySucceeded(msg, null);
+ replySucceeded(msg);
break;
case WifiScanner.CMD_STOP_TRACKING_CHANGE:
untrackWifiChanges(ci, msg.arg2);
@@ -379,7 +444,7 @@
configureWifiChange((WifiScanner.WifiChangeSettings) msg.obj);
break;
case CMD_SCAN_RESULTS_AVAILABLE: {
- ScanResult[] results = WifiNative.getScanResults();
+ ScanData[] results = WifiNative.getScanResults(/* flush = */ true);
Collection<ClientInfo> clients = mClients.values();
for (ClientInfo ci2 : clients) {
ci2.reportScanResults(results);
@@ -388,7 +453,7 @@
break;
case CMD_FULL_SCAN_RESULTS: {
ScanResult result = (ScanResult) msg.obj;
- if (DBG) Log.d(TAG, "reporting fullscan result for " + result.SSID);
+ if (DBG) localLog("reporting fullscan result for " + result.SSID);
Collection<ClientInfo> clients = mClients.values();
for (ClientInfo ci2 : clients) {
ci2.reportFullScanResult(result);
@@ -398,10 +463,19 @@
case CMD_HOTLIST_AP_FOUND: {
ScanResult[] results = (ScanResult[])msg.obj;
- if (DBG) Log.d(TAG, "Found " + results.length + " results");
+ if (DBG) localLog("Found " + results.length + " results");
Collection<ClientInfo> clients = mClients.values();
for (ClientInfo ci2 : clients) {
- ci2.reportHotlistResults(results);
+ ci2.reportHotlistResults(WifiScanner.CMD_AP_FOUND, results);
+ }
+ }
+ break;
+ case CMD_HOTLIST_AP_LOST: {
+ ScanResult[] results = (ScanResult[])msg.obj;
+ if (DBG) localLog("Lost " + results.length + " results");
+ Collection<ClientInfo> clients = mClients.values();
+ for (ClientInfo ci2 : clients) {
+ ci2.reportHotlistResults(WifiScanner.CMD_AP_LOST, results);
}
}
break;
@@ -415,7 +489,15 @@
reportWifiStabilized(results);
}
break;
-
+ case CMD_SCAN_PAUSED: {
+ ScanData results[] = (ScanData[]) msg.obj;
+ Collection<ClientInfo> clients = mClients.values();
+ for (ClientInfo ci2 : clients) {
+ ci2.reportScanResults(results);
+ }
+ transitionTo(mPausedState);
+ }
+ break;
default:
return NOT_HANDLED;
}
@@ -427,13 +509,13 @@
class PausedState extends State {
@Override
public void enter() {
- if (DBG) Log.d(TAG, "PausedState");
+ if (DBG) localLog("PausedState");
}
@Override
public boolean processMessage(Message msg) {
- if (DBG) Log.d(TAG, "PausedState got" + msg);
+ if (DBG) localLog("PausedState got" + msg);
switch (msg.what) {
case CMD_SCAN_RESTARTED:
@@ -450,11 +532,17 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- super.dump(fd, pw, args);
pw.println("number of clients : " + mClients.size());
+ for (ClientInfo client : mClients.values()) {
+ client.dump(fd, pw, args);
+ pw.append("------\n");
+ }
pw.println();
+ pw.println("localLog : ");
+ mLocalLog.dump(fd, pw, args);
+ pw.append("\n\n");
+ super.dump(fd, pw, args);
}
-
}
/* client management */
@@ -464,28 +552,93 @@
private static final int MAX_LIMIT = 16;
private final AsyncChannel mChannel;
private final Messenger mMessenger;
+ private final int mUid;
+ private final WorkSource mWorkSource;
+ private boolean mScanWorkReported = false;
- ClientInfo(AsyncChannel c, Messenger m) {
+ ClientInfo(int uid, AsyncChannel c, Messenger m) {
mChannel = c;
mMessenger = m;
- if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m);
+ mUid = uid;
+ mWorkSource = new WorkSource(uid, TAG);
+ if (DBG) localLog("New client, channel: " + c + " messenger: " + m);
+ }
+
+ void reportBatchedScanStart() {
+ if (mUid == 0)
+ return;
+
+ int csph = getCsph();
+
+ try {
+ mBatteryStats.noteWifiBatchedScanStartedFromSource(mWorkSource, csph);
+ localLog("started scanning for UID " + mUid + ", csph = " + csph);
+ } catch (RemoteException e) {
+ logw("failed to report scan work: " + e.toString());
+ }
+ }
+
+ void reportBatchedScanStop() {
+ if (mUid == 0)
+ return;
+
+ try {
+ mBatteryStats.noteWifiBatchedScanStoppedFromSource(mWorkSource);
+ localLog("stopped scanning for UID " + mUid);
+ } catch (RemoteException e) {
+ logw("failed to cleanup scan work: " + e.toString());
+ }
+ }
+
+ int getCsph() {
+ int csph = 0;
+ for (ScanSettings settings : getScanSettings()) {
+ int num_channels = settings.channels == null ? 0 : settings.channels.length;
+ if (num_channels == 0 && settings.band != 0) {
+ num_channels = getChannelsForBand(settings.band).length;
+ }
+
+ int scans_per_Hour = settings.periodInMs == 0 ? 1 : (3600 * 1000) / settings.periodInMs;
+ csph += num_channels * scans_per_Hour;
+ }
+
+ return csph;
+ }
+
+ void reportScanWorkUpdate() {
+ if (mScanWorkReported) {
+ reportBatchedScanStop();
+ mScanWorkReported = false;
+ }
+ if (mScanSettings.isEmpty() == false) {
+ reportBatchedScanStart();
+ mScanWorkReported = true;
+ }
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("mChannel ").append(mChannel).append("\n");
- sb.append("mMessenger ").append(mMessenger).append("\n");
+ sb.append("mMessenger ").append(mMessenger);
+ return sb.toString();
+ }
+
+ void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(toString());
Iterator<Map.Entry<Integer, ScanSettings>> it = mScanSettings.entrySet().iterator();
for (; it.hasNext(); ) {
Map.Entry<Integer, ScanSettings> entry = it.next();
- sb.append("[ScanId ").append(entry.getKey()).append("\n");
- sb.append("ScanSettings ").append(entry.getValue()).append("\n");
- sb.append("]");
+ sb.append("ScanId ").append(entry.getKey()).append("\n");
+
+ ScanSettings scanSettings = entry.getValue();
+ sb.append(describe(scanSettings));
+ sb.append("\n");
}
- return sb.toString();
+ pw.println(sb.toString());
}
HashMap<Integer, ScanSettings> mScanSettings = new HashMap<Integer, ScanSettings>(4);
@@ -493,13 +646,19 @@
void addScanRequest(ScanSettings settings, int id) {
mScanSettings.put(id, settings);
+ reportScanWorkUpdate();
}
void removeScanRequest(int id) {
- mScanSettings.remove(id);
+ ScanSettings settings = mScanSettings.remove(id);
+ if (settings != null && settings.periodInMs == 0) {
+ /* this was a single shot scan */
+ mChannel.sendMessage(WifiScanner.CMD_SINGLE_SCAN_COMPLETED, 0, id);
+ }
+ reportScanWorkUpdate();
}
- Iterator<Map.Entry<Integer, WifiScanner.ScanSettings>> getScans() {
+ Iterator<Map.Entry<Integer, ScanSettings>> getScans() {
return mScanSettings.entrySet().iterator();
}
@@ -507,7 +666,7 @@
return mScanSettings.values();
}
- void reportScanResults(ScanResult[] results) {
+ void reportScanResults(ScanData[] results) {
Iterator<Integer> it = mScanSettings.keySet().iterator();
while (it.hasNext()) {
int handler = it.next();
@@ -515,9 +674,9 @@
}
}
- void reportScanResults(ScanResult[] results, int handler) {
+ void reportScanResults(ScanData[] results, int handler) {
ScanSettings settings = mScanSettings.get(handler);
- WifiScanner.ChannelSpec desiredChannels[] = settings.channels;
+ ChannelSpec desiredChannels[] = settings.channels;
if (settings.band != WifiScanner.WIFI_BAND_UNSPECIFIED
|| desiredChannels == null || desiredChannels.length == 0) {
desiredChannels = getChannelsForBand(settings.band);
@@ -525,42 +684,62 @@
// check the channels this client asked for ..
int num_results = 0;
- for (ScanResult result : results) {
- for (WifiScanner.ChannelSpec channelSpec : desiredChannels) {
- if (channelSpec.frequency == result.frequency) {
+ for (ScanData result : results) {
+ boolean copyScanData = false;
+ for (ScanResult scanResult : result.getResults()) {
+ for (ChannelSpec channelSpec : desiredChannels) {
+ if (channelSpec.frequency == scanResult.frequency) {
+ copyScanData = true;
+ break;
+ }
+ }
+ if (copyScanData) {
num_results++;
break;
}
}
}
- if (num_results == 0) {
- // nothing to report
- return;
- }
+ localLog("results = " + results.length + ", num_results = " + num_results);
- ScanResult results2[] = new ScanResult[num_results];
+ ScanData results2[] = new ScanData[num_results];
int index = 0;
- for (ScanResult result : results) {
- for (WifiScanner.ChannelSpec channelSpec : desiredChannels) {
- if (channelSpec.frequency == result.frequency) {
- WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded(result.SSID);
- ScanResult newResult = new ScanResult(wifiSsid, result.BSSID, "",
- result.level, result.frequency, result.timestamp);
- results2[index] = newResult;
- index++;
+ for (ScanData result : results) {
+ boolean copyScanData = false;
+ for (ScanResult scanResult : result.getResults()) {
+ for (ChannelSpec channelSpec : desiredChannels) {
+ if (channelSpec.frequency == scanResult.frequency) {
+ copyScanData = true;
+ break;
+ }
+ }
+ if (copyScanData) {
break;
}
}
+
+ if (copyScanData) {
+ if (VDBG) {
+ localLog("adding at " + index);
+ }
+ results2[index] = new WifiScanner.ScanData(result);
+ index++;
+ }
}
+
+ localLog("delivering results, num = " + results2.length);
deliverScanResults(handler, results2);
+ if (settings.periodInMs == 0) {
+ /* this is a single shot scan; stop the scan now */
+ mStateMachine.sendMessage(CMD_STOP_SCAN_INTERNAL, 0, handler, this);
+ }
}
- void deliverScanResults(int handler, ScanResult results[]) {
- WifiScanner.ParcelableScanResults parcelableScanResults =
- new WifiScanner.ParcelableScanResults(results);
- mChannel.sendMessage(WifiScanner.CMD_SCAN_RESULT, 0, handler, parcelableScanResults);
+ void deliverScanResults(int handler, ScanData results[]) {
+ WifiScanner.ParcelableScanData parcelableScanData =
+ new WifiScanner.ParcelableScanData(results);
+ mChannel.sendMessage(WifiScanner.CMD_SCAN_RESULT, 0, handler, parcelableScanData);
}
void reportFullScanResult(ScanResult result) {
@@ -568,17 +747,15 @@
while (it.hasNext()) {
int handler = it.next();
ScanSettings settings = mScanSettings.get(handler);
- WifiScanner.ChannelSpec desiredChannels[] = settings.channels;
+ ChannelSpec desiredChannels[] = settings.channels;
if (settings.band != WifiScanner.WIFI_BAND_UNSPECIFIED
|| desiredChannels == null || desiredChannels.length == 0) {
desiredChannels = getChannelsForBand(settings.band);
}
- for (WifiScanner.ChannelSpec channelSpec : desiredChannels) {
+ for (ChannelSpec channelSpec : desiredChannels) {
if (channelSpec.frequency == result.frequency) {
- WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded(result.SSID);
- ScanResult newResult = new ScanResult(wifiSsid, result.BSSID, "",
- result.level, result.frequency, result.timestamp);
- if (DBG) Log.d(TAG, "sending it to " + handler);
+ ScanResult newResult = new ScanResult(result);
+ if (DBG) localLog("sending it to " + handler);
newResult.informationElements = result.informationElements.clone();
mChannel.sendMessage(
WifiScanner.CMD_FULL_SCAN_RESULT, 0, handler, newResult);
@@ -614,7 +791,7 @@
return mHotlistSettings.values();
}
- void reportHotlistResults(ScanResult[] results) {
+ void reportHotlistResults(int what, ScanResult[] results) {
Iterator<Map.Entry<Integer, WifiScanner.HotlistSettings>> it =
mHotlistSettings.entrySet().iterator();
while (it.hasNext()) {
@@ -623,7 +800,7 @@
WifiScanner.HotlistSettings settings = entry.getValue();
int num_results = 0;
for (ScanResult result : results) {
- for (WifiScanner.BssidInfo BssidInfo : settings.bssidInfos) {
+ for (BssidInfo BssidInfo : settings.bssidInfos) {
if (result.BSSID.equalsIgnoreCase(BssidInfo.bssid)) {
num_results++;
break;
@@ -639,7 +816,7 @@
ScanResult results2[] = new ScanResult[num_results];
int index = 0;
for (ScanResult result : results) {
- for (WifiScanner.BssidInfo BssidInfo : settings.bssidInfos) {
+ for (BssidInfo BssidInfo : settings.bssidInfos) {
if (result.BSSID.equalsIgnoreCase(BssidInfo.bssid)) {
results2[index] = result;
index++;
@@ -650,7 +827,7 @@
WifiScanner.ParcelableScanResults parcelableScanResults =
new WifiScanner.ParcelableScanResults(results2);
- mChannel.sendMessage(WifiScanner.CMD_AP_FOUND, 0, handler, parcelableScanResults);
+ mChannel.sendMessage(what, 0, handler, parcelableScanResults);
}
}
@@ -701,16 +878,15 @@
}
mSignificantWifiHandlers.clear();
- Log.d(TAG, "Successfully stopped all requests for client " + this);
+ localLog("Successfully stopped all requests for client " + this);
}
}
- void replySucceeded(Message msg, Object obj) {
+ void replySucceeded(Message msg) {
if (msg.replyTo != null) {
Message reply = Message.obtain();
reply.what = WifiScanner.CMD_OP_SUCCEEDED;
reply.arg2 = msg.arg2;
- reply.obj = obj;
try {
msg.replyTo.send(reply);
} catch (RemoteException e) {
@@ -737,9 +913,9 @@
}
}
- private static class SettingsComputer {
+ private class SettingsComputer {
- private static class TimeBucket {
+ private class TimeBucket {
int periodInSecond;
int periodMinInSecond;
int periodMaxInSecond;
@@ -751,53 +927,49 @@
}
}
- private static final TimeBucket[] mTimeBuckets = new TimeBucket[] {
+ private final TimeBucket[] mTimeBuckets = new TimeBucket[] {
new TimeBucket( 1, 0, 5 ),
new TimeBucket( 5, 5, 10 ),
new TimeBucket( 10, 10, 25 ),
new TimeBucket( 30, 25, 55 ),
- new TimeBucket( 60, 55, 100),
+ new TimeBucket( 60, 55, 240),
new TimeBucket( 300, 240, 500),
new TimeBucket( 600, 500, 1500),
new TimeBucket( 1800, 1500, WifiScanner.MAX_SCAN_PERIOD_MS) };
- private static final int MAX_BUCKETS = 8;
- private static final int MAX_CHANNELS = 8;
- private static final int DEFAULT_MAX_AP_PER_SCAN = 10;
- private static final int DEFAULT_REPORT_THRESHOLD = 10;
+ private static final int MAX_CHANNELS = 32;
private static final int DEFAULT_BASE_PERIOD_MS = 5000;
+ private static final int DEFAULT_REPORT_THRESHOLD_NUM_SCANS = 10;
+ private static final int DEFAULT_REPORT_THRESHOLD_PERCENT = 100;
private WifiNative.ScanSettings mSettings;
{
mSettings = new WifiNative.ScanSettings();
- mSettings.max_ap_per_scan = DEFAULT_MAX_AP_PER_SCAN;
+ mSettings.max_ap_per_scan = mScanCapabilities.max_ap_cache_per_scan;
mSettings.base_period_ms = DEFAULT_BASE_PERIOD_MS;
- mSettings.report_threshold = DEFAULT_REPORT_THRESHOLD;
+ mSettings.report_threshold_percent = DEFAULT_REPORT_THRESHOLD_PERCENT;
+ mSettings.report_threshold_num_scans = DEFAULT_REPORT_THRESHOLD_NUM_SCANS;
- mSettings.buckets = new WifiNative.BucketSettings[MAX_BUCKETS];
+ mSettings.buckets = new WifiNative.BucketSettings[mScanCapabilities.max_scan_buckets];
for (int i = 0; i < mSettings.buckets.length; i++) {
WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings();
bucketSettings.bucket = i;
bucketSettings.report_events = 0;
bucketSettings.channels = new WifiNative.ChannelSettings[MAX_CHANNELS];
bucketSettings.num_channels = 0;
- for (int j = 0; j < bucketSettings.channels.length; j++) {
- WifiNative.ChannelSettings channelSettings = new WifiNative.ChannelSettings();
- bucketSettings.channels[j] = channelSettings;
- }
mSettings.buckets[i] = bucketSettings;
}
}
HashMap<Integer, Integer> mChannelToBucketMap = new HashMap<Integer, Integer>();
- private int getBestBucket(WifiScanner.ScanSettings settings) {
+ private int getBestBucket(ScanSettings settings) {
// check to see if any of the channels are being scanned already
// and find the smallest bucket index (it represents the quickest
// period of scan)
- WifiScanner.ChannelSpec channels[] = settings.channels;
+ ChannelSpec channels[] = settings.channels;
if (channels == null) {
// set channels based on band
channels = getChannelsForBand(settings.band);
@@ -805,13 +977,13 @@
if (channels == null) {
// still no channels; then there's nothing to scan
- Log.e(TAG, "No channels to scan!!");
+ loge("No channels to scan!!");
return -1;
}
int mostFrequentBucketIndex = mTimeBuckets.length;
- for (WifiScanner.ChannelSpec desiredChannelSpec : channels) {
+ for (ChannelSpec desiredChannelSpec : channels) {
if (mChannelToBucketMap.containsKey(desiredChannelSpec.frequency)) {
int bucket = mChannelToBucketMap.get(desiredChannelSpec.frequency);
if (bucket < mostFrequentBucketIndex) {
@@ -832,36 +1004,36 @@
}
if (mostFrequentBucketIndex < bestBucketIndex) {
- for (WifiScanner.ChannelSpec desiredChannelSpec : channels) {
+ for (ChannelSpec desiredChannelSpec : channels) {
mChannelToBucketMap.put(desiredChannelSpec.frequency, mostFrequentBucketIndex);
}
- Log.d(TAG, "returning mf bucket number " + mostFrequentBucketIndex);
+ localLog("returning mf bucket number " + mostFrequentBucketIndex);
return mostFrequentBucketIndex;
} else if (bestBucketIndex != -1) {
- for (WifiScanner.ChannelSpec desiredChannelSpec : channels) {
+ for (ChannelSpec desiredChannelSpec : channels) {
mChannelToBucketMap.put(desiredChannelSpec.frequency, bestBucketIndex);
}
- Log.d(TAG, "returning best bucket number " + bestBucketIndex);
+ localLog("returning best bucket number " + bestBucketIndex);
return bestBucketIndex;
}
- Log.e(TAG, "Could not find suitable bucket for period " + settings.periodInMs);
+ loge("Could not find suitable bucket for period " + settings.periodInMs);
return -1;
}
- void prepChannelMap(WifiScanner.ScanSettings settings) {
+ void prepChannelMap(ScanSettings settings) {
getBestBucket(settings);
}
- int addScanRequestToBucket(WifiScanner.ScanSettings settings) {
+ int addScanRequestToBucket(ScanSettings settings) {
int bucketIndex = getBestBucket(settings);
if (bucketIndex == -1) {
- Log.e(TAG, "Ignoring invalid settings");
+ loge("Ignoring invalid settings");
return -1;
}
- WifiScanner.ChannelSpec desiredChannels[] = settings.channels;
+ ChannelSpec desiredChannels[] = settings.channels;
if (settings.band != WifiScanner.WIFI_BAND_UNSPECIFIED
|| desiredChannels == null
|| desiredChannels.length == 0) {
@@ -869,28 +1041,29 @@
desiredChannels = getChannelsForBand(settings.band);
if (desiredChannels == null) {
// still no channels; then there's nothing to scan
- Log.e(TAG, "No channels to scan!!");
+ loge("No channels to scan!!");
return -1;
}
}
// merge the channel lists for these buckets
- Log.d(TAG, "merging " + desiredChannels.length + " channels "
- + " for period " + settings.periodInMs);
+ localLog("merging " + desiredChannels.length + " channels "
+ + " for period " + settings.periodInMs
+ + " maxScans " + settings.maxScansToCache);
WifiNative.BucketSettings bucket = mSettings.buckets[bucketIndex];
boolean added = (bucket.num_channels == 0)
&& (bucket.band == WifiScanner.WIFI_BAND_UNSPECIFIED);
- Log.d(TAG, "existing " + bucket.num_channels + " channels ");
+ localLog("existing " + bucket.num_channels + " channels ");
- HashSet<WifiScanner.ChannelSpec> newChannels = new HashSet<WifiScanner.ChannelSpec>();
- for (WifiScanner.ChannelSpec desiredChannelSpec : desiredChannels) {
+ HashSet<ChannelSpec> newChannels = new HashSet<ChannelSpec>();
+ for (ChannelSpec desiredChannelSpec : desiredChannels) {
- Log.d(TAG, "desired channel " + desiredChannelSpec.frequency);
+ if (DBG) localLog("desired channel " + desiredChannelSpec.frequency);
boolean found = false;
- for (WifiNative.ChannelSettings existingChannelSpec : bucket.channels) {
- if (desiredChannelSpec.frequency == existingChannelSpec.frequency) {
+ for (int i = 0; i < bucket.num_channels; i++) {
+ if (desiredChannelSpec.frequency == bucket.channels[i].frequency) {
found = true;
break;
}
@@ -899,7 +1072,7 @@
if (!found) {
newChannels.add(desiredChannelSpec);
} else {
- if (DBG) Log.d(TAG, "Already scanning channel " + desiredChannelSpec.frequency);
+ if (DBG) localLog("Already scanning channel " + desiredChannelSpec.frequency);
}
}
@@ -910,24 +1083,25 @@
bucket.band = getBandFromChannels(bucket.channels)
| getBandFromChannels(desiredChannels);
bucket.channels = new WifiNative.ChannelSettings[0];
- Log.d(TAG, "switching to using band " + bucket.band);
+ localLog("switching to using band " + bucket.band);
} else {
- for (WifiScanner.ChannelSpec desiredChannelSpec : newChannels) {
+ for (ChannelSpec desiredChannelSpec : newChannels) {
- Log.d(TAG, "adding new channel spec " + desiredChannelSpec.frequency);
+ localLog("adding new channel spec " + desiredChannelSpec.frequency);
- WifiNative.ChannelSettings channelSettings = bucket.channels[bucket.num_channels];
+ WifiNative.ChannelSettings channelSettings = new WifiNative.ChannelSettings();
channelSettings.frequency = desiredChannelSpec.frequency;
+ bucket.channels[bucket.num_channels] = channelSettings;
bucket.num_channels++;
mChannelToBucketMap.put(bucketIndex, channelSettings.frequency);
}
}
if (bucket.report_events < settings.reportEvents) {
- if (DBG) Log.d(TAG, "setting report_events to " + settings.reportEvents);
+ if (DBG) localLog("setting report_events to " + settings.reportEvents);
bucket.report_events = settings.reportEvents;
} else {
- if (DBG) Log.d(TAG, "report_events is " + settings.reportEvents);
+ if (DBG) localLog("report_events is " + settings.reportEvents);
}
if (added) {
@@ -935,8 +1109,16 @@
mSettings.num_buckets++;
}
- if (mSettings.max_ap_per_scan < settings.numBssidsPerScan) {
- mSettings.max_ap_per_scan = settings.numBssidsPerScan;
+ if ( settings.numBssidsPerScan != 0) {
+ if (mSettings.max_ap_per_scan > settings.numBssidsPerScan) {
+ mSettings.max_ap_per_scan = settings.numBssidsPerScan;
+ }
+ }
+
+ if (settings.maxScansToCache != 0) {
+ if (mSettings.report_threshold_num_scans > settings.maxScansToCache) {
+ mSettings.report_threshold_num_scans = settings.maxScansToCache;
+ }
}
return bucket.period_ms;
@@ -980,13 +1162,13 @@
for (ClientInfo ci : clients) {
Iterator it = ci.getScans();
while (it.hasNext()) {
- Map.Entry<Integer, WifiScanner.ScanSettings> entry =
- (Map.Entry<Integer,WifiScanner.ScanSettings>)it.next();
+ Map.Entry<Integer, ScanSettings> entry =
+ (Map.Entry<Integer,ScanSettings>)it.next();
int id = entry.getKey();
ScanSettings s = entry.getValue();
int newPeriodInMs = c.addScanRequestToBucket(s);
if (newPeriodInMs == -1) {
- if (DBG) Log.d(TAG, "could not find a good bucket");
+ if (DBG) localLog("could not find a good bucket");
return false;
}
if (newPeriodInMs != s.periodInMs) {
@@ -999,25 +1181,46 @@
WifiNative.ScanSettings s = c.getComputedSettings();
if (s.num_buckets == 0) {
- if (DBG) Log.d(TAG, "Stopping scan because there are no buckets");
+ if (DBG) localLog("Stopping scan because there are no buckets");
WifiNative.stopScan();
return true;
} else {
if (WifiNative.startScan(s, mStateMachine)) {
- if (DBG) Log.d(TAG, "Successfully started scan of " + s.num_buckets + " buckets at"
- + "time = " + SystemClock.elapsedRealtimeNanos()/1000);
+ localLog("Successfully started scan of " + s.num_buckets + " buckets at"
+ + "time = " + SystemClock.elapsedRealtimeNanos() / 1000 + " period "
+ + s.base_period_ms);
return true;
} else {
- if (DBG) Log.d(TAG, "Failed to start scan of " + s.num_buckets + " buckets");
+ loge("Failed to start scan of " + s.num_buckets + " buckets");
return false;
}
}
}
+ void logScanRequest(String request, ClientInfo ci, int id, ScanSettings settings) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(request);
+ sb.append("\nClient ");
+ sb.append(ci.toString());
+ sb.append("\nId ");
+ sb.append(id);
+ sb.append("\n");
+ if (settings != null) {
+ sb.append(describe(settings));
+ sb.append("\n");
+ }
+ sb.append("\n");
+ localLog(sb.toString());
+ }
+
boolean addScanRequest(ClientInfo ci, int handler, ScanSettings settings) {
// sanity check the input
+ if (ci == null) {
+ Log.d(TAG, "Failing scan request ClientInfo not found " + handler);
+ return false;
+ }
if (settings.periodInMs < WifiScanner.MIN_SCAN_PERIOD_MS) {
- Log.d(TAG, "Failing scan request because periodInMs is " + settings.periodInMs);
+ localLog("Failing scan request because periodInMs is " + settings.periodInMs);
return false;
}
@@ -1040,30 +1243,63 @@
}
if (settings.periodInMs < minSupportedPeriodMs) {
- Log.d(TAG, "Failing scan request because minSupportedPeriodMs is "
+ localLog("Failing scan request because minSupportedPeriodMs is "
+ minSupportedPeriodMs + " but the request wants " + settings.periodInMs);
return false;
}
+ logScanRequest("addScanRequest", ci, handler, settings);
ci.addScanRequest(settings, handler);
if (resetBuckets()) {
return true;
} else {
ci.removeScanRequest(handler);
- Log.d(TAG, "Failing scan request because failed to reset scan");
+ localLog("Failing scan request because failed to reset scan");
+ return false;
+ }
+ }
+
+ boolean addSingleScanRequest(ClientInfo ci, int handler, ScanSettings settings) {
+ if (ci == null) {
+ Log.d(TAG, "Failing single scan request ClientInfo not found " + handler);
+ return false;
+ }
+ if (settings.reportEvents == 0) {
+ settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
+ }
+ if (settings.periodInMs == 0) {
+ settings.periodInMs = 10000; // 10s - although second scan should never happen
+ }
+
+ logScanRequest("addSingleScanRequest", ci, handler, settings);
+ ci.addScanRequest(settings, handler);
+ if (resetBuckets()) {
+ /* reset periodInMs to 0 to indicate single shot scan */
+ settings.periodInMs = 0;
+ return true;
+ } else {
+ ci.removeScanRequest(handler);
+ localLog("Failing scan request because failed to reset scan");
return false;
}
}
void removeScanRequest(ClientInfo ci, int handler) {
- ci.removeScanRequest(handler);
- resetBuckets();
+ if (ci != null) {
+ logScanRequest("removeScanRequest", ci, handler, null);
+ ci.removeScanRequest(handler);
+ resetBuckets();
+ }
}
- ScanResult[] getScanResults(ClientInfo ci) {
- ScanResult results[] = WifiNative.getScanResults();
- ci.reportScanResults(results);
- return results;
+ boolean reportScanResults() {
+ ScanData results[] = WifiNative.getScanResults(/* flush = */ true);
+ Collection<ClientInfo> clients = mClients.values();
+ for (ClientInfo ci2 : clients) {
+ ci2.reportScanResults(results);
+ }
+
+ return true;
}
void resetHotlist() {
@@ -1080,7 +1316,7 @@
if (num_hotlist_ap == 0) {
WifiNative.resetHotlist();
} else {
- WifiScanner.BssidInfo bssidInfos[] = new WifiScanner.BssidInfo[num_hotlist_ap];
+ BssidInfo bssidInfos[] = new BssidInfo[num_hotlist_ap];
int index = 0;
for (ClientInfo ci : clients) {
Collection<WifiScanner.HotlistSettings> settings = ci.getHotlistSettings();
@@ -1220,12 +1456,12 @@
class DefaultState extends State {
@Override
public void enter() {
- if (DBG) Log.d(TAG, "Entering IdleState");
+ if (DBG) localLog("Entering IdleState");
}
@Override
public boolean processMessage(Message msg) {
- if (DBG) Log.d(TAG, "DefaultState state got " + msg);
+ if (DBG) localLog("DefaultState state got " + msg);
switch (msg.what) {
case WIFI_CHANGE_CMD_ENABLE :
transitionTo(mMovingState);
@@ -1250,24 +1486,24 @@
class StationaryState extends State {
@Override
public void enter() {
- if (DBG) Log.d(TAG, "Entering StationaryState");
+ if (DBG) localLog("Entering StationaryState");
reportWifiStabilized(mCurrentBssids);
}
@Override
public boolean processMessage(Message msg) {
- if (DBG) Log.d(TAG, "Stationary state got " + msg);
+ if (DBG) localLog("Stationary state got " + msg);
switch (msg.what) {
case WIFI_CHANGE_CMD_ENABLE :
// do nothing
break;
case WIFI_CHANGE_CMD_CHANGE_DETECTED:
- if (DBG) Log.d(TAG, "Got wifi change detected");
+ if (DBG) localLog("Got wifi change detected");
reportWifiChanged((ScanResult[])msg.obj);
transitionTo(mMovingState);
break;
case WIFI_CHANGE_CMD_DISABLE:
- if (DBG) Log.d(TAG, "Got Disable Wifi Change");
+ if (DBG) localLog("Got Disable Wifi Change");
mCurrentBssids = null;
removeScanRequest();
untrackSignificantWifiChange();
@@ -1290,29 +1526,30 @@
@Override
public void enter() {
- if (DBG) Log.d(TAG, "Entering MovingState");
+ if (DBG) localLog("Entering MovingState");
issueFullScan();
}
@Override
public boolean processMessage(Message msg) {
- if (DBG) Log.d(TAG, "MovingState state got " + msg);
+ if (DBG) localLog("MovingState state got " + msg);
switch (msg.what) {
case WIFI_CHANGE_CMD_ENABLE :
// do nothing
break;
case WIFI_CHANGE_CMD_DISABLE:
- if (DBG) Log.d(TAG, "Got Disable Wifi Change");
+ if (DBG) localLog("Got Disable Wifi Change");
mCurrentBssids = null;
removeScanRequest();
untrackSignificantWifiChange();
transitionTo(mDefaultState);
break;
case WIFI_CHANGE_CMD_NEW_SCAN_RESULTS:
- if (DBG) Log.d(TAG, "Got scan results");
+ if (DBG) localLog("Got scan results");
if (mScanResultsPending) {
- if (DBG) Log.d(TAG, "reconfiguring scan");
- reconfigureScan((ScanResult[])msg.obj, STATIONARY_SCAN_PERIOD_MS);
+ if (DBG) localLog("reconfiguring scan");
+ reconfigureScan((ScanData[])msg.obj,
+ STATIONARY_SCAN_PERIOD_MS);
mWifiChangeDetected = false;
mAlarmManager.setExact(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + MOVING_STATE_TIMEOUT_MS,
@@ -1321,7 +1558,7 @@
}
break;
case WIFI_CHANGE_CMD_CONFIGURE:
- if (DBG) Log.d(TAG, "Got configuration from app");
+ if (DBG) localLog("Got configuration from app");
WifiScanner.WifiChangeSettings settings =
(WifiScanner.WifiChangeSettings) msg.obj;
reconfigureScan(settings);
@@ -1333,14 +1570,14 @@
mTimeoutIntent);
break;
case WIFI_CHANGE_CMD_CHANGE_DETECTED:
- if (DBG) Log.d(TAG, "Change detected");
+ if (DBG) localLog("Change detected");
mAlarmManager.cancel(mTimeoutIntent);
reportWifiChanged((ScanResult[])msg.obj);
mWifiChangeDetected = true;
issueFullScan();
break;
case WIFI_CHANGE_CMD_CHANGE_TIMEOUT:
- if (DBG) Log.d(TAG, "Got timeout event");
+ if (DBG) localLog("Got timeout event");
if (mWifiChangeDetected == false) {
transitionTo(mStationaryState);
}
@@ -1357,8 +1594,8 @@
}
void issueFullScan() {
- if (DBG) Log.d(TAG, "Issuing full scan");
- WifiScanner.ScanSettings settings = new WifiScanner.ScanSettings();
+ if (DBG) localLog("Issuing full scan");
+ ScanSettings settings = new ScanSettings();
settings.band = WifiScanner.WIFI_BAND_BOTH;
settings.periodInMs = MOVING_SCAN_PERIOD_MS;
settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
@@ -1368,10 +1605,10 @@
}
- void reconfigureScan(ScanResult[] results, int period) {
+ void reconfigureScan(ScanData[] results, int period) {
// find brightest APs and set them as sentinels
if (results.length < MAX_APS_TO_TRACK) {
- Log.d(TAG, "too few APs (" + results.length + ") available to track wifi change");
+ localLog("too few APs (" + results.length + ") available to track wifi change");
return;
}
@@ -1379,7 +1616,7 @@
// remove duplicate BSSIDs
HashMap<String, ScanResult> bssidToScanResult = new HashMap<String, ScanResult>();
- for (ScanResult result : results) {
+ for (ScanResult result : results[0].getResults()) {
ScanResult saved = bssidToScanResult.get(result.BSSID);
if (saved == null) {
bssidToScanResult.put(result.BSSID, result);
@@ -1418,14 +1655,14 @@
}
}
- if (DBG) Log.d(TAG, "Found " + channels.size() + " channels");
+ if (DBG) localLog("Found " + channels.size() + " channels");
// set scanning schedule
- WifiScanner.ScanSettings settings = new WifiScanner.ScanSettings();
+ ScanSettings settings = new ScanSettings();
settings.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
- settings.channels = new WifiScanner.ChannelSpec[channels.size()];
+ settings.channels = new ChannelSpec[channels.size()];
for (int i = 0; i < channels.size(); i++) {
- settings.channels[i] = new WifiScanner.ChannelSpec(channels.get(i));
+ settings.channels[i] = new ChannelSpec(channels.get(i));
}
settings.periodInMs = period;
@@ -1436,17 +1673,17 @@
settings2.lostApSampleSize = 3;
settings2.unchangedSampleSize = 3;
settings2.minApsBreachingThreshold = 2;
- settings2.bssidInfos = new WifiScanner.BssidInfo[brightest.length];
+ settings2.bssidInfos = new BssidInfo[brightest.length];
for (int i = 0; i < brightest.length; i++) {
- WifiScanner.BssidInfo BssidInfo = new WifiScanner.BssidInfo();
+ BssidInfo BssidInfo = new BssidInfo();
BssidInfo.bssid = brightest[i].BSSID;
int threshold = (100 + brightest[i].level) / 32 + 2;
BssidInfo.low = brightest[i].level - threshold;
BssidInfo.high = brightest[i].level + threshold;
settings2.bssidInfos[i] = BssidInfo;
- if (DBG) Log.d(TAG, "Setting bssid=" + BssidInfo.bssid + ", " +
+ if (DBG) localLog("Setting bssid=" + BssidInfo.bssid + ", " +
"low=" + BssidInfo.low + ", high=" + BssidInfo.high);
}
@@ -1457,12 +1694,12 @@
void reconfigureScan(WifiScanner.WifiChangeSettings settings) {
if (settings.bssidInfos.length < MAX_APS_TO_TRACK) {
- Log.d(TAG, "too few APs (" + settings.bssidInfos.length
+ localLog("too few APs (" + settings.bssidInfos.length
+ ") available to track wifi change");
return;
}
- if (DBG) Log.d(TAG, "Setting configuration specified by app");
+ if (DBG) localLog("Setting configuration specified by app");
mCurrentBssids = new ScanResult[settings.bssidInfos.length];
HashSet<Integer> channels = new HashSet<Integer>();
@@ -1478,12 +1715,12 @@
removeScanRequest();
// set new scanning schedule
- WifiScanner.ScanSettings settings2 = new WifiScanner.ScanSettings();
+ ScanSettings settings2 = new ScanSettings();
settings2.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
- settings2.channels = new WifiScanner.ChannelSpec[channels.size()];
+ settings2.channels = new ChannelSpec[channels.size()];
int i = 0;
for (Integer channel : channels) {
- settings2.channels[i++] = new WifiScanner.ChannelSpec(channel);
+ settings2.channels[i++] = new ChannelSpec(channel);
}
settings2.periodInMs = settings.periodInMs;
@@ -1495,11 +1732,11 @@
class ClientInfoLocal extends ClientInfo {
ClientInfoLocal() {
- super(null, null);
+ super(0, null, null);
}
@Override
- void deliverScanResults(int handler, ScanResult results[]) {
- if (DBG) Log.d(TAG, "Delivering messages directly");
+ void deliverScanResults(int handler, ScanData results[]) {
+ if (DBG) localLog("Delivering messages directly");
sendMessage(WIFI_CHANGE_CMD_NEW_SCAN_RESULTS, 0, 0, results);
}
@Override
@@ -1516,8 +1753,8 @@
ClientInfo mClientInfo = new ClientInfoLocal();
private static final int SCAN_COMMAND_ID = 1;
- void addScanRequest(WifiScanner.ScanSettings settings) {
- if (DBG) Log.d(TAG, "Starting scans");
+ void addScanRequest(ScanSettings settings) {
+ if (DBG) localLog("Starting scans");
Message msg = Message.obtain();
msg.what = WifiScanner.CMD_START_BACKGROUND_SCAN;
msg.arg2 = SCAN_COMMAND_ID;
@@ -1526,7 +1763,7 @@
}
void removeScanRequest() {
- if (DBG) Log.d(TAG, "Stopping scans");
+ if (DBG) localLog("Stopping scans");
Message msg = Message.obtain();
msg.what = WifiScanner.CMD_STOP_BACKGROUND_SCAN;
msg.arg2 = SCAN_COMMAND_ID;
@@ -1544,44 +1781,156 @@
}
- private static WifiScanner.ChannelSpec[] getChannelsForBand(int band) {
- int channels[] = WifiNative.getChannelsForBand(band);
- if (channels != null) {
- WifiScanner.ChannelSpec channelSpecs[] = new WifiScanner.ChannelSpec[channels.length];
- for (int i = 0; i < channels.length; i++) {
- channelSpecs[i] = new WifiScanner.ChannelSpec(channels[i]);
- }
- return channelSpecs;
- } else {
- return new WifiScanner.ChannelSpec[0];
+ private static ChannelSpec mChannels[][];
+
+ private static void copyChannels(
+ ChannelSpec channelSpec[], int offset, int channels[]) {
+ for (int i = 0; i < channels.length; i++) {
+ channelSpec[offset +i] = new ChannelSpec(channels[i]);
}
}
- private static int getBandFromChannels(WifiScanner.ChannelSpec[] channels) {
+ private static boolean initChannels() {
+ if (mChannels != null) {
+ /* already initialized */
+ return true;
+ }
+
+ int channels24[] = WifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ);
+ if (channels24 == null) {
+ loge("Could not get channels for 2.4 GHz");
+ return false;
+ }
+
+ int channels5[] = WifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ);
+ if (channels5 == null) {
+ loge("Could not get channels for 5 GHz");
+ return false;
+ }
+
+ int channelsDfs[] = WifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY);
+ if (channelsDfs == null) {
+ loge("Could not get channels for DFS");
+ return false;
+ }
+
+ mChannels = new ChannelSpec[8][];
+
+ mChannels[0] = new ChannelSpec[0];
+
+ mChannels[1] = new ChannelSpec[channels24.length];
+ copyChannels(mChannels[1], 0, channels24);
+
+ mChannels[2] = new ChannelSpec[channels5.length];
+ copyChannels(mChannels[2], 0, channels5);
+
+ mChannels[3] = new ChannelSpec[channels24.length + channels5.length];
+ copyChannels(mChannels[3], 0, channels24);
+ copyChannels(mChannels[3], channels24.length, channels5);
+
+ mChannels[4] = new ChannelSpec[channelsDfs.length];
+ copyChannels(mChannels[4], 0, channelsDfs);
+
+ mChannels[5] = new ChannelSpec[channels24.length + channelsDfs.length];
+ copyChannels(mChannels[5], 0, channels24);
+ copyChannels(mChannels[5], channels24.length, channelsDfs);
+
+ mChannels[6] = new ChannelSpec[channels5.length + channelsDfs.length];
+ copyChannels(mChannels[6], 0, channels5);
+ copyChannels(mChannels[6], channels5.length, channelsDfs);
+
+ mChannels[7] = new ChannelSpec[
+ channels24.length + channels5.length + channelsDfs.length];
+ copyChannels(mChannels[7], 0, channels24);
+ copyChannels(mChannels[7], channels24.length, channels5);
+ copyChannels(mChannels[7], channels24.length + channels5.length, channelsDfs);
+
+ return true;
+ }
+
+ private static ChannelSpec[] getChannelsForBand(int band) {
+ initChannels();
+
+ if (band < WifiScanner.WIFI_BAND_24_GHZ || band > WifiScanner.WIFI_BAND_BOTH_WITH_DFS)
+ /* invalid value for band */
+ return mChannels[0];
+ else
+ return mChannels[band];
+ }
+
+ private static boolean isDfs(int channel) {
+ ChannelSpec[] dfsChannels = getChannelsForBand(WifiScanner
+ .WIFI_BAND_5_GHZ_DFS_ONLY);
+ for (int i = 0; i < dfsChannels.length; i++) {
+ if (channel == dfsChannels[i].frequency) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static int getBandFromChannels(ChannelSpec[] channels) {
int band = WifiScanner.WIFI_BAND_UNSPECIFIED;
- for (WifiScanner.ChannelSpec channel : channels) {
+ for (ChannelSpec channel : channels) {
if (2400 <= channel.frequency && channel.frequency < 2500) {
band |= WifiScanner.WIFI_BAND_24_GHZ;
+ } else if ( isDfs(channel.frequency)) {
+ band |= WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY;
} else if (5100 <= channel.frequency && channel.frequency < 6000) {
band |= WifiScanner.WIFI_BAND_5_GHZ;
- } else {
- /* TODO: Add DFS Range */
}
}
return band;
}
+
private static int getBandFromChannels(WifiNative.ChannelSettings[] channels) {
int band = WifiScanner.WIFI_BAND_UNSPECIFIED;
for (WifiNative.ChannelSettings channel : channels) {
- if (2400 <= channel.frequency && channel.frequency < 2500) {
- band |= WifiScanner.WIFI_BAND_24_GHZ;
- } else if (5100 <= channel.frequency && channel.frequency < 6000) {
- band |= WifiScanner.WIFI_BAND_5_GHZ;
- } else {
- /* TODO: Add DFS Range */
+ if (channel != null) {
+ if (2400 <= channel.frequency && channel.frequency < 2500) {
+ band |= WifiScanner.WIFI_BAND_24_GHZ;
+ } else if ( isDfs(channel.frequency)) {
+ band |= WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY;
+ } else if (5100 <= channel.frequency && channel.frequency < 6000) {
+ band |= WifiScanner.WIFI_BAND_5_GHZ;
+ }
}
}
return band;
}
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump WifiScanner from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " without permission "
+ + android.Manifest.permission.DUMP);
+ return;
+ }
+ mStateMachine.dump(fd, pw, args);
+ }
+
+ static String describe(ScanSettings scanSettings) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(" band:").append(scanSettings.band);
+ sb.append(" period:").append(scanSettings.periodInMs);
+ sb.append(" reportEvents:").append(scanSettings.reportEvents);
+ sb.append(" numBssidsPerScan:").append(scanSettings.numBssidsPerScan);
+ sb.append(" maxScansToCache:").append(scanSettings.maxScansToCache).append("\n");
+
+ sb.append(" channels: ");
+
+ if (scanSettings.channels != null) {
+ for (int i = 0; i < scanSettings.channels.length; i++) {
+ sb.append(scanSettings.channels[i].frequency);
+ sb.append(" ");
+ }
+ }
+ sb.append("\n");
+ return sb.toString();
+ }
+
}
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index cc5824e..46058ad 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -30,45 +30,71 @@
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.DhcpResults;
-import android.net.IpConfiguration.ProxySettings;
-import android.net.LinkAddress;
+import android.net.Network;
+import android.net.NetworkScorerAppManager;
import android.net.NetworkUtils;
-import android.net.RouteInfo;
-import android.net.wifi.*;
+import android.net.Uri;
+import android.net.wifi.BatchedScanResult;
+import android.net.wifi.BatchedScanSettings;
import android.net.wifi.IWifiManager;
+import android.net.wifi.ScanResult;
+import android.net.wifi.ScanSettings;
+import android.net.wifi.WifiActivityEnergyInfo;
+import android.net.wifi.WifiChannel;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConnectionStatistics;
+import android.net.wifi.WifiEnterpriseConfig;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiLinkLayerStats;
+import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Binder;
+import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
+import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
-import java.io.FileNotFoundException;
-import java.io.BufferedReader;
-import java.io.FileDescriptor;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.lang.Override;
-import java.net.InetAddress;
-import java.net.Inet4Address;
-import java.util.ArrayList;
-import java.util.List;
-
import com.android.internal.R;
import com.android.internal.app.IBatteryStats;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.AsyncChannel;
import com.android.server.am.BatteryStatsService;
+import com.android.server.wifi.configparse.ConfigBuilder;
+
+import org.xml.sax.SAXException;
+
+import java.io.BufferedReader;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidator;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.PKIXParameters;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import static com.android.server.wifi.WifiController.CMD_AIRPLANE_TOGGLED;
import static com.android.server.wifi.WifiController.CMD_BATTERY_CHANGED;
@@ -89,6 +115,7 @@
public final class WifiServiceImpl extends IWifiManager.Stub {
private static final String TAG = "WifiService";
private static final boolean DBG = true;
+ private static final boolean VDBG = false;
final WifiStateMachine mWifiStateMachine;
@@ -109,7 +136,9 @@
private int mMulticastDisabled;
private final IBatteryStats mBatteryStats;
+ private final PowerManager mPowerManager;
private final AppOpsManager mAppOps;
+ private final UserManager mUserManager;
private String mInterfaceName;
@@ -123,8 +152,6 @@
/* Tracks the persisted states for wi-fi & airplane mode */
final WifiSettingsStore mSettingsStore;
- final boolean mBatchedScanSupported;
-
/**
* Asynchronous channel to WifiStateMachine
*/
@@ -173,31 +200,21 @@
WifiConfiguration config = (WifiConfiguration) msg.obj;
int networkId = msg.arg1;
if (msg.what == WifiManager.SAVE_NETWORK) {
- if (config != null) {
- if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
- config.creatorUid = Binder.getCallingUid();
- } else {
- config.lastUpdateUid = Binder.getCallingUid();
- }
- }
Slog.e("WiFiServiceImpl ", "SAVE"
+ " nid=" + Integer.toString(networkId)
- + " uid=" + Integer.toString(config.creatorUid)
- + "/" + Integer.toString(config.lastUpdateUid));
+ + " uid=" + msg.sendingUid
+ + " name="
+ + mContext.getPackageManager().getNameForUid(msg.sendingUid));
}
if (msg.what == WifiManager.CONNECT_NETWORK) {
- if (config != null) {
- if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
- config.creatorUid = Binder.getCallingUid();
- } else {
- config.lastUpdateUid = Binder.getCallingUid();
- }
- }
Slog.e("WiFiServiceImpl ", "CONNECT "
+ " nid=" + Integer.toString(networkId)
- + " uid=" + Binder.getCallingUid());
+ + " uid=" + msg.sendingUid
+ + " name="
+ + mContext.getPackageManager().getNameForUid(msg.sendingUid));
}
- if (config != null && config.isValid()) {
+
+ if (config != null && isValid(config)) {
if (DBG) Slog.d(TAG, "Connect with config" + config);
mWifiStateMachine.sendMessage(Message.obtain(msg));
} else if (config == null
@@ -306,7 +323,9 @@
mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName, mTrafficPoller);
mWifiStateMachine.enableRssiPolling(true);
mBatteryStats = BatteryStatsService.getService();
+ mPowerManager = context.getSystemService(PowerManager.class);
mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
+ mUserManager = UserManager.get(mContext);
mNotificationController = new WifiNotificationController(mContext, mWifiStateMachine);
mSettingsStore = new WifiSettingsStore(mContext);
@@ -316,9 +335,6 @@
mClientHandler = new ClientHandler(wifiThread.getLooper());
mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
mWifiController = new WifiController(mContext, this, wifiThread.getLooper());
-
- mBatchedScanSupported = mContext.getResources().getBoolean(
- R.bool.config_wifi_batched_scan_supported);
}
@@ -350,6 +366,8 @@
// can result in race conditions when apps toggle wifi in the background
// without active user involvement. Always receive broadcasts.
registerForBroadcasts();
+ registerForPackageOrUserRemoval();
+ mInIdleMode = mPowerManager.isDeviceIdleMode();
mWifiController.start();
@@ -390,6 +408,7 @@
// Start a location scan.
// L release: A location scan is implemented as a normal scan and avoids scanning DFS channels
+ // Deprecated: Will soon remove implementation
public void startLocationRestrictedScan(WorkSource workSource) {
enforceChangePermission();
enforceLocationHardwarePermission();
@@ -421,6 +440,23 @@
*/
public void startScan(ScanSettings settings, WorkSource workSource) {
enforceChangePermission();
+ synchronized (this) {
+ if (mInIdleMode) {
+ // Need to send an immediate scan result broadcast in case the
+ // caller is waiting for a result ..
+
+ // clear calling identity to send broadcast
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ mWifiStateMachine.sendScanResultsAvailableBroadcast(/* scanSucceeded = */ false);
+ } finally {
+ // restore calling identity
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ mScanPending = true;
+ return;
+ }
+ }
if (settings != null) {
settings = new ScanSettings(settings);
if (!settings.isValid()) {
@@ -438,42 +474,11 @@
settings, workSource);
}
- private class BatchedScanRequest extends DeathRecipient {
- final BatchedScanSettings settings;
- final int uid;
- final int pid;
- final WorkSource workSource;
-
- BatchedScanRequest(BatchedScanSettings settings, IBinder binder, WorkSource ws) {
- super(0, null, binder, null);
- this.settings = settings;
- this.uid = getCallingUid();
- this.pid = getCallingPid();
- workSource = ws;
- }
- public void binderDied() {
- stopBatchedScan(settings, uid, pid);
- }
- public String toString() {
- return "BatchedScanRequest{settings=" + settings + ", binder=" + mBinder + "}";
- }
-
- public boolean isSameApp(int uid, int pid) {
- return (this.uid == uid && this.pid == pid);
- }
- }
-
- private final List<BatchedScanRequest> mBatchedScanners = new ArrayList<BatchedScanRequest>();
-
public boolean isBatchedScanSupported() {
- return mBatchedScanSupported;
+ return false;
}
- public void pollBatchedScan() {
- enforceChangePermission();
- if (mBatchedScanSupported == false) return;
- mWifiStateMachine.requestBatchedScanPoll();
- }
+ public void pollBatchedScan() { }
public String getWpsNfcConfigurationToken(int netId) {
enforceConnectivityInternalPermission();
@@ -485,145 +490,36 @@
*/
public boolean requestBatchedScan(BatchedScanSettings requested, IBinder binder,
WorkSource workSource) {
- enforceChangePermission();
- if (workSource != null) {
- enforceWorkSourcePermission();
- // WifiManager currently doesn't use names, so need to clear names out of the
- // supplied WorkSource to allow future WorkSource combining.
- workSource.clearNames();
- }
- if (mBatchedScanSupported == false) return false;
- requested = new BatchedScanSettings(requested);
- if (requested.isInvalid()) return false;
- BatchedScanRequest r = new BatchedScanRequest(requested, binder, workSource);
- synchronized(mBatchedScanners) {
- mBatchedScanners.add(r);
- resolveBatchedScannersLocked();
- }
- return true;
+ return false;
}
public List<BatchedScanResult> getBatchedScanResults(String callingPackage) {
- enforceAccessPermission();
- if (mBatchedScanSupported == false) return new ArrayList<BatchedScanResult>();
- int uid = Binder.getCallingUid();
- int userId = UserHandle.getCallingUserId();
- boolean hasInteractUsersFull = checkInteractAcrossUsersFull();
- long ident = Binder.clearCallingIdentity();
- try {
- if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage)
- != AppOpsManager.MODE_ALLOWED) {
- return new ArrayList<BatchedScanResult>();
- }
- if (!isCurrentProfile(userId) && !hasInteractUsersFull) {
- return new ArrayList<BatchedScanResult>();
- }
- return mWifiStateMachine.syncGetBatchedScanResultsList();
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
+ return null;
}
- public void stopBatchedScan(BatchedScanSettings settings) {
- enforceChangePermission();
- if (mBatchedScanSupported == false) return;
- stopBatchedScan(settings, getCallingUid(), getCallingPid());
- }
+ public void stopBatchedScan(BatchedScanSettings settings) { }
- private void stopBatchedScan(BatchedScanSettings settings, int uid, int pid) {
- ArrayList<BatchedScanRequest> found = new ArrayList<BatchedScanRequest>();
- synchronized(mBatchedScanners) {
- for (BatchedScanRequest r : mBatchedScanners) {
- if (r.isSameApp(uid, pid) && (settings == null || settings.equals(r.settings))) {
- found.add(r);
- if (settings != null) break;
- }
- }
- for (BatchedScanRequest r : found) {
- mBatchedScanners.remove(r);
- }
- if (found.size() != 0) {
- resolveBatchedScannersLocked();
- }
- }
- }
+ boolean mInIdleMode;
+ boolean mScanPending;
- private void resolveBatchedScannersLocked() {
- BatchedScanSettings setting = new BatchedScanSettings();
- WorkSource responsibleWorkSource = null;
- int responsibleUid = 0;
- double responsibleCsph = 0; // Channel Scans Per Hour
-
- if (mBatchedScanners.size() == 0) {
- mWifiStateMachine.setBatchedScanSettings(null, 0, 0, null);
- return;
- }
- for (BatchedScanRequest r : mBatchedScanners) {
- BatchedScanSettings s = r.settings;
-
- // evaluate responsibility
- int currentChannelCount;
- int currentScanInterval;
- double currentCsph;
-
- if (s.channelSet == null || s.channelSet.isEmpty()) {
- // all channels - 11 B and 9 A channels roughly.
- currentChannelCount = 9 + 11;
- } else {
- currentChannelCount = s.channelSet.size();
- // these are rough est - no real need to correct for reg-domain;
- if (s.channelSet.contains("A")) currentChannelCount += (9 - 1);
- if (s.channelSet.contains("B")) currentChannelCount += (11 - 1);
-
- }
- if (s.scanIntervalSec == BatchedScanSettings.UNSPECIFIED) {
- currentScanInterval = BatchedScanSettings.DEFAULT_INTERVAL_SEC;
- } else {
- currentScanInterval = s.scanIntervalSec;
- }
- currentCsph = 60 * 60 * currentChannelCount / currentScanInterval;
-
- if (currentCsph > responsibleCsph) {
- responsibleUid = r.uid;
- responsibleWorkSource = r.workSource;
- responsibleCsph = currentCsph;
- }
-
- if (s.maxScansPerBatch != BatchedScanSettings.UNSPECIFIED &&
- s.maxScansPerBatch < setting.maxScansPerBatch) {
- setting.maxScansPerBatch = s.maxScansPerBatch;
- }
- if (s.maxApPerScan != BatchedScanSettings.UNSPECIFIED &&
- (setting.maxApPerScan == BatchedScanSettings.UNSPECIFIED ||
- s.maxApPerScan > setting.maxApPerScan)) {
- setting.maxApPerScan = s.maxApPerScan;
- }
- if (s.scanIntervalSec != BatchedScanSettings.UNSPECIFIED &&
- s.scanIntervalSec < setting.scanIntervalSec) {
- setting.scanIntervalSec = s.scanIntervalSec;
- }
- if (s.maxApForDistance != BatchedScanSettings.UNSPECIFIED &&
- (setting.maxApForDistance == BatchedScanSettings.UNSPECIFIED ||
- s.maxApForDistance > setting.maxApForDistance)) {
- setting.maxApForDistance = s.maxApForDistance;
- }
- if (s.channelSet != null && s.channelSet.size() != 0) {
- if (setting.channelSet == null || setting.channelSet.size() != 0) {
- if (setting.channelSet == null) setting.channelSet = new ArrayList<String>();
- for (String i : s.channelSet) {
- if (setting.channelSet.contains(i) == false) setting.channelSet.add(i);
+ void handleIdleModeChanged() {
+ boolean doScan = false;
+ synchronized (this) {
+ boolean idle = mPowerManager.isDeviceIdleMode();
+ if (mInIdleMode != idle) {
+ mInIdleMode = idle;
+ if (!idle) {
+ if (mScanPending) {
+ mScanPending = false;
+ doScan = true;
}
- } // else, ignore the constraint - we already use all channels
- } else {
- if (setting.channelSet == null || setting.channelSet.size() != 0) {
- setting.channelSet = new ArrayList<String>();
}
}
}
-
- setting.constrain();
- mWifiStateMachine.setBatchedScanSettings(setting, responsibleUid, (int)responsibleCsph,
- responsibleWorkSource);
+ if (doScan) {
+ // Someone requested a scan while we were idle; do a full scan now.
+ startScan(null, null);
+ }
}
private void enforceAccessPermission() {
@@ -633,7 +529,7 @@
private void enforceChangePermission() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
- "WifiService");
+ "WifiService");
}
private void enforceLocationHardwarePermission() {
@@ -719,12 +615,11 @@
public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
enforceChangePermission();
ConnectivityManager.enforceTetherChangePermission(mContext);
- UserManager um = UserManager.get(mContext);
- if (um.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
+ if (mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
throw new SecurityException("DISALLOW_CONFIG_TETHERING is enabled for this user.");
}
// null wifiConfig is a meaningful input for CMD_SET_AP
- if (wifiConfig == null || wifiConfig.isValid()) {
+ if (wifiConfig == null || isValid(wifiConfig)) {
mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget();
} else {
Slog.e(TAG, "Invalid WifiConfiguration");
@@ -754,6 +649,25 @@
}
/**
+ * see {@link WifiManager#buildWifiConfig()}
+ * @return a WifiConfiguration.
+ */
+ public WifiConfiguration buildWifiConfig(String uriString, String mimeType, byte[] data) {
+ if (mimeType.equals(ConfigBuilder.WifiConfigType)) {
+ try {
+ return ConfigBuilder.buildConfig(uriString, data, mContext);
+ }
+ catch (IOException | GeneralSecurityException | SAXException e) {
+ Log.e(TAG, "Failed to parse wi-fi configuration: " + e);
+ }
+ }
+ else {
+ Log.i(TAG, "Unknown wi-fi config type: " + mimeType);
+ }
+ return null;
+ }
+
+ /**
* see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
* @param wifiConfig WifiConfiguration details for soft access point
*/
@@ -761,7 +675,7 @@
enforceChangePermission();
if (wifiConfig == null)
return;
- if (wifiConfig.isValid()) {
+ if (isValid(wifiConfig)) {
mWifiStateMachine.setWifiApConfiguration(wifiConfig);
} else {
Slog.e(TAG, "Invalid WifiConfiguration");
@@ -816,7 +730,7 @@
}
/**
- * see {@link android.net.wifi.WifiAdapter#reportActivityInfo}
+ * see {@link android.net.wifi.WifiManager#getControllerActivityEnergyInfo(int)}
*/
public WifiActivityEnergyInfo reportActivityInfo() {
enforceAccessPermission();
@@ -825,11 +739,39 @@
if (mWifiStateMachineChannel != null) {
stats = mWifiStateMachine.syncGetLinkLayerStats(mWifiStateMachineChannel);
if (stats != null) {
+ final long rxIdleCurrent = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_wifi_idle_receive_cur_ma);
+ final long rxCurrent = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_wifi_active_rx_cur_ma);
+ final long txCurrent = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_wifi_tx_cur_ma);
+ final double voltage = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_wifi_operating_voltage_mv)
+ / 1000.0;
+
+ final long rxIdleTime = stats.on_time - stats.tx_time - stats.rx_time;
+ final long energyUsed = (long)((stats.tx_time * txCurrent +
+ stats.rx_time * rxCurrent +
+ rxIdleTime * rxIdleCurrent) * voltage);
+ if (VDBG || rxIdleTime < 0 || stats.on_time < 0 || stats.tx_time < 0 ||
+ stats.rx_time < 0 || energyUsed < 0) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(" rxIdleCur=" + rxIdleCurrent);
+ sb.append(" rxCur=" + rxCurrent);
+ sb.append(" txCur=" + txCurrent);
+ sb.append(" voltage=" + voltage);
+ sb.append(" on_time=" + stats.on_time);
+ sb.append(" tx_time=" + stats.tx_time);
+ sb.append(" rx_time=" + stats.rx_time);
+ sb.append(" rxIdleTime=" + rxIdleTime);
+ sb.append(" energy=" + energyUsed);
+ Log.e(TAG, " reportActivityInfo: " + sb.toString());
+ }
+
// Convert the LinkLayerStats into EnergyActivity
- energyInfo = new WifiActivityEnergyInfo(
+ energyInfo = new WifiActivityEnergyInfo(SystemClock.elapsedRealtime(),
WifiActivityEnergyInfo.STACK_STATE_STATE_IDLE, stats.tx_time,
- stats.rx_time, stats.on_time - stats.tx_time - stats.rx_time,
- 0 /* TBD */);
+ stats.rx_time, rxIdleTime, energyUsed);
}
return energyInfo;
} else {
@@ -869,15 +811,47 @@
}
/**
+ * Returns a WifiConfiguration matching this ScanResult
+ * @param scanResult scanResult that represents the BSSID
+ * @return {@link WifiConfiguration} that matches this BSSID or null
+ */
+ public WifiConfiguration getMatchingWifiConfig(ScanResult scanResult) {
+ enforceAccessPermission();
+ return mWifiStateMachine.syncGetMatchingWifiConfig(scanResult, mWifiStateMachineChannel);
+ }
+
+
+ /**
* see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
* @return the supplicant-assigned identifier for the new or updated
* network if the operation succeeds, or {@code -1} if it fails
*/
public int addOrUpdateNetwork(WifiConfiguration config) {
enforceChangePermission();
- if (config.isValid()) {
+ if (isValid(config) && isValidPasspoint(config)) {
+
+ WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
+
+ if (config.isPasspoint() &&
+ (enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TLS ||
+ enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TTLS)) {
+ try {
+ verifyCert(enterpriseConfig.getCaCertificate());
+ } catch (CertPathValidatorException cpve) {
+ Slog.e(TAG, "CA Cert " +
+ enterpriseConfig.getCaCertificate().getSubjectX500Principal() +
+ " untrusted: " + cpve.getMessage());
+ return -1;
+ } catch (GeneralSecurityException | IOException e) {
+ Slog.e(TAG, "Failed to verify certificate" +
+ enterpriseConfig.getCaCertificate().getSubjectX500Principal() +
+ ": " + e);
+ return -1;
+ }
+ }
+
//TODO: pass the Uid the WifiStateMachine as a message parameter
- Slog.e("addOrUpdateNetwork", " uid = " + Integer.toString(Binder.getCallingUid())
+ Slog.i("addOrUpdateNetwork", " uid = " + Integer.toString(Binder.getCallingUid())
+ " SSID " + config.SSID
+ " nid=" + Integer.toString(config.networkId));
if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
@@ -897,7 +871,21 @@
}
}
- /**
+ public static void verifyCert(X509Certificate caCert)
+ throws GeneralSecurityException, IOException {
+ CertificateFactory factory = CertificateFactory.getInstance("X.509");
+ CertPathValidator validator =
+ CertPathValidator.getInstance(CertPathValidator.getDefaultType());
+ CertPath path = factory.generateCertPath(
+ Arrays.asList(caCert));
+ KeyStore ks = KeyStore.getInstance("AndroidCAStore");
+ ks.load(null, null);
+ PKIXParameters params = new PKIXParameters(ks);
+ params.setRevocationEnabled(false);
+ validator.validate(path, params);
+ }
+
+ /**
* See {@link android.net.wifi.WifiManager#removeNetwork(int)}
* @param netId the integer that identifies the network configuration
* to the supplicant
@@ -975,9 +963,20 @@
enforceAccessPermission();
int userId = UserHandle.getCallingUserId();
int uid = Binder.getCallingUid();
+ boolean canReadPeerMacAddresses = checkPeersMacAddress();
+ boolean isActiveNetworkScorer =
+ NetworkScorerAppManager.isCallerActiveScorer(mContext, uid);
boolean hasInteractUsersFull = checkInteractAcrossUsersFull();
long ident = Binder.clearCallingIdentity();
try {
+ if (!canReadPeerMacAddresses && !isActiveNetworkScorer
+ && !isLocationEnabled()) {
+ return new ArrayList<ScanResult>();
+ }
+ if (!canReadPeerMacAddresses && !isActiveNetworkScorer
+ && !checkCallerCanAccessScanResults(callingPackage, uid)) {
+ return new ArrayList<ScanResult>();
+ }
if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage)
!= AppOpsManager.MODE_ALLOWED) {
return new ArrayList<ScanResult>();
@@ -991,6 +990,11 @@
}
}
+ private boolean isLocationEnabled() {
+ return Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.LOCATION_MODE,
+ Settings.Secure.LOCATION_MODE_OFF) != Settings.Secure.LOCATION_MODE_OFF;
+ }
+
/**
* Returns true if the caller holds INTERACT_ACROSS_USERS_FULL.
*/
@@ -1001,6 +1005,14 @@
}
/**
+ * Returns true if the caller holds PEERS_MAC_ADDRESS.
+ */
+ private boolean checkPeersMacAddress() {
+ return mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.PEERS_MAC_ADDRESS) == PackageManager.PERMISSION_GRANTED;
+ }
+
+ /**
* Returns true if the calling user is the current one or a profile of the
* current user..
*/
@@ -1009,7 +1021,7 @@
if (userId == currentUser) {
return true;
}
- List<UserInfo> profiles = UserManager.get(mContext).getProfiles(currentUser);
+ List<UserInfo> profiles = mUserManager.getProfiles(currentUser);
for (UserInfo user : profiles) {
if (userId == user.id) {
return true;
@@ -1031,7 +1043,7 @@
if (userId == ownerUser) {
return true;
}
- List<UserInfo> profiles = UserManager.get(mContext).getProfiles(ownerUser);
+ List<UserInfo> profiles = mUserManager.getProfiles(ownerUser);
for (UserInfo profile : profiles) {
if (userId == profile.id) {
return true;
@@ -1083,6 +1095,15 @@
}
}
+ /**
+ * Get the country code
+ * @return ISO 3166 country code.
+ */
+ public String getCountryCode() {
+ enforceConnectivityInternalPermission();
+ String country = mWifiStateMachine.getCountryCode();
+ return country;
+ }
/**
* Set the operational frequency band
* @param band One of
@@ -1350,6 +1371,8 @@
} else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false);
mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0);
+ } else if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
+ handleIdleModeChanged();
}
}
};
@@ -1380,9 +1403,41 @@
intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
+ intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
mContext.registerReceiver(mReceiver, intentFilter);
}
+ private void registerForPackageOrUserRemoval() {
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ intentFilter.addAction(Intent.ACTION_USER_REMOVED);
+ mContext.registerReceiverAsUser(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ switch (intent.getAction()) {
+ case Intent.ACTION_PACKAGE_REMOVED: {
+ if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ return;
+ }
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ Uri uri = intent.getData();
+ if (uid == -1 || uri == null) {
+ return;
+ }
+ String pkgName = uri.getSchemeSpecificPart();
+ mWifiStateMachine.removeAppConfigs(pkgName, uid);
+ break;
+ }
+ case Intent.ACTION_USER_REMOVED: {
+ int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+ mWifiStateMachine.removeUserConfigs(userHandle);
+ break;
+ }
+ }
+ }
+ }, UserHandle.ALL, intentFilter, null, null);
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -1398,6 +1453,8 @@
Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
pw.println("mMulticastEnabled " + mMulticastEnabled);
pw.println("mMulticastDisabled " + mMulticastDisabled);
+ pw.println("mInIdleMode " + mInIdleMode);
+ pw.println("mScanPending " + mScanPending);
mWifiController.dump(fd, pw, args);
mSettingsStore.dump(fd, pw, args);
mNotificationController.dump(fd, pw, args);
@@ -1439,6 +1496,12 @@
pw.println("Locks held:");
mLocks.dump(pw);
+ pw.println("Multicast Locks held:");
+ for (Multicaster l : mMulticasters) {
+ pw.print(" ");
+ pw.println(l);
+ }
+
mWifiWatchdogStateMachine.dump(fd, pw, args);
pw.println();
mWifiStateMachine.dump(fd, pw, args);
@@ -1840,6 +1903,25 @@
return mWifiStateMachine.getAllowScansWithTraffic();
}
+ public boolean enableAutoJoinWhenAssociated(boolean enabled) {
+ enforceChangePermission();
+ return mWifiStateMachine.enableAutoJoinWhenAssociated(enabled);
+ }
+
+ public boolean getEnableAutoJoinWhenAssociated() {
+ enforceAccessPermission();
+ return mWifiStateMachine.getEnableAutoJoinWhenAssociated();
+ }
+ public void setHalBasedAutojoinOffload(int enabled) {
+ enforceChangePermission();
+ mWifiStateMachine.setHalBasedAutojoinOffload(enabled);
+ }
+
+ public int getHalBasedAutojoinOffload() {
+ enforceAccessPermission();
+ return mWifiStateMachine.getHalBasedAutojoinOffload();
+ }
+
/* Return the Wifi Connection statistics object */
public WifiConnectionStatistics getConnectionStatistics() {
enforceAccessPermission();
@@ -1851,4 +1933,162 @@
return null;
}
}
+
+ public void factoryReset() {
+ enforceConnectivityInternalPermission();
+
+ if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) {
+ return;
+ }
+
+ if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
+ // Turn mobile hotspot off
+ setWifiApEnabled(null, false);
+ }
+
+ if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI)) {
+ // Enable wifi
+ setWifiEnabled(true);
+ // Delete all Wifi SSIDs
+ List<WifiConfiguration> networks = getConfiguredNetworks();
+ if (networks != null) {
+ for (WifiConfiguration config : networks) {
+ removeNetwork(config.networkId);
+ }
+ saveConfiguration();
+ }
+ }
+ }
+
+ /* private methods */
+ static boolean logAndReturnFalse(String s) {
+ Log.d(TAG, s);
+ return false;
+ }
+
+ public static boolean isValid(WifiConfiguration config) {
+ String validity = checkValidity(config);
+ return validity == null || logAndReturnFalse(validity);
+ }
+
+ public static boolean isValidPasspoint(WifiConfiguration config) {
+ String validity = checkPasspointValidity(config);
+ return validity == null || logAndReturnFalse(validity);
+ }
+
+ public static String checkValidity(WifiConfiguration config) {
+ if (config.allowedKeyManagement == null)
+ return "allowed kmgmt";
+
+ if (config.allowedKeyManagement.cardinality() > 1) {
+ if (config.allowedKeyManagement.cardinality() != 2) {
+ return "cardinality != 2";
+ }
+ if (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP)) {
+ return "not WPA_EAP";
+ }
+ if ((!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X))
+ && (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK))) {
+ return "not PSK or 8021X";
+ }
+ }
+ return null;
+ }
+
+ public static String checkPasspointValidity(WifiConfiguration config) {
+ if (!TextUtils.isEmpty(config.FQDN)) {
+ /* this is passpoint configuration; it must not have an SSID */
+ if (!TextUtils.isEmpty(config.SSID)) {
+ return "SSID not expected for Passpoint: '" + config.SSID +
+ "' FQDN " + toHexString(config.FQDN);
+ }
+ /* this is passpoint configuration; it must have a providerFriendlyName */
+ if (TextUtils.isEmpty(config.providerFriendlyName)) {
+ return "no provider friendly name";
+ }
+ WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
+ /* this is passpoint configuration; it must have enterprise config */
+ if (enterpriseConfig == null
+ || enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.NONE ) {
+ return "no enterprise config";
+ }
+ if ((enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TLS ||
+ enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TTLS ||
+ enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.PEAP) &&
+ enterpriseConfig.getCaCertificate() == null) {
+ return "no CA certificate";
+ }
+ }
+ return null;
+ }
+
+ public Network getCurrentNetwork() {
+ enforceAccessPermission();
+ return mWifiStateMachine.getCurrentNetwork();
+ }
+
+ public static String toHexString(String s) {
+ if (s == null) {
+ return "null";
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append('\'').append(s).append('\'');
+ for (int n = 0; n < s.length(); n++) {
+ sb.append(String.format(" %02x", s.charAt(n) & 0xffff));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Checks that calling process has android.Manifest.permission.ACCESS_COARSE_LOCATION or
+ * android.Manifest.permission.ACCESS_FINE_LOCATION and a corresponding app op is allowed
+ */
+ private boolean checkCallerCanAccessScanResults(String callingPackage, int uid) {
+ if (ActivityManager.checkUidPermission(Manifest.permission.ACCESS_FINE_LOCATION, uid)
+ == PackageManager.PERMISSION_GRANTED
+ && isAppOppAllowed(AppOpsManager.OP_FINE_LOCATION, callingPackage, uid)) {
+ return true;
+ }
+
+ if (ActivityManager.checkUidPermission(Manifest.permission.ACCESS_COARSE_LOCATION, uid)
+ == PackageManager.PERMISSION_GRANTED
+ && isAppOppAllowed(AppOpsManager.OP_COARSE_LOCATION, callingPackage, uid)) {
+ return true;
+ }
+ // Enforce location permission for apps targeting M and later versions
+ boolean enforceLocationPermission = true;
+ try {
+ enforceLocationPermission = mContext.getPackageManager().getApplicationInfo(
+ callingPackage, 0).targetSdkVersion >= Build.VERSION_CODES.M;
+ } catch (PackageManager.NameNotFoundException e) {
+ // In case of exception, enforce permission anyway
+ }
+ if (enforceLocationPermission) {
+ throw new SecurityException("Need ACCESS_COARSE_LOCATION or "
+ + "ACCESS_FINE_LOCATION permission to get scan results");
+ }
+ // Pre-M apps running in the foreground should continue getting scan results
+ if (isForegroundApp(callingPackage)) {
+ return true;
+ }
+ Log.e(TAG, "Permission denial: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION "
+ + "permission to get scan results");
+ return false;
+ }
+
+ private boolean isAppOppAllowed(int op, String callingPackage, int uid) {
+ return mAppOps.noteOp(op, uid, callingPackage) == AppOpsManager.MODE_ALLOWED;
+ }
+
+ /**
+ * Return true if the specified package name is a foreground app.
+ *
+ * @param pkgName application package name.
+ */
+ private boolean isForegroundApp(String pkgName) {
+ ActivityManager am = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
+ List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
+ return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName());
+ }
+
}
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index eaa46f8..4bc62b3 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -31,6 +31,7 @@
*/
import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
+import android.Manifest;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.PendingIntent;
@@ -40,12 +41,18 @@
import android.content.Context;
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;
import android.net.DhcpResults;
+import android.net.BaseDhcpStateMachine;
import android.net.DhcpStateMachine;
+import android.net.Network;
+import android.net.dhcp.DhcpClient;
import android.net.InterfaceConfiguration;
+import android.net.IpReachabilityMonitor;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkAgent;
@@ -58,8 +65,6 @@
import android.net.RouteInfo;
import android.net.StaticIpConfiguration;
import android.net.TrafficStats;
-import android.net.wifi.BatchedScanResult;
-import android.net.wifi.BatchedScanSettings;
import android.net.wifi.RssiPacketCountInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.ScanSettings;
@@ -71,12 +76,14 @@
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiLinkLayerStats;
import android.net.wifi.WifiManager;
+import android.net.wifi.WifiScanner;
import android.net.wifi.WifiSsid;
import android.net.wifi.WpsInfo;
import android.net.wifi.WpsResult;
import android.net.wifi.WpsResult.Status;
import android.net.wifi.p2p.IWifiP2pManager;
import android.os.BatteryStats;
+import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.INetworkManagementService;
@@ -104,6 +111,9 @@
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.server.net.NetlinkTracker;
+import com.android.server.wifi.hotspot2.NetworkDetail;
+import com.android.server.wifi.hotspot2.SupplicantBridge;
+import com.android.server.wifi.hotspot2.Utils;
import com.android.server.wifi.p2p.WifiP2pServiceImpl;
import java.io.BufferedReader;
@@ -115,14 +125,15 @@
import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.ArrayList;
+import java.util.Calendar;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Queue;
+import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
@@ -136,14 +147,16 @@
*
* @hide
*/
-public class WifiStateMachine extends StateMachine {
+public class WifiStateMachine extends StateMachine implements WifiNative.WifiPnoEventHandler {
private static final String NETWORKTYPE = "WIFI";
private static final String NETWORKTYPE_UNTRUSTED = "WIFI_UT";
private static boolean DBG = false;
private static boolean VDBG = false;
private static boolean VVDBG = false;
+ private static boolean USE_PAUSE_SCANS = false;
private static boolean mLogMessages = false;
+ private static final String TAG = "WifiStateMachine";
private static final int ONE_HOUR_MILLI = 1000 * 60 * 60;
@@ -165,8 +178,11 @@
protected void loge(String s) {
Log.e(getName(), s);
}
+ protected void logd(String s) {
+ Log.d(getName(), s);
+ }
protected void log(String s) {;
- Log.e(getName(), s);
+ Log.d(getName(), s);
}
private WifiMonitor mWifiMonitor;
@@ -175,35 +191,29 @@
private WifiAutoJoinController mWifiAutoJoinController;
private INetworkManagementService mNwService;
private ConnectivityManager mCm;
-
+ private WifiLogger mWifiLogger;
+ private WifiApConfigStore mWifiApConfigStore;
private final boolean mP2pSupported;
private final AtomicBoolean mP2pConnected = new AtomicBoolean(false);
private boolean mTemporarilyDisconnectWifi = false;
private final String mPrimaryDeviceType;
/* Scan results handling */
- private List<ScanResult> mScanResults = new ArrayList<ScanResult>();
+ private List<ScanDetail> mScanResults = new ArrayList<>();
private static final Pattern scanResultPattern = Pattern.compile("\t+");
private static final int SCAN_RESULT_CACHE_SIZE = 160;
- private final LruCache<String, ScanResult> mScanResultCache;
+ private final LruCache<NetworkDetail, ScanDetail> mScanResultCache;
// For debug, number of known scan results that were found as part of last scan result event,
// as well the number of scans results returned by the supplicant with that message
private int mNumScanResultsKnown;
private int mNumScanResultsReturned;
- /* Batch scan results */
- private final List<BatchedScanResult> mBatchedScanResults =
- new ArrayList<BatchedScanResult>();
- private int mBatchedScanOwnerUid = UNKNOWN_SCAN_SOURCE;
- private int mExpectedBatchedScans = 0;
- private long mBatchedScanMinPollTime = 0;
-
private boolean mScreenOn = false;
/* Chipset supports background scan */
private final boolean mBackgroundScanSupported;
- private String mInterfaceName;
+ private final String mInterfaceName;
/* Tethering interface could be separate from wlan interface */
private String mTetherInterfaceName;
@@ -212,12 +222,66 @@
private int mLastNetworkId; // The network Id we successfully joined
private boolean linkDebouncing = false;
+ private boolean mHalBasedPnoDriverSupported = false;
+
+ // Below booleans are configurations coming from the Developper Settings
+ private boolean mEnableAssociatedNetworkSwitchingInDevSettings = true;
+ private boolean mHalBasedPnoEnableInDevSettings = false;
+
+
+ private int mHalFeatureSet = 0;
+ private static int mPnoResultFound = 0;
+
+ @Override
+ public void onPnoNetworkFound(ScanResult results[]) {
+ if (DBG) {
+ Log.e(TAG, "onPnoNetworkFound event received num = " + results.length);
+ for (int i = 0; i < results.length; i++) {
+ Log.e(TAG, results[i].toString());
+ }
+ }
+ sendMessage(CMD_PNO_NETWORK_FOUND, results.length, 0, results);
+ }
+
+ public void processPnoNetworkFound(ScanResult results[]) {
+ ScanSettings settings = new ScanSettings();
+ settings.channelSet = new ArrayList<WifiChannel>();
+ StringBuilder sb = new StringBuilder();
+ sb.append("");
+ for (int i=0; i<results.length; i++) {
+ WifiChannel channel = new WifiChannel();
+ channel.freqMHz = results[i].frequency;
+ settings.channelSet.add(channel);
+ sb.append(results[i].SSID).append(" ");
+ }
+
+ stopPnoOffload();
+
+ Log.e(TAG, "processPnoNetworkFound starting scan cnt=" + mPnoResultFound);
+ startScan(PNO_NETWORK_FOUND_SOURCE, mPnoResultFound, settings, null);
+ mPnoResultFound ++;
+ //sendMessage(CMD_SCAN_RESULTS_AVAILABLE);
+ int delay = 30 * 1000;
+ // reconfigure Pno after 1 minutes if we're still in disconnected state
+ sendMessageDelayed(CMD_RESTART_AUTOJOIN_OFFLOAD, delay,
+ mRestartAutoJoinOffloadCounter, " processPnoNetworkFound " + sb.toString(),
+ (long)delay);
+ mRestartAutoJoinOffloadCounter++;
+ }
+
+ public void registerNetworkDisabled(int netId) {
+ // Restart legacy PNO and autojoin offload if needed
+ sendMessage(CMD_RESTART_AUTOJOIN_OFFLOAD, 0,
+ mRestartAutoJoinOffloadCounter, " registerNetworkDisabled " + netId);
+ mRestartAutoJoinOffloadCounter++;
+ }
+
// Testing various network disconnect cases by sending lots of spurious
// disconnect to supplicant
private boolean testNetworkDisconnect = false;
private boolean mEnableRssiPolling = false;
- private boolean mEnableBackgroundScan = false;
+ private boolean mLegacyPnoEnabled = false;
private int mRssiPollToken = 0;
/* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE
* In CONNECT_MODE, the STA can scan and connect to an access point
@@ -237,15 +301,13 @@
private static final int SET_ALLOW_UNTRUSTED_SOURCE = -4;
private static final int ENABLE_WIFI = -5;
public static final int DFS_RESTRICTED_SCAN_REQUEST = -6;
+ public static final int PNO_NETWORK_FOUND_SOURCE = -7;
private static final int SCAN_REQUEST_BUFFER_MAX_SIZE = 10;
private static final String CUSTOMIZED_SCAN_SETTING = "customized_scan_settings";
private static final String CUSTOMIZED_SCAN_WORKSOURCE = "customized_scan_worksource";
private static final String SCAN_REQUEST_TIME = "scan_request_time";
- private static final String BATCHED_SETTING = "batched_settings";
- private static final String BATCHED_WORKSOURCE = "batched_worksource";
-
/* Tracks if state machine has received any screen state change broadcast yet.
* We can miss one of these at boot.
*/
@@ -298,6 +360,12 @@
private int mDriverStartToken = 0;
/**
+ * Don't select new network when previous network selection is
+ * pending connection for this much time
+ */
+ private static final int CONNECT_TIMEOUT_MSEC = 3000;
+
+ /**
* The link properties of the wifi interface.
* Do not modify this directly; use updateLinkProperties instead.
*/
@@ -313,11 +381,13 @@
private final Object mDhcpResultsLock = new Object();
private DhcpResults mDhcpResults;
+
+ // NOTE: Do not return to clients - use #getWiFiInfoForUid(int)
private WifiInfo mWifiInfo;
private NetworkInfo mNetworkInfo;
private NetworkCapabilities mNetworkCapabilities;
private SupplicantStateTracker mSupplicantStateTracker;
- private DhcpStateMachine mDhcpStateMachine;
+ private BaseDhcpStateMachine mDhcpStateMachine;
private boolean mDhcpActive = false;
private int mWifiLinkLayerStatsSupported = 4; // Temporary disable
@@ -346,6 +416,9 @@
// Used as debug to indicate which configuration last was removed
private WifiConfiguration lastForgetConfigurationAttempt = null;
+ //Random used by softAP channel Selection
+ private static Random mRandom = new Random(Calendar.getInstance().getTimeInMillis());
+
boolean isRoaming() {
return mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_ROAMING
|| mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_EXTENDED_ROAMING;
@@ -367,12 +440,11 @@
if (!mTargetRoamBSSID.equals("any") && bssid.equals("any")) {
// Changing to ANY
if (!mWifiConfigStore.roamOnAny) {
- ret = false; // Nothing to do
+ ret = false; // Nothing to do
}
}
if (VDBG) {
- loge("autoRoamSetBSSID " + bssid
- + " key=" + config.configKey());
+ logd("autoRoamSetBSSID " + bssid + " key=" + config.configKey());
}
config.autoJoinBSSID = bssid;
mTargetRoamBSSID = bssid;
@@ -381,17 +453,71 @@
}
/**
+ * Save the UID correctly depending on if this is a new or existing network.
+ * @return true if operation is authorized, false otherwise
+ */
+ boolean recordUidIfAuthorized(WifiConfiguration config, int uid, boolean onlyAnnotate) {
+ if (!mWifiConfigStore.isNetworkConfigured(config)) {
+ config.creatorUid = uid;
+ config.creatorName = mContext.getPackageManager().getNameForUid(uid);
+ } else if (!mWifiConfigStore.canModifyNetwork(uid, config, onlyAnnotate)) {
+ return false;
+ }
+
+ config.lastUpdateUid = uid;
+ config.lastUpdateName = mContext.getPackageManager().getNameForUid(uid);
+
+ return true;
+
+ }
+
+ /**
+ * Checks to see if user has specified if the apps configuration is connectable.
+ * If the user hasn't specified we query the user and return true.
+ *
+ * @param message The message to be deferred
+ * @param netId Network id of the configuration to check against
+ * @param allowOverride If true we won't defer to the user if the uid of the message holds the
+ * CONFIG_OVERRIDE_PERMISSION
+ * @return True if we are waiting for user feedback or netId is invalid. False otherwise.
+ */
+ boolean deferForUserInput(Message message, int netId, boolean allowOverride){
+ final WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(netId);
+
+ // We can only evaluate saved configurations.
+ if (config == null) {
+ logd("deferForUserInput: configuration for netId=" + netId + " not stored");
+ return true;
+ }
+
+ switch (config.userApproved) {
+ case WifiConfiguration.USER_APPROVED:
+ case WifiConfiguration.USER_BANNED:
+ return false;
+ case WifiConfiguration.USER_PENDING:
+ default: // USER_UNSPECIFIED
+ /* the intention was to ask user here; but a dialog box is *
+ * too invasive; so we are going to allow connection for now */
+ config.userApproved = WifiConfiguration.USER_APPROVED;
+ return false;
+ }
+ }
+
+ /**
* Subset of link properties coming from netlink.
* Currently includes IPv4 and IPv6 addresses. In the future will also include IPv6 DNS servers
* and domains obtained from router advertisements (RFC 6106).
*/
private NetlinkTracker mNetlinkTracker;
+ private IpReachabilityMonitor mIpReachabilityMonitor;
+
private AlarmManager mAlarmManager;
private PendingIntent mScanIntent;
private PendingIntent mDriverStopIntent;
- private PendingIntent mBatchedScanIntervalIntent;
+ private PendingIntent mPnoIntent;
+ private int mDisconnectedPnoAlarmCount = 0;
/* Tracks current frequency mode */
private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO);
@@ -407,11 +533,15 @@
private AsyncChannel mWifiP2pChannel;
private AsyncChannel mWifiApConfigChannel;
+ private WifiScanner mWifiScanner;
+
private int mConnectionRequests = 0;
private WifiNetworkFactory mNetworkFactory;
private UntrustedWifiNetworkFactory mUntrustedNetworkFactory;
private WifiNetworkAgent mNetworkAgent;
+ private String[] mWhiteListedSsids = null;
+
// Keep track of various statistics, for retrieval by System Apps, i.e. under @SystemApi
// We should really persist that into the networkHistory.txt file, and read it back when
// WifiStateMachine starts up
@@ -423,87 +553,87 @@
/* The base for wifi message types */
static final int BASE = Protocol.BASE_WIFI;
/* Start the supplicant */
- static final int CMD_START_SUPPLICANT = BASE + 11;
+ static final int CMD_START_SUPPLICANT = BASE + 11;
/* Stop the supplicant */
- static final int CMD_STOP_SUPPLICANT = BASE + 12;
+ static final int CMD_STOP_SUPPLICANT = BASE + 12;
/* Start the driver */
- static final int CMD_START_DRIVER = BASE + 13;
+ static final int CMD_START_DRIVER = BASE + 13;
/* Stop the driver */
- static final int CMD_STOP_DRIVER = BASE + 14;
+ static final int CMD_STOP_DRIVER = BASE + 14;
/* Indicates Static IP succeeded */
- static final int CMD_STATIC_IP_SUCCESS = BASE + 15;
+ static final int CMD_STATIC_IP_SUCCESS = BASE + 15;
/* Indicates Static IP failed */
- static final int CMD_STATIC_IP_FAILURE = BASE + 16;
+ static final int CMD_STATIC_IP_FAILURE = BASE + 16;
/* Indicates supplicant stop failed */
- static final int CMD_STOP_SUPPLICANT_FAILED = BASE + 17;
+ static final int CMD_STOP_SUPPLICANT_FAILED = BASE + 17;
/* Delayed stop to avoid shutting down driver too quick*/
- static final int CMD_DELAYED_STOP_DRIVER = BASE + 18;
+ static final int CMD_DELAYED_STOP_DRIVER = BASE + 18;
/* A delayed message sent to start driver when it fail to come up */
- static final int CMD_DRIVER_START_TIMED_OUT = BASE + 19;
+ static final int CMD_DRIVER_START_TIMED_OUT = BASE + 19;
/* Start the soft access point */
- static final int CMD_START_AP = BASE + 21;
+ static final int CMD_START_AP = BASE + 21;
/* Indicates soft ap start succeeded */
- static final int CMD_START_AP_SUCCESS = BASE + 22;
+ static final int CMD_START_AP_SUCCESS = BASE + 22;
/* Indicates soft ap start failed */
- static final int CMD_START_AP_FAILURE = BASE + 23;
+ static final int CMD_START_AP_FAILURE = BASE + 23;
/* Stop the soft access point */
- static final int CMD_STOP_AP = BASE + 24;
+ static final int CMD_STOP_AP = BASE + 24;
/* Set the soft access point configuration */
- static final int CMD_SET_AP_CONFIG = BASE + 25;
+ static final int CMD_SET_AP_CONFIG = BASE + 25;
/* Soft access point configuration set completed */
- static final int CMD_SET_AP_CONFIG_COMPLETED = BASE + 26;
+ static final int CMD_SET_AP_CONFIG_COMPLETED = BASE + 26;
/* Request the soft access point configuration */
- static final int CMD_REQUEST_AP_CONFIG = BASE + 27;
+ static final int CMD_REQUEST_AP_CONFIG = BASE + 27;
/* Response to access point configuration request */
- static final int CMD_RESPONSE_AP_CONFIG = BASE + 28;
+ static final int CMD_RESPONSE_AP_CONFIG = BASE + 28;
/* Invoked when getting a tether state change notification */
- static final int CMD_TETHER_STATE_CHANGE = BASE + 29;
+ static final int CMD_TETHER_STATE_CHANGE = BASE + 29;
/* A delayed message sent to indicate tether state change failed to arrive */
- static final int CMD_TETHER_NOTIFICATION_TIMED_OUT = BASE + 30;
+ static final int CMD_TETHER_NOTIFICATION_TIMED_OUT = BASE + 30;
- static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 31;
+ static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 31;
/* Supplicant commands */
/* Is supplicant alive ? */
- static final int CMD_PING_SUPPLICANT = BASE + 51;
+ static final int CMD_PING_SUPPLICANT = BASE + 51;
/* Add/update a network configuration */
- static final int CMD_ADD_OR_UPDATE_NETWORK = BASE + 52;
+ static final int CMD_ADD_OR_UPDATE_NETWORK = BASE + 52;
/* Delete a network */
- static final int CMD_REMOVE_NETWORK = BASE + 53;
+ static final int CMD_REMOVE_NETWORK = BASE + 53;
/* Enable a network. The device will attempt a connection to the given network. */
- static final int CMD_ENABLE_NETWORK = BASE + 54;
+ static final int CMD_ENABLE_NETWORK = BASE + 54;
/* Enable all networks */
- static final int CMD_ENABLE_ALL_NETWORKS = BASE + 55;
+ static final int CMD_ENABLE_ALL_NETWORKS = BASE + 55;
/* Blacklist network. De-prioritizes the given BSSID for connection. */
- static final int CMD_BLACKLIST_NETWORK = BASE + 56;
+ static final int CMD_BLACKLIST_NETWORK = BASE + 56;
/* Clear the blacklist network list */
- static final int CMD_CLEAR_BLACKLIST = BASE + 57;
+ static final int CMD_CLEAR_BLACKLIST = BASE + 57;
/* Save configuration */
- static final int CMD_SAVE_CONFIG = BASE + 58;
+ static final int CMD_SAVE_CONFIG = BASE + 58;
/* Get configured networks */
- static final int CMD_GET_CONFIGURED_NETWORKS = BASE + 59;
+ static final int CMD_GET_CONFIGURED_NETWORKS = BASE + 59;
/* Get available frequencies */
- static final int CMD_GET_CAPABILITY_FREQ = BASE + 60;
+ static final int CMD_GET_CAPABILITY_FREQ = BASE + 60;
/* Get adaptors */
- static final int CMD_GET_SUPPORTED_FEATURES = BASE + 61;
+ static final int CMD_GET_SUPPORTED_FEATURES = BASE + 61;
/* Get configured networks with real preSharedKey */
- static final int CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS = BASE + 62;
+ static final int CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS = BASE + 62;
/* Get Link Layer Stats thru HAL */
- static final int CMD_GET_LINK_LAYER_STATS = BASE + 63;
+ static final int CMD_GET_LINK_LAYER_STATS = BASE + 63;
/* Supplicant commands after driver start*/
/* Initiate a scan */
- static final int CMD_START_SCAN = BASE + 71;
+ static final int CMD_START_SCAN = BASE + 71;
/* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */
- static final int CMD_SET_OPERATIONAL_MODE = BASE + 72;
+ static final int CMD_SET_OPERATIONAL_MODE = BASE + 72;
/* Disconnect from a network */
- static final int CMD_DISCONNECT = BASE + 73;
+ static final int CMD_DISCONNECT = BASE + 73;
/* Reconnect to a network */
- static final int CMD_RECONNECT = BASE + 74;
+ static final int CMD_RECONNECT = BASE + 74;
/* Reassociate to a network */
- static final int CMD_REASSOCIATE = BASE + 75;
+ static final int CMD_REASSOCIATE = BASE + 75;
/* Get Connection Statistis */
- static final int CMD_GET_CONNECTION_STATISTICS = BASE + 76;
+ static final int CMD_GET_CONNECTION_STATISTICS = BASE + 76;
/* Controls suspend mode optimizations
*
@@ -516,38 +646,66 @@
* - turn off roaming
* - DTIM wake up settings
*/
- static final int CMD_SET_HIGH_PERF_MODE = BASE + 77;
+ static final int CMD_SET_HIGH_PERF_MODE = BASE + 77;
/* Set the country code */
- static final int CMD_SET_COUNTRY_CODE = BASE + 80;
+ static final int CMD_SET_COUNTRY_CODE = BASE + 80;
/* Enables RSSI poll */
- static final int CMD_ENABLE_RSSI_POLL = BASE + 82;
+ static final int CMD_ENABLE_RSSI_POLL = BASE + 82;
/* RSSI poll */
- static final int CMD_RSSI_POLL = BASE + 83;
+ static final int CMD_RSSI_POLL = BASE + 83;
/* Set up packet filtering */
- static final int CMD_START_PACKET_FILTERING = BASE + 84;
+ static final int CMD_START_PACKET_FILTERING = BASE + 84;
/* Clear packet filter */
- static final int CMD_STOP_PACKET_FILTERING = BASE + 85;
+ static final int CMD_STOP_PACKET_FILTERING = BASE + 85;
/* Enable suspend mode optimizations in the driver */
- static final int CMD_SET_SUSPEND_OPT_ENABLED = BASE + 86;
+ static final int CMD_SET_SUSPEND_OPT_ENABLED = BASE + 86;
/* Delayed NETWORK_DISCONNECT */
- static final int CMD_DELAYED_NETWORK_DISCONNECT = BASE + 87;
+ static final int CMD_DELAYED_NETWORK_DISCONNECT = BASE + 87;
/* When there are no saved networks, we do a periodic scan to notify user of
* an open network */
- static final int CMD_NO_NETWORKS_PERIODIC_SCAN = BASE + 88;
+ static final int CMD_NO_NETWORKS_PERIODIC_SCAN = BASE + 88;
/* Test network Disconnection NETWORK_DISCONNECT */
- static final int CMD_TEST_NETWORK_DISCONNECT = BASE + 89;
+ static final int CMD_TEST_NETWORK_DISCONNECT = BASE + 89;
+
private int testNetworkDisconnectCounter = 0;
/* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */
- static final int MULTICAST_V6 = 1;
- static final int MULTICAST_V4 = 0;
+ static final int MULTICAST_V6 = 1;
+ static final int MULTICAST_V4 = 0;
- /* Set the frequency band */
- static final int CMD_SET_FREQUENCY_BAND = BASE + 90;
+ /* Set the frequency band */
+ static final int CMD_SET_FREQUENCY_BAND = BASE + 90;
/* Enable TDLS on a specific MAC address */
- static final int CMD_ENABLE_TDLS = BASE + 92;
+ static final int CMD_ENABLE_TDLS = BASE + 92;
/* DHCP/IP configuration watchdog */
- static final int CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER = BASE + 93;
+ static final int CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER = BASE + 93;
+
+ /**
+ * Watchdog for protecting against b/16823537
+ * Leave time for 4-way handshake to succeed
+ */
+ static final int ROAM_GUARD_TIMER_MSEC = 15000;
+
+ int roamWatchdogCount = 0;
+ /* Roam state watchdog */
+ static final int CMD_ROAM_WATCHDOG_TIMER = BASE + 94;
+ /* Screen change intent handling */
+ static final int CMD_SCREEN_STATE_CHANGED = BASE + 95;
+
+ /* Disconnecting state watchdog */
+ static final int CMD_DISCONNECTING_WATCHDOG_TIMER = BASE + 96;
+
+ /* Remove a packages associated configrations */
+ static final int CMD_REMOVE_APP_CONFIGURATIONS = BASE + 97;
+
+ /* Disable an ephemeral network */
+ static final int CMD_DISABLE_EPHEMERAL_NETWORK = BASE + 98;
+
+ /* Get matching network */
+ static final int CMD_GET_MATCHING_CONFIG = BASE + 99;
+
+ /* alert from firmware */
+ static final int CMD_FIRMWARE_ALERT = BASE + 100;
/**
* Make this timer 40 seconds, which is about the normal DHCP timeout.
@@ -560,84 +718,82 @@
/* Commands from/to the SupplicantStateTracker */
/* Reset the supplicant state tracker */
- static final int CMD_RESET_SUPPLICANT_STATE = BASE + 111;
-
-
- /**
- * Watchdog for protecting against b/16823537
- * Leave time for 4-ways handshake to succeed
- */
- static final int ROAM_GUARD_TIMER_MSEC = 15000;
-
- int roamWatchdogCount = 0;
- /* Roam state watchdog */
- static final int CMD_ROAM_WATCHDOG_TIMER = BASE + 94;
- /* Screen change intent handling */
- static final int CMD_SCREEN_STATE_CHANGED = BASE + 95;
+ static final int CMD_RESET_SUPPLICANT_STATE = BASE + 111;
int disconnectingWatchdogCount = 0;
static final int DISCONNECTING_GUARD_TIMER_MSEC = 5000;
- /* Disconnecting state watchdog */
- static final int CMD_DISCONNECTING_WATCHDOG_TIMER = BASE + 96;
-
- /* Disable an ephemeral network */
- static final int CMD_DISABLE_EPHEMERAL_NETWORK = BASE + 98;
-
/* P2p commands */
/* We are ok with no response here since we wont do much with it anyway */
- public static final int CMD_ENABLE_P2P = BASE + 131;
+ public static final int CMD_ENABLE_P2P = BASE + 131;
/* In order to shut down supplicant cleanly, we wait till p2p has
* been disabled */
- public static final int CMD_DISABLE_P2P_REQ = BASE + 132;
- public static final int CMD_DISABLE_P2P_RSP = BASE + 133;
+ public static final int CMD_DISABLE_P2P_REQ = BASE + 132;
+ public static final int CMD_DISABLE_P2P_RSP = BASE + 133;
- public static final int CMD_BOOT_COMPLETED = BASE + 134;
-
- /* change the batch scan settings.
- * arg1 = responsible UID
- * arg2 = csph (channel scans per hour)
- * obj = bundle with the new settings and the optional worksource
- */
- public static final int CMD_SET_BATCHED_SCAN = BASE + 135;
- public static final int CMD_START_NEXT_BATCHED_SCAN = BASE + 136;
- public static final int CMD_POLL_BATCHED_SCAN = BASE + 137;
+ public static final int CMD_BOOT_COMPLETED = BASE + 134;
/* We now have a valid IP configuration. */
- static final int CMD_IP_CONFIGURATION_SUCCESSFUL = BASE + 138;
+ static final int CMD_IP_CONFIGURATION_SUCCESSFUL = BASE + 138;
/* We no longer have a valid IP configuration. */
- static final int CMD_IP_CONFIGURATION_LOST = BASE + 139;
+ static final int CMD_IP_CONFIGURATION_LOST = BASE + 139;
/* Link configuration (IP address, DNS, ...) changes notified via netlink */
- static final int CMD_UPDATE_LINKPROPERTIES = BASE + 140;
+ static final int CMD_UPDATE_LINKPROPERTIES = BASE + 140;
/* Supplicant is trying to associate to a given BSSID */
- static final int CMD_TARGET_BSSID = BASE + 141;
+ static final int CMD_TARGET_BSSID = BASE + 141;
/* Reload all networks and reconnect */
- static final int CMD_RELOAD_TLS_AND_RECONNECT = BASE + 142;
+ static final int CMD_RELOAD_TLS_AND_RECONNECT = BASE + 142;
- static final int CMD_AUTO_CONNECT = BASE + 143;
+ static final int CMD_AUTO_CONNECT = BASE + 143;
- static final int network_status_unwanted_disconnect = 0;
- static final int network_status_unwanted_disable_autojoin = 1;
+ private static final int NETWORK_STATUS_UNWANTED_DISCONNECT = 0;
+ private static final int NETWORK_STATUS_UNWANTED_VALIDATION_FAILED = 1;
+ private static final int NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN = 2;
- static final int CMD_UNWANTED_NETWORK = BASE + 144;
+ static final int CMD_UNWANTED_NETWORK = BASE + 144;
- static final int CMD_AUTO_ROAM = BASE + 145;
+ static final int CMD_AUTO_ROAM = BASE + 145;
- static final int CMD_AUTO_SAVE_NETWORK = BASE + 146;
+ static final int CMD_AUTO_SAVE_NETWORK = BASE + 146;
- static final int CMD_ASSOCIATED_BSSID = BASE + 147;
+ static final int CMD_ASSOCIATED_BSSID = BASE + 147;
- static final int CMD_NETWORK_STATUS = BASE + 148;
+ static final int CMD_NETWORK_STATUS = BASE + 148;
+
+ /* A layer 3 neighbor on the Wi-Fi link became unreachable. */
+ static final int CMD_IP_REACHABILITY_LOST = BASE + 149;
+
+ /* Remove a packages associated configrations */
+ static final int CMD_REMOVE_USER_CONFIGURATIONS = BASE + 152;
+
+ static final int CMD_ACCEPT_UNVALIDATED = BASE + 153;
+
+ /* used to restart PNO when it was stopped due to association attempt */
+ static final int CMD_RESTART_AUTOJOIN_OFFLOAD = BASE + 154;
+
+ static int mRestartAutoJoinOffloadCounter = 0;
+
+ /* used to log if PNO was started */
+ static final int CMD_STARTED_PNO_DBG = BASE + 155;
+
+ static final int CMD_PNO_NETWORK_FOUND = BASE + 156;
+
+ /* used to log if PNO was started */
+ static final int CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION = BASE + 158;
+
+ /* used to log if GSCAN was started */
+ static final int CMD_STARTED_GSCAN_DBG = BASE + 159;
+
/* Wifi state machine modes of operation */
/* CONNECT_MODE - connect to any 'known' AP when it becomes available */
- public static final int CONNECT_MODE = 1;
+ public static final int CONNECT_MODE = 1;
/* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */
- public static final int SCAN_ONLY_MODE = 2;
+ public static final int SCAN_ONLY_MODE = 2;
/* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */
- public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3;
+ public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3;
private static final int SUCCESS = 1;
private static final int FAILURE = -1;
@@ -649,9 +805,9 @@
*/
private int mSuspendOptNeedsDisabled = 0;
- private static final int SUSPEND_DUE_TO_DHCP = 1;
- private static final int SUSPEND_DUE_TO_HIGH_PERF = 1<<1;
- private static final int SUSPEND_DUE_TO_SCREEN = 1<<2;
+ private static final int SUSPEND_DUE_TO_DHCP = 1;
+ private static final int SUSPEND_DUE_TO_HIGH_PERF = 1 << 1;
+ private static final int SUSPEND_DUE_TO_SCREEN = 1 << 2;
/* Tracks if user has enabled suspend optimizations through settings */
private AtomicBoolean mUserWantsSuspendOpt = new AtomicBoolean(true);
@@ -665,7 +821,11 @@
*/
private final int mDefaultFrameworkScanIntervalMs;
- private final int mDisconnectedScanPeriodMs;
+
+ /**
+ * Scan period for the NO_NETWORKS_PERIIDOC_SCAN_FEATURE
+ */
+ private final int mNoNetworksPeriodicScan;
/**
* Supplicant scan interval in milliseconds.
@@ -690,7 +850,7 @@
* autojoin while connected with screen lit
* Max time is 5 minutes
*/
- private static final long maxFullBandConnectedTimeIntervalMilli = 1000 * 60 * 5;
+ private static final long maxFullBandConnectedTimeIntervalMilli = 1000 * 60 * 5;
/**
* Minimum time interval between enabling all networks.
@@ -710,13 +870,14 @@
private int mDelayedStopCounter;
private boolean mInDelayedStop = false;
- // sometimes telephony gives us this data before boot is complete and we can't store it
- // until after, so the write is deferred
- private volatile String mPersistedCountryCode;
+ // there is a delay between StateMachine change country code and Supplicant change country code
+ // here save the current WifiStateMachine set country code
+ private volatile String mSetCountryCode = null;
// Supplicant doesn't like setting the same country code multiple times (it may drop
- // currently connected network), so we save the country code here to avoid redundency
- private String mLastSetCountryCode;
+ // currently connected network), so we save the current device set country code here to avoid
+ // redundency
+ private String mDriverSetCountryCode = null;
/* Default parent state */
private State mDefaultState = new DefaultState();
@@ -773,9 +934,40 @@
/* Waiting for untether confirmation before stopping soft Ap */
private State mUntetheringState = new UntetheringState();
+
+
+ private class WifiScanListener implements WifiScanner.ScanListener {
+ @Override
+ public void onSuccess() {
+ Log.e(TAG, "WifiScanListener onSuccess");
+ };
+ @Override
+ public void onFailure(int reason, String description) {
+ Log.e(TAG, "WifiScanListener onFailure");
+ };
+ @Override
+ public void onPeriodChanged(int periodInMs) {
+ Log.e(TAG, "WifiScanListener onPeriodChanged period=" + periodInMs);
+ }
+ @Override
+ public void onResults(WifiScanner.ScanData[] results) {
+ Log.e(TAG, "WifiScanListener onResults2 " + results.length);
+ }
+ @Override
+ public void onFullResult(ScanResult fullScanResult) {
+ Log.e(TAG, "WifiScanListener onFullResult " + fullScanResult.toString());
+ }
+
+ WifiScanListener() {}
+ }
+
+ WifiScanListener mWifiScanListener = new WifiScanListener();
+
+
private class TetherStateChange {
ArrayList<String> available;
ArrayList<String> active;
+
TetherStateChange(ArrayList<String> av, ArrayList<String> ac) {
available = av;
active = ac;
@@ -786,50 +978,42 @@
int networkId;
int protocol;
String ssid;
- String[] challenges;
- }
-
- public static class SimAuthResponseData {
- int id;
- String Kc1;
- String SRES1;
- String Kc2;
- String SRES2;
- String Kc3;
- String SRES3;
+ // EAP-SIM: data[] contains the 3 rand, one for each of the 3 challenges
+ // EAP-AKA/AKA': data[] contains rand & authn couple for the single challenge
+ String[] data;
}
/**
* One of {@link WifiManager#WIFI_STATE_DISABLED},
- * {@link WifiManager#WIFI_STATE_DISABLING},
- * {@link WifiManager#WIFI_STATE_ENABLED},
- * {@link WifiManager#WIFI_STATE_ENABLING},
- * {@link WifiManager#WIFI_STATE_UNKNOWN}
- *
+ * {@link WifiManager#WIFI_STATE_DISABLING},
+ * {@link WifiManager#WIFI_STATE_ENABLED},
+ * {@link WifiManager#WIFI_STATE_ENABLING},
+ * {@link WifiManager#WIFI_STATE_UNKNOWN}
*/
private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
/**
* 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}
- *
+ * {@link WifiManager#WIFI_AP_STATE_DISABLING},
+ * {@link WifiManager#WIFI_AP_STATE_ENABLED},
+ * {@link WifiManager#WIFI_AP_STATE_ENABLING},
+ * {@link WifiManager#WIFI_AP_STATE_FAILED}
*/
private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED);
private static final int SCAN_REQUEST = 0;
private static final String ACTION_START_SCAN =
- "com.android.server.WifiManager.action.START_SCAN";
+ "com.android.server.WifiManager.action.START_SCAN";
+
+ private static final int PNO_START_REQUEST = 0;
+ private static final String ACTION_START_PNO =
+ "com.android.server.WifiManager.action.START_PNO";
private static final String DELAYED_STOP_COUNTER = "DelayedStopCounter";
private static final int DRIVER_STOP_REQUEST = 0;
private static final String ACTION_DELAYED_DRIVER_STOP =
- "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP";
+ "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP";
- private static final String ACTION_REFRESH_BATCHED_SCAN =
- "com.android.server.WifiManager.action.REFRESH_BATCHED_SCAN";
/**
* Keep track of whether WIFI is running.
*/
@@ -852,17 +1036,6 @@
private final IBatteryStats mBatteryStats;
- private BatchedScanSettings mBatchedScanSettings = null;
-
- /**
- * Track the worksource/cost of the current settings and track what's been noted
- * to the battery stats, so we can mark the end of the previous when changing.
- */
- private WorkSource mBatchedScanWorkSource = null;
- private int mBatchedScanCsph = 0;
- private WorkSource mNotedBatchedScanWorkSource = null;
- private int mNotedBatchedScanCsph = 0;
-
private String mTcpBufferSizes = null;
// Used for debug and stats gathering
@@ -870,10 +1043,17 @@
final static int frameworkMinScanIntervalSaneValue = 10000;
+ boolean mPnoEnabled;
+ boolean mLazyRoamEnabled;
+ long mGScanStartTimeMilli;
+ long mGScanPeriodMilli;
+
public WifiStateMachine(Context context, String wlanInterface,
- WifiTrafficPoller trafficPoller){
+ WifiTrafficPoller trafficPoller) {
super("WifiStateMachine");
mContext = context;
+ mSetCountryCode = Settings.Global.getString(
+ mContext.getContentResolver(), Settings.Global.WIFI_COUNTRY_CODE);
mInterfaceName = wlanInterface;
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
@@ -886,17 +1066,21 @@
PackageManager.FEATURE_WIFI_DIRECT);
mWifiNative = new WifiNative(mInterfaceName);
- mWifiConfigStore = new WifiConfigStore(context, mWifiNative);
+ mWifiConfigStore = new WifiConfigStore(context,this, mWifiNative);
mWifiAutoJoinController = new WifiAutoJoinController(context, this,
mWifiConfigStore, mWifiConnectionStatistics, mWifiNative);
mWifiMonitor = new WifiMonitor(this, mWifiNative);
+ mWifiLogger = new WifiLogger(this);
+
mWifiInfo = new WifiInfo();
mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore,
getHandler());
mLinkProperties = new LinkProperties();
IBinder s1 = ServiceManager.getService(Context.WIFI_P2P_SERVICE);
- mWifiP2pServiceImpl = (WifiP2pServiceImpl)IWifiP2pManager.Stub.asInterface(s1);
+ mWifiP2pServiceImpl = (WifiP2pServiceImpl) IWifiP2pManager.Stub.asInterface(s1);
+
+ IBinder s2 = ServiceManager.getService(Context.WIFI_PASSPOINT_SERVICE);
mNetworkInfo.setIsAvailable(false);
mLastBssid = null;
@@ -914,9 +1098,9 @@
loge("Couldn't register netlink tracker: " + e.toString());
}
- mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+ mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mScanIntent = getPrivateBroadcast(ACTION_START_SCAN, SCAN_REQUEST);
- mBatchedScanIntervalIntent = getPrivateBroadcast(ACTION_REFRESH_BATCHED_SCAN, 0);
+ mPnoIntent = getPrivateBroadcast(ACTION_START_PNO, PNO_START_REQUEST);
// Make sure the interval is not configured less than 10 seconds
int period = mContext.getResources().getInteger(
@@ -925,8 +1109,10 @@
period = frameworkMinScanIntervalSaneValue;
}
mDefaultFrameworkScanIntervalMs = period;
- mDisconnectedScanPeriodMs = mContext.getResources().getInteger(
- R.integer.config_wifi_disconnected_scan_interval);
+
+ mNoNetworksPeriodicScan = mContext.getResources().getInteger(
+ R.integer.config_wifi_no_network_periodic_scan_interval);
+
mDriverStopDelayMs = mContext.getResources().getInteger(
R.integer.config_wifi_driver_stop_delay);
@@ -937,7 +1123,7 @@
R.string.config_wifi_p2p_device_type);
mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1);
+ Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1);
mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
@@ -948,16 +1134,16 @@
mNetworkCapabilities = new NetworkCapabilities(mNetworkCapabilitiesFilter);
mContext.registerReceiver(
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- ArrayList<String> available = intent.getStringArrayListExtra(
- ConnectivityManager.EXTRA_AVAILABLE_TETHER);
- ArrayList<String> active = intent.getStringArrayListExtra(
- ConnectivityManager.EXTRA_ACTIVE_TETHER);
- sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active));
- }
- },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ ArrayList<String> available = intent.getStringArrayListExtra(
+ ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+ ArrayList<String> active = intent.getStringArrayListExtra(
+ ConnectivityManager.EXTRA_ACTIVE_TETHER);
+ sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active));
+ }
+ }, new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
mContext.registerReceiver(
new BroadcastReceiver() {
@@ -966,15 +1152,27 @@
sScanAlarmIntentCount++; // Used for debug only
startScan(SCAN_ALARM_SOURCE, mDelayedScanCounter.incrementAndGet(), null, null);
if (VDBG)
- loge("WiFiStateMachine SCAN ALARM -> " + mDelayedScanCounter.get());
+ logd("SCAN ALARM -> " + mDelayedScanCounter.get());
}
},
new IntentFilter(ACTION_START_SCAN));
+ mContext.registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ sendMessage(CMD_RESTART_AUTOJOIN_OFFLOAD, 0,
+ mRestartAutoJoinOffloadCounter, "pno alarm");
+ if (DBG)
+ logd("PNO START ALARM sent");
+ }
+ },
+ new IntentFilter(ACTION_START_PNO));
+
+
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
- filter.addAction(ACTION_REFRESH_BATCHED_SCAN);
mContext.registerReceiver(
new BroadcastReceiver() {
@Override
@@ -985,8 +1183,6 @@
sendMessage(CMD_SCREEN_STATE_CHANGED, 1);
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
sendMessage(CMD_SCREEN_STATE_CHANGED, 0);
- } else if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) {
- startNextBatchedScanAsync();
}
}
}, filter);
@@ -995,14 +1191,14 @@
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0);
- sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0);
+ int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0);
+ sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0);
}
},
new IntentFilter(ACTION_DELAYED_DRIVER_STOP));
mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
- Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false,
+ Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false,
new ContentObserver(getHandler()) {
@Override
public void onChange(boolean selfChange) {
@@ -1020,9 +1216,9 @@
},
new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
- mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE);
+ mScanResultCache = new LruCache<>(SCAN_RESULT_CACHE_SIZE);
- PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+ PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName());
mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend");
@@ -1076,7 +1272,8 @@
PendingIntent getPrivateBroadcast(String action, int requestCode) {
Intent intent = new Intent(action, null);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- intent.setPackage(this.getClass().getPackage().getName());
+ //intent.setPackage(this.getClass().getPackage().getName());
+ intent.setPackage("android");
return PendingIntent.getBroadcast(mContext, requestCode, intent, 0);
}
@@ -1101,6 +1298,7 @@
mLogMessages = false;
mWifiNative.setSupplicantLogLevel("INFO");
}
+ mWifiLogger.startLogging(mVerboseLoggingLevel > 0);
mWifiAutoJoinController.enableVerboseLogging(verbose);
mWifiMonitor.enableVerboseLogging(verbose);
mWifiNative.enableVerboseLogging(verbose);
@@ -1108,6 +1306,99 @@
mSupplicantStateTracker.enableVerboseLogging(verbose);
}
+ public void setHalBasedAutojoinOffload(int enabled) {
+ // Shoult be used for debug only, triggered form developper settings
+ // enabling HAl based PNO dynamically is not safe and not a normal operation
+ mHalBasedPnoEnableInDevSettings = enabled > 0;
+ mWifiConfigStore.enableHalBasedPno.set(mHalBasedPnoEnableInDevSettings);
+ mWifiConfigStore.enableSsidWhitelist.set(mHalBasedPnoEnableInDevSettings);
+ sendMessage(CMD_DISCONNECT);
+ }
+
+ int getHalBasedAutojoinOffload() {
+ return mHalBasedPnoEnableInDevSettings ? 1 : 0;
+ }
+
+ boolean useHalBasedAutoJoinOffload() {
+ // all three settings need to be true:
+ // - developper settings switch
+ // - driver support
+ // - config option
+ return mHalBasedPnoEnableInDevSettings
+ && mHalBasedPnoDriverSupported
+ && mWifiConfigStore.enableHalBasedPno.get();
+ }
+
+ boolean allowFullBandScanAndAssociated() {
+
+ if (!getEnableAutoJoinWhenAssociated()) {
+ if (DBG) {
+ Log.e(TAG, "allowFullBandScanAndAssociated: "
+ + " enableAutoJoinWhenAssociated : disallow");
+ }
+ return false;
+ }
+
+ if (mWifiInfo.txSuccessRate >
+ mWifiConfigStore.maxTxPacketForFullScans
+ || mWifiInfo.rxSuccessRate >
+ mWifiConfigStore.maxRxPacketForFullScans) {
+ if (DBG) {
+ Log.e(TAG, "allowFullBandScanAndAssociated: packet rate tx"
+ + mWifiInfo.txSuccessRate + " rx "
+ + mWifiInfo.rxSuccessRate
+ + " allow scan with traffic " + getAllowScansWithTraffic());
+ }
+ // Too much traffic at the interface, hence no full band scan
+ if (getAllowScansWithTraffic() == 0) {
+ return false;
+ }
+ }
+
+ if (getCurrentState() != mConnectedState) {
+ if (DBG) {
+ Log.e(TAG, "allowFullBandScanAndAssociated: getCurrentState() : disallow");
+ }
+ return false;
+ }
+
+ return true;
+ }
+
+ long mLastScanPermissionUpdate = 0;
+ boolean mConnectedModeGScanOffloadStarted = false;
+ // Don't do a G-scan enable/re-enable cycle more than once within 20seconds
+ // The function updateAssociatedScanPermission() can be called quite frequently, hence
+ // we want to throttle the GScan Stop->Start transition
+ static final long SCAN_PERMISSION_UPDATE_THROTTLE_MILLI = 20000;
+ void updateAssociatedScanPermission() {
+
+ if (useHalBasedAutoJoinOffload()) {
+ boolean allowed = allowFullBandScanAndAssociated();
+
+ long now = System.currentTimeMillis();
+ if (mConnectedModeGScanOffloadStarted && !allowed) {
+ if (DBG) {
+ Log.e(TAG, " useHalBasedAutoJoinOffload stop offload");
+ }
+ stopPnoOffload();
+ stopGScan(" useHalBasedAutoJoinOffload");
+ }
+ if (!mConnectedModeGScanOffloadStarted && allowed) {
+ if ((now - mLastScanPermissionUpdate) > SCAN_PERMISSION_UPDATE_THROTTLE_MILLI) {
+ // Re-enable Gscan offload, this will trigger periodic scans and allow firmware
+ // to look for 5GHz BSSIDs and better networks
+ if (DBG) {
+ Log.e(TAG, " useHalBasedAutoJoinOffload restart offload");
+ }
+ startGScanConnectedModeOffload("updatePermission "
+ + (now - mLastScanPermissionUpdate) + "ms");
+ mLastScanPermissionUpdate = now;
+ }
+ }
+ }
+ }
+
private int mAggressiveHandover = 0;
int getAggressiveHandover() {
@@ -1118,31 +1409,46 @@
mAggressiveHandover = enabled;
}
+ public void clearANQPCache() {
+ mWifiConfigStore.trimANQPCache(true);
+ }
+
public void setAllowScansWithTraffic(int enabled) {
- mWifiConfigStore.alwaysEnableScansWhileAssociated = enabled;
+ mWifiConfigStore.alwaysEnableScansWhileAssociated.set(enabled);
}
public int getAllowScansWithTraffic() {
- return mWifiConfigStore.alwaysEnableScansWhileAssociated;
+ return mWifiConfigStore.alwaysEnableScansWhileAssociated.get();
}
+ public boolean enableAutoJoinWhenAssociated(boolean enabled) {
+ boolean old_state = getEnableAutoJoinWhenAssociated();
+ mWifiConfigStore.enableAutoJoinWhenAssociated.set(enabled);
+ if (!old_state && enabled && mScreenOn && getCurrentState() == mConnectedState) {
+ startDelayedScan(mWifiConfigStore.wifiAssociatedShortScanIntervalMilli.get(), null,
+ null);
+ }
+ return true;
+ }
+
+ public boolean getEnableAutoJoinWhenAssociated() {
+ return mWifiConfigStore.enableAutoJoinWhenAssociated.get();
+ }
/*
*
* Framework scan control
*/
private boolean mAlarmEnabled = false;
- /* This is set from the overlay config file or from a secure setting.
- * A value of 0 disables scanning in the framework.
- */
- private long mFrameworkScanIntervalMs = 10000;
private AtomicInteger mDelayedScanCounter = new AtomicInteger();
private void setScanAlarm(boolean enabled) {
if (PDBG) {
- loge("setScanAlarm " + enabled
- + " period " + mDefaultFrameworkScanIntervalMs
+ String state;
+ if (enabled) state = "enabled"; else state = "disabled";
+ logd("setScanAlarm " + state
+ + " defaultperiod " + mDefaultFrameworkScanIntervalMs
+ " mBackgroundScanSupported " + mBackgroundScanSupported);
}
if (mBackgroundScanSupported == false) {
@@ -1168,11 +1474,11 @@
private void cancelDelayedScan() {
mDelayedScanCounter.incrementAndGet();
- loge("cancelDelayedScan -> " + mDelayedScanCounter);
}
private boolean checkAndRestartDelayedScan(int counter, boolean restart, int milli,
- ScanSettings settings, WorkSource workSource) {
+ ScanSettings settings, WorkSource workSource) {
+
if (counter != mDelayedScanCounter.get()) {
return false;
}
@@ -1194,21 +1500,21 @@
mDelayedScanCounter.incrementAndGet();
if (mScreenOn &&
(getCurrentState() == mDisconnectedState
- || getCurrentState() == mConnectedState)) {
+ || getCurrentState() == mConnectedState)) {
Bundle bundle = new Bundle();
bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings);
bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
bundle.putLong(SCAN_REQUEST_TIME, System.currentTimeMillis());
sendMessageDelayed(CMD_START_SCAN, SCAN_ALARM_SOURCE,
mDelayedScanCounter.get(), bundle, milli);
- if (DBG) loge("startDelayedScan send -> " + mDelayedScanCounter + " milli " + milli);
+ if (DBG) logd("startDelayedScan send -> " + mDelayedScanCounter + " milli " + milli);
} else if (mBackgroundScanSupported == false
&& !mScreenOn && getCurrentState() == mDisconnectedState) {
setScanAlarm(true);
- if (DBG) loge("startDelayedScan start scan alarm -> "
+ if (DBG) logd("startDelayedScan start scan alarm -> "
+ mDelayedScanCounter + " milli " + milli);
} else {
- if (DBG) loge("startDelayedScan unhandled -> "
+ if (DBG) logd("startDelayedScan unhandled -> "
+ mDelayedScanCounter + " milli " + milli);
}
}
@@ -1226,9 +1532,11 @@