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