WifiAwareMetrics.java revision da389f4b673e0f3fe54dc5b1123221037eb96e42
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.util.Log; 21import android.util.SparseArray; 22import android.util.SparseIntArray; 23 24import com.android.internal.annotations.VisibleForTesting; 25import com.android.server.wifi.Clock; 26import com.android.server.wifi.nano.WifiMetricsProto; 27 28import java.io.FileDescriptor; 29import java.io.PrintWriter; 30import java.util.HashMap; 31import java.util.HashSet; 32import java.util.Map; 33import java.util.Set; 34 35/** 36 * Wi-Fi Aware metric container/processor. 37 */ 38public class WifiAwareMetrics { 39 private static final String TAG = "WifiAwareMetrics"; 40 private static final boolean DBG = false; 41 42 // Histogram: 8 buckets (i=0, ..., 7) of 9 slots in range 10^i -> 10^(i+1) 43 // Buckets: 44 // 1 -> 10: 9 @ 1 45 // 10 -> 100: 9 @ 10 46 // 100 -> 1000: 9 @ 10^2 47 // 10^3 -> 10^4: 9 @ 10^3 48 // 10^4 -> 10^5: 9 @ 10^4 49 // 10^5 -> 10^6: 9 @ 10^5 50 // 10^6 -> 10^7: 9 @ 10^6 51 // 10^7 -> 10^8: 9 @ 10^7 --> 10^8 ms -> 10^5s -> 28 hours 52 private static final HistParms DURATION_LOG_HISTOGRAM = new HistParms(0, 1, 10, 9, 8); 53 54 private final Object mLock = new Object(); 55 private final Clock mClock; 56 57 // enableUsage/disableUsage data 58 private long mLastEnableUsageMs = 0; 59 private long mLastEnableUsageInThisSampleWindowMs = 0; 60 private long mAvailableTimeMs = 0; 61 private SparseIntArray mHistogramAwareAvailableDurationMs = new SparseIntArray(); 62 63 // enabled data 64 private long mLastEnableAwareMs = 0; 65 private long mLastEnableAwareInThisSampleWindowMs = 0; 66 private long mEnabledTimeMs = 0; 67 private SparseIntArray mHistogramAwareEnabledDurationMs = new SparseIntArray(); 68 69 // attach data 70 private static class AttachData { 71 boolean mUsesIdentityCallback; // do any attach sessions of the UID use identity callback 72 int mMaxConcurrentAttaches; 73 } 74 private Map<Integer, AttachData> mAttachDataByUid = new HashMap<>(); 75 private SparseIntArray mAttachStatusData = new SparseIntArray(); 76 private SparseIntArray mHistogramAttachDuration = new SparseIntArray(); 77 78 // discovery data 79 private SparseIntArray mMaxPublishByUid = new SparseIntArray(); 80 private SparseIntArray mMaxSubscribeByUid = new SparseIntArray(); 81 private SparseIntArray mMaxDiscoveryByUid = new SparseIntArray(); 82 private int mMaxPublishInSystem = 0; 83 private int mMaxSubscribeInSystem = 0; 84 private int mMaxDiscoveryInSystem = 0; 85 private SparseIntArray mPublishStatusData = new SparseIntArray(); 86 private SparseIntArray mSubscribeStatusData = new SparseIntArray(); 87 private SparseIntArray mHistogramPublishDuration = new SparseIntArray(); 88 private SparseIntArray mHistogramSubscribeDuration = new SparseIntArray(); 89 private Set<Integer> mAppsWithDiscoverySessionResourceFailure = new HashSet<>(); 90 91 public WifiAwareMetrics(Clock clock) { 92 mClock = clock; 93 } 94 95 /** 96 * Push usage stats for WifiAwareStateMachine.enableUsage() to 97 * histogram_aware_available_duration_ms. 98 */ 99 public void recordEnableUsage() { 100 synchronized (mLock) { 101 if (mLastEnableUsageMs != 0) { 102 Log.w(TAG, "enableUsage: mLastEnableUsage*Ms initialized!?"); 103 } 104 mLastEnableUsageMs = mClock.getElapsedSinceBootMillis(); 105 mLastEnableUsageInThisSampleWindowMs = mLastEnableUsageMs; 106 } 107 } 108 109 /** 110 * Push usage stats for WifiAwareStateMachine.disableUsage() to 111 * histogram_aware_available_duration_ms. 112 */ 113 114 public void recordDisableUsage() { 115 synchronized (mLock) { 116 if (mLastEnableUsageMs == 0) { 117 Log.e(TAG, "disableUsage: mLastEnableUsage not initialized!?"); 118 return; 119 } 120 121 long now = mClock.getElapsedSinceBootMillis(); 122 addLogValueToHistogram(now - mLastEnableUsageMs, mHistogramAwareAvailableDurationMs, 123 DURATION_LOG_HISTOGRAM); 124 mAvailableTimeMs += now - mLastEnableUsageInThisSampleWindowMs; 125 mLastEnableUsageMs = 0; 126 mLastEnableUsageInThisSampleWindowMs = 0; 127 } 128 } 129 130 /** 131 * Push usage stats of Aware actually being enabled on-the-air: start 132 */ 133 public void recordEnableAware() { 134 synchronized (mLock) { 135 if (mLastEnableAwareMs != 0) { 136 return; // already enabled 137 } 138 mLastEnableAwareMs = mClock.getElapsedSinceBootMillis(); 139 mLastEnableAwareInThisSampleWindowMs = mLastEnableAwareMs; 140 } 141 } 142 143 /** 144 * Push usage stats of Aware actually being enabled on-the-air: stop (disable) 145 */ 146 public void recordDisableAware() { 147 synchronized (mLock) { 148 if (mLastEnableAwareMs == 0) { 149 return; // already disabled 150 } 151 152 long now = mClock.getElapsedSinceBootMillis(); 153 addLogValueToHistogram(now - mLastEnableAwareMs, mHistogramAwareEnabledDurationMs, 154 DURATION_LOG_HISTOGRAM); 155 mEnabledTimeMs += now - mLastEnableAwareInThisSampleWindowMs; 156 mLastEnableAwareMs = 0; 157 mLastEnableAwareInThisSampleWindowMs = 0; 158 } 159 } 160 161 /** 162 * Push information about a new attach session. 163 */ 164 public void recordAttachSession(int uid, boolean usesIdentityCallback, 165 SparseArray<WifiAwareClientState> clients) { 166 // count the number of clients with the specific uid 167 int currentConcurrentCount = 0; 168 for (int i = 0; i < clients.size(); ++i) { 169 if (clients.valueAt(i).getUid() == uid) { 170 ++currentConcurrentCount; 171 } 172 } 173 174 synchronized (mLock) { 175 AttachData data = mAttachDataByUid.get(uid); 176 if (data == null) { 177 data = new AttachData(); 178 mAttachDataByUid.put(uid, data); 179 } 180 data.mUsesIdentityCallback |= usesIdentityCallback; 181 data.mMaxConcurrentAttaches = Math.max(data.mMaxConcurrentAttaches, 182 currentConcurrentCount); 183 recordAttachStatus(NanStatusType.SUCCESS); 184 } 185 } 186 187 /** 188 * Push information about a new attach session status (recorded when attach session is created). 189 */ 190 public void recordAttachStatus(int status) { 191 synchronized (mLock) { 192 mAttachStatusData.put(status, mAttachStatusData.get(status) + 1); 193 } 194 } 195 196 /** 197 * Push duration information of an attach session. 198 */ 199 public void recordAttachSessionDuration(long creationTime) { 200 synchronized (mLock) { 201 addLogValueToHistogram(mClock.getElapsedSinceBootMillis() - creationTime, 202 mHistogramAttachDuration, 203 DURATION_LOG_HISTOGRAM); 204 } 205 } 206 207 /** 208 * Push information about the new discovery session. 209 */ 210 public void recordDiscoverySession(int uid, boolean isPublish, 211 SparseArray<WifiAwareClientState> clients) { 212 // count the number of sessions per uid and overall 213 int numPublishesInSystem = 0; 214 int numSubscribesInSystem = 0; 215 int numPublishesOnUid = 0; 216 int numSubscribesOnUid = 0; 217 218 for (int i = 0; i < clients.size(); ++i) { 219 WifiAwareClientState client = clients.valueAt(i); 220 boolean sameUid = client.getUid() == uid; 221 222 SparseArray<WifiAwareDiscoverySessionState> sessions = client.getSessions(); 223 for (int j = 0; j < sessions.size(); ++j) { 224 WifiAwareDiscoverySessionState session = sessions.valueAt(j); 225 226 if (session.isPublishSession()) { 227 numPublishesInSystem += 1; 228 if (sameUid) { 229 numPublishesOnUid += 1; 230 } 231 } else { 232 numSubscribesInSystem += 1; 233 if (sameUid) { 234 numSubscribesOnUid += 1; 235 } 236 } 237 } 238 } 239 240 synchronized (mLock) { 241 mMaxPublishByUid.put(uid, Math.max(mMaxPublishByUid.get(uid), numPublishesOnUid)); 242 mMaxSubscribeByUid.put(uid, Math.max(mMaxSubscribeByUid.get(uid), numSubscribesOnUid)); 243 mMaxDiscoveryByUid.put(uid, 244 Math.max(mMaxDiscoveryByUid.get(uid), numPublishesOnUid + numSubscribesOnUid)); 245 mMaxPublishInSystem = Math.max(mMaxPublishInSystem, numPublishesInSystem); 246 mMaxSubscribeInSystem = Math.max(mMaxSubscribeInSystem, numSubscribesInSystem); 247 mMaxDiscoveryInSystem = Math.max(mMaxDiscoveryInSystem, 248 numPublishesInSystem + numSubscribesInSystem); 249 } 250 } 251 252 /** 253 * Push information about a new discovery session status (recorded when the discovery session is 254 * created). 255 */ 256 public void recordDiscoveryStatus(int uid, int status, boolean isPublish) { 257 synchronized (mLock) { 258 if (isPublish) { 259 mPublishStatusData.put(status, mPublishStatusData.get(status) + 1); 260 } else { 261 mSubscribeStatusData.put(status, mSubscribeStatusData.get(status) + 1); 262 } 263 264 if (status == NanStatusType.NO_RESOURCES_AVAILABLE) { 265 mAppsWithDiscoverySessionResourceFailure.add(uid); 266 } 267 } 268 } 269 270 /** 271 * Push duration information of a discovery session. 272 */ 273 public void recordDiscoverySessionDuration(long creationTime, boolean isPublish) { 274 synchronized (mLock) { 275 addLogValueToHistogram(mClock.getElapsedSinceBootMillis() - creationTime, 276 isPublish ? mHistogramPublishDuration : mHistogramSubscribeDuration, 277 DURATION_LOG_HISTOGRAM); 278 } 279 } 280 281 /** 282 * Consolidate all metrics into the proto. 283 */ 284 public WifiMetricsProto.WifiAwareLog consolidateProto() { 285 WifiMetricsProto.WifiAwareLog log = new WifiMetricsProto.WifiAwareLog(); 286 long now = mClock.getElapsedSinceBootMillis(); 287 synchronized (mLock) { 288 log.histogramAwareAvailableDurationMs = histogramToProtoArray( 289 mHistogramAwareAvailableDurationMs, DURATION_LOG_HISTOGRAM); 290 log.availableTimeMs = mAvailableTimeMs; 291 if (mLastEnableUsageInThisSampleWindowMs != 0) { 292 log.availableTimeMs += now - mLastEnableUsageInThisSampleWindowMs; 293 } 294 295 log.histogramAwareEnabledDurationMs = histogramToProtoArray( 296 mHistogramAwareEnabledDurationMs, DURATION_LOG_HISTOGRAM); 297 log.enabledTimeMs = mEnabledTimeMs; 298 if (mLastEnableAwareInThisSampleWindowMs != 0) { 299 log.enabledTimeMs += now - mLastEnableAwareInThisSampleWindowMs; 300 } 301 302 log.numApps = mAttachDataByUid.size(); 303 log.numAppsUsingIdentityCallback = 0; 304 log.maxConcurrentAttachSessionsInApp = 0; 305 for (AttachData ad: mAttachDataByUid.values()) { 306 if (ad.mUsesIdentityCallback) { 307 ++log.numAppsUsingIdentityCallback; 308 } 309 log.maxConcurrentAttachSessionsInApp = Math.max( 310 log.maxConcurrentAttachSessionsInApp, ad.mMaxConcurrentAttaches); 311 } 312 log.histogramAttachSessionStatus = histogramToProtoArray(mAttachStatusData); 313 log.histogramAttachDurationMs = histogramToProtoArray(mHistogramAttachDuration, 314 DURATION_LOG_HISTOGRAM); 315 316 log.maxConcurrentPublishInApp = max(mMaxPublishByUid); 317 log.maxConcurrentSubscribeInApp = max(mMaxSubscribeByUid); 318 log.maxConcurrentDiscoverySessionsInApp = max(mMaxDiscoveryByUid); 319 log.maxConcurrentPublishInSystem = mMaxPublishInSystem; 320 log.maxConcurrentSubscribeInSystem = mMaxSubscribeInSystem; 321 log.maxConcurrentDiscoverySessionsInSystem = mMaxDiscoveryInSystem; 322 log.histogramPublishStatus = histogramToProtoArray(mPublishStatusData); 323 log.histogramSubscribeStatus = histogramToProtoArray(mSubscribeStatusData); 324 log.numAppsWithDiscoverySessionFailureOutOfResources = 325 mAppsWithDiscoverySessionResourceFailure.size(); 326 log.histogramPublishSessionDurationMs = histogramToProtoArray(mHistogramPublishDuration, 327 DURATION_LOG_HISTOGRAM); 328 log.histogramSubscribeSessionDurationMs = histogramToProtoArray( 329 mHistogramSubscribeDuration, DURATION_LOG_HISTOGRAM); 330 } 331 return log; 332 } 333 334 /** 335 * clear Wi-Fi Aware metrics 336 */ 337 public void clear() { 338 long now = mClock.getElapsedSinceBootMillis(); 339 synchronized (mLock) { 340 // don't clear mLastEnableUsage since could be valid for next measurement period 341 mHistogramAwareAvailableDurationMs.clear(); 342 mAvailableTimeMs = 0; 343 if (mLastEnableUsageInThisSampleWindowMs != 0) { 344 mLastEnableUsageInThisSampleWindowMs = now; 345 } 346 347 // don't clear mLastEnableAware since could be valid for next measurement period 348 mHistogramAwareEnabledDurationMs.clear(); 349 mEnabledTimeMs = 0; 350 if (mLastEnableAwareInThisSampleWindowMs != 0) { 351 mLastEnableAwareInThisSampleWindowMs = now; 352 } 353 354 mAttachDataByUid.clear(); 355 mAttachStatusData.clear(); 356 mHistogramAttachDuration.clear(); 357 358 mMaxPublishByUid.clear(); 359 mMaxSubscribeByUid.clear(); 360 mMaxDiscoveryByUid.clear(); 361 mMaxPublishInSystem = 0; 362 mMaxSubscribeInSystem = 0; 363 mMaxDiscoveryInSystem = 0; 364 mPublishStatusData.clear(); 365 mSubscribeStatusData.clear(); 366 mHistogramPublishDuration.clear(); 367 mHistogramSubscribeDuration.clear(); 368 mAppsWithDiscoverySessionResourceFailure.clear(); 369 } 370 } 371 372 /** 373 * Dump all WifiAwareMetrics to console (pw) - this method is never called to dump the 374 * serialized metrics (handled by parent WifiMetrics). 375 * 376 * @param fd unused 377 * @param pw PrintWriter for writing dump to 378 * @param args unused 379 */ 380 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 381 synchronized (mLock) { 382 pw.println("mLastEnableUsage:" + mLastEnableUsageMs); 383 pw.println( 384 "mLastEnableUsageInThisSampleWindow:" + mLastEnableUsageInThisSampleWindowMs); 385 pw.println("mAvailableTime:" + mAvailableTimeMs); 386 pw.println("mHistogramAwareAvailableDurationMs:"); 387 for (int i = 0; i < mHistogramAwareAvailableDurationMs.size(); ++i) { 388 pw.println(" " + mHistogramAwareAvailableDurationMs.keyAt(i) + ": " 389 + mHistogramAwareAvailableDurationMs.valueAt(i)); 390 } 391 pw.println("mAttachDataByUid:"); 392 for (Map.Entry<Integer, AttachData> ade: mAttachDataByUid.entrySet()) { 393 pw.println(" " + "uid=" + ade.getKey() + ": identity=" 394 + ade.getValue().mUsesIdentityCallback + ", maxConcurrent=" 395 + ade.getValue().mMaxConcurrentAttaches); 396 } 397 pw.println("mAttachStatusData:"); 398 for (int i = 0; i < mAttachStatusData.size(); ++i) { 399 pw.println(" " + mAttachStatusData.keyAt(i) + ": " 400 + mAttachStatusData.valueAt(i)); 401 } 402 pw.println("mHistogramAttachDuration:"); 403 for (int i = 0; i < mHistogramAttachDuration.size(); ++i) { 404 pw.println(" " + mHistogramAttachDuration.keyAt(i) + ": " 405 + mHistogramAttachDuration.valueAt(i)); 406 } 407 } 408 } 409 410 // histogram utilities 411 412 /** 413 * Specifies a ~log histogram consisting of two levels of buckets - a set of N big buckets: 414 * 415 * Buckets starts at: B + P * M^i, where i=0, ... , N-1 (N big buckets) 416 * Each big bucket is divided into S sub-buckets 417 * 418 * Each (big) bucket is M times bigger than the previous one. 419 * 420 * The buckets are then: 421 * #0: B + P * M^0 with S buckets each of width (P*M^1-P*M^0)/S 422 * #1: B + P * M^1 with S buckets each of width (P*M^2-P*M^1)/S 423 * ... 424 * #N-1: B + P * M^(N-1) with S buckets each of width (P*M^N-P*M^(N-1))/S 425 */ 426 @VisibleForTesting 427 public static class HistParms { 428 public HistParms(int b, int p, int m, int s, int n) { 429 this.b = b; 430 this.p = p; 431 this.m = m; 432 this.s = s; 433 this.n = n; 434 435 // derived values 436 mLog = Math.log(m); 437 bb = new double[n]; 438 sbw = new double[n]; 439 bb[0] = b + p; 440 sbw[0] = p * (m - 1.0) / (double) s; 441 for (int i = 1; i < n; ++i) { 442 bb[i] = m * (bb[i - 1] - b) + b; 443 sbw[i] = m * sbw[i - 1]; 444 } 445 } 446 447 // spec 448 public int b; 449 public int p; 450 public int m; 451 public int s; 452 public int n; 453 454 // derived 455 public double mLog; 456 public double[] bb; // bucket base 457 public double[] sbw; // sub-bucket width 458 } 459 460 /** 461 * Adds the input value to the histogram based on the histogram parameters. 462 */ 463 @VisibleForTesting 464 public static int addLogValueToHistogram(long x, SparseIntArray histogram, HistParms hp) { 465 double logArg = (double) (x - hp.b) / (double) hp.p; 466 int bigBucketIndex = -1; 467 if (logArg > 0) { 468 bigBucketIndex = (int) (Math.log(logArg) / hp.mLog); 469 } 470 int subBucketIndex; 471 if (bigBucketIndex < 0) { 472 bigBucketIndex = 0; 473 subBucketIndex = 0; 474 } else if (bigBucketIndex >= hp.n) { 475 bigBucketIndex = hp.n - 1; 476 subBucketIndex = hp.s - 1; 477 } else { 478 subBucketIndex = (int) ((x - hp.bb[bigBucketIndex]) / hp.sbw[bigBucketIndex]); 479 if (subBucketIndex >= hp.s) { // probably a rounding error so move to next big bucket 480 bigBucketIndex++; 481 if (bigBucketIndex >= hp.n) { 482 bigBucketIndex = hp.n - 1; 483 subBucketIndex = hp.s - 1; 484 } else { 485 subBucketIndex = (int) ((x - hp.bb[bigBucketIndex]) / hp.sbw[bigBucketIndex]); 486 } 487 } 488 } 489 int key = bigBucketIndex * hp.s + subBucketIndex; 490 491 // note that get() returns 0 if index not there already 492 int newValue = histogram.get(key) + 1; 493 histogram.put(key, newValue); 494 495 return newValue; 496 } 497 498 /** 499 * Converts the histogram (with the specified histogram parameters) to an array of proto 500 * histogram buckets. 501 */ 502 @VisibleForTesting 503 public static WifiMetricsProto.WifiAwareLog.HistogramBucket[] histogramToProtoArray( 504 SparseIntArray histogram, HistParms hp) { 505 WifiMetricsProto.WifiAwareLog.HistogramBucket[] protoArray = 506 new WifiMetricsProto.WifiAwareLog.HistogramBucket[histogram.size()]; 507 for (int i = 0; i < histogram.size(); ++i) { 508 int key = histogram.keyAt(i); 509 510 protoArray[i] = new WifiMetricsProto.WifiAwareLog.HistogramBucket(); 511 protoArray[i].start = (long) (hp.bb[key / hp.s] + hp.sbw[key / hp.s] * (key % hp.s)); 512 protoArray[i].end = (long) (protoArray[i].start + hp.sbw[key / hp.s]); 513 protoArray[i].count = histogram.valueAt(i); 514 } 515 516 return protoArray; 517 } 518 519 /** 520 * Adds the NanStatusType to the histogram (translating to the proto enumeration of the status). 521 */ 522 public static void addNanHalStatusToHistogram(int halStatus, SparseIntArray histogram) { 523 int protoStatus = convertNanStatusTypeToProtoEnum(halStatus); 524 int newValue = histogram.get(protoStatus) + 1; 525 histogram.put(protoStatus, newValue); 526 } 527 528 /** 529 * Converts a histogram of proto NanStatusTypeEnum to a raw proto histogram. 530 */ 531 @VisibleForTesting 532 public static WifiMetricsProto.WifiAwareLog.NanStatusHistogramBucket[] histogramToProtoArray( 533 SparseIntArray histogram) { 534 WifiMetricsProto.WifiAwareLog.NanStatusHistogramBucket[] protoArray = 535 new WifiMetricsProto.WifiAwareLog.NanStatusHistogramBucket[histogram.size()]; 536 537 for (int i = 0; i < histogram.size(); ++i) { 538 protoArray[i] = new WifiMetricsProto.WifiAwareLog.NanStatusHistogramBucket(); 539 protoArray[i].nanStatusType = histogram.keyAt(i); 540 protoArray[i].count = histogram.valueAt(i); 541 } 542 543 return protoArray; 544 } 545 546 /** 547 * Convert a HAL NanStatusType enum to a Metrics proto enum NanStatusTypeEnum. 548 */ 549 public static int convertNanStatusTypeToProtoEnum(int nanStatusType) { 550 switch (nanStatusType) { 551 case NanStatusType.SUCCESS: 552 return WifiMetricsProto.WifiAwareLog.SUCCESS; 553 case NanStatusType.INTERNAL_FAILURE: 554 return WifiMetricsProto.WifiAwareLog.INTERNAL_FAILURE; 555 case NanStatusType.PROTOCOL_FAILURE: 556 return WifiMetricsProto.WifiAwareLog.PROTOCOL_FAILURE; 557 case NanStatusType.INVALID_SESSION_ID: 558 return WifiMetricsProto.WifiAwareLog.INVALID_SESSION_ID; 559 case NanStatusType.NO_RESOURCES_AVAILABLE: 560 return WifiMetricsProto.WifiAwareLog.NO_RESOURCES_AVAILABLE; 561 case NanStatusType.INVALID_ARGS: 562 return WifiMetricsProto.WifiAwareLog.INVALID_ARGS; 563 case NanStatusType.INVALID_PEER_ID: 564 return WifiMetricsProto.WifiAwareLog.INVALID_PEER_ID; 565 case NanStatusType.INVALID_NDP_ID: 566 return WifiMetricsProto.WifiAwareLog.INVALID_NDP_ID; 567 case NanStatusType.NAN_NOT_ALLOWED: 568 return WifiMetricsProto.WifiAwareLog.NAN_NOT_ALLOWED; 569 case NanStatusType.NO_OTA_ACK: 570 return WifiMetricsProto.WifiAwareLog.NO_OTA_ACK; 571 case NanStatusType.ALREADY_ENABLED: 572 return WifiMetricsProto.WifiAwareLog.ALREADY_ENABLED; 573 case NanStatusType.FOLLOWUP_TX_QUEUE_FULL: 574 return WifiMetricsProto.WifiAwareLog.FOLLOWUP_TX_QUEUE_FULL; 575 case NanStatusType.UNSUPPORTED_CONCURRENCY_NAN_DISABLED: 576 return WifiMetricsProto.WifiAwareLog.UNSUPPORTED_CONCURRENCY_NAN_DISABLED; 577 default: 578 Log.e(TAG, "Unrecognized NanStatusType: " + nanStatusType); 579 return WifiMetricsProto.WifiAwareLog.UNKNOWN_HAL_STATUS; 580 } 581 } 582 583 private int max(SparseIntArray array) { 584 int max = 0; 585 for (int i = 0; i < array.size(); ++i) { 586 max = Math.max(max, array.valueAt(i)); 587 } 588 return max; 589 } 590} 591