1 /* 2 * Copyright 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wifi; 18 19 import android.net.wifi.WifiUsabilityStatsEntry.LinkState; 20 import android.util.SparseArray; 21 22 import java.util.Arrays; 23 24 /** 25 * A class representing link layer statistics collected over a Wifi Interface. 26 */ 27 28 /** 29 * {@hide} 30 */ 31 public class WifiLinkLayerStats { 32 public static final String V1_0 = "V1_0"; 33 public static final String V1_3 = "V1_3"; 34 public static final String V1_5 = "V1_5"; 35 36 /** The version of hal StaLinkLayerStats **/ 37 public String version; 38 39 /** 40 * Link specific statistics. 41 */ 42 public static class LinkSpecificStats { 43 44 /** Link identifier of the link */ 45 public int link_id; 46 47 /** Link state as {@link LinkState} */ 48 public @LinkState int state; 49 50 /** Identifier of the radio on which link is currently operating */ 51 public int radio_id; 52 53 /** Frequency of the link in MHz */ 54 public int frequencyMhz; 55 56 /** Number of beacons received from our own AP */ 57 public int beacon_rx; 58 59 /** RSSI of management frames */ 60 public int rssi_mgmt; 61 62 /* Packet counters and contention time stats */ 63 64 /** WME Best Effort Access Category received mpdu */ 65 public long rxmpdu_be; 66 /** WME Best Effort Access Category transmitted mpdu */ 67 public long txmpdu_be; 68 /** WME Best Effort Access Category lost mpdu */ 69 public long lostmpdu_be; 70 /** WME Best Effort Access Category number of transmission retries */ 71 public long retries_be; 72 /** WME Best Effort Access Category data packet min contention time in microseconds */ 73 public long contentionTimeMinBeInUsec; 74 /** WME Best Effort Access Category data packet max contention time in microseconds */ 75 public long contentionTimeMaxBeInUsec; 76 /** WME Best Effort Access Category data packet average contention time in microseconds */ 77 public long contentionTimeAvgBeInUsec; 78 /** 79 * WME Best Effort Access Category number of data packets used for deriving the min, the 80 * max, 81 * and the average contention time 82 */ 83 public long contentionNumSamplesBe; 84 85 /** WME Background Access Category received mpdu */ 86 public long rxmpdu_bk; 87 /** WME Background Access Category transmitted mpdu */ 88 public long txmpdu_bk; 89 /** WME Background Access Category lost mpdu */ 90 public long lostmpdu_bk; 91 /** WME Background Access Category number of transmission retries */ 92 public long retries_bk; 93 /** WME Background Access Category data packet min contention time in microseconds */ 94 public long contentionTimeMinBkInUsec; 95 /** WME Background Access Category data packet max contention time in microseconds */ 96 public long contentionTimeMaxBkInUsec; 97 /** WME Background Access Category data packet average contention time in microseconds */ 98 public long contentionTimeAvgBkInUsec; 99 /** 100 * WME Background Access Category number of data packets used for deriving the min, the max, 101 * and the average contention time 102 */ 103 public long contentionNumSamplesBk; 104 105 /** WME Video Access Category received mpdu */ 106 public long rxmpdu_vi; 107 /** WME Video Access Category transmitted mpdu */ 108 public long txmpdu_vi; 109 /** WME Video Access Category lost mpdu */ 110 public long lostmpdu_vi; 111 /** WME Video Access Category number of transmission retries */ 112 public long retries_vi; 113 /** WME Video Access Category data packet min contention time in microseconds */ 114 public long contentionTimeMinViInUsec; 115 /** WME Video Access Category data packet max contention time in microseconds */ 116 public long contentionTimeMaxViInUsec; 117 /** WME Video Access Category data packet average contention time in microseconds */ 118 public long contentionTimeAvgViInUsec; 119 /** 120 * WME Video Access Category number of data packets used for deriving the min, the max, and 121 * the average contention time 122 */ 123 public long contentionNumSamplesVi; 124 125 /** WME Voice Access Category received mpdu */ 126 public long rxmpdu_vo; 127 /** WME Voice Access Category transmitted mpdu */ 128 public long txmpdu_vo; 129 /** WME Voice Access Category lost mpdu */ 130 public long lostmpdu_vo; 131 /** WME Voice Access Category number of transmission retries */ 132 public long retries_vo; 133 /** WME Voice Access Category data packet min contention time in microseconds */ 134 public long contentionTimeMinVoInUsec; 135 /** WME Voice Access Category data packet max contention time in microseconds */ 136 public long contentionTimeMaxVoInUsec; 137 /** WME Voice Access Category data packet average contention time in microseconds */ 138 public long contentionTimeAvgVoInUsec; 139 /** 140 * WME Voice Access Category number of data packets used for deriving the min, the max, and 141 * the average contention time 142 */ 143 public long contentionNumSamplesVo; 144 145 /** 146 * Duty cycle of the link. 147 * if this link is being served using time slicing on a radio with one or more ifaces 148 * (i.e MCC), then the duty cycle assigned to this iface in %. 149 * If not using time slicing (i.e SCC or DBS), set to 100. 150 */ 151 public short timeSliceDutyCycleInPercent = -1; 152 153 /** 154 * Peer statistics. 155 */ 156 public PeerInfo[] peerInfo; 157 158 } 159 160 public LinkSpecificStats[] links; 161 162 /** 163 * The stats below which is already captured in WifiLinkLayerStats#LinkSpecificStats will be 164 * having an aggregated value. The aggregation logic is defined at 165 * wifiNative#setAggregatedLinkLayerStats(). 166 */ 167 168 /** Number of beacons received from our own AP */ 169 public int beacon_rx; 170 171 /** RSSI of management frames */ 172 public int rssi_mgmt; 173 174 /* Packet counters and contention time stats */ 175 176 /** WME Best Effort Access Category received mpdu */ 177 public long rxmpdu_be; 178 /** WME Best Effort Access Category transmitted mpdu */ 179 public long txmpdu_be; 180 /** WME Best Effort Access Category lost mpdu */ 181 public long lostmpdu_be; 182 /** WME Best Effort Access Category number of transmission retries */ 183 public long retries_be; 184 /** WME Best Effort Access Category data packet min contention time in microseconds */ 185 public long contentionTimeMinBeInUsec; 186 /** WME Best Effort Access Category data packet max contention time in microseconds */ 187 public long contentionTimeMaxBeInUsec; 188 /** WME Best Effort Access Category data packet average contention time in microseconds */ 189 public long contentionTimeAvgBeInUsec; 190 /** 191 * WME Best Effort Access Category number of data packets used for deriving the min, the max, 192 * and the average contention time 193 */ 194 public long contentionNumSamplesBe; 195 196 /** WME Background Access Category received mpdu */ 197 public long rxmpdu_bk; 198 /** WME Background Access Category transmitted mpdu */ 199 public long txmpdu_bk; 200 /** WME Background Access Category lost mpdu */ 201 public long lostmpdu_bk; 202 /** WME Background Access Category number of transmission retries */ 203 public long retries_bk; 204 /** WME Background Access Category data packet min contention time in microseconds */ 205 public long contentionTimeMinBkInUsec; 206 /** WME Background Access Category data packet max contention time in microseconds */ 207 public long contentionTimeMaxBkInUsec; 208 /** WME Background Access Category data packet average contention time in microseconds */ 209 public long contentionTimeAvgBkInUsec; 210 /** 211 * WME Background Access Category number of data packets used for deriving the min, the max, 212 * and the average contention time 213 */ 214 public long contentionNumSamplesBk; 215 216 /** WME Video Access Category received mpdu */ 217 public long rxmpdu_vi; 218 /** WME Video Access Category transmitted mpdu */ 219 public long txmpdu_vi; 220 /** WME Video Access Category lost mpdu */ 221 public long lostmpdu_vi; 222 /** WME Video Access Category number of transmission retries */ 223 public long retries_vi; 224 /** WME Video Access Category data packet min contention time in microseconds */ 225 public long contentionTimeMinViInUsec; 226 /** WME Video Access Category data packet max contention time in microseconds */ 227 public long contentionTimeMaxViInUsec; 228 /** WME Video Access Category data packet average contention time in microseconds */ 229 public long contentionTimeAvgViInUsec; 230 /** 231 * WME Video Access Category number of data packets used for deriving the min, the max, and 232 * the average contention time 233 */ 234 public long contentionNumSamplesVi; 235 236 /** WME Voice Access Category received mpdu */ 237 public long rxmpdu_vo; 238 /** WME Voice Access Category transmitted mpdu */ 239 public long txmpdu_vo; 240 /** WME Voice Access Category lost mpdu */ 241 public long lostmpdu_vo; 242 /** WME Voice Access Category number of transmission retries */ 243 public long retries_vo; 244 /** WME Voice Access Category data packet min contention time in microseconds */ 245 public long contentionTimeMinVoInUsec; 246 /** WME Voice Access Category data packet max contention time in microseconds */ 247 public long contentionTimeMaxVoInUsec; 248 /** WME Voice Access Category data packet average contention time in microseconds */ 249 public long contentionTimeAvgVoInUsec; 250 /** 251 * WME Voice Access Category number of data packets used for deriving the min, the max, and 252 * the average contention time 253 */ 254 public long contentionNumSamplesVo; 255 256 /** 257 * Cumulative milliseconds when radio is awake 258 */ 259 public int on_time; 260 /** 261 * Cumulative milliseconds of active transmission 262 */ 263 public int tx_time; 264 /** 265 * Cumulative milliseconds per radio transmit power level of active transmission 266 */ 267 public int[] tx_time_per_level; 268 /** 269 * Cumulative milliseconds of active receive 270 */ 271 public int rx_time; 272 /** 273 * Cumulative milliseconds when radio is awake due to scan 274 */ 275 public int on_time_scan; 276 /** 277 * Cumulative milliseconds when radio is awake due to nan scan 278 */ 279 public int on_time_nan_scan; 280 /** 281 * Cumulative milliseconds when radio is awake due to background scan 282 */ 283 public int on_time_background_scan; 284 /** 285 * Cumulative milliseconds when radio is awake due to roam scan 286 */ 287 public int on_time_roam_scan; 288 /** 289 * Cumulative milliseconds when radio is awake due to pno scan 290 */ 291 public int on_time_pno_scan; 292 /** 293 * Cumulative milliseconds when radio is awake due to hotspot 2.0 scan amd GAS exchange 294 */ 295 public int on_time_hs20_scan; 296 297 /** 298 * channel stats 299 */ 300 public static class ChannelStats { 301 /** 302 * Channel frequency in MHz; 303 */ 304 public int frequency; 305 /** 306 * Cumulative milliseconds radio is awake on this channel 307 */ 308 public int radioOnTimeMs; 309 /** 310 * Cumulative milliseconds CCA is held busy on this channel 311 */ 312 public int ccaBusyTimeMs; 313 } 314 315 /** 316 * Channel stats list 317 */ 318 public final SparseArray<ChannelStats> channelStatsMap = new SparseArray<>(); 319 320 /** 321 * numRadios - Number of radios used for coalescing above radio stats. 322 */ 323 public int numRadios; 324 325 /** 326 * TimeStamp - absolute milliseconds from boot when these stats were sampled. 327 */ 328 public long timeStampInMs; 329 330 /** 331 * Duty cycle of the iface. 332 * if this iface is being served using time slicing on a radio with one or more ifaces 333 * (i.e MCC), then the duty cycle assigned to this iface in %. 334 * If not using time slicing (i.e SCC or DBS), set to 100. 335 */ 336 public short timeSliceDutyCycleInPercent = -1; 337 338 /** 339 * Per rate information and statistics. 340 */ 341 public static class RateStat { 342 /** 343 * Preamble information. 0: OFDM, 1:CCK, 2:HT 3:VHT 4:HE 5..7 reserved. 344 */ 345 public int preamble; 346 /** 347 * Number of spatial streams. 0:1x1, 1:2x2, 3:3x3, 4:4x4. 348 */ 349 public int nss; 350 /** 351 * Bandwidth information. 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz. 352 */ 353 public int bw; 354 /** 355 * MCS index. OFDM/CCK rate code would be as per IEEE std in the units of 0.5Mbps. 356 * HT/VHT/HE: it would be MCS index. 357 */ 358 public int rateMcsIdx; 359 /** 360 * Bitrate in units of 100 Kbps. 361 */ 362 public int bitRateInKbps; 363 /** 364 * Number of successfully transmitted data packets (ACK received). 365 */ 366 public int txMpdu; 367 /** 368 * Number of received data packets. 369 */ 370 public int rxMpdu; 371 /** 372 * Number of data packet losses (no ACK). 373 */ 374 public int mpduLost; 375 /** 376 * Number of data packet retries. 377 */ 378 public int retries; 379 } 380 381 /** 382 * Per peer statistics. 383 */ 384 public static class PeerInfo { 385 /** 386 * Station count. 387 */ 388 public short staCount; 389 /** 390 * Channel utilization. 391 */ 392 public short chanUtil; 393 /** 394 * Per rate statistics. 395 */ 396 public RateStat[] rateStats; 397 } 398 399 /** 400 * Peer statistics. 401 */ 402 public PeerInfo[] peerInfo; 403 404 /** 405 * Radio stats 406 */ 407 public static class RadioStat { 408 /** 409 * Radio identifier 410 */ 411 public int radio_id; 412 /** 413 * Cumulative milliseconds when radio is awake from the last radio chip reset 414 */ 415 public int on_time; 416 /** 417 * Cumulative milliseconds of active transmission from the last radio chip reset 418 */ 419 public int tx_time; 420 /** 421 * Cumulative milliseconds of active receive from the last radio chip reset 422 */ 423 public int rx_time; 424 /** 425 * Cumulative milliseconds when radio is awake due to scan from the last radio chip reset 426 */ 427 public int on_time_scan; 428 /** 429 * Cumulative milliseconds when radio is awake due to nan scan from the last radio chip 430 * reset 431 */ 432 public int on_time_nan_scan; 433 /** 434 * Cumulative milliseconds when radio is awake due to background scan from the last radio 435 * chip reset 436 */ 437 public int on_time_background_scan; 438 /** 439 * Cumulative milliseconds when radio is awake due to roam scan from the last radio chip 440 * reset 441 */ 442 public int on_time_roam_scan; 443 /** 444 * Cumulative milliseconds when radio is awake due to pno scan from the last radio chip 445 * reset 446 */ 447 public int on_time_pno_scan; 448 /** 449 * Cumulative milliseconds when radio is awake due to hotspot 2.0 scan amd GAS exchange 450 * from the last radio chip reset 451 */ 452 public int on_time_hs20_scan; 453 /** 454 * Channel stats list 455 */ 456 public final SparseArray<ChannelStats> channelStatsMap = new SparseArray<>(); 457 } 458 459 /** 460 * Radio stats of all the radios. 461 */ 462 public RadioStat[] radioStats; 463 464 @Override toString()465 public String toString() { 466 StringBuilder sbuf = new StringBuilder(); 467 sbuf.append(" WifiLinkLayerStats: ").append('\n'); 468 469 sbuf.append(" version of StaLinkLayerStats: ").append(version).append('\n'); 470 sbuf.append(" my bss beacon rx: ").append(Integer.toString(this.beacon_rx)).append('\n'); 471 sbuf.append(" RSSI mgmt: ").append(Integer.toString(this.rssi_mgmt)).append('\n'); 472 sbuf.append(" BE : ").append(" rx=").append(Long.toString(this.rxmpdu_be)) 473 .append(" tx=").append(Long.toString(this.txmpdu_be)) 474 .append(" lost=").append(Long.toString(this.lostmpdu_be)) 475 .append(" retries=").append(Long.toString(this.retries_be)).append('\n') 476 .append(" contention_time_min") 477 .append(Long.toString(this.contentionTimeMinBeInUsec)) 478 .append(" contention_time_max") 479 .append(Long.toString(this.contentionTimeMaxBeInUsec)).append('\n') 480 .append(" contention_time_avg") 481 .append(Long.toString(this.contentionTimeAvgBeInUsec)) 482 .append(" contention_num_samples") 483 .append(Long.toString(this.contentionNumSamplesBe)).append('\n'); 484 sbuf.append(" BK : ").append(" rx=").append(Long.toString(this.rxmpdu_bk)) 485 .append(" tx=").append(Long.toString(this.txmpdu_bk)) 486 .append(" lost=").append(Long.toString(this.lostmpdu_bk)) 487 .append(" retries=").append(Long.toString(this.retries_bk)).append('\n') 488 .append(" contention_time_min") 489 .append(Long.toString(this.contentionTimeMinBkInUsec)) 490 .append(" contention_time_max") 491 .append(Long.toString(this.contentionTimeMaxBkInUsec)).append('\n') 492 .append(" contention_time_avg") 493 .append(Long.toString(this.contentionTimeAvgBkInUsec)) 494 .append(" contention_num_samples") 495 .append(Long.toString(this.contentionNumSamplesBk)).append('\n'); 496 sbuf.append(" VI : ").append(" rx=").append(Long.toString(this.rxmpdu_vi)) 497 .append(" tx=").append(Long.toString(this.txmpdu_vi)) 498 .append(" lost=").append(Long.toString(this.lostmpdu_vi)) 499 .append(" retries=").append(Long.toString(this.retries_vi)).append('\n') 500 .append(" contention_time_min") 501 .append(Long.toString(this.contentionTimeMinViInUsec)) 502 .append(" contention_time_max") 503 .append(Long.toString(this.contentionTimeMaxViInUsec)).append('\n') 504 .append(" contention_time_avg") 505 .append(Long.toString(this.contentionTimeAvgViInUsec)) 506 .append(" contention_num_samples") 507 .append(Long.toString(this.contentionNumSamplesVi)).append('\n'); 508 sbuf.append(" VO : ").append(" rx=").append(Long.toString(this.rxmpdu_vo)) 509 .append(" tx=").append(Long.toString(this.txmpdu_vo)) 510 .append(" lost=").append(Long.toString(this.lostmpdu_vo)) 511 .append(" retries=").append(Long.toString(this.retries_vo)).append('\n') 512 .append(" contention_time_min") 513 .append(Long.toString(this.contentionTimeMinVoInUsec)) 514 .append(" contention_time_max") 515 .append(Long.toString(this.contentionTimeMaxVoInUsec)).append('\n') 516 .append(" contention_time_avg") 517 .append(Long.toString(this.contentionTimeAvgVoInUsec)) 518 .append(" contention_num_samples") 519 .append(Long.toString(this.contentionNumSamplesVo)).append('\n'); 520 if (this.links != null) { 521 sbuf.append("Per link stats: Number of links = ").append(this.links.length).append( 522 "\n"); 523 for (WifiLinkLayerStats.LinkSpecificStats link : this.links) { 524 sbuf.append(" link id: ").append(link.link_id).append("\n"); 525 sbuf.append(" bss beacon rx: ").append(Integer.toString(link.beacon_rx)).append( 526 '\n'); 527 sbuf.append(" RSSI mgmt: ").append(Integer.toString(link.rssi_mgmt)).append('\n'); 528 sbuf.append(" BE : ").append(" rx=").append(Long.toString(link.rxmpdu_be)) 529 .append(" tx=").append(Long.toString(link.txmpdu_be)) 530 .append(" lost=").append(Long.toString(link.lostmpdu_be)) 531 .append(" retries=").append(Long.toString(link.retries_be)).append('\n') 532 .append(" contention_time_min") 533 .append(Long.toString(link.contentionTimeMinBeInUsec)) 534 .append(" contention_time_max") 535 .append(Long.toString(link.contentionTimeMaxBeInUsec)).append('\n') 536 .append(" contention_time_avg") 537 .append(Long.toString(link.contentionTimeAvgBeInUsec)) 538 .append(" contention_num_samples") 539 .append(Long.toString(link.contentionNumSamplesBe)).append('\n'); 540 sbuf.append(" BK : ").append(" rx=").append(Long.toString(link.rxmpdu_bk)) 541 .append(" tx=").append(Long.toString(link.txmpdu_bk)) 542 .append(" lost=").append(Long.toString(link.lostmpdu_bk)) 543 .append(" retries=").append(Long.toString(link.retries_bk)).append('\n') 544 .append(" contention_time_min") 545 .append(Long.toString(link.contentionTimeMinBkInUsec)) 546 .append(" contention_time_max") 547 .append(Long.toString(link.contentionTimeMaxBkInUsec)).append('\n') 548 .append(" contention_time_avg") 549 .append(Long.toString(link.contentionTimeAvgBkInUsec)) 550 .append(" contention_num_samples") 551 .append(Long.toString(link.contentionNumSamplesBk)).append('\n'); 552 sbuf.append(" VI : ").append(" rx=").append(Long.toString(link.rxmpdu_vi)) 553 .append(" tx=").append(Long.toString(link.txmpdu_vi)) 554 .append(" lost=").append(Long.toString(link.lostmpdu_vi)) 555 .append(" retries=").append(Long.toString(link.retries_vi)).append('\n') 556 .append(" contention_time_min") 557 .append(Long.toString(link.contentionTimeMinViInUsec)) 558 .append(" contention_time_max") 559 .append(Long.toString(link.contentionTimeMaxViInUsec)).append('\n') 560 .append(" contention_time_avg") 561 .append(Long.toString(link.contentionTimeAvgViInUsec)) 562 .append(" contention_num_samples") 563 .append(Long.toString(link.contentionNumSamplesVi)).append('\n'); 564 sbuf.append(" VO : ").append(" rx=").append(Long.toString(link.rxmpdu_vo)) 565 .append(" tx=").append(Long.toString(link.txmpdu_vo)) 566 .append(" lost=").append(Long.toString(link.lostmpdu_vo)) 567 .append(" retries=").append(Long.toString(link.retries_vo)).append('\n') 568 .append(" contention_time_min") 569 .append(Long.toString(link.contentionTimeMinVoInUsec)) 570 .append(" contention_time_max") 571 .append(Long.toString(link.contentionTimeMaxVoInUsec)).append('\n') 572 .append(" contention_time_avg") 573 .append(Long.toString(link.contentionTimeAvgVoInUsec)) 574 .append(" contention_num_samples") 575 .append(Long.toString(link.contentionNumSamplesVo)).append('\n'); 576 sbuf.append(" Duty cycle of the link=").append( 577 Short.toString(timeSliceDutyCycleInPercent)).append("\n"); 578 if (link.peerInfo != null) { 579 sbuf.append(" Number of peers=").append(link.peerInfo.length).append('\n'); 580 for (PeerInfo peer : link.peerInfo) { 581 sbuf.append(" staCount=").append(peer.staCount) 582 .append(" chanUtil=").append(peer.chanUtil).append('\n'); 583 if (peer.rateStats != null) { 584 for (RateStat rateStat : peer.rateStats) { 585 sbuf.append(" preamble=").append(rateStat.preamble) 586 .append(" nss=").append(rateStat.nss) 587 .append(" bw=").append(rateStat.bw) 588 .append(" rateMcsIdx=").append(rateStat.rateMcsIdx) 589 .append(" bitRateInKbps=").append( 590 rateStat.bitRateInKbps).append( 591 '\n') 592 .append(" txMpdu=").append(rateStat.txMpdu) 593 .append(" rxMpdu=").append(rateStat.rxMpdu) 594 .append(" mpduLost=").append(rateStat.mpduLost) 595 .append(" retries=").append(rateStat.retries).append('\n'); 596 } 597 } 598 } 599 } 600 } 601 } 602 603 sbuf.append(" numRadios=" + numRadios) 604 .append(" on_time= ").append(Integer.toString(this.on_time)) 605 .append(" tx_time=").append(Integer.toString(this.tx_time)) 606 .append(" rx_time=").append(Integer.toString(this.rx_time)) 607 .append(" scan_time=").append(Integer.toString(this.on_time_scan)).append('\n') 608 .append(" nan_scan_time=") 609 .append(Integer.toString(this.on_time_nan_scan)).append('\n') 610 .append(" g_scan_time=") 611 .append(Integer.toString(this.on_time_background_scan)).append('\n') 612 .append(" roam_scan_time=") 613 .append(Integer.toString(this.on_time_roam_scan)).append('\n') 614 .append(" pno_scan_time=") 615 .append(Integer.toString(this.on_time_pno_scan)).append('\n') 616 .append(" hs2.0_scan_time=") 617 .append(Integer.toString(this.on_time_hs20_scan)).append('\n') 618 .append(" tx_time_per_level=" + Arrays.toString(tx_time_per_level)).append('\n'); 619 int numChanStats = this.channelStatsMap.size(); 620 sbuf.append(" Number of channel stats=").append(numChanStats).append('\n'); 621 for (int i = 0; i < numChanStats; ++i) { 622 ChannelStats channelStatsEntry = this.channelStatsMap.valueAt(i); 623 sbuf.append(" Frequency=").append(channelStatsEntry.frequency) 624 .append(" radioOnTimeMs=").append(channelStatsEntry.radioOnTimeMs) 625 .append(" ccaBusyTimeMs=").append(channelStatsEntry.ccaBusyTimeMs).append('\n'); 626 } 627 int numRadios = this.radioStats == null ? 0 : this.radioStats.length; 628 sbuf.append(" Individual radio stats: numRadios=").append(numRadios).append('\n'); 629 for (int i = 0; i < numRadios; i++) { 630 RadioStat radio = this.radioStats[i]; 631 sbuf.append(" radio_id=" + radio.radio_id) 632 .append(" on_time=").append(Integer.toString(radio.on_time)) 633 .append(" tx_time=").append(Integer.toString(radio.tx_time)) 634 .append(" rx_time=").append(Integer.toString(radio.rx_time)) 635 .append(" scan_time=").append(Integer.toString(radio.on_time_scan)).append('\n') 636 .append(" nan_scan_time=") 637 .append(Integer.toString(radio.on_time_nan_scan)).append('\n') 638 .append(" g_scan_time=") 639 .append(Integer.toString(radio.on_time_background_scan)).append('\n') 640 .append(" roam_scan_time=") 641 .append(Integer.toString(radio.on_time_roam_scan)).append('\n') 642 .append(" pno_scan_time=") 643 .append(Integer.toString(radio.on_time_pno_scan)).append('\n') 644 .append(" hs2.0_scan_time=") 645 .append(Integer.toString(radio.on_time_hs20_scan)).append('\n'); 646 int numRadioChanStats = radio.channelStatsMap.size(); 647 sbuf.append(" Number of channel stats=").append(numRadioChanStats).append('\n'); 648 for (int j = 0; j < numRadioChanStats; ++j) { 649 ChannelStats channelStatsEntry = radio.channelStatsMap.valueAt(j); 650 sbuf.append(" Frequency=").append(channelStatsEntry.frequency) 651 .append(" radioOnTimeMs=").append(channelStatsEntry.radioOnTimeMs) 652 .append(" ccaBusyTimeMs=").append(channelStatsEntry.ccaBusyTimeMs) 653 .append('\n'); 654 } 655 } 656 sbuf.append(" ts=" + timeStampInMs); 657 int numPeers = this.peerInfo == null ? 0 : this.peerInfo.length; 658 sbuf.append(" Number of peers=").append(numPeers).append('\n'); 659 for (int i = 0; i < numPeers; i++) { 660 PeerInfo peer = this.peerInfo[i]; 661 sbuf.append(" staCount=").append(peer.staCount) 662 .append(" chanUtil=").append(peer.chanUtil).append('\n'); 663 int numRateStats = peer.rateStats == null ? 0 : peer.rateStats.length; 664 for (int j = 0; j < numRateStats; j++) { 665 RateStat rateStat = peer.rateStats[j]; 666 sbuf.append(" preamble=").append(rateStat.preamble) 667 .append(" nss=").append(rateStat.nss) 668 .append(" bw=").append(rateStat.bw) 669 .append(" rateMcsIdx=").append(rateStat.rateMcsIdx) 670 .append(" bitRateInKbps=").append(rateStat.bitRateInKbps).append('\n') 671 .append(" txMpdu=").append(rateStat.txMpdu) 672 .append(" rxMpdu=").append(rateStat.rxMpdu) 673 .append(" mpduLost=").append(rateStat.mpduLost) 674 .append(" retries=").append(rateStat.retries).append('\n'); 675 } 676 } 677 return sbuf.toString(); 678 } 679 680 /** 681 * Returns the link which has the best (=max) RSSI. 682 * 683 * @return link index. 684 */ getBestLinkIndex()685 private int getBestLinkIndex() { 686 int best = 0; 687 for (int i = 1; i < links.length; ++i) { 688 if (links[i].rssi_mgmt > links[best].rssi_mgmt) { 689 best = i; 690 } 691 } 692 return best; 693 } 694 clearAggregatedPacketStats()695 private void clearAggregatedPacketStats() { 696 rxmpdu_be = 0; 697 txmpdu_be = 0; 698 lostmpdu_be = 0; 699 retries_be = 0; 700 701 rxmpdu_bk = 0; 702 txmpdu_bk = 0; 703 lostmpdu_bk = 0; 704 retries_bk = 0; 705 706 rxmpdu_vi = 0; 707 txmpdu_vi = 0; 708 lostmpdu_vi = 0; 709 retries_vi = 0; 710 711 rxmpdu_vo = 0; 712 txmpdu_vo = 0; 713 lostmpdu_vo = 0; 714 retries_vo = 0; 715 } 716 717 /** 718 * Add packet stats for all links. 719 */ aggregatePacketStats()720 private void aggregatePacketStats() { 721 clearAggregatedPacketStats(); 722 for (LinkSpecificStats link : links) { 723 rxmpdu_be += link.rxmpdu_be; 724 txmpdu_be += link.txmpdu_be; 725 lostmpdu_be += link.lostmpdu_be; 726 retries_be += link.retries_be; 727 728 rxmpdu_bk += link.rxmpdu_bk; 729 txmpdu_bk += link.txmpdu_bk; 730 lostmpdu_bk += link.lostmpdu_bk; 731 retries_bk += link.retries_bk; 732 733 rxmpdu_vi += link.rxmpdu_vi; 734 txmpdu_vi += link.txmpdu_vi; 735 lostmpdu_vi += link.lostmpdu_vi; 736 retries_vi += link.retries_vi; 737 738 rxmpdu_vo += link.rxmpdu_vo; 739 txmpdu_vo += link.txmpdu_vo; 740 lostmpdu_vo += link.lostmpdu_vo; 741 retries_vo += link.retries_vo; 742 } 743 } 744 745 /** 746 * Squash all link peer stats to a single list. 747 */ aggregatePeerStats()748 private void aggregatePeerStats() { 749 if (links == null) { 750 return; 751 } 752 int numOfPeers = 0; 753 for (LinkSpecificStats link : links) { 754 if (link.peerInfo != null) { 755 numOfPeers += link.peerInfo.length; 756 } 757 } 758 if (numOfPeers == 0) { 759 return; 760 } 761 peerInfo = new PeerInfo[numOfPeers]; 762 for (LinkSpecificStats link : links) { 763 if (link.peerInfo == null) continue; 764 int i = 0; 765 for (PeerInfo peer : link.peerInfo) { 766 peerInfo[i] = new PeerInfo(); 767 peerInfo[i].staCount = peer.staCount; 768 peerInfo[i].chanUtil = peer.chanUtil; 769 if (peer.rateStats == null) continue; 770 peerInfo[i].rateStats = new RateStat[peer.rateStats.length]; 771 int j = 0; 772 for (RateStat rateStat : peer.rateStats) { 773 peerInfo[i].rateStats[j] = new RateStat(); 774 peerInfo[i].rateStats[j].preamble = rateStat.preamble; 775 peerInfo[i].rateStats[j].nss = rateStat.nss; 776 peerInfo[i].rateStats[j].bw = rateStat.bw; 777 peerInfo[i].rateStats[j].rateMcsIdx = rateStat.rateMcsIdx; 778 peerInfo[i].rateStats[j].bitRateInKbps = rateStat.bitRateInKbps; 779 peerInfo[i].rateStats[j].txMpdu = rateStat.txMpdu; 780 peerInfo[i].rateStats[j].rxMpdu = rateStat.rxMpdu; 781 peerInfo[i].rateStats[j].mpduLost = rateStat.mpduLost; 782 peerInfo[i].rateStats[j].retries = rateStat.retries; 783 j++; 784 } 785 i++; 786 } 787 } 788 } 789 790 /** 791 * Aggregate link layer stats per link. The logic for aggregation is different for each of the 792 * stats. 793 * - Best link is selected based on rssi. 794 * - Use best link for rssi, beacon_rx and dutyCycle and Contention stats. 795 * - Packet related stats are added. 796 * - Squash all peer stat lists to a single list of peers. 797 */ aggregateLinkLayerStats()798 public void aggregateLinkLayerStats() { 799 if (links == null) return; 800 int i = getBestLinkIndex(); 801 rssi_mgmt = links[i].rssi_mgmt; 802 beacon_rx = links[i].beacon_rx; 803 timeSliceDutyCycleInPercent = links[i].timeSliceDutyCycleInPercent; 804 contentionTimeMinBeInUsec = links[i].contentionTimeMinBeInUsec; 805 contentionTimeMaxBeInUsec = links[i].contentionTimeMaxBeInUsec; 806 contentionTimeAvgBeInUsec = links[i].contentionTimeAvgBeInUsec; 807 contentionNumSamplesBe = links[i].contentionNumSamplesBe; 808 contentionTimeMinBkInUsec = links[i].contentionTimeMinBkInUsec; 809 contentionTimeMaxBkInUsec = links[i].contentionTimeMaxBkInUsec; 810 contentionTimeAvgBkInUsec = links[i].contentionTimeAvgBkInUsec; 811 contentionNumSamplesBk = links[i].contentionNumSamplesBk; 812 contentionTimeMinViInUsec = links[i].contentionTimeMinViInUsec; 813 contentionTimeMaxViInUsec = links[i].contentionTimeMaxViInUsec; 814 contentionTimeAvgViInUsec = links[i].contentionTimeAvgViInUsec; 815 contentionNumSamplesVi = links[i].contentionNumSamplesVi; 816 contentionTimeMinVoInUsec = links[i].contentionTimeMinVoInUsec; 817 contentionTimeMaxVoInUsec = links[i].contentionTimeMaxVoInUsec; 818 contentionTimeAvgVoInUsec = links[i].contentionTimeAvgVoInUsec; 819 contentionNumSamplesVo = links[i].contentionNumSamplesVo; 820 aggregatePacketStats(); 821 aggregatePeerStats(); 822 } 823 } 824