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