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