Home | History | Annotate | Download | only in wifi
      1 /*
      2  * Copyright (C) 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.settingslib.wifi;
     18 
     19 import android.content.Context;
     20 import android.net.wifi.ScanResult;
     21 import android.net.wifi.WifiConfiguration;
     22 import android.net.wifi.WifiInfo;
     23 import android.os.SystemClock;
     24 import android.support.annotation.VisibleForTesting;
     25 
     26 import com.android.settingslib.R;
     27 
     28 import java.util.Map;
     29 
     30 public class WifiUtils {
     31 
     32     public static String buildLoggingSummary(AccessPoint accessPoint, WifiConfiguration config) {
     33         final StringBuilder summary = new StringBuilder();
     34         final WifiInfo info = accessPoint.getInfo();
     35         // Add RSSI/band information for this config, what was seen up to 6 seconds ago
     36         // verbose WiFi Logging is only turned on thru developers settings
     37         if (accessPoint.isActive() && info != null) {
     38             summary.append(" f=" + Integer.toString(info.getFrequency()));
     39         }
     40         summary.append(" " + getVisibilityStatus(accessPoint));
     41         if (config != null && !config.getNetworkSelectionStatus().isNetworkEnabled()) {
     42             summary.append(" (" + config.getNetworkSelectionStatus().getNetworkStatusString());
     43             if (config.getNetworkSelectionStatus().getDisableTime() > 0) {
     44                 long now = System.currentTimeMillis();
     45                 long diff = (now - config.getNetworkSelectionStatus().getDisableTime()) / 1000;
     46                 long sec = diff % 60; //seconds
     47                 long min = (diff / 60) % 60; //minutes
     48                 long hour = (min / 60) % 60; //hours
     49                 summary.append(", ");
     50                 if (hour > 0) summary.append(Long.toString(hour) + "h ");
     51                 summary.append(Long.toString(min) + "m ");
     52                 summary.append(Long.toString(sec) + "s ");
     53             }
     54             summary.append(")");
     55         }
     56 
     57         if (config != null) {
     58             WifiConfiguration.NetworkSelectionStatus networkStatus =
     59                     config.getNetworkSelectionStatus();
     60             for (int index = WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
     61                     index < WifiConfiguration.NetworkSelectionStatus
     62                             .NETWORK_SELECTION_DISABLED_MAX; index++) {
     63                 if (networkStatus.getDisableReasonCounter(index) != 0) {
     64                     summary.append(" " + WifiConfiguration.NetworkSelectionStatus
     65                             .getNetworkDisableReasonString(index) + "="
     66                             + networkStatus.getDisableReasonCounter(index));
     67                 }
     68             }
     69         }
     70 
     71         return summary.toString();
     72     }
     73 
     74     /**
     75      * Returns the visibility status of the WifiConfiguration.
     76      *
     77      * @return autojoin debugging information
     78      * TODO: use a string formatter
     79      * ["rssi 5Ghz", "num results on 5GHz" / "rssi 5Ghz", "num results on 5GHz"]
     80      * For instance [-40,5/-30,2]
     81      */
     82     @VisibleForTesting
     83     static String getVisibilityStatus(AccessPoint accessPoint) {
     84         final WifiInfo info = accessPoint.getInfo();
     85         StringBuilder visibility = new StringBuilder();
     86         StringBuilder scans24GHz = new StringBuilder();
     87         StringBuilder scans5GHz = new StringBuilder();
     88         String bssid = null;
     89 
     90         if (accessPoint.isActive() && info != null) {
     91             bssid = info.getBSSID();
     92             if (bssid != null) {
     93                 visibility.append(" ").append(bssid);
     94             }
     95             visibility.append(" rssi=").append(info.getRssi());
     96             visibility.append(" ");
     97             visibility.append(" score=").append(info.score);
     98             if (accessPoint.getSpeed() != AccessPoint.Speed.NONE) {
     99                 visibility.append(" speed=").append(accessPoint.getSpeedLabel());
    100             }
    101             visibility.append(String.format(" tx=%.1f,", info.txSuccessRate));
    102             visibility.append(String.format("%.1f,", info.txRetriesRate));
    103             visibility.append(String.format("%.1f ", info.txBadRate));
    104             visibility.append(String.format("rx=%.1f", info.rxSuccessRate));
    105         }
    106 
    107         int maxRssi5 = WifiConfiguration.INVALID_RSSI;
    108         int maxRssi24 = WifiConfiguration.INVALID_RSSI;
    109         final int maxDisplayedScans = 4;
    110         int num5 = 0; // number of scanned BSSID on 5GHz band
    111         int num24 = 0; // number of scanned BSSID on 2.4Ghz band
    112         int numBlackListed = 0;
    113 
    114         // TODO: sort list by RSSI or age
    115         long nowMs = SystemClock.elapsedRealtime();
    116         for (ScanResult result : accessPoint.getScanResults()) {
    117             if (result == null) {
    118                 continue;
    119             }
    120             if (result.frequency >= AccessPoint.LOWER_FREQ_5GHZ
    121                     && result.frequency <= AccessPoint.HIGHER_FREQ_5GHZ) {
    122                 // Strictly speaking: [4915, 5825]
    123                 num5++;
    124 
    125                 if (result.level > maxRssi5) {
    126                     maxRssi5 = result.level;
    127                 }
    128                 if (num5 <= maxDisplayedScans) {
    129                     scans5GHz.append(
    130                             verboseScanResultSummary(accessPoint, result, bssid,
    131                                     nowMs));
    132                 }
    133             } else if (result.frequency >= AccessPoint.LOWER_FREQ_24GHZ
    134                     && result.frequency <= AccessPoint.HIGHER_FREQ_24GHZ) {
    135                 // Strictly speaking: [2412, 2482]
    136                 num24++;
    137 
    138                 if (result.level > maxRssi24) {
    139                     maxRssi24 = result.level;
    140                 }
    141                 if (num24 <= maxDisplayedScans) {
    142                     scans24GHz.append(
    143                             verboseScanResultSummary(accessPoint, result, bssid,
    144                                     nowMs));
    145                 }
    146             }
    147         }
    148         visibility.append(" [");
    149         if (num24 > 0) {
    150             visibility.append("(").append(num24).append(")");
    151             if (num24 > maxDisplayedScans) {
    152                 visibility.append("max=").append(maxRssi24).append(",");
    153             }
    154             visibility.append(scans24GHz.toString());
    155         }
    156         visibility.append(";");
    157         if (num5 > 0) {
    158             visibility.append("(").append(num5).append(")");
    159             if (num5 > maxDisplayedScans) {
    160                 visibility.append("max=").append(maxRssi5).append(",");
    161             }
    162             visibility.append(scans5GHz.toString());
    163         }
    164         if (numBlackListed > 0) {
    165             visibility.append("!").append(numBlackListed);
    166         }
    167         visibility.append("]");
    168 
    169         return visibility.toString();
    170     }
    171 
    172     @VisibleForTesting
    173     /* package */ static String verboseScanResultSummary(AccessPoint accessPoint, ScanResult result,
    174             String bssid, long nowMs) {
    175         StringBuilder stringBuilder = new StringBuilder();
    176         stringBuilder.append(" \n{").append(result.BSSID);
    177         if (result.BSSID.equals(bssid)) {
    178             stringBuilder.append("*");
    179         }
    180         stringBuilder.append("=").append(result.frequency);
    181         stringBuilder.append(",").append(result.level);
    182         int speed = getSpecificApSpeed(result, accessPoint.getScoredNetworkCache());
    183         if (speed != AccessPoint.Speed.NONE) {
    184             stringBuilder.append(",")
    185                     .append(accessPoint.getSpeedLabel(speed));
    186         }
    187         int ageSeconds = (int) (nowMs - result.timestamp / 1000) / 1000;
    188         stringBuilder.append(",").append(ageSeconds).append("s");
    189         stringBuilder.append("}");
    190         return stringBuilder.toString();
    191     }
    192 
    193     @AccessPoint.Speed
    194     private static int getSpecificApSpeed(ScanResult result,
    195             Map<String, TimestampedScoredNetwork> scoredNetworkCache) {
    196         TimestampedScoredNetwork timedScore = scoredNetworkCache.get(result.BSSID);
    197         if (timedScore == null) {
    198             return AccessPoint.Speed.NONE;
    199         }
    200         // For debugging purposes we may want to use mRssi rather than result.level as the average
    201         // speed wil be determined by mRssi
    202         return timedScore.getScore().calculateBadge(result.level);
    203     }
    204 
    205     public static String getMeteredLabel(Context context, WifiConfiguration config) {
    206         // meteredOverride is whether the user manually set the metered setting or not.
    207         // meteredHint is whether the network itself is telling us that it is metered
    208         if (config.meteredOverride == WifiConfiguration.METERED_OVERRIDE_METERED
    209                 || (config.meteredHint && !isMeteredOverridden(config))) {
    210             return context.getString(R.string.wifi_metered_label);
    211         }
    212         return context.getString(R.string.wifi_unmetered_label);
    213     }
    214 
    215     public static boolean isMeteredOverridden(WifiConfiguration config) {
    216         return config.meteredOverride != WifiConfiguration.METERED_OVERRIDE_NONE;
    217     }
    218 }
    219