Use IpManager on Ethernet

Bug: 17733693
Bug: 26991160
Change-Id: Idaee8c64bf452e58b93031d8d7ad666edb0c82ae
This commit is contained in:
Erik Kline
2016-02-11 22:06:48 +09:00
parent 189063ffb0
commit 1cb0138ad3

View File

@@ -31,8 +31,8 @@ import android.net.NetworkCapabilities;
import android.net.NetworkFactory; import android.net.NetworkFactory;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.DetailedState;
import android.net.NetworkUtils;
import android.net.StaticIpConfiguration; import android.net.StaticIpConfiguration;
import android.net.ip.IpManager;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.INetworkManagementService; import android.os.INetworkManagementService;
@@ -100,6 +100,8 @@ class EthernetNetworkFactory {
private static boolean mLinkUp; private static boolean mLinkUp;
private NetworkInfo mNetworkInfo; private NetworkInfo mNetworkInfo;
private LinkProperties mLinkProperties; private LinkProperties mLinkProperties;
private IpManager mIpManager;
private Thread mIpProvisioningThread;
EthernetNetworkFactory(RemoteCallbackList<IEthernetServiceListener> listeners) { EthernetNetworkFactory(RemoteCallbackList<IEthernetServiceListener> listeners) {
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, "");
@@ -120,6 +122,21 @@ class EthernetNetworkFactory {
} }
} }
private void stopIpManagerLocked() {
if (mIpManager != null) {
mIpManager.shutdown();
mIpManager = null;
}
}
private void stopIpProvisioningThreadLocked() {
stopIpManagerLocked();
if (mIpProvisioningThread != null) {
mIpProvisioningThread.interrupt();
mIpProvisioningThread = null;
}
}
/** /**
* Updates interface state variables. * Updates interface state variables.
@@ -137,6 +154,7 @@ class EthernetNetworkFactory {
if (!up) { if (!up) {
// Tell the agent we're disconnected. It will call disconnect(). // Tell the agent we're disconnected. It will call disconnect().
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
stopIpProvisioningThreadLocked();
} }
updateAgent(); updateAgent();
// set our score lower than any network could go // set our score lower than any network could go
@@ -166,7 +184,6 @@ class EthernetNetworkFactory {
private void setInterfaceUp(String iface) { private void setInterfaceUp(String iface) {
// Bring up the interface so we get link status indications. // Bring up the interface so we get link status indications.
try { try {
NetworkUtils.stopDhcp(iface);
mNMService.setInterfaceUp(iface); mNMService.setInterfaceUp(iface);
String hwAddr = null; String hwAddr = null;
InterfaceConfiguration config = mNMService.getInterfaceConfig(iface); InterfaceConfiguration config = mNMService.getInterfaceConfig(iface);
@@ -209,7 +226,7 @@ class EthernetNetworkFactory {
Log.d(TAG, "Stopped tracking interface " + iface); Log.d(TAG, "Stopped tracking interface " + iface);
// TODO: Unify this codepath with stop(). // TODO: Unify this codepath with stop().
synchronized (this) { synchronized (this) {
NetworkUtils.stopDhcp(mIface); stopIpProvisioningThreadLocked();
setInterfaceInfoLocked("", null); setInterfaceInfoLocked("", null);
mNetworkInfo.setExtraInfo(null); mNetworkInfo.setExtraInfo(null);
mLinkUp = false; mLinkUp = false;
@@ -257,12 +274,52 @@ class EthernetNetworkFactory {
} }
} }
private class IpManagerCallback extends IpManager.Callback {
private LinkProperties mCallbackLinkProperties;
public LinkProperties waitForProvisioning() {
synchronized (this) {
try {
wait();
} catch (InterruptedException e) {}
return mCallbackLinkProperties;
}
}
@Override
public void onProvisioningSuccess(LinkProperties newLp) {
synchronized (this) {
mCallbackLinkProperties = newLp;
notify();
}
}
@Override
public void onProvisioningFailure(LinkProperties newLp) {
synchronized (this) {
mCallbackLinkProperties = null;
notify();
}
}
}
/* Called by the NetworkFactory on the handler thread. */ /* Called by the NetworkFactory on the handler thread. */
public void onRequestNetwork() { public void onRequestNetwork() {
synchronized(EthernetNetworkFactory.this) {
if (mIpProvisioningThread != null) {
return;
}
}
// TODO: Handle DHCP renew. // TODO: Handle DHCP renew.
Thread dhcpThread = new Thread(new Runnable() { final Thread ipProvisioningThread = new Thread(new Runnable() {
public void run() { public void run() {
if (DBG) Log.i(TAG, "dhcpThread(" + mIface + "): mNetworkInfo=" + mNetworkInfo); if (DBG) {
Log.d(TAG, String.format("starting ipProvisioningThread(%s): mNetworkInfo=%s",
mIface, mNetworkInfo));
}
LinkProperties linkProperties; LinkProperties linkProperties;
IpConfiguration config = mEthernetManager.getConfiguration(); IpConfiguration config = mEthernetManager.getConfiguration();
@@ -275,39 +332,41 @@ class EthernetNetworkFactory {
linkProperties = config.getStaticIpConfiguration().toLinkProperties(mIface); linkProperties = config.getStaticIpConfiguration().toLinkProperties(mIface);
} else { } else {
mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr);
IpManagerCallback blockingCallback = new IpManagerCallback();
DhcpResults dhcpResults = new DhcpResults(); synchronized(EthernetNetworkFactory.this) {
// TODO: Handle DHCP renewals better. stopIpManagerLocked();
// In general runDhcp handles DHCP renewals for us, because mIpManager = new IpManager(mContext, mIface, blockingCallback);
// the dhcp client stays running, but if the renewal fails, mIpManager.startProvisioning();
// we will lose our IP address and connectivity without }
// noticing. linkProperties = blockingCallback.waitForProvisioning();
if (!NetworkUtils.runDhcp(mIface, dhcpResults)) { if (linkProperties == null) {
Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError()); Log.e(TAG, "IP provisioning error");
// set our score lower than any network could go // set our score lower than any network could go
// so we get dropped. // so we get dropped.
mFactory.setScoreFilter(-1); mFactory.setScoreFilter(-1);
// If DHCP timed out (as opposed to failing), the DHCP client will still be synchronized(EthernetNetworkFactory.this) {
// running, because in M we changed its timeout to infinite. Stop it now. stopIpManagerLocked();
NetworkUtils.stopDhcp(mIface); }
return; return;
} }
linkProperties = dhcpResults.toLinkProperties(mIface);
} }
if (config.getProxySettings() == ProxySettings.STATIC || if (config.getProxySettings() == ProxySettings.STATIC ||
config.getProxySettings() == ProxySettings.PAC) { config.getProxySettings() == ProxySettings.PAC) {
linkProperties.setHttpProxy(config.getHttpProxy()); linkProperties.setHttpProxy(config.getHttpProxy());
} }
String tcpBufferSizes = mContext.getResources().getString( final String tcpBufferSizes = mContext.getResources().getString(
com.android.internal.R.string.config_ethernet_tcp_buffers); com.android.internal.R.string.config_ethernet_tcp_buffers);
if (TextUtils.isEmpty(tcpBufferSizes) == false) { if (!TextUtils.isEmpty(tcpBufferSizes)) {
linkProperties.setTcpBufferSizes(tcpBufferSizes); linkProperties.setTcpBufferSizes(tcpBufferSizes);
} }
synchronized(EthernetNetworkFactory.this) { synchronized(EthernetNetworkFactory.this) {
if (mNetworkAgent != null) { if (mNetworkAgent != null) {
Log.e(TAG, "Already have a NetworkAgent - aborting new request"); Log.e(TAG, "Already have a NetworkAgent - aborting new request");
stopIpManagerLocked();
mIpProvisioningThread = null;
return; return;
} }
mLinkProperties = linkProperties; mLinkProperties = linkProperties;
@@ -321,7 +380,7 @@ class EthernetNetworkFactory {
public void unwanted() { public void unwanted() {
synchronized(EthernetNetworkFactory.this) { synchronized(EthernetNetworkFactory.this) {
if (this == mNetworkAgent) { if (this == mNetworkAgent) {
NetworkUtils.stopDhcp(mIface); stopIpManagerLocked();
mLinkProperties.clear(); mLinkProperties.clear();
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null,
@@ -340,10 +399,23 @@ class EthernetNetworkFactory {
} }
}; };
}; };
mIpProvisioningThread = null;
}
if (DBG) {
Log.d(TAG, String.format("exiting ipProvisioningThread(%s): mNetworkInfo=%s",
mIface, mNetworkInfo));
} }
} }
}); });
dhcpThread.start();
synchronized(EthernetNetworkFactory.this) {
if (mIpProvisioningThread == null) {
mIpProvisioningThread = ipProvisioningThread;
mIpProvisioningThread.start();
}
}
} }
/** /**
@@ -402,7 +474,7 @@ class EthernetNetworkFactory {
} }
public synchronized void stop() { public synchronized void stop() {
NetworkUtils.stopDhcp(mIface); stopIpProvisioningThreadLocked();
// ConnectivityService will only forget our NetworkAgent if we send it a NetworkInfo object // ConnectivityService will only forget our NetworkAgent if we send it a NetworkInfo object
// with a state of DISCONNECTED or SUSPENDED. So we can't simply clear our NetworkInfo here: // with a state of DISCONNECTED or SUSPENDED. So we can't simply clear our NetworkInfo here:
// that sets the state to IDLE, and ConnectivityService will still think we're connected. // that sets the state to IDLE, and ConnectivityService will still think we're connected.