WifiMetrics.java revision 947e55415eab3989f2f5cede0c03745cf9268309
11b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne/*
21b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne * Copyright (C) 2016 The Android Open Source Project
31b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne *
41b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne * Licensed under the Apache License, Version 2.0 (the "License");
51b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne * you may not use this file except in compliance with the License.
61b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne * You may obtain a copy of the License at
71b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne *
81b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne *      http://www.apache.org/licenses/LICENSE-2.0
91b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne *
101b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne * Unless required by applicable law or agreed to in writing, software
111b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne * distributed under the License is distributed on an "AS IS" BASIS,
121b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne * See the License for the specific language governing permissions and
141b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne * limitations under the License.
151b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne */
161b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
171b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhnepackage com.android.server.wifi;
181b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
192532a24b254d724a9b6771d327dc410b32b18602Glen Kuhneimport android.net.wifi.WifiConfiguration;
201b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhneimport android.net.wifi.WifiInfo;
211b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhneimport android.os.SystemClock;
221b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhneimport android.util.Base64;
231b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhneimport android.util.SparseArray;
241b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
251b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhneimport java.io.FileDescriptor;
261b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhneimport java.io.PrintWriter;
271b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhneimport java.util.ArrayList;
281b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhneimport java.util.Calendar;
291b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhneimport java.util.List;
301b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
311b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne/**
321b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne * Provides storage for wireless connectivity metrics, as they are generated.
331b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne * Metrics logged by this class include:
341b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne *   Aggregated connection stats (num of connections, num of failures, ...)
351b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne *   Discrete connection event stats (time, duration, failure codes, ...)
361b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne *   Router details (technology type, authentication type, ...)
371b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne *   Scan stats
381b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne */
391b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhnepublic class WifiMetrics {
401b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    private static final String TAG = "WifiMetrics";
411b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    private final Object mLock = new Object();
422532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne    private static final int MAX_CONNECTION_EVENTS = 256;
431b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    /**
441b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * Metrics are stored within an instance of the WifiLog proto during runtime,
451b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * The ConnectionEvent, SystemStateEntries & ScanReturnEntries metrics are stored during
461b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * runtime in member lists of this WifiMetrics class, with the final WifiLog proto being pieced
471b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * together at dump-time
481b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     */
491b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    private final WifiMetricsProto.WifiLog mWifiLogProto;
501b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    /**
511b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * Session information that gets logged for every Wifi connection attempt.
521b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     */
531b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    private final List<ConnectionEvent> mConnectionEventList;
541b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    /**
551b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * The latest started (but un-ended) connection attempt
561b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     */
571b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    private ConnectionEvent mCurrentConnectionEvent;
581b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    /**
591b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * Count of number of times each scan return code, indexed by WifiLog.ScanReturnCode
601b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     */
611b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    private final SparseArray<WifiMetricsProto.WifiLog.ScanReturnEntry> mScanReturnEntries;
621b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    /**
631b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * Mapping of system state to the counts of scans requested in that wifi state * screenOn
641b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * combination. Indexed by WifiLog.WifiState * (1 + screenOn)
651b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     */
661b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    private final SparseArray<WifiMetricsProto.WifiLog.WifiSystemStateEntry>
671b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            mWifiSystemStateEntries;
681b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
691b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    class RouterFingerPrint {
701b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        private WifiMetricsProto.RouterFingerPrint mRouterFingerPrintProto;
712532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        RouterFingerPrint() {
721b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            mRouterFingerPrintProto = new WifiMetricsProto.RouterFingerPrint();
731b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
741b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
751b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        public String toString() {
761b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            StringBuilder sb = new StringBuilder();
771b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            synchronized (mLock) {
781b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append("mConnectionEvent.roamType=" + mRouterFingerPrintProto.roamType);
791b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append(", mChannelInfo=" + mRouterFingerPrintProto.channelInfo);
801b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append(", mDtim=" + mRouterFingerPrintProto.dtim);
811b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append(", mAuthentication=" + mRouterFingerPrintProto.authentication);
821b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append(", mHidden=" + mRouterFingerPrintProto.hidden);
831b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append(", mRouterTechnology=" + mRouterFingerPrintProto.routerTechnology);
841b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append(", mSupportsIpv6=" + mRouterFingerPrintProto.supportsIpv6);
851b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            }
861b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            return sb.toString();
871b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
882532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        public void updateFromWifiConfiguration(WifiConfiguration config) {
892532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne            if (config != null) {
902532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                /*<TODO>
912532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mRouterFingerPrintProto.roamType
922532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mRouterFingerPrintProto.routerTechnology
932532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mRouterFingerPrintProto.supportsIpv6
942532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                */
952532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                if (config.allowedAuthAlgorithms != null
962532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                        && config.allowedAuthAlgorithms.get(WifiConfiguration.AuthAlgorithm.OPEN)) {
972532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                    mRouterFingerPrintProto.authentication =
982532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                            WifiMetricsProto.RouterFingerPrint.AUTH_OPEN;
992532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                } else if (config.isEnterprise()) {
1002532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                    mRouterFingerPrintProto.authentication =
1012532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                            WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE;
1022532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                } else {
1032532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                    mRouterFingerPrintProto.authentication =
1042532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                            WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL;
1052532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                }
1062532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mRouterFingerPrintProto.hidden = config.hiddenSSID;
1072532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mRouterFingerPrintProto.channelInfo = config.apChannel;
108947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne                // Config may not have a valid dtimInterval set yet, in which case dtim will be zero
109947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne                // (These are only populated from beacon frame scan results, which are returned as
110947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne                // scan results from the chip far less frequently than Probe-responses)
111947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne                if (config.dtimInterval > 0) {
112947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne                    mRouterFingerPrintProto.dtim = config.dtimInterval;
113947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne                }
1142532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne            }
1152532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        }
1161b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
1171b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
1181b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    /**
1191b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * Log event, tracking the start time, end time and result of a wireless connection attempt.
1201b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     */
1211b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    class ConnectionEvent {
1221b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        WifiMetricsProto.ConnectionEvent mConnectionEvent;
1231b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        RouterFingerPrint mRouterFingerPrint;
1241b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        private long mRealStartTime;
1251b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        /**
1261b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne         * Bitset tracking the capture completeness of this connection event bit 1='Event started',
1271b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne         * bit 2='Event ended' value = 3 for capture completeness
1281b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne         */
1291b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        private int mEventCompleteness;
1301b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        private long mRealEndTime;
1311b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
1322532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        //<TODO> Move these constants into a wifi.proto Enum
1332532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        // Level 2 Failure Codes
1342532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        // Failure is unknown
1352532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        public static final int LLF_UNKNOWN = 0;
1362532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        // NONE
1372532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        public static final int LLF_NONE = 1;
1382532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        // ASSOCIATION_REJECTION_EVENT
1392532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        public static final int LLF_ASSOCIATION_REJECTION = 2;
1402532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        // AUTHENTICATION_FAILURE_EVENT
1412532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        public static final int LLF_AUTHENTICATION_FAILURE = 3;
1422532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        // SSID_TEMP_DISABLED (Also Auth failure)
1432532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        public static final int LLF_SSID_TEMP_DISABLED = 4;
1442532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        // CONNECT_NETWORK_FAILED
1452532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        public static final int LLF_CONNECT_NETWORK_FAILED = 5;
1462532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        // NETWORK_DISCONNECTION_EVENT
1472532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        public static final int LLF_NETWORK_DISCONNECTION = 6;
1482532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne
1491b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        private ConnectionEvent() {
1501b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            mConnectionEvent = new WifiMetricsProto.ConnectionEvent();
151947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne            mRealEndTime = 0;
152947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne            mRealStartTime = 0;
153947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne            mEventCompleteness = 0;
1542532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne            mRouterFingerPrint = new RouterFingerPrint();
1552532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne            mConnectionEvent.routerFingerprint = mRouterFingerPrint.mRouterFingerPrintProto;
1561b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
1571b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
1581b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        public String toString() {
1591b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            StringBuilder sb = new StringBuilder();
1601b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            sb.append("startTime=");
1611b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            Calendar c = Calendar.getInstance();
1621b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            synchronized (mLock) {
1631b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                c.setTimeInMillis(mConnectionEvent.startTimeMillis);
1641b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append(mConnectionEvent.startTimeMillis == 0 ? "            <null>" :
1651b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                        String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
1661b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append(", endTime=");
1671b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                c.setTimeInMillis(mRealEndTime);
1681b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append(mRealEndTime == 0 ? "            <null>" :
1691b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                        String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
1701b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append(", durationTakenToConnectMillis=");
1711b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append(mConnectionEvent.durationTakenToConnectMillis);
1722532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                sb.append(", roamType=");
1732532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                switch(mConnectionEvent.roamType){
1742532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                    case 1:
1752532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                        sb.append("ROAM_NONE");
1762532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                        break;
1772532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                    case 2:
1782532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                        sb.append("ROAM_DBDC");
1792532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                        break;
1802532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                    case 3:
1812532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                        sb.append("ROAM_ENTERPRISE");
1822532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                        break;
1832532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                    case 4:
1842532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                        sb.append("ROAM_USER_SELECTED");
1852532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                        break;
1862532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                    case 5:
1872532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                        sb.append("ROAM_UNRELATED");
1882532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                        break;
1892532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                    default:
1902532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                        sb.append("ROAM_UNKNOWN");
1912532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                }
1921b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append(", level2FailureCode=");
1931b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append(mConnectionEvent.level2FailureCode);
1941b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append(", connectivityLevelFailureCode=");
1951b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append(mConnectionEvent.connectivityLevelFailureCode);
1961b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append(", mEventCompleteness=");
1971b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append(mEventCompleteness);
1981b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append("\n  ");
1992532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                sb.append("mRouterFingerprint: ");
2001b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                sb.append(mRouterFingerPrint.toString());
2011b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            }
2021b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            return sb.toString();
2031b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
2041b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
2051b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
2061b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    public WifiMetrics() {
2071b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        mWifiLogProto = new WifiMetricsProto.WifiLog();
2081b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        mConnectionEventList = new ArrayList<>();
2091b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        mCurrentConnectionEvent = null;
2101b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        mScanReturnEntries = new SparseArray<WifiMetricsProto.WifiLog.ScanReturnEntry>();
2111b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        mWifiSystemStateEntries = new SparseArray<WifiMetricsProto.WifiLog.WifiSystemStateEntry>();
2121b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
2131b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
2141b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    /**
2151b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * Create a new connection event. Call when wifi attempts to make a new network connection
2161b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * If there is a current 'un-ended' connection event, it will be ended with UNKNOWN connectivity
2171b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * failure code.
2181b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * Gathers and sets the RouterFingerPrint data as well
2191b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     *
2201b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * @param wifiInfo WifiInfo for the current connection attempt, used for connection metrics
221947e55415eab3989f2f5cede0c03745cf9268309Glen Kuhne     * @param config WifiConfiguration of the config used for the current connection attempt
2221b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * @param roamType Roam type that caused connection attempt, see WifiMetricsProto.WifiLog.ROAM_X
2231b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     */
2242532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne    public void startConnectionEvent(WifiInfo wifiInfo, WifiConfiguration config, int roamType) {
2251b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        synchronized (mLock) {
2262532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne            if (mConnectionEventList.size() <= MAX_CONNECTION_EVENTS) {
2272532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mCurrentConnectionEvent = new ConnectionEvent();
2282532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mCurrentConnectionEvent.mEventCompleteness |= 1;
2292532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mCurrentConnectionEvent.mConnectionEvent.startTimeMillis =
2302532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                        System.currentTimeMillis();
2312532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mCurrentConnectionEvent.mConnectionEvent.roamType = roamType;
2322532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mCurrentConnectionEvent.mRouterFingerPrint.updateFromWifiConfiguration(config);
2332532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                if (wifiInfo != null) {
2342532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                    mCurrentConnectionEvent.mConnectionEvent.signalStrength = wifiInfo.getRssi();
2352532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                }
2362532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mCurrentConnectionEvent.mRealStartTime = SystemClock.elapsedRealtime();
2372532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mConnectionEventList.add(mCurrentConnectionEvent);
2381b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            }
2391b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
2401b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
2411b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
2421b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    public void startConnectionEvent(WifiInfo wifiInfo) {
2432532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        startConnectionEvent(wifiInfo, null, WifiMetricsProto.ConnectionEvent.ROAM_NONE);
2441b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
2451b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
2461b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    /**
2472532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne     * set the RoamType of the current ConnectionEvent (if any)
2482532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne     */
2492532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne    public void setConnectionEventRoamType(int roamType) {
2502532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        if (mCurrentConnectionEvent != null) {
2512532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne            mCurrentConnectionEvent.mConnectionEvent.roamType = roamType;
2522532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        }
2532532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne    }
2542532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne    /**
2551b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * End a Connection event record. Call when wifi connection attempt succeeds or fails.
2561b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * If a Connection event has not been started and is active when .end is called, a new one is
2571b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * created with zero duration.
2581b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     *
2591b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * @param level2FailureCode Level 2 failure code returned by supplicant
2601b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * @param connectivityFailureCode WifiMetricsProto.ConnectionEvent.HLF_X
2611b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     */
2621b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    public void endConnectionEvent(int level2FailureCode, int connectivityFailureCode) {
2631b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        synchronized (mLock) {
2642532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne            if (mCurrentConnectionEvent != null) {
2652532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                boolean result = (level2FailureCode == 1)
2662532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                        && (connectivityFailureCode == WifiMetricsProto.ConnectionEvent.HLF_NONE);
2672532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mCurrentConnectionEvent.mConnectionEvent.connectionResult = result ? 1 : 0;
2682532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mCurrentConnectionEvent.mEventCompleteness |= 2;
2692532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mCurrentConnectionEvent.mRealEndTime = SystemClock.elapsedRealtime();
2702532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mCurrentConnectionEvent.mConnectionEvent.durationTakenToConnectMillis = (int)
2712532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                        (mCurrentConnectionEvent.mRealEndTime
2722532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                        - mCurrentConnectionEvent.mRealStartTime);
2732532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mCurrentConnectionEvent.mConnectionEvent.level2FailureCode = level2FailureCode;
2742532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mCurrentConnectionEvent.mConnectionEvent.connectivityLevelFailureCode =
2752532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                        connectivityFailureCode;
2762532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                //ConnectionEvent already added to ConnectionEvents List
2772532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mCurrentConnectionEvent = null;
2781b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            }
2791b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
2801b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
2811b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
2821b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    void setNumSavedNetworks(int num) {
2831b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        synchronized (mLock) {
2841b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            mWifiLogProto.numSavedNetworks = num;
2851b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
2861b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
2871b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
2881b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    void setNumOpenNetworks(int num) {
2891b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        synchronized (mLock) {
2901b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            mWifiLogProto.numOpenNetworks = num;
2911b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
2921b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
2931b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
2941b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    void setNumPersonalNetworks(int num) {
2951b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        synchronized (mLock) {
2961b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            mWifiLogProto.numPersonalNetworks = num;
2971b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
2981b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
2991b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
3001b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    void setNumEnterpriseNetworks(int num) {
3011b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        synchronized (mLock) {
3021b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            mWifiLogProto.numEnterpriseNetworks = num;
3031b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
3041b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
3051b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
3061b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    void setNumNetworksAddedByUser(int num) {
3071b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        synchronized (mLock) {
3081b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            mWifiLogProto.numNetworksAddedByUser = num;
3091b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
3101b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
3111b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
3121b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    void setNumNetworksAddedByApps(int num) {
3131b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        synchronized (mLock) {
3141b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            mWifiLogProto.numNetworksAddedByApps = num;
3151b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
3161b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
3171b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
3181b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    void setIsLocationEnabled(boolean enabled) {
3191b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        synchronized (mLock) {
3201b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            mWifiLogProto.isLocationEnabled = enabled;
3211b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
3221b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
3231b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
3241b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    void setIsScanningAlwaysEnabled(boolean enabled) {
3251b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        synchronized (mLock) {
3261b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            mWifiLogProto.isScanningAlwaysEnabled = enabled;
3271b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
3281b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
3291b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
3301b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    /**
3311b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * Increment Airplane mode toggle count
3321b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     */
3331b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    public void incrementAirplaneToggleCount() {
3341b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        synchronized (mLock) {
3351b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            mWifiLogProto.numWifiToggledViaAirplane++;
3361b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
3371b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
3381b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
3391b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    /**
3401b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * Increment Wifi Toggle count
3411b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     */
3421b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    public void incrementWifiToggleCount() {
3431b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        synchronized (mLock) {
3441b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            mWifiLogProto.numWifiToggledViaSettings++;
3451b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
3461b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
3471b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
3481b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    /**
3491b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * Increment Non Empty Scan Results count
3501b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     */
3511b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    public void incrementNonEmptyScanResultCount() {
3521b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        synchronized (mLock) {
3531b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            mWifiLogProto.numNonEmptyScanResults++;
3541b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
3551b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
3561b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
3571b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    /**
3581b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * Increment Empty Scan Results count
3591b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     */
3601b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    public void incrementEmptyScanResultCount() {
3611b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        synchronized (mLock) {
3621b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            mWifiLogProto.numEmptyScanResults++;
3631b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
3641b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
3651b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
3661b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    /**
3671b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * Increment count of scan return code occurrence
3681b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     *
3691b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * @param scanReturnCode Return code from scan attempt WifiMetricsProto.WifiLog.SCAN_X
3701b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     */
3711b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    public void incrementScanReturnEntry(int scanReturnCode) {
3721b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        synchronized (mLock) {
3731b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            WifiMetricsProto.WifiLog.ScanReturnEntry entry = mScanReturnEntries.get(scanReturnCode);
3741b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            if (entry == null) {
3751b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                entry = new WifiMetricsProto.WifiLog.ScanReturnEntry();
3761b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                entry.scanReturnCode = scanReturnCode;
3771b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                entry.scanResultsCount = 0;
3781b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            }
3791b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            entry.scanResultsCount++;
3801b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            mScanReturnEntries.put(scanReturnCode, entry);
3811b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
3821b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
3831b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
3841b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    /**
3851b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * Increments the count of scans initiated by each wifi state, accounts for screenOn/Off
3861b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     *
3871b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * @param state State of the system when scan was initiated, see WifiMetricsProto.WifiLog.WIFI_X
3881b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * @param screenOn Is the screen on
3891b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     */
3901b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    public void incrementWifiSystemScanStateCount(int state, boolean screenOn) {
3911b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        synchronized (mLock) {
3921b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            int index = state * (screenOn ? 2 : 1);
3931b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            WifiMetricsProto.WifiLog.WifiSystemStateEntry entry =
3941b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                    mWifiSystemStateEntries.get(index);
3951b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            if (entry == null) {
3961b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                entry = new WifiMetricsProto.WifiLog.WifiSystemStateEntry();
3971b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                entry.wifiState = state;
3981b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                entry.wifiStateCount = 0;
3991b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                entry.isScreenOn = screenOn;
4001b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            }
4011b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            entry.wifiStateCount++;
4021b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            mWifiSystemStateEntries.put(state, entry);
4031b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
4041b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
4051b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
40611638f348ba45f9f417928e79b81186cef76c561Glen Kuhne    public static final String PROTO_DUMP_ARG = "wifiMetricsProto";
4071b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    /**
4081b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * Dump all WifiMetrics. Collects some metrics from ConfigStore, Settings and WifiManager
4091b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * at this time
4101b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     *
4111b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * @param fd unused
4121b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * @param pw PrintWriter for writing dump to
4131b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * @param args unused
4141b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     */
4151b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
4161b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        synchronized (mLock) {
4171b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            pw.println("WifiMetrics:");
41811638f348ba45f9f417928e79b81186cef76c561Glen Kuhne            if (args.length > 0 && PROTO_DUMP_ARG.equals(args[0])) {
4191b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                //Dump serialized WifiLog proto
4201b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                consolidateProto(true);
4211b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                for (ConnectionEvent event : mConnectionEventList) {
4221b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                    if (mCurrentConnectionEvent != event) {
4231b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                        //indicate that automatic bug report has been taken for all valid
4241b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                        //connection events
4251b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                        event.mConnectionEvent.automaticBugReportTaken = true;
4261b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                    }
4271b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                }
4281b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                byte[] wifiMetricsProto = WifiMetricsProto.WifiLog.toByteArray(mWifiLogProto);
4291b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                String metricsProtoDump = Base64.encodeToString(wifiMetricsProto, Base64.DEFAULT);
4301b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                pw.println(metricsProtoDump);
4311b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                pw.println("EndWifiMetrics");
4322532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                clear();
4331b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            } else {
4341b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                pw.println("mConnectionEvents:");
4351b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                for (ConnectionEvent event : mConnectionEventList) {
4361b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                    String eventLine = event.toString();
4371b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                    if (event == mCurrentConnectionEvent) {
4381b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                        eventLine += "CURRENTLY OPEN EVENT";
4391b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                    }
4401b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                    pw.println(eventLine);
4411b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                }
4421b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                pw.println("mWifiLogProto.numSavedNetworks=" + mWifiLogProto.numSavedNetworks);
4431b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                pw.println("mWifiLogProto.numOpenNetworks=" + mWifiLogProto.numOpenNetworks);
4441b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                pw.println("mWifiLogProto.numPersonalNetworks="
4451b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                        + mWifiLogProto.numPersonalNetworks);
4461b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                pw.println("mWifiLogProto.numEnterpriseNetworks="
4471b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                        + mWifiLogProto.numEnterpriseNetworks);
4481b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                pw.println("mWifiLogProto.isLocationEnabled=" + mWifiLogProto.isLocationEnabled);
4491b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                pw.println("mWifiLogProto.isScanningAlwaysEnabled="
4501b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                        + mWifiLogProto.isScanningAlwaysEnabled);
4511b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                pw.println("mWifiLogProto.numWifiToggledViaSettings="
4521b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                        + mWifiLogProto.numWifiToggledViaSettings);
4531b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                pw.println("mWifiLogProto.numWifiToggledViaAirplane="
4541b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                        + mWifiLogProto.numWifiToggledViaAirplane);
4551b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                pw.println("mWifiLogProto.numNetworksAddedByUser="
4561b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                        + mWifiLogProto.numNetworksAddedByUser);
4571b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                //TODO - Pending scanning refactor
4581b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                pw.println("mWifiLogProto.numNetworksAddedByApps=" + "<TODO>");
4591b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                pw.println("mWifiLogProto.numNonEmptyScanResults=" + "<TODO>");
4601b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                pw.println("mWifiLogProto.numEmptyScanResults=" + "<TODO>");
4611b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                pw.println("mWifiLogProto.numOneshotScans=" + "<TODO>");
4621b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                pw.println("mWifiLogProto.numBackgroundScans=" + "<TODO>");
4631b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                pw.println("mScanReturnEntries:" + " <TODO>");
4641b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                pw.println("mSystemStateEntries:" + " <TODO>");
4651b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            }
4661b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
4671b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
4681b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
4691b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    /**
4701b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * Assign the separate ConnectionEvent, SystemStateEntry and ScanReturnCode lists to their
4711b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * respective lists within mWifiLogProto, and clear the original lists managed here.
4721b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     *
4731b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * @param incremental Only include ConnectionEvents created since last automatic bug report
4741b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     */
4751b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    private void consolidateProto(boolean incremental) {
4761b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        List<WifiMetricsProto.ConnectionEvent> events = new ArrayList<>();
4771b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        synchronized (mLock) {
4781b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            for (ConnectionEvent event : mConnectionEventList) {
4791b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                if (!incremental || ((mCurrentConnectionEvent != event)
4801b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                        && !event.mConnectionEvent.automaticBugReportTaken)) {
4811b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                    //Get all ConnectionEvents that haven not been dumped as a proto, also exclude
4821b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                    //the current active un-ended connection event
4831b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                    events.add(event.mConnectionEvent);
4842532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                    event.mConnectionEvent.automaticBugReportTaken = true;
4851b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                }
4861b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            }
4871b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            if (events.size() > 0) {
4881b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne                mWifiLogProto.connectionEvent = events.toArray(mWifiLogProto.connectionEvent);
4891b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            }
4901b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne            //<TODO> SystemStateEntry and ScanReturnCode list consolidation
4911b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        }
4921b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
4931b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne
4941b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    /**
4951b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * Serializes all of WifiMetrics to WifiLog proto, and returns the byte array.
4961b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * Does not count as taking an automatic bug report
4971b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     *
4981b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     * @return byte array of the deserialized & consolidated Proto
4991b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne     */
5001b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    public byte[] toByteArray() {
5011b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        consolidateProto(false);
5021b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne        return mWifiLogProto.toByteArray(mWifiLogProto);
5031b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne    }
5042532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne
5052532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne    /**
5062532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne     * Clear all WifiMetrics, except for currentConnectionEvent.
5072532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne     */
5082532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne    private void clear() {
5092532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        synchronized (mLock) {
5102532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne            mConnectionEventList.clear();
5112532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne            if (mCurrentConnectionEvent != null) {
5122532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne                mConnectionEventList.add(mCurrentConnectionEvent);
5132532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne            }
5142532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne            mScanReturnEntries.clear();
5152532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne            mWifiSystemStateEntries.clear();
5162532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne            mWifiLogProto.clear();
5172532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne        }
5182532a24b254d724a9b6771d327dc410b32b18602Glen Kuhne    }
5191b067831bbff14f8e7a99b927b69f714d1b03448Glen Kuhne}
520