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