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