1 /*
2  * Copyright 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 
17 package com.android.server.wifi;
18 
19 import android.annotation.NonNull;
20 import android.net.wifi.MloLink;
21 import android.net.wifi.WifiInfo;
22 
23 /**
24  * Extends WifiInfo with the methods for computing the averaged packet rates
25  */
26 public class ExtendedWifiInfo extends WifiInfo {
27     private static final long RESET_TIME_STAMP = Long.MIN_VALUE;
28     private static final double FILTER_TIME_CONSTANT = 3000.0;
29     private static final int SOURCE_UNKNOWN = 0;
30     private static final int SOURCE_TRAFFIC_COUNTERS = 1;
31     private static final int SOURCE_LLSTATS = 2;
32 
33     private final WifiGlobals mWifiGlobals;
34     private final String mIfaceName;
35 
36     private int mLastSource = SOURCE_UNKNOWN;
37     private long mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
38 
ExtendedWifiInfo(WifiGlobals wifiGlobals, String ifaceName)39     ExtendedWifiInfo(WifiGlobals wifiGlobals, String ifaceName) {
40         mWifiGlobals = wifiGlobals;
41         mIfaceName = ifaceName;
42     }
43 
44     @Override
reset()45     public void reset() {
46         super.reset();
47         mLastSource = SOURCE_UNKNOWN;
48         mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
49         if (mWifiGlobals.isConnectedMacRandomizationEnabled()) {
50             setMacAddress(DEFAULT_MAC_ADDRESS);
51         }
52     }
53 
54     /**
55      * Updates the packet rates using link layer stats
56      *
57      * @param stats WifiLinkLayerStats
58      * @param timeStamp time in milliseconds
59      */
updatePacketRates(@onNull WifiLinkLayerStats stats, long timeStamp)60     public void updatePacketRates(@NonNull WifiLinkLayerStats stats, long timeStamp) {
61         long txgood = stats.txmpdu_be + stats.txmpdu_bk + stats.txmpdu_vi + stats.txmpdu_vo;
62         long txretries = stats.retries_be + stats.retries_bk + stats.retries_vi + stats.retries_vo;
63         long txbad = stats.lostmpdu_be + stats.lostmpdu_bk + stats.lostmpdu_vi + stats.lostmpdu_vo;
64         long rxgood = stats.rxmpdu_be + stats.rxmpdu_bk + stats.rxmpdu_vi + stats.rxmpdu_vo;
65         updateWifiInfoRates(SOURCE_LLSTATS, txgood, txretries, txbad, rxgood, timeStamp);
66         // Process link stats if available.
67         if (stats.links == null) return;
68         for (WifiLinkLayerStats.LinkSpecificStats link : stats.links) {
69             updateMloRates(
70                     link.link_id,
71                     SOURCE_LLSTATS,
72                     link.txmpdu_be + link.txmpdu_bk + link.txmpdu_vi + link.txmpdu_vo,
73                     link.retries_be + link.retries_bk + link.retries_vi + link.retries_vo,
74                     link.lostmpdu_be + link.lostmpdu_bk + link.lostmpdu_vi + link.lostmpdu_vo,
75                     link.rxmpdu_be + link.rxmpdu_bk + link.rxmpdu_vi + link.rxmpdu_vo,
76                     timeStamp);
77         }
78     }
79 
80     /**
81      * This function is less powerful and used if the WifiLinkLayerStats API is not implemented
82      * at the Wifi HAL
83      */
updatePacketRates(long txPackets, long rxPackets, long timeStamp)84     public void updatePacketRates(long txPackets, long rxPackets, long timeStamp) {
85         updateWifiInfoRates(SOURCE_TRAFFIC_COUNTERS, txPackets, 0, 0, rxPackets, timeStamp);
86     }
87 
updateMloRates( int linkId, int source, long txgood, long txretries, long txbad, long rxgood, long timeStamp)88     private void updateMloRates(
89             int linkId,
90             int source,
91             long txgood,
92             long txretries,
93             long txbad,
94             long rxgood,
95             long timeStamp) {
96         MloLink link = getAffiliatedMloLink(linkId);
97         if (link == null) return;
98         if (source == mLastSource
99                 && link.lastPacketCountUpdateTimeStamp != RESET_TIME_STAMP
100                 && link.lastPacketCountUpdateTimeStamp < timeStamp
101                 && link.txBad <= txbad
102                 && link.txSuccess <= txgood
103                 && link.rxSuccess <= rxgood
104                 && link.txRetries <= txretries) {
105             long timeDelta = timeStamp - link.lastPacketCountUpdateTimeStamp;
106             double lastSampleWeight = Math.exp(-1.0 * timeDelta / FILTER_TIME_CONSTANT);
107             double currentSampleWeight = 1.0 - lastSampleWeight;
108 
109             link.setLostTxPacketsPerSecond(
110                     link.getLostTxPacketsPerSecond() * lastSampleWeight
111                             + (txbad - link.txBad) * 1000.0 / timeDelta * currentSampleWeight);
112             link.setSuccessfulTxPacketsPerSecond(
113                     link.getSuccessfulTxPacketsPerSecond() * lastSampleWeight
114                             + (txgood - link.txSuccess) * 1000.0 / timeDelta * currentSampleWeight);
115             link.setSuccessfulRxPacketsPerSecond(
116                     link.getSuccessfulRxPacketsPerSecond() * lastSampleWeight
117                             + (rxgood - link.rxSuccess) * 1000.0 / timeDelta * currentSampleWeight);
118             link.setRetriedTxPacketsRate(
119                     link.getRetriedTxPacketsPerSecond() * lastSampleWeight
120                             + (txretries - link.txRetries)
121                                     * 1000.0
122                                     / timeDelta
123                                     * currentSampleWeight);
124         } else {
125             link.setLostTxPacketsPerSecond(0);
126             link.setSuccessfulTxPacketsPerSecond(0);
127             link.setSuccessfulRxPacketsPerSecond(0);
128             link.setRetriedTxPacketsRate(0);
129             mLastSource = source;
130         }
131         link.txBad = txbad;
132         link.txSuccess = txgood;
133         link.rxSuccess = rxgood;
134         link.txRetries = txretries;
135         link.lastPacketCountUpdateTimeStamp = timeStamp;
136     }
137 
updateWifiInfoRates( int source, long txgood, long txretries, long txbad, long rxgood, long timeStamp)138     private void updateWifiInfoRates(
139             int source, long txgood, long txretries, long txbad, long rxgood, long timeStamp) {
140         if (source == mLastSource
141                 && mLastPacketCountUpdateTimeStamp != RESET_TIME_STAMP
142                 && mLastPacketCountUpdateTimeStamp < timeStamp
143                 && txBad <= txbad
144                 && txSuccess <= txgood
145                 && rxSuccess <= rxgood
146                 && txRetries <= txretries) {
147             long timeDelta = timeStamp - mLastPacketCountUpdateTimeStamp;
148             double lastSampleWeight = Math.exp(-1.0 * timeDelta / FILTER_TIME_CONSTANT);
149             double currentSampleWeight = 1.0 - lastSampleWeight;
150 
151             setLostTxPacketsPerSecond(getLostTxPacketsPerSecond() * lastSampleWeight
152                     + (txbad - txBad) * 1000.0 / timeDelta
153                     * currentSampleWeight);
154             setSuccessfulTxPacketsPerSecond(getSuccessfulTxPacketsPerSecond() * lastSampleWeight
155                     + (txgood - txSuccess) * 1000.0 / timeDelta
156                     * currentSampleWeight);
157             setSuccessfulRxPacketsPerSecond(getSuccessfulRxPacketsPerSecond() * lastSampleWeight
158                     + (rxgood - rxSuccess) * 1000.0 / timeDelta
159                     * currentSampleWeight);
160             setRetriedTxPacketsRate(getRetriedTxPacketsPerSecond() * lastSampleWeight
161                     + (txretries - txRetries) * 1000.0 / timeDelta
162                     * currentSampleWeight);
163         } else {
164             setLostTxPacketsPerSecond(0);
165             setSuccessfulTxPacketsPerSecond(0);
166             setSuccessfulRxPacketsPerSecond(0);
167             setRetriedTxPacketsRate(0);
168             mLastSource = source;
169         }
170         txBad = txbad;
171         txSuccess = txgood;
172         rxSuccess = rxgood;
173         txRetries = txretries;
174         mLastPacketCountUpdateTimeStamp = timeStamp;
175     }
176 
getIfaceName()177     public String getIfaceName() {
178         return mIfaceName;
179     }
180 }
181