Home | History | Annotate | Download | only in wifi
      1 /*
      2  * Copyright (C) 2008 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 android.net.wifi;
     18 
     19 import android.os.Parcelable;
     20 import android.os.Parcel;
     21 import android.net.NetworkInfo.DetailedState;
     22 import android.net.NetworkUtils;
     23 import android.text.TextUtils;
     24 
     25 import java.net.InetAddress;
     26 import java.net.Inet4Address;
     27 import java.net.UnknownHostException;
     28 import java.util.EnumMap;
     29 import java.util.Locale;
     30 
     31 /**
     32  * Describes the state of any Wifi connection that is active or
     33  * is in the process of being set up.
     34  */
     35 public class WifiInfo implements Parcelable {
     36     private static final String TAG = "WifiInfo";
     37     /**
     38      * This is the map described in the Javadoc comment above. The positions
     39      * of the elements of the array must correspond to the ordinal values
     40      * of <code>DetailedState</code>.
     41      */
     42     private static final EnumMap<SupplicantState, DetailedState> stateMap =
     43             new EnumMap<SupplicantState, DetailedState>(SupplicantState.class);
     44 
     45     /**
     46      * Default MAC address reported to a client that does not have the
     47      * android.permission.LOCAL_MAC_ADDRESS permission.
     48      *
     49      * @hide
     50      */
     51     public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00";
     52 
     53     static {
     54         stateMap.put(SupplicantState.DISCONNECTED, DetailedState.DISCONNECTED);
     55         stateMap.put(SupplicantState.INTERFACE_DISABLED, DetailedState.DISCONNECTED);
     56         stateMap.put(SupplicantState.INACTIVE, DetailedState.IDLE);
     57         stateMap.put(SupplicantState.SCANNING, DetailedState.SCANNING);
     58         stateMap.put(SupplicantState.AUTHENTICATING, DetailedState.CONNECTING);
     59         stateMap.put(SupplicantState.ASSOCIATING, DetailedState.CONNECTING);
     60         stateMap.put(SupplicantState.ASSOCIATED, DetailedState.CONNECTING);
     61         stateMap.put(SupplicantState.FOUR_WAY_HANDSHAKE, DetailedState.AUTHENTICATING);
     62         stateMap.put(SupplicantState.GROUP_HANDSHAKE, DetailedState.AUTHENTICATING);
     63         stateMap.put(SupplicantState.COMPLETED, DetailedState.OBTAINING_IPADDR);
     64         stateMap.put(SupplicantState.DORMANT, DetailedState.DISCONNECTED);
     65         stateMap.put(SupplicantState.UNINITIALIZED, DetailedState.IDLE);
     66         stateMap.put(SupplicantState.INVALID, DetailedState.FAILED);
     67     }
     68 
     69     private SupplicantState mSupplicantState;
     70     private String mBSSID;
     71     private WifiSsid mWifiSsid;
     72     private int mNetworkId;
     73 
     74     /** @hide **/
     75     public static final int INVALID_RSSI = -127;
     76 
     77     /** @hide **/
     78     public static final int MIN_RSSI = -126;
     79 
     80     /** @hide **/
     81     public static final int MAX_RSSI = 200;
     82 
     83 
     84     /**
     85      * Received Signal Strength Indicator
     86      */
     87     private int mRssi;
     88 
     89     /**
     90      * Link speed in Mbps
     91      */
     92     public static final String LINK_SPEED_UNITS = "Mbps";
     93     private int mLinkSpeed;
     94 
     95     /**
     96      * Frequency in MHz
     97      */
     98     public static final String FREQUENCY_UNITS = "MHz";
     99     private int mFrequency;
    100 
    101     private InetAddress mIpAddress;
    102     private String mMacAddress = DEFAULT_MAC_ADDRESS;
    103 
    104     private boolean mEphemeral;
    105 
    106     /**
    107      * @hide
    108      */
    109     public long txBad;
    110     /**
    111      * @hide
    112      */
    113     public long txRetries;
    114     /**
    115      * @hide
    116      */
    117     public long txSuccess;
    118     /**
    119      * @hide
    120      */
    121     public long rxSuccess;
    122     /**
    123      * @hide
    124      */
    125     public double txBadRate;
    126     /**
    127      * @hide
    128      */
    129     public double txRetriesRate;
    130     /**
    131      * @hide
    132      */
    133     public double txSuccessRate;
    134     /**
    135      * @hide
    136      */
    137     public double rxSuccessRate;
    138 
    139     /**
    140      * @hide
    141      */
    142     public int badRssiCount;
    143 
    144     /**
    145      * @hide
    146      */
    147     public int linkStuckCount;
    148 
    149     /**
    150      * @hide
    151      */
    152     public int lowRssiCount;
    153 
    154     /**
    155      * @hide
    156      */
    157     public int score;
    158 
    159     /**
    160      * TODO: get actual timestamp and calculate true rates
    161      * @hide
    162      */
    163     public void updatePacketRates(WifiLinkLayerStats stats) {
    164         if (stats != null) {
    165             long txgood = stats.txmpdu_be + stats.txmpdu_bk + stats.txmpdu_vi + stats.txmpdu_vo;
    166             long txretries = stats.retries_be + stats.retries_bk
    167                     + stats.retries_vi + stats.retries_vo;
    168             long rxgood = stats.rxmpdu_be + stats.rxmpdu_bk + stats.rxmpdu_vi + stats.rxmpdu_vo;
    169             long txbad = stats.lostmpdu_be + stats.lostmpdu_bk
    170                     + stats.lostmpdu_vi + stats.lostmpdu_vo;
    171 
    172             if (txBad <= txbad
    173                     && txSuccess <= txgood
    174                     && rxSuccess <= rxgood
    175                     && txRetries <= txretries) {
    176                 txBadRate = (txBadRate * 0.5)
    177                         + ((double) (txbad - txBad) * 0.5);
    178                 txSuccessRate = (txSuccessRate * 0.5)
    179                         + ((double) (txgood - txSuccess) * 0.5);
    180                 rxSuccessRate = (rxSuccessRate * 0.5)
    181                         + ((double) (rxgood - rxSuccess) * 0.5);
    182                 txRetriesRate = (txRetriesRate * 0.5)
    183                         + ((double) (txretries - txRetries) * 0.5);
    184             } else {
    185                 txBadRate = 0;
    186                 txSuccessRate = 0;
    187                 rxSuccessRate = 0;
    188                 txRetriesRate = 0;
    189             }
    190             txBad = txbad;
    191             txSuccess = txgood;
    192             rxSuccess = rxgood;
    193             txRetries = txretries;
    194         } else {
    195             txBad = 0;
    196             txSuccess = 0;
    197             rxSuccess = 0;
    198             txRetries = 0;
    199             txBadRate = 0;
    200             txSuccessRate = 0;
    201             rxSuccessRate = 0;
    202             txRetriesRate = 0;
    203         }
    204     }
    205 
    206 
    207     /**
    208      * This function is less powerful and used if the WifiLinkLayerStats API is not implemented
    209      * at the Wifi HAL
    210      * @hide
    211      */
    212     public void updatePacketRates(long txPackets, long rxPackets) {
    213         //paranoia
    214         txBad = 0;
    215         txRetries = 0;
    216         txBadRate = 0;
    217         txRetriesRate = 0;
    218         if (txSuccess <= txPackets && rxSuccess <= rxPackets) {
    219             txSuccessRate = (txSuccessRate * 0.5)
    220                     + ((double) (txPackets - txSuccess) * 0.5);
    221             rxSuccessRate = (rxSuccessRate * 0.5)
    222                     + ((double) (rxPackets - rxSuccess) * 0.5);
    223         } else {
    224             txBadRate = 0;
    225             txRetriesRate = 0;
    226         }
    227         txSuccess = txPackets;
    228         rxSuccess = rxPackets;
    229     }
    230 
    231         /**
    232          * Flag indicating that AP has hinted that upstream connection is metered,
    233          * and sensitive to heavy data transfers.
    234          */
    235     private boolean mMeteredHint;
    236 
    237     /** @hide */
    238     public WifiInfo() {
    239         mWifiSsid = null;
    240         mBSSID = null;
    241         mNetworkId = -1;
    242         mSupplicantState = SupplicantState.UNINITIALIZED;
    243         mRssi = INVALID_RSSI;
    244         mLinkSpeed = -1;
    245         mFrequency = -1;
    246     }
    247 
    248     /** @hide */
    249     public void reset() {
    250         setInetAddress(null);
    251         setBSSID(null);
    252         setSSID(null);
    253         setNetworkId(-1);
    254         setRssi(INVALID_RSSI);
    255         setLinkSpeed(-1);
    256         setFrequency(-1);
    257         setMeteredHint(false);
    258         setEphemeral(false);
    259         txBad = 0;
    260         txSuccess = 0;
    261         rxSuccess = 0;
    262         txRetries = 0;
    263         txBadRate = 0;
    264         txSuccessRate = 0;
    265         rxSuccessRate = 0;
    266         txRetriesRate = 0;
    267         lowRssiCount = 0;
    268         badRssiCount = 0;
    269         linkStuckCount = 0;
    270         score = 0;
    271     }
    272 
    273     /**
    274      * Copy constructor
    275      * @hide
    276      */
    277     public WifiInfo(WifiInfo source) {
    278         if (source != null) {
    279             mSupplicantState = source.mSupplicantState;
    280             mBSSID = source.mBSSID;
    281             mWifiSsid = source.mWifiSsid;
    282             mNetworkId = source.mNetworkId;
    283             mRssi = source.mRssi;
    284             mLinkSpeed = source.mLinkSpeed;
    285             mFrequency = source.mFrequency;
    286             mIpAddress = source.mIpAddress;
    287             mMacAddress = source.mMacAddress;
    288             mMeteredHint = source.mMeteredHint;
    289             mEphemeral = source.mEphemeral;
    290             txBad = source.txBad;
    291             txRetries = source.txRetries;
    292             txSuccess = source.txSuccess;
    293             rxSuccess = source.rxSuccess;
    294             txBadRate = source.txBadRate;
    295             txRetriesRate = source.txRetriesRate;
    296             txSuccessRate = source.txSuccessRate;
    297             rxSuccessRate = source.rxSuccessRate;
    298             score = source.score;
    299             badRssiCount = source.badRssiCount;
    300             lowRssiCount = source.lowRssiCount;
    301             linkStuckCount = source.linkStuckCount;
    302         }
    303     }
    304 
    305     /** @hide */
    306     public void setSSID(WifiSsid wifiSsid) {
    307         mWifiSsid = wifiSsid;
    308     }
    309 
    310     /**
    311      * Returns the service set identifier (SSID) of the current 802.11 network.
    312      * If the SSID can be decoded as UTF-8, it will be returned surrounded by double
    313      * quotation marks. Otherwise, it is returned as a string of hex digits. The
    314      * SSID may be &lt;unknown ssid&gt; if there is no network currently connected.
    315      * @return the SSID
    316      */
    317     public String getSSID() {
    318         if (mWifiSsid != null) {
    319             String unicode = mWifiSsid.toString();
    320             if (!TextUtils.isEmpty(unicode)) {
    321                 return "\"" + unicode + "\"";
    322             } else {
    323                 String hex = mWifiSsid.getHexString();
    324                 return (hex != null) ? hex : WifiSsid.NONE;
    325             }
    326         }
    327         return WifiSsid.NONE;
    328     }
    329 
    330     /** @hide */
    331     public WifiSsid getWifiSsid() {
    332         return mWifiSsid;
    333     }
    334 
    335     /** @hide */
    336     public void setBSSID(String BSSID) {
    337         mBSSID = BSSID;
    338     }
    339 
    340     /**
    341      * Return the basic service set identifier (BSSID) of the current access point.
    342      * The BSSID may be {@code null} if there is no network currently connected.
    343      * @return the BSSID, in the form of a six-byte MAC address: {@code XX:XX:XX:XX:XX:XX}
    344      */
    345     public String getBSSID() {
    346         return mBSSID;
    347     }
    348 
    349     /**
    350      * Returns the received signal strength indicator of the current 802.11
    351      * network, in dBm.
    352      *
    353      * <p>Use {@link android.net.wifi.WifiManager#calculateSignalLevel} to convert this number into
    354      * an absolute signal level which can be displayed to a user.
    355      *
    356      * @return the RSSI.
    357      */
    358     public int getRssi() {
    359         return mRssi;
    360     }
    361 
    362     /** @hide */
    363     public void setRssi(int rssi) {
    364         if (rssi < INVALID_RSSI)
    365             rssi = INVALID_RSSI;
    366         if (rssi > MAX_RSSI)
    367             rssi = MAX_RSSI;
    368         mRssi = rssi;
    369     }
    370 
    371     /**
    372      * Returns the current link speed in {@link #LINK_SPEED_UNITS}.
    373      * @return the link speed.
    374      * @see #LINK_SPEED_UNITS
    375      */
    376     public int getLinkSpeed() {
    377         return mLinkSpeed;
    378     }
    379 
    380     /** @hide */
    381     public void setLinkSpeed(int linkSpeed) {
    382         this.mLinkSpeed = linkSpeed;
    383     }
    384 
    385     /**
    386      * Returns the current frequency in {@link #FREQUENCY_UNITS}.
    387      * @return the frequency.
    388      * @see #FREQUENCY_UNITS
    389      */
    390     public int getFrequency() {
    391         return mFrequency;
    392     }
    393 
    394     /** @hide */
    395     public void setFrequency(int frequency) {
    396         this.mFrequency = frequency;
    397     }
    398 
    399     /**
    400      * @hide
    401      * TODO: makes real freq boundaries
    402      */
    403     public boolean is24GHz() {
    404         return ScanResult.is24GHz(mFrequency);
    405     }
    406 
    407     /**
    408      * @hide
    409      * TODO: makes real freq boundaries
    410      */
    411     public boolean is5GHz() {
    412         return ScanResult.is5GHz(mFrequency);
    413     }
    414 
    415     /**
    416      * Record the MAC address of the WLAN interface
    417      * @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form
    418      * @hide
    419      */
    420     public void setMacAddress(String macAddress) {
    421         this.mMacAddress = macAddress;
    422     }
    423 
    424     public String getMacAddress() {
    425         return mMacAddress;
    426     }
    427 
    428     /**
    429      * @return true if {@link #getMacAddress()} has a real MAC address.
    430      *
    431      * @hide
    432      */
    433     public boolean hasRealMacAddress() {
    434         return mMacAddress != null && !DEFAULT_MAC_ADDRESS.equals(mMacAddress);
    435     }
    436 
    437     /** {@hide} */
    438     public void setMeteredHint(boolean meteredHint) {
    439         mMeteredHint = meteredHint;
    440     }
    441 
    442     /** {@hide} */
    443     public boolean getMeteredHint() {
    444         return mMeteredHint;
    445     }
    446 
    447     /** {@hide} */
    448     public void setEphemeral(boolean ephemeral) {
    449         mEphemeral = ephemeral;
    450     }
    451 
    452     /** {@hide} */
    453     public boolean isEphemeral() {
    454         return mEphemeral;
    455     }
    456 
    457     /** @hide */
    458     public void setNetworkId(int id) {
    459         mNetworkId = id;
    460     }
    461 
    462     /**
    463      * Each configured network has a unique small integer ID, used to identify
    464      * the network when performing operations on the supplicant. This method
    465      * returns the ID for the currently connected network.
    466      * @return the network ID, or -1 if there is no currently connected network
    467      */
    468     public int getNetworkId() {
    469         return mNetworkId;
    470     }
    471 
    472     /**
    473      * Return the detailed state of the supplicant's negotiation with an
    474      * access point, in the form of a {@link SupplicantState SupplicantState} object.
    475      * @return the current {@link SupplicantState SupplicantState}
    476      */
    477     public SupplicantState getSupplicantState() {
    478         return mSupplicantState;
    479     }
    480 
    481     /** @hide */
    482     public void setSupplicantState(SupplicantState state) {
    483         mSupplicantState = state;
    484     }
    485 
    486     /** @hide */
    487     public void setInetAddress(InetAddress address) {
    488         mIpAddress = address;
    489     }
    490 
    491     public int getIpAddress() {
    492         int result = 0;
    493         if (mIpAddress instanceof Inet4Address) {
    494             result = NetworkUtils.inetAddressToInt((Inet4Address)mIpAddress);
    495         }
    496         return result;
    497     }
    498 
    499     /**
    500      * @return {@code true} if this network does not broadcast its SSID, so an
    501      * SSID-specific probe request must be used for scans.
    502      */
    503     public boolean getHiddenSSID() {
    504         if (mWifiSsid == null) return false;
    505         return mWifiSsid.isHidden();
    506     }
    507 
    508    /**
    509      * Map a supplicant state into a fine-grained network connectivity state.
    510      * @param suppState the supplicant state
    511      * @return the corresponding {@link DetailedState}
    512      */
    513     public static DetailedState getDetailedStateOf(SupplicantState suppState) {
    514         return stateMap.get(suppState);
    515     }
    516 
    517     /**
    518      * Set the <code>SupplicantState</code> from the string name
    519      * of the state.
    520      * @param stateName the name of the state, as a <code>String</code> returned
    521      * in an event sent by {@code wpa_supplicant}.
    522      */
    523     void setSupplicantState(String stateName) {
    524         mSupplicantState = valueOf(stateName);
    525     }
    526 
    527     static SupplicantState valueOf(String stateName) {
    528         if ("4WAY_HANDSHAKE".equalsIgnoreCase(stateName))
    529             return SupplicantState.FOUR_WAY_HANDSHAKE;
    530         else {
    531             try {
    532                 return SupplicantState.valueOf(stateName.toUpperCase(Locale.ROOT));
    533             } catch (IllegalArgumentException e) {
    534                 return SupplicantState.INVALID;
    535             }
    536         }
    537     }
    538 
    539     /** {@hide} */
    540     public static String removeDoubleQuotes(String string) {
    541         if (string == null) return null;
    542         final int length = string.length();
    543         if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
    544             return string.substring(1, length - 1);
    545         }
    546         return string;
    547     }
    548 
    549     @Override
    550     public String toString() {
    551         StringBuffer sb = new StringBuffer();
    552         String none = "<none>";
    553 
    554         sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid).
    555             append(", BSSID: ").append(mBSSID == null ? none : mBSSID).
    556             append(", MAC: ").append(mMacAddress == null ? none : mMacAddress).
    557             append(", Supplicant state: ").
    558             append(mSupplicantState == null ? none : mSupplicantState).
    559             append(", RSSI: ").append(mRssi).
    560             append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS).
    561             append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS).
    562             append(", Net ID: ").append(mNetworkId).
    563             append(", Metered hint: ").append(mMeteredHint).
    564             append(", score: ").append(Integer.toString(score));
    565         return sb.toString();
    566     }
    567 
    568     /** Implement the Parcelable interface {@hide} */
    569     public int describeContents() {
    570         return 0;
    571     }
    572 
    573     /** Implement the Parcelable interface {@hide} */
    574     public void writeToParcel(Parcel dest, int flags) {
    575         dest.writeInt(mNetworkId);
    576         dest.writeInt(mRssi);
    577         dest.writeInt(mLinkSpeed);
    578         dest.writeInt(mFrequency);
    579         if (mIpAddress != null) {
    580             dest.writeByte((byte)1);
    581             dest.writeByteArray(mIpAddress.getAddress());
    582         } else {
    583             dest.writeByte((byte)0);
    584         }
    585         if (mWifiSsid != null) {
    586             dest.writeInt(1);
    587             mWifiSsid.writeToParcel(dest, flags);
    588         } else {
    589             dest.writeInt(0);
    590         }
    591         dest.writeString(mBSSID);
    592         dest.writeString(mMacAddress);
    593         dest.writeInt(mMeteredHint ? 1 : 0);
    594         dest.writeInt(mEphemeral ? 1 : 0);
    595         dest.writeInt(score);
    596         dest.writeDouble(txSuccessRate);
    597         dest.writeDouble(txRetriesRate);
    598         dest.writeDouble(txBadRate);
    599         dest.writeDouble(rxSuccessRate);
    600         dest.writeInt(badRssiCount);
    601         dest.writeInt(lowRssiCount);
    602         mSupplicantState.writeToParcel(dest, flags);
    603     }
    604 
    605     /** Implement the Parcelable interface {@hide} */
    606     public static final Creator<WifiInfo> CREATOR =
    607         new Creator<WifiInfo>() {
    608             public WifiInfo createFromParcel(Parcel in) {
    609                 WifiInfo info = new WifiInfo();
    610                 info.setNetworkId(in.readInt());
    611                 info.setRssi(in.readInt());
    612                 info.setLinkSpeed(in.readInt());
    613                 info.setFrequency(in.readInt());
    614                 if (in.readByte() == 1) {
    615                     try {
    616                         info.setInetAddress(InetAddress.getByAddress(in.createByteArray()));
    617                     } catch (UnknownHostException e) {}
    618                 }
    619                 if (in.readInt() == 1) {
    620                     info.mWifiSsid = WifiSsid.CREATOR.createFromParcel(in);
    621                 }
    622                 info.mBSSID = in.readString();
    623                 info.mMacAddress = in.readString();
    624                 info.mMeteredHint = in.readInt() != 0;
    625                 info.mEphemeral = in.readInt() != 0;
    626                 info.score = in.readInt();
    627                 info.txSuccessRate = in.readDouble();
    628                 info.txRetriesRate = in.readDouble();
    629                 info.txBadRate = in.readDouble();
    630                 info.rxSuccessRate = in.readDouble();
    631                 info.badRssiCount = in.readInt();
    632                 info.lowRssiCount = in.readInt();
    633                 info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in);
    634                 return info;
    635             }
    636 
    637             public WifiInfo[] newArray(int size) {
    638                 return new WifiInfo[size];
    639             }
    640         };
    641 }
    642