From 9ab518ad793385f8405edf19363fe825fb64f5f8 Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Fri, 12 Mar 2010 15:48:17 -0800 Subject: [PATCH] softAp framework changes Remove AP persist settings Add new netd interface Handle errors Handle AP config change Bug: 2413908 Change-Id: I31a1221ef5479da8d4a2620f0f0ee0b62539bc69 --- .../android/os/INetworkManagementService.aidl | 3 +- core/java/android/provider/Settings.java | 21 +++ core/res/res/values/strings.xml | 2 + .../server/NetworkManagementService.java | 35 +++- .../java/com/android/server/WifiService.java | 153 +++++++++++------- wifi/java/android/net/wifi/IWifiManager.aidl | 2 + wifi/java/android/net/wifi/WifiManager.java | 14 ++ 7 files changed, 168 insertions(+), 62 deletions(-) diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index d1d8b0a0ee2a9..afe419115cd65 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -19,6 +19,7 @@ package android.os; import android.net.InterfaceConfiguration; import android.net.INetworkManagementEventObserver; +import android.net.wifi.WifiConfiguration; /** * @hide @@ -166,7 +167,7 @@ interface INetworkManagementService /** * Start Wifi Access Point */ - void startAccessPoint(); + void startAccessPoint(in WifiConfiguration wifiConfig, String intf); /** * Stop Wifi Access Point diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 503d8b8da1dd5..66f340e32ae60 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -2501,6 +2501,27 @@ public final class Settings { */ public static final String WIFI_AP_ON = "wifi_ap_on"; + /** + * AP SSID + * + * @hide + */ + public static final String WIFI_AP_SSID = "wifi_ap_ssid"; + + /** + * AP security + * + * @hide + */ + public static final String WIFI_AP_SECURITY = "wifi_ap_security"; + + /** + * AP passphrase + * + * @hide + */ + public static final String WIFI_AP_PASSWD = "wifi_ap_passwd"; + /** * The acceptable packet loss percentage (range 0 - 100) before trying * another AP on the same network. diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 584fe25106716..bf7425f1cf33d 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2013,6 +2013,8 @@ Open Wi-Fi network available Open Wi-Fi networks available + + AndroidAP Insert character diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index aa9ced8127abc..b114ca2c5820b 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -26,10 +26,13 @@ import android.content.pm.PackageManager; import android.net.Uri; import android.net.InterfaceConfiguration; import android.net.INetworkManagementEventObserver; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiConfiguration.KeyMgmt; import android.os.INetworkManagementService; import android.os.Handler; import android.os.SystemProperties; import android.text.TextUtils; +import android.util.Log; import android.util.Slog; import java.util.ArrayList; import java.util.StringTokenizer; @@ -457,14 +460,38 @@ class NetworkManagementService extends INetworkManagementService.Stub { throw new IllegalStateException("Got an empty response"); } - public void startAccessPoint() + public void startAccessPoint(WifiConfiguration wifiConfig, String intf) throws IllegalStateException { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService"); - mConnector.doCommand(String.format("softap set")); - mConnector.doCommand(String.format("softap start")); + mConnector.doCommand(String.format("softap stop " + intf)); + mConnector.doCommand(String.format("softap fwreload " + intf + " AP")); + mConnector.doCommand(String.format("softap start " + intf)); + if (wifiConfig == null) { + mConnector.doCommand(String.format("softap set " + intf + " wl0.1")); + } else { + /** + * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8] + * argv1 - wlan interface + * argv2 - softap interface + * argv3 - SSID + * argv4 - Security + * argv5 - Key + * argv6 - Channel + * argv7 - Preamble + * argv8 - Max SCB + * + * TODO: get a configurable softap interface from driver + */ + String str = String.format("softap set " + intf + " wl0.1 %s %s %s", wifiConfig.SSID, + wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ? + "wpa2-psk" : "open", + wifiConfig.preSharedKey); + mConnector.doCommand(str); + } + mConnector.doCommand(String.format("softap startap")); } public void stopAccessPoint() throws IllegalStateException { @@ -472,7 +499,7 @@ class NetworkManagementService extends INetworkManagementService.Stub { android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService"); - mConnector.doCommand("softap stop"); + mConnector.doCommand("softap stopap"); } } diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 599eec5c30f4d..4eb529c48a7ed 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -46,6 +46,7 @@ import android.net.wifi.WifiStateTracker; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.net.wifi.SupplicantState; +import android.net.wifi.WifiConfiguration.KeyMgmt; import android.net.ConnectivityManager; import android.net.InterfaceConfiguration; import android.net.NetworkStateTracker; @@ -81,6 +82,7 @@ import java.net.UnknownHostException; import com.android.internal.app.IBatteryStats; import android.app.backup.IBackupManager; import com.android.server.am.BatteryStatsService; +import com.android.internal.R; /** * WifiService handles remote WiFi operation requests by implementing @@ -105,6 +107,8 @@ public class WifiService extends IWifiManager.Stub { private boolean mDeviceIdle; private int mPluggedType; + private enum DriverAction {DRIVER_UNLOAD, NO_DRIVER_UNLOAD}; + // true if the user enabled Wifi while in airplane mode private boolean mAirplaneModeOverwridden; @@ -271,11 +275,9 @@ public class WifiService extends IWifiManager.Stub { */ public void startWifi() { boolean wifiEnabled = getPersistedWifiEnabled(); - boolean wifiAPEnabled = wifiEnabled ? false : getPersistedWifiApEnabled(); Slog.i(TAG, "WifiService starting up with Wi-Fi " + (wifiEnabled ? "enabled" : "disabled")); setWifiEnabledBlocking(wifiEnabled, false, Process.myUid()); - setWifiApEnabledBlocking(wifiAPEnabled, true, Process.myUid(), null); } private void updateTetherState(ArrayList available, ArrayList tethered) { @@ -297,28 +299,22 @@ public class WifiService extends IWifiManager.Stub { try { ifcg = service.getInterfaceConfig(intf); if (ifcg != null) { - /* IP/netmask: 169.254.2.1/255.255.255.0 */ - ifcg.ipAddr = (169 << 24) + (254 << 16) + (2 << 8) + 1; + /* IP/netmask: 169.254.2.2/255.255.255.0 */ + ifcg.ipAddr = (169 << 24) + (254 << 16) + (2 << 8) + 2; ifcg.netmask = (255 << 24) + (255 << 16) + (255 << 8) + 0; ifcg.interfaceFlags = "up"; service.setInterfaceConfig(intf, ifcg); } } catch (Exception e) { - /** - * TODO: Add broadcast to indicate tether failed - */ Slog.e(TAG, "Error configuring interface " + intf + ", :" + e); + setWifiApEnabledState(WIFI_AP_STATE_FAILED, 0, DriverAction.DRIVER_UNLOAD); return; } - /** - * TODO: Add broadcast to indicate tether failed - */ - if(mCm.tether(intf) == ConnectivityManager.TETHER_ERROR_NO_ERROR) { - Slog.d(TAG, "Tethered "+intf); - } else { + if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { Slog.e(TAG, "Error tethering "+intf); + setWifiApEnabledState(WIFI_AP_STATE_FAILED, 0, DriverAction.DRIVER_UNLOAD); } break; } @@ -434,7 +430,7 @@ public class WifiService extends IWifiManager.Stub { setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid); if ((mWifiApState == WIFI_AP_STATE_ENABLED) && enable) { - setWifiApEnabledBlocking(false, true, Process.myUid(), null); + setWifiApEnabledBlocking(false, Process.myUid(), null); } if (enable) { @@ -581,21 +577,6 @@ public class WifiService extends IWifiManager.Stub { return mWifiStateTracker.reassociate(); } - private boolean getPersistedWifiApEnabled() { - final ContentResolver cr = mContext.getContentResolver(); - try { - return Settings.Secure.getInt(cr, Settings.Secure.WIFI_AP_ON) == 1; - } catch (Settings.SettingNotFoundException e) { - Settings.Secure.putInt(cr, Settings.Secure.WIFI_AP_ON, 0); - return false; - } - } - - private void persistWifiApEnabled(boolean enabled) { - final ContentResolver cr = mContext.getContentResolver(); - Settings.Secure.putInt(cr, Settings.Secure.WIFI_AP_ON, enabled ? 1 : 0); - } - /** * see {@link android.net.wifi.WifiManager#startAccessPoint(WifiConfiguration)} * @param wifiConfig SSID, security and channel details as @@ -621,46 +602,101 @@ public class WifiService extends IWifiManager.Stub { return true; } + public WifiConfiguration getWifiApConfiguration() { + final ContentResolver cr = mContext.getContentResolver(); + WifiConfiguration wifiConfig = new WifiConfiguration(); + int authType; + try { + wifiConfig.SSID = Settings.Secure.getString(cr, Settings.Secure.WIFI_AP_SSID); + if (wifiConfig.SSID == null) + return null; + authType = Settings.Secure.getInt(cr, Settings.Secure.WIFI_AP_SECURITY); + wifiConfig.allowedKeyManagement.set(authType); + wifiConfig.preSharedKey = Settings.Secure.getString(cr, Settings.Secure.WIFI_AP_PASSWD); + return wifiConfig; + } catch (Settings.SettingNotFoundException e) { + Slog.e(TAG,"AP settings not found, returning"); + return null; + } + } + + private void persistApConfiguration(WifiConfiguration wifiConfig) { + final ContentResolver cr = mContext.getContentResolver(); + boolean isWpa; + if (wifiConfig == null) + return; + Settings.Secure.putString(cr, Settings.Secure.WIFI_AP_SSID, wifiConfig.SSID); + isWpa = wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK); + Settings.Secure.putInt(cr, + Settings.Secure.WIFI_AP_SECURITY, + isWpa ? KeyMgmt.WPA_PSK : KeyMgmt.NONE); + if (isWpa) + Settings.Secure.putString(cr, Settings.Secure.WIFI_AP_PASSWD, wifiConfig.preSharedKey); + } + /** * Enables/disables Wi-Fi AP synchronously. The driver is loaded * and soft access point configured as a single operation. * @param enable {@code true} to turn Wi-Fi on, {@code false} to turn it off. - * @param persist {@code true} if the setting should be persisted. * @param uid The UID of the process making the request. - * @param config The WifiConfiguration for AP + * @param wifiConfig The WifiConfiguration for AP * @return {@code true} if the operation succeeds (or if the existing state * is the same as the requested state) */ - /** - * TODO: persist needs to go away in WifiService - * This will affect all persist related functions - * for Access Point - */ private boolean setWifiApEnabledBlocking(boolean enable, - boolean persist, int uid, WifiConfiguration wifiConfig) { + int uid, WifiConfiguration wifiConfig) { final int eventualWifiApState = enable ? WIFI_AP_STATE_ENABLED : WIFI_AP_STATE_DISABLED; if (mWifiApState == eventualWifiApState) { - return true; + /* Configuration changed on a running access point */ + if(enable && (wifiConfig != null)) { + try { + persistApConfiguration(wifiConfig); + nwService.stopAccessPoint(); + nwService.startAccessPoint(wifiConfig, mWifiStateTracker.getInterfaceName()); + return true; + } catch(Exception e) { + Slog.e(TAG, "Exception in nwService during AP restart"); + setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.DRIVER_UNLOAD); + return false; + } + } else { + return true; + } } - setWifiApEnabledState(enable ? WIFI_AP_STATE_ENABLING : WIFI_AP_STATE_DISABLING, uid); - - if (enable && (mWifiStateTracker.getWifiState() == WIFI_STATE_ENABLED)) { - setWifiEnabledBlocking(false, true, Process.myUid()); - } + setWifiApEnabledState(enable ? WIFI_AP_STATE_ENABLING : + WIFI_AP_STATE_DISABLING, uid, DriverAction.NO_DRIVER_UNLOAD); if (enable) { + + /** + * Disable client mode for starting AP + */ + if (mWifiStateTracker.getWifiState() == WIFI_STATE_ENABLED) { + setWifiEnabledBlocking(false, true, Process.myUid()); + } + + /* Use default config if there is no existing config */ + if (wifiConfig == null && ((wifiConfig = getWifiApConfiguration()) == null)) { + wifiConfig = new WifiConfiguration(); + wifiConfig.SSID = mContext.getString(R.string.wifi_tether_configure_ssid_default); + wifiConfig.allowedKeyManagement.set(KeyMgmt.NONE); + } + persistApConfiguration(wifiConfig); + if (!mWifiStateTracker.loadDriver()) { Slog.e(TAG, "Failed to load Wi-Fi driver for AP mode"); - setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid); + setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.NO_DRIVER_UNLOAD); return false; } try { - nwService.startAccessPoint(); + nwService.startAccessPoint(wifiConfig, mWifiStateTracker.getInterfaceName()); } catch(Exception e) { Slog.e(TAG, "Exception in startAccessPoint()"); + setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.DRIVER_UNLOAD); + return false; } } else { @@ -669,20 +705,18 @@ public class WifiService extends IWifiManager.Stub { nwService.stopAccessPoint(); } catch(Exception e) { Slog.e(TAG, "Exception in stopAccessPoint()"); + setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.DRIVER_UNLOAD); + return false; } if (!mWifiStateTracker.unloadDriver()) { Slog.e(TAG, "Failed to unload Wi-Fi driver for AP mode"); - setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid); + setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.NO_DRIVER_UNLOAD); return false; } } - // Success! - if (persist) { - persistWifiApEnabled(enable); - } - setWifiApEnabledState(eventualWifiApState, uid); + setWifiApEnabledState(eventualWifiApState, uid, DriverAction.NO_DRIVER_UNLOAD); return true; } @@ -699,9 +733,16 @@ public class WifiService extends IWifiManager.Stub { return mWifiApState; } - private void setWifiApEnabledState(int wifiAPState, int uid) { + private void setWifiApEnabledState(int wifiAPState, int uid, DriverAction flag) { final int previousWifiApState = mWifiApState; + /** + * Unload the driver if going to a failed state + */ + if ((mWifiApState == WIFI_AP_STATE_FAILED) && (flag == DriverAction.DRIVER_UNLOAD)) { + mWifiStateTracker.unloadDriver(); + } + long ident = Binder.clearCallingIdentity(); try { if (wifiAPState == WIFI_AP_STATE_ENABLED) { @@ -1694,7 +1735,7 @@ public class WifiService extends IWifiManager.Stub { private void sendAccessPointMessage(boolean enable, WifiConfiguration wifiConfig, int uid) { Message.obtain(mWifiHandler, (enable ? MESSAGE_START_ACCESS_POINT : MESSAGE_STOP_ACCESS_POINT), - 0, uid, wifiConfig).sendToTarget(); + uid, 0, wifiConfig).sendToTarget(); } private void updateWifiState() { @@ -1841,15 +1882,13 @@ public class WifiService extends IWifiManager.Stub { case MESSAGE_START_ACCESS_POINT: setWifiApEnabledBlocking(true, - msg.arg1 == 1, - msg.arg2, + msg.arg1, (WifiConfiguration) msg.obj); break; case MESSAGE_STOP_ACCESS_POINT: setWifiApEnabledBlocking(false, - msg.arg1 == 1, - msg.arg2, + msg.arg1, (WifiConfiguration) msg.obj); sWakeLock.release(); break; diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index d833e33760f8e..5fd44b1df6c88 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -81,5 +81,7 @@ interface IWifiManager boolean setWifiApEnabled(in WifiConfiguration wifiConfig, boolean enable); int getWifiApEnabledState(); + + WifiConfiguration getWifiApConfiguration(); } diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 9ef8ba158baec..970d5fc18f250 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -809,6 +809,20 @@ public class WifiManager { return getWifiApState() == WIFI_AP_STATE_ENABLED; } + /** + * Gets the Wi-Fi AP Configuration. + * @return AP details in WifiConfiguration + * + * @hide Dont open yet + */ + public WifiConfiguration getWifiApConfiguration() { + try { + return mService.getWifiApConfiguration(); + } catch (RemoteException e) { + return null; + } + } + /** * Allows an application to keep the Wi-Fi radio awake. * Normally the Wi-Fi radio may turn off when the user has not used the device in a while.