am 8ab6a6d4: Merge "Add DhcpStateMachine for interation with dhcpcd" into honeycomb-LTE

* commit '8ab6a6d415156bb543a735612fbbdecfbff6c3a4':
  Add DhcpStateMachine for interation with dhcpcd
This commit is contained in:
Irfan Sheriff
2011-05-02 12:26:52 -07:00
committed by Android Git Automerger
4 changed files with 545 additions and 131 deletions

View File

@@ -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.State;
import com.android.internal.util.StateMachine;
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 StateMachine {
private static final String TAG = "DhcpStateMachine";
private static final boolean DBG = false;
/* A StateMachine that controls the DhcpStateMachine */
private StateMachine 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 State mDefaultState = new DefaultState();
private State mStoppedState = new StoppedState();
private State mWaitBeforeStartState = new WaitBeforeStartState();
private State mRunningState = new RunningState();
private State mWaitBeforeRenewalState = new WaitBeforeRenewalState();
private DhcpStateMachine(Context context, StateMachine 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, StateMachine 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 State {
@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 SM_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 State {
@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 State {
@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 State {
@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 State {
@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;
}
}

View File

@@ -79,6 +79,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

View File

@@ -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 },

View File

@@ -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 StateMachine {
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 StateMachine {
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;
@@ -338,8 +340,11 @@ public class WifiStateMachine extends StateMachine {
*/
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
@@ -1392,8 +1397,10 @@ public class WifiStateMachine extends StateMachine {
*/
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 */
@@ -1419,6 +1426,100 @@ public class WifiStateMachine extends StateMachine {
}
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();
}
/*********************************************************
* Notifications from WifiMonitor
@@ -1590,6 +1691,8 @@ public class WifiStateMachine extends StateMachine {
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*/
@@ -2462,74 +2565,18 @@ public class WifiStateMachine extends StateMachine {
}
class ConnectingState extends State {
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);
@@ -2541,16 +2588,13 @@ public class WifiStateMachine extends StateMachine {
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);
}
}
}
@@ -2559,44 +2603,26 @@ public class WifiStateMachine extends StateMachine {
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);
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);
}
mWifiInfo.setInetAddress(addr);
configureLinkProperties();
if (getNetworkDetailedState() == DetailedState.CONNECTED) {
sendLinkConfigurationChangedBroadcast();
} else {
setNetworkDetailedState(DetailedState.CONNECTED);
sendNetworkStateChangeBroadcast(mLastBssid);
}
//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:
@@ -2640,23 +2666,6 @@ public class WifiStateMachine extends StateMachine {
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 State {
@@ -2674,6 +2683,19 @@ public class WifiStateMachine extends StateMachine {
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);