summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorGlen Kuhne <kuh@google.com>2017-04-24 22:52:07 +0000
committerandroid-build-merger <android-build-merger@google.com>2017-04-24 22:52:07 +0000
commita84a8d948173001e1ba9265e15b8a93aad312201 (patch)
treeabebc8df61bde0b615615331ff85f12fe5b819d6 /service
parent07aebf0cd691a3041d0c32ba56a4ea3ad0bfd8fd (diff)
parente2bd998b5a9aa0748c5de85a5e39839a54028f0a (diff)
Merge "New Wifi Metrics Connection Event logging" into oc-dev am: a0123342c2
am: e2bd998b5a Change-Id: I3bf3368c00ee19c1d4acefb115549c564120bd27
Diffstat (limited to 'service')
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java4
-rw-r--r--service/java/com/android/server/wifi/WifiMetrics.java404
-rw-r--r--service/java/com/android/server/wifi/WifiStateMachine.java50
3 files changed, 451 insertions, 7 deletions
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 3d444a448..a977a4693 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -88,7 +88,7 @@ public class WifiInjector {
private final WifiController mWifiController;
private final WificondControl mWificondControl;
private final Clock mClock = new Clock();
- private final WifiMetrics mWifiMetrics = new WifiMetrics(mClock);
+ private final WifiMetrics mWifiMetrics;
private final WifiLastResortWatchdog mWifiLastResortWatchdog;
private final PropertyService mPropertyService = new SystemPropertyService();
private final BuildProperties mBuildProperties = new SystemBuildProperties();
@@ -151,7 +151,7 @@ public class WifiInjector {
mWifiStateMachineHandlerThread = new HandlerThread("WifiStateMachine");
mWifiStateMachineHandlerThread.start();
Looper wifiStateMachineLooper = mWifiStateMachineHandlerThread.getLooper();
-
+ mWifiMetrics = new WifiMetrics(mClock, wifiStateMachineLooper);
// Modules interacting with Native.
mWifiMonitor = new WifiMonitor(this);
mHalDeviceManager = new HalDeviceManager();
diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java
index 934a4c64f..411d7d7e1 100644
--- a/service/java/com/android/server/wifi/WifiMetrics.java
+++ b/service/java/com/android/server/wifi/WifiMetrics.java
@@ -16,23 +16,33 @@
package com.android.server.wifi;
+import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback;
import android.net.NetworkAgent;
import android.net.wifi.ScanResult;
+import android.net.wifi.SupplicantState;
import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.util.Base64;
import android.util.Log;
import android.util.SparseIntArray;
import com.android.server.wifi.hotspot2.NetworkDetail;
import com.android.server.wifi.nano.WifiMetricsProto;
+import com.android.server.wifi.nano.WifiMetricsProto.StaEvent;
+import com.android.server.wifi.nano.WifiMetricsProto.StaEvent.ConfigInfo;
import com.android.server.wifi.util.InformationElementUtil;
import com.android.server.wifi.util.ScanResultUtil;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.BitSet;
import java.util.Calendar;
+import java.util.LinkedList;
import java.util.List;
/**
@@ -62,6 +72,7 @@ public class WifiMetrics {
private Clock mClock;
private boolean mScreenOn;
private int mWifiState;
+ private Handler mHandler;
/**
* Metrics are stored within an instance of the WifiLog proto during runtime,
* The ConnectionEvent, SystemStateEntries & ScanReturnEntries metrics are stored during
@@ -333,12 +344,20 @@ public class WifiMetrics {
}
}
- public WifiMetrics(Clock clock) {
+ public WifiMetrics(Clock clock, Looper looper) {
mClock = clock;
mCurrentConnectionEvent = null;
mScreenOn = true;
mWifiState = WifiMetricsProto.WifiLog.WIFI_DISABLED;
mRecordStartTimeSec = mClock.getElapsedSinceBootMillis() / 1000;
+
+ mHandler = new Handler(looper) {
+ public void handleMessage(Message msg) {
+ synchronized (mLock) {
+ processMessage(msg);
+ }
+ }
+ };
}
// Values used for indexing SystemStateEntries
@@ -796,6 +815,16 @@ public class WifiMetrics {
}
/**
+ * Increment various poll related metrics, and cache performance data for StaEvent logging
+ */
+ public void handlePollResult(WifiInfo wifiInfo) {
+ mLastPollRssi = wifiInfo.getRssi();
+ mLastPollLinkSpeed = wifiInfo.getLinkSpeed();
+ mLastPollFreq = wifiInfo.getFrequency();
+ incrementRssiPollRssiCount(mLastPollRssi);
+ }
+
+ /**
* Increment occurence count of RSSI level from RSSI poll.
* Ignores rssi values outside the bounds of [MIN_RSSI_POLL, MAX_RSSI_POLL]
*/
@@ -1146,6 +1175,10 @@ public class WifiMetrics {
pw.println(" FAILED_NO_CHANNEL: " + mSoftApManagerReturnCodeCounts.get(
WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL));
pw.print("\n");
+ pw.println("StaEventList:");
+ for (StaEvent event : mStaEventList) {
+ pw.println(staEventToString(event));
+ }
}
}
}
@@ -1308,6 +1341,8 @@ public class WifiMetrics {
mWifiLogProto.softApReturnCode[sapCode].count =
mSoftApManagerReturnCodeCounts.valueAt(sapCode);
}
+
+ mWifiLogProto.staEventList = mStaEventList.toArray(mWifiLogProto.staEventList);
}
}
@@ -1330,6 +1365,7 @@ public class WifiMetrics {
mWifiLogProto.clear();
mScanResultRssiTimestampMillis = -1;
mSoftApManagerReturnCodeCounts.clear();
+ mStaEventList.clear();
}
}
@@ -1350,4 +1386,370 @@ public class WifiMetrics {
mWifiState = wifiState;
}
}
+
+ /**
+ * Message handler for interesting WifiMonitor messages. Generates StaEvents
+ */
+ private void processMessage(Message msg) {
+ StaEvent event = new StaEvent();
+ boolean logEvent = true;
+ switch (msg.what) {
+ case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
+ event.type = StaEvent.TYPE_ASSOCIATION_REJECTION_EVENT;
+ event.associationTimedOut = msg.arg1 > 0 ? true : false;
+ event.status = msg.arg2;
+ break;
+ case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
+ event.type = StaEvent.TYPE_AUTHENTICATION_FAILURE_EVENT;
+ switch (msg.arg2) {
+ case WifiManager.ERROR_AUTH_FAILURE_NONE:
+ event.authFailureReason = StaEvent.AUTH_FAILURE_NONE;
+ break;
+ case WifiManager.ERROR_AUTH_FAILURE_TIMEOUT:
+ event.authFailureReason = StaEvent.AUTH_FAILURE_TIMEOUT;
+ break;
+ case WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD:
+ event.authFailureReason = StaEvent.AUTH_FAILURE_WRONG_PSWD;
+ break;
+ case WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE:
+ event.authFailureReason = StaEvent.AUTH_FAILURE_EAP_FAILURE;
+ break;
+ default:
+ break;
+ }
+ break;
+ case WifiMonitor.NETWORK_CONNECTION_EVENT:
+ event.type = StaEvent.TYPE_NETWORK_CONNECTION_EVENT;
+ break;
+ case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
+ event.type = StaEvent.TYPE_NETWORK_DISCONNECTION_EVENT;
+ event.reason = msg.arg2;
+ event.localGen = msg.arg1 == 0 ? false : true;
+ break;
+ case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
+ logEvent = false;
+ StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
+ mSupplicantStateChangeBitmask |= supplicantStateToBit(stateChangeResult.state);
+ break;
+ case WifiStateMachine.CMD_ASSOCIATED_BSSID:
+ event.type = StaEvent.TYPE_CMD_ASSOCIATED_BSSID;
+ break;
+ case WifiStateMachine.CMD_TARGET_BSSID:
+ event.type = StaEvent.TYPE_CMD_TARGET_BSSID;
+ break;
+ default:
+ return;
+ }
+ if (logEvent) {
+ addStaEvent(event);
+ }
+ }
+ /**
+ * Log a StaEvent from WifiStateMachine. The StaEvent must not be one of the supplicant
+ * generated event types, which are logged through 'sendMessage'
+ * @param type StaEvent.EventType describing the event
+ */
+ public void logStaEvent(int type) {
+ logStaEvent(type, StaEvent.DISCONNECT_UNKNOWN, null);
+ }
+ /**
+ * Log a StaEvent from WifiStateMachine. The StaEvent must not be one of the supplicant
+ * generated event types, which are logged through 'sendMessage'
+ * @param type StaEvent.EventType describing the event
+ * @param config WifiConfiguration for a framework initiated connection attempt
+ */
+ public void logStaEvent(int type, WifiConfiguration config) {
+ logStaEvent(type, StaEvent.DISCONNECT_UNKNOWN, config);
+ }
+ /**
+ * Log a StaEvent from WifiStateMachine. The StaEvent must not be one of the supplicant
+ * generated event types, which are logged through 'sendMessage'
+ * @param type StaEvent.EventType describing the event
+ * @param frameworkDisconnectReason StaEvent.FrameworkDisconnectReason explaining why framework
+ * initiated a FRAMEWORK_DISCONNECT
+ */
+ public void logStaEvent(int type, int frameworkDisconnectReason) {
+ logStaEvent(type, frameworkDisconnectReason, null);
+ }
+ /**
+ * Log a StaEvent from WifiStateMachine. The StaEvent must not be one of the supplicant
+ * generated event types, which are logged through 'sendMessage'
+ * @param type StaEvent.EventType describing the event
+ * @param frameworkDisconnectReason StaEvent.FrameworkDisconnectReason explaining why framework
+ * initiated a FRAMEWORK_DISCONNECT
+ * @param config WifiConfiguration for a framework initiated connection attempt
+ */
+ public void logStaEvent(int type, int frameworkDisconnectReason, WifiConfiguration config) {
+ switch (type) {
+ case StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL:
+ case StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST:
+ case StaEvent.TYPE_CMD_IP_REACHABILITY_LOST:
+ case StaEvent.TYPE_CMD_START_CONNECT:
+ case StaEvent.TYPE_CMD_START_ROAM:
+ case StaEvent.TYPE_CONNECT_NETWORK:
+ case StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK:
+ case StaEvent.TYPE_FRAMEWORK_DISCONNECT:
+ break;
+ default:
+ Log.e(TAG, "Unknown StaEvent:" + type);
+ return;
+ }
+ StaEvent event = new StaEvent();
+ event.type = type;
+ if (frameworkDisconnectReason != StaEvent.DISCONNECT_UNKNOWN) {
+ event.frameworkDisconnectReason = frameworkDisconnectReason;
+ }
+ event.configInfo = createConfigInfo(config);
+ addStaEvent(event);
+ }
+
+ private void addStaEvent(StaEvent staEvent) {
+ staEvent.startTimeMillis = mClock.getElapsedSinceBootMillis();
+ staEvent.lastRssi = mLastPollRssi;
+ staEvent.lastFreq = mLastPollFreq;
+ staEvent.lastLinkSpeed = mLastPollLinkSpeed;
+ staEvent.supplicantStateChangesBitmask = mSupplicantStateChangeBitmask;
+ mSupplicantStateChangeBitmask = 0;
+ mLastPollRssi = -127;
+ mLastPollFreq = -1;
+ mLastPollLinkSpeed = -1;
+ mStaEventList.add(staEvent);
+ // Prune StaEventList if it gets too long
+ if (mStaEventList.size() > MAX_STA_EVENTS) mStaEventList.remove();
+ }
+
+ private ConfigInfo createConfigInfo(WifiConfiguration config) {
+ if (config == null) return null;
+ ConfigInfo info = new ConfigInfo();
+ info.allowedKeyManagement = bitSetToInt(config.allowedKeyManagement);
+ info.allowedProtocols = bitSetToInt(config.allowedProtocols);
+ info.allowedAuthAlgorithms = bitSetToInt(config.allowedAuthAlgorithms);
+ info.allowedPairwiseCiphers = bitSetToInt(config.allowedPairwiseCiphers);
+ info.allowedGroupCiphers = bitSetToInt(config.allowedGroupCiphers);
+ info.hiddenSsid = config.hiddenSSID;
+ info.isPasspoint = config.isPasspoint();
+ info.isEphemeral = config.isEphemeral();
+ info.hasEverConnected = config.getNetworkSelectionStatus().getHasEverConnected();
+ ScanResult candidate = config.getNetworkSelectionStatus().getCandidate();
+ if (candidate != null) {
+ info.scanRssi = candidate.level;
+ info.scanFreq = candidate.frequency;
+ }
+ return info;
+ }
+
+ public Handler getHandler() {
+ return mHandler;
+ }
+
+ // Rather than generate a StaEvent for each SUPPLICANT_STATE_CHANGE, cache these in a bitmask
+ // and attach it to the next event which is generated.
+ private int mSupplicantStateChangeBitmask = 0;
+
+ /**
+ * Converts a SupplicantState value to a single bit, with position defined by
+ * {@code StaEvent.SupplicantState}
+ */
+ public static int supplicantStateToBit(SupplicantState state) {
+ switch(state) {
+ case DISCONNECTED:
+ return 1 << StaEvent.STATE_DISCONNECTED;
+ case INTERFACE_DISABLED:
+ return 1 << StaEvent.STATE_INTERFACE_DISABLED;
+ case INACTIVE:
+ return 1 << StaEvent.STATE_INACTIVE;
+ case SCANNING:
+ return 1 << StaEvent.STATE_SCANNING;
+ case AUTHENTICATING:
+ return 1 << StaEvent.STATE_AUTHENTICATING;
+ case ASSOCIATING:
+ return 1 << StaEvent.STATE_ASSOCIATING;
+ case ASSOCIATED:
+ return 1 << StaEvent.STATE_ASSOCIATED;
+ case FOUR_WAY_HANDSHAKE:
+ return 1 << StaEvent.STATE_FOUR_WAY_HANDSHAKE;
+ case GROUP_HANDSHAKE:
+ return 1 << StaEvent.STATE_GROUP_HANDSHAKE;
+ case COMPLETED:
+ return 1 << StaEvent.STATE_COMPLETED;
+ case DORMANT:
+ return 1 << StaEvent.STATE_DORMANT;
+ case UNINITIALIZED:
+ return 1 << StaEvent.STATE_UNINITIALIZED;
+ case INVALID:
+ return 1 << StaEvent.STATE_INVALID;
+ default:
+ Log.wtf(TAG, "Got unknown supplicant state: " + state.ordinal());
+ return 0;
+ }
+ }
+
+ private static String supplicantStateChangesBitmaskToString(int mask) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("SUPPLICANT_STATE_CHANGE_EVENTS: {");
+ if ((mask & (1 << StaEvent.STATE_DISCONNECTED)) > 0) sb.append(" DISCONNECTED");
+ if ((mask & (1 << StaEvent.STATE_INTERFACE_DISABLED)) > 0) sb.append(" INTERFACE_DISABLED");
+ if ((mask & (1 << StaEvent.STATE_INACTIVE)) > 0) sb.append(" INACTIVE");
+ if ((mask & (1 << StaEvent.STATE_SCANNING)) > 0) sb.append(" SCANNING");
+ if ((mask & (1 << StaEvent.STATE_AUTHENTICATING)) > 0) sb.append(" AUTHENTICATING");
+ if ((mask & (1 << StaEvent.STATE_ASSOCIATING)) > 0) sb.append(" ASSOCIATING");
+ if ((mask & (1 << StaEvent.STATE_ASSOCIATED)) > 0) sb.append(" ASSOCIATED");
+ if ((mask & (1 << StaEvent.STATE_FOUR_WAY_HANDSHAKE)) > 0) sb.append(" FOUR_WAY_HANDSHAKE");
+ if ((mask & (1 << StaEvent.STATE_GROUP_HANDSHAKE)) > 0) sb.append(" GROUP_HANDSHAKE");
+ if ((mask & (1 << StaEvent.STATE_COMPLETED)) > 0) sb.append(" COMPLETED");
+ if ((mask & (1 << StaEvent.STATE_DORMANT)) > 0) sb.append(" DORMANT");
+ if ((mask & (1 << StaEvent.STATE_UNINITIALIZED)) > 0) sb.append(" UNINITIALIZED");
+ if ((mask & (1 << StaEvent.STATE_INVALID)) > 0) sb.append(" INVALID");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Returns a human readable string from a Sta Event. Only adds information relevant to the event
+ * type.
+ */
+ public static String staEventToString(StaEvent event) {
+ if (event == null) return "<NULL>";
+ StringBuilder sb = new StringBuilder();
+ Long time = event.startTimeMillis;
+ sb.append(String.format("%9d ", time.longValue())).append(" ");
+ switch (event.type) {
+ case StaEvent.TYPE_ASSOCIATION_REJECTION_EVENT:
+ sb.append("ASSOCIATION_REJECTION_EVENT:")
+ .append(" timedOut=").append(event.associationTimedOut)
+ .append(" status=").append(event.status).append(":")
+ .append(ISupplicantStaIfaceCallback.StatusCode.toString(event.status));
+ break;
+ case StaEvent.TYPE_AUTHENTICATION_FAILURE_EVENT:
+ sb.append("AUTHENTICATION_FAILURE_EVENT: reason=").append(event.authFailureReason)
+ .append(":").append(authFailureReasonToString(event.authFailureReason));
+ break;
+ case StaEvent.TYPE_NETWORK_CONNECTION_EVENT:
+ sb.append("NETWORK_CONNECTION_EVENT:");
+ break;
+ case StaEvent.TYPE_NETWORK_DISCONNECTION_EVENT:
+ sb.append("NETWORK_DISCONNECTION_EVENT:")
+ .append(" local_gen=").append(event.localGen)
+ .append(" reason=").append(event.reason).append(":")
+ .append(ISupplicantStaIfaceCallback.ReasonCode.toString(
+ (event.reason >= 0 ? event.reason : -1 * event.reason)));
+ break;
+ case StaEvent.TYPE_CMD_ASSOCIATED_BSSID:
+ sb.append("CMD_ASSOCIATED_BSSID:");
+ break;
+ case StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL:
+ sb.append("CMD_IP_CONFIGURATION_SUCCESSFUL:");
+ break;
+ case StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST:
+ sb.append("CMD_IP_CONFIGURATION_LOST:");
+ break;
+ case StaEvent.TYPE_CMD_IP_REACHABILITY_LOST:
+ sb.append("CMD_IP_REACHABILITY_LOST:");
+ break;
+ case StaEvent.TYPE_CMD_TARGET_BSSID:
+ sb.append("CMD_TARGET_BSSID:");
+ break;
+ case StaEvent.TYPE_CMD_START_CONNECT:
+ sb.append("CMD_START_CONNECT:");
+ break;
+ case StaEvent.TYPE_CMD_START_ROAM:
+ sb.append("CMD_START_ROAM:");
+ break;
+ case StaEvent.TYPE_CONNECT_NETWORK:
+ sb.append("CONNECT_NETWORK:");
+ break;
+ case StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK:
+ sb.append("NETWORK_AGENT_VALID_NETWORK:");
+ break;
+ case StaEvent.TYPE_FRAMEWORK_DISCONNECT:
+ sb.append("FRAMEWORK_DISCONNECT:")
+ .append(" reason=")
+ .append(frameworkDisconnectReasonToString(event.frameworkDisconnectReason));
+ break;
+ default:
+ sb.append("UNKNOWN " + event.type + ":");
+ break;
+ }
+ if (event.lastRssi != -127) sb.append(" lastRssi=").append(event.lastRssi);
+ if (event.lastFreq != -1) sb.append(" lastFreq=").append(event.lastFreq);
+ if (event.lastLinkSpeed != -1) sb.append(" lastLinkSpeed=").append(event.lastLinkSpeed);
+ if (event.supplicantStateChangesBitmask != 0) {
+ sb.append("\n ").append(supplicantStateChangesBitmaskToString(
+ event.supplicantStateChangesBitmask));
+ }
+ if (event.configInfo != null) {
+ sb.append("\n ").append(configInfoToString(event.configInfo));
+ }
+
+ return sb.toString();
+ }
+
+ private static String authFailureReasonToString(int authFailureReason) {
+ switch (authFailureReason) {
+ case StaEvent.AUTH_FAILURE_NONE:
+ return "ERROR_AUTH_FAILURE_NONE";
+ case StaEvent.AUTH_FAILURE_TIMEOUT:
+ return "ERROR_AUTH_FAILURE_TIMEOUT";
+ case StaEvent.AUTH_FAILURE_WRONG_PSWD:
+ return "ERROR_AUTH_FAILURE_WRONG_PSWD";
+ case StaEvent.AUTH_FAILURE_EAP_FAILURE:
+ return "ERROR_AUTH_FAILURE_EAP_FAILURE";
+ default:
+ return "";
+ }
+ }
+
+ private static String frameworkDisconnectReasonToString(int frameworkDisconnectReason) {
+ switch (frameworkDisconnectReason) {
+ case StaEvent.DISCONNECT_API:
+ return "DISCONNECT_API";
+ case StaEvent.DISCONNECT_GENERIC:
+ return "DISCONNECT_GENERIC";
+ case StaEvent.DISCONNECT_UNWANTED:
+ return "DISCONNECT_UNWANTED";
+ case StaEvent.DISCONNECT_ROAM_WATCHDOG_TIMER:
+ return "DISCONNECT_ROAM_WATCHDOG_TIMER";
+ case StaEvent.DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST:
+ return "DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST";
+ case StaEvent.DISCONNECT_RESET_SIM_NETWORKS:
+ return "DISCONNECT_RESET_SIM_NETWORKS";
+ default:
+ return "DISCONNECT_UNKNOWN=" + frameworkDisconnectReason;
+ }
+ }
+
+ private static String configInfoToString(ConfigInfo info) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("ConfigInfo:")
+ .append(" allowed_key_management=").append(info.allowedKeyManagement)
+ .append(" allowed_protocols=").append(info.allowedProtocols)
+ .append(" allowed_auth_algorithms=").append(info.allowedAuthAlgorithms)
+ .append(" allowed_pairwise_ciphers=").append(info.allowedPairwiseCiphers)
+ .append(" allowed_group_ciphers=").append(info.allowedGroupCiphers)
+ .append(" hidden_ssid=").append(info.hiddenSsid)
+ .append(" is_passpoint=").append(info.isPasspoint)
+ .append(" is_ephemeral=").append(info.isEphemeral)
+ .append(" has_ever_connected=").append(info.hasEverConnected)
+ .append(" scan_rssi=").append(info.scanRssi)
+ .append(" scan_freq=").append(info.scanFreq);
+ return sb.toString();
+ }
+
+ public static final int MAX_STA_EVENTS = 512;
+ private LinkedList<StaEvent> mStaEventList = new LinkedList<StaEvent>();
+ private int mLastPollRssi = -127;
+ private int mLastPollLinkSpeed = -1;
+ private int mLastPollFreq = -1;
+
+ /**
+ * Converts the first 31 bits of a BitSet to a little endian int
+ */
+ private static int bitSetToInt(BitSet bits) {
+ int value = 0;
+ int nBits = bits.length() < 31 ? bits.length() : 31;
+ for (int i = 0; i < nBits; i++) {
+ value += bits.get(i) ? (1 << i) : 0;
+ }
+ return value;
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index d90962157..eaac5560a 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -114,6 +114,7 @@ import com.android.server.wifi.hotspot2.PasspointManager;
import com.android.server.wifi.hotspot2.Utils;
import com.android.server.wifi.hotspot2.WnmData;
import com.android.server.wifi.nano.WifiMetricsProto;
+import com.android.server.wifi.nano.WifiMetricsProto.StaEvent;
import com.android.server.wifi.p2p.WifiP2pServiceImpl;
import com.android.server.wifi.util.NativeUtil;
import com.android.server.wifi.util.TelephonyUtil;
@@ -1072,6 +1073,21 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.WPS_SUCCESS_EVENT, getHandler());
mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.WPS_TIMEOUT_EVENT, getHandler());
+ mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.ASSOCIATION_REJECTION_EVENT,
+ mWifiMetrics.getHandler());
+ mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
+ mWifiMetrics.getHandler());
+ mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.NETWORK_CONNECTION_EVENT,
+ mWifiMetrics.getHandler());
+ mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.NETWORK_DISCONNECTION_EVENT,
+ mWifiMetrics.getHandler());
+ mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT,
+ mWifiMetrics.getHandler());
+ mWifiMonitor.registerHandler(mInterfaceName, CMD_ASSOCIATED_BSSID,
+ mWifiMetrics.getHandler());
+ mWifiMonitor.registerHandler(mInterfaceName, CMD_TARGET_BSSID,
+ mWifiMetrics.getHandler());
+
final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
@@ -1103,12 +1119,14 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
@Override
public void onProvisioningSuccess(LinkProperties newLp) {
+ mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL);
sendMessage(CMD_UPDATE_LINKPROPERTIES, newLp);
sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL);
}
@Override
public void onProvisioningFailure(LinkProperties newLp) {
+ mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST);
sendMessage(CMD_IP_CONFIGURATION_LOST);
}
@@ -1119,6 +1137,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
@Override
public void onReachabilityLost(String logMsg) {
+ mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_IP_REACHABILITY_LOST);
sendMessage(CMD_IP_REACHABILITY_LOST, logMsg);
}
@@ -2884,10 +2903,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
if (newRssi > 0) newRssi -= 256;
mWifiInfo.setRssi(newRssi);
/*
- * Log the rssi poll value in metrics
- */
- mWifiMetrics.incrementRssiPollRssiCount(newRssi);
- /*
* Rather then sending the raw RSSI out every time it
* changes, we precalculate the signal level that would
* be displayed in the status bar, and only send the
@@ -2921,6 +2936,12 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
mWifiInfo.setFrequency(newFrequency);
}
mWifiConfigManager.updateScanDetailCacheFromWifiInfo(mWifiInfo);
+ /*
+ * Increment various performance metrics
+ */
+ if (newRssi != null && newLinkSpeed != null && newFrequency != null) {
+ mWifiMetrics.handlePollResult(mWifiInfo);
+ }
}
// Polling has completed, hence we wont have a score anymore
@@ -4818,6 +4839,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
break;
case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
if (message.arg1 == 1) {
+ mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
+ StaEvent.DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST);
mWifiNative.disconnect();
mTemporarilyDisconnectWifi = true;
} else {
@@ -4913,6 +4936,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
WifiConfiguration.NetworkSelectionStatus
.DISABLED_AUTHENTICATION_NO_CREDENTIALS);
}
+ mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
+ StaEvent.DISCONNECT_GENERIC);
mWifiNative.disconnect();
}
break;
@@ -4972,6 +4997,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
reportConnectionAttemptStart(config, mTargetRoamBSSID,
WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED);
if (mWifiNative.connectToNetwork(config)) {
+ mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_START_CONNECT, config);
lastConnectAttemptTimestamp = mClock.getWallClockMillis();
targetWificonfiguration = config;
mIsAutoRoaming = false;
@@ -5039,6 +5065,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
WifiManager.NOT_AUTHORIZED);
break;
}
+ mWifiMetrics.logStaEvent(StaEvent.TYPE_CONNECT_NETWORK, config);
broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
break;
@@ -5332,6 +5359,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
log("WifiNetworkAgent -> Wifi networkStatus valid, score= "
+ Integer.toString(mWifiInfo.score));
}
+ mWifiMetrics.logStaEvent(StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK);
doNetworkStatus(status);
}
}
@@ -5594,11 +5622,15 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
break;
case CMD_DISCONNECT:
+ mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
+ StaEvent.DISCONNECT_UNKNOWN);
mWifiNative.disconnect();
transitionTo(mDisconnectingState);
break;
case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
if (message.arg1 == 1) {
+ mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
+ StaEvent.DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST);
mWifiNative.disconnect();
mTemporarilyDisconnectWifi = true;
transitionTo(mDisconnectingState);
@@ -5731,6 +5763,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
WifiConfiguration config =
mWifiConfigManager.getConfiguredNetwork(mLastNetworkId);
if (TelephonyUtil.isSimConfig(config)) {
+ mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
+ StaEvent.DISCONNECT_RESET_SIM_NETWORKS);
mWifiNative.disconnect();
transitionTo(mDisconnectingState);
}
@@ -5946,6 +5980,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
WifiMetricsProto.ConnectionEvent.HLF_NONE);
mRoamFailCount++;
handleNetworkDisconnect();
+ mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
+ StaEvent.DISCONNECT_ROAM_WATCHDOG_TIMER);
mWifiNative.disconnect();
transitionTo(mDisconnectedState);
}
@@ -6060,6 +6096,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
switch (message.what) {
case CMD_UNWANTED_NETWORK:
if (message.arg1 == NETWORK_STATUS_UNWANTED_DISCONNECT) {
+ mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
+ StaEvent.DISCONNECT_UNWANTED);
mWifiNative.disconnect();
transitionTo(mDisconnectingState);
} else if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN ||
@@ -6202,6 +6240,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
lastConnectAttemptTimestamp = mClock.getWallClockMillis();
targetWificonfiguration = config;
mIsAutoRoaming = true;
+ mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_START_ROAM, config);
transitionTo(mRoamingState);
} else {
loge("CMD_START_ROAM Failed to start roaming to network " + config);
@@ -6315,6 +6354,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
class DisconnectedState extends State {
@Override
public void enter() {
+ Log.i(TAG, "disconnectedstate enter");
// We dont scan frequently if this is a temporary disconnect
// due to p2p
if (mTemporarilyDisconnectWifi) {
@@ -6387,6 +6427,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
break;
case CMD_DISCONNECT:
+ mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
+ StaEvent.DISCONNECT_UNKNOWN);
mWifiNative.disconnect();
break;
/* Ignore network disconnect */