Make Ethernet more robust.
1. Remove the IP provisioning thread and just attempt provisioning indefinitely whenever we have an interface. 2. Make all methods run on the passed-in handler thread. This makes it easier to verify correctness by code inspection. 3. Remove the code that changes the factory score depending on whether we're tracking an interface and have link. This is unnecessary complexity, as there is no penalty to accepting a request even if we don't have an interface. 4. Remove code duplication and only have one codepath for stopping layer 3. Tested the following are tested with this CL: - Booting with an interface connected. - Disconnecting/reconnecting the Ethernet cable repeatedly, particularly at inconvenient times (e.g., during provisioning). - Similarly, disconnecting/reconnecting USB Ethernet interfaces. - Falling back to another Ethernet interface if the currently tracked Ethernet interface is unplugged. - Disconnecting and restarting provisioning when provisioning is lost (e.g., if the default route is deleted). - Crashing the system server causes Ethernet to reconnect on restart. - The above while running watch -n 0.1 adb shell dumpsys ethernet Bug: 62308954 Test: tested on marlin with USB ethernet adapters, as described Change-Id: Iad12a52a903bfaccf7e245dfe499652c752c31e9
This commit is contained in:
@@ -34,7 +34,6 @@ import android.net.NetworkInfo.DetailedState;
|
|||||||
import android.net.StaticIpConfiguration;
|
import android.net.StaticIpConfiguration;
|
||||||
import android.net.ip.IpManager;
|
import android.net.ip.IpManager;
|
||||||
import android.net.ip.IpManager.ProvisioningConfiguration;
|
import android.net.ip.IpManager.ProvisioningConfiguration;
|
||||||
import android.net.ip.IpManager.WaitForProvisioningCallback;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.INetworkManagementService;
|
import android.os.INetworkManagementService;
|
||||||
@@ -50,6 +49,8 @@ import com.android.server.net.BaseNetworkObserver;
|
|||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,6 +85,9 @@ class EthernetNetworkFactory {
|
|||||||
/** To set link state and configure IP addresses. */
|
/** To set link state and configure IP addresses. */
|
||||||
private INetworkManagementService mNMService;
|
private INetworkManagementService mNMService;
|
||||||
|
|
||||||
|
/** All code runs here, including start(). */
|
||||||
|
private Handler mHandler;
|
||||||
|
|
||||||
/* To communicate with ConnectivityManager */
|
/* To communicate with ConnectivityManager */
|
||||||
private NetworkCapabilities mNetworkCapabilities;
|
private NetworkCapabilities mNetworkCapabilities;
|
||||||
private NetworkAgent mNetworkAgent;
|
private NetworkAgent mNetworkAgent;
|
||||||
@@ -96,19 +100,18 @@ class EthernetNetworkFactory {
|
|||||||
/** To notify Ethernet status. */
|
/** To notify Ethernet status. */
|
||||||
private final RemoteCallbackList<IEthernetServiceListener> mListeners;
|
private final RemoteCallbackList<IEthernetServiceListener> mListeners;
|
||||||
|
|
||||||
/** Data members. All accesses to these must be synchronized(this). */
|
/** Data members. All accesses to these must be on the handler thread. */
|
||||||
private static String mIface = "";
|
private String mIface = "";
|
||||||
private String mHwAddr;
|
private String mHwAddr;
|
||||||
private static boolean mLinkUp;
|
private boolean mLinkUp;
|
||||||
private NetworkInfo mNetworkInfo;
|
private NetworkInfo mNetworkInfo;
|
||||||
private LinkProperties mLinkProperties;
|
private LinkProperties mLinkProperties;
|
||||||
private IpManager mIpManager;
|
private IpManager mIpManager;
|
||||||
private Thread mIpProvisioningThread;
|
private boolean mNetworkRequested = false;
|
||||||
|
|
||||||
EthernetNetworkFactory(RemoteCallbackList<IEthernetServiceListener> listeners) {
|
EthernetNetworkFactory(RemoteCallbackList<IEthernetServiceListener> listeners) {
|
||||||
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, "");
|
|
||||||
mLinkProperties = new LinkProperties();
|
|
||||||
initNetworkCapabilities();
|
initNetworkCapabilities();
|
||||||
|
clearInfo();
|
||||||
mListeners = listeners;
|
mListeners = listeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,26 +121,40 @@ class EthernetNetworkFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void startNetwork() {
|
protected void startNetwork() {
|
||||||
onRequestNetwork();
|
if (!mNetworkRequested) {
|
||||||
|
mNetworkRequested = true;
|
||||||
|
maybeStartIpManager();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void stopNetwork() {
|
protected void stopNetwork() {
|
||||||
|
mNetworkRequested = false;
|
||||||
|
stopIpManager();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopIpManagerLocked() {
|
private void clearInfo() {
|
||||||
|
mLinkProperties = new LinkProperties();
|
||||||
|
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, "");
|
||||||
|
mNetworkInfo.setExtraInfo(mHwAddr);
|
||||||
|
mNetworkInfo.setIsAvailable(isTrackingInterface());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopIpManager() {
|
||||||
if (mIpManager != null) {
|
if (mIpManager != null) {
|
||||||
mIpManager.shutdown();
|
mIpManager.shutdown();
|
||||||
mIpManager = null;
|
mIpManager = null;
|
||||||
}
|
}
|
||||||
}
|
// 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:
|
||||||
private void stopIpProvisioningThreadLocked() {
|
// that sets the state to IDLE, and ConnectivityService will still think we're connected.
|
||||||
stopIpManagerLocked();
|
//
|
||||||
|
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
|
||||||
if (mIpProvisioningThread != null) {
|
if (mNetworkAgent != null) {
|
||||||
mIpProvisioningThread.interrupt();
|
updateAgent();
|
||||||
mIpProvisioningThread = null;
|
mNetworkAgent = null;
|
||||||
}
|
}
|
||||||
|
clearInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -150,36 +167,36 @@ class EthernetNetworkFactory {
|
|||||||
}
|
}
|
||||||
Log.d(TAG, "updateInterface: " + iface + " link " + (up ? "up" : "down"));
|
Log.d(TAG, "updateInterface: " + iface + " link " + (up ? "up" : "down"));
|
||||||
|
|
||||||
synchronized(this) {
|
mLinkUp = up;
|
||||||
mLinkUp = up;
|
if (up) {
|
||||||
mNetworkInfo.setIsAvailable(up);
|
maybeStartIpManager();
|
||||||
if (!up) {
|
} else {
|
||||||
// Tell the agent we're disconnected. It will call disconnect().
|
stopIpManager();
|
||||||
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
|
|
||||||
stopIpProvisioningThreadLocked();
|
|
||||||
}
|
|
||||||
updateAgent();
|
|
||||||
// set our score lower than any network could go
|
|
||||||
// so we get dropped. TODO - just unregister the factory
|
|
||||||
// when link goes down.
|
|
||||||
mFactory.setScoreFilter(up ? NETWORK_SCORE : -1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class InterfaceObserver extends BaseNetworkObserver {
|
private class InterfaceObserver extends BaseNetworkObserver {
|
||||||
@Override
|
@Override
|
||||||
public void interfaceLinkStateChanged(String iface, boolean up) {
|
public void interfaceLinkStateChanged(String iface, boolean up) {
|
||||||
updateInterfaceState(iface, up);
|
mHandler.post(() -> {
|
||||||
|
updateInterfaceState(iface, up);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void interfaceAdded(String iface) {
|
public void interfaceAdded(String iface) {
|
||||||
maybeTrackInterface(iface);
|
mHandler.post(() -> {
|
||||||
|
maybeTrackInterface(iface);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void interfaceRemoved(String iface) {
|
public void interfaceRemoved(String iface) {
|
||||||
stopTrackingInterface(iface);
|
mHandler.post(() -> {
|
||||||
|
if (stopTrackingInterface(iface)) {
|
||||||
|
trackFirstAvailableInterface();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,15 +212,13 @@ class EthernetNetworkFactory {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (this) {
|
if (!isTrackingInterface()) {
|
||||||
if (!isTrackingInterface()) {
|
setInterfaceInfo(iface, config.getHardwareAddress());
|
||||||
setInterfaceInfoLocked(iface, config.getHardwareAddress());
|
mNetworkInfo.setIsAvailable(true);
|
||||||
mNetworkInfo.setIsAvailable(true);
|
mNetworkInfo.setExtraInfo(mHwAddr);
|
||||||
mNetworkInfo.setExtraInfo(mHwAddr);
|
} else {
|
||||||
} else {
|
Log.e(TAG, "Interface unexpectedly changed from " + iface + " to " + mIface);
|
||||||
Log.e(TAG, "Interface unexpectedly changed from " + iface + " to " + mIface);
|
mNMService.setInterfaceDown(iface);
|
||||||
mNMService.setInterfaceDown(iface);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Error upping interface " + mIface + ": " + e);
|
Log.e(TAG, "Error upping interface " + mIface + ": " + e);
|
||||||
@@ -221,23 +236,14 @@ class EthernetNetworkFactory {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopTrackingInterface(String iface) {
|
private boolean stopTrackingInterface(String iface) {
|
||||||
if (!iface.equals(mIface))
|
if (!iface.equals(mIface))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
Log.d(TAG, "Stopped tracking interface " + iface);
|
Log.d(TAG, "Stopped tracking interface " + iface);
|
||||||
// TODO: Unify this codepath with stop().
|
setInterfaceInfo("", null);
|
||||||
synchronized (this) {
|
stopIpManager();
|
||||||
stopIpProvisioningThreadLocked();
|
return true;
|
||||||
setInterfaceInfoLocked("", null);
|
|
||||||
mNetworkInfo.setExtraInfo(null);
|
|
||||||
mLinkUp = false;
|
|
||||||
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
|
|
||||||
updateAgent();
|
|
||||||
mNetworkAgent = null;
|
|
||||||
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, "");
|
|
||||||
mLinkProperties = new LinkProperties();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean setStaticIpAddress(StaticIpConfiguration staticConfig) {
|
private boolean setStaticIpAddress(StaticIpConfiguration staticConfig) {
|
||||||
@@ -260,156 +266,127 @@ class EthernetNetworkFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updateAgent() {
|
public void updateAgent() {
|
||||||
synchronized (EthernetNetworkFactory.this) {
|
if (mNetworkAgent == null) return;
|
||||||
if (mNetworkAgent == null) return;
|
if (DBG) {
|
||||||
if (DBG) {
|
Log.i(TAG, "Updating mNetworkAgent with: " +
|
||||||
Log.i(TAG, "Updating mNetworkAgent with: " +
|
mNetworkCapabilities + ", " +
|
||||||
mNetworkCapabilities + ", " +
|
mNetworkInfo + ", " +
|
||||||
mNetworkInfo + ", " +
|
mLinkProperties);
|
||||||
mLinkProperties);
|
}
|
||||||
|
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
|
||||||
|
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
|
||||||
|
mNetworkAgent.sendLinkProperties(mLinkProperties);
|
||||||
|
// never set the network score below 0.
|
||||||
|
mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onIpLayerStarted(LinkProperties linkProperties) {
|
||||||
|
if (mNetworkAgent != null) {
|
||||||
|
Log.e(TAG, "Already have a NetworkAgent - aborting new request");
|
||||||
|
stopIpManager();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mLinkProperties = linkProperties;
|
||||||
|
mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr);
|
||||||
|
|
||||||
|
// Create our NetworkAgent.
|
||||||
|
mNetworkAgent = new NetworkAgent(mHandler.getLooper(), mContext,
|
||||||
|
NETWORK_TYPE, mNetworkInfo, mNetworkCapabilities, mLinkProperties,
|
||||||
|
NETWORK_SCORE) {
|
||||||
|
public void unwanted() {
|
||||||
|
if (this == mNetworkAgent) {
|
||||||
|
stopIpManager();
|
||||||
|
} else if (mNetworkAgent != null) {
|
||||||
|
Log.d(TAG, "Ignoring unwanted as we have a more modern " +
|
||||||
|
"instance");
|
||||||
|
} // Otherwise, we've already called stopIpManager.
|
||||||
}
|
}
|
||||||
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
|
};
|
||||||
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
|
}
|
||||||
mNetworkAgent.sendLinkProperties(mLinkProperties);
|
|
||||||
// never set the network score below 0.
|
void onIpLayerStopped(LinkProperties linkProperties) {
|
||||||
mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0);
|
// This cannot happen due to provisioning timeout, because our timeout is 0. It can only
|
||||||
|
// happen if we're provisioned and we lose provisioning.
|
||||||
|
stopIpManager();
|
||||||
|
maybeStartIpManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateLinkProperties(LinkProperties linkProperties) {
|
||||||
|
mLinkProperties = linkProperties;
|
||||||
|
if (mNetworkAgent != null) {
|
||||||
|
mNetworkAgent.sendLinkProperties(linkProperties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called by the NetworkFactory on the handler thread. */
|
public void maybeStartIpManager() {
|
||||||
public void onRequestNetwork() {
|
if (mNetworkRequested && mIpManager == null && isTrackingInterface()) {
|
||||||
synchronized(EthernetNetworkFactory.this) {
|
startIpManager();
|
||||||
if (mIpProvisioningThread != null) {
|
}
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
public void startIpManager() {
|
||||||
|
if (DBG) {
|
||||||
|
Log.d(TAG, String.format("starting IpManager(%s): mNetworkInfo=%s", mIface,
|
||||||
|
mNetworkInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
final Thread ipProvisioningThread = new Thread(new Runnable() {
|
LinkProperties linkProperties;
|
||||||
public void run() {
|
|
||||||
if (DBG) {
|
|
||||||
Log.d(TAG, String.format("starting ipProvisioningThread(%s): mNetworkInfo=%s",
|
|
||||||
mIface, mNetworkInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
LinkProperties linkProperties;
|
IpConfiguration config = mEthernetManager.getConfiguration();
|
||||||
|
|
||||||
IpConfiguration config = mEthernetManager.getConfiguration();
|
if (config.getIpAssignment() == IpAssignment.STATIC) {
|
||||||
|
if (!setStaticIpAddress(config.getStaticIpConfiguration())) {
|
||||||
if (config.getIpAssignment() == IpAssignment.STATIC) {
|
// We've already logged an error.
|
||||||
if (!setStaticIpAddress(config.getStaticIpConfiguration())) {
|
return;
|
||||||
// We've already logged an error.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
linkProperties = config.getStaticIpConfiguration().toLinkProperties(mIface);
|
|
||||||
} else {
|
|
||||||
mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr);
|
|
||||||
WaitForProvisioningCallback ipmCallback = new WaitForProvisioningCallback() {
|
|
||||||
@Override
|
|
||||||
public void onLinkPropertiesChange(LinkProperties newLp) {
|
|
||||||
synchronized(EthernetNetworkFactory.this) {
|
|
||||||
if (mNetworkAgent != null && mNetworkInfo.isConnected()) {
|
|
||||||
mLinkProperties = newLp;
|
|
||||||
mNetworkAgent.sendLinkProperties(newLp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
synchronized(EthernetNetworkFactory.this) {
|
|
||||||
stopIpManagerLocked();
|
|
||||||
mIpManager = new IpManager(mContext, mIface, ipmCallback);
|
|
||||||
|
|
||||||
if (config.getProxySettings() == ProxySettings.STATIC ||
|
|
||||||
config.getProxySettings() == ProxySettings.PAC) {
|
|
||||||
mIpManager.setHttpProxy(config.getHttpProxy());
|
|
||||||
}
|
|
||||||
|
|
||||||
final String tcpBufferSizes = mContext.getResources().getString(
|
|
||||||
com.android.internal.R.string.config_ethernet_tcp_buffers);
|
|
||||||
if (!TextUtils.isEmpty(tcpBufferSizes)) {
|
|
||||||
mIpManager.setTcpBufferSizes(tcpBufferSizes);
|
|
||||||
}
|
|
||||||
|
|
||||||
final ProvisioningConfiguration provisioningConfiguration =
|
|
||||||
mIpManager.buildProvisioningConfiguration()
|
|
||||||
.withProvisioningTimeoutMs(0)
|
|
||||||
.build();
|
|
||||||
mIpManager.startProvisioning(provisioningConfiguration);
|
|
||||||
}
|
|
||||||
|
|
||||||
linkProperties = ipmCallback.waitForProvisioning();
|
|
||||||
if (linkProperties == null) {
|
|
||||||
Log.e(TAG, "IP provisioning error");
|
|
||||||
// set our score lower than any network could go
|
|
||||||
// so we get dropped.
|
|
||||||
mFactory.setScoreFilter(-1);
|
|
||||||
synchronized(EthernetNetworkFactory.this) {
|
|
||||||
stopIpManagerLocked();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized(EthernetNetworkFactory.this) {
|
|
||||||
if (mNetworkAgent != null) {
|
|
||||||
Log.e(TAG, "Already have a NetworkAgent - aborting new request");
|
|
||||||
stopIpManagerLocked();
|
|
||||||
mIpProvisioningThread = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mLinkProperties = linkProperties;
|
|
||||||
mNetworkInfo.setIsAvailable(true);
|
|
||||||
mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr);
|
|
||||||
|
|
||||||
// Create our NetworkAgent.
|
|
||||||
mNetworkAgent = new NetworkAgent(mFactory.getLooper(), mContext,
|
|
||||||
NETWORK_TYPE, mNetworkInfo, mNetworkCapabilities, mLinkProperties,
|
|
||||||
NETWORK_SCORE) {
|
|
||||||
public void unwanted() {
|
|
||||||
synchronized(EthernetNetworkFactory.this) {
|
|
||||||
if (this == mNetworkAgent) {
|
|
||||||
stopIpManagerLocked();
|
|
||||||
|
|
||||||
mLinkProperties.clear();
|
|
||||||
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null,
|
|
||||||
mHwAddr);
|
|
||||||
updateAgent();
|
|
||||||
mNetworkAgent = null;
|
|
||||||
try {
|
|
||||||
mNMService.clearInterfaceAddresses(mIface);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "Failed to clear addresses or disable ipv6" + e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "Ignoring unwanted as we have a more modern " +
|
|
||||||
"instance");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
mIpProvisioningThread = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DBG) {
|
|
||||||
Log.d(TAG, String.format("exiting ipProvisioningThread(%s): mNetworkInfo=%s",
|
|
||||||
mIface, mNetworkInfo));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
linkProperties = config.getStaticIpConfiguration().toLinkProperties(mIface);
|
||||||
|
} else {
|
||||||
|
mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr);
|
||||||
|
IpManager.Callback ipmCallback = new IpManager.Callback() {
|
||||||
|
@Override
|
||||||
|
public void onProvisioningSuccess(LinkProperties newLp) {
|
||||||
|
mHandler.post(() -> onIpLayerStarted(newLp));
|
||||||
|
}
|
||||||
|
|
||||||
synchronized(EthernetNetworkFactory.this) {
|
@Override
|
||||||
if (mIpProvisioningThread == null) {
|
public void onProvisioningFailure(LinkProperties newLp) {
|
||||||
mIpProvisioningThread = ipProvisioningThread;
|
mHandler.post(() -> onIpLayerStopped(newLp));
|
||||||
mIpProvisioningThread.start();
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLinkPropertiesChange(LinkProperties newLp) {
|
||||||
|
mHandler.post(() -> updateLinkProperties(newLp));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
stopIpManager();
|
||||||
|
mIpManager = new IpManager(mContext, mIface, ipmCallback);
|
||||||
|
|
||||||
|
if (config.getProxySettings() == ProxySettings.STATIC ||
|
||||||
|
config.getProxySettings() == ProxySettings.PAC) {
|
||||||
|
mIpManager.setHttpProxy(config.getHttpProxy());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final String tcpBufferSizes = mContext.getResources().getString(
|
||||||
|
com.android.internal.R.string.config_ethernet_tcp_buffers);
|
||||||
|
if (!TextUtils.isEmpty(tcpBufferSizes)) {
|
||||||
|
mIpManager.setTcpBufferSizes(tcpBufferSizes);
|
||||||
|
}
|
||||||
|
|
||||||
|
final ProvisioningConfiguration provisioningConfiguration =
|
||||||
|
mIpManager.buildProvisioningConfiguration()
|
||||||
|
.withProvisioningTimeoutMs(0)
|
||||||
|
.build();
|
||||||
|
mIpManager.startProvisioning(provisioningConfiguration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Begin monitoring connectivity
|
* Begin monitoring connectivity
|
||||||
*/
|
*/
|
||||||
public synchronized void start(Context context, Handler target) {
|
public void start(Context context, Handler handler) {
|
||||||
|
mHandler = handler;
|
||||||
|
|
||||||
// The services we use.
|
// The services we use.
|
||||||
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
|
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
|
||||||
mNMService = INetworkManagementService.Stub.asInterface(b);
|
mNMService = INetworkManagementService.Stub.asInterface(b);
|
||||||
@@ -420,9 +397,9 @@ class EthernetNetworkFactory {
|
|||||||
com.android.internal.R.string.config_ethernet_iface_regex);
|
com.android.internal.R.string.config_ethernet_iface_regex);
|
||||||
|
|
||||||
// Create and register our NetworkFactory.
|
// Create and register our NetworkFactory.
|
||||||
mFactory = new LocalNetworkFactory(NETWORK_TYPE, context, target.getLooper());
|
mFactory = new LocalNetworkFactory(NETWORK_TYPE, context, mHandler.getLooper());
|
||||||
mFactory.setCapabilityFilter(mNetworkCapabilities);
|
mFactory.setCapabilityFilter(mNetworkCapabilities);
|
||||||
mFactory.setScoreFilter(-1); // this set high when we have an iface
|
mFactory.setScoreFilter(NETWORK_SCORE);
|
||||||
mFactory.register();
|
mFactory.register();
|
||||||
|
|
||||||
mContext = context;
|
mContext = context;
|
||||||
@@ -437,23 +414,22 @@ class EthernetNetworkFactory {
|
|||||||
|
|
||||||
// If an Ethernet interface is already connected, start tracking that.
|
// If an Ethernet interface is already connected, start tracking that.
|
||||||
// Otherwise, the first Ethernet interface to appear will be tracked.
|
// Otherwise, the first Ethernet interface to appear will be tracked.
|
||||||
|
mHandler.post(() -> trackFirstAvailableInterface());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void trackFirstAvailableInterface() {
|
||||||
try {
|
try {
|
||||||
final String[] ifaces = mNMService.listInterfaces();
|
final String[] ifaces = mNMService.listInterfaces();
|
||||||
for (String iface : ifaces) {
|
for (String iface : ifaces) {
|
||||||
synchronized(this) {
|
if (maybeTrackInterface(iface)) {
|
||||||
if (maybeTrackInterface(iface)) {
|
// We have our interface. Track it.
|
||||||
// We have our interface. Track it.
|
// Note: if the interface already has link (e.g., if we crashed and got
|
||||||
// Note: if the interface already has link (e.g., if we
|
// restarted while it was running), we need to fake a link up notification so we
|
||||||
// crashed and got restarted while it was running),
|
// start configuring it.
|
||||||
// we need to fake a link up notification so we start
|
if (mNMService.getInterfaceConfig(iface).hasFlag("running")) {
|
||||||
// configuring it. Since we're already holding the lock,
|
updateInterfaceState(iface, true);
|
||||||
// any real link up/down notification will only arrive
|
|
||||||
// after we've done this.
|
|
||||||
if (mNMService.getInterfaceConfig(iface).hasFlag("running")) {
|
|
||||||
updateInterfaceState(iface, true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (RemoteException|IllegalStateException e) {
|
} catch (RemoteException|IllegalStateException e) {
|
||||||
@@ -461,21 +437,9 @@ class EthernetNetworkFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void stop() {
|
public void stop() {
|
||||||
stopIpProvisioningThreadLocked();
|
stopIpManager();
|
||||||
// ConnectivityService will only forget our NetworkAgent if we send it a NetworkInfo object
|
setInterfaceInfo("", null);
|
||||||
// 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.
|
|
||||||
//
|
|
||||||
// TODO: stop using explicit comparisons to DISCONNECTED / SUSPENDED in ConnectivityService,
|
|
||||||
// and instead use isConnectedOrConnecting().
|
|
||||||
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
|
|
||||||
mLinkUp = false;
|
|
||||||
updateAgent();
|
|
||||||
mLinkProperties = new LinkProperties();
|
|
||||||
mNetworkAgent = null;
|
|
||||||
setInterfaceInfoLocked("", null);
|
|
||||||
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, "");
|
|
||||||
mFactory.unregister();
|
mFactory.unregister();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,20 +453,22 @@ class EthernetNetworkFactory {
|
|||||||
mNetworkCapabilities.setLinkDownstreamBandwidthKbps(100 * 1000);
|
mNetworkCapabilities.setLinkDownstreamBandwidthKbps(100 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized boolean isTrackingInterface() {
|
public boolean isTrackingInterface() {
|
||||||
return !TextUtils.isEmpty(mIface);
|
return !TextUtils.isEmpty(mIface);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set interface information and notify listeners if availability is changed.
|
* Set interface information and notify listeners if availability is changed.
|
||||||
* This should be called with the lock held.
|
|
||||||
*/
|
*/
|
||||||
private void setInterfaceInfoLocked(String iface, String hwAddr) {
|
private void setInterfaceInfo(String iface, String hwAddr) {
|
||||||
boolean oldAvailable = isTrackingInterface();
|
boolean oldAvailable = isTrackingInterface();
|
||||||
mIface = iface;
|
mIface = iface;
|
||||||
mHwAddr = hwAddr;
|
mHwAddr = hwAddr;
|
||||||
boolean available = isTrackingInterface();
|
boolean available = isTrackingInterface();
|
||||||
|
|
||||||
|
mNetworkInfo.setExtraInfo(mHwAddr);
|
||||||
|
mNetworkInfo.setIsAvailable(available);
|
||||||
|
|
||||||
if (oldAvailable != available) {
|
if (oldAvailable != available) {
|
||||||
int n = mListeners.beginBroadcast();
|
int n = mListeners.beginBroadcast();
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
@@ -516,26 +482,46 @@ class EthernetNetworkFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
|
private void postAndWaitForRunnable(Runnable r) throws InterruptedException {
|
||||||
if (isTrackingInterface()) {
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
pw.println("Tracking interface: " + mIface);
|
mHandler.post(() -> {
|
||||||
pw.increaseIndent();
|
try {
|
||||||
pw.println("MAC address: " + mHwAddr);
|
r.run();
|
||||||
pw.println("Link state: " + (mLinkUp ? "up" : "down"));
|
} finally {
|
||||||
pw.decreaseIndent();
|
latch.countDown();
|
||||||
} else {
|
}
|
||||||
pw.println("Not tracking any interface");
|
});
|
||||||
}
|
latch.await();
|
||||||
|
}
|
||||||
|
|
||||||
pw.println();
|
|
||||||
pw.println("NetworkInfo: " + mNetworkInfo);
|
void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
|
||||||
pw.println("LinkProperties: " + mLinkProperties);
|
try {
|
||||||
pw.println("NetworkAgent: " + mNetworkAgent);
|
postAndWaitForRunnable(() -> {
|
||||||
if (mIpManager != null) {
|
pw.println("Network Requested: " + mNetworkRequested);
|
||||||
pw.println("IpManager:");
|
if (isTrackingInterface()) {
|
||||||
pw.increaseIndent();
|
pw.println("Tracking interface: " + mIface);
|
||||||
mIpManager.dump(fd, pw, args);
|
pw.increaseIndent();
|
||||||
pw.decreaseIndent();
|
pw.println("MAC address: " + mHwAddr);
|
||||||
|
pw.println("Link state: " + (mLinkUp ? "up" : "down"));
|
||||||
|
pw.decreaseIndent();
|
||||||
|
} else {
|
||||||
|
pw.println("Not tracking any interface");
|
||||||
|
}
|
||||||
|
|
||||||
|
pw.println();
|
||||||
|
pw.println("NetworkInfo: " + mNetworkInfo);
|
||||||
|
pw.println("LinkProperties: " + mLinkProperties);
|
||||||
|
pw.println("NetworkAgent: " + mNetworkAgent);
|
||||||
|
if (mIpManager != null) {
|
||||||
|
pw.println("IpManager:");
|
||||||
|
pw.increaseIndent();
|
||||||
|
mIpManager.dump(fd, pw, args);
|
||||||
|
pw.decreaseIndent();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new IllegalStateException("dump() interrupted");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user