summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/net/DhcpStateMachine.java353
-rw-r--r--core/java/android/net/NetworkUtils.java10
-rw-r--r--core/jni/android_net_NetUtils.cpp35
-rw-r--r--wifi/java/android/net/wifi/WifiStateMachine.java278
4 files changed, 545 insertions, 131 deletions
diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java
new file mode 100644
index 0000000..f5cf14b
--- /dev/null
+++ b/core/java/android/net/DhcpStateMachine.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import com.android.internal.util.Protocol;
+import com.android.internal.util.HierarchicalState;
+import com.android.internal.util.HierarchicalStateMachine;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.DhcpInfoInternal;
+import android.net.NetworkUtils;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.util.Log;
+
+/**
+ * StateMachine that interacts with the native DHCP client and can talk to
+ * a controller that also needs to be a StateMachine
+ *
+ * The Dhcp state machine provides the following features:
+ * - Wakeup and renewal using the native DHCP client (which will not renew
+ * on its own when the device is in suspend state and this can lead to device
+ * holding IP address beyond expiry)
+ * - A notification right before DHCP request or renewal is started. This
+ * can be used for any additional setup before DHCP. For example, wifi sets
+ * BT-Wifi coex settings right before DHCP is initiated
+ *
+ * @hide
+ */
+public class DhcpStateMachine extends HierarchicalStateMachine {
+
+ private static final String TAG = "DhcpStateMachine";
+ private static final boolean DBG = false;
+
+
+ /* A StateMachine that controls the DhcpStateMachine */
+ private HierarchicalStateMachine mController;
+
+ private Context mContext;
+ private BroadcastReceiver mBroadcastReceiver;
+ private AlarmManager mAlarmManager;
+ private PendingIntent mDhcpRenewalIntent;
+ private PowerManager.WakeLock mDhcpRenewWakeLock;
+ private static final String WAKELOCK_TAG = "DHCP";
+
+ private static final int DHCP_RENEW = 0;
+ private static final String ACTION_DHCP_RENEW = "android.net.wifi.DHCP_RENEW";
+
+ private enum DhcpAction {
+ START,
+ RENEW
+ };
+
+ private String mInterfaceName;
+ private boolean mRegisteredForPreDhcpNotification = false;
+
+ private static final int BASE = Protocol.BASE_DHCP;
+
+ /* Commands from controller to start/stop DHCP */
+ public static final int CMD_START_DHCP = BASE + 1;
+ public static final int CMD_STOP_DHCP = BASE + 2;
+ public static final int CMD_RENEW_DHCP = BASE + 3;
+
+ /* Notification from DHCP state machine prior to DHCP discovery/renewal */
+ public static final int CMD_PRE_DHCP_ACTION = BASE + 4;
+ /* Notification from DHCP state machine post DHCP discovery/renewal. Indicates
+ * success/failure */
+ public static final int CMD_POST_DHCP_ACTION = BASE + 5;
+
+ /* Command from controller to indicate DHCP discovery/renewal can continue
+ * after pre DHCP action is complete */
+ public static final int CMD_PRE_DHCP_ACTION_COMPLETE = BASE + 6;
+
+ /* Message.arg1 arguments to CMD_POST_DHCP notification */
+ public static final int DHCP_SUCCESS = 1;
+ public static final int DHCP_FAILURE = 2;
+
+ private HierarchicalState mDefaultState = new DefaultState();
+ private HierarchicalState mStoppedState = new StoppedState();
+ private HierarchicalState mWaitBeforeStartState = new WaitBeforeStartState();
+ private HierarchicalState mRunningState = new RunningState();
+ private HierarchicalState mWaitBeforeRenewalState = new WaitBeforeRenewalState();
+
+ private DhcpStateMachine(Context context, HierarchicalStateMachine controller, String intf) {
+ super(TAG);
+
+ mContext = context;
+ mController = controller;
+ mInterfaceName = intf;
+
+ mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+ Intent dhcpRenewalIntent = new Intent(ACTION_DHCP_RENEW, null);
+ mDhcpRenewalIntent = PendingIntent.getBroadcast(mContext, DHCP_RENEW, dhcpRenewalIntent, 0);
+
+ PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+ mDhcpRenewWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
+
+ mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ //DHCP renew
+ if (DBG) Log.d(TAG, "Sending a DHCP renewal " + this);
+ //acquire a 40s wakelock to finish DHCP renewal
+ mDhcpRenewWakeLock.acquire(40000);
+ sendMessage(CMD_RENEW_DHCP);
+ }
+ };
+ mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ACTION_DHCP_RENEW));
+
+ addState(mDefaultState);
+ addState(mStoppedState, mDefaultState);
+ addState(mWaitBeforeStartState, mDefaultState);
+ addState(mRunningState, mDefaultState);
+ addState(mWaitBeforeRenewalState, mDefaultState);
+
+ setInitialState(mStoppedState);
+ }
+
+ public static DhcpStateMachine makeDhcpStateMachine(Context context, HierarchicalStateMachine controller,
+ String intf) {
+ DhcpStateMachine dsm = new DhcpStateMachine(context, controller, intf);
+ dsm.start();
+ return dsm;
+ }
+
+ /**
+ * This sends a notification right before DHCP request/renewal so that the
+ * controller can do certain actions before DHCP packets are sent out.
+ * When the controller is ready, it sends a CMD_PRE_DHCP_ACTION_COMPLETE message
+ * to indicate DHCP can continue
+ *
+ * This is used by Wifi at this time for the purpose of doing BT-Wifi coex
+ * handling during Dhcp
+ */
+ public void registerForPreDhcpNotification() {
+ mRegisteredForPreDhcpNotification = true;
+ }
+
+ class DefaultState extends HierarchicalState {
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_RENEW_DHCP:
+ Log.e(TAG, "Error! Failed to handle a DHCP renewal on " + mInterfaceName);
+ break;
+ case HSM_QUIT_CMD:
+ mContext.unregisterReceiver(mBroadcastReceiver);
+ //let parent kill the state machine
+ return NOT_HANDLED;
+ default:
+ Log.e(TAG, "Error! unhandled message " + message);
+ break;
+ }
+ return HANDLED;
+ }
+ }
+
+
+ class StoppedState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ boolean retValue = HANDLED;
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_START_DHCP:
+ if (mRegisteredForPreDhcpNotification) {
+ /* Notify controller before starting DHCP */
+ mController.sendMessage(CMD_PRE_DHCP_ACTION);
+ transitionTo(mWaitBeforeStartState);
+ } else {
+ if (runDhcp(DhcpAction.START)) {
+ transitionTo(mRunningState);
+ }
+ }
+ break;
+ case CMD_STOP_DHCP:
+ //ignore
+ break;
+ default:
+ retValue = NOT_HANDLED;
+ break;
+ }
+ return retValue;
+ }
+ }
+
+ class WaitBeforeStartState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ boolean retValue = HANDLED;
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_PRE_DHCP_ACTION_COMPLETE:
+ if (runDhcp(DhcpAction.START)) {
+ transitionTo(mRunningState);
+ } else {
+ transitionTo(mStoppedState);
+ }
+ break;
+ case CMD_STOP_DHCP:
+ transitionTo(mStoppedState);
+ break;
+ case CMD_START_DHCP:
+ //ignore
+ break;
+ default:
+ retValue = NOT_HANDLED;
+ break;
+ }
+ return retValue;
+ }
+ }
+
+ class RunningState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ boolean retValue = HANDLED;
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_STOP_DHCP:
+ mAlarmManager.cancel(mDhcpRenewalIntent);
+ if (!NetworkUtils.stopDhcp(mInterfaceName)) {
+ Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName);
+ }
+ transitionTo(mStoppedState);
+ break;
+ case CMD_RENEW_DHCP:
+ if (mRegisteredForPreDhcpNotification) {
+ /* Notify controller before starting DHCP */
+ mController.sendMessage(CMD_PRE_DHCP_ACTION);
+ transitionTo(mWaitBeforeRenewalState);
+ } else {
+ if (!runDhcp(DhcpAction.RENEW)) {
+ transitionTo(mStoppedState);
+ }
+ }
+ break;
+ case CMD_START_DHCP:
+ //ignore
+ break;
+ default:
+ retValue = NOT_HANDLED;
+ }
+ return retValue;
+ }
+ }
+
+ class WaitBeforeRenewalState extends HierarchicalState {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ boolean retValue = HANDLED;
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_STOP_DHCP:
+ mAlarmManager.cancel(mDhcpRenewalIntent);
+ if (!NetworkUtils.stopDhcp(mInterfaceName)) {
+ Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName);
+ }
+ transitionTo(mStoppedState);
+ break;
+ case CMD_PRE_DHCP_ACTION_COMPLETE:
+ if (runDhcp(DhcpAction.RENEW)) {
+ transitionTo(mRunningState);
+ } else {
+ transitionTo(mStoppedState);
+ }
+ break;
+ case CMD_START_DHCP:
+ //ignore
+ break;
+ default:
+ retValue = NOT_HANDLED;
+ break;
+ }
+ return retValue;
+ }
+ }
+
+ private boolean runDhcp(DhcpAction dhcpAction) {
+ boolean success = false;
+ DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
+
+ if (dhcpAction == DhcpAction.START) {
+ Log.d(TAG, "DHCP request on " + mInterfaceName);
+ success = NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal);
+ } else if (dhcpAction == DhcpAction.RENEW) {
+ Log.d(TAG, "DHCP renewal on " + mInterfaceName);
+ success = NetworkUtils.runDhcpRenew(mInterfaceName, dhcpInfoInternal);
+ }
+
+ if (success) {
+ Log.d(TAG, "DHCP succeeded on " + mInterfaceName);
+ //Do it a bit earlier than half the lease duration time
+ //to beat the native DHCP client and avoid extra packets
+ //48% for one hour lease time = 29 minutes
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() +
+ dhcpInfoInternal.leaseDuration * 480, //in milliseconds
+ mDhcpRenewalIntent);
+
+ mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpInfoInternal)
+ .sendToTarget();
+ } else {
+ Log.d(TAG, "DHCP failed on " + mInterfaceName + ": " +
+ NetworkUtils.getDhcpError());
+ NetworkUtils.stopDhcp(mInterfaceName);
+ mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0)
+ .sendToTarget();
+ }
+ return success;
+ }
+}
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index b3f3988..823d10f 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -80,6 +80,16 @@ public class NetworkUtils {
public native static boolean runDhcp(String interfaceName, DhcpInfoInternal ipInfo);
/**
+ * Initiate renewal on the Dhcp client daemon. This call blocks until it obtains
+ * a result (either success or failure) from the daemon.
+ * @param interfaceName the name of the interface to configure
+ * @param ipInfo if the request succeeds, this object is filled in with
+ * the IP address information.
+ * @return {@code true} for success, {@code false} for failure
+ */
+ public native static boolean runDhcpRenew(String interfaceName, DhcpInfoInternal ipInfo);
+
+ /**
* Shut down the DHCP client daemon.
* @param interfaceName the name of the interface for which the daemon
* should be stopped
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 3adf770..4becad7 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -40,6 +40,16 @@ int dhcp_do_request(const char *ifname,
const char *dns2,
const char *server,
uint32_t *lease);
+
+int dhcp_do_request_renew(const char *ifname,
+ const char *ipaddr,
+ const char *gateway,
+ uint32_t *prefixLength,
+ const char *dns1,
+ const char *dns2,
+ const char *server,
+ uint32_t *lease);
+
int dhcp_stop(const char *ifname);
int dhcp_release_lease(const char *ifname);
char *dhcp_get_errmsg();
@@ -146,7 +156,8 @@ static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz, jstri
return (jint)result;
}
-static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstring ifname,
+ jobject info, bool renew)
{
int result;
char ipaddr[PROPERTY_VALUE_MAX];
@@ -160,8 +171,14 @@ static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring if
const char *nameStr = env->GetStringUTFChars(ifname, NULL);
if (nameStr == NULL) return (jboolean)false;
- result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
- dns1, dns2, server, &lease);
+ if (renew) {
+ result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength,
+ dns1, dns2, server, &lease);
+ } else {
+ result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
+ dns1, dns2, server, &lease);
+ }
+
env->ReleaseStringUTFChars(ifname, nameStr);
if (result == 0 && dhcpInfoInternalFieldIds.dhcpInfoInternalClass != NULL) {
env->SetObjectField(info, dhcpInfoInternalFieldIds.ipaddress, env->NewStringUTF(ipaddr));
@@ -176,6 +193,17 @@ static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring if
return (jboolean)(result == 0);
}
+static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+{
+ return android_net_utils_runDhcpCommon(env, clazz, ifname, info, false);
+}
+
+static jboolean android_net_utils_runDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+{
+ return android_net_utils_runDhcpCommon(env, clazz, ifname, info, true);
+}
+
+
static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname)
{
int result;
@@ -219,6 +247,7 @@ static JNINativeMethod gNetworkUtilMethods[] = {
{ "removeDefaultRoute", "(Ljava/lang/String;)I", (void *)android_net_utils_removeDefaultRoute },
{ "resetConnections", "(Ljava/lang/String;)I", (void *)android_net_utils_resetConnections },
{ "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z", (void *)android_net_utils_runDhcp },
+ { "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z", (void *)android_net_utils_runDhcpRenew },
{ "stopDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_stopDhcp },
{ "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease },
{ "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 4e96703..0c0e253 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -48,6 +48,7 @@ import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.DhcpInfoInternal;
+import android.net.DhcpStateMachine;
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -152,6 +153,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
private NetworkInfo mNetworkInfo;
private SupplicantStateTracker mSupplicantStateTracker;
private WpsStateMachine mWpsStateMachine;
+ private DhcpStateMachine mDhcpStateMachine;
private AlarmManager mAlarmManager;
private PendingIntent mScanIntent;
@@ -189,10 +191,10 @@ public class WifiStateMachine extends HierarchicalStateMachine {
static final int CMD_START_DRIVER = BASE + 13;
/* Start the driver */
static final int CMD_STOP_DRIVER = BASE + 14;
- /* Indicates DHCP succeded */
- static final int CMD_IP_CONFIG_SUCCESS = BASE + 15;
- /* Indicates DHCP failed */
- static final int CMD_IP_CONFIG_FAILURE = BASE + 16;
+ /* Indicates Static IP succeded */
+ static final int CMD_STATIC_IP_SUCCESS = BASE + 15;
+ /* Indicates Static IP failed */
+ static final int CMD_STATIC_IP_FAILURE = BASE + 16;
/* Start the soft access point */
static final int CMD_START_AP = BASE + 21;
@@ -342,8 +344,11 @@ public class WifiStateMachine extends HierarchicalStateMachine {
*/
private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
- private static final int POWER_MODE_ACTIVE = 1;
- private static final int POWER_MODE_AUTO = 0;
+ static final int POWER_MODE_ACTIVE = 1;
+ static final int POWER_MODE_AUTO = 0;
+
+ /* Tracks the power mode for restoration after a DHCP request/renewal goes through */
+ private int mPowerMode = POWER_MODE_AUTO;
/**
* See {@link Settings.Secure#WIFI_SCAN_INTERVAL_MS}. This is the default value if a
@@ -1411,8 +1416,10 @@ public class WifiStateMachine extends HierarchicalStateMachine {
*/
NetworkUtils.resetConnections(mInterfaceName);
- if (!NetworkUtils.stopDhcp(mInterfaceName)) {
- Log.e(TAG, "Could not stop DHCP");
+ if (mDhcpStateMachine != null) {
+ mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
+ mDhcpStateMachine.quit();
+ mDhcpStateMachine = null;
}
/* Disable interface */
@@ -1438,6 +1445,99 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
+ void handlePreDhcpSetup() {
+ if (!mBluetoothConnectionActive) {
+ /*
+ * There are problems setting the Wi-Fi driver's power
+ * mode to active when bluetooth coexistence mode is
+ * enabled or sense.
+ * <p>
+ * We set Wi-Fi to active mode when
+ * obtaining an IP address because we've found
+ * compatibility issues with some routers with low power
+ * mode.
+ * <p>
+ * In order for this active power mode to properly be set,
+ * we disable coexistence mode until we're done with
+ * obtaining an IP address. One exception is if we
+ * are currently connected to a headset, since disabling
+ * coexistence would interrupt that connection.
+ */
+ // Disable the coexistence mode
+ WifiNative.setBluetoothCoexistenceModeCommand(
+ WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
+ }
+
+ mPowerMode = WifiNative.getPowerModeCommand();
+ if (mPowerMode < 0) {
+ // Handle the case where supplicant driver does not support
+ // getPowerModeCommand.
+ mPowerMode = WifiStateMachine.POWER_MODE_AUTO;
+ }
+ if (mPowerMode != WifiStateMachine.POWER_MODE_ACTIVE) {
+ WifiNative.setPowerModeCommand(WifiStateMachine.POWER_MODE_ACTIVE);
+ }
+ }
+
+
+ void handlePostDhcpSetup() {
+ /* restore power mode */
+ WifiNative.setPowerModeCommand(mPowerMode);
+
+ // Set the coexistence mode back to its default value
+ WifiNative.setBluetoothCoexistenceModeCommand(
+ WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
+ }
+
+ private void handleSuccessfulIpConfiguration(DhcpInfoInternal dhcpInfoInternal) {
+ synchronized (mDhcpInfoInternal) {
+ mDhcpInfoInternal = dhcpInfoInternal;
+ }
+ mLastSignalLevel = -1; // force update of signal strength
+ WifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal);
+ InetAddress addr = NetworkUtils.numericToInetAddress(dhcpInfoInternal.ipAddress);
+ mWifiInfo.setInetAddress(addr);
+ if (getNetworkDetailedState() == DetailedState.CONNECTED) {
+ //DHCP renewal in connected state
+ LinkProperties linkProperties = dhcpInfoInternal.makeLinkProperties();
+ linkProperties.setHttpProxy(WifiConfigStore.getProxyProperties(mLastNetworkId));
+ linkProperties.setInterfaceName(mInterfaceName);
+ if (!linkProperties.equals(mLinkProperties)) {
+ Log.d(TAG, "Link configuration changed for netId: " + mLastNetworkId
+ + " old: " + mLinkProperties + "new: " + linkProperties);
+ NetworkUtils.resetConnections(mInterfaceName);
+ mLinkProperties = linkProperties;
+ sendLinkConfigurationChangedBroadcast();
+ }
+ } else {
+ configureLinkProperties();
+ setNetworkDetailedState(DetailedState.CONNECTED);
+ sendNetworkStateChangeBroadcast(mLastBssid);
+ }
+ }
+
+ private void handleFailedIpConfiguration() {
+ Log.e(TAG, "IP configuration failed");
+
+ mWifiInfo.setInetAddress(null);
+ /**
+ * If we've exceeded the maximum number of retries for DHCP
+ * to a given network, disable the network
+ */
+ if (++mReconnectCount > getMaxDhcpRetries()) {
+ Log.e(TAG, "Failed " +
+ mReconnectCount + " times, Disabling " + mLastNetworkId);
+ WifiConfigStore.disableNetwork(mLastNetworkId);
+ mReconnectCount = 0;
+ }
+
+ /* DHCP times out after about 30 seconds, we do a
+ * disconnect and an immediate reconnect to try again
+ */
+ WifiNative.disconnectCommand();
+ WifiNative.reconnectCommand();
+ }
+
private boolean startSoftApWithConfig(WifiConfiguration config, int currentStatus) {
if (config == null) {
config = WifiApConfigStore.getApConfiguration();
@@ -1463,6 +1563,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
return true;
}
+
/*********************************************************
* Notifications from WifiMonitor
********************************************************/
@@ -1640,6 +1741,8 @@ public class WifiStateMachine extends HierarchicalStateMachine {
case CMD_FORGET_NETWORK:
case CMD_RSSI_POLL:
case CMD_ENABLE_ALL_NETWORKS:
+ case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+ case DhcpStateMachine.CMD_POST_DHCP_ACTION:
break;
case CMD_START_WPS:
/* Return failure when the state machine cannot handle WPS initiation*/
@@ -2502,74 +2605,18 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
class ConnectingState extends HierarchicalState {
- boolean mModifiedBluetoothCoexistenceMode;
- int mPowerMode;
- boolean mUseStaticIp;
- Thread mDhcpThread;
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- mUseStaticIp = WifiConfigStore.isUsingStaticIp(mLastNetworkId);
- if (!mUseStaticIp) {
- mDhcpThread = null;
- mModifiedBluetoothCoexistenceMode = false;
- mPowerMode = POWER_MODE_AUTO;
-
- if (!mBluetoothConnectionActive) {
- /*
- * There are problems setting the Wi-Fi driver's power
- * mode to active when bluetooth coexistence mode is
- * enabled or sense.
- * <p>
- * We set Wi-Fi to active mode when
- * obtaining an IP address because we've found
- * compatibility issues with some routers with low power
- * mode.
- * <p>
- * In order for this active power mode to properly be set,
- * we disable coexistence mode until we're done with
- * obtaining an IP address. One exception is if we
- * are currently connected to a headset, since disabling
- * coexistence would interrupt that connection.
- */
- mModifiedBluetoothCoexistenceMode = true;
-
- // Disable the coexistence mode
- WifiNative.setBluetoothCoexistenceModeCommand(
- WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
- }
-
- mPowerMode = WifiNative.getPowerModeCommand();
- if (mPowerMode < 0) {
- // Handle the case where supplicant driver does not support
- // getPowerModeCommand.
- mPowerMode = POWER_MODE_AUTO;
- }
- if (mPowerMode != POWER_MODE_ACTIVE) {
- WifiNative.setPowerModeCommand(POWER_MODE_ACTIVE);
- }
- Log.d(TAG, "DHCP request started");
- mDhcpThread = new Thread(new Runnable() {
- public void run() {
- DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
- if (NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal)) {
- Log.d(TAG, "DHCP request succeeded");
- synchronized (mDhcpInfoInternal) {
- mDhcpInfoInternal = dhcpInfoInternal;
- }
- WifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal);
- sendMessage(CMD_IP_CONFIG_SUCCESS);
- } else {
- Log.d(TAG, "DHCP request failed: " +
- NetworkUtils.getDhcpError());
- sendMessage(CMD_IP_CONFIG_FAILURE);
- }
- }
- });
- mDhcpThread.start();
+ if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
+ //start DHCP
+ mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
+ mContext, WifiStateMachine.this, mInterfaceName);
+ mDhcpStateMachine.registerForPreDhcpNotification();
+ mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
} else {
DhcpInfoInternal dhcpInfoInternal = WifiConfigStore.getIpConfiguration(
mLastNetworkId);
@@ -2581,16 +2628,13 @@ public class WifiStateMachine extends HierarchicalStateMachine {
try {
netd.setInterfaceConfig(mInterfaceName, ifcg);
Log.v(TAG, "Static IP configuration succeeded");
- synchronized (mDhcpInfoInternal) {
- mDhcpInfoInternal = dhcpInfoInternal;
- }
- sendMessage(CMD_IP_CONFIG_SUCCESS);
+ sendMessage(CMD_STATIC_IP_SUCCESS, dhcpInfoInternal);
} catch (RemoteException re) {
Log.v(TAG, "Static IP configuration failed: " + re);
- sendMessage(CMD_IP_CONFIG_FAILURE);
+ sendMessage(CMD_STATIC_IP_FAILURE);
} catch (IllegalStateException e) {
Log.v(TAG, "Static IP configuration failed: " + e);
- sendMessage(CMD_IP_CONFIG_FAILURE);
+ sendMessage(CMD_STATIC_IP_FAILURE);
}
}
}
@@ -2599,44 +2643,26 @@ public class WifiStateMachine extends HierarchicalStateMachine {
if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
switch(message.what) {
- case CMD_IP_CONFIG_SUCCESS:
- mLastSignalLevel = -1; // force update of signal strength
- InetAddress addr;
- synchronized (mDhcpInfoInternal) {
- addr = NetworkUtils.numericToInetAddress(mDhcpInfoInternal.ipAddress);
- }
- mWifiInfo.setInetAddress(addr);
- configureLinkProperties();
- if (getNetworkDetailedState() == DetailedState.CONNECTED) {
- sendLinkConfigurationChangedBroadcast();
- } else {
- setNetworkDetailedState(DetailedState.CONNECTED);
- sendNetworkStateChangeBroadcast(mLastBssid);
+ case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+ handlePreDhcpSetup();
+ mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
+ break;
+ case DhcpStateMachine.CMD_POST_DHCP_ACTION:
+ handlePostDhcpSetup();
+ if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
+ handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
+ transitionTo(mConnectedState);
+ } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
+ handleFailedIpConfiguration();
+ transitionTo(mDisconnectingState);
}
- //TODO: The framework is not detecting a DHCP renewal and a possible
- //IP change. we should detect this and send out a config change broadcast
+ break;
+ case CMD_STATIC_IP_SUCCESS:
+ handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
transitionTo(mConnectedState);
break;
- case CMD_IP_CONFIG_FAILURE:
- mWifiInfo.setInetAddress(null);
-
- Log.e(TAG, "IP configuration failed");
- /**
- * If we've exceeded the maximum number of retries for DHCP
- * to a given network, disable the network
- */
- if (++mReconnectCount > getMaxDhcpRetries()) {
- Log.e(TAG, "Failed " +
- mReconnectCount + " times, Disabling " + mLastNetworkId);
- WifiConfigStore.disableNetwork(mLastNetworkId);
- mReconnectCount = 0;
- }
-
- /* DHCP times out after about 30 seconds, we do a
- * disconnect and an immediate reconnect to try again
- */
- WifiNative.disconnectCommand();
- WifiNative.reconnectCommand();
+ case CMD_STATIC_IP_FAILURE:
+ handleFailedIpConfiguration();
transitionTo(mDisconnectingState);
break;
case CMD_DISCONNECT:
@@ -2680,23 +2706,6 @@ public class WifiStateMachine extends HierarchicalStateMachine {
EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
-
- @Override
- public void exit() {
- /* reset power state & bluetooth coexistence if on DHCP */
- if (!mUseStaticIp) {
- if (mPowerMode != POWER_MODE_ACTIVE) {
- WifiNative.setPowerModeCommand(mPowerMode);
- }
-
- if (mModifiedBluetoothCoexistenceMode) {
- // Set the coexistence mode back to its default value
- WifiNative.setBluetoothCoexistenceModeCommand(
- WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
- }
- }
-
- }
}
class ConnectedState extends HierarchicalState {
@@ -2714,6 +2723,19 @@ public class WifiStateMachine extends HierarchicalStateMachine {
if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
boolean eventLoggingEnabled = true;
switch (message.what) {
+ case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+ handlePreDhcpSetup();
+ mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
+ break;
+ case DhcpStateMachine.CMD_POST_DHCP_ACTION:
+ handlePostDhcpSetup();
+ if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
+ handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
+ } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
+ handleFailedIpConfiguration();
+ transitionTo(mDisconnectingState);
+ }
+ break;
case CMD_DISCONNECT:
WifiNative.disconnectCommand();
transitionTo(mDisconnectingState);