Enable multiple active Ethernet interfaces
- reworked EthernetNetworkFactory to support multiple active Ethernet interfaces - allow vendors to specify network capabilities + ip config through XML config overlay Test: manual using hikey960 + multiple usb->eth adapters Change-Id: Ie39bcb0d2a3f960f497222159c7bd5797accaa68
This commit is contained in:
@@ -17,11 +17,8 @@
|
|||||||
package com.android.server.ethernet;
|
package com.android.server.ethernet;
|
||||||
|
|
||||||
import android.net.IpConfiguration;
|
import android.net.IpConfiguration;
|
||||||
import android.net.IpConfiguration.IpAssignment;
|
|
||||||
import android.net.IpConfiguration.ProxySettings;
|
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.util.Log;
|
import android.util.ArrayMap;
|
||||||
import android.util.SparseArray;
|
|
||||||
|
|
||||||
import com.android.server.net.IpConfigStore;
|
import com.android.server.net.IpConfigStore;
|
||||||
|
|
||||||
@@ -29,34 +26,60 @@ import com.android.server.net.IpConfigStore;
|
|||||||
/**
|
/**
|
||||||
* This class provides an API to store and manage Ethernet network configuration.
|
* This class provides an API to store and manage Ethernet network configuration.
|
||||||
*/
|
*/
|
||||||
public class EthernetConfigStore extends IpConfigStore {
|
public class EthernetConfigStore {
|
||||||
private static final String TAG = "EthernetConfigStore";
|
|
||||||
|
|
||||||
private static final String ipConfigFile = Environment.getDataDirectory() +
|
private static final String ipConfigFile = Environment.getDataDirectory() +
|
||||||
"/misc/ethernet/ipconfig.txt";
|
"/misc/ethernet/ipconfig.txt";
|
||||||
|
|
||||||
|
private IpConfigStore mStore = new IpConfigStore();
|
||||||
|
private ArrayMap<String, IpConfiguration> mIpConfigurations;
|
||||||
|
private IpConfiguration mIpConfigurationForDefaultInterface;
|
||||||
|
private final Object mSync = new Object();
|
||||||
|
|
||||||
public EthernetConfigStore() {
|
public EthernetConfigStore() {
|
||||||
|
mIpConfigurations = new ArrayMap<>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IpConfiguration readIpAndProxyConfigurations() {
|
public void read() {
|
||||||
SparseArray<IpConfiguration> networks = readIpAndProxyConfigurations(ipConfigFile);
|
synchronized (mSync) {
|
||||||
|
ArrayMap<String, IpConfiguration> configs =
|
||||||
|
IpConfigStore.readIpConfigurations(ipConfigFile);
|
||||||
|
|
||||||
if (networks.size() == 0) {
|
// This configuration may exist in old file versions when there was only a single active
|
||||||
Log.w(TAG, "No Ethernet configuration found. Using default.");
|
// Ethernet interface.
|
||||||
return new IpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, null, null);
|
if (configs.containsKey("0")) {
|
||||||
|
mIpConfigurationForDefaultInterface = configs.remove("0");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (networks.size() > 1) {
|
mIpConfigurations = configs;
|
||||||
// Currently we only support a single Ethernet interface.
|
}
|
||||||
Log.w(TAG, "Multiple Ethernet configurations detected. Only reading first one.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return networks.valueAt(0);
|
public void write(String iface, IpConfiguration config) {
|
||||||
|
boolean modified;
|
||||||
|
|
||||||
|
synchronized (mSync) {
|
||||||
|
if (config == null) {
|
||||||
|
modified = mIpConfigurations.remove(iface) != null;
|
||||||
|
} else {
|
||||||
|
IpConfiguration oldConfig = mIpConfigurations.put(iface, config);
|
||||||
|
modified = !config.equals(oldConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeIpAndProxyConfigurations(IpConfiguration config) {
|
if (modified) {
|
||||||
SparseArray<IpConfiguration> networks = new SparseArray<IpConfiguration>();
|
mStore.writeIpConfigurations(ipConfigFile, mIpConfigurations);
|
||||||
networks.put(0, config);
|
}
|
||||||
writeIpAndProxyConfigurations(ipConfigFile, networks);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayMap<String, IpConfiguration> getIpConfigurations() {
|
||||||
|
synchronized (mSync) {
|
||||||
|
return new ArrayMap<>(mIpConfigurations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IpConfiguration getIpConfigurationForDefaultInterface() {
|
||||||
|
synchronized (mSync) {
|
||||||
|
return new IpConfiguration(mIpConfigurationForDefaultInterface);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,9 @@
|
|||||||
|
|
||||||
package com.android.server.ethernet;
|
package com.android.server.ethernet;
|
||||||
|
|
||||||
|
import static android.net.ConnectivityManager.TYPE_ETHERNET;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.net.DhcpResults;
|
|
||||||
import android.net.EthernetManager;
|
|
||||||
import android.net.IEthernetServiceListener;
|
|
||||||
import android.net.InterfaceConfiguration;
|
|
||||||
import android.net.IpConfiguration;
|
import android.net.IpConfiguration;
|
||||||
import android.net.IpConfiguration.IpAssignment;
|
import android.net.IpConfiguration.IpAssignment;
|
||||||
import android.net.IpConfiguration.ProxySettings;
|
import android.net.IpConfiguration.ProxySettings;
|
||||||
@@ -31,292 +28,215 @@ 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.StaticIpConfiguration;
|
import android.net.NetworkRequest;
|
||||||
import android.net.ip.IpManager;
|
import android.net.NetworkSpecifier;
|
||||||
import android.net.ip.IpManager.ProvisioningConfiguration;
|
import android.net.StringNetworkSpecifier;
|
||||||
|
import android.net.ip.IpClient;
|
||||||
|
import android.net.ip.IpClient.ProvisioningConfiguration;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
|
||||||
import android.os.INetworkManagementService;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.os.RemoteCallbackList;
|
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.os.ServiceManager;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.internal.util.IndentingPrintWriter;
|
import com.android.internal.util.IndentingPrintWriter;
|
||||||
import com.android.server.net.BaseNetworkObserver;
|
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.PrintWriter;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages connectivity for an Ethernet interface.
|
* {@link NetworkFactory} that represents Ethernet networks.
|
||||||
*
|
*
|
||||||
* Ethernet Interfaces may be present at boot time or appear after boot (e.g.,
|
* This class reports a static network score of 70 when it is tracking an interface and that
|
||||||
* for Ethernet adapters connected over USB). This class currently supports
|
* interface's link is up, and a score of 0 otherwise.
|
||||||
* only one interface. When an interface appears on the system (or is present
|
|
||||||
* at boot time) this class will start tracking it and bring it up, and will
|
|
||||||
* attempt to connect when requested. Any other interfaces that subsequently
|
|
||||||
* appear will be ignored until the tracked interface disappears. Only
|
|
||||||
* interfaces whose names match the <code>config_ethernet_iface_regex</code>
|
|
||||||
* regular expression are tracked.
|
|
||||||
*
|
|
||||||
* This class reports a static network score of 70 when it is tracking an
|
|
||||||
* interface and that interface's link is up, and a score of 0 otherwise.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
*/
|
||||||
class EthernetNetworkFactory {
|
public class EthernetNetworkFactory extends NetworkFactory {
|
||||||
|
private final static String TAG = EthernetNetworkFactory.class.getSimpleName();
|
||||||
|
final static boolean DBG = true;
|
||||||
|
|
||||||
|
private final static int NETWORK_SCORE = 70;
|
||||||
private static final String NETWORK_TYPE = "Ethernet";
|
private static final String NETWORK_TYPE = "Ethernet";
|
||||||
private static final String TAG = "EthernetNetworkFactory";
|
|
||||||
private static final int NETWORK_SCORE = 70;
|
|
||||||
private static final boolean DBG = true;
|
|
||||||
|
|
||||||
/** Tracks interface changes. Called from NetworkManagementService. */
|
private final ConcurrentHashMap<String, NetworkInterfaceState> mTrackingInterfaces =
|
||||||
private InterfaceObserver mInterfaceObserver;
|
new ConcurrentHashMap<>();
|
||||||
|
private final Handler mHandler;
|
||||||
|
private final Context mContext;
|
||||||
|
|
||||||
/** For static IP configuration */
|
public EthernetNetworkFactory(Handler handler, Context context, NetworkCapabilities filter) {
|
||||||
private EthernetManager mEthernetManager;
|
super(handler.getLooper(), context, NETWORK_TYPE, filter);
|
||||||
|
|
||||||
/** To set link state and configure IP addresses. */
|
mHandler = handler;
|
||||||
private INetworkManagementService mNMService;
|
mContext = context;
|
||||||
|
|
||||||
/** All code runs here, including start(). */
|
setScoreFilter(NETWORK_SCORE);
|
||||||
private Handler mHandler;
|
|
||||||
|
|
||||||
/* To communicate with ConnectivityManager */
|
|
||||||
private NetworkCapabilities mNetworkCapabilities;
|
|
||||||
private NetworkAgent mNetworkAgent;
|
|
||||||
private LocalNetworkFactory mFactory;
|
|
||||||
private Context mContext;
|
|
||||||
|
|
||||||
/** Product-dependent regular expression of interface names we track. */
|
|
||||||
private static String mIfaceMatch = "";
|
|
||||||
|
|
||||||
/** To notify Ethernet status. */
|
|
||||||
private final RemoteCallbackList<IEthernetServiceListener> mListeners;
|
|
||||||
|
|
||||||
/** Data members. All accesses to these must be on the handler thread. */
|
|
||||||
private String mIface = "";
|
|
||||||
private String mHwAddr;
|
|
||||||
private boolean mLinkUp;
|
|
||||||
private NetworkInfo mNetworkInfo;
|
|
||||||
private LinkProperties mLinkProperties;
|
|
||||||
private IpManager mIpManager;
|
|
||||||
private boolean mNetworkRequested = false;
|
|
||||||
|
|
||||||
EthernetNetworkFactory(RemoteCallbackList<IEthernetServiceListener> listeners) {
|
|
||||||
initNetworkCapabilities();
|
|
||||||
clearInfo();
|
|
||||||
mListeners = listeners;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class LocalNetworkFactory extends NetworkFactory {
|
@Override
|
||||||
LocalNetworkFactory(String name, Context context, Looper looper) {
|
public boolean acceptRequest(NetworkRequest request, int score) {
|
||||||
super(looper, context, name, new NetworkCapabilities());
|
if (DBG) {
|
||||||
|
Log.d(TAG, "acceptRequest, request: " + request + ", score: " + score);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void startNetwork() {
|
return networkForRequest(request) != null;
|
||||||
if (!mNetworkRequested) {
|
}
|
||||||
mNetworkRequested = true;
|
|
||||||
maybeStartIpManager();
|
@Override
|
||||||
|
protected void needNetworkFor(NetworkRequest networkRequest, int score) {
|
||||||
|
NetworkInterfaceState network = networkForRequest(networkRequest);
|
||||||
|
|
||||||
|
if (network == null) {
|
||||||
|
Log.e(TAG, "needNetworkFor, failed to get a network for " + networkRequest);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++network.refCount == 1) {
|
||||||
|
network.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void stopNetwork() {
|
@Override
|
||||||
mNetworkRequested = false;
|
protected void releaseNetworkFor(NetworkRequest networkRequest) {
|
||||||
stopIpManager();
|
NetworkInterfaceState network = networkForRequest(networkRequest);
|
||||||
}
|
if (network == null) {
|
||||||
|
Log.e(TAG, "needNetworkFor, failed to get a network for " + networkRequest);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearInfo() {
|
if (--network.refCount == 1) {
|
||||||
mLinkProperties = new LinkProperties();
|
network.stop();
|
||||||
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, "");
|
|
||||||
mNetworkInfo.setExtraInfo(mHwAddr);
|
|
||||||
mNetworkInfo.setIsAvailable(isTrackingInterface());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopIpManager() {
|
|
||||||
if (mIpManager != null) {
|
|
||||||
mIpManager.shutdown();
|
|
||||||
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:
|
|
||||||
// that sets the state to IDLE, and ConnectivityService will still think we're connected.
|
|
||||||
//
|
|
||||||
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
|
|
||||||
if (mNetworkAgent != null) {
|
|
||||||
updateAgent();
|
|
||||||
mNetworkAgent = null;
|
|
||||||
}
|
|
||||||
clearInfo();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates interface state variables.
|
* Returns an array of available interface names. The array is sorted: unrestricted interfaces
|
||||||
* Called on link state changes or on startup.
|
* goes first, then sorted by name.
|
||||||
*/
|
*/
|
||||||
private void updateInterfaceState(String iface, boolean up) {
|
String[] getAvailableInterfaces(boolean includeRestricted) {
|
||||||
if (!mIface.equals(iface)) {
|
return mTrackingInterfaces.values()
|
||||||
return;
|
.stream()
|
||||||
}
|
.filter(iface -> !iface.isRestricted() || includeRestricted)
|
||||||
Log.d(TAG, "updateInterface: " + iface + " link " + (up ? "up" : "down"));
|
.sorted((iface1, iface2) -> {
|
||||||
|
int r = Boolean.compare(iface1.isRestricted(), iface2.isRestricted());
|
||||||
mLinkUp = up;
|
return r == 0 ? iface1.name.compareTo(iface2.name) : r;
|
||||||
if (up) {
|
})
|
||||||
maybeStartIpManager();
|
.map(iface -> iface.name)
|
||||||
} else {
|
.toArray(String[]::new);
|
||||||
stopIpManager();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class InterfaceObserver extends BaseNetworkObserver {
|
void addInterface(String ifaceName, String hwAddress, NetworkCapabilities capabilities,
|
||||||
@Override
|
IpConfiguration ipConfiguration) {
|
||||||
public void interfaceLinkStateChanged(String iface, boolean up) {
|
if (mTrackingInterfaces.containsKey(ifaceName)) {
|
||||||
mHandler.post(() -> {
|
Log.e(TAG, "Interface with name " + ifaceName + " already exists.");
|
||||||
updateInterfaceState(iface, up);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void interfaceAdded(String iface) {
|
|
||||||
mHandler.post(() -> {
|
|
||||||
maybeTrackInterface(iface);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void interfaceRemoved(String iface) {
|
|
||||||
mHandler.post(() -> {
|
|
||||||
if (stopTrackingInterface(iface)) {
|
|
||||||
trackFirstAvailableInterface();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setInterfaceUp(String iface) {
|
|
||||||
// Bring up the interface so we get link status indications.
|
|
||||||
try {
|
|
||||||
mNMService.setInterfaceUp(iface);
|
|
||||||
String hwAddr = null;
|
|
||||||
InterfaceConfiguration config = mNMService.getInterfaceConfig(iface);
|
|
||||||
|
|
||||||
if (config == null) {
|
|
||||||
Log.e(TAG, "Null interface config for " + iface + ". Bailing out.");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isTrackingInterface()) {
|
|
||||||
setInterfaceInfo(iface, config.getHardwareAddress());
|
|
||||||
mNetworkInfo.setIsAvailable(true);
|
|
||||||
mNetworkInfo.setExtraInfo(mHwAddr);
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "Interface unexpectedly changed from " + iface + " to " + mIface);
|
|
||||||
mNMService.setInterfaceDown(iface);
|
|
||||||
}
|
|
||||||
} catch (RemoteException | IllegalStateException e) {
|
|
||||||
// Either the system is crashing or the interface has disappeared. Just ignore the
|
|
||||||
// error; we haven't modified any state because we only do that if our calls succeed.
|
|
||||||
Log.e(TAG, "Error upping interface " + mIface + ": " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean maybeTrackInterface(String iface) {
|
|
||||||
// If we don't already have an interface, and if this interface matches
|
|
||||||
// our regex, start tracking it.
|
|
||||||
if (!iface.matches(mIfaceMatch) || isTrackingInterface())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Log.d(TAG, "Started tracking interface " + iface);
|
|
||||||
setInterfaceUp(iface);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean stopTrackingInterface(String iface) {
|
|
||||||
if (!iface.equals(mIface))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Log.d(TAG, "Stopped tracking interface " + iface);
|
|
||||||
setInterfaceInfo("", null);
|
|
||||||
stopIpManager();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateAgent() {
|
|
||||||
if (mNetworkAgent == null) return;
|
|
||||||
if (DBG) {
|
if (DBG) {
|
||||||
Log.i(TAG, "Updating mNetworkAgent with: " +
|
Log.d(TAG, "addInterface, iface: " + ifaceName + ", capabilities: " + capabilities);
|
||||||
mNetworkCapabilities + ", " +
|
|
||||||
mNetworkInfo + ", " +
|
|
||||||
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) {
|
NetworkInterfaceState iface = new NetworkInterfaceState(
|
||||||
if (mNetworkAgent != null) {
|
ifaceName, hwAddress, mHandler, mContext, capabilities);
|
||||||
Log.e(TAG, "Already have a NetworkAgent - aborting new request");
|
iface.setIpConfig(ipConfiguration);
|
||||||
stopIpManager();
|
mTrackingInterfaces.put(ifaceName, iface);
|
||||||
return;
|
|
||||||
}
|
|
||||||
mLinkProperties = linkProperties;
|
|
||||||
mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr);
|
|
||||||
|
|
||||||
// Create our NetworkAgent.
|
updateCapabilityFilter();
|
||||||
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.
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void onIpLayerStopped(LinkProperties linkProperties) {
|
private void updateCapabilityFilter() {
|
||||||
// This cannot happen due to provisioning timeout, because our timeout is 0. It can only
|
NetworkCapabilities capabilitiesFilter = new NetworkCapabilities();
|
||||||
// happen if we're provisioned and we lose provisioning.
|
capabilitiesFilter.clearAll();
|
||||||
stopIpManager();
|
|
||||||
maybeStartIpManager();
|
for (NetworkInterfaceState iface: mTrackingInterfaces.values()) {
|
||||||
|
capabilitiesFilter.combineCapabilities(iface.mCapabilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateLinkProperties(LinkProperties linkProperties) {
|
if (DBG) Log.d(TAG, "updateCapabilityFilter: " + capabilitiesFilter);
|
||||||
mLinkProperties = linkProperties;
|
setCapabilityFilter(capabilitiesFilter);
|
||||||
if (mNetworkAgent != null) {
|
|
||||||
mNetworkAgent.sendLinkProperties(linkProperties);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void maybeStartIpManager() {
|
void removeInterface(String interfaceName) {
|
||||||
if (mNetworkRequested && mIpManager == null && isTrackingInterface()) {
|
NetworkInterfaceState iface = mTrackingInterfaces.remove(interfaceName);
|
||||||
startIpManager();
|
if (iface != null) {
|
||||||
}
|
iface.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCapabilityFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if state has been modified */
|
||||||
|
boolean updateInterfaceLinkState(String ifaceName, boolean up) {
|
||||||
|
if (!mTrackingInterfaces.containsKey(ifaceName)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startIpManager() {
|
|
||||||
if (DBG) {
|
if (DBG) {
|
||||||
Log.d(TAG, String.format("starting IpManager(%s): mNetworkInfo=%s", mIface,
|
Log.d(TAG, "updateInterfaceLinkState, iface: " + ifaceName + ", up: " + up);
|
||||||
mNetworkInfo));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IpConfiguration config = mEthernetManager.getConfiguration();
|
NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName);
|
||||||
|
return iface.updateLinkState(up);
|
||||||
|
}
|
||||||
|
|
||||||
mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr);
|
boolean hasInterface(String interfacName) {
|
||||||
IpManager.Callback ipmCallback = new IpManager.Callback() {
|
return mTrackingInterfaces.containsKey(interfacName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) {
|
||||||
|
NetworkInterfaceState network = mTrackingInterfaces.get(iface);
|
||||||
|
if (network != null) {
|
||||||
|
network.setIpConfig(ipConfiguration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private NetworkInterfaceState networkForRequest(NetworkRequest request) {
|
||||||
|
String requestedIface = null;
|
||||||
|
|
||||||
|
NetworkSpecifier specifier = request.networkCapabilities.getNetworkSpecifier();
|
||||||
|
if (specifier instanceof StringNetworkSpecifier) {
|
||||||
|
requestedIface = ((StringNetworkSpecifier) specifier).specifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkInterfaceState network = null;
|
||||||
|
if (!TextUtils.isEmpty(requestedIface)) {
|
||||||
|
NetworkInterfaceState n = mTrackingInterfaces.get(requestedIface);
|
||||||
|
if (n != null && n.statisified(request.networkCapabilities)) {
|
||||||
|
network = n;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (NetworkInterfaceState n : mTrackingInterfaces.values()) {
|
||||||
|
if (n.statisified(request.networkCapabilities)) {
|
||||||
|
network = n;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DBG) {
|
||||||
|
Log.i(TAG, "networkForRequest, request: " + request + ", network: " + network);
|
||||||
|
}
|
||||||
|
|
||||||
|
return network;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class NetworkInterfaceState {
|
||||||
|
final String name;
|
||||||
|
|
||||||
|
private final String mHwAddress;
|
||||||
|
private final NetworkCapabilities mCapabilities;
|
||||||
|
private final Handler mHandler;
|
||||||
|
private final Context mContext;
|
||||||
|
private final NetworkInfo mNetworkInfo;
|
||||||
|
|
||||||
|
private static String sTcpBufferSizes = null; // Lazy initialized.
|
||||||
|
|
||||||
|
private boolean mLinkUp;
|
||||||
|
private LinkProperties mLinkProperties = new LinkProperties();
|
||||||
|
|
||||||
|
private IpClient mIpClient;
|
||||||
|
private NetworkAgent mNetworkAgent;
|
||||||
|
private IpConfiguration mIpConfig;
|
||||||
|
|
||||||
|
long refCount = 0;
|
||||||
|
|
||||||
|
private final IpClient.Callback mIpClientCallback = new IpClient.Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void onProvisioningSuccess(LinkProperties newLp) {
|
public void onProvisioningSuccess(LinkProperties newLp) {
|
||||||
mHandler.post(() -> onIpLayerStarted(newLp));
|
mHandler.post(() -> onIpLayerStarted(newLp));
|
||||||
@@ -333,178 +253,191 @@ class EthernetNetworkFactory {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
stopIpManager();
|
NetworkInterfaceState(String ifaceName, String hwAddress, Handler handler, Context context,
|
||||||
mIpManager = new IpManager(mContext, mIface, ipmCallback);
|
NetworkCapabilities capabilities) {
|
||||||
|
name = ifaceName;
|
||||||
|
mCapabilities = capabilities;
|
||||||
|
mHandler = handler;
|
||||||
|
mContext = context;
|
||||||
|
|
||||||
if (config.getProxySettings() == ProxySettings.STATIC ||
|
mHwAddress = hwAddress;
|
||||||
config.getProxySettings() == ProxySettings.PAC) {
|
mNetworkInfo = new NetworkInfo(TYPE_ETHERNET, 0, NETWORK_TYPE, "");
|
||||||
mIpManager.setHttpProxy(config.getHttpProxy());
|
mNetworkInfo.setExtraInfo(mHwAddress);
|
||||||
|
mNetworkInfo.setIsAvailable(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
final String tcpBufferSizes = mContext.getResources().getString(
|
void setIpConfig(IpConfiguration ipConfig) {
|
||||||
|
|
||||||
|
this.mIpConfig = ipConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean statisified(NetworkCapabilities requestedCapabilities) {
|
||||||
|
return requestedCapabilities.satisfiedByNetworkCapabilities(mCapabilities);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isRestricted() {
|
||||||
|
return mCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void start() {
|
||||||
|
if (DBG) {
|
||||||
|
Log.d(TAG, String.format("starting IpClient(%s): mNetworkInfo=%s", name,
|
||||||
|
mNetworkInfo));
|
||||||
|
}
|
||||||
|
if (mIpClient != null) stop();
|
||||||
|
|
||||||
|
mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddress);
|
||||||
|
|
||||||
|
mIpClient = new IpClient(mContext, name, mIpClientCallback);
|
||||||
|
|
||||||
|
if (sTcpBufferSizes == null) {
|
||||||
|
sTcpBufferSizes = mContext.getResources().getString(
|
||||||
com.android.internal.R.string.config_ethernet_tcp_buffers);
|
com.android.internal.R.string.config_ethernet_tcp_buffers);
|
||||||
|
}
|
||||||
|
provisionIpClient(mIpClient, mIpConfig, sTcpBufferSizes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onIpLayerStarted(LinkProperties linkProperties) {
|
||||||
|
if (mNetworkAgent != null) {
|
||||||
|
Log.e(TAG, "Already have a NetworkAgent - aborting new request");
|
||||||
|
stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mLinkProperties = linkProperties;
|
||||||
|
mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddress);
|
||||||
|
mNetworkInfo.setIsAvailable(true);
|
||||||
|
|
||||||
|
// Create our NetworkAgent.
|
||||||
|
mNetworkAgent = new NetworkAgent(mHandler.getLooper(), mContext,
|
||||||
|
NETWORK_TYPE, mNetworkInfo, mCapabilities, mLinkProperties,
|
||||||
|
NETWORK_SCORE) {
|
||||||
|
public void unwanted() {
|
||||||
|
if (this == mNetworkAgent) {
|
||||||
|
stop();
|
||||||
|
} else if (mNetworkAgent != null) {
|
||||||
|
Log.d(TAG, "Ignoring unwanted as we have a more modern " +
|
||||||
|
"instance");
|
||||||
|
} // Otherwise, we've already called stop.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void onIpLayerStopped(LinkProperties linkProperties) {
|
||||||
|
// This cannot happen due to provisioning timeout, because our timeout is 0. It can only
|
||||||
|
// happen if we're provisioned and we lose provisioning.
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateLinkProperties(LinkProperties linkProperties) {
|
||||||
|
mLinkProperties = linkProperties;
|
||||||
|
if (mNetworkAgent != null) {
|
||||||
|
mNetworkAgent.sendLinkProperties(linkProperties);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if state has been modified */
|
||||||
|
boolean updateLinkState(boolean up) {
|
||||||
|
if (mLinkUp == up) return false;
|
||||||
|
|
||||||
|
mLinkUp = up;
|
||||||
|
if (up) {
|
||||||
|
start();
|
||||||
|
} else {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop() {
|
||||||
|
if (mIpClient != null) {
|
||||||
|
mIpClient.shutdown();
|
||||||
|
mIpClient = 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:
|
||||||
|
// that sets the state to IDLE, and ConnectivityService will still think we're connected.
|
||||||
|
//
|
||||||
|
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddress);
|
||||||
|
if (mNetworkAgent != null) {
|
||||||
|
updateAgent();
|
||||||
|
mNetworkAgent = null;
|
||||||
|
}
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateAgent() {
|
||||||
|
if (mNetworkAgent == null) return;
|
||||||
|
if (DBG) {
|
||||||
|
Log.i(TAG, "Updating mNetworkAgent with: " +
|
||||||
|
mCapabilities + ", " +
|
||||||
|
mNetworkInfo + ", " +
|
||||||
|
mLinkProperties);
|
||||||
|
}
|
||||||
|
mNetworkAgent.sendNetworkCapabilities(mCapabilities);
|
||||||
|
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
|
||||||
|
mNetworkAgent.sendLinkProperties(mLinkProperties);
|
||||||
|
// never set the network score below 0.
|
||||||
|
mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clear() {
|
||||||
|
mLinkProperties.clear();
|
||||||
|
mNetworkInfo.setDetailedState(DetailedState.IDLE, null, null);
|
||||||
|
mNetworkInfo.setIsAvailable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void provisionIpClient(IpClient ipClient, IpConfiguration config,
|
||||||
|
String tcpBufferSizes) {
|
||||||
|
if (config.getProxySettings() == ProxySettings.STATIC ||
|
||||||
|
config.getProxySettings() == ProxySettings.PAC) {
|
||||||
|
ipClient.setHttpProxy(config.getHttpProxy());
|
||||||
|
}
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(tcpBufferSizes)) {
|
if (!TextUtils.isEmpty(tcpBufferSizes)) {
|
||||||
mIpManager.setTcpBufferSizes(tcpBufferSizes);
|
ipClient.setTcpBufferSizes(tcpBufferSizes);
|
||||||
}
|
}
|
||||||
|
|
||||||
final ProvisioningConfiguration provisioningConfiguration;
|
final ProvisioningConfiguration provisioningConfiguration;
|
||||||
if (config.getIpAssignment() == IpAssignment.STATIC) {
|
if (config.getIpAssignment() == IpAssignment.STATIC) {
|
||||||
provisioningConfiguration = IpManager.buildProvisioningConfiguration()
|
provisioningConfiguration = IpClient.buildProvisioningConfiguration()
|
||||||
.withStaticConfiguration(config.getStaticIpConfiguration())
|
.withStaticConfiguration(config.getStaticIpConfiguration())
|
||||||
.build();
|
.build();
|
||||||
} else {
|
} else {
|
||||||
provisioningConfiguration = mIpManager.buildProvisioningConfiguration()
|
provisioningConfiguration = IpClient.buildProvisioningConfiguration()
|
||||||
.withProvisioningTimeoutMs(0)
|
.withProvisioningTimeoutMs(0)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
mIpManager.startProvisioning(provisioningConfiguration);
|
ipClient.startProvisioning(provisioningConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Begin monitoring connectivity
|
public String toString() {
|
||||||
*/
|
return getClass().getSimpleName() + "{ "
|
||||||
public void start(Context context, Handler handler) {
|
+ "iface: " + name + ", "
|
||||||
mHandler = handler;
|
+ "up: " + mLinkUp + ", "
|
||||||
|
+ "hwAddress: " + mHwAddress + ", "
|
||||||
// The services we use.
|
+ "networkInfo: " + mNetworkInfo + ", "
|
||||||
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
|
+ "networkAgent: " + mNetworkAgent + ", "
|
||||||
mNMService = INetworkManagementService.Stub.asInterface(b);
|
+ "ipClient: " + mIpClient + ","
|
||||||
mEthernetManager = (EthernetManager) context.getSystemService(Context.ETHERNET_SERVICE);
|
+ "linkProperties: " + mLinkProperties
|
||||||
|
+ "}";
|
||||||
// Interface match regex.
|
|
||||||
mIfaceMatch = context.getResources().getString(
|
|
||||||
com.android.internal.R.string.config_ethernet_iface_regex);
|
|
||||||
|
|
||||||
// Create and register our NetworkFactory.
|
|
||||||
mFactory = new LocalNetworkFactory(NETWORK_TYPE, context, mHandler.getLooper());
|
|
||||||
mFactory.setCapabilityFilter(mNetworkCapabilities);
|
|
||||||
mFactory.setScoreFilter(NETWORK_SCORE);
|
|
||||||
mFactory.register();
|
|
||||||
|
|
||||||
mContext = context;
|
|
||||||
|
|
||||||
// Start tracking interface change events.
|
|
||||||
mInterfaceObserver = new InterfaceObserver();
|
|
||||||
try {
|
|
||||||
mNMService.registerObserver(mInterfaceObserver);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "Could not register InterfaceObserver " + e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If an Ethernet interface is already connected, start tracking that.
|
|
||||||
// Otherwise, the first Ethernet interface to appear will be tracked.
|
|
||||||
mHandler.post(() -> trackFirstAvailableInterface());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void trackFirstAvailableInterface() {
|
|
||||||
try {
|
|
||||||
final String[] ifaces = mNMService.listInterfaces();
|
|
||||||
for (String iface : ifaces) {
|
|
||||||
if (maybeTrackInterface(iface)) {
|
|
||||||
// We have our interface. Track it.
|
|
||||||
// Note: if the interface already has link (e.g., if we crashed and got
|
|
||||||
// restarted while it was running), we need to fake a link up notification so we
|
|
||||||
// start configuring it.
|
|
||||||
if (mNMService.getInterfaceConfig(iface).hasFlag("running")) {
|
|
||||||
updateInterfaceState(iface, true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (RemoteException|IllegalStateException e) {
|
|
||||||
Log.e(TAG, "Could not get list of interfaces " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
stopIpManager();
|
|
||||||
setInterfaceInfo("", null);
|
|
||||||
mFactory.unregister();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initNetworkCapabilities() {
|
|
||||||
mNetworkCapabilities = new NetworkCapabilities();
|
|
||||||
mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET);
|
|
||||||
mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
|
|
||||||
mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
|
|
||||||
mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
|
|
||||||
mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED);
|
|
||||||
mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
|
|
||||||
// We have no useful data on bandwidth. Say 100M up and 100M down. :-(
|
|
||||||
mNetworkCapabilities.setLinkUpstreamBandwidthKbps(100 * 1000);
|
|
||||||
mNetworkCapabilities.setLinkDownstreamBandwidthKbps(100 * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isTrackingInterface() {
|
|
||||||
return !TextUtils.isEmpty(mIface);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set interface information and notify listeners if availability is changed.
|
|
||||||
*/
|
|
||||||
private void setInterfaceInfo(String iface, String hwAddr) {
|
|
||||||
boolean oldAvailable = isTrackingInterface();
|
|
||||||
mIface = iface;
|
|
||||||
mHwAddr = hwAddr;
|
|
||||||
boolean available = isTrackingInterface();
|
|
||||||
|
|
||||||
mNetworkInfo.setExtraInfo(mHwAddr);
|
|
||||||
mNetworkInfo.setIsAvailable(available);
|
|
||||||
|
|
||||||
if (oldAvailable != available) {
|
|
||||||
int n = mListeners.beginBroadcast();
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
try {
|
|
||||||
mListeners.getBroadcastItem(i).onAvailabilityChanged(available);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
// Do nothing here.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mListeners.finishBroadcast();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void postAndWaitForRunnable(Runnable r) throws InterruptedException {
|
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
|
||||||
mHandler.post(() -> {
|
|
||||||
try {
|
|
||||||
r.run();
|
|
||||||
} finally {
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
latch.await();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
|
void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
|
||||||
try {
|
super.dump(fd, pw, args);
|
||||||
postAndWaitForRunnable(() -> {
|
pw.println(getClass().getSimpleName());
|
||||||
pw.println("Network Requested: " + mNetworkRequested);
|
pw.println("Tracking interfaces:");
|
||||||
if (isTrackingInterface()) {
|
|
||||||
pw.println("Tracking interface: " + mIface);
|
|
||||||
pw.increaseIndent();
|
pw.increaseIndent();
|
||||||
pw.println("MAC address: " + mHwAddr);
|
for (String iface: mTrackingInterfaces.keySet()) {
|
||||||
pw.println("Link state: " + (mLinkUp ? "up" : "down"));
|
NetworkInterfaceState ifaceState = mTrackingInterfaces.get(iface);
|
||||||
pw.decreaseIndent();
|
pw.println(iface + ":" + ifaceState);
|
||||||
} 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();
|
pw.increaseIndent();
|
||||||
mIpManager.dump(fd, pw, args);
|
ifaceState.mIpClient.dump(fd, pw, args);
|
||||||
pw.decreaseIndent();
|
pw.decreaseIndent();
|
||||||
}
|
}
|
||||||
});
|
pw.decreaseIndent();
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new IllegalStateException("dump() interrupted");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,14 +21,10 @@ import android.content.pm.PackageManager;
|
|||||||
import android.net.IEthernetManager;
|
import android.net.IEthernetManager;
|
||||||
import android.net.IEthernetServiceListener;
|
import android.net.IEthernetServiceListener;
|
||||||
import android.net.IpConfiguration;
|
import android.net.IpConfiguration;
|
||||||
import android.net.IpConfiguration.IpAssignment;
|
|
||||||
import android.net.IpConfiguration.ProxySettings;
|
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.os.RemoteCallbackList;
|
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.provider.Settings;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.PrintWriterPrinter;
|
import android.util.PrintWriterPrinter;
|
||||||
|
|
||||||
@@ -41,31 +37,18 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
/**
|
/**
|
||||||
* EthernetServiceImpl handles remote Ethernet operation requests by implementing
|
* EthernetServiceImpl handles remote Ethernet operation requests by implementing
|
||||||
* the IEthernetManager interface.
|
* the IEthernetManager interface.
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
*/
|
||||||
public class EthernetServiceImpl extends IEthernetManager.Stub {
|
public class EthernetServiceImpl extends IEthernetManager.Stub {
|
||||||
private static final String TAG = "EthernetServiceImpl";
|
private static final String TAG = "EthernetServiceImpl";
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final EthernetConfigStore mEthernetConfigStore;
|
|
||||||
private final AtomicBoolean mStarted = new AtomicBoolean(false);
|
private final AtomicBoolean mStarted = new AtomicBoolean(false);
|
||||||
private IpConfiguration mIpConfiguration;
|
|
||||||
|
|
||||||
private Handler mHandler;
|
private Handler mHandler;
|
||||||
private final EthernetNetworkFactory mTracker;
|
private EthernetTracker mTracker;
|
||||||
private final RemoteCallbackList<IEthernetServiceListener> mListeners =
|
|
||||||
new RemoteCallbackList<IEthernetServiceListener>();
|
|
||||||
|
|
||||||
public EthernetServiceImpl(Context context) {
|
public EthernetServiceImpl(Context context) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
Log.i(TAG, "Creating EthernetConfigStore");
|
|
||||||
mEthernetConfigStore = new EthernetConfigStore();
|
|
||||||
mIpConfiguration = mEthernetConfigStore.readIpAndProxyConfigurations();
|
|
||||||
|
|
||||||
Log.i(TAG, "Read stored IP configuration: " + mIpConfiguration);
|
|
||||||
|
|
||||||
mTracker = new EthernetNetworkFactory(mListeners);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enforceAccessPermission() {
|
private void enforceAccessPermission() {
|
||||||
@@ -80,6 +63,18 @@ public class EthernetServiceImpl extends IEthernetManager.Stub {
|
|||||||
"ConnectivityService");
|
"ConnectivityService");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void enforceUseRestrictedNetworksPermission() {
|
||||||
|
mContext.enforceCallingOrSelfPermission(
|
||||||
|
android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS,
|
||||||
|
"ConnectivityService");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkUseRestrictedNetworksPermission() {
|
||||||
|
return mContext.checkCallingOrSelfPermission(
|
||||||
|
android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS)
|
||||||
|
== PackageManager.PERMISSION_GRANTED;
|
||||||
|
}
|
||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
Log.i(TAG, "Starting Ethernet service");
|
Log.i(TAG, "Starting Ethernet service");
|
||||||
|
|
||||||
@@ -87,60 +82,68 @@ public class EthernetServiceImpl extends IEthernetManager.Stub {
|
|||||||
handlerThread.start();
|
handlerThread.start();
|
||||||
mHandler = new Handler(handlerThread.getLooper());
|
mHandler = new Handler(handlerThread.getLooper());
|
||||||
|
|
||||||
mTracker.start(mContext, mHandler);
|
mTracker = new EthernetTracker(mContext, mHandler);
|
||||||
|
mTracker.start();
|
||||||
|
|
||||||
mStarted.set(true);
|
mStarted.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getAvailableInterfaces() throws RemoteException {
|
||||||
|
return mTracker.getInterfaces(checkUseRestrictedNetworksPermission());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Ethernet configuration
|
* Get Ethernet configuration
|
||||||
* @return the Ethernet Configuration, contained in {@link IpConfiguration}.
|
* @return the Ethernet Configuration, contained in {@link IpConfiguration}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public IpConfiguration getConfiguration() {
|
public IpConfiguration getConfiguration(String iface) {
|
||||||
enforceAccessPermission();
|
enforceAccessPermission();
|
||||||
|
|
||||||
synchronized (mIpConfiguration) {
|
if (mTracker.isRestrictedInterface(iface)) {
|
||||||
return new IpConfiguration(mIpConfiguration);
|
enforceUseRestrictedNetworksPermission();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new IpConfiguration(mTracker.getIpConfiguration(iface));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set Ethernet configuration
|
* Set Ethernet configuration
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setConfiguration(IpConfiguration config) {
|
public void setConfiguration(String iface, IpConfiguration config) {
|
||||||
if (!mStarted.get()) {
|
if (!mStarted.get()) {
|
||||||
Log.w(TAG, "System isn't ready enough to change ethernet configuration");
|
Log.w(TAG, "System isn't ready enough to change ethernet configuration");
|
||||||
}
|
}
|
||||||
|
|
||||||
enforceConnectivityInternalPermission();
|
enforceConnectivityInternalPermission();
|
||||||
|
|
||||||
synchronized (mIpConfiguration) {
|
if (mTracker.isRestrictedInterface(iface)) {
|
||||||
mEthernetConfigStore.writeIpAndProxyConfigurations(config);
|
enforceUseRestrictedNetworksPermission();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: this does not check proxy settings, gateways, etc.
|
// TODO: this does not check proxy settings, gateways, etc.
|
||||||
// Fix this by making IpConfiguration a complete representation of static configuration.
|
// Fix this by making IpConfiguration a complete representation of static configuration.
|
||||||
if (!config.equals(mIpConfiguration)) {
|
mTracker.updateIpConfiguration(iface, new IpConfiguration(config));
|
||||||
mIpConfiguration = new IpConfiguration(config);
|
|
||||||
mTracker.stop();
|
|
||||||
mTracker.start(mContext, mHandler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether the system currently has one or more
|
* Indicates whether given interface is available.
|
||||||
* Ethernet interfaces.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean isAvailable() {
|
public boolean isAvailable(String iface) {
|
||||||
enforceAccessPermission();
|
enforceAccessPermission();
|
||||||
return mTracker.isTrackingInterface();
|
|
||||||
|
if (mTracker.isRestrictedInterface(iface)) {
|
||||||
|
enforceUseRestrictedNetworksPermission();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mTracker.isTrackingInterface(iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Addes a listener.
|
* Adds a listener.
|
||||||
* @param listener A {@link IEthernetServiceListener} to add.
|
* @param listener A {@link IEthernetServiceListener} to add.
|
||||||
*/
|
*/
|
||||||
public void addListener(IEthernetServiceListener listener) {
|
public void addListener(IEthernetServiceListener listener) {
|
||||||
@@ -148,7 +151,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub {
|
|||||||
throw new IllegalArgumentException("listener must not be null");
|
throw new IllegalArgumentException("listener must not be null");
|
||||||
}
|
}
|
||||||
enforceAccessPermission();
|
enforceAccessPermission();
|
||||||
mListeners.register(listener);
|
mTracker.addListener(listener, checkUseRestrictedNetworksPermission());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -160,7 +163,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub {
|
|||||||
throw new IllegalArgumentException("listener must not be null");
|
throw new IllegalArgumentException("listener must not be null");
|
||||||
}
|
}
|
||||||
enforceAccessPermission();
|
enforceAccessPermission();
|
||||||
mListeners.unregister(listener);
|
mTracker.removeListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -179,12 +182,6 @@ public class EthernetServiceImpl extends IEthernetManager.Stub {
|
|||||||
mTracker.dump(fd, pw, args);
|
mTracker.dump(fd, pw, args);
|
||||||
pw.decreaseIndent();
|
pw.decreaseIndent();
|
||||||
|
|
||||||
pw.println();
|
|
||||||
pw.println("Stored Ethernet configuration: ");
|
|
||||||
pw.increaseIndent();
|
|
||||||
pw.println(mIpConfiguration);
|
|
||||||
pw.decreaseIndent();
|
|
||||||
|
|
||||||
pw.println("Handler:");
|
pw.println("Handler:");
|
||||||
pw.increaseIndent();
|
pw.increaseIndent();
|
||||||
mHandler.dump(new PrintWriterPrinter(pw), "EthernetServiceImpl");
|
mHandler.dump(new PrintWriterPrinter(pw), "EthernetServiceImpl");
|
||||||
|
|||||||
383
service-t/src/com/android/server/ethernet/EthernetTracker.java
Normal file
383
service-t/src/com/android/server/ethernet/EthernetTracker.java
Normal file
@@ -0,0 +1,383 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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 com.android.server.ethernet;
|
||||||
|
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.IEthernetServiceListener;
|
||||||
|
import android.net.InterfaceConfiguration;
|
||||||
|
import android.net.IpConfiguration;
|
||||||
|
import android.net.IpConfiguration.IpAssignment;
|
||||||
|
import android.net.IpConfiguration.ProxySettings;
|
||||||
|
import android.net.LinkAddress;
|
||||||
|
import android.net.NetworkCapabilities;
|
||||||
|
import android.net.StaticIpConfiguration;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.INetworkManagementService;
|
||||||
|
import android.os.RemoteCallbackList;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.os.ServiceManager;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.ArrayMap;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.internal.util.IndentingPrintWriter;
|
||||||
|
import com.android.server.net.BaseNetworkObserver;
|
||||||
|
|
||||||
|
import java.io.FileDescriptor;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks Ethernet interfaces and manages interface configurations.
|
||||||
|
*
|
||||||
|
* <p>Interfaces may have different {@link android.net.NetworkCapabilities}. This mapping is defined
|
||||||
|
* in {@code config_ethernet_interfaces}. Notably, some interfaces could be marked as restricted by
|
||||||
|
* not specifying {@link android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED} flag.
|
||||||
|
* Interfaces could have associated {@link android.net.IpConfiguration}.
|
||||||
|
* Ethernet Interfaces may be present at boot time or appear after boot (e.g., for Ethernet adapters
|
||||||
|
* connected over USB). This class supports multiple interfaces. When an interface appears on the
|
||||||
|
* system (or is present at boot time) this class will start tracking it and bring it up. Only
|
||||||
|
* interfaces whose names match the {@code config_ethernet_iface_regex} regular expression are
|
||||||
|
* tracked.
|
||||||
|
*
|
||||||
|
* <p>All public or package private methods must be thread-safe unless stated otherwise.
|
||||||
|
*/
|
||||||
|
final class EthernetTracker {
|
||||||
|
private final static String TAG = EthernetTracker.class.getSimpleName();
|
||||||
|
private final static boolean DBG = EthernetNetworkFactory.DBG;
|
||||||
|
|
||||||
|
/** Product-dependent regular expression of interface names we track. */
|
||||||
|
private final String mIfaceMatch;
|
||||||
|
|
||||||
|
/** Mapping between {iface name | mac address} -> {NetworkCapabilities} */
|
||||||
|
private final ConcurrentHashMap<String, NetworkCapabilities> mNetworkCapabilities =
|
||||||
|
new ConcurrentHashMap<>();
|
||||||
|
private final ConcurrentHashMap<String, IpConfiguration> mIpConfigurations =
|
||||||
|
new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private final INetworkManagementService mNMService;
|
||||||
|
private final Handler mHandler;
|
||||||
|
private final EthernetNetworkFactory mFactory;
|
||||||
|
private final EthernetConfigStore mConfigStore;
|
||||||
|
|
||||||
|
private final RemoteCallbackList<IEthernetServiceListener> mListeners =
|
||||||
|
new RemoteCallbackList<>();
|
||||||
|
|
||||||
|
private volatile IpConfiguration mIpConfigForDefaultInterface;
|
||||||
|
|
||||||
|
EthernetTracker(Context context, Handler handler) {
|
||||||
|
mHandler = handler;
|
||||||
|
|
||||||
|
// The services we use.
|
||||||
|
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
|
||||||
|
mNMService = INetworkManagementService.Stub.asInterface(b);
|
||||||
|
|
||||||
|
// Interface match regex.
|
||||||
|
mIfaceMatch = context.getResources().getString(
|
||||||
|
com.android.internal.R.string.config_ethernet_iface_regex);
|
||||||
|
|
||||||
|
// Read default Ethernet interface configuration from resources
|
||||||
|
final String[] interfaceConfigs = context.getResources().getStringArray(
|
||||||
|
com.android.internal.R.array.config_ethernet_interfaces);
|
||||||
|
for (String strConfig : interfaceConfigs) {
|
||||||
|
parseEthernetConfig(strConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
mConfigStore = new EthernetConfigStore();
|
||||||
|
|
||||||
|
NetworkCapabilities nc = createNetworkCapabilities(true /* clear default capabilities */);
|
||||||
|
mFactory = new EthernetNetworkFactory(handler, context, nc);
|
||||||
|
mFactory.register();
|
||||||
|
}
|
||||||
|
|
||||||
|
void start() {
|
||||||
|
mConfigStore.read();
|
||||||
|
|
||||||
|
// Default interface is just the first one we want to track.
|
||||||
|
mIpConfigForDefaultInterface = mConfigStore.getIpConfigurationForDefaultInterface();
|
||||||
|
final ArrayMap<String, IpConfiguration> configs = mConfigStore.getIpConfigurations();
|
||||||
|
for (int i = 0; i < configs.size(); i++) {
|
||||||
|
mIpConfigurations.put(configs.keyAt(i), configs.valueAt(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
mNMService.registerObserver(new InterfaceObserver());
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "Could not register InterfaceObserver " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
mHandler.post(this::trackAvailableInterfaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) {
|
||||||
|
if (DBG) {
|
||||||
|
Log.i(TAG, "updateIpConfiguration, iface: " + iface + ", cfg: " + ipConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
mConfigStore.write(iface, ipConfiguration);
|
||||||
|
mIpConfigurations.put(iface, ipConfiguration);
|
||||||
|
|
||||||
|
mHandler.post(() -> mFactory.updateIpConfiguration(iface, ipConfiguration));
|
||||||
|
}
|
||||||
|
|
||||||
|
IpConfiguration getIpConfiguration(String iface) {
|
||||||
|
return mIpConfigurations.get(iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isTrackingInterface(String iface) {
|
||||||
|
return mFactory.hasInterface(iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] getInterfaces(boolean includeRestricted) {
|
||||||
|
return mFactory.getAvailableInterfaces(includeRestricted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if given interface was configured as restricted (doesn't have
|
||||||
|
* NET_CAPABILITY_NOT_RESTRICTED) capability. Otherwise, returns false.
|
||||||
|
*/
|
||||||
|
boolean isRestrictedInterface(String iface) {
|
||||||
|
final NetworkCapabilities nc = mNetworkCapabilities.get(iface);
|
||||||
|
return nc != null && !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addListener(IEthernetServiceListener listener, boolean canUseRestrictedNetworks) {
|
||||||
|
mListeners.register(listener, new ListenerInfo(canUseRestrictedNetworks));
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeListener(IEthernetServiceListener listener) {
|
||||||
|
mListeners.unregister(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeInterface(String iface) {
|
||||||
|
mFactory.removeInterface(iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addInterface(String iface) {
|
||||||
|
InterfaceConfiguration config = null;
|
||||||
|
// Bring up the interface so we get link status indications.
|
||||||
|
try {
|
||||||
|
mNMService.setInterfaceUp(iface);
|
||||||
|
config = mNMService.getInterfaceConfig(iface);
|
||||||
|
} catch (RemoteException | IllegalStateException e) {
|
||||||
|
// Either the system is crashing or the interface has disappeared. Just ignore the
|
||||||
|
// error; we haven't modified any state because we only do that if our calls succeed.
|
||||||
|
Log.e(TAG, "Error upping interface " + iface, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config == null) {
|
||||||
|
Log.e(TAG, "Null interface config for " + iface + ". Bailing out.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String hwAddress = config.getHardwareAddress();
|
||||||
|
|
||||||
|
NetworkCapabilities nc = mNetworkCapabilities.get(iface);
|
||||||
|
if (nc == null) {
|
||||||
|
// Try to resolve using mac address
|
||||||
|
nc = mNetworkCapabilities.get(hwAddress);
|
||||||
|
if (nc == null) {
|
||||||
|
nc = createDefaultNetworkCapabilities();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IpConfiguration ipConfiguration = mIpConfigurations.get(iface);
|
||||||
|
if (ipConfiguration == null) {
|
||||||
|
ipConfiguration = createDefaultIpConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "Started tracking interface " + iface);
|
||||||
|
mFactory.addInterface(iface, hwAddress, nc, ipConfiguration);
|
||||||
|
|
||||||
|
// Note: if the interface already has link (e.g., if we crashed and got
|
||||||
|
// restarted while it was running), we need to fake a link up notification so we
|
||||||
|
// start configuring it.
|
||||||
|
if (config.hasFlag("running")) {
|
||||||
|
updateInterfaceState(iface, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateInterfaceState(String iface, boolean up) {
|
||||||
|
boolean modified = mFactory.updateInterfaceLinkState(iface, up);
|
||||||
|
if (modified) {
|
||||||
|
boolean restricted = isRestrictedInterface(iface);
|
||||||
|
int n = mListeners.beginBroadcast();
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
try {
|
||||||
|
if (restricted) {
|
||||||
|
ListenerInfo listenerInfo = (ListenerInfo) mListeners.getBroadcastCookie(i);
|
||||||
|
if (!listenerInfo.canUseRestrictedNetworks) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mListeners.getBroadcastItem(i).onAvailabilityChanged(iface, up);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
// Do nothing here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mListeners.finishBroadcast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void maybeTrackInterface(String iface) {
|
||||||
|
if (DBG) Log.i(TAG, "maybeTrackInterface " + iface);
|
||||||
|
// If we don't already track this interface, and if this interface matches
|
||||||
|
// our regex, start tracking it.
|
||||||
|
if (!iface.matches(mIfaceMatch) || mFactory.hasInterface(iface)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mIpConfigForDefaultInterface != null) {
|
||||||
|
updateIpConfiguration(iface, mIpConfigForDefaultInterface);
|
||||||
|
mIpConfigForDefaultInterface = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
addInterface(iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void trackAvailableInterfaces() {
|
||||||
|
try {
|
||||||
|
final String[] ifaces = mNMService.listInterfaces();
|
||||||
|
for (String iface : ifaces) {
|
||||||
|
maybeTrackInterface(iface);
|
||||||
|
}
|
||||||
|
} catch (RemoteException | IllegalStateException e) {
|
||||||
|
Log.e(TAG, "Could not get list of interfaces " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class InterfaceObserver extends BaseNetworkObserver {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void interfaceLinkStateChanged(String iface, boolean up) {
|
||||||
|
if (DBG) {
|
||||||
|
Log.i(TAG, "interfaceLinkStateChanged, iface: " + iface + ", up: " + up);
|
||||||
|
}
|
||||||
|
mHandler.post(() -> updateInterfaceState(iface, up));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void interfaceAdded(String iface) {
|
||||||
|
mHandler.post(() -> maybeTrackInterface(iface));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void interfaceRemoved(String iface) {
|
||||||
|
mHandler.post(() -> removeInterface(iface));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ListenerInfo {
|
||||||
|
|
||||||
|
boolean canUseRestrictedNetworks = false;
|
||||||
|
|
||||||
|
ListenerInfo(boolean canUseRestrictedNetworks) {
|
||||||
|
this.canUseRestrictedNetworks = canUseRestrictedNetworks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseEthernetConfig(String configString) {
|
||||||
|
String[] tokens = configString.split(";");
|
||||||
|
String name = tokens[0];
|
||||||
|
String capabilities = tokens.length > 1 ? tokens[1] : null;
|
||||||
|
NetworkCapabilities nc = createNetworkCapabilities(
|
||||||
|
!TextUtils.isEmpty(capabilities) /* clear default capabilities */, capabilities);
|
||||||
|
mNetworkCapabilities.put(name, nc);
|
||||||
|
|
||||||
|
if (tokens.length > 2 && !TextUtils.isEmpty(tokens[2])) {
|
||||||
|
IpConfiguration ipConfig = createStaticIpConfiguration(tokens[2]);
|
||||||
|
mIpConfigurations.put(name, ipConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NetworkCapabilities createDefaultNetworkCapabilities() {
|
||||||
|
NetworkCapabilities nc = createNetworkCapabilities(false /* clear default capabilities */);
|
||||||
|
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
|
||||||
|
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
|
||||||
|
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
|
||||||
|
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
|
||||||
|
|
||||||
|
return nc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NetworkCapabilities createNetworkCapabilities(boolean clearDefaultCapabilities) {
|
||||||
|
return createNetworkCapabilities(clearDefaultCapabilities, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NetworkCapabilities createNetworkCapabilities(
|
||||||
|
boolean clearDefaultCapabilities, @Nullable String commaSeparatedCapabilities) {
|
||||||
|
|
||||||
|
NetworkCapabilities nc = new NetworkCapabilities();
|
||||||
|
if (clearDefaultCapabilities) {
|
||||||
|
nc.clearAll(); // Remove default capabilities.
|
||||||
|
}
|
||||||
|
nc.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET);
|
||||||
|
nc.setLinkUpstreamBandwidthKbps(100 * 1000);
|
||||||
|
nc.setLinkDownstreamBandwidthKbps(100 * 1000);
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(commaSeparatedCapabilities)) {
|
||||||
|
for (String strNetworkCapability : commaSeparatedCapabilities.split(",")) {
|
||||||
|
if (!TextUtils.isEmpty(strNetworkCapability)) {
|
||||||
|
nc.addCapability(Integer.valueOf(strNetworkCapability));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IpConfiguration createStaticIpConfiguration(String strIpAddress) {
|
||||||
|
StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();
|
||||||
|
staticIpConfiguration.ipAddress = new LinkAddress(strIpAddress);
|
||||||
|
return new IpConfiguration(
|
||||||
|
IpAssignment.STATIC, ProxySettings.NONE, staticIpConfiguration, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IpConfiguration createDefaultIpConfiguration() {
|
||||||
|
return new IpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void postAndWaitForRunnable(Runnable r) {
|
||||||
|
mHandler.runWithScissors(r, 2000L /* timeout */);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
|
||||||
|
postAndWaitForRunnable(() -> {
|
||||||
|
pw.println(getClass().getSimpleName());
|
||||||
|
pw.println("Ethernet interface name filter: " + mIfaceMatch);
|
||||||
|
pw.println("Listeners: " + mListeners.getRegisteredCallbackCount());
|
||||||
|
pw.println("IP Configurations:");
|
||||||
|
pw.increaseIndent();
|
||||||
|
for (String iface : mIpConfigurations.keySet()) {
|
||||||
|
pw.println(iface + ": " + mIpConfigurations.get(iface));
|
||||||
|
}
|
||||||
|
pw.decreaseIndent();
|
||||||
|
pw.println();
|
||||||
|
|
||||||
|
pw.println("Network Capabilities:");
|
||||||
|
pw.increaseIndent();
|
||||||
|
for (String iface : mNetworkCapabilities.keySet()) {
|
||||||
|
pw.println(iface + ": " + mNetworkCapabilities.get(iface));
|
||||||
|
}
|
||||||
|
pw.decreaseIndent();
|
||||||
|
pw.println();
|
||||||
|
|
||||||
|
mFactory.dump(fd, pw, args);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user