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