am 59c73b92
: Merge "Convert soft ap config store to state machine" into ics-mr1
* commit '59c73b92a9ef8df5d4873bc36f05b776c3a476bc': Convert soft ap config store to state machine
This commit is contained in:
@ -619,12 +619,7 @@ public class WifiService extends IWifiManager.Stub {
|
||||
*/
|
||||
public WifiConfiguration getWifiApConfiguration() {
|
||||
enforceAccessPermission();
|
||||
if (mWifiStateMachineChannel != null) {
|
||||
return mWifiStateMachine.syncGetWifiApConfiguration(mWifiStateMachineChannel);
|
||||
} else {
|
||||
Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
|
||||
return null;
|
||||
}
|
||||
return mWifiStateMachine.syncGetWifiApConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,11 +19,16 @@ package android.net.wifi;
|
||||
import android.content.Context;
|
||||
import android.net.wifi.WifiConfiguration.KeyMgmt;
|
||||
import android.os.Environment;
|
||||
import android.os.Message;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.util.AsyncChannel;
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.util.State;
|
||||
import com.android.internal.util.StateMachine;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
@ -34,16 +39,13 @@ import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
|
||||
/**
|
||||
* Provides API to the WifiStateMachine for doing read/write access
|
||||
* to soft access point configuration
|
||||
*/
|
||||
class WifiApConfigStore {
|
||||
class WifiApConfigStore extends StateMachine {
|
||||
|
||||
private static Context sContext;
|
||||
private Context mContext;
|
||||
private static final String TAG = "WifiApConfigStore";
|
||||
|
||||
private static final String AP_CONFIG_FILE = Environment.getDataDirectory() +
|
||||
@ -51,131 +53,160 @@ class WifiApConfigStore {
|
||||
|
||||
private static final int AP_CONFIG_FILE_VERSION = 1;
|
||||
|
||||
private static WifiConfiguration sApConfig = new WifiConfiguration();
|
||||
private static final Object sApConfigLock = new Object();
|
||||
private State mDefaultState = new DefaultState();
|
||||
private State mInactiveState = new InactiveState();
|
||||
private State mActiveState = new ActiveState();
|
||||
|
||||
private static FileReadWriteHandler sFileReadWriteHandler;
|
||||
private static final int READ_AP_CONFIG = 1;
|
||||
private static final int WRITE_AP_CONFIG = 2;
|
||||
private WifiConfiguration mWifiApConfig = null;
|
||||
private AsyncChannel mReplyChannel = new AsyncChannel();
|
||||
|
||||
static void initialize(Context context) {
|
||||
sContext = context;
|
||||
WifiApConfigStore(Context context, Handler target) {
|
||||
super(TAG, target.getLooper());
|
||||
|
||||
/* File operations happen on a seperate thread */
|
||||
HandlerThread configThread = new HandlerThread("WifiApConfigStore");
|
||||
configThread.start();
|
||||
sFileReadWriteHandler = new FileReadWriteHandler(configThread.getLooper());
|
||||
Message.obtain(sFileReadWriteHandler, READ_AP_CONFIG).sendToTarget();
|
||||
mContext = context;
|
||||
addState(mDefaultState);
|
||||
addState(mInactiveState, mDefaultState);
|
||||
addState(mActiveState, mDefaultState);
|
||||
|
||||
setInitialState(mInactiveState);
|
||||
}
|
||||
|
||||
|
||||
static void setApConfiguration(WifiConfiguration config) {
|
||||
synchronized (sApConfigLock) {
|
||||
sApConfig = config;
|
||||
}
|
||||
Message.obtain(sFileReadWriteHandler, WRITE_AP_CONFIG, new WifiConfiguration(config))
|
||||
.sendToTarget();
|
||||
public static WifiApConfigStore makeWifiApConfigStore(Context context, Handler target) {
|
||||
WifiApConfigStore s = new WifiApConfigStore(context, target);
|
||||
s.start();
|
||||
return s;
|
||||
}
|
||||
|
||||
static WifiConfiguration getApConfiguration() {
|
||||
synchronized (sApConfigLock) {
|
||||
return new WifiConfiguration(sApConfig);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* File read/write handler
|
||||
*/
|
||||
private static class FileReadWriteHandler extends Handler {
|
||||
|
||||
public FileReadWriteHandler(android.os.Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case WRITE_AP_CONFIG:
|
||||
writeApConfiguration((WifiConfiguration) msg.obj);
|
||||
class DefaultState extends State {
|
||||
public boolean processMessage(Message message) {
|
||||
switch (message.what) {
|
||||
case WifiStateMachine.CMD_SET_AP_CONFIG:
|
||||
case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED:
|
||||
Log.e(TAG, "Unexpected message: " + message);
|
||||
break;
|
||||
case READ_AP_CONFIG:
|
||||
readApConfiguration();
|
||||
case WifiStateMachine.CMD_REQUEST_AP_CONFIG:
|
||||
mReplyChannel.replyToMessage(message,
|
||||
WifiStateMachine.CMD_RESPONSE_AP_CONFIG, mWifiApConfig);
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Unknown command in FileReadWriteHandler: " + msg);
|
||||
Log.e(TAG, "Failed to handle " + message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeApConfiguration(final WifiConfiguration config) {
|
||||
DataOutputStream out = null;
|
||||
try {
|
||||
out = new DataOutputStream(new BufferedOutputStream(
|
||||
new FileOutputStream(AP_CONFIG_FILE)));
|
||||
|
||||
out.writeInt(AP_CONFIG_FILE_VERSION);
|
||||
out.writeUTF(config.SSID);
|
||||
int authType = config.getAuthType();
|
||||
out.writeInt(authType);
|
||||
if(authType != KeyMgmt.NONE) {
|
||||
out.writeUTF(config.preSharedKey);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Error writing hotspot configuration" + e);
|
||||
} finally {
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void readApConfiguration() {
|
||||
DataInputStream in = null;
|
||||
try {
|
||||
WifiConfiguration config = new WifiConfiguration();
|
||||
in = new DataInputStream(new BufferedInputStream(new FileInputStream(
|
||||
AP_CONFIG_FILE)));
|
||||
|
||||
int version = in.readInt();
|
||||
if (version != 1) {
|
||||
Log.e(TAG, "Bad version on hotspot configuration file, set defaults");
|
||||
setDefaultApConfiguration();
|
||||
return;
|
||||
}
|
||||
config.SSID = in.readUTF();
|
||||
int authType = in.readInt();
|
||||
config.allowedKeyManagement.set(authType);
|
||||
if (authType != KeyMgmt.NONE) {
|
||||
config.preSharedKey = in.readUTF();
|
||||
}
|
||||
synchronized (sApConfigLock) {
|
||||
sApConfig = config;
|
||||
}
|
||||
} catch (IOException ignore) {
|
||||
setDefaultApConfiguration();
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate a default WPA2 based configuration with a random password.
|
||||
We are changing the Wifi Ap configuration storage from secure settings to a
|
||||
flat file accessible only by the system. A WPA2 based default configuration
|
||||
will keep the device secure after the update */
|
||||
private static void setDefaultApConfiguration() {
|
||||
WifiConfiguration config = new WifiConfiguration();
|
||||
config.SSID = sContext.getString(R.string.wifi_tether_configure_ssid_default);
|
||||
config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
|
||||
String randomUUID = UUID.randomUUID().toString();
|
||||
//first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
|
||||
config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9,13);
|
||||
setApConfiguration(config);
|
||||
return HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
class InactiveState extends State {
|
||||
public boolean processMessage(Message message) {
|
||||
switch (message.what) {
|
||||
case WifiStateMachine.CMD_SET_AP_CONFIG:
|
||||
mWifiApConfig = (WifiConfiguration) message.obj;
|
||||
transitionTo(mActiveState);
|
||||
break;
|
||||
default:
|
||||
return NOT_HANDLED;
|
||||
}
|
||||
return HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
class ActiveState extends State {
|
||||
public void enter() {
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
writeApConfiguration(mWifiApConfig);
|
||||
sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
public boolean processMessage(Message message) {
|
||||
switch (message.what) {
|
||||
//TODO: have feedback to the user when we do this
|
||||
//to indicate the write is currently in progress
|
||||
case WifiStateMachine.CMD_SET_AP_CONFIG:
|
||||
deferMessage(message);
|
||||
break;
|
||||
case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED:
|
||||
transitionTo(mInactiveState);
|
||||
break;
|
||||
default:
|
||||
return NOT_HANDLED;
|
||||
}
|
||||
return HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
void loadApConfiguration() {
|
||||
DataInputStream in = null;
|
||||
try {
|
||||
WifiConfiguration config = new WifiConfiguration();
|
||||
in = new DataInputStream(new BufferedInputStream(new FileInputStream(
|
||||
AP_CONFIG_FILE)));
|
||||
|
||||
int version = in.readInt();
|
||||
if (version != 1) {
|
||||
Log.e(TAG, "Bad version on hotspot configuration file, set defaults");
|
||||
setDefaultApConfiguration();
|
||||
return;
|
||||
}
|
||||
config.SSID = in.readUTF();
|
||||
int authType = in.readInt();
|
||||
config.allowedKeyManagement.set(authType);
|
||||
if (authType != KeyMgmt.NONE) {
|
||||
config.preSharedKey = in.readUTF();
|
||||
}
|
||||
mWifiApConfig = config;
|
||||
} catch (IOException ignore) {
|
||||
setDefaultApConfiguration();
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Messenger getMessenger() {
|
||||
return new Messenger(getHandler());
|
||||
}
|
||||
|
||||
private void writeApConfiguration(final WifiConfiguration config) {
|
||||
DataOutputStream out = null;
|
||||
try {
|
||||
out = new DataOutputStream(new BufferedOutputStream(
|
||||
new FileOutputStream(AP_CONFIG_FILE)));
|
||||
|
||||
out.writeInt(AP_CONFIG_FILE_VERSION);
|
||||
out.writeUTF(config.SSID);
|
||||
int authType = config.getAuthType();
|
||||
out.writeInt(authType);
|
||||
if(authType != KeyMgmt.NONE) {
|
||||
out.writeUTF(config.preSharedKey);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Error writing hotspot configuration" + e);
|
||||
} finally {
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate a default WPA2 based configuration with a random password.
|
||||
We are changing the Wifi Ap configuration storage from secure settings to a
|
||||
flat file accessible only by the system. A WPA2 based default configuration
|
||||
will keep the device secure after the update */
|
||||
private void setDefaultApConfiguration() {
|
||||
WifiConfiguration config = new WifiConfiguration();
|
||||
config.SSID = mContext.getString(R.string.wifi_tether_configure_ssid_default);
|
||||
config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
|
||||
String randomUUID = UUID.randomUUID().toString();
|
||||
//first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
|
||||
config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9,13);
|
||||
sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG, config);
|
||||
}
|
||||
}
|
||||
|
@ -184,6 +184,7 @@ public class WifiStateMachine extends StateMachine {
|
||||
private WifiP2pManager mWifiP2pManager;
|
||||
//Used to initiate a connection with WifiP2pService
|
||||
private AsyncChannel mWifiP2pChannel = new AsyncChannel();
|
||||
private AsyncChannel mWifiApConfigChannel = new AsyncChannel();
|
||||
|
||||
// Event log tags (must be in sync with event-log-tags)
|
||||
private static final int EVENTLOG_WIFI_STATE_CHANGED = 50021;
|
||||
@ -233,12 +234,16 @@ public class WifiStateMachine extends StateMachine {
|
||||
static final int CMD_STOP_AP = BASE + 24;
|
||||
/* Set the soft access point configuration */
|
||||
static final int CMD_SET_AP_CONFIG = BASE + 25;
|
||||
/* Get the soft access point configuration */
|
||||
static final int CMD_GET_AP_CONFIG = BASE + 26;
|
||||
/* Soft access point configuration set completed */
|
||||
static final int CMD_SET_AP_CONFIG_COMPLETED = BASE + 26;
|
||||
/* Request the soft access point configuration */
|
||||
static final int CMD_REQUEST_AP_CONFIG = BASE + 27;
|
||||
/* Response to access point configuration request */
|
||||
static final int CMD_RESPONSE_AP_CONFIG = BASE + 28;
|
||||
/* Set configuration on tether interface */
|
||||
static final int CMD_TETHER_INTERFACE = BASE + 27;
|
||||
static final int CMD_TETHER_INTERFACE = BASE + 29;
|
||||
|
||||
static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 28;
|
||||
static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 30;
|
||||
|
||||
/* Supplicant commands */
|
||||
/* Is supplicant alive ? */
|
||||
@ -530,6 +535,11 @@ public class WifiStateMachine extends StateMachine {
|
||||
mWpsStateMachine = new WpsStateMachine(context, this, getHandler());
|
||||
mLinkProperties = new LinkProperties();
|
||||
|
||||
WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore(
|
||||
context, getHandler());
|
||||
wifiApConfigStore.loadApConfiguration();
|
||||
mWifiApConfigChannel.connectSync(mContext, getHandler(), wifiApConfigStore.getMessenger());
|
||||
|
||||
mNetworkInfo.setIsAvailable(false);
|
||||
mLinkProperties.clear();
|
||||
mLastBssid = null;
|
||||
@ -659,11 +669,11 @@ public class WifiStateMachine extends StateMachine {
|
||||
}
|
||||
|
||||
public void setWifiApConfiguration(WifiConfiguration config) {
|
||||
sendMessage(obtainMessage(CMD_SET_AP_CONFIG, config));
|
||||
mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
|
||||
}
|
||||
|
||||
public WifiConfiguration syncGetWifiApConfiguration(AsyncChannel channel) {
|
||||
Message resultMsg = channel.sendMessageSynchronously(CMD_GET_AP_CONFIG);
|
||||
public WifiConfiguration syncGetWifiApConfiguration() {
|
||||
Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG);
|
||||
WifiConfiguration ret = (WifiConfiguration) resultMsg.obj;
|
||||
resultMsg.recycle();
|
||||
return ret;
|
||||
@ -1714,25 +1724,27 @@ public class WifiStateMachine extends StateMachine {
|
||||
* TODO: Add control channel setup through hostapd that allows changing config
|
||||
* on a running daemon
|
||||
*/
|
||||
private boolean startSoftApWithConfig(WifiConfiguration config) {
|
||||
if (config == null) {
|
||||
config = WifiApConfigStore.getApConfiguration();
|
||||
} else {
|
||||
WifiApConfigStore.setApConfiguration(config);
|
||||
}
|
||||
try {
|
||||
mNwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
|
||||
} catch (Exception e) {
|
||||
loge("Exception in softap start " + e);
|
||||
try {
|
||||
mNwService.stopAccessPoint(mInterfaceName);
|
||||
mNwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
|
||||
} catch (Exception e1) {
|
||||
loge("Exception in softap re-start " + e1);
|
||||
return false;
|
||||
private void startSoftApWithConfig(final WifiConfiguration config) {
|
||||
// start hostapd on a seperate thread
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
mNwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
|
||||
} catch (Exception e) {
|
||||
loge("Exception in softap start " + e);
|
||||
try {
|
||||
mNwService.stopAccessPoint(mInterfaceName);
|
||||
mNwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
|
||||
} catch (Exception e1) {
|
||||
loge("Exception in softap re-start " + e1);
|
||||
sendMessage(CMD_START_AP_FAILURE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (DBG) log("Soft AP start successful");
|
||||
sendMessage(CMD_START_AP_SUCCESS);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}).start();
|
||||
}
|
||||
|
||||
/********************************************************
|
||||
@ -1775,13 +1787,6 @@ public class WifiStateMachine extends StateMachine {
|
||||
case CMD_ENABLE_BACKGROUND_SCAN:
|
||||
mEnableBackgroundScan = (message.arg1 == 1);
|
||||
break;
|
||||
case CMD_SET_AP_CONFIG:
|
||||
WifiApConfigStore.setApConfiguration((WifiConfiguration) message.obj);
|
||||
break;
|
||||
case CMD_GET_AP_CONFIG:
|
||||
WifiConfiguration config = WifiApConfigStore.getApConfiguration();
|
||||
mReplyChannel.replyToMessage(message, message.what, config);
|
||||
break;
|
||||
/* Discard */
|
||||
case CMD_LOAD_DRIVER:
|
||||
case CMD_UNLOAD_DRIVER:
|
||||
@ -1823,6 +1828,11 @@ public class WifiStateMachine extends StateMachine {
|
||||
case CMD_ENABLE_ALL_NETWORKS:
|
||||
case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
|
||||
case DhcpStateMachine.CMD_POST_DHCP_ACTION:
|
||||
/* Handled by WifiApConfigStore */
|
||||
case CMD_SET_AP_CONFIG:
|
||||
case CMD_SET_AP_CONFIG_COMPLETED:
|
||||
case CMD_REQUEST_AP_CONFIG:
|
||||
case CMD_RESPONSE_AP_CONFIG:
|
||||
break;
|
||||
case WifiMonitor.DRIVER_HUNG_EVENT:
|
||||
setWifiEnabled(false);
|
||||
@ -1856,8 +1866,6 @@ public class WifiStateMachine extends StateMachine {
|
||||
// 50021 wifi_state_changed (custom|1|5)
|
||||
EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
|
||||
|
||||
WifiApConfigStore.initialize(mContext);
|
||||
|
||||
if (WifiNative.isDriverLoaded()) {
|
||||
transitionTo(mDriverLoadedState);
|
||||
}
|
||||
@ -3243,21 +3251,19 @@ public class WifiStateMachine extends StateMachine {
|
||||
if (DBG) log(getName() + "\n");
|
||||
EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
|
||||
|
||||
final Message message = Message.obtain(getCurrentMessage());
|
||||
final WifiConfiguration config = (WifiConfiguration) message.obj;
|
||||
final Message message = getCurrentMessage();
|
||||
if (message.what == CMD_START_AP) {
|
||||
final WifiConfiguration config = (WifiConfiguration) message.obj;
|
||||
|
||||
// start hostapd on a seperate thread
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
if (startSoftApWithConfig(config)) {
|
||||
if (DBG) log("Soft AP start successful");
|
||||
sendMessage(CMD_START_AP_SUCCESS);
|
||||
} else {
|
||||
loge("Soft AP start failed");
|
||||
sendMessage(CMD_START_AP_FAILURE);
|
||||
}
|
||||
if (config == null) {
|
||||
mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG);
|
||||
} else {
|
||||
mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
|
||||
startSoftApWithConfig(config);
|
||||
}
|
||||
}).start();
|
||||
} else {
|
||||
throw new RuntimeException("Illegal transition to SoftApStartingState: " + message);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public boolean processMessage(Message message) {
|
||||
@ -3282,6 +3288,15 @@ public class WifiStateMachine extends StateMachine {
|
||||
case WifiP2pService.P2P_ENABLE_PENDING:
|
||||
deferMessage(message);
|
||||
break;
|
||||
case WifiStateMachine.CMD_RESPONSE_AP_CONFIG:
|
||||
WifiConfiguration config = (WifiConfiguration) message.obj;
|
||||
if (config != null) {
|
||||
startSoftApWithConfig(config);
|
||||
} else {
|
||||
loge("Softap config is null!");
|
||||
sendMessage(CMD_START_AP_FAILURE);
|
||||
}
|
||||
break;
|
||||
case CMD_START_AP_SUCCESS:
|
||||
setWifiApState(WIFI_AP_STATE_ENABLED);
|
||||
transitionTo(mSoftApStartedState);
|
||||
|
Reference in New Issue
Block a user