Move DHCPv4 mechanics into IpManager

Bug: 17345682
Change-Id: I2c3d9d665ff3c38f02084c0cf86cd76035e7b0aa
This commit is contained in:
Erik Kline
2016-02-02 13:06:21 +09:00
parent c0e87a55f2
commit 8afa558c52

View File

@@ -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 @@ public class IpManager extends StateMachine {
* 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 @@ public class IpManager extends StateMachine {
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 @@ public class IpManager extends StateMachine {
* 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 @@ public class IpManager extends StateMachine {
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 @@ public class IpManager extends StateMachine {
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 @@ public class IpManager extends StateMachine {
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 @@ public class IpManager extends StateMachine {
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 @@ public class IpManager extends StateMachine {
} else {
sendMessage(CMD_UPDATE_DHCPV4_RESULTS);
}
} else {
// Start DHCPv4.
makeDhcpStateMachine();
mDhcpStateMachine.registerForPreDhcpNotification();
mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
}
}
@@ -399,6 +435,12 @@ public class IpManager extends StateMachine {
mIpReachabilityMonitor.stop();
mIpReachabilityMonitor = null;
if (mDhcpStateMachine != null) {
mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
mDhcpStateMachine.doQuit();
mDhcpStateMachine = null;
}
resetLinkProperties();
}
@@ -410,32 +452,45 @@ public class IpManager extends StateMachine {
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 @@ public class IpManager extends StateMachine {
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 @@ public class IpManager extends StateMachine {
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);
}
}
}
}