WifiAwareMetrics.java revision dca9963c7292e17318f5ba0dee6c3683c7c9f941
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 17package com.android.server.wifi.aware; 18 19import android.hardware.wifi.V1_0.NanStatusType; 20import android.net.wifi.aware.WifiAwareNetworkSpecifier; 21import android.text.TextUtils; 22import android.util.Log; 23import android.util.SparseArray; 24import android.util.SparseIntArray; 25 26import com.android.internal.annotations.VisibleForTesting; 27import com.android.server.wifi.Clock; 28import com.android.server.wifi.nano.WifiMetricsProto; 29 30import java.io.FileDescriptor; 31import java.io.PrintWriter; 32import java.util.Collections; 33import java.util.HashMap; 34import java.util.HashSet; 35import java.util.Map; 36import java.util.Set; 37 38/** 39 * Wi-Fi Aware metric container/processor. 40 */ 41public class WifiAwareMetrics { 42 private static final String TAG = "WifiAwareMetrics"; 43 private static final boolean DBG = false; 44 45 // Histogram: 8 buckets (i=0, ..., 7) of 9 slots in range 10^i -> 10^(i+1) 46 // Buckets: 47 // 1 -> 10: 9 @ 1 48 // 10 -> 100: 9 @ 10 49 // 100 -> 1000: 9 @ 10^2 50 // 10^3 -> 10^4: 9 @ 10^3 51 // 10^4 -> 10^5: 9 @ 10^4 52 // 10^5 -> 10^6: 9 @ 10^5 53 // 10^6 -> 10^7: 9 @ 10^6 54 // 10^7 -> 10^8: 9 @ 10^7 --> 10^8 ms -> 10^5s -> 28 hours 55 private static final HistParms DURATION_LOG_HISTOGRAM = new HistParms(0, 1, 10, 9, 8); 56 57 private final Object mLock = new Object(); 58 private final Clock mClock; 59 60 // enableUsage/disableUsage data 61 private long mLastEnableUsageMs = 0; 62 private long mLastEnableUsageInThisSampleWindowMs = 0; 63 private long mAvailableTimeMs = 0; 64 private SparseIntArray mHistogramAwareAvailableDurationMs = new SparseIntArray(); 65 66 // enabled data 67 private long mLastEnableAwareMs = 0; 68 private long mLastEnableAwareInThisSampleWindowMs = 0; 69 private long mEnabledTimeMs = 0; 70 private SparseIntArray mHistogramAwareEnabledDurationMs = new SparseIntArray(); 71 72 // attach data 73 private static class AttachData { 74 boolean mUsesIdentityCallback; // do any attach sessions of the UID use identity callback 75 int mMaxConcurrentAttaches; 76 } 77 private Map<Integer, AttachData> mAttachDataByUid = new HashMap<>(); 78 private SparseIntArray mAttachStatusData = new SparseIntArray(); 79 private SparseIntArray mHistogramAttachDuration = new SparseIntArray(); 80 81 // discovery data 82 private int mMaxPublishInApp = 0; 83 private int mMaxSubscribeInApp = 0; 84 private int mMaxDiscoveryInApp = 0; 85 private int mMaxPublishInSystem = 0; 86 private int mMaxSubscribeInSystem = 0; 87 private int mMaxDiscoveryInSystem = 0; 88 private SparseIntArray mPublishStatusData = new SparseIntArray(); 89 private SparseIntArray mSubscribeStatusData = new SparseIntArray(); 90 private SparseIntArray mHistogramPublishDuration = new SparseIntArray(); 91 private SparseIntArray mHistogramSubscribeDuration = new SparseIntArray(); 92 private Set<Integer> mAppsWithDiscoverySessionResourceFailure = new HashSet<>(); 93 94 // data-path (NDI/NDP) data 95 private int mMaxNdiInApp = 0; 96 private int mMaxNdpInApp = 0; 97 private int mMaxSecureNdpInApp = 0; 98 private int mMaxNdiInSystem = 0; 99 private int mMaxNdpInSystem = 0; 100 private int mMaxSecureNdpInSystem = 0; 101 private int mMaxNdpPerNdi = 0; 102 private SparseIntArray mInBandNdpStatusData = new SparseIntArray(); 103 private SparseIntArray mOutOfBandNdpStatusData = new SparseIntArray(); 104 105 private SparseIntArray mNdpCreationTimeDuration = new SparseIntArray(); 106 private long mNdpCreationTimeMin = -1; 107 private long mNdpCreationTimeMax = 0; 108 private long mNdpCreationTimeSum = 0; 109 private long mNdpCreationTimeSumSq = 0; 110 private long mNdpCreationTimeNumSamples = 0; 111 112 public WifiAwareMetrics(Clock clock) { 113 mClock = clock; 114 } 115 116 /** 117 * Push usage stats for WifiAwareStateMachine.enableUsage() to 118 * histogram_aware_available_duration_ms. 119 */ 120 public void recordEnableUsage() { 121 synchronized (mLock) { 122 if (mLastEnableUsageMs != 0) { 123 Log.w(TAG, "enableUsage: mLastEnableUsage*Ms initialized!?"); 124 } 125 mLastEnableUsageMs = mClock.getElapsedSinceBootMillis(); 126 mLastEnableUsageInThisSampleWindowMs = mLastEnableUsageMs; 127 } 128 } 129 130 /** 131 * Push usage stats for WifiAwareStateMachine.disableUsage() to 132 * histogram_aware_available_duration_ms. 133 */ 134 135 public void recordDisableUsage() { 136 synchronized (mLock) { 137 if (mLastEnableUsageMs == 0) { 138 Log.e(TAG, "disableUsage: mLastEnableUsage not initialized!?"); 139 return; 140 } 141 142 long now = mClock.getElapsedSinceBootMillis(); 143 addLogValueToHistogram(now - mLastEnableUsageMs, mHistogramAwareAvailableDurationMs, 144 DURATION_LOG_HISTOGRAM); 145 mAvailableTimeMs += now - mLastEnableUsageInThisSampleWindowMs; 146 mLastEnableUsageMs = 0; 147 mLastEnableUsageInThisSampleWindowMs = 0; 148 } 149 } 150 151 /** 152 * Push usage stats of Aware actually being enabled on-the-air: start 153 */ 154 public void recordEnableAware() { 155 synchronized (mLock) { 156 if (mLastEnableAwareMs != 0) { 157 return; // already enabled 158 } 159 mLastEnableAwareMs = mClock.getElapsedSinceBootMillis(); 160 mLastEnableAwareInThisSampleWindowMs = mLastEnableAwareMs; 161 } 162 } 163 164 /** 165 * Push usage stats of Aware actually being enabled on-the-air: stop (disable) 166 */ 167 public void recordDisableAware() { 168 synchronized (mLock) { 169 if (mLastEnableAwareMs == 0) { 170 return; // already disabled 171 } 172 173 long now = mClock.getElapsedSinceBootMillis(); 174 addLogValueToHistogram(now - mLastEnableAwareMs, mHistogramAwareEnabledDurationMs, 175 DURATION_LOG_HISTOGRAM); 176 mEnabledTimeMs += now - mLastEnableAwareInThisSampleWindowMs; 177 mLastEnableAwareMs = 0; 178 mLastEnableAwareInThisSampleWindowMs = 0; 179 } 180 } 181 182 /** 183 * Push information about a new attach session. 184 */ 185 public void recordAttachSession(int uid, boolean usesIdentityCallback, 186 SparseArray<WifiAwareClientState> clients) { 187 // count the number of clients with the specific uid 188 int currentConcurrentCount = 0; 189 for (int i = 0; i < clients.size(); ++i) { 190 if (clients.valueAt(i).getUid() == uid) { 191 ++currentConcurrentCount; 192 } 193 } 194 195 synchronized (mLock) { 196 AttachData data = mAttachDataByUid.get(uid); 197 if (data == null) { 198 data = new AttachData(); 199 mAttachDataByUid.put(uid, data); 200 } 201 data.mUsesIdentityCallback |= usesIdentityCallback; 202 data.mMaxConcurrentAttaches = Math.max(data.mMaxConcurrentAttaches, 203 currentConcurrentCount); 204 recordAttachStatus(NanStatusType.SUCCESS); 205 } 206 } 207 208 /** 209 * Push information about a new attach session status (recorded when attach session is created). 210 */ 211 public void recordAttachStatus(int status) { 212 synchronized (mLock) { 213 mAttachStatusData.put(status, mAttachStatusData.get(status) + 1); 214 } 215 } 216 217 /** 218 * Push duration information of an attach session. 219 */ 220 public void recordAttachSessionDuration(long creationTime) { 221 synchronized (mLock) { 222 addLogValueToHistogram(mClock.getElapsedSinceBootMillis() - creationTime, 223 mHistogramAttachDuration, 224 DURATION_LOG_HISTOGRAM); 225 } 226 } 227 228 /** 229 * Push information about the new discovery session. 230 */ 231 public void recordDiscoverySession(int uid, boolean isPublish, 232 SparseArray<WifiAwareClientState> clients) { 233 // count the number of sessions per uid and overall 234 int numPublishesInSystem = 0; 235 int numSubscribesInSystem = 0; 236 int numPublishesOnUid = 0; 237 int numSubscribesOnUid = 0; 238 239 for (int i = 0; i < clients.size(); ++i) { 240 WifiAwareClientState client = clients.valueAt(i); 241 boolean sameUid = client.getUid() == uid; 242 243 SparseArray<WifiAwareDiscoverySessionState> sessions = client.getSessions(); 244 for (int j = 0; j < sessions.size(); ++j) { 245 WifiAwareDiscoverySessionState session = sessions.valueAt(j); 246 247 if (session.isPublishSession()) { 248 numPublishesInSystem += 1; 249 if (sameUid) { 250 numPublishesOnUid += 1; 251 } 252 } else { 253 numSubscribesInSystem += 1; 254 if (sameUid) { 255 numSubscribesOnUid += 1; 256 } 257 } 258 } 259 } 260 261 synchronized (mLock) { 262 mMaxPublishInApp = Math.max(mMaxPublishInApp, numPublishesOnUid); 263 mMaxSubscribeInApp = Math.max(mMaxSubscribeInApp, numSubscribesOnUid); 264 mMaxDiscoveryInApp = Math.max(mMaxDiscoveryInApp, 265 numPublishesOnUid + numSubscribesOnUid); 266 mMaxPublishInSystem = Math.max(mMaxPublishInSystem, numPublishesInSystem); 267 mMaxSubscribeInSystem = Math.max(mMaxSubscribeInSystem, numSubscribesInSystem); 268 mMaxDiscoveryInSystem = Math.max(mMaxDiscoveryInSystem, 269 numPublishesInSystem + numSubscribesInSystem); 270 } 271 } 272 273 /** 274 * Push information about a new discovery session status (recorded when the discovery session is 275 * created). 276 */ 277 public void recordDiscoveryStatus(int uid, int status, boolean isPublish) { 278 synchronized (mLock) { 279 if (isPublish) { 280 mPublishStatusData.put(status, mPublishStatusData.get(status) + 1); 281 } else { 282 mSubscribeStatusData.put(status, mSubscribeStatusData.get(status) + 1); 283 } 284 285 if (status == NanStatusType.NO_RESOURCES_AVAILABLE) { 286 mAppsWithDiscoverySessionResourceFailure.add(uid); 287 } 288 } 289 } 290 291 /** 292 * Push duration information of a discovery session. 293 */ 294 public void recordDiscoverySessionDuration(long creationTime, boolean isPublish) { 295 synchronized (mLock) { 296 addLogValueToHistogram(mClock.getElapsedSinceBootMillis() - creationTime, 297 isPublish ? mHistogramPublishDuration : mHistogramSubscribeDuration, 298 DURATION_LOG_HISTOGRAM); 299 } 300 } 301 302 /** 303 * Record NDP (and by extension NDI) usage - on successful creation of an NDP. 304 */ 305 public void recordNdpCreation(int uid, 306 Map<WifiAwareNetworkSpecifier, WifiAwareDataPathStateManager 307 .AwareNetworkRequestInformation> networkRequestCache) { 308 int numNdpInApp = 0; 309 int numSecureNdpInApp = 0; 310 int numNdpInSystem = 0; 311 int numSecureNdpInSystem = 0; 312 313 Map<String, Integer> ndpPerNdiMap = new HashMap<>(); 314 Set<String> ndiInApp = new HashSet<>(); 315 Set<String> ndiInSystem = new HashSet<>(); 316 317 for (WifiAwareDataPathStateManager.AwareNetworkRequestInformation anri : 318 networkRequestCache.values()) { 319 if (anri.state 320 != WifiAwareDataPathStateManager.AwareNetworkRequestInformation 321 .STATE_INITIATOR_CONFIRMED 322 && anri.state 323 != WifiAwareDataPathStateManager.AwareNetworkRequestInformation 324 .STATE_RESPONDER_CONFIRMED) { 325 continue; // only count completed (up-and-running) NDPs 326 } 327 328 boolean sameUid = anri.uid == uid; 329 boolean isSecure = !TextUtils.isEmpty(anri.networkSpecifier.passphrase) || ( 330 anri.networkSpecifier.pmk != null && anri.networkSpecifier.pmk.length != 0); 331 332 // in-app stats 333 if (sameUid) { 334 numNdpInApp += 1; 335 if (isSecure) { 336 numSecureNdpInApp += 1; 337 } 338 339 ndiInApp.add(anri.interfaceName); 340 } 341 342 // system stats 343 numNdpInSystem += 1; 344 if (isSecure) { 345 numSecureNdpInSystem += 1; 346 } 347 348 // ndp/ndi stats 349 Integer ndpCount = ndpPerNdiMap.get(anri.interfaceName); 350 if (ndpCount == null) { 351 ndpPerNdiMap.put(anri.interfaceName, 1); 352 } else { 353 ndpPerNdiMap.put(anri.interfaceName, ndpCount + 1); 354 } 355 356 // ndi stats 357 ndiInSystem.add(anri.interfaceName); 358 } 359 360 synchronized (mLock) { 361 mMaxNdiInApp = Math.max(mMaxNdiInApp, ndiInApp.size()); 362 mMaxNdpInApp = Math.max(mMaxNdpInApp, numNdpInApp); 363 mMaxSecureNdpInApp = Math.max(mMaxSecureNdpInApp, numSecureNdpInApp); 364 mMaxNdiInSystem = Math.max(mMaxNdiInSystem, ndiInSystem.size()); 365 mMaxNdpInSystem = Math.max(mMaxNdpInSystem, numNdpInSystem); 366 mMaxSecureNdpInSystem = Math.max(mMaxSecureNdpInSystem, numSecureNdpInSystem); 367 mMaxNdpPerNdi = Math.max(mMaxNdpPerNdi, Collections.max(ndpPerNdiMap.values())); 368 } 369 } 370 371 /** 372 * Record the completion status of NDP negotiation. There are multiple steps in NDP negotiation 373 * a failure on any aborts the process and is recorded. A success on intermediate stages is 374 * not recorded - only the final success. 375 */ 376 public void recordNdpStatus(int status, boolean isOutOfBand, long startTimestamp) { 377 synchronized (mLock) { 378 if (isOutOfBand) { 379 mOutOfBandNdpStatusData.put(status, mOutOfBandNdpStatusData.get(status) + 1); 380 } else { 381 mInBandNdpStatusData.put(status, mOutOfBandNdpStatusData.get(status) + 1); 382 } 383 384 if (status == NanStatusType.SUCCESS) { 385 long creationTime = mClock.getElapsedSinceBootMillis() - startTimestamp; 386 addLogValueToHistogram(creationTime, mNdpCreationTimeDuration, 387 DURATION_LOG_HISTOGRAM); 388 mNdpCreationTimeMin = (mNdpCreationTimeMin == -1) ? creationTime : Math.min( 389 mNdpCreationTimeMin, creationTime); 390 mNdpCreationTimeMax = Math.max(mNdpCreationTimeMax, creationTime); 391 mNdpCreationTimeSum += creationTime; 392 mNdpCreationTimeSumSq += creationTime * creationTime; 393 mNdpCreationTimeNumSamples += 1; 394 } 395 } 396 } 397 398 /** 399 * Consolidate all metrics into the proto. 400 */ 401 public WifiMetricsProto.WifiAwareLog consolidateProto() { 402 WifiMetricsProto.WifiAwareLog log = new WifiMetricsProto.WifiAwareLog(); 403 long now = mClock.getElapsedSinceBootMillis(); 404 synchronized (mLock) { 405 log.histogramAwareAvailableDurationMs = histogramToProtoArray( 406 mHistogramAwareAvailableDurationMs, DURATION_LOG_HISTOGRAM); 407 log.availableTimeMs = mAvailableTimeMs; 408 if (mLastEnableUsageInThisSampleWindowMs != 0) { 409 log.availableTimeMs += now - mLastEnableUsageInThisSampleWindowMs; 410 } 411 412 log.histogramAwareEnabledDurationMs = histogramToProtoArray( 413 mHistogramAwareEnabledDurationMs, DURATION_LOG_HISTOGRAM); 414 log.enabledTimeMs = mEnabledTimeMs; 415 if (mLastEnableAwareInThisSampleWindowMs != 0) { 416 log.enabledTimeMs += now - mLastEnableAwareInThisSampleWindowMs; 417 } 418 419 log.numApps = mAttachDataByUid.size(); 420 log.numAppsUsingIdentityCallback = 0; 421 log.maxConcurrentAttachSessionsInApp = 0; 422 for (AttachData ad: mAttachDataByUid.values()) { 423 if (ad.mUsesIdentityCallback) { 424 ++log.numAppsUsingIdentityCallback; 425 } 426 log.maxConcurrentAttachSessionsInApp = Math.max( 427 log.maxConcurrentAttachSessionsInApp, ad.mMaxConcurrentAttaches); 428 } 429 log.histogramAttachSessionStatus = histogramToProtoArray(mAttachStatusData); 430 log.histogramAttachDurationMs = histogramToProtoArray(mHistogramAttachDuration, 431 DURATION_LOG_HISTOGRAM); 432 433 log.maxConcurrentPublishInApp = mMaxPublishInApp; 434 log.maxConcurrentSubscribeInApp = mMaxSubscribeInApp; 435 log.maxConcurrentDiscoverySessionsInApp = mMaxDiscoveryInApp; 436 log.maxConcurrentPublishInSystem = mMaxPublishInSystem; 437 log.maxConcurrentSubscribeInSystem = mMaxSubscribeInSystem; 438 log.maxConcurrentDiscoverySessionsInSystem = mMaxDiscoveryInSystem; 439 log.histogramPublishStatus = histogramToProtoArray(mPublishStatusData); 440 log.histogramSubscribeStatus = histogramToProtoArray(mSubscribeStatusData); 441 log.numAppsWithDiscoverySessionFailureOutOfResources = 442 mAppsWithDiscoverySessionResourceFailure.size(); 443 log.histogramPublishSessionDurationMs = histogramToProtoArray(mHistogramPublishDuration, 444 DURATION_LOG_HISTOGRAM); 445 log.histogramSubscribeSessionDurationMs = histogramToProtoArray( 446 mHistogramSubscribeDuration, DURATION_LOG_HISTOGRAM); 447 448 log.maxConcurrentNdiInApp = mMaxNdiInApp; 449 log.maxConcurrentNdiInSystem = mMaxNdiInSystem; 450 log.maxConcurrentNdpInApp = mMaxNdpInApp; 451 log.maxConcurrentNdpInSystem = mMaxNdpInSystem; 452 log.maxConcurrentSecureNdpInApp = mMaxSecureNdpInApp; 453 log.maxConcurrentSecureNdpInSystem = mMaxSecureNdpInSystem; 454 log.maxConcurrentNdpPerNdi = mMaxNdpPerNdi; 455 log.histogramRequestNdpStatus = histogramToProtoArray(mInBandNdpStatusData); 456 log.histogramRequestNdpOobStatus = histogramToProtoArray(mOutOfBandNdpStatusData); 457 458 log.histogramNdpCreationTimeMs = histogramToProtoArray(mNdpCreationTimeDuration, 459 DURATION_LOG_HISTOGRAM); 460 log.ndpCreationTimeMsMin = mNdpCreationTimeMin; 461 log.ndpCreationTimeMsMax = mNdpCreationTimeMax; 462 log.ndpCreationTimeMsSum = mNdpCreationTimeSum; 463 log.ndpCreationTimeMsSumOfSq = mNdpCreationTimeSumSq; 464 log.ndpCreationTimeMsNumSamples = mNdpCreationTimeNumSamples; 465 } 466 return log; 467 } 468 469 /** 470 * clear Wi-Fi Aware metrics 471 */ 472 public void clear() { 473 long now = mClock.getElapsedSinceBootMillis(); 474 synchronized (mLock) { 475 // don't clear mLastEnableUsage since could be valid for next measurement period 476 mHistogramAwareAvailableDurationMs.clear(); 477 mAvailableTimeMs = 0; 478 if (mLastEnableUsageInThisSampleWindowMs != 0) { 479 mLastEnableUsageInThisSampleWindowMs = now; 480 } 481 482 // don't clear mLastEnableAware since could be valid for next measurement period 483 mHistogramAwareEnabledDurationMs.clear(); 484 mEnabledTimeMs = 0; 485 if (mLastEnableAwareInThisSampleWindowMs != 0) { 486 mLastEnableAwareInThisSampleWindowMs = now; 487 } 488 489 mAttachDataByUid.clear(); 490 mAttachStatusData.clear(); 491 mHistogramAttachDuration.clear(); 492 493 mMaxPublishInApp = 0; 494 mMaxSubscribeInApp = 0; 495 mMaxDiscoveryInApp = 0; 496 mMaxPublishInSystem = 0; 497 mMaxSubscribeInSystem = 0; 498 mMaxDiscoveryInSystem = 0; 499 mPublishStatusData.clear(); 500 mSubscribeStatusData.clear(); 501 mHistogramPublishDuration.clear(); 502 mHistogramSubscribeDuration.clear(); 503 mAppsWithDiscoverySessionResourceFailure.clear(); 504 505 mMaxNdiInApp = 0; 506 mMaxNdpInApp = 0; 507 mMaxSecureNdpInApp = 0; 508 mMaxNdiInSystem = 0; 509 mMaxNdpInSystem = 0; 510 mMaxSecureNdpInSystem = 0; 511 mMaxNdpPerNdi = 0; 512 mInBandNdpStatusData.clear(); 513 mOutOfBandNdpStatusData.clear(); 514 515 mNdpCreationTimeDuration.clear(); 516 mNdpCreationTimeMin = -1; 517 mNdpCreationTimeMax = 0; 518 mNdpCreationTimeSum = 0; 519 mNdpCreationTimeSumSq = 0; 520 mNdpCreationTimeNumSamples = 0; 521 } 522 } 523 524 /** 525 * Dump all WifiAwareMetrics to console (pw) - this method is never called to dump the 526 * serialized metrics (handled by parent WifiMetrics). 527 * 528 * @param fd unused 529 * @param pw PrintWriter for writing dump to 530 * @param args unused 531 */ 532 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 533 synchronized (mLock) { 534 pw.println("mLastEnableUsage:" + mLastEnableUsageMs); 535 pw.println( 536 "mLastEnableUsageInThisSampleWindow:" + mLastEnableUsageInThisSampleWindowMs); 537 pw.println("mAvailableTime:" + mAvailableTimeMs); 538 pw.println("mHistogramAwareAvailableDurationMs:"); 539 for (int i = 0; i < mHistogramAwareAvailableDurationMs.size(); ++i) { 540 pw.println(" " + mHistogramAwareAvailableDurationMs.keyAt(i) + ": " 541 + mHistogramAwareAvailableDurationMs.valueAt(i)); 542 } 543 pw.println("mAttachDataByUid:"); 544 for (Map.Entry<Integer, AttachData> ade: mAttachDataByUid.entrySet()) { 545 pw.println(" " + "uid=" + ade.getKey() + ": identity=" 546 + ade.getValue().mUsesIdentityCallback + ", maxConcurrent=" 547 + ade.getValue().mMaxConcurrentAttaches); 548 } 549 pw.println("mAttachStatusData:"); 550 for (int i = 0; i < mAttachStatusData.size(); ++i) { 551 pw.println(" " + mAttachStatusData.keyAt(i) + ": " 552 + mAttachStatusData.valueAt(i)); 553 } 554 pw.println("mHistogramAttachDuration:"); 555 for (int i = 0; i < mHistogramAttachDuration.size(); ++i) { 556 pw.println(" " + mHistogramAttachDuration.keyAt(i) + ": " 557 + mHistogramAttachDuration.valueAt(i)); 558 } 559 } 560 } 561 562 // histogram utilities 563 564 /** 565 * Specifies a ~log histogram consisting of two levels of buckets - a set of N big buckets: 566 * 567 * Buckets starts at: B + P * M^i, where i=0, ... , N-1 (N big buckets) 568 * Each big bucket is divided into S sub-buckets 569 * 570 * Each (big) bucket is M times bigger than the previous one. 571 * 572 * The buckets are then: 573 * #0: B + P * M^0 with S buckets each of width (P*M^1-P*M^0)/S 574 * #1: B + P * M^1 with S buckets each of width (P*M^2-P*M^1)/S 575 * ... 576 * #N-1: B + P * M^(N-1) with S buckets each of width (P*M^N-P*M^(N-1))/S 577 */ 578 @VisibleForTesting 579 public static class HistParms { 580 public HistParms(int b, int p, int m, int s, int n) { 581 this.b = b; 582 this.p = p; 583 this.m = m; 584 this.s = s; 585 this.n = n; 586 587 // derived values 588 mLog = Math.log(m); 589 bb = new double[n]; 590 sbw = new double[n]; 591 bb[0] = b + p; 592 sbw[0] = p * (m - 1.0) / (double) s; 593 for (int i = 1; i < n; ++i) { 594 bb[i] = m * (bb[i - 1] - b) + b; 595 sbw[i] = m * sbw[i - 1]; 596 } 597 } 598 599 // spec 600 public int b; 601 public int p; 602 public int m; 603 public int s; 604 public int n; 605 606 // derived 607 public double mLog; 608 public double[] bb; // bucket base 609 public double[] sbw; // sub-bucket width 610 } 611 612 /** 613 * Adds the input value to the histogram based on the histogram parameters. 614 */ 615 @VisibleForTesting 616 public static int addLogValueToHistogram(long x, SparseIntArray histogram, HistParms hp) { 617 double logArg = (double) (x - hp.b) / (double) hp.p; 618 int bigBucketIndex = -1; 619 if (logArg > 0) { 620 bigBucketIndex = (int) (Math.log(logArg) / hp.mLog); 621 } 622 int subBucketIndex; 623 if (bigBucketIndex < 0) { 624 bigBucketIndex = 0; 625 subBucketIndex = 0; 626 } else if (bigBucketIndex >= hp.n) { 627 bigBucketIndex = hp.n - 1; 628 subBucketIndex = hp.s - 1; 629 } else { 630 subBucketIndex = (int) ((x - hp.bb[bigBucketIndex]) / hp.sbw[bigBucketIndex]); 631 if (subBucketIndex >= hp.s) { // probably a rounding error so move to next big bucket 632 bigBucketIndex++; 633 if (bigBucketIndex >= hp.n) { 634 bigBucketIndex = hp.n - 1; 635 subBucketIndex = hp.s - 1; 636 } else { 637 subBucketIndex = (int) ((x - hp.bb[bigBucketIndex]) / hp.sbw[bigBucketIndex]); 638 } 639 } 640 } 641 int key = bigBucketIndex * hp.s + subBucketIndex; 642 643 // note that get() returns 0 if index not there already 644 int newValue = histogram.get(key) + 1; 645 histogram.put(key, newValue); 646 647 return newValue; 648 } 649 650 /** 651 * Converts the histogram (with the specified histogram parameters) to an array of proto 652 * histogram buckets. 653 */ 654 @VisibleForTesting 655 public static WifiMetricsProto.WifiAwareLog.HistogramBucket[] histogramToProtoArray( 656 SparseIntArray histogram, HistParms hp) { 657 WifiMetricsProto.WifiAwareLog.HistogramBucket[] protoArray = 658 new WifiMetricsProto.WifiAwareLog.HistogramBucket[histogram.size()]; 659 for (int i = 0; i < histogram.size(); ++i) { 660 int key = histogram.keyAt(i); 661 662 protoArray[i] = new WifiMetricsProto.WifiAwareLog.HistogramBucket(); 663 protoArray[i].start = (long) (hp.bb[key / hp.s] + hp.sbw[key / hp.s] * (key % hp.s)); 664 protoArray[i].end = (long) (protoArray[i].start + hp.sbw[key / hp.s]); 665 protoArray[i].count = histogram.valueAt(i); 666 } 667 668 return protoArray; 669 } 670 671 /** 672 * Adds the NanStatusType to the histogram (translating to the proto enumeration of the status). 673 */ 674 public static void addNanHalStatusToHistogram(int halStatus, SparseIntArray histogram) { 675 int protoStatus = convertNanStatusTypeToProtoEnum(halStatus); 676 int newValue = histogram.get(protoStatus) + 1; 677 histogram.put(protoStatus, newValue); 678 } 679 680 /** 681 * Converts a histogram of proto NanStatusTypeEnum to a raw proto histogram. 682 */ 683 @VisibleForTesting 684 public static WifiMetricsProto.WifiAwareLog.NanStatusHistogramBucket[] histogramToProtoArray( 685 SparseIntArray histogram) { 686 WifiMetricsProto.WifiAwareLog.NanStatusHistogramBucket[] protoArray = 687 new WifiMetricsProto.WifiAwareLog.NanStatusHistogramBucket[histogram.size()]; 688 689 for (int i = 0; i < histogram.size(); ++i) { 690 protoArray[i] = new WifiMetricsProto.WifiAwareLog.NanStatusHistogramBucket(); 691 protoArray[i].nanStatusType = histogram.keyAt(i); 692 protoArray[i].count = histogram.valueAt(i); 693 } 694 695 return protoArray; 696 } 697 698 /** 699 * Convert a HAL NanStatusType enum to a Metrics proto enum NanStatusTypeEnum. 700 */ 701 public static int convertNanStatusTypeToProtoEnum(int nanStatusType) { 702 switch (nanStatusType) { 703 case NanStatusType.SUCCESS: 704 return WifiMetricsProto.WifiAwareLog.SUCCESS; 705 case NanStatusType.INTERNAL_FAILURE: 706 return WifiMetricsProto.WifiAwareLog.INTERNAL_FAILURE; 707 case NanStatusType.PROTOCOL_FAILURE: 708 return WifiMetricsProto.WifiAwareLog.PROTOCOL_FAILURE; 709 case NanStatusType.INVALID_SESSION_ID: 710 return WifiMetricsProto.WifiAwareLog.INVALID_SESSION_ID; 711 case NanStatusType.NO_RESOURCES_AVAILABLE: 712 return WifiMetricsProto.WifiAwareLog.NO_RESOURCES_AVAILABLE; 713 case NanStatusType.INVALID_ARGS: 714 return WifiMetricsProto.WifiAwareLog.INVALID_ARGS; 715 case NanStatusType.INVALID_PEER_ID: 716 return WifiMetricsProto.WifiAwareLog.INVALID_PEER_ID; 717 case NanStatusType.INVALID_NDP_ID: 718 return WifiMetricsProto.WifiAwareLog.INVALID_NDP_ID; 719 case NanStatusType.NAN_NOT_ALLOWED: 720 return WifiMetricsProto.WifiAwareLog.NAN_NOT_ALLOWED; 721 case NanStatusType.NO_OTA_ACK: 722 return WifiMetricsProto.WifiAwareLog.NO_OTA_ACK; 723 case NanStatusType.ALREADY_ENABLED: 724 return WifiMetricsProto.WifiAwareLog.ALREADY_ENABLED; 725 case NanStatusType.FOLLOWUP_TX_QUEUE_FULL: 726 return WifiMetricsProto.WifiAwareLog.FOLLOWUP_TX_QUEUE_FULL; 727 case NanStatusType.UNSUPPORTED_CONCURRENCY_NAN_DISABLED: 728 return WifiMetricsProto.WifiAwareLog.UNSUPPORTED_CONCURRENCY_NAN_DISABLED; 729 default: 730 Log.e(TAG, "Unrecognized NanStatusType: " + nanStatusType); 731 return WifiMetricsProto.WifiAwareLog.UNKNOWN_HAL_STATUS; 732 } 733 } 734} 735