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                 return mWifiSsid.getHexString();
    324             }
    325         }
    326         return WifiSsid.NONE;
    327     }
    328 
    329     /** @hide */
    330     public WifiSsid getWifiSsid() {
    331         return mWifiSsid;
    332     }
    333 
    334     /** @hide */
    335     public void setBSSID(String BSSID) {
    336         mBSSID = BSSID;
    337     }
    338 
    339     /**
    340      * Return the basic service set identifier (BSSID) of the current access point.
    341      * The BSSID may be {@code null} if there is no network currently connected.
    342      * @return the BSSID, in the form of a six-byte MAC address: {@code XX:XX:XX:XX:XX:XX}
    343      */
    344     public String getBSSID() {
    345         return mBSSID;
    346     }
    347 
    348     /**
    349      * Returns the received signal strength indicator of the current 802.11
    350      * network, in dBm.
    351      *
    352      * <p>Use {@link android.net.wifi.WifiManager#calculateSignalLevel} to convert this number into
    353      * an absolute signal level which can be displayed to a user.
    354      *
    355      * @return the RSSI.
    356      */
    357     public int getRssi() {
    358         return mRssi;
    359     }
    360 
    361     /** @hide */
    362     public void setRssi(int rssi) {
    363         if (rssi < INVALID_RSSI)
    364             rssi = INVALID_RSSI;
    365         if (rssi > MAX_RSSI)
    366             rssi = MAX_RSSI;
    367         mRssi = rssi;
    368     }
    369 
    370     /**
    371      * Returns the current link speed in {@link #LINK_SPEED_UNITS}.
    372      * @return the link speed.
    373      * @see #LINK_SPEED_UNITS
    374      */
    375     public int getLinkSpeed() {
    376         return mLinkSpeed;
    377     }
    378 
    379     /** @hide */
    380     public void setLinkSpeed(int linkSpeed) {
    381         this.mLinkSpeed = linkSpeed;
    382     }
    383 
    384     /**
    385      * Returns the current frequency in {@link #FREQUENCY_UNITS}.
    386      * @return the frequency.
    387      * @see #FREQUENCY_UNITS
    388      */
    389     public int getFrequency() {
    390         return mFrequency;
    391     }
    392 
    393     /** @hide */
    394     public void setFrequency(int frequency) {
    395         this.mFrequency = frequency;
    396     }
    397 
    398     /**
    399      * @hide
    400      * TODO: makes real freq boundaries
    401      */
    402     public boolean is24GHz() {
    403         return ScanResult.is24GHz(mFrequency);
    404     }
    405 
    406     /**
    407      * @hide
    408      * TODO: makes real freq boundaries
    409      */
    410     public boolean is5GHz() {
    411         return ScanResult.is5GHz(mFrequency);
    412     }
    413 
    414     /**
    415      * Record the MAC address of the WLAN interface
    416      * @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form
    417      * @hide
    418      */
    419     public void setMacAddress(String macAddress) {
    420         this.mMacAddress = macAddress;
    421     }
    422 
    423     public String getMacAddress() {
    424         return mMacAddress;
    425     }
    426 
    427     /** {@hide} */
    428     public void setMeteredHint(boolean meteredHint) {
    429         mMeteredHint = meteredHint;
    430     }
    431 
    432     /** {@hide} */
    433     public boolean getMeteredHint() {
    434         return mMeteredHint;
    435     }
    436 
    437     /** {@hide} */
    438     public void setEphemeral(boolean ephemeral) {
    439         mEphemeral = ephemeral;
    440     }
    441 
    442     /** {@hide} */
    443     public boolean isEphemeral() {
    444         return mEphemeral;
    445     }
    446 
    447     /** @hide */
    448     public void setNetworkId(int id) {
    449         mNetworkId = id;
    450     }
    451 
    452     /**
    453      * Each configured network has a unique small integer ID, used to identify
    454      * the network when performing operations on the supplicant. This method
    455      * returns the ID for the currently connected network.
    456      * @return the network ID, or -1 if there is no currently connected network
    457      */
    458     public int getNetworkId() {
    459         return mNetworkId;
    460     }
    461 
    462     /**
    463      * Return the detailed state of the supplicant's negotiation with an
    464      * access point, in the form of a {@link SupplicantState SupplicantState} object.
    465      * @return the current {@link SupplicantState SupplicantState}
    466      */
    467     public SupplicantState getSupplicantState() {
    468         return mSupplicantState;
    469     }
    470 
    471     /** @hide */
    472     public void setSupplicantState(SupplicantState state) {
    473         mSupplicantState = state;
    474     }
    475 
    476     /** @hide */
    477     public void setInetAddress(InetAddress address) {
    478         mIpAddress = address;
    479     }
    480 
    481     public int getIpAddress() {
    482         int result = 0;
    483         if (mIpAddress instanceof Inet4Address) {
    484             result = NetworkUtils.inetAddressToInt((Inet4Address)mIpAddress);
    485         }
    486         return result;
    487     }
    488 
    489     /**
    490      * @return {@code true} if this network does not broadcast its SSID, so an
    491      * SSID-specific probe request must be used for scans.
    492      */
    493     public boolean getHiddenSSID() {
    494         if (mWifiSsid == null) return false;
    495         return mWifiSsid.isHidden();
    496     }
    497 
    498    /**
    499      * Map a supplicant state into a fine-grained network connectivity state.
    500      * @param suppState the supplicant state
    501      * @return the corresponding {@link DetailedState}
    502      */
    503     public static DetailedState getDetailedStateOf(SupplicantState suppState) {
    504         return stateMap.get(suppState);
    505     }
    506 
    507     /**
    508      * Set the <code>SupplicantState</code> from the string name
    509      * of the state.
    510      * @param stateName the name of the state, as a <code>String</code> returned
    511      * in an event sent by {@code wpa_supplicant}.
    512      */
    513     void setSupplicantState(String stateName) {
    514         mSupplicantState = valueOf(stateName);
    515     }
    516 
    517     static SupplicantState valueOf(String stateName) {
    518         if ("4WAY_HANDSHAKE".equalsIgnoreCase(stateName))
    519             return SupplicantState.FOUR_WAY_HANDSHAKE;
    520         else {
    521             try {
    522                 return SupplicantState.valueOf(stateName.toUpperCase(Locale.ROOT));
    523             } catch (IllegalArgumentException e) {
    524                 return SupplicantState.INVALID;
    525             }
    526         }
    527     }
    528 
    529     /** {@hide} */
    530     public static String removeDoubleQuotes(String string) {
    531         if (string == null) return null;
    532         final int length = string.length();
    533         if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
    534             return string.substring(1, length - 1);
    535         }
    536         return string;
    537     }
    538 
    539     @Override
    540     public String toString() {
    541         StringBuffer sb = new StringBuffer();
    542         String none = "<none>";
    543 
    544         sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid).
    545             append(", BSSID: ").append(mBSSID == null ? none : mBSSID).
    546             append(", MAC: ").append(mMacAddress == null ? none : mMacAddress).
    547             append(", Supplicant state: ").
    548             append(mSupplicantState == null ? none : mSupplicantState).
    549             append(", RSSI: ").append(mRssi).
    550             append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS).
    551             append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS).
    552             append(", Net ID: ").append(mNetworkId).
    553             append(", Metered hint: ").append(mMeteredHint).
    554             append(", score: ").append(Integer.toString(score));
    555         return sb.toString();
    556     }
    557 
    558     /** Implement the Parcelable interface {@hide} */
    559     public int describeContents() {
    560         return 0;
    561     }
    562 
    563     /** Implement the Parcelable interface {@hide} */
    564     public void writeToParcel(Parcel dest, int flags) {
    565         dest.writeInt(mNetworkId);
    566         dest.writeInt(mRssi);
    567         dest.writeInt(mLinkSpeed);
    568         dest.writeInt(mFrequency);
    569         if (mIpAddress != null) {
    570             dest.writeByte((byte)1);
    571             dest.writeByteArray(mIpAddress.getAddress());
    572         } else {
    573             dest.writeByte((byte)0);
    574         }
    575         if (mWifiSsid != null) {
    576             dest.writeInt(1);
    577             mWifiSsid.writeToParcel(dest, flags);
    578         } else {
    579             dest.writeInt(0);
    580         }
    581         dest.writeString(mBSSID);
    582         dest.writeString(mMacAddress);
    583         dest.writeInt(mMeteredHint ? 1 : 0);
    584         dest.writeInt(mEphemeral ? 1 : 0);
    585         dest.writeInt(score);
    586         dest.writeDouble(txSuccessRate);
    587         dest.writeDouble(txRetriesRate);
    588         dest.writeDouble(txBadRate);
    589         dest.writeDouble(rxSuccessRate);
    590         dest.writeInt(badRssiCount);
    591         dest.writeInt(lowRssiCount);
    592         mSupplicantState.writeToParcel(dest, flags);
    593     }
    594 
    595     /** Implement the Parcelable interface {@hide} */
    596     public static final Creator<WifiInfo> CREATOR =
    597         new Creator<WifiInfo>() {
    598             public WifiInfo createFromParcel(Parcel in) {
    599                 WifiInfo info = new WifiInfo();
    600                 info.setNetworkId(in.readInt());
    601                 info.setRssi(in.readInt());
    602                 info.setLinkSpeed(in.readInt());
    603                 info.setFrequency(in.readInt());
    604                 if (in.readByte() == 1) {
    605                     try {
    606                         info.setInetAddress(InetAddress.getByAddress(in.createByteArray()));
    607                     } catch (UnknownHostException e) {}
    608                 }
    609                 if (in.readInt() == 1) {
    610                     info.mWifiSsid = WifiSsid.CREATOR.createFromParcel(in);
    611                 }
    612                 info.mBSSID = in.readString();
    613                 info.mMacAddress = in.readString();
    614                 info.mMeteredHint = in.readInt() != 0;
    615                 info.mEphemeral = in.readInt() != 0;
    616                 info.score = in.readInt();
    617                 info.txSuccessRate = in.readDouble();
    618                 info.txRetriesRate = in.readDouble();
    619                 info.txBadRate = in.readDouble();
    620                 info.rxSuccessRate = in.readDouble();
    621                 info.badRssiCount = in.readInt();
    622                 info.lowRssiCount = in.readInt();
    623                 info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in);
    624                 return info;
    625             }
    626 
    627             public WifiInfo[] newArray(int size) {
    628                 return new WifiInfo[size];
    629             }
    630         };
    631 }
    632