Home | History | Annotate | Download | only in wifi
      1 /*
      2  * Copyright (C) 2016 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.server.wifi;
     18 
     19 import android.text.TextUtils;
     20 import android.util.Log;
     21 
     22 import java.io.FileDescriptor;
     23 import java.io.PrintWriter;
     24 
     25 /**
     26  * Provide functions for making changes to WiFi country code.
     27  * This Country Code is from MCC or phone default setting. This class sends Country Code
     28  * to driver through wpa_supplicant when WifiStateMachine marks current state as ready
     29  * using setReadyForChange(true).
     30  */
     31 public class WifiCountryCode {
     32     private static final String TAG = "WifiCountryCode";
     33     private final WifiNative mWifiNative;
     34     private boolean DBG = false;
     35     private boolean mReady = false;
     36 
     37     /** config option that indicate whether or not to reset country code to default when
     38      * cellular radio indicates country code loss
     39      */
     40     private boolean mRevertCountryCodeOnCellularLoss;
     41     private String mDefaultCountryCode = null;
     42     private String mTelephonyCountryCode = null;
     43     private String mCurrentCountryCode = null;
     44 
     45     public WifiCountryCode(
     46             WifiNative wifiNative,
     47             String oemDefaultCountryCode,
     48             boolean revertCountryCodeOnCellularLoss) {
     49 
     50         mWifiNative = wifiNative;
     51         mRevertCountryCodeOnCellularLoss = revertCountryCodeOnCellularLoss;
     52 
     53         if (!TextUtils.isEmpty(oemDefaultCountryCode)) {
     54             mDefaultCountryCode = oemDefaultCountryCode.toUpperCase();
     55         } else {
     56             if (mRevertCountryCodeOnCellularLoss) {
     57                 Log.w(TAG, "config_wifi_revert_country_code_on_cellular_loss is set, "
     58                          + "but there is no default country code.");
     59                 mRevertCountryCodeOnCellularLoss = false;
     60                 return;
     61             }
     62         }
     63 
     64         if (mRevertCountryCodeOnCellularLoss) {
     65             Log.d(TAG, "Country code will be reverted to " + mDefaultCountryCode
     66                     + " on MCC loss");
     67         }
     68     }
     69 
     70     /**
     71      * Enable verbose logging for WifiCountryCode.
     72      */
     73     public void enableVerboseLogging(int verbose) {
     74         if (verbose > 0) {
     75             DBG = true;
     76         } else {
     77             DBG = false;
     78         }
     79     }
     80 
     81     /**
     82      * This is called when airplane mode is enabled.
     83      * In this case we should invalidate all other country code except the
     84      * phone default one.
     85      */
     86     public synchronized void airplaneModeEnabled() {
     87         if (DBG) Log.d(TAG, "Airplane Mode Enabled");
     88         // Airplane mode is enabled, we need to reset the country code to phone default.
     89         // Country code will be set upon when wpa_supplicant starts next time.
     90         mTelephonyCountryCode = null;
     91     }
     92 
     93     /**
     94      * Change the state to indicates if wpa_supplicant is ready to handle country code changing
     95      * request or not.
     96      * We call native code to request country code changes only when wpa_supplicant is
     97      * started but not yet L2 connected.
     98      */
     99     public synchronized void setReadyForChange(boolean ready) {
    100         if (DBG) Log.d(TAG, "Set ready: " + ready);
    101         mReady = ready;
    102         // We are ready to set country code now.
    103         // We need to post pending country code request.
    104         if (mReady) {
    105             updateCountryCode();
    106         }
    107     }
    108 
    109     /**
    110      * Handle country code change request.
    111      * @param countryCode The country code intended to set.
    112      * This is supposed to be from Telephony service.
    113      * otherwise we think it is from other applications.
    114      * @return Returns true if the country code passed in is acceptable.
    115      */
    116     public synchronized boolean setCountryCode(String countryCode) {
    117         if (DBG) Log.d(TAG, "Receive set country code request: " + countryCode);
    118         // Empty country code.
    119         if (TextUtils.isEmpty(countryCode)) {
    120             if (mRevertCountryCodeOnCellularLoss) {
    121                 if (DBG) Log.d(TAG, "Received empty country code, reset to default country code");
    122                 mTelephonyCountryCode = null;
    123             }
    124         } else {
    125             mTelephonyCountryCode = countryCode.toUpperCase();
    126         }
    127         // If wpa_supplicant is ready we set the country code now, otherwise it will be
    128         // set once wpa_supplicant is ready.
    129         if (mReady) {
    130             updateCountryCode();
    131         }
    132         return true;
    133     }
    134 
    135     /**
    136      * Method to get the Country Code that was sent to wpa_supplicant.
    137      *
    138      * @return Returns the local copy of the Country Code that was sent to the driver upon
    139      * setReadyForChange(true).
    140      * If wpa_supplicant was never started, this may be null even if a SIM reported a valid
    141      * country code.
    142      * Returns null if no Country Code was sent to driver.
    143      */
    144     public synchronized String getCountryCodeSentToDriver() {
    145         return mCurrentCountryCode;
    146     }
    147 
    148     /**
    149      * Method to return the currently reported Country Code from the SIM or phone default setting.
    150      *
    151      * @return The currently reported Country Code from the SIM. If there is no Country Code
    152      * reported from SIM, a phone default Country Code will be returned.
    153      * Returns null when there is no Country Code available.
    154      */
    155     public synchronized String getCountryCode() {
    156         return pickCountryCode();
    157     }
    158 
    159     /**
    160      * Method to dump the current state of this WifiCounrtyCode object.
    161      */
    162     public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    163         if (mCurrentCountryCode != null) {
    164             pw.println("CountryCode sent to driver: " + mCurrentCountryCode);
    165         } else {
    166             if (pickCountryCode() != null) {
    167                 pw.println("CountryCode: " + pickCountryCode() + " was not sent to driver");
    168             } else {
    169                 pw.println("CountryCode was not initialized");
    170             }
    171         }
    172     }
    173 
    174     private void updateCountryCode() {
    175         if (DBG) Log.d(TAG, "Update country code");
    176         String country = pickCountryCode();
    177         // We do not check if the country code equals the current one.
    178         // There are two reasons:
    179         // 1. Wpa supplicant may silently modify the country code.
    180         // 2. If Wifi restarted therefoere wpa_supplicant also restarted,
    181         // the country code counld be reset to '00' by wpa_supplicant.
    182         if (country != null) {
    183             setCountryCodeNative(country);
    184         }
    185         // We do not set country code if there is no candidate. This is reasonable
    186         // because wpa_supplicant usually starts with an international safe country
    187         // code setting: '00'.
    188     }
    189 
    190     private String pickCountryCode() {
    191         if (mTelephonyCountryCode != null) {
    192             return mTelephonyCountryCode;
    193         }
    194         if (mDefaultCountryCode != null) {
    195             return mDefaultCountryCode;
    196         }
    197         // If there is no candidate country code we will return null.
    198         return null;
    199     }
    200 
    201     private boolean setCountryCodeNative(String country) {
    202         if (mWifiNative.setCountryCode(mWifiNative.getClientInterfaceName(), country)) {
    203             Log.d(TAG, "Succeeded to set country code to: " + country);
    204             mCurrentCountryCode = country;
    205             return true;
    206         }
    207         Log.d(TAG, "Failed to set country code to: " + country);
    208         return false;
    209     }
    210 }
    211 
    212