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