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