WifiScoreReport.java revision 33d55307b8e4a03b7ace877968585002ec37dbea
1/* 2 * Copyright (C) 2016 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; 18 19import android.content.Context; 20import android.net.NetworkAgent; 21import android.net.wifi.WifiInfo; 22import android.util.Log; 23 24import java.io.FileDescriptor; 25import java.io.PrintWriter; 26import java.text.SimpleDateFormat; 27import java.util.Date; 28import java.util.LinkedList; 29import java.util.Locale; 30 31/** 32 * Class used to calculate scores for connected wifi networks and report it to the associated 33 * network agent. 34*/ 35public class WifiScoreReport { 36 private static final String TAG = "WifiScoreReport"; 37 38 private static final int DUMPSYS_ENTRY_COUNT_LIMIT = 14400; // 12 hours on 3 second poll 39 40 private boolean mVerboseLoggingEnabled = false; 41 private static final long FIRST_REASONABLE_WALL_CLOCK = 1490000000000L; // mid-December 2016 42 43 // Cache of the last score report. 44 private String mReport; 45 private boolean mReportValid = false; 46 47 private final Clock mClock; 48 private int mSessionNumber = 0; 49 50 ConnectedScore mConnectedScore; 51 ConnectedScore mAggressiveConnectedScore; 52 53 WifiScoreReport(Context context, WifiConfigManager wifiConfigManager, Clock clock) { 54 mClock = clock; 55 mConnectedScore = new LegacyConnectedScore(context, wifiConfigManager, clock); 56 mAggressiveConnectedScore = new AggressiveConnectedScore(context, clock); 57 } 58 59 /** 60 * Method returning the String representation of the last score report. 61 * 62 * @return String score report 63 */ 64 public String getLastReport() { 65 return mReport; 66 } 67 68 /** 69 * Reset the last calculated score. 70 */ 71 public void reset() { 72 mReport = ""; 73 if (mReportValid) { 74 mSessionNumber++; 75 mReportValid = false; 76 } 77 mConnectedScore.reset(); 78 mAggressiveConnectedScore.reset(); 79 if (mVerboseLoggingEnabled) Log.d(TAG, "reset"); 80 } 81 82 /** 83 * Checks if the last report data is valid or not. This will be cleared when {@link #reset()} is 84 * invoked. 85 * 86 * @return true if valid, false otherwise. 87 */ 88 public boolean isLastReportValid() { 89 return mReportValid; 90 } 91 92 /** 93 * Enable/Disable verbose logging in score report generation. 94 */ 95 public void enableVerboseLogging(boolean enable) { 96 mVerboseLoggingEnabled = enable; 97 } 98 99 /** 100 * Calculate wifi network score based on updated link layer stats and send the score to 101 * the provided network agent. 102 * 103 * If the score has changed from the previous value, update the WifiNetworkAgent. 104 * 105 * Called periodically (POLL_RSSI_INTERVAL_MSECS) about every 3 seconds. 106 * 107 * @param wifiInfo WifiInfo instance pointing to the currently connected network. 108 * @param networkAgent NetworkAgent to be notified of new score. 109 * @param aggressiveHandover int current aggressiveHandover setting. 110 * @param wifiMetrics for reporting our scores. 111 */ 112 public void calculateAndReportScore(WifiInfo wifiInfo, NetworkAgent networkAgent, 113 int aggressiveHandover, WifiMetrics wifiMetrics) { 114 int score; 115 116 long millis = mConnectedScore.getMillis(); 117 118 mConnectedScore.updateUsingWifiInfo(wifiInfo, millis); 119 mAggressiveConnectedScore.updateUsingWifiInfo(wifiInfo, millis); 120 121 int s0 = mConnectedScore.generateScore(); 122 int s1 = mAggressiveConnectedScore.generateScore(); 123 124 if (aggressiveHandover == 0) { 125 score = s0; 126 } else { 127 score = s1; 128 } 129 130 //sanitize boundaries 131 if (score > NetworkAgent.WIFI_BASE_SCORE) { 132 score = NetworkAgent.WIFI_BASE_SCORE; 133 } 134 if (score < 0) { 135 score = 0; 136 } 137 138 logLinkMetrics(wifiInfo, s0, s1); 139 140 //report score 141 if (score != wifiInfo.score) { 142 if (mVerboseLoggingEnabled) { 143 Log.d(TAG, " report new wifi score " + score); 144 } 145 wifiInfo.score = score; 146 if (networkAgent != null) { 147 networkAgent.sendNetworkScore(score); 148 } 149 } 150 151 mReport = String.format(Locale.US, " score=%d", score); 152 mReportValid = true; 153 wifiMetrics.incrementWifiScoreCount(score); 154 } 155 156 /** 157 * Data for dumpsys 158 * 159 * These are stored as csv formatted lines 160 */ 161 private LinkedList<String> mLinkMetricsHistory = new LinkedList<String>(); 162 163 /** 164 * Data logging for dumpsys 165 */ 166 private void logLinkMetrics(WifiInfo wifiInfo, int s0, int s1) { 167 long now = mClock.getWallClockMillis(); 168 if (now < FIRST_REASONABLE_WALL_CLOCK) return; 169 double rssi = wifiInfo.getRssi(); 170 int freq = wifiInfo.getFrequency(); 171 int linkSpeed = wifiInfo.getLinkSpeed(); 172 double txSuccessRate = wifiInfo.txSuccessRate; 173 double txRetriesRate = wifiInfo.txRetriesRate; 174 double txBadRate = wifiInfo.txBadRate; 175 double rxSuccessRate = wifiInfo.rxSuccessRate; 176 try { 177 String timestamp = new SimpleDateFormat("MM-dd HH:mm:ss.SSS").format(new Date(now)); 178 String s = String.format(Locale.US, // Use US to avoid comma/decimal confusion 179 "%s,%d,%.1f,%d,%d,%.2f,%.2f,%.2f,%.2f,%d,%d", 180 timestamp, mSessionNumber, rssi, freq, linkSpeed, 181 txSuccessRate, txRetriesRate, txBadRate, rxSuccessRate, 182 s0, s1); 183 mLinkMetricsHistory.add(s); 184 } catch (Exception e) { 185 Log.e(TAG, "format problem", e); 186 } 187 while (mLinkMetricsHistory.size() > DUMPSYS_ENTRY_COUNT_LIMIT) { 188 mLinkMetricsHistory.removeFirst(); 189 } 190 } 191 192 /** 193 * Tag to be used in dumpsys request 194 */ 195 public static final String DUMP_ARG = "WifiScoreReport"; 196 197 /** 198 * Dump logged signal strength and traffic measurements. 199 * @param fd unused 200 * @param pw PrintWriter for writing dump to 201 * @param args unused 202 */ 203 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 204 pw.println("time,session,rssi,freq,linkspeed,tx_good,tx_retry,tx_bad,rx,s0,s1"); 205 for (String line : mLinkMetricsHistory) { 206 pw.println(line); 207 } 208 } 209} 210