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