diff options
author | Glen Kuhne <kuh@google.com> | 2016-01-04 13:50:09 -0800 |
---|---|---|
committer | Glen Kuhne <kuh@google.com> | 2016-01-20 15:17:27 -0800 |
commit | 1b067831bbff14f8e7a99b927b69f714d1b03448 (patch) | |
tree | 3fee821102f27727bd5c5daa150adc13ee42c366 /service/java | |
parent | 8e14dcb9dc38149b4672eceb3fe22287ea4343a0 (diff) | |
download | android_frameworks_opt_net_wifi-1b067831bbff14f8e7a99b927b69f714d1b03448.tar.gz android_frameworks_opt_net_wifi-1b067831bbff14f8e7a99b927b69f714d1b03448.tar.bz2 android_frameworks_opt_net_wifi-1b067831bbff14f8e7a99b927b69f714d1b03448.zip |
Wifi Metrics, Initial Commit
Created WifiMetrics class to log wireless metrics.
Dumps Metrics as Base64 wifi.proto, with dumpsys option 'proto'.
Implements SOME metric collection from wifi service
Bug: 25691077
Change-Id: I28a745b5f66dd1d38868b7eadd79882fd2c5c5a2
Diffstat (limited to 'service/java')
3 files changed, 572 insertions, 42 deletions
diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java new file mode 100644 index 000000000..723c51485 --- /dev/null +++ b/service/java/com/android/server/wifi/WifiMetrics.java @@ -0,0 +1,453 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wifi; + +import android.net.wifi.WifiInfo; +import android.os.SystemClock; +import android.util.Base64; +import android.util.SparseArray; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; + +/** + * Provides storage for wireless connectivity metrics, as they are generated. + * Metrics logged by this class include: + * Aggregated connection stats (num of connections, num of failures, ...) + * Discrete connection event stats (time, duration, failure codes, ...) + * Router details (technology type, authentication type, ...) + * Scan stats + */ +public class WifiMetrics { + private static final String TAG = "WifiMetrics"; + private final Object mLock = new Object(); + /** + * Metrics are stored within an instance of the WifiLog proto during runtime, + * The ConnectionEvent, SystemStateEntries & ScanReturnEntries metrics are stored during + * runtime in member lists of this WifiMetrics class, with the final WifiLog proto being pieced + * together at dump-time + */ + private final WifiMetricsProto.WifiLog mWifiLogProto; + /** + * Session information that gets logged for every Wifi connection attempt. + */ + private final List<ConnectionEvent> mConnectionEventList; + /** + * The latest started (but un-ended) connection attempt + */ + private ConnectionEvent mCurrentConnectionEvent; + /** + * Count of number of times each scan return code, indexed by WifiLog.ScanReturnCode + */ + private final SparseArray<WifiMetricsProto.WifiLog.ScanReturnEntry> mScanReturnEntries; + /** + * Mapping of system state to the counts of scans requested in that wifi state * screenOn + * combination. Indexed by WifiLog.WifiState * (1 + screenOn) + */ + private final SparseArray<WifiMetricsProto.WifiLog.WifiSystemStateEntry> + mWifiSystemStateEntries; + + class RouterFingerPrint { + private WifiMetricsProto.RouterFingerPrint mRouterFingerPrintProto; + + public RouterFingerPrint(int roamType, + int channelInfo, + int dtim, + int authentication, + boolean hidden, + int routerTechnology, + boolean supportsIpv6) { + mRouterFingerPrintProto = new WifiMetricsProto.RouterFingerPrint(); + mRouterFingerPrintProto.roamType = roamType; + mRouterFingerPrintProto.channelInfo = channelInfo; + mRouterFingerPrintProto.dtim = dtim; + mRouterFingerPrintProto.authentication = authentication; + mRouterFingerPrintProto.hidden = hidden; + mRouterFingerPrintProto.routerTechnology = routerTechnology; + mRouterFingerPrintProto.supportsIpv6 = supportsIpv6; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + synchronized (mLock) { + sb.append("mConnectionEvent.roamType=" + mRouterFingerPrintProto.roamType); + sb.append(", mChannelInfo=" + mRouterFingerPrintProto.channelInfo); + sb.append(", mDtim=" + mRouterFingerPrintProto.dtim); + sb.append(", mAuthentication=" + mRouterFingerPrintProto.authentication); + sb.append(", mHidden=" + mRouterFingerPrintProto.hidden); + sb.append(", mRouterTechnology=" + mRouterFingerPrintProto.routerTechnology); + sb.append(", mSupportsIpv6=" + mRouterFingerPrintProto.supportsIpv6); + } + return sb.toString(); + } + } + + /** + * Log event, tracking the start time, end time and result of a wireless connection attempt. + */ + class ConnectionEvent { + WifiMetricsProto.ConnectionEvent mConnectionEvent; + RouterFingerPrint mRouterFingerPrint; + private long mRealStartTime; + /** + * Bitset tracking the capture completeness of this connection event bit 1='Event started', + * bit 2='Event ended' value = 3 for capture completeness + */ + private int mEventCompleteness; + private long mRealEndTime; + + private ConnectionEvent() { + mConnectionEvent = new WifiMetricsProto.ConnectionEvent(); + mConnectionEvent.startTimeMillis = -1; + mRealEndTime = -1; + mConnectionEvent.durationTakenToConnectMillis = -1; + mRouterFingerPrint = new RouterFingerPrint(0, 0, 0, 0, false, 0, false); + mConnectionEvent.signalStrength = -1; + mConnectionEvent.roamType = WifiMetricsProto.ConnectionEvent.ROAM_UNKNOWN; + mConnectionEvent.connectionResult = -1; + mConnectionEvent.level2FailureCode = -1; + mConnectionEvent.connectivityLevelFailureCode = + WifiMetricsProto.ConnectionEvent.HLF_UNKNOWN; + mConnectionEvent.automaticBugReportTaken = false; + mEventCompleteness = 0; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("startTime="); + Calendar c = Calendar.getInstance(); + synchronized (mLock) { + c.setTimeInMillis(mConnectionEvent.startTimeMillis); + sb.append(mConnectionEvent.startTimeMillis == 0 ? " <null>" : + String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); + sb.append(", endTime="); + c.setTimeInMillis(mRealEndTime); + sb.append(mRealEndTime == 0 ? " <null>" : + String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); + sb.append(", durationTakenToConnectMillis="); + sb.append(mConnectionEvent.durationTakenToConnectMillis); + sb.append(", level2FailureCode="); + sb.append(mConnectionEvent.level2FailureCode); + sb.append(", connectivityLevelFailureCode="); + sb.append(mConnectionEvent.connectivityLevelFailureCode); + sb.append(", mEventCompleteness="); + sb.append(mEventCompleteness); + sb.append("\n "); + sb.append("mRouterFingerprint:\n "); + sb.append(mRouterFingerPrint.toString()); + } + return sb.toString(); + } + } + + public WifiMetrics() { + mWifiLogProto = new WifiMetricsProto.WifiLog(); + mConnectionEventList = new ArrayList<>(); + mCurrentConnectionEvent = null; + mScanReturnEntries = new SparseArray<WifiMetricsProto.WifiLog.ScanReturnEntry>(); + mWifiSystemStateEntries = new SparseArray<WifiMetricsProto.WifiLog.WifiSystemStateEntry>(); + } + + /** + * Create a new connection event. Call when wifi attempts to make a new network connection + * If there is a current 'un-ended' connection event, it will be ended with UNKNOWN connectivity + * failure code. + * Gathers and sets the RouterFingerPrint data as well + * + * @param wifiInfo WifiInfo for the current connection attempt, used for connection metrics + * @param roamType Roam type that caused connection attempt, see WifiMetricsProto.WifiLog.ROAM_X + */ + public void startConnectionEvent(WifiInfo wifiInfo, int roamType) { + synchronized (mLock) { + mCurrentConnectionEvent = new ConnectionEvent(); + mCurrentConnectionEvent.mEventCompleteness |= 1; + mCurrentConnectionEvent.mConnectionEvent.startTimeMillis = System.currentTimeMillis(); + mCurrentConnectionEvent.mConnectionEvent.roamType = roamType; + //<TODO> Get actual routerfingerprint metrics, not these placeholders + mCurrentConnectionEvent.mRouterFingerPrint = new RouterFingerPrint( + WifiMetricsProto.RouterFingerPrint.ROAM_TYPE_UNKNOWN, //TODO + -1, //mChannelInfo TODO + -1, //Dtim TODO + WifiMetricsProto.RouterFingerPrint.AUTH_UNKNOWN, //TODO + false, //mHidden TODO + WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_UNKNOWN, //TODO + false //mSupportsIpv6 TODO + ); + if (wifiInfo != null) { + mCurrentConnectionEvent.mConnectionEvent.signalStrength = wifiInfo.getRssi(); + } + mCurrentConnectionEvent.mRealStartTime = SystemClock.elapsedRealtime(); + mConnectionEventList.add(mCurrentConnectionEvent); + } + } + + public void startConnectionEvent(WifiInfo wifiInfo) { + startConnectionEvent(wifiInfo, WifiMetricsProto.ConnectionEvent.ROAM_NONE); + } + + /** + * End a Connection event record. Call when wifi connection attempt succeeds or fails. + * If a Connection event has not been started and is active when .end is called, a new one is + * created with zero duration. + * + * @param level2FailureCode Level 2 failure code returned by supplicant + * @param connectivityFailureCode WifiMetricsProto.ConnectionEvent.HLF_X + */ + public void endConnectionEvent(int level2FailureCode, int connectivityFailureCode) { + synchronized (mLock) { + if (mCurrentConnectionEvent == null) { + //No currentConnectionEvent exists, create an 'un-started' one, and End it + mCurrentConnectionEvent = new ConnectionEvent(); + mConnectionEventList.add(mCurrentConnectionEvent); + } + mCurrentConnectionEvent.mEventCompleteness |= 2; + mCurrentConnectionEvent.mRealEndTime = SystemClock.elapsedRealtime(); + mCurrentConnectionEvent.mConnectionEvent.durationTakenToConnectMillis = (int) + (mCurrentConnectionEvent.mRealEndTime - mCurrentConnectionEvent.mRealStartTime); + mCurrentConnectionEvent.mConnectionEvent.level2FailureCode = level2FailureCode; + mCurrentConnectionEvent.mConnectionEvent.connectivityLevelFailureCode = + connectivityFailureCode; + //ConnectionEvent already added to ConnectionEvents List + mCurrentConnectionEvent = null; + } + } + + void setNumSavedNetworks(int num) { + synchronized (mLock) { + mWifiLogProto.numSavedNetworks = num; + } + } + + void setNumOpenNetworks(int num) { + synchronized (mLock) { + mWifiLogProto.numOpenNetworks = num; + } + } + + void setNumPersonalNetworks(int num) { + synchronized (mLock) { + mWifiLogProto.numPersonalNetworks = num; + } + } + + void setNumEnterpriseNetworks(int num) { + synchronized (mLock) { + mWifiLogProto.numEnterpriseNetworks = num; + } + } + + void setNumNetworksAddedByUser(int num) { + synchronized (mLock) { + mWifiLogProto.numNetworksAddedByUser = num; + } + } + + void setNumNetworksAddedByApps(int num) { + synchronized (mLock) { + mWifiLogProto.numNetworksAddedByApps = num; + } + } + + void setIsLocationEnabled(boolean enabled) { + synchronized (mLock) { + mWifiLogProto.isLocationEnabled = enabled; + } + } + + void setIsScanningAlwaysEnabled(boolean enabled) { + synchronized (mLock) { + mWifiLogProto.isScanningAlwaysEnabled = enabled; + } + } + + /** + * Increment Airplane mode toggle count + */ + public void incrementAirplaneToggleCount() { + synchronized (mLock) { + mWifiLogProto.numWifiToggledViaAirplane++; + } + } + + /** + * Increment Wifi Toggle count + */ + public void incrementWifiToggleCount() { + synchronized (mLock) { + mWifiLogProto.numWifiToggledViaSettings++; + } + } + + /** + * Increment Non Empty Scan Results count + */ + public void incrementNonEmptyScanResultCount() { + synchronized (mLock) { + mWifiLogProto.numNonEmptyScanResults++; + } + } + + /** + * Increment Empty Scan Results count + */ + public void incrementEmptyScanResultCount() { + synchronized (mLock) { + mWifiLogProto.numEmptyScanResults++; + } + } + + /** + * Increment count of scan return code occurrence + * + * @param scanReturnCode Return code from scan attempt WifiMetricsProto.WifiLog.SCAN_X + */ + public void incrementScanReturnEntry(int scanReturnCode) { + synchronized (mLock) { + WifiMetricsProto.WifiLog.ScanReturnEntry entry = mScanReturnEntries.get(scanReturnCode); + if (entry == null) { + entry = new WifiMetricsProto.WifiLog.ScanReturnEntry(); + entry.scanReturnCode = scanReturnCode; + entry.scanResultsCount = 0; + } + entry.scanResultsCount++; + mScanReturnEntries.put(scanReturnCode, entry); + } + } + + /** + * Increments the count of scans initiated by each wifi state, accounts for screenOn/Off + * + * @param state State of the system when scan was initiated, see WifiMetricsProto.WifiLog.WIFI_X + * @param screenOn Is the screen on + */ + public void incrementWifiSystemScanStateCount(int state, boolean screenOn) { + synchronized (mLock) { + int index = state * (screenOn ? 2 : 1); + WifiMetricsProto.WifiLog.WifiSystemStateEntry entry = + mWifiSystemStateEntries.get(index); + if (entry == null) { + entry = new WifiMetricsProto.WifiLog.WifiSystemStateEntry(); + entry.wifiState = state; + entry.wifiStateCount = 0; + entry.isScreenOn = screenOn; + } + entry.wifiStateCount++; + mWifiSystemStateEntries.put(state, entry); + } + } + + /** + * Dump all WifiMetrics. Collects some metrics from ConfigStore, Settings and WifiManager + * at this time + * + * @param fd unused + * @param pw PrintWriter for writing dump to + * @param args unused + */ + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + synchronized (mLock) { + pw.println("WifiMetrics:"); + if (args.length > 0 && "proto".equals(args[0])) { + //Dump serialized WifiLog proto + consolidateProto(true); + for (ConnectionEvent event : mConnectionEventList) { + if (mCurrentConnectionEvent != event) { + //indicate that automatic bug report has been taken for all valid + //connection events + event.mConnectionEvent.automaticBugReportTaken = true; + } + } + byte[] wifiMetricsProto = WifiMetricsProto.WifiLog.toByteArray(mWifiLogProto); + String metricsProtoDump = Base64.encodeToString(wifiMetricsProto, Base64.DEFAULT); + pw.println(metricsProtoDump); + pw.println("EndWifiMetrics"); + } else { + pw.println("mConnectionEvents:"); + for (ConnectionEvent event : mConnectionEventList) { + String eventLine = event.toString(); + if (event == mCurrentConnectionEvent) { + eventLine += "CURRENTLY OPEN EVENT"; + } + pw.println(eventLine); + } + pw.println("mWifiLogProto.numSavedNetworks=" + mWifiLogProto.numSavedNetworks); + pw.println("mWifiLogProto.numOpenNetworks=" + mWifiLogProto.numOpenNetworks); + pw.println("mWifiLogProto.numPersonalNetworks=" + + mWifiLogProto.numPersonalNetworks); + pw.println("mWifiLogProto.numEnterpriseNetworks=" + + mWifiLogProto.numEnterpriseNetworks); + pw.println("mWifiLogProto.isLocationEnabled=" + mWifiLogProto.isLocationEnabled); + pw.println("mWifiLogProto.isScanningAlwaysEnabled=" + + mWifiLogProto.isScanningAlwaysEnabled); + pw.println("mWifiLogProto.numWifiToggledViaSettings=" + + mWifiLogProto.numWifiToggledViaSettings); + pw.println("mWifiLogProto.numWifiToggledViaAirplane=" + + mWifiLogProto.numWifiToggledViaAirplane); + pw.println("mWifiLogProto.numNetworksAddedByUser=" + + mWifiLogProto.numNetworksAddedByUser); + //TODO - Pending scanning refactor + pw.println("mWifiLogProto.numNetworksAddedByApps=" + "<TODO>"); + pw.println("mWifiLogProto.numNonEmptyScanResults=" + "<TODO>"); + pw.println("mWifiLogProto.numEmptyScanResults=" + "<TODO>"); + pw.println("mWifiLogProto.numOneshotScans=" + "<TODO>"); + pw.println("mWifiLogProto.numBackgroundScans=" + "<TODO>"); + pw.println("mScanReturnEntries:" + " <TODO>"); + pw.println("mSystemStateEntries:" + " <TODO>"); + } + } + } + + /** + * Assign the separate ConnectionEvent, SystemStateEntry and ScanReturnCode lists to their + * respective lists within mWifiLogProto, and clear the original lists managed here. + * + * @param incremental Only include ConnectionEvents created since last automatic bug report + */ + private void consolidateProto(boolean incremental) { + List<WifiMetricsProto.ConnectionEvent> events = new ArrayList<>(); + synchronized (mLock) { + for (ConnectionEvent event : mConnectionEventList) { + if (!incremental || ((mCurrentConnectionEvent != event) + && !event.mConnectionEvent.automaticBugReportTaken)) { + //<TODO> Revisit logic on when to mark connection events + // as 'automaticBugreportTaken'</TODO> + //Get all ConnectionEvents that haven not been dumped as a proto, also exclude + //the current active un-ended connection event + events.add(event.mConnectionEvent); + } + } + if (events.size() > 0) { + mWifiLogProto.connectionEvent = events.toArray(mWifiLogProto.connectionEvent); + } + //<TODO> SystemStateEntry and ScanReturnCode list consolidation + } + } + + /** + * Serializes all of WifiMetrics to WifiLog proto, and returns the byte array. + * Does not count as taking an automatic bug report + * + * @return byte array of the deserialized & consolidated Proto + */ + public byte[] toByteArray() { + consolidateProto(false); + return mWifiLogProto.toByteArray(mWifiLogProto); + } +} diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java index aca2ba74f..9c88936ef 100644 --- a/service/java/com/android/server/wifi/WifiServiceImpl.java +++ b/service/java/com/android/server/wifi/WifiServiceImpl.java @@ -155,7 +155,8 @@ public class WifiServiceImpl extends IWifiManager.Stub { private WifiTrafficPoller mTrafficPoller; /* Tracks the persisted states for wi-fi & airplane mode */ final WifiSettingsStore mSettingsStore; - + /* Logs connection events and some general router and scan stats */ + private final WifiMetrics mWifiMetrics; /** * Asynchronous channel to WifiStateMachine */ @@ -320,14 +321,14 @@ public class WifiServiceImpl extends IWifiManager.Stub { public WifiServiceImpl(Context context) { mContext = context; - FrameworkFacade facade = new FrameworkFacade(); - HandlerThread wifiThread = new HandlerThread("WifiService"); wifiThread.start(); + mWifiMetrics = new WifiMetrics(); mTrafficPoller = new WifiTrafficPoller(mContext, wifiThread.getLooper(), WifiNative.getWlanNativeInterface().getInterfaceName()); - mWifiStateMachine = new WifiStateMachine(mContext, mTrafficPoller, facade); + mWifiStateMachine = new WifiStateMachine(mContext, mTrafficPoller, facade, mWifiMetrics); + mSettingsStore = new WifiSettingsStore(mContext); mWifiStateMachine.enableRssiPolling(true); mBatteryStats = BatteryStatsService.getService(); mPowerManager = context.getSystemService(PowerManager.class); @@ -335,7 +336,7 @@ public class WifiServiceImpl extends IWifiManager.Stub { mUserManager = UserManager.get(mContext); mNotificationController = new WifiNotificationController(mContext, mWifiStateMachine); - mSettingsStore = new WifiSettingsStore(mContext); + mClientHandler = new ClientHandler(wifiThread.getLooper()); mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper()); diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java index 5c5c93024..bb9bcbd46 100644 --- a/service/java/com/android/server/wifi/WifiStateMachine.java +++ b/service/java/com/android/server/wifi/WifiStateMachine.java @@ -16,6 +16,17 @@ package com.android.server.wifi; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; +import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; +import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; +import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; +import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; +import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; + import android.Manifest; import android.app.ActivityManager; import android.app.AlarmManager; @@ -122,17 +133,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Pattern; -import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; -import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; -import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; -import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; -import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; -import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; -import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; -import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; -import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; -import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; - /** * TODO: * Deprecate WIFI_STATE_UNKNOWN @@ -188,6 +188,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno Log.d(getName(), s); } + private WifiMetrics mWifiMetrics; private WifiMonitor mWifiMonitor; private WifiNative mWifiNative; private WifiConfigStore mWifiConfigStore; @@ -231,7 +232,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno private boolean mEnableAssociatedNetworkSwitchingInDevSettings = true; private boolean mHalBasedPnoEnableInDevSettings = false; - private int mHalFeatureSet = 0; private static int mPnoResultFound = 0; @@ -1139,8 +1139,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno private FrameworkFacade mFacade; public WifiStateMachine(Context context, WifiTrafficPoller trafficPoller, - FrameworkFacade facade) { + FrameworkFacade facade, WifiMetrics wifiMetrics) { super("WifiStateMachine"); + mWifiMetrics = wifiMetrics; mContext = context; mFacade = facade; mWifiNative = WifiNative.getWlanNativeInterface(); @@ -2714,7 +2715,12 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno } else { pw.println("mUntrustedNetworkFactory is not initialized"); } - + pw.println(); + updateWifiMetrics(); + mWifiMetrics.dump(fd, pw, args); + pw.println(); + mNetworkFactory.dump(fd, pw, args); + mUntrustedNetworkFactory.dump(fd, pw, args); pw.println(); mWifiConfigStore.dump(fd, pw, args); @@ -3932,11 +3938,15 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno synchronized (mScanResultCache) { mScanResults = scanResults; mNumScanResultsReturned = mScanResults.size(); - for (ScanDetail resultDetail : mScanResults) { mScanResultCache.put(resultDetail.getNetworkDetail(), resultDetail); } } + if (mNumScanResultsReturned > 0) { + mWifiMetrics.incrementNonEmptyScanResultCount(); + } else { + mWifiMetrics.incrementEmptyScanResultCount(); + } mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false); @@ -4798,26 +4808,26 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno && stateChangeResult.wifiSsid != null) { String SSID = stateChangeResult.wifiSsid.toString(); String currentSSID = mWifiInfo.getSSID(); - if (SSID != null - && currentSSID != null - && !SSID.equals(WifiSsid.NONE)) { - // Remove quote before comparing - if (SSID.length() >= 2 && SSID.charAt(0) == '"' - && SSID.charAt(SSID.length() - 1) == '"') - { - SSID = SSID.substring(1, SSID.length() - 1); - } - if (currentSSID.length() >= 2 && currentSSID.charAt(0) == '"' - && currentSSID.charAt(currentSSID.length() - 1) == '"') { - currentSSID = currentSSID.substring(1, currentSSID.length() - 1); - } - if ((!SSID.equals(currentSSID)) && (getCurrentState() == mConnectedState)) { - lastConnectAttemptTimestamp = System.currentTimeMillis(); - targetWificonfiguration - = mWifiConfigStore.getWifiConfiguration(mWifiInfo.getNetworkId()); - transitionTo(mRoamingState); - } - } + if (SSID != null && currentSSID != null && !SSID.equals(WifiSsid.NONE)) { + // Remove quote before comparing + if (SSID.length() >= 2 && SSID.charAt(0) == '"' + && SSID.charAt(SSID.length() - 1) == '"') { + SSID = SSID.substring(1, SSID.length() - 1); + } + if (currentSSID.length() >= 2 && currentSSID.charAt(0) == '"' + && currentSSID.charAt(currentSSID.length() - 1) == '"') { + currentSSID = currentSSID.substring(1, currentSSID.length() - 1); + } + if ((!SSID.equals(currentSSID)) && (getCurrentState() == mConnectedState)) { + lastConnectAttemptTimestamp = System.currentTimeMillis(); + //Create new connection event for connection attempt. + mWifiMetrics.startConnectionEvent(mWifiInfo, + WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE); + targetWificonfiguration = + mWifiConfigStore.getWifiConfiguration(mWifiInfo.getNetworkId()); + transitionTo(mRoamingState); + } + } } mWifiInfo.setSSID(stateChangeResult.wifiSsid); @@ -4985,7 +4995,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true); mWifiNative.setPowerSave(true); - mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY, WifiP2pServiceImpl.DISABLED); + mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY, + WifiP2pServiceImpl.DISABLED); // Set the coexistence mode back to its default value mWifiNative.setBluetoothCoexistenceMode( @@ -7160,7 +7171,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno // Remember time of last connection attempt lastConnectAttemptTimestamp = System.currentTimeMillis(); - + //Create clearcut connection event of type USER_SELECTED + mWifiMetrics.startConnectionEvent(mWifiInfo, + WifiMetricsProto.ConnectionEvent.ROAM_USER_SELECTED); mWifiConnectionStatistics.numWifiManagerJoinAttempt++; // As a courtesy to the caller, trigger a scan now @@ -7204,6 +7217,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno mWifiQualifiedNetworkSelector.enableNetworkByUser(config); // Remember time of last connection attempt lastConnectAttemptTimestamp = System.currentTimeMillis(); + mWifiMetrics.startConnectionEvent(mWifiInfo, + WifiMetricsProto.ConnectionEvent.ROAM_USER_SELECTED); + mWifiConnectionStatistics.numWifiManagerJoinAttempt++; } // Cancel auto roam requests mTargetNetworkId = netId; @@ -7355,6 +7371,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno break; case CMD_REASSOCIATE: lastConnectAttemptTimestamp = System.currentTimeMillis(); + mWifiMetrics.startConnectionEvent(mWifiInfo); mWifiNative.reassociate(); break; case CMD_RELOAD_TLS_AND_RECONNECT: @@ -7362,6 +7379,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno logd("Reconnecting to give a chance to un-connected TLS networks"); mWifiNative.disconnect(); lastConnectAttemptTimestamp = System.currentTimeMillis(); + mWifiMetrics.startConnectionEvent(mWifiInfo); mWifiNative.reconnect(); } break; @@ -7444,6 +7462,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ false, lastConnectUid) && mWifiNative.reconnect()) { lastConnectAttemptTimestamp = System.currentTimeMillis(); + mWifiMetrics.startConnectionEvent(mWifiInfo, + WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED); targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); config = mWifiConfigStore.getWifiConfiguration(netId); if (config != null @@ -7604,6 +7624,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ true, message.sendingUid) && mWifiNative.reconnect()) { lastConnectAttemptTimestamp = System.currentTimeMillis(); + mWifiMetrics.startConnectionEvent(mWifiInfo, + WifiMetricsProto.ConnectionEvent.ROAM_USER_SELECTED); targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); /* The state tracker handles enabling networks upon completion/failure */ @@ -8128,12 +8150,15 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno } log("DHCP failure count=" + count); } + mWifiMetrics.endConnectionEvent(0, + WifiMetricsProto.ConnectionEvent.HLF_DHCP); handleIPv4Failure(DhcpStateMachine.DHCP_FAILURE); // As above, we transition to mDisconnectingState via updateLinkProperties. } break; case CMD_IP_CONFIGURATION_SUCCESSFUL: handleSuccessfulIpConfiguration(); + mWifiMetrics.endConnectionEvent(0, WifiMetricsProto.ConnectionEvent.HLF_NONE); sendConnectedState(); transitionTo(mConnectedState); break; @@ -9036,6 +9061,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno } if (ret) { lastConnectAttemptTimestamp = System.currentTimeMillis(); + mWifiMetrics.startConnectionEvent(mWifiInfo); targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); // replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); @@ -9257,6 +9283,10 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno break; /* Ignore network disconnect */ case WifiMonitor.NETWORK_DISCONNECTION_EVENT: + // Interpret this as an L2 connection failure + // End current connection event and log L2 reason code. + mWifiMetrics.endConnectionEvent(message.arg2, + WifiMetricsProto.ConnectionEvent.HLF_UNKNOWN); break; case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: StateChangeResult stateChangeResult = (StateChangeResult) message.obj; @@ -9480,6 +9510,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno mSourceMessage.recycle(); mSourceMessage = null; transitionTo(mDisconnectedState); + mWifiMetrics.endConnectionEvent( + message.arg1, WifiMetricsProto.ConnectionEvent.HLF_UNKNOWN); } else { if (DBG) log("Ignore unspecified fail event during WPS connection"); } @@ -10118,4 +10150,48 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno || reason == 23 // IEEE_802_1X_AUTH_FAILED || reason == 34; // DISASSOC_LOW_ACK } + + /** + * Update WifiMetrics before dumping + */ + void updateWifiMetrics() { + int numSavedNetworks = mWifiConfigStore.getConfiguredNetworksSize(); + int numOpenNetworks = 0; + int numPersonalNetworks = 0; + int numEnterpriseNetworks = 0; + int numNetworksAddedByUser = 0; + int numNetworksAddedByApps = 0; + for (WifiConfiguration config : mWifiConfigStore.getConfiguredNetworks()) { + if (config.allowedAuthAlgorithms.get(WifiConfiguration.AuthAlgorithm.OPEN)) { + numOpenNetworks++; + } else if (config.isEnterprise()) { + numEnterpriseNetworks++; + } else { + numPersonalNetworks++; + } + if (config.selfAdded) { + numNetworksAddedByUser++; + } else { + numNetworksAddedByApps++; + } + } + mWifiMetrics.setNumSavedNetworks(numSavedNetworks); + mWifiMetrics.setNumOpenNetworks(numOpenNetworks); + mWifiMetrics.setNumPersonalNetworks(numPersonalNetworks); + mWifiMetrics.setNumEnterpriseNetworks(numEnterpriseNetworks); + mWifiMetrics.setNumNetworksAddedByUser(numNetworksAddedByUser); + mWifiMetrics.setNumNetworksAddedByApps(numNetworksAddedByApps); + + /* <TODO> decide how to access WifiServiecImpl.isLocationEnabled() or if to do it manually + mWifiMetrics.setIsLocationEnabled(Settings.Secure.getInt( + mContext.getContentResolver(), + Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF) + != Settings.Secure.LOCATION_MODE_OFF); + */ + + /* <TODO> decide how statemachine will access WifiSettingsStore + mWifiMetrics.setIsScanningAlwaysEnabled(mSettingsStore.isScanningAlwaysAvailable()); + */ + } } + |