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