Move DHCPv4 mechanics into IpManager
am: 8afa558c52
* commit '8afa558c527b4be4e0e489b17485577e23148636':
Move DHCPv4 mechanics into IpManager
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 62c635d..9c9719f 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -17,16 +17,21 @@
package android.net.ip;
import android.content.Context;
+import android.net.BaseDhcpStateMachine;
import android.net.DhcpResults;
+import android.net.DhcpStateMachine;
import android.net.InterfaceConfiguration;
+import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.LinkProperties.ProvisioningChange;
import android.net.RouteInfo;
import android.net.StaticIpConfiguration;
+import android.net.dhcp.DhcpClient;
import android.os.INetworkManagementService;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.provider.Settings;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -85,6 +90,10 @@
* as IpManager invokes them.
*/
+ // Implementations must call IpManager#completedPreDhcpAction().
+ public void onPreDhcpAction() {}
+ public void onPostDhcpAction() {}
+
// TODO: Kill with fire once DHCP and static configuration are moved
// out of WifiStateMachine.
public void onIPv4ProvisioningSuccess(DhcpResults dhcpResults) {}
@@ -105,8 +114,9 @@
private static final int CMD_START = 2;
private static final int CMD_CONFIRM = 3;
private static final int CMD_UPDATE_DHCPV4_RESULTS = 4;
+ private static final int EVENT_PRE_DHCP_ACTION_COMPLETE = 5;
// Sent by NetlinkTracker to communicate netlink events.
- private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 5;
+ private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 6;
private static final int MAX_LOG_RECORDS = 1000;
@@ -127,6 +137,7 @@
* Non-final member variables accessed only from within our StateMachine.
*/
private IpReachabilityMonitor mIpReachabilityMonitor;
+ private BaseDhcpStateMachine mDhcpStateMachine;
private DhcpResults mDhcpResults;
private StaticIpConfiguration mStaticIpConfig;
@@ -210,17 +221,16 @@
sendMessage(CMD_CONFIRM);
}
+ public void completedPreDhcpAction() {
+ sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
+ }
+
public LinkProperties getLinkProperties() {
synchronized (mLock) {
return new LinkProperties(mLinkProperties);
}
}
- // TODO: Kill with fire once DHCPv4/static config is moved into IpManager.
- public void updateWithDhcpResults(DhcpResults dhcpResults) {
- sendMessage(CMD_UPDATE_DHCPV4_RESULTS, dhcpResults);
- }
-
/**
* Internals.
@@ -323,6 +333,16 @@
return newLp;
}
+ private void clearIPv4Address() {
+ try {
+ final InterfaceConfiguration ifcg = new InterfaceConfiguration();
+ ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0"));
+ mNwService.setInterfaceConfig(mInterfaceName, ifcg);
+ } catch (RemoteException e) {
+ Log.e(TAG, "ALERT: Failed to clear IPv4 address on interface " + mInterfaceName, e);
+ }
+ }
+
class StoppedState extends State {
@Override
public void enter() {
@@ -351,6 +371,16 @@
setLinkProperties(assembleLinkProperties());
break;
+ case DhcpStateMachine.CMD_ON_QUIT:
+ // CMD_ON_QUIT is really more like "EVENT_ON_QUIT".
+ // Shutting down DHCPv4 progresses simultaneously with
+ // transitioning to StoppedState, so we can receive this
+ // message after we've already transitioned here.
+ //
+ // TODO: Figure out if this is actually useful and if not
+ // expunge it.
+ break;
+
default:
return NOT_HANDLED;
}
@@ -365,6 +395,7 @@
try {
mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
mNwService.enableIpv6(mInterfaceName);
+ // TODO: Perhaps clearIPv4Address() as well.
} catch (RemoteException re) {
Log.e(TAG, "Unable to change interface settings: " + re);
} catch (IllegalStateException ie) {
@@ -391,6 +422,11 @@
} else {
sendMessage(CMD_UPDATE_DHCPV4_RESULTS);
}
+ } else {
+ // Start DHCPv4.
+ makeDhcpStateMachine();
+ mDhcpStateMachine.registerForPreDhcpNotification();
+ mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
}
}
@@ -399,6 +435,12 @@
mIpReachabilityMonitor.stop();
mIpReachabilityMonitor = null;
+ if (mDhcpStateMachine != null) {
+ mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
+ mDhcpStateMachine.doQuit();
+ mDhcpStateMachine = null;
+ }
+
resetLinkProperties();
}
@@ -410,32 +452,45 @@
break;
case CMD_START:
- // TODO: Defer this message to be delivered after a state transition
- // to StoppedState. That way, receiving CMD_START in StartedState
- // effects a restart.
- Log.e(TAG, "ALERT: START received in StartedState.");
+ Log.e(TAG, "ALERT: START received in StartedState. Please fix caller.");
break;
case CMD_CONFIRM:
+ // TODO: Possibly introduce a second type of confirmation
+ // that both probes (a) on-link neighbors and (b) does
+ // a DHCPv4 RENEW. We used to do this on Wi-Fi framework
+ // roams.
if (mCallback.usingIpReachabilityMonitor()) {
mIpReachabilityMonitor.probeAll();
}
break;
- case CMD_UPDATE_DHCPV4_RESULTS:
+ case CMD_UPDATE_DHCPV4_RESULTS: {
final DhcpResults dhcpResults = (DhcpResults) msg.obj;
if (dhcpResults != null) {
mDhcpResults = new DhcpResults(dhcpResults);
setLinkProperties(assembleLinkProperties());
mCallback.onIPv4ProvisioningSuccess(dhcpResults);
} else {
+ clearIPv4Address();
mDhcpResults = null;
setLinkProperties(assembleLinkProperties());
mCallback.onIPv4ProvisioningFailure();
}
break;
+ }
- case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+ case EVENT_PRE_DHCP_ACTION_COMPLETE:
+ // It's possible to reach here if, for example, someone
+ // calls completedPreDhcpAction() after provisioning with
+ // a static IP configuration.
+ if (mDhcpStateMachine != null) {
+ mDhcpStateMachine.sendMessage(
+ DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
+ }
+ break;
+
+ case EVENT_NETLINK_LINKPROPERTIES_CHANGED: {
final LinkProperties newLp = assembleLinkProperties();
final ProvisioningChange delta = setLinkProperties(newLp);
@@ -456,7 +511,44 @@
mCallback.onLinkPropertiesChange(newLp);
break;
}
+ break;
+ }
+ case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+ mCallback.onPreDhcpAction();
+ break;
+
+ case DhcpStateMachine.CMD_POST_DHCP_ACTION: {
+ // Note that onPostDhcpAction() is likely to be
+ // asynchronous, and thus there is no guarantee that we
+ // will be able to observe any of its effects here.
+ mCallback.onPostDhcpAction();
+
+ final DhcpResults dhcpResults = (DhcpResults) msg.obj;
+ switch (msg.arg1) {
+ case DhcpStateMachine.DHCP_SUCCESS:
+ mDhcpResults = new DhcpResults(dhcpResults);
+ setLinkProperties(assembleLinkProperties());
+ mCallback.onIPv4ProvisioningSuccess(dhcpResults);
+ break;
+ case DhcpStateMachine.DHCP_FAILURE:
+ clearIPv4Address();
+ mDhcpResults = null;
+ setLinkProperties(assembleLinkProperties());
+ mCallback.onIPv4ProvisioningFailure();
+ break;
+ default:
+ Log.e(TAG, "Unknown CMD_POST_DHCP_ACTION status:" + msg.arg1);
+ }
+ break;
+ }
+
+ case DhcpStateMachine.CMD_ON_QUIT:
+ // CMD_ON_QUIT is really more like "EVENT_ON_QUIT".
+ // Regardless, we ignore it.
+ //
+ // TODO: Figure out if this is actually useful and if not
+ // expunge it.
break;
default:
@@ -479,5 +571,23 @@
return true;
}
+
+ private void makeDhcpStateMachine() {
+ final boolean usingLegacyDhcp = (Settings.Global.getInt(
+ mContext.getContentResolver(),
+ Settings.Global.LEGACY_DHCP_CLIENT, 0) == 1);
+
+ if (usingLegacyDhcp) {
+ mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
+ mContext,
+ IpManager.this,
+ mInterfaceName);
+ } else {
+ mDhcpStateMachine = DhcpClient.makeDhcpStateMachine(
+ mContext,
+ IpManager.this,
+ mInterfaceName);
+ }
+ }
}
}