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