Home | History | Annotate | Download | only in aware
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.wifi.aware;
     18 
     19 import android.hardware.wifi.V1_0.NanStatusType;
     20 import android.net.wifi.aware.WifiAwareNetworkSpecifier;
     21 import android.text.TextUtils;
     22 import android.util.Log;
     23 import android.util.SparseArray;
     24 import android.util.SparseIntArray;
     25 
     26 import com.android.internal.annotations.VisibleForTesting;
     27 import com.android.server.wifi.Clock;
     28 import com.android.server.wifi.nano.WifiMetricsProto;
     29 import com.android.server.wifi.util.MetricsUtils;
     30 
     31 import java.io.FileDescriptor;
     32 import java.io.PrintWriter;
     33 import java.util.Collections;
     34 import java.util.HashMap;
     35 import java.util.HashSet;
     36 import java.util.Map;
     37 import java.util.Set;
     38 
     39 /**
     40  * Wi-Fi Aware metric container/processor.
     41  */
     42 public class WifiAwareMetrics {
     43     private static final String TAG = "WifiAwareMetrics";
     44     private static final boolean VDBG = false;
     45     /* package */ boolean mDbg = false;
     46 
     47     // Histogram: 8 buckets (i=0, ..., 7) of 9 slots in range 10^i -> 10^(i+1)
     48     // Buckets:
     49     //    1 -> 10: 9 @ 1
     50     //    10 -> 100: 9 @ 10
     51     //    100 -> 1000: 9 @ 10^2
     52     //    10^3 -> 10^4: 9 @ 10^3
     53     //    10^4 -> 10^5: 9 @ 10^4
     54     //    10^5 -> 10^6: 9 @ 10^5
     55     //    10^6 -> 10^7: 9 @ 10^6
     56     //    10^7 -> 10^8: 9 @ 10^7 --> 10^8 ms -> 10^5s -> 28 hours
     57     private static final MetricsUtils.LogHistParms DURATION_LOG_HISTOGRAM =
     58             new MetricsUtils.LogHistParms(0, 1, 10, 9, 8);
     59 
     60     // Histogram for ranging limits in discovery. Indicates the following 5 buckets (in meters):
     61     //   < 10
     62     //   [10, 30)
     63     //   [30, 60)
     64     //   [60, 100)
     65     //   >= 100
     66     private static final int[] RANGING_LIMIT_METERS = { 10, 30, 60, 100 };
     67 
     68     private final Object mLock = new Object();
     69     private final Clock mClock;
     70 
     71     // enableUsage/disableUsage data
     72     private long mLastEnableUsageMs = 0;
     73     private long mLastEnableUsageInThisSampleWindowMs = 0;
     74     private long mAvailableTimeMs = 0;
     75     private SparseIntArray mHistogramAwareAvailableDurationMs = new SparseIntArray();
     76 
     77     // enabled data
     78     private long mLastEnableAwareMs = 0;
     79     private long mLastEnableAwareInThisSampleWindowMs = 0;
     80     private long mEnabledTimeMs = 0;
     81     private SparseIntArray mHistogramAwareEnabledDurationMs = new SparseIntArray();
     82 
     83     // attach data
     84     private static class AttachData {
     85         boolean mUsesIdentityCallback; // do any attach sessions of the UID use identity callback
     86         int mMaxConcurrentAttaches;
     87     }
     88     private Map<Integer, AttachData> mAttachDataByUid = new HashMap<>();
     89     private SparseIntArray mAttachStatusData = new SparseIntArray();
     90     private SparseIntArray mHistogramAttachDuration = new SparseIntArray();
     91 
     92     // discovery data
     93     private int mMaxPublishInApp = 0;
     94     private int mMaxSubscribeInApp = 0;
     95     private int mMaxDiscoveryInApp = 0;
     96     private int mMaxPublishInSystem = 0;
     97     private int mMaxSubscribeInSystem = 0;
     98     private int mMaxDiscoveryInSystem = 0;
     99     private SparseIntArray mPublishStatusData = new SparseIntArray();
    100     private SparseIntArray mSubscribeStatusData = new SparseIntArray();
    101     private SparseIntArray mHistogramPublishDuration = new SparseIntArray();
    102     private SparseIntArray mHistogramSubscribeDuration = new SparseIntArray();
    103     private Set<Integer> mAppsWithDiscoverySessionResourceFailure = new HashSet<>();
    104 
    105     // discovery with ranging data
    106     private int mMaxPublishWithRangingInApp = 0;
    107     private int mMaxSubscribeWithRangingInApp = 0;
    108     private int mMaxPublishWithRangingInSystem = 0;
    109     private int mMaxSubscribeWithRangingInSystem = 0;
    110     private SparseIntArray mHistogramSubscribeGeofenceMin = new SparseIntArray();
    111     private SparseIntArray mHistogramSubscribeGeofenceMax = new SparseIntArray();
    112     private int mNumSubscribesWithRanging = 0;
    113     private int mNumMatchesWithRanging = 0;
    114     private int mNumMatchesWithoutRangingForRangingEnabledSubscribes = 0;
    115 
    116     // data-path (NDI/NDP) data
    117     private int mMaxNdiInApp = 0;
    118     private int mMaxNdpInApp = 0;
    119     private int mMaxSecureNdpInApp = 0;
    120     private int mMaxNdiInSystem = 0;
    121     private int mMaxNdpInSystem = 0;
    122     private int mMaxSecureNdpInSystem = 0;
    123     private int mMaxNdpPerNdi = 0;
    124     private SparseIntArray mInBandNdpStatusData = new SparseIntArray();
    125     private SparseIntArray mOutOfBandNdpStatusData = new SparseIntArray();
    126 
    127     private SparseIntArray mNdpCreationTimeDuration = new SparseIntArray();
    128     private long mNdpCreationTimeMin = -1;
    129     private long mNdpCreationTimeMax = 0;
    130     private long mNdpCreationTimeSum = 0;
    131     private long mNdpCreationTimeSumSq = 0;
    132     private long mNdpCreationTimeNumSamples = 0;
    133 
    134     private SparseIntArray mHistogramNdpDuration = new SparseIntArray();
    135 
    136     public WifiAwareMetrics(Clock clock) {
    137         mClock = clock;
    138     }
    139 
    140     /**
    141      * Push usage stats for WifiAwareStateMachine.enableUsage() to
    142      * histogram_aware_available_duration_ms.
    143      */
    144     public void recordEnableUsage() {
    145         synchronized (mLock) {
    146             if (mLastEnableUsageMs != 0) {
    147                 Log.w(TAG, "enableUsage: mLastEnableUsage*Ms initialized!?");
    148             }
    149             mLastEnableUsageMs = mClock.getElapsedSinceBootMillis();
    150             mLastEnableUsageInThisSampleWindowMs = mLastEnableUsageMs;
    151         }
    152     }
    153 
    154     /**
    155      * Push usage stats for WifiAwareStateMachine.disableUsage() to
    156      * histogram_aware_available_duration_ms.
    157      */
    158 
    159     public void recordDisableUsage() {
    160         synchronized (mLock) {
    161             if (mLastEnableUsageMs == 0) {
    162                 Log.e(TAG, "disableUsage: mLastEnableUsage not initialized!?");
    163                 return;
    164             }
    165 
    166             long now = mClock.getElapsedSinceBootMillis();
    167             MetricsUtils.addValueToLogHistogram(now - mLastEnableUsageMs,
    168                     mHistogramAwareAvailableDurationMs, DURATION_LOG_HISTOGRAM);
    169             mAvailableTimeMs += now - mLastEnableUsageInThisSampleWindowMs;
    170             mLastEnableUsageMs = 0;
    171             mLastEnableUsageInThisSampleWindowMs = 0;
    172         }
    173     }
    174 
    175     /**
    176      * Push usage stats of Aware actually being enabled on-the-air: start
    177      */
    178     public void recordEnableAware() {
    179         synchronized (mLock) {
    180             if (mLastEnableAwareMs != 0) {
    181                 return; // already enabled
    182             }
    183             mLastEnableAwareMs = mClock.getElapsedSinceBootMillis();
    184             mLastEnableAwareInThisSampleWindowMs = mLastEnableAwareMs;
    185         }
    186     }
    187 
    188     /**
    189      * Push usage stats of Aware actually being enabled on-the-air: stop (disable)
    190      */
    191     public void recordDisableAware() {
    192         synchronized (mLock) {
    193             if (mLastEnableAwareMs == 0) {
    194                 return; // already disabled
    195             }
    196 
    197             long now = mClock.getElapsedSinceBootMillis();
    198             MetricsUtils.addValueToLogHistogram(now - mLastEnableAwareMs,
    199                     mHistogramAwareEnabledDurationMs, DURATION_LOG_HISTOGRAM);
    200             mEnabledTimeMs += now - mLastEnableAwareInThisSampleWindowMs;
    201             mLastEnableAwareMs = 0;
    202             mLastEnableAwareInThisSampleWindowMs = 0;
    203         }
    204     }
    205 
    206     /**
    207      * Push information about a new attach session.
    208      */
    209     public void recordAttachSession(int uid, boolean usesIdentityCallback,
    210             SparseArray<WifiAwareClientState> clients) {
    211         // count the number of clients with the specific uid
    212         int currentConcurrentCount = 0;
    213         for (int i = 0; i < clients.size(); ++i) {
    214             if (clients.valueAt(i).getUid() == uid) {
    215                 ++currentConcurrentCount;
    216             }
    217         }
    218 
    219         synchronized (mLock) {
    220             AttachData data = mAttachDataByUid.get(uid);
    221             if (data == null) {
    222                 data = new AttachData();
    223                 mAttachDataByUid.put(uid, data);
    224             }
    225             data.mUsesIdentityCallback |= usesIdentityCallback;
    226             data.mMaxConcurrentAttaches = Math.max(data.mMaxConcurrentAttaches,
    227                     currentConcurrentCount);
    228             recordAttachStatus(NanStatusType.SUCCESS);
    229         }
    230     }
    231 
    232     /**
    233      * Push information about a new attach session status (recorded when attach session is created).
    234      */
    235     public void recordAttachStatus(int status) {
    236         synchronized (mLock) {
    237             mAttachStatusData.put(status, mAttachStatusData.get(status) + 1);
    238         }
    239     }
    240 
    241     /**
    242      * Push duration information of an attach session.
    243      */
    244     public void recordAttachSessionDuration(long creationTime) {
    245         synchronized (mLock) {
    246             MetricsUtils.addValueToLogHistogram(mClock.getElapsedSinceBootMillis() - creationTime,
    247                     mHistogramAttachDuration, DURATION_LOG_HISTOGRAM);
    248         }
    249     }
    250 
    251     /**
    252      * Push information about the new discovery session.
    253      */
    254     public void recordDiscoverySession(int uid, SparseArray<WifiAwareClientState> clients) {
    255         recordDiscoverySessionInternal(uid, clients, false, -1, -1);
    256     }
    257 
    258     /**
    259      * Push information about the new discovery session with ranging enabled
    260      */
    261     public void recordDiscoverySessionWithRanging(int uid, boolean isSubscriberWithRanging,
    262             int minRange, int maxRange, SparseArray<WifiAwareClientState> clients) {
    263         recordDiscoverySessionInternal(uid, clients, isSubscriberWithRanging, minRange, maxRange);
    264     }
    265 
    266     /**
    267      * Internal combiner of discovery session information.
    268      */
    269     private void recordDiscoverySessionInternal(int uid, SparseArray<WifiAwareClientState> clients,
    270             boolean isRangingEnabledSubscriber, int minRange, int maxRange) {
    271         // count the number of sessions per uid and overall
    272         int numPublishesInSystem = 0;
    273         int numSubscribesInSystem = 0;
    274         int numPublishesOnUid = 0;
    275         int numSubscribesOnUid = 0;
    276 
    277         int numPublishesWithRangingInSystem = 0;
    278         int numSubscribesWithRangingInSystem = 0;
    279         int numPublishesWithRangingOnUid = 0;
    280         int numSubscribesWithRangingOnUid = 0;
    281 
    282         for (int i = 0; i < clients.size(); ++i) {
    283             WifiAwareClientState client = clients.valueAt(i);
    284             boolean sameUid = client.getUid() == uid;
    285 
    286             SparseArray<WifiAwareDiscoverySessionState> sessions = client.getSessions();
    287             for (int j = 0; j < sessions.size(); ++j) {
    288                 WifiAwareDiscoverySessionState session = sessions.valueAt(j);
    289                 boolean isRangingEnabledForThisSession = session.isRangingEnabled();
    290 
    291                 if (session.isPublishSession()) {
    292                     numPublishesInSystem += 1;
    293                     if (isRangingEnabledForThisSession) {
    294                         numPublishesWithRangingInSystem += 1;
    295                     }
    296                     if (sameUid) {
    297                         numPublishesOnUid += 1;
    298                         if (isRangingEnabledForThisSession) {
    299                             numPublishesWithRangingOnUid += 1;
    300                         }
    301                     }
    302                 } else {
    303                     numSubscribesInSystem += 1;
    304                     if (isRangingEnabledForThisSession) {
    305                         numSubscribesWithRangingInSystem += 1;
    306                     }
    307                     if (sameUid) {
    308                         numSubscribesOnUid += 1;
    309                         if (isRangingEnabledForThisSession) {
    310                             numSubscribesWithRangingOnUid += 1;
    311                         }
    312                     }
    313                 }
    314             }
    315         }
    316 
    317         synchronized (mLock) {
    318             mMaxPublishInApp = Math.max(mMaxPublishInApp, numPublishesOnUid);
    319             mMaxSubscribeInApp = Math.max(mMaxSubscribeInApp, numSubscribesOnUid);
    320             mMaxDiscoveryInApp = Math.max(mMaxDiscoveryInApp,
    321                     numPublishesOnUid + numSubscribesOnUid);
    322             mMaxPublishInSystem = Math.max(mMaxPublishInSystem, numPublishesInSystem);
    323             mMaxSubscribeInSystem = Math.max(mMaxSubscribeInSystem, numSubscribesInSystem);
    324             mMaxDiscoveryInSystem = Math.max(mMaxDiscoveryInSystem,
    325                     numPublishesInSystem + numSubscribesInSystem);
    326 
    327             mMaxPublishWithRangingInApp = Math.max(mMaxPublishWithRangingInApp,
    328                     numPublishesWithRangingOnUid);
    329             mMaxSubscribeWithRangingInApp = Math.max(mMaxSubscribeWithRangingInApp,
    330                     numSubscribesWithRangingOnUid);
    331             mMaxPublishWithRangingInSystem = Math.max(mMaxPublishWithRangingInSystem,
    332                     numPublishesWithRangingInSystem);
    333             mMaxSubscribeWithRangingInSystem = Math.max(mMaxSubscribeWithRangingInSystem,
    334                     numSubscribesWithRangingInSystem);
    335             if (isRangingEnabledSubscriber) {
    336                 mNumSubscribesWithRanging += 1;
    337             }
    338 
    339             if (minRange != -1) {
    340                 MetricsUtils.addValueToLinearHistogram(minRange, mHistogramSubscribeGeofenceMin,
    341                         RANGING_LIMIT_METERS);
    342             }
    343             if (maxRange != -1) {
    344                 MetricsUtils.addValueToLinearHistogram(maxRange, mHistogramSubscribeGeofenceMax,
    345                         RANGING_LIMIT_METERS);
    346             }
    347         }
    348     }
    349 
    350     /**
    351      * Push information about a new discovery session status (recorded when the discovery session is
    352      * created).
    353      */
    354     public void recordDiscoveryStatus(int uid, int status, boolean isPublish) {
    355         synchronized (mLock) {
    356             if (isPublish) {
    357                 mPublishStatusData.put(status, mPublishStatusData.get(status) + 1);
    358             } else {
    359                 mSubscribeStatusData.put(status, mSubscribeStatusData.get(status) + 1);
    360             }
    361 
    362             if (status == NanStatusType.NO_RESOURCES_AVAILABLE) {
    363                 mAppsWithDiscoverySessionResourceFailure.add(uid);
    364             }
    365         }
    366     }
    367 
    368     /**
    369      * Push duration information of a discovery session.
    370      */
    371     public void recordDiscoverySessionDuration(long creationTime, boolean isPublish) {
    372         synchronized (mLock) {
    373             MetricsUtils.addValueToLogHistogram(mClock.getElapsedSinceBootMillis() - creationTime,
    374                     isPublish ? mHistogramPublishDuration : mHistogramSubscribeDuration,
    375                     DURATION_LOG_HISTOGRAM);
    376         }
    377     }
    378 
    379     /**
    380      * Push information about Match indication (aka service discovered) for subscribe sessions
    381      * which enabled ranging. Collect information about whether or not service discovery was
    382      * triggered with ranging information or without (i.e. ranging disabled for some reason).
    383      */
    384     public void recordMatchIndicationForRangeEnabledSubscribe(boolean rangeProvided) {
    385         if (rangeProvided) {
    386             mNumMatchesWithRanging++;
    387         } else {
    388             mNumMatchesWithoutRangingForRangingEnabledSubscribes++;
    389         }
    390     }
    391 
    392     /**
    393      * Record NDP (and by extension NDI) usage - on successful creation of an NDP.
    394      */
    395     public void recordNdpCreation(int uid,
    396             Map<WifiAwareNetworkSpecifier, WifiAwareDataPathStateManager
    397                     .AwareNetworkRequestInformation> networkRequestCache) {
    398         int numNdpInApp = 0;
    399         int numSecureNdpInApp = 0;
    400         int numNdpInSystem = 0;
    401         int numSecureNdpInSystem = 0;
    402 
    403         Map<String, Integer> ndpPerNdiMap = new HashMap<>();
    404         Set<String> ndiInApp = new HashSet<>();
    405         Set<String> ndiInSystem = new HashSet<>();
    406 
    407         for (WifiAwareDataPathStateManager.AwareNetworkRequestInformation anri :
    408                 networkRequestCache.values()) {
    409             if (anri.state
    410                     != WifiAwareDataPathStateManager.AwareNetworkRequestInformation
    411                     .STATE_CONFIRMED) {
    412                 continue; // only count completed (up-and-running) NDPs
    413             }
    414 
    415             boolean sameUid = anri.uid == uid;
    416             boolean isSecure = !TextUtils.isEmpty(anri.networkSpecifier.passphrase) || (
    417                     anri.networkSpecifier.pmk != null && anri.networkSpecifier.pmk.length != 0);
    418 
    419             // in-app stats
    420             if (sameUid) {
    421                 numNdpInApp += 1;
    422                 if (isSecure) {
    423                     numSecureNdpInApp += 1;
    424                 }
    425 
    426                 ndiInApp.add(anri.interfaceName);
    427             }
    428 
    429             // system stats
    430             numNdpInSystem += 1;
    431             if (isSecure) {
    432                 numSecureNdpInSystem += 1;
    433             }
    434 
    435             // ndp/ndi stats
    436             Integer ndpCount = ndpPerNdiMap.get(anri.interfaceName);
    437             if (ndpCount == null) {
    438                 ndpPerNdiMap.put(anri.interfaceName, 1);
    439             } else {
    440                 ndpPerNdiMap.put(anri.interfaceName, ndpCount + 1);
    441             }
    442 
    443             // ndi stats
    444             ndiInSystem.add(anri.interfaceName);
    445         }
    446 
    447         synchronized (mLock) {
    448             mMaxNdiInApp = Math.max(mMaxNdiInApp, ndiInApp.size());
    449             mMaxNdpInApp = Math.max(mMaxNdpInApp, numNdpInApp);
    450             mMaxSecureNdpInApp = Math.max(mMaxSecureNdpInApp, numSecureNdpInApp);
    451             mMaxNdiInSystem = Math.max(mMaxNdiInSystem, ndiInSystem.size());
    452             mMaxNdpInSystem = Math.max(mMaxNdpInSystem, numNdpInSystem);
    453             mMaxSecureNdpInSystem = Math.max(mMaxSecureNdpInSystem, numSecureNdpInSystem);
    454             mMaxNdpPerNdi = Math.max(mMaxNdpPerNdi, Collections.max(ndpPerNdiMap.values()));
    455         }
    456     }
    457 
    458     /**
    459      * Record the completion status of NDP negotiation. There are multiple steps in NDP negotiation
    460      * a failure on any aborts the process and is recorded. A success on intermediate stages is
    461      * not recorded - only the final success.
    462      */
    463     public void recordNdpStatus(int status, boolean isOutOfBand, long startTimestamp) {
    464         synchronized (mLock) {
    465             if (isOutOfBand) {
    466                 mOutOfBandNdpStatusData.put(status, mOutOfBandNdpStatusData.get(status) + 1);
    467             } else {
    468                 mInBandNdpStatusData.put(status, mOutOfBandNdpStatusData.get(status) + 1);
    469             }
    470 
    471             if (status == NanStatusType.SUCCESS) {
    472                 long creationTime = mClock.getElapsedSinceBootMillis() - startTimestamp;
    473                 MetricsUtils.addValueToLogHistogram(creationTime, mNdpCreationTimeDuration,
    474                         DURATION_LOG_HISTOGRAM);
    475                 mNdpCreationTimeMin = (mNdpCreationTimeMin == -1) ? creationTime : Math.min(
    476                         mNdpCreationTimeMin, creationTime);
    477                 mNdpCreationTimeMax = Math.max(mNdpCreationTimeMax, creationTime);
    478                 mNdpCreationTimeSum += creationTime;
    479                 mNdpCreationTimeSumSq += creationTime * creationTime;
    480                 mNdpCreationTimeNumSamples += 1;
    481             }
    482         }
    483     }
    484 
    485     /**
    486      * Record the duration of the NDP session. The creation time is assumed to be the time at
    487      * which a confirm message was received (i.e. the end of the setup negotiation).
    488      */
    489     public void recordNdpSessionDuration(long creationTime) {
    490         synchronized (mLock) {
    491             MetricsUtils.addValueToLogHistogram(mClock.getElapsedSinceBootMillis() - creationTime,
    492                     mHistogramNdpDuration, DURATION_LOG_HISTOGRAM);
    493         }
    494     }
    495 
    496     /**
    497      * Consolidate all metrics into the proto.
    498      */
    499     public WifiMetricsProto.WifiAwareLog consolidateProto() {
    500         WifiMetricsProto.WifiAwareLog log = new WifiMetricsProto.WifiAwareLog();
    501         long now = mClock.getElapsedSinceBootMillis();
    502         synchronized (mLock) {
    503             log.histogramAwareAvailableDurationMs = histogramToProtoArray(
    504                     MetricsUtils.logHistogramToGenericBuckets(mHistogramAwareAvailableDurationMs,
    505                             DURATION_LOG_HISTOGRAM));
    506             log.availableTimeMs = mAvailableTimeMs;
    507             if (mLastEnableUsageInThisSampleWindowMs != 0) {
    508                 log.availableTimeMs += now - mLastEnableUsageInThisSampleWindowMs;
    509             }
    510 
    511             log.histogramAwareEnabledDurationMs = histogramToProtoArray(
    512                     MetricsUtils.logHistogramToGenericBuckets(mHistogramAwareEnabledDurationMs,
    513                             DURATION_LOG_HISTOGRAM));
    514             log.enabledTimeMs = mEnabledTimeMs;
    515             if (mLastEnableAwareInThisSampleWindowMs != 0) {
    516                 log.enabledTimeMs += now - mLastEnableAwareInThisSampleWindowMs;
    517             }
    518 
    519             log.numApps = mAttachDataByUid.size();
    520             log.numAppsUsingIdentityCallback = 0;
    521             log.maxConcurrentAttachSessionsInApp = 0;
    522             for (AttachData ad: mAttachDataByUid.values()) {
    523                 if (ad.mUsesIdentityCallback) {
    524                     ++log.numAppsUsingIdentityCallback;
    525                 }
    526                 log.maxConcurrentAttachSessionsInApp = Math.max(
    527                         log.maxConcurrentAttachSessionsInApp, ad.mMaxConcurrentAttaches);
    528             }
    529             log.histogramAttachSessionStatus = histogramToProtoArray(mAttachStatusData);
    530             log.histogramAttachDurationMs = histogramToProtoArray(
    531                     MetricsUtils.logHistogramToGenericBuckets(mHistogramAttachDuration,
    532                             DURATION_LOG_HISTOGRAM));
    533 
    534             log.maxConcurrentPublishInApp = mMaxPublishInApp;
    535             log.maxConcurrentSubscribeInApp = mMaxSubscribeInApp;
    536             log.maxConcurrentDiscoverySessionsInApp = mMaxDiscoveryInApp;
    537             log.maxConcurrentPublishInSystem = mMaxPublishInSystem;
    538             log.maxConcurrentSubscribeInSystem = mMaxSubscribeInSystem;
    539             log.maxConcurrentDiscoverySessionsInSystem = mMaxDiscoveryInSystem;
    540             log.histogramPublishStatus = histogramToProtoArray(mPublishStatusData);
    541             log.histogramSubscribeStatus = histogramToProtoArray(mSubscribeStatusData);
    542             log.numAppsWithDiscoverySessionFailureOutOfResources =
    543                     mAppsWithDiscoverySessionResourceFailure.size();
    544             log.histogramPublishSessionDurationMs = histogramToProtoArray(
    545                     MetricsUtils.logHistogramToGenericBuckets(mHistogramPublishDuration,
    546                             DURATION_LOG_HISTOGRAM));
    547             log.histogramSubscribeSessionDurationMs = histogramToProtoArray(
    548                     MetricsUtils.logHistogramToGenericBuckets(mHistogramSubscribeDuration,
    549                             DURATION_LOG_HISTOGRAM));
    550 
    551             log.maxConcurrentPublishWithRangingInApp = mMaxPublishWithRangingInApp;
    552             log.maxConcurrentSubscribeWithRangingInApp = mMaxSubscribeWithRangingInApp;
    553             log.maxConcurrentPublishWithRangingInSystem = mMaxPublishWithRangingInSystem;
    554             log.maxConcurrentSubscribeWithRangingInSystem = mMaxSubscribeWithRangingInSystem;
    555             log.histogramSubscribeGeofenceMin = histogramToProtoArray(
    556                     MetricsUtils.linearHistogramToGenericBuckets(mHistogramSubscribeGeofenceMin,
    557                             RANGING_LIMIT_METERS));
    558             log.histogramSubscribeGeofenceMax = histogramToProtoArray(
    559                     MetricsUtils.linearHistogramToGenericBuckets(mHistogramSubscribeGeofenceMax,
    560                             RANGING_LIMIT_METERS));
    561             log.numSubscribesWithRanging = mNumSubscribesWithRanging;
    562             log.numMatchesWithRanging = mNumMatchesWithRanging;
    563             log.numMatchesWithoutRangingForRangingEnabledSubscribes =
    564                     mNumMatchesWithoutRangingForRangingEnabledSubscribes;
    565 
    566             log.maxConcurrentNdiInApp = mMaxNdiInApp;
    567             log.maxConcurrentNdiInSystem = mMaxNdiInSystem;
    568             log.maxConcurrentNdpInApp = mMaxNdpInApp;
    569             log.maxConcurrentNdpInSystem = mMaxNdpInSystem;
    570             log.maxConcurrentSecureNdpInApp = mMaxSecureNdpInApp;
    571             log.maxConcurrentSecureNdpInSystem = mMaxSecureNdpInSystem;
    572             log.maxConcurrentNdpPerNdi = mMaxNdpPerNdi;
    573             log.histogramRequestNdpStatus = histogramToProtoArray(mInBandNdpStatusData);
    574             log.histogramRequestNdpOobStatus = histogramToProtoArray(mOutOfBandNdpStatusData);
    575 
    576             log.histogramNdpCreationTimeMs = histogramToProtoArray(
    577                     MetricsUtils.logHistogramToGenericBuckets(mNdpCreationTimeDuration,
    578                             DURATION_LOG_HISTOGRAM));
    579             log.ndpCreationTimeMsMin = mNdpCreationTimeMin;
    580             log.ndpCreationTimeMsMax = mNdpCreationTimeMax;
    581             log.ndpCreationTimeMsSum = mNdpCreationTimeSum;
    582             log.ndpCreationTimeMsSumOfSq = mNdpCreationTimeSumSq;
    583             log.ndpCreationTimeMsNumSamples = mNdpCreationTimeNumSamples;
    584 
    585             log.histogramNdpSessionDurationMs = histogramToProtoArray(
    586                     MetricsUtils.logHistogramToGenericBuckets(mHistogramNdpDuration,
    587                             DURATION_LOG_HISTOGRAM));
    588         }
    589         return log;
    590     }
    591 
    592     /**
    593      * clear Wi-Fi Aware metrics
    594      */
    595     public void clear() {
    596         long now = mClock.getElapsedSinceBootMillis();
    597         synchronized (mLock) {
    598             // don't clear mLastEnableUsage since could be valid for next measurement period
    599             mHistogramAwareAvailableDurationMs.clear();
    600             mAvailableTimeMs = 0;
    601             if (mLastEnableUsageInThisSampleWindowMs != 0) {
    602                 mLastEnableUsageInThisSampleWindowMs = now;
    603             }
    604 
    605             // don't clear mLastEnableAware since could be valid for next measurement period
    606             mHistogramAwareEnabledDurationMs.clear();
    607             mEnabledTimeMs = 0;
    608             if (mLastEnableAwareInThisSampleWindowMs != 0) {
    609                 mLastEnableAwareInThisSampleWindowMs = now;
    610             }
    611 
    612             mAttachDataByUid.clear();
    613             mAttachStatusData.clear();
    614             mHistogramAttachDuration.clear();
    615 
    616             mMaxPublishInApp = 0;
    617             mMaxSubscribeInApp = 0;
    618             mMaxDiscoveryInApp = 0;
    619             mMaxPublishInSystem = 0;
    620             mMaxSubscribeInSystem = 0;
    621             mMaxDiscoveryInSystem = 0;
    622             mPublishStatusData.clear();
    623             mSubscribeStatusData.clear();
    624             mHistogramPublishDuration.clear();
    625             mHistogramSubscribeDuration.clear();
    626             mAppsWithDiscoverySessionResourceFailure.clear();
    627 
    628             mMaxPublishWithRangingInApp = 0;
    629             mMaxSubscribeWithRangingInApp = 0;
    630             mMaxPublishWithRangingInSystem = 0;
    631             mMaxSubscribeWithRangingInSystem = 0;
    632             mHistogramSubscribeGeofenceMin.clear();
    633             mHistogramSubscribeGeofenceMax.clear();
    634             mNumSubscribesWithRanging = 0;
    635             mNumMatchesWithRanging = 0;
    636             mNumMatchesWithoutRangingForRangingEnabledSubscribes = 0;
    637 
    638             mMaxNdiInApp = 0;
    639             mMaxNdpInApp = 0;
    640             mMaxSecureNdpInApp = 0;
    641             mMaxNdiInSystem = 0;
    642             mMaxNdpInSystem = 0;
    643             mMaxSecureNdpInSystem = 0;
    644             mMaxNdpPerNdi = 0;
    645             mInBandNdpStatusData.clear();
    646             mOutOfBandNdpStatusData.clear();
    647 
    648             mNdpCreationTimeDuration.clear();
    649             mNdpCreationTimeMin = -1;
    650             mNdpCreationTimeMax = 0;
    651             mNdpCreationTimeSum = 0;
    652             mNdpCreationTimeSumSq = 0;
    653             mNdpCreationTimeNumSamples = 0;
    654 
    655             mHistogramNdpDuration.clear();
    656         }
    657     }
    658 
    659     /**
    660      * Dump all WifiAwareMetrics to console (pw) - this method is never called to dump the
    661      * serialized metrics (handled by parent WifiMetrics).
    662      *
    663      * @param fd   unused
    664      * @param pw   PrintWriter for writing dump to
    665      * @param args unused
    666      */
    667     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    668         synchronized (mLock) {
    669             pw.println("mLastEnableUsageMs:" + mLastEnableUsageMs);
    670             pw.println(
    671                     "mLastEnableUsageInThisSampleWindowMs:" + mLastEnableUsageInThisSampleWindowMs);
    672             pw.println("mAvailableTimeMs:" + mAvailableTimeMs);
    673             pw.println("mHistogramAwareAvailableDurationMs:");
    674             for (int i = 0; i < mHistogramAwareAvailableDurationMs.size(); ++i) {
    675                 pw.println("  " + mHistogramAwareAvailableDurationMs.keyAt(i) + ": "
    676                         + mHistogramAwareAvailableDurationMs.valueAt(i));
    677             }
    678 
    679             pw.println("mLastEnableAwareMs:" + mLastEnableAwareMs);
    680             pw.println(
    681                     "mLastEnableAwareInThisSampleWindowMs:" + mLastEnableAwareInThisSampleWindowMs);
    682             pw.println("mEnabledTimeMs:" + mEnabledTimeMs);
    683             pw.println("mHistogramAwareEnabledDurationMs:");
    684             for (int i = 0; i < mHistogramAwareEnabledDurationMs.size(); ++i) {
    685                 pw.println("  " + mHistogramAwareEnabledDurationMs.keyAt(i) + ": "
    686                         + mHistogramAwareEnabledDurationMs.valueAt(i));
    687             }
    688 
    689             pw.println("mAttachDataByUid:");
    690             for (Map.Entry<Integer, AttachData> ade: mAttachDataByUid.entrySet()) {
    691                 pw.println("  " + "uid=" + ade.getKey() + ": identity="
    692                         + ade.getValue().mUsesIdentityCallback + ", maxConcurrent="
    693                         + ade.getValue().mMaxConcurrentAttaches);
    694             }
    695             pw.println("mAttachStatusData:");
    696             for (int i = 0; i < mAttachStatusData.size(); ++i) {
    697                 pw.println("  " + mAttachStatusData.keyAt(i) + ": "
    698                         + mAttachStatusData.valueAt(i));
    699             }
    700             pw.println("mHistogramAttachDuration:");
    701             for (int i = 0; i < mHistogramAttachDuration.size(); ++i) {
    702                 pw.println("  " + mHistogramAttachDuration.keyAt(i) + ": "
    703                         + mHistogramAttachDuration.valueAt(i));
    704             }
    705 
    706             pw.println("mMaxPublishInApp:" + mMaxPublishInApp);
    707             pw.println("mMaxSubscribeInApp:" + mMaxSubscribeInApp);
    708             pw.println("mMaxDiscoveryInApp:" + mMaxDiscoveryInApp);
    709             pw.println("mMaxPublishInSystem:" + mMaxPublishInSystem);
    710             pw.println("mMaxSubscribeInSystem:" + mMaxSubscribeInSystem);
    711             pw.println("mMaxDiscoveryInSystem:" + mMaxDiscoveryInSystem);
    712             pw.println("mPublishStatusData:");
    713             for (int i = 0; i < mPublishStatusData.size(); ++i) {
    714                 pw.println("  " + mPublishStatusData.keyAt(i) + ": "
    715                         + mPublishStatusData.valueAt(i));
    716             }
    717             pw.println("mSubscribeStatusData:");
    718             for (int i = 0; i < mSubscribeStatusData.size(); ++i) {
    719                 pw.println("  " + mSubscribeStatusData.keyAt(i) + ": "
    720                         + mSubscribeStatusData.valueAt(i));
    721             }
    722             pw.println("mHistogramPublishDuration:");
    723             for (int i = 0; i < mHistogramPublishDuration.size(); ++i) {
    724                 pw.println("  " + mHistogramPublishDuration.keyAt(i) + ": "
    725                         + mHistogramPublishDuration.valueAt(i));
    726             }
    727             pw.println("mHistogramSubscribeDuration:");
    728             for (int i = 0; i < mHistogramSubscribeDuration.size(); ++i) {
    729                 pw.println("  " + mHistogramSubscribeDuration.keyAt(i) + ": "
    730                         + mHistogramSubscribeDuration.valueAt(i));
    731             }
    732             pw.println("mAppsWithDiscoverySessionResourceFailure:");
    733             for (Integer uid: mAppsWithDiscoverySessionResourceFailure) {
    734                 pw.println("  " + uid);
    735 
    736             }
    737 
    738             pw.println("mMaxPublishWithRangingInApp:" + mMaxPublishWithRangingInApp);
    739             pw.println("mMaxSubscribeWithRangingInApp:" + mMaxSubscribeWithRangingInApp);
    740             pw.println("mMaxPublishWithRangingInSystem:" + mMaxPublishWithRangingInSystem);
    741             pw.println("mMaxSubscribeWithRangingInSystem:" + mMaxSubscribeWithRangingInSystem);
    742             pw.println("mHistogramSubscribeGeofenceMin:");
    743             for (int i = 0; i < mHistogramSubscribeGeofenceMin.size(); ++i) {
    744                 pw.println("  " + mHistogramSubscribeGeofenceMin.keyAt(i) + ": "
    745                         + mHistogramSubscribeGeofenceMin.valueAt(i));
    746             }
    747             pw.println("mHistogramSubscribeGeofenceMax:");
    748             for (int i = 0; i < mHistogramSubscribeGeofenceMax.size(); ++i) {
    749                 pw.println("  " + mHistogramSubscribeGeofenceMax.keyAt(i) + ": "
    750                         + mHistogramSubscribeGeofenceMax.valueAt(i));
    751             }
    752             pw.println("mNumSubscribesWithRanging:" + mNumSubscribesWithRanging);
    753             pw.println("mNumMatchesWithRanging:" + mNumMatchesWithRanging);
    754             pw.println("mNumMatchesWithoutRangingForRangingEnabledSubscribes:"
    755                     + mNumMatchesWithoutRangingForRangingEnabledSubscribes);
    756 
    757             pw.println("mMaxNdiInApp:" + mMaxNdiInApp);
    758             pw.println("mMaxNdpInApp:" + mMaxNdpInApp);
    759             pw.println("mMaxSecureNdpInApp:" + mMaxSecureNdpInApp);
    760             pw.println("mMaxNdiInSystem:" + mMaxNdiInSystem);
    761             pw.println("mMaxNdpInSystem:" + mMaxNdpInSystem);
    762             pw.println("mMaxSecureNdpInSystem:" + mMaxSecureNdpInSystem);
    763             pw.println("mMaxNdpPerNdi:" + mMaxNdpPerNdi);
    764             pw.println("mInBandNdpStatusData:");
    765             for (int i = 0; i < mInBandNdpStatusData.size(); ++i) {
    766                 pw.println("  " + mInBandNdpStatusData.keyAt(i) + ": "
    767                         + mInBandNdpStatusData.valueAt(i));
    768             }
    769             pw.println("mOutOfBandNdpStatusData:");
    770             for (int i = 0; i < mOutOfBandNdpStatusData.size(); ++i) {
    771                 pw.println("  " + mOutOfBandNdpStatusData.keyAt(i) + ": "
    772                         + mOutOfBandNdpStatusData.valueAt(i));
    773             }
    774 
    775             pw.println("mNdpCreationTimeDuration:");
    776             for (int i = 0; i < mNdpCreationTimeDuration.size(); ++i) {
    777                 pw.println("  " + mNdpCreationTimeDuration.keyAt(i) + ": "
    778                         + mNdpCreationTimeDuration.valueAt(i));
    779             }
    780             pw.println("mNdpCreationTimeMin:" + mNdpCreationTimeMin);
    781             pw.println("mNdpCreationTimeMax:" + mNdpCreationTimeMax);
    782             pw.println("mNdpCreationTimeSum:" + mNdpCreationTimeSum);
    783             pw.println("mNdpCreationTimeSumSq:" + mNdpCreationTimeSumSq);
    784             pw.println("mNdpCreationTimeNumSamples:" + mNdpCreationTimeNumSamples);
    785 
    786             pw.println("mHistogramNdpDuration:");
    787             for (int i = 0; i < mHistogramNdpDuration.size(); ++i) {
    788                 pw.println("  " + mHistogramNdpDuration.keyAt(i) + ": "
    789                         + mHistogramNdpDuration.valueAt(i));
    790             }
    791         }
    792     }
    793 
    794     // histogram utilities
    795     /**
    796      * Convert a generic bucket to Aware HistogramBucket proto.
    797      */
    798     @VisibleForTesting
    799     public static WifiMetricsProto.WifiAwareLog.HistogramBucket[] histogramToProtoArray(
    800             MetricsUtils.GenericBucket[] buckets) {
    801         WifiMetricsProto.WifiAwareLog.HistogramBucket[] protoArray =
    802                 new WifiMetricsProto.WifiAwareLog.HistogramBucket[buckets.length];
    803 
    804         for (int i = 0; i < buckets.length; ++i) {
    805             protoArray[i] = new WifiMetricsProto.WifiAwareLog.HistogramBucket();
    806             protoArray[i].start = buckets[i].start;
    807             protoArray[i].end = buckets[i].end;
    808             protoArray[i].count = buckets[i].count;
    809         }
    810 
    811         return protoArray;
    812     }
    813 
    814     /**
    815      * Adds the NanStatusType to the histogram (translating to the proto enumeration of the status).
    816      */
    817     public static void addNanHalStatusToHistogram(int halStatus, SparseIntArray histogram) {
    818         int protoStatus = convertNanStatusTypeToProtoEnum(halStatus);
    819         int newValue = histogram.get(protoStatus) + 1;
    820         histogram.put(protoStatus, newValue);
    821     }
    822 
    823     /**
    824      * Converts a histogram of proto NanStatusTypeEnum to a raw proto histogram.
    825      */
    826     @VisibleForTesting
    827     public static WifiMetricsProto.WifiAwareLog.NanStatusHistogramBucket[] histogramToProtoArray(
    828             SparseIntArray histogram) {
    829         WifiMetricsProto.WifiAwareLog.NanStatusHistogramBucket[] protoArray =
    830                 new WifiMetricsProto.WifiAwareLog.NanStatusHistogramBucket[histogram.size()];
    831 
    832         for (int i = 0; i < histogram.size(); ++i) {
    833             protoArray[i] = new WifiMetricsProto.WifiAwareLog.NanStatusHistogramBucket();
    834             protoArray[i].nanStatusType = histogram.keyAt(i);
    835             protoArray[i].count = histogram.valueAt(i);
    836         }
    837 
    838         return protoArray;
    839     }
    840 
    841     /**
    842      * Convert a HAL NanStatusType enum to a Metrics proto enum NanStatusTypeEnum.
    843      */
    844     public static int convertNanStatusTypeToProtoEnum(int nanStatusType) {
    845         switch (nanStatusType) {
    846             case NanStatusType.SUCCESS:
    847                 return WifiMetricsProto.WifiAwareLog.SUCCESS;
    848             case NanStatusType.INTERNAL_FAILURE:
    849                 return WifiMetricsProto.WifiAwareLog.INTERNAL_FAILURE;
    850             case NanStatusType.PROTOCOL_FAILURE:
    851                 return WifiMetricsProto.WifiAwareLog.PROTOCOL_FAILURE;
    852             case NanStatusType.INVALID_SESSION_ID:
    853                 return WifiMetricsProto.WifiAwareLog.INVALID_SESSION_ID;
    854             case NanStatusType.NO_RESOURCES_AVAILABLE:
    855                 return WifiMetricsProto.WifiAwareLog.NO_RESOURCES_AVAILABLE;
    856             case NanStatusType.INVALID_ARGS:
    857                 return WifiMetricsProto.WifiAwareLog.INVALID_ARGS;
    858             case NanStatusType.INVALID_PEER_ID:
    859                 return WifiMetricsProto.WifiAwareLog.INVALID_PEER_ID;
    860             case NanStatusType.INVALID_NDP_ID:
    861                 return WifiMetricsProto.WifiAwareLog.INVALID_NDP_ID;
    862             case NanStatusType.NAN_NOT_ALLOWED:
    863                 return WifiMetricsProto.WifiAwareLog.NAN_NOT_ALLOWED;
    864             case NanStatusType.NO_OTA_ACK:
    865                 return WifiMetricsProto.WifiAwareLog.NO_OTA_ACK;
    866             case NanStatusType.ALREADY_ENABLED:
    867                 return WifiMetricsProto.WifiAwareLog.ALREADY_ENABLED;
    868             case NanStatusType.FOLLOWUP_TX_QUEUE_FULL:
    869                 return WifiMetricsProto.WifiAwareLog.FOLLOWUP_TX_QUEUE_FULL;
    870             case NanStatusType.UNSUPPORTED_CONCURRENCY_NAN_DISABLED:
    871                 return WifiMetricsProto.WifiAwareLog.UNSUPPORTED_CONCURRENCY_NAN_DISABLED;
    872             default:
    873                 Log.e(TAG, "Unrecognized NanStatusType: " + nanStatusType);
    874                 return WifiMetricsProto.WifiAwareLog.UNKNOWN_HAL_STATUS;
    875         }
    876     }
    877 }
    878