diff options
Diffstat (limited to 'java/com/android/server/ethernet')
6 files changed, 0 insertions, 2226 deletions
diff --git a/java/com/android/server/ethernet/EthernetConfigStore.java b/java/com/android/server/ethernet/EthernetConfigStore.java deleted file mode 100644 index 6b623f4..0000000 --- a/java/com/android/server/ethernet/EthernetConfigStore.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2014 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.net.IpConfiguration; -import android.os.Environment; -import android.util.ArrayMap; - -import com.android.server.net.IpConfigStore; - - -/** - * This class provides an API to store and manage Ethernet network configuration. - */ -public class EthernetConfigStore { - private static final String ipConfigFile = Environment.getDataDirectory() + - "/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() { - mIpConfigurations = new ArrayMap<>(0); - } - - public void read() { - synchronized (mSync) { - ArrayMap<String, IpConfiguration> configs = - IpConfigStore.readIpConfigurations(ipConfigFile); - - // This configuration may exist in old file versions when there was only a single active - // Ethernet interface. - if (configs.containsKey("0")) { - mIpConfigurationForDefaultInterface = configs.remove("0"); - } - - mIpConfigurations = configs; - } - } - - 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); - } - - if (modified) { - mStore.writeIpConfigurations(ipConfigFile, mIpConfigurations); - } - } - } - - public ArrayMap<String, IpConfiguration> getIpConfigurations() { - synchronized (mSync) { - return new ArrayMap<>(mIpConfigurations); - } - } - - @Nullable - public IpConfiguration getIpConfigurationForDefaultInterface() { - synchronized (mSync) { - return mIpConfigurationForDefaultInterface == null - ? null : new IpConfiguration(mIpConfigurationForDefaultInterface); - } - } -} diff --git a/java/com/android/server/ethernet/EthernetNetworkAgent.java b/java/com/android/server/ethernet/EthernetNetworkAgent.java deleted file mode 100644 index 57fbce7..0000000 --- a/java/com/android/server/ethernet/EthernetNetworkAgent.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2021 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.content.Context; -import android.net.LinkProperties; -import android.net.NetworkAgent; -import android.net.NetworkAgentConfig; -import android.net.NetworkCapabilities; -import android.net.NetworkProvider; -import android.net.NetworkScore; -import android.os.Looper; -import android.annotation.NonNull; -import android.annotation.Nullable; - -public class EthernetNetworkAgent extends NetworkAgent { - - private static final String TAG = "EthernetNetworkAgent"; - - public interface Callbacks { - void onNetworkUnwanted(); - } - - private final Callbacks mCallbacks; - - EthernetNetworkAgent( - @NonNull Context context, - @NonNull Looper looper, - @NonNull NetworkCapabilities nc, - @NonNull LinkProperties lp, - @NonNull NetworkAgentConfig config, - @Nullable NetworkProvider provider, - @NonNull Callbacks cb) { - super(context, looper, TAG, nc, lp, new NetworkScore.Builder().build(), config, provider); - mCallbacks = cb; - } - - @Override - public void onNetworkUnwanted() { - mCallbacks.onNetworkUnwanted(); - } - - // sendLinkProperties is final in NetworkAgent, so it cannot be mocked. - public void sendLinkPropertiesImpl(LinkProperties lp) { - sendLinkProperties(lp); - } - - public Callbacks getCallbacks() { - return mCallbacks; - } -} diff --git a/java/com/android/server/ethernet/EthernetNetworkFactory.java b/java/com/android/server/ethernet/EthernetNetworkFactory.java deleted file mode 100644 index d910629..0000000 --- a/java/com/android/server/ethernet/EthernetNetworkFactory.java +++ /dev/null @@ -1,785 +0,0 @@ -/* - * Copyright (C) 2014 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.NonNull; -import android.annotation.Nullable; -import android.content.Context; -import android.content.res.Resources; -import android.net.ConnectivityManager; -import android.net.ConnectivityResources; -import android.net.EthernetManager; -import android.net.EthernetNetworkSpecifier; -import android.net.EthernetNetworkManagementException; -import android.net.INetworkInterfaceOutcomeReceiver; -import android.net.IpConfiguration; -import android.net.IpConfiguration.IpAssignment; -import android.net.IpConfiguration.ProxySettings; -import android.net.LinkProperties; -import android.net.Network; -import android.net.NetworkAgentConfig; -import android.net.NetworkCapabilities; -import android.net.NetworkFactory; -import android.net.NetworkProvider; -import android.net.NetworkRequest; -import android.net.NetworkSpecifier; -import android.net.ip.IIpClient; -import android.net.ip.IpClientCallbacks; -import android.net.ip.IpClientManager; -import android.net.ip.IpClientUtil; -import android.net.shared.ProvisioningConfiguration; -import android.os.ConditionVariable; -import android.os.Handler; -import android.os.Looper; -import android.os.RemoteException; -import android.text.TextUtils; -import android.util.AndroidRuntimeException; -import android.util.Log; -import android.util.SparseArray; - -import com.android.connectivity.resources.R; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.IndentingPrintWriter; -import com.android.net.module.util.InterfaceParams; - -import java.io.FileDescriptor; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; - -/** - * {@link NetworkFactory} that represents Ethernet networks. - * - * 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. - */ -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 LEGACY_TCP_BUFFER_SIZES = - "524288,1048576,3145728,524288,1048576,2097152"; - - private final ConcurrentHashMap<String, NetworkInterfaceState> mTrackingInterfaces = - new ConcurrentHashMap<>(); - private final Handler mHandler; - private final Context mContext; - final Dependencies mDeps; - - public static class Dependencies { - public void makeIpClient(Context context, String iface, IpClientCallbacks callbacks) { - IpClientUtil.makeIpClient(context, iface, callbacks); - } - - public IpClientManager makeIpClientManager(@NonNull final IIpClient ipClient) { - return new IpClientManager(ipClient, TAG); - } - - public EthernetNetworkAgent makeEthernetNetworkAgent(Context context, Looper looper, - NetworkCapabilities nc, LinkProperties lp, NetworkAgentConfig config, - NetworkProvider provider, EthernetNetworkAgent.Callbacks cb) { - return new EthernetNetworkAgent(context, looper, nc, lp, config, provider, cb); - } - - public InterfaceParams getNetworkInterfaceByName(String name) { - return InterfaceParams.getByName(name); - } - - // TODO: remove legacy resource fallback after migrating its overlays. - private String getPlatformTcpBufferSizes(Context context) { - final Resources r = context.getResources(); - final int resId = r.getIdentifier("config_ethernet_tcp_buffers", "string", - context.getPackageName()); - return r.getString(resId); - } - - public String getTcpBufferSizesFromResource(Context context) { - final String tcpBufferSizes; - final String platformTcpBufferSizes = getPlatformTcpBufferSizes(context); - if (!LEGACY_TCP_BUFFER_SIZES.equals(platformTcpBufferSizes)) { - // Platform resource is not the historical default: use the overlay. - tcpBufferSizes = platformTcpBufferSizes; - } else { - final ConnectivityResources resources = new ConnectivityResources(context); - tcpBufferSizes = resources.get().getString(R.string.config_ethernet_tcp_buffers); - } - return tcpBufferSizes; - } - } - - public static class ConfigurationException extends AndroidRuntimeException { - public ConfigurationException(String msg) { - super(msg); - } - } - - public EthernetNetworkFactory(Handler handler, Context context) { - this(handler, context, new Dependencies()); - } - - @VisibleForTesting - EthernetNetworkFactory(Handler handler, Context context, Dependencies deps) { - super(handler.getLooper(), context, NETWORK_TYPE, createDefaultNetworkCapabilities()); - - mHandler = handler; - mContext = context; - mDeps = deps; - - setScoreFilter(NETWORK_SCORE); - } - - @Override - public boolean acceptRequest(NetworkRequest request) { - if (DBG) { - Log.d(TAG, "acceptRequest, request: " + request); - } - - return networkForRequest(request) != null; - } - - @Override - protected void needNetworkFor(NetworkRequest networkRequest) { - 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(); - } - } - - @Override - protected void releaseNetworkFor(NetworkRequest networkRequest) { - NetworkInterfaceState network = networkForRequest(networkRequest); - if (network == null) { - Log.e(TAG, "releaseNetworkFor, failed to get a network for " + networkRequest); - return; - } - - if (--network.refCount == 0) { - network.stop(); - } - } - - /** - * Returns an array of available interface names. The array is sorted: unrestricted interfaces - * goes first, then sorted by name. - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - protected String[] getAvailableInterfaces(boolean includeRestricted) { - return mTrackingInterfaces.values() - .stream() - .filter(iface -> !iface.isRestricted() || includeRestricted) - .sorted((iface1, iface2) -> { - int r = Boolean.compare(iface1.isRestricted(), iface2.isRestricted()); - return r == 0 ? iface1.name.compareTo(iface2.name) : r; - }) - .map(iface -> iface.name) - .toArray(String[]::new); - } - - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - protected void addInterface(@NonNull final String ifaceName, @NonNull final String hwAddress, - @NonNull final IpConfiguration ipConfig, - @NonNull final NetworkCapabilities capabilities) { - if (mTrackingInterfaces.containsKey(ifaceName)) { - Log.e(TAG, "Interface with name " + ifaceName + " already exists."); - return; - } - - final NetworkCapabilities nc = new NetworkCapabilities.Builder(capabilities) - .setNetworkSpecifier(new EthernetNetworkSpecifier(ifaceName)) - .build(); - - if (DBG) { - Log.d(TAG, "addInterface, iface: " + ifaceName + ", capabilities: " + nc); - } - - final NetworkInterfaceState iface = new NetworkInterfaceState( - ifaceName, hwAddress, mHandler, mContext, ipConfig, nc, this, mDeps); - mTrackingInterfaces.put(ifaceName, iface); - updateCapabilityFilter(); - } - - @VisibleForTesting - protected int getInterfaceState(@NonNull String iface) { - final NetworkInterfaceState interfaceState = mTrackingInterfaces.get(iface); - if (interfaceState == null) { - return EthernetManager.STATE_ABSENT; - } else if (!interfaceState.mLinkUp) { - return EthernetManager.STATE_LINK_DOWN; - } else { - return EthernetManager.STATE_LINK_UP; - } - } - - /** - * Update a network's configuration and restart it if necessary. - * - * @param ifaceName the interface name of the network to be updated. - * @param ipConfig the desired {@link IpConfiguration} for the given network or null. If - * {@code null} is passed, the existing IpConfiguration is not updated. - * @param capabilities the desired {@link NetworkCapabilities} for the given network. If - * {@code null} is passed, then the network's current - * {@link NetworkCapabilities} will be used in support of existing APIs as - * the public API does not allow this. - * @param listener an optional {@link INetworkInterfaceOutcomeReceiver} to notify callers of - * completion. - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - protected void updateInterface(@NonNull final String ifaceName, - @Nullable final IpConfiguration ipConfig, - @Nullable final NetworkCapabilities capabilities, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { - if (!hasInterface(ifaceName)) { - maybeSendNetworkManagementCallbackForUntracked(ifaceName, listener); - return; - } - - final NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName); - iface.updateInterface(ipConfig, capabilities, listener); - mTrackingInterfaces.put(ifaceName, iface); - updateCapabilityFilter(); - } - - private static NetworkCapabilities mixInCapabilities(NetworkCapabilities nc, - NetworkCapabilities addedNc) { - final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(nc); - for (int transport : addedNc.getTransportTypes()) builder.addTransportType(transport); - for (int capability : addedNc.getCapabilities()) builder.addCapability(capability); - return builder.build(); - } - - private void updateCapabilityFilter() { - NetworkCapabilities capabilitiesFilter = createDefaultNetworkCapabilities(); - for (NetworkInterfaceState iface: mTrackingInterfaces.values()) { - capabilitiesFilter = mixInCapabilities(capabilitiesFilter, iface.mCapabilities); - } - - if (DBG) Log.d(TAG, "updateCapabilityFilter: " + capabilitiesFilter); - setCapabilityFilter(capabilitiesFilter); - } - - private static NetworkCapabilities createDefaultNetworkCapabilities() { - return NetworkCapabilities.Builder - .withoutDefaultCapabilities() - .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET).build(); - } - - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - protected void removeInterface(String interfaceName) { - NetworkInterfaceState iface = mTrackingInterfaces.remove(interfaceName); - if (iface != null) { - iface.maybeSendNetworkManagementCallbackForAbort(); - iface.stop(); - } - - updateCapabilityFilter(); - } - - /** Returns true if state has been modified */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - protected boolean updateInterfaceLinkState(@NonNull final String ifaceName, final boolean up, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { - if (!hasInterface(ifaceName)) { - maybeSendNetworkManagementCallbackForUntracked(ifaceName, listener); - return false; - } - - if (DBG) { - Log.d(TAG, "updateInterfaceLinkState, iface: " + ifaceName + ", up: " + up); - } - - NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName); - return iface.updateLinkState(up, listener); - } - - private void maybeSendNetworkManagementCallbackForUntracked( - String ifaceName, INetworkInterfaceOutcomeReceiver listener) { - maybeSendNetworkManagementCallback(listener, null, - new EthernetNetworkManagementException( - ifaceName + " can't be updated as it is not available.")); - } - - @VisibleForTesting - protected boolean hasInterface(String ifaceName) { - return mTrackingInterfaces.containsKey(ifaceName); - } - - private NetworkInterfaceState networkForRequest(NetworkRequest request) { - String requestedIface = null; - - NetworkSpecifier specifier = request.getNetworkSpecifier(); - if (specifier instanceof EthernetNetworkSpecifier) { - requestedIface = ((EthernetNetworkSpecifier) specifier) - .getInterfaceName(); - } - - NetworkInterfaceState network = null; - if (!TextUtils.isEmpty(requestedIface)) { - NetworkInterfaceState n = mTrackingInterfaces.get(requestedIface); - if (n != null && request.canBeSatisfiedBy(n.mCapabilities)) { - network = n; - } - } else { - for (NetworkInterfaceState n : mTrackingInterfaces.values()) { - if (request.canBeSatisfiedBy(n.mCapabilities) && n.mLinkUp) { - network = n; - break; - } - } - } - - if (DBG) { - Log.i(TAG, "networkForRequest, request: " + request + ", network: " + network); - } - - return network; - } - - private static void maybeSendNetworkManagementCallback( - @Nullable final INetworkInterfaceOutcomeReceiver listener, - @Nullable final String iface, - @Nullable final EthernetNetworkManagementException e) { - if (null == listener) { - return; - } - - try { - if (iface != null) { - listener.onResult(iface); - } else { - listener.onError(e); - } - } catch (RemoteException re) { - Log.e(TAG, "Can't send onComplete for network management callback", re); - } - } - - @VisibleForTesting - static class NetworkInterfaceState { - final String name; - - private final String mHwAddress; - private final Handler mHandler; - private final Context mContext; - private final NetworkFactory mNetworkFactory; - private final Dependencies mDeps; - - private static String sTcpBufferSizes = null; // Lazy initialized. - - private boolean mLinkUp; - private int mLegacyType; - private LinkProperties mLinkProperties = new LinkProperties(); - - private volatile @Nullable IpClientManager mIpClient; - private @NonNull NetworkCapabilities mCapabilities; - private @Nullable EthernetIpClientCallback mIpClientCallback; - private @Nullable EthernetNetworkAgent mNetworkAgent; - private @Nullable IpConfiguration mIpConfig; - - /** - * A map of TRANSPORT_* types to legacy transport types available for each type an ethernet - * interface could propagate. - * - * There are no legacy type equivalents to LOWPAN or WIFI_AWARE. These types are set to - * TYPE_NONE to match the behavior of their own network factories. - */ - private static final SparseArray<Integer> sTransports = new SparseArray(); - static { - sTransports.put(NetworkCapabilities.TRANSPORT_ETHERNET, - ConnectivityManager.TYPE_ETHERNET); - sTransports.put(NetworkCapabilities.TRANSPORT_BLUETOOTH, - ConnectivityManager.TYPE_BLUETOOTH); - sTransports.put(NetworkCapabilities.TRANSPORT_WIFI, ConnectivityManager.TYPE_WIFI); - sTransports.put(NetworkCapabilities.TRANSPORT_CELLULAR, - ConnectivityManager.TYPE_MOBILE); - sTransports.put(NetworkCapabilities.TRANSPORT_LOWPAN, ConnectivityManager.TYPE_NONE); - sTransports.put(NetworkCapabilities.TRANSPORT_WIFI_AWARE, - ConnectivityManager.TYPE_NONE); - } - - long refCount = 0; - - private class EthernetIpClientCallback extends IpClientCallbacks { - private final ConditionVariable mIpClientStartCv = new ConditionVariable(false); - private final ConditionVariable mIpClientShutdownCv = new ConditionVariable(false); - @Nullable INetworkInterfaceOutcomeReceiver mNetworkManagementListener; - - EthernetIpClientCallback(@Nullable final INetworkInterfaceOutcomeReceiver listener) { - mNetworkManagementListener = listener; - } - - @Override - public void onIpClientCreated(IIpClient ipClient) { - mIpClient = mDeps.makeIpClientManager(ipClient); - mIpClientStartCv.open(); - } - - private void awaitIpClientStart() { - mIpClientStartCv.block(); - } - - private void awaitIpClientShutdown() { - mIpClientShutdownCv.block(); - } - - // At the time IpClient is stopped, an IpClient event may have already been posted on - // the back of the handler and is awaiting execution. Once that event is executed, the - // associated callback object may not be valid anymore - // (NetworkInterfaceState#mIpClientCallback points to a different object / null). - private boolean isCurrentCallback() { - return this == mIpClientCallback; - } - - private void handleIpEvent(final @NonNull Runnable r) { - mHandler.post(() -> { - if (!isCurrentCallback()) { - Log.i(TAG, "Ignoring stale IpClientCallbacks " + this); - return; - } - r.run(); - }); - } - - @Override - public void onProvisioningSuccess(LinkProperties newLp) { - handleIpEvent(() -> onIpLayerStarted(newLp, mNetworkManagementListener)); - } - - @Override - public void onProvisioningFailure(LinkProperties newLp) { - // This cannot happen due to provisioning timeout, because our timeout is 0. It can - // happen due to errors while provisioning or on provisioning loss. - handleIpEvent(() -> onIpLayerStopped(mNetworkManagementListener)); - } - - @Override - public void onLinkPropertiesChange(LinkProperties newLp) { - handleIpEvent(() -> updateLinkProperties(newLp)); - } - - @Override - public void onReachabilityLost(String logMsg) { - handleIpEvent(() -> updateNeighborLostEvent(logMsg)); - } - - @Override - public void onQuit() { - mIpClient = null; - mIpClientShutdownCv.open(); - } - } - - NetworkInterfaceState(String ifaceName, String hwAddress, Handler handler, Context context, - @NonNull IpConfiguration ipConfig, @NonNull NetworkCapabilities capabilities, - NetworkFactory networkFactory, Dependencies deps) { - name = ifaceName; - mIpConfig = Objects.requireNonNull(ipConfig); - mCapabilities = Objects.requireNonNull(capabilities); - mLegacyType = getLegacyType(mCapabilities); - mHandler = handler; - mContext = context; - mNetworkFactory = networkFactory; - mDeps = deps; - mHwAddress = hwAddress; - } - - /** - * Determines the legacy transport type from a NetworkCapabilities transport type. Defaults - * to legacy TYPE_NONE if there is no known conversion - */ - private static int getLegacyType(int transport) { - return sTransports.get(transport, ConnectivityManager.TYPE_NONE); - } - - private static int getLegacyType(@NonNull final NetworkCapabilities capabilities) { - final int[] transportTypes = capabilities.getTransportTypes(); - if (transportTypes.length > 0) { - return getLegacyType(transportTypes[0]); - } - - // Should never happen as transport is always one of ETHERNET or a valid override - throw new ConfigurationException("Network Capabilities do not have an associated " - + "transport type."); - } - - private void setCapabilities(@NonNull final NetworkCapabilities capabilities) { - mCapabilities = new NetworkCapabilities(capabilities); - mLegacyType = getLegacyType(mCapabilities); - } - - void updateInterface(@Nullable final IpConfiguration ipConfig, - @Nullable final NetworkCapabilities capabilities, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { - if (DBG) { - Log.d(TAG, "updateInterface, iface: " + name - + ", ipConfig: " + ipConfig + ", old ipConfig: " + mIpConfig - + ", capabilities: " + capabilities + ", old capabilities: " + mCapabilities - + ", listener: " + listener - ); - } - - if (null != ipConfig){ - mIpConfig = ipConfig; - } - if (null != capabilities) { - setCapabilities(capabilities); - } - // Send an abort callback if a request is filed before the previous one has completed. - maybeSendNetworkManagementCallbackForAbort(); - // TODO: Update this logic to only do a restart if required. Although a restart may - // be required due to the capabilities or ipConfiguration values, not all - // capabilities changes require a restart. - restart(listener); - } - - boolean isRestricted() { - return !mCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); - } - - private void start() { - start(null); - } - - private void start(@Nullable final INetworkInterfaceOutcomeReceiver listener) { - if (mIpClient != null) { - if (DBG) Log.d(TAG, "IpClient already started"); - return; - } - if (DBG) { - Log.d(TAG, String.format("Starting Ethernet IpClient(%s)", name)); - } - - mIpClientCallback = new EthernetIpClientCallback(listener); - mDeps.makeIpClient(mContext, name, mIpClientCallback); - mIpClientCallback.awaitIpClientStart(); - - if (sTcpBufferSizes == null) { - sTcpBufferSizes = mDeps.getTcpBufferSizesFromResource(mContext); - } - provisionIpClient(mIpClient, mIpConfig, sTcpBufferSizes); - } - - void onIpLayerStarted(@NonNull final LinkProperties linkProperties, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { - if (mNetworkAgent != null) { - Log.e(TAG, "Already have a NetworkAgent - aborting new request"); - stop(); - return; - } - mLinkProperties = linkProperties; - - // Create our NetworkAgent. - final NetworkAgentConfig config = new NetworkAgentConfig.Builder() - .setLegacyType(mLegacyType) - .setLegacyTypeName(NETWORK_TYPE) - .setLegacyExtraInfo(mHwAddress) - .build(); - mNetworkAgent = mDeps.makeEthernetNetworkAgent(mContext, mHandler.getLooper(), - mCapabilities, mLinkProperties, config, mNetworkFactory.getProvider(), - new EthernetNetworkAgent.Callbacks() { - @Override - public void onNetworkUnwanted() { - // if mNetworkAgent is null, we have already called stop. - if (mNetworkAgent == null) return; - - if (this == mNetworkAgent.getCallbacks()) { - stop(); - } else { - Log.d(TAG, "Ignoring unwanted as we have a more modern " + - "instance"); - } - } - }); - mNetworkAgent.register(); - mNetworkAgent.markConnected(); - realizeNetworkManagementCallback(name, null); - } - - void onIpLayerStopped(@Nullable final INetworkInterfaceOutcomeReceiver listener) { - // There is no point in continuing if the interface is gone as stop() will be triggered - // by removeInterface() when processed on the handler thread and start() won't - // work for a non-existent interface. - if (null == mDeps.getNetworkInterfaceByName(name)) { - if (DBG) Log.d(TAG, name + " is no longer available."); - // Send a callback in case a provisioning request was in progress. - maybeSendNetworkManagementCallbackForAbort(); - return; - } - restart(listener); - } - - private void maybeSendNetworkManagementCallbackForAbort() { - realizeNetworkManagementCallback(null, - new EthernetNetworkManagementException( - "The IP provisioning request has been aborted.")); - } - - // Must be called on the handler thread - private void realizeNetworkManagementCallback(@Nullable final String iface, - @Nullable final EthernetNetworkManagementException e) { - ensureRunningOnEthernetHandlerThread(); - if (null == mIpClientCallback) { - return; - } - - EthernetNetworkFactory.maybeSendNetworkManagementCallback( - mIpClientCallback.mNetworkManagementListener, iface, e); - // Only send a single callback per listener. - mIpClientCallback.mNetworkManagementListener = null; - } - - private void ensureRunningOnEthernetHandlerThread() { - if (mHandler.getLooper().getThread() != Thread.currentThread()) { - throw new IllegalStateException( - "Not running on the Ethernet thread: " - + Thread.currentThread().getName()); - } - } - - void updateLinkProperties(LinkProperties linkProperties) { - mLinkProperties = linkProperties; - if (mNetworkAgent != null) { - mNetworkAgent.sendLinkPropertiesImpl(linkProperties); - } - } - - void updateNeighborLostEvent(String logMsg) { - Log.i(TAG, "updateNeighborLostEvent " + logMsg); - // Reachability lost will be seen only if the gateway is not reachable. - // Since ethernet FW doesn't have the mechanism to scan for new networks - // like WiFi, simply restart. - // If there is a better network, that will become default and apps - // will be able to use internet. If ethernet gets connected again, - // and has backhaul connectivity, it will become default. - restart(); - } - - /** Returns true if state has been modified */ - boolean updateLinkState(final boolean up, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { - if (mLinkUp == up) { - EthernetNetworkFactory.maybeSendNetworkManagementCallback(listener, null, - new EthernetNetworkManagementException( - "No changes with requested link state " + up + " for " + name)); - return false; - } - mLinkUp = up; - - if (!up) { // was up, goes down - // Send an abort on a provisioning request callback if necessary before stopping. - maybeSendNetworkManagementCallbackForAbort(); - stop(); - // If only setting the interface down, send a callback to signal completion. - EthernetNetworkFactory.maybeSendNetworkManagementCallback(listener, name, null); - } else { // was down, goes up - stop(); - start(listener); - } - - return true; - } - - void stop() { - // Invalidate all previous start requests - if (mIpClient != null) { - mIpClient.shutdown(); - mIpClientCallback.awaitIpClientShutdown(); - mIpClient = null; - } - mIpClientCallback = null; - - if (mNetworkAgent != null) { - mNetworkAgent.unregister(); - mNetworkAgent = null; - } - mLinkProperties.clear(); - } - - private static void provisionIpClient(@NonNull final IpClientManager ipClient, - @NonNull final IpConfiguration config, @NonNull final String tcpBufferSizes) { - if (config.getProxySettings() == ProxySettings.STATIC || - config.getProxySettings() == ProxySettings.PAC) { - ipClient.setHttpProxy(config.getHttpProxy()); - } - - if (!TextUtils.isEmpty(tcpBufferSizes)) { - ipClient.setTcpBufferSizes(tcpBufferSizes); - } - - ipClient.startProvisioning(createProvisioningConfiguration(config)); - } - - private static ProvisioningConfiguration createProvisioningConfiguration( - @NonNull final IpConfiguration config) { - if (config.getIpAssignment() == IpAssignment.STATIC) { - return new ProvisioningConfiguration.Builder() - .withStaticConfiguration(config.getStaticIpConfiguration()) - .build(); - } - return new ProvisioningConfiguration.Builder() - .withProvisioningTimeoutMs(0) - .build(); - } - - void restart() { - restart(null); - } - - void restart(@Nullable final INetworkInterfaceOutcomeReceiver listener) { - if (DBG) Log.d(TAG, "reconnecting Ethernet"); - stop(); - start(listener); - } - - @Override - public String toString() { - return getClass().getSimpleName() + "{ " - + "refCount: " + refCount + ", " - + "iface: " + name + ", " - + "up: " + mLinkUp + ", " - + "hwAddress: " + mHwAddress + ", " - + "networkCapabilities: " + mCapabilities + ", " - + "networkAgent: " + mNetworkAgent + ", " - + "ipClient: " + mIpClient + "," - + "linkProperties: " + mLinkProperties - + "}"; - } - } - - void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) { - super.dump(fd, pw, args); - pw.println(getClass().getSimpleName()); - pw.println("Tracking interfaces:"); - pw.increaseIndent(); - for (String iface: mTrackingInterfaces.keySet()) { - NetworkInterfaceState ifaceState = mTrackingInterfaces.get(iface); - pw.println(iface + ":" + ifaceState); - pw.increaseIndent(); - if (null == ifaceState.mIpClient) { - pw.println("IpClient is null"); - } - pw.decreaseIndent(); - } - pw.decreaseIndent(); - } -} diff --git a/java/com/android/server/ethernet/EthernetService.java b/java/com/android/server/ethernet/EthernetService.java deleted file mode 100644 index d405fd5..0000000 --- a/java/com/android/server/ethernet/EthernetService.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2014 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.content.Context; -import android.net.INetd; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; - -import java.util.Objects; - -// TODO: consider renaming EthernetServiceImpl to EthernetService and deleting this file. -public final class EthernetService { - private static final String TAG = "EthernetService"; - private static final String THREAD_NAME = "EthernetServiceThread"; - - private static INetd getNetd(Context context) { - final INetd netd = - INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE)); - Objects.requireNonNull(netd, "could not get netd instance"); - return netd; - } - - public static EthernetServiceImpl create(Context context) { - final HandlerThread handlerThread = new HandlerThread(THREAD_NAME); - handlerThread.start(); - final Handler handler = new Handler(handlerThread.getLooper()); - final EthernetNetworkFactory factory = new EthernetNetworkFactory(handler, context); - return new EthernetServiceImpl(context, handler, - new EthernetTracker(context, handler, factory, getNetd(context))); - } -} diff --git a/java/com/android/server/ethernet/EthernetServiceImpl.java b/java/com/android/server/ethernet/EthernetServiceImpl.java deleted file mode 100644 index 5e830ad..0000000 --- a/java/com/android/server/ethernet/EthernetServiceImpl.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright (C) 2014 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 static android.net.NetworkCapabilities.TRANSPORT_TEST; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.Context; -import android.content.pm.PackageManager; -import android.net.IEthernetManager; -import android.net.IEthernetServiceListener; -import android.net.INetworkInterfaceOutcomeReceiver; -import android.net.ITetheredInterfaceCallback; -import android.net.EthernetNetworkUpdateRequest; -import android.net.IpConfiguration; -import android.net.NetworkCapabilities; -import android.os.Binder; -import android.os.Handler; -import android.os.RemoteException; -import android.util.Log; -import android.util.PrintWriterPrinter; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.IndentingPrintWriter; -import com.android.net.module.util.PermissionUtils; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * EthernetServiceImpl handles remote Ethernet operation requests by implementing - * the IEthernetManager interface. - */ -public class EthernetServiceImpl extends IEthernetManager.Stub { - private static final String TAG = "EthernetServiceImpl"; - - @VisibleForTesting - final AtomicBoolean mStarted = new AtomicBoolean(false); - private final Context mContext; - private final Handler mHandler; - private final EthernetTracker mTracker; - - EthernetServiceImpl(@NonNull final Context context, @NonNull final Handler handler, - @NonNull final EthernetTracker tracker) { - mContext = context; - mHandler = handler; - mTracker = tracker; - } - - private void enforceAutomotiveDevice(final @NonNull String methodName) { - PermissionUtils.enforceSystemFeature(mContext, PackageManager.FEATURE_AUTOMOTIVE, - methodName + " is only available on automotive devices."); - } - - private boolean checkUseRestrictedNetworksPermission() { - return PermissionUtils.checkAnyPermissionOf(mContext, - android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS); - } - - public void start() { - Log.i(TAG, "Starting Ethernet service"); - mTracker.start(); - mStarted.set(true); - } - - private void throwIfEthernetNotStarted() { - if (!mStarted.get()) { - throw new IllegalStateException("System isn't ready to change ethernet configurations"); - } - } - - @Override - public String[] getAvailableInterfaces() throws RemoteException { - PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); - return mTracker.getInterfaces(checkUseRestrictedNetworksPermission()); - } - - /** - * Get Ethernet configuration - * @return the Ethernet Configuration, contained in {@link IpConfiguration}. - */ - @Override - public IpConfiguration getConfiguration(String iface) { - PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); - if (mTracker.isRestrictedInterface(iface)) { - PermissionUtils.enforceRestrictedNetworkPermission(mContext, TAG); - } - - return new IpConfiguration(mTracker.getIpConfiguration(iface)); - } - - /** - * Set Ethernet configuration - */ - @Override - public void setConfiguration(String iface, IpConfiguration config) { - throwIfEthernetNotStarted(); - - PermissionUtils.enforceNetworkStackPermission(mContext); - if (mTracker.isRestrictedInterface(iface)) { - PermissionUtils.enforceRestrictedNetworkPermission(mContext, TAG); - } - - // TODO: this does not check proxy settings, gateways, etc. - // Fix this by making IpConfiguration a complete representation of static configuration. - mTracker.updateIpConfiguration(iface, new IpConfiguration(config)); - } - - /** - * Indicates whether given interface is available. - */ - @Override - public boolean isAvailable(String iface) { - PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); - if (mTracker.isRestrictedInterface(iface)) { - PermissionUtils.enforceRestrictedNetworkPermission(mContext, TAG); - } - - return mTracker.isTrackingInterface(iface); - } - - /** - * Adds a listener. - * @param listener A {@link IEthernetServiceListener} to add. - */ - public void addListener(IEthernetServiceListener listener) throws RemoteException { - Objects.requireNonNull(listener, "listener must not be null"); - PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); - mTracker.addListener(listener, checkUseRestrictedNetworksPermission()); - } - - /** - * Removes a listener. - * @param listener A {@link IEthernetServiceListener} to remove. - */ - public void removeListener(IEthernetServiceListener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } - PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); - mTracker.removeListener(listener); - } - - @Override - public void setIncludeTestInterfaces(boolean include) { - PermissionUtils.enforceNetworkStackPermissionOr(mContext, - android.Manifest.permission.NETWORK_SETTINGS); - mTracker.setIncludeTestInterfaces(include); - } - - @Override - public void requestTetheredInterface(ITetheredInterfaceCallback callback) { - Objects.requireNonNull(callback, "callback must not be null"); - PermissionUtils.enforceNetworkStackPermissionOr(mContext, - android.Manifest.permission.NETWORK_SETTINGS); - mTracker.requestTetheredInterface(callback); - } - - @Override - public void releaseTetheredInterface(ITetheredInterfaceCallback callback) { - Objects.requireNonNull(callback, "callback must not be null"); - PermissionUtils.enforceNetworkStackPermissionOr(mContext, - android.Manifest.permission.NETWORK_SETTINGS); - mTracker.releaseTetheredInterface(callback); - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { - final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump EthernetService from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - - pw.println("Current Ethernet state: "); - pw.increaseIndent(); - mTracker.dump(fd, pw, args); - pw.decreaseIndent(); - - pw.println("Handler:"); - pw.increaseIndent(); - mHandler.dump(new PrintWriterPrinter(pw), "EthernetServiceImpl"); - pw.decreaseIndent(); - } - - private void enforceNetworkManagementPermission() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.MANAGE_ETHERNET_NETWORKS, - "EthernetServiceImpl"); - } - - private void enforceManageTestNetworksPermission() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.MANAGE_TEST_NETWORKS, - "EthernetServiceImpl"); - } - - private void maybeValidateTestCapabilities(final String iface, - @Nullable final NetworkCapabilities nc) { - if (!mTracker.isValidTestInterface(iface)) { - return; - } - // For test interfaces, only null or capabilities that include TRANSPORT_TEST are - // allowed. - if (nc != null && !nc.hasTransport(TRANSPORT_TEST)) { - throw new IllegalArgumentException( - "Updates to test interfaces must have NetworkCapabilities.TRANSPORT_TEST."); - } - } - - private void enforceAdminPermission(final String iface, boolean enforceAutomotive, - final String logMessage) { - if (mTracker.isValidTestInterface(iface)) { - enforceManageTestNetworksPermission(); - } else { - enforceNetworkManagementPermission(); - if (enforceAutomotive) { - enforceAutomotiveDevice(logMessage); - } - } - } - - @Override - public void updateConfiguration(@NonNull final String iface, - @NonNull final EthernetNetworkUpdateRequest request, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { - Objects.requireNonNull(iface); - Objects.requireNonNull(request); - throwIfEthernetNotStarted(); - - // TODO: validate that iface is listed in overlay config_ethernet_interfaces - // only automotive devices are allowed to set the NetworkCapabilities using this API - enforceAdminPermission(iface, request.getNetworkCapabilities() != null, - "updateConfiguration() with non-null capabilities"); - maybeValidateTestCapabilities(iface, request.getNetworkCapabilities()); - - mTracker.updateConfiguration( - iface, request.getIpConfiguration(), request.getNetworkCapabilities(), listener); - } - - @Override - public void connectNetwork(@NonNull final String iface, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { - Log.i(TAG, "connectNetwork called with: iface=" + iface + ", listener=" + listener); - Objects.requireNonNull(iface); - throwIfEthernetNotStarted(); - - enforceAdminPermission(iface, true, "connectNetwork()"); - - mTracker.connectNetwork(iface, listener); - } - - @Override - public void disconnectNetwork(@NonNull final String iface, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { - Log.i(TAG, "disconnectNetwork called with: iface=" + iface + ", listener=" + listener); - Objects.requireNonNull(iface); - throwIfEthernetNotStarted(); - - enforceAdminPermission(iface, true, "connectNetwork()"); - - mTracker.disconnectNetwork(iface, listener); - } - - @Override - public void setEthernetEnabled(boolean enabled) { - PermissionUtils.enforceNetworkStackPermissionOr(mContext, - android.Manifest.permission.NETWORK_SETTINGS); - - mTracker.setEthernetEnabled(enabled); - } - - @Override - public List<String> getInterfaceList() { - PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); - return mTracker.getInterfaceList(); - } -} diff --git a/java/com/android/server/ethernet/EthernetTracker.java b/java/com/android/server/ethernet/EthernetTracker.java deleted file mode 100644 index c291b3f..0000000 --- a/java/com/android/server/ethernet/EthernetTracker.java +++ /dev/null @@ -1,942 +0,0 @@ -/* - * 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 static android.net.EthernetManager.ETHERNET_STATE_DISABLED; -import static android.net.EthernetManager.ETHERNET_STATE_ENABLED; -import static android.net.TestNetworkManager.TEST_TAP_PREFIX; - -import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.Context; -import android.content.res.Resources; -import android.net.ConnectivityResources; -import android.net.EthernetManager; -import android.net.IEthernetServiceListener; -import android.net.INetworkInterfaceOutcomeReceiver; -import android.net.INetd; -import android.net.ITetheredInterfaceCallback; -import android.net.InterfaceConfigurationParcel; -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.ConditionVariable; -import android.os.Handler; -import android.os.RemoteCallbackList; -import android.os.RemoteException; -import android.os.ServiceSpecificException; -import android.text.TextUtils; -import android.util.ArrayMap; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.IndentingPrintWriter; -import com.android.net.module.util.BaseNetdUnsolicitedEventListener; -import com.android.net.module.util.NetdUtils; -import com.android.net.module.util.PermissionUtils; - -import java.io.FileDescriptor; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -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. - */ -@VisibleForTesting(visibility = PACKAGE) -public class EthernetTracker { - private static final int INTERFACE_MODE_CLIENT = 1; - private static final int INTERFACE_MODE_SERVER = 2; - - private static final String TAG = EthernetTracker.class.getSimpleName(); - private static final boolean DBG = EthernetNetworkFactory.DBG; - - private static final String TEST_IFACE_REGEXP = TEST_TAP_PREFIX + "\\d+"; - private static final String LEGACY_IFACE_REGEXP = "eth\\d"; - - /** - * Interface names we track. This is a product-dependent regular expression, plus, - * if setIncludeTestInterfaces is true, any test interfaces. - */ - private volatile String mIfaceMatch; - /** - * Track test interfaces if true, don't track otherwise. - */ - private boolean mIncludeTestInterfaces = false; - - /** 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 Context mContext; - private final INetd mNetd; - private final Handler mHandler; - private final EthernetNetworkFactory mFactory; - private final EthernetConfigStore mConfigStore; - private final Dependencies mDeps; - - private final RemoteCallbackList<IEthernetServiceListener> mListeners = - new RemoteCallbackList<>(); - private final TetheredInterfaceRequestList mTetheredInterfaceRequests = - new TetheredInterfaceRequestList(); - - // Used only on the handler thread - private String mDefaultInterface; - private int mDefaultInterfaceMode = INTERFACE_MODE_CLIENT; - // Tracks whether clients were notified that the tethered interface is available - private boolean mTetheredInterfaceWasAvailable = false; - private volatile IpConfiguration mIpConfigForDefaultInterface; - - private int mEthernetState = ETHERNET_STATE_ENABLED; - - private class TetheredInterfaceRequestList extends - RemoteCallbackList<ITetheredInterfaceCallback> { - @Override - public void onCallbackDied(ITetheredInterfaceCallback cb, Object cookie) { - mHandler.post(EthernetTracker.this::maybeUntetherDefaultInterface); - } - } - - public static class Dependencies { - // TODO: remove legacy resource fallback after migrating its overlays. - private String getPlatformRegexResource(Context context) { - final Resources r = context.getResources(); - final int resId = - r.getIdentifier("config_ethernet_iface_regex", "string", context.getPackageName()); - return r.getString(resId); - } - - // TODO: remove legacy resource fallback after migrating its overlays. - private String[] getPlatformInterfaceConfigs(Context context) { - final Resources r = context.getResources(); - final int resId = r.getIdentifier("config_ethernet_interfaces", "array", - context.getPackageName()); - return r.getStringArray(resId); - } - - public String getInterfaceRegexFromResource(Context context) { - final String platformRegex = getPlatformRegexResource(context); - final String match; - if (!LEGACY_IFACE_REGEXP.equals(platformRegex)) { - // Platform resource is not the historical default: use the overlay - match = platformRegex; - } else { - final ConnectivityResources resources = new ConnectivityResources(context); - match = resources.get().getString( - com.android.connectivity.resources.R.string.config_ethernet_iface_regex); - } - return match; - } - - public String[] getInterfaceConfigFromResource(Context context) { - final String[] platformInterfaceConfigs = getPlatformInterfaceConfigs(context); - final String[] interfaceConfigs; - if (platformInterfaceConfigs.length != 0) { - // Platform resource is not the historical default: use the overlay - interfaceConfigs = platformInterfaceConfigs; - } else { - final ConnectivityResources resources = new ConnectivityResources(context); - interfaceConfigs = resources.get().getStringArray( - com.android.connectivity.resources.R.array.config_ethernet_interfaces); - } - return interfaceConfigs; - } - } - - EthernetTracker(@NonNull final Context context, @NonNull final Handler handler, - @NonNull final EthernetNetworkFactory factory, @NonNull final INetd netd) { - this(context, handler, factory, netd, new Dependencies()); - } - - @VisibleForTesting - EthernetTracker(@NonNull final Context context, @NonNull final Handler handler, - @NonNull final EthernetNetworkFactory factory, @NonNull final INetd netd, - @NonNull final Dependencies deps) { - mContext = context; - mHandler = handler; - mFactory = factory; - mNetd = netd; - mDeps = deps; - - // Interface match regex. - updateIfaceMatchRegexp(); - - // Read default Ethernet interface configuration from resources - final String[] interfaceConfigs = mDeps.getInterfaceConfigFromResource(context); - for (String strConfig : interfaceConfigs) { - parseEthernetConfig(strConfig); - } - - mConfigStore = new EthernetConfigStore(); - } - - void start() { - mFactory.register(); - 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 { - PermissionUtils.enforceNetworkStackPermission(mContext); - mNetd.registerUnsolicitedEventListener(new InterfaceObserver()); - } catch (RemoteException | ServiceSpecificException 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); - } - writeIpConfiguration(iface, ipConfiguration); - mHandler.post(() -> { - mFactory.updateInterface(iface, ipConfiguration, null, null); - broadcastInterfaceStateChange(iface); - }); - } - - private void writeIpConfiguration(@NonNull final String iface, - @NonNull final IpConfiguration ipConfig) { - mConfigStore.write(iface, ipConfig); - mIpConfigurations.put(iface, ipConfig); - } - - private IpConfiguration getIpConfigurationForCallback(String iface, int state) { - return (state == EthernetManager.STATE_ABSENT) ? null : getOrCreateIpConfiguration(iface); - } - - private void ensureRunningOnEthernetServiceThread() { - if (mHandler.getLooper().getThread() != Thread.currentThread()) { - throw new IllegalStateException( - "Not running on EthernetService thread: " - + Thread.currentThread().getName()); - } - } - - /** - * Broadcast the link state or IpConfiguration change of existing Ethernet interfaces to all - * listeners. - */ - protected void broadcastInterfaceStateChange(@NonNull String iface) { - ensureRunningOnEthernetServiceThread(); - final int state = mFactory.getInterfaceState(iface); - final int role = getInterfaceRole(iface); - final IpConfiguration config = getIpConfigurationForCallback(iface, state); - final int n = mListeners.beginBroadcast(); - for (int i = 0; i < n; i++) { - try { - mListeners.getBroadcastItem(i).onInterfaceStateChanged(iface, state, role, config); - } catch (RemoteException e) { - // Do nothing here. - } - } - mListeners.finishBroadcast(); - } - - /** - * Unicast the interface state or IpConfiguration change of existing Ethernet interfaces to a - * specific listener. - */ - protected void unicastInterfaceStateChange(@NonNull IEthernetServiceListener listener, - @NonNull String iface) { - ensureRunningOnEthernetServiceThread(); - final int state = mFactory.getInterfaceState(iface); - final int role = getInterfaceRole(iface); - final IpConfiguration config = getIpConfigurationForCallback(iface, state); - try { - listener.onInterfaceStateChanged(iface, state, role, config); - } catch (RemoteException e) { - // Do nothing here. - } - } - - @VisibleForTesting(visibility = PACKAGE) - protected void updateConfiguration(@NonNull final String iface, - @Nullable final IpConfiguration ipConfig, - @Nullable final NetworkCapabilities capabilities, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { - if (DBG) { - Log.i(TAG, "updateConfiguration, iface: " + iface + ", capabilities: " + capabilities - + ", ipConfig: " + ipConfig); - } - - final IpConfiguration localIpConfig = ipConfig == null - ? null : new IpConfiguration(ipConfig); - if (ipConfig != null) { - writeIpConfiguration(iface, localIpConfig); - } - - if (null != capabilities) { - mNetworkCapabilities.put(iface, capabilities); - } - mHandler.post(() -> { - mFactory.updateInterface(iface, localIpConfig, capabilities, listener); - broadcastInterfaceStateChange(iface); - }); - } - - @VisibleForTesting(visibility = PACKAGE) - protected void connectNetwork(@NonNull final String iface, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { - mHandler.post(() -> updateInterfaceState(iface, true, listener)); - } - - @VisibleForTesting(visibility = PACKAGE) - protected void disconnectNetwork(@NonNull final String iface, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { - mHandler.post(() -> updateInterfaceState(iface, false, listener)); - } - - IpConfiguration getIpConfiguration(String iface) { - return mIpConfigurations.get(iface); - } - - @VisibleForTesting(visibility = PACKAGE) - protected boolean isTrackingInterface(String iface) { - return mFactory.hasInterface(iface); - } - - String[] getInterfaces(boolean includeRestricted) { - return mFactory.getAvailableInterfaces(includeRestricted); - } - - List<String> getInterfaceList() { - final List<String> interfaceList = new ArrayList<String>(); - final String[] ifaces; - try { - ifaces = mNetd.interfaceGetList(); - } catch (RemoteException e) { - Log.e(TAG, "Could not get list of interfaces " + e); - return interfaceList; - } - final String ifaceMatch = mIfaceMatch; - for (String iface : ifaces) { - if (iface.matches(ifaceMatch)) interfaceList.add(iface); - } - return interfaceList; - } - - /** - * 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) { - mHandler.post(() -> { - if (!mListeners.register(listener, new ListenerInfo(canUseRestrictedNetworks))) { - // Remote process has already died - return; - } - for (String iface : getInterfaces(canUseRestrictedNetworks)) { - unicastInterfaceStateChange(listener, iface); - } - - unicastEthernetStateChange(listener, mEthernetState); - }); - } - - void removeListener(IEthernetServiceListener listener) { - mHandler.post(() -> mListeners.unregister(listener)); - } - - public void setIncludeTestInterfaces(boolean include) { - mHandler.post(() -> { - mIncludeTestInterfaces = include; - updateIfaceMatchRegexp(); - mHandler.post(() -> trackAvailableInterfaces()); - }); - } - - public void requestTetheredInterface(ITetheredInterfaceCallback callback) { - mHandler.post(() -> { - if (!mTetheredInterfaceRequests.register(callback)) { - // Remote process has already died - return; - } - if (mDefaultInterfaceMode == INTERFACE_MODE_SERVER) { - if (mTetheredInterfaceWasAvailable) { - notifyTetheredInterfaceAvailable(callback, mDefaultInterface); - } - return; - } - - setDefaultInterfaceMode(INTERFACE_MODE_SERVER); - }); - } - - public void releaseTetheredInterface(ITetheredInterfaceCallback callback) { - mHandler.post(() -> { - mTetheredInterfaceRequests.unregister(callback); - maybeUntetherDefaultInterface(); - }); - } - - private void notifyTetheredInterfaceAvailable(ITetheredInterfaceCallback cb, String iface) { - try { - cb.onAvailable(iface); - } catch (RemoteException e) { - Log.e(TAG, "Error sending tethered interface available callback", e); - } - } - - private void notifyTetheredInterfaceUnavailable(ITetheredInterfaceCallback cb) { - try { - cb.onUnavailable(); - } catch (RemoteException e) { - Log.e(TAG, "Error sending tethered interface available callback", e); - } - } - - private void maybeUntetherDefaultInterface() { - if (mTetheredInterfaceRequests.getRegisteredCallbackCount() > 0) return; - if (mDefaultInterfaceMode == INTERFACE_MODE_CLIENT) return; - setDefaultInterfaceMode(INTERFACE_MODE_CLIENT); - } - - private void setDefaultInterfaceMode(int mode) { - Log.d(TAG, "Setting default interface mode to " + mode); - mDefaultInterfaceMode = mode; - if (mDefaultInterface != null) { - removeInterface(mDefaultInterface); - addInterface(mDefaultInterface); - } - } - - private int getInterfaceRole(final String iface) { - if (!mFactory.hasInterface(iface)) return EthernetManager.ROLE_NONE; - final int mode = getInterfaceMode(iface); - return (mode == INTERFACE_MODE_CLIENT) - ? EthernetManager.ROLE_CLIENT - : EthernetManager.ROLE_SERVER; - } - - private int getInterfaceMode(final String iface) { - if (iface.equals(mDefaultInterface)) { - return mDefaultInterfaceMode; - } - return INTERFACE_MODE_CLIENT; - } - - private void removeInterface(String iface) { - mFactory.removeInterface(iface); - maybeUpdateServerModeInterfaceState(iface, false); - } - - private void stopTrackingInterface(String iface) { - removeInterface(iface); - if (iface.equals(mDefaultInterface)) { - mDefaultInterface = null; - } - broadcastInterfaceStateChange(iface); - } - - private void addInterface(String iface) { - InterfaceConfigurationParcel config = null; - // Bring up the interface so we get link status indications. - try { - PermissionUtils.enforceNetworkStackPermission(mContext); - NetdUtils.setInterfaceUp(mNetd, iface); - config = NetdUtils.getInterfaceConfigParcel(mNetd, iface); - } catch (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 parcelable for " + iface + ". Bailing out."); - return; - } - - final String hwAddress = config.hwAddr; - - NetworkCapabilities nc = mNetworkCapabilities.get(iface); - if (nc == null) { - // Try to resolve using mac address - nc = mNetworkCapabilities.get(hwAddress); - if (nc == null) { - final boolean isTestIface = iface.matches(TEST_IFACE_REGEXP); - nc = createDefaultNetworkCapabilities(isTestIface); - } - } - - final int mode = getInterfaceMode(iface); - if (mode == INTERFACE_MODE_CLIENT) { - IpConfiguration ipConfiguration = getOrCreateIpConfiguration(iface); - Log.d(TAG, "Tracking interface in client mode: " + iface); - mFactory.addInterface(iface, hwAddress, ipConfiguration, nc); - } else { - maybeUpdateServerModeInterfaceState(iface, true); - } - - // 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 (NetdUtils.hasFlag(config, "running")) { - updateInterfaceState(iface, true); - } - } - - private void updateInterfaceState(String iface, boolean up) { - updateInterfaceState(iface, up, null /* listener */); - } - - private void updateInterfaceState(@NonNull final String iface, final boolean up, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { - final int mode = getInterfaceMode(iface); - final boolean factoryLinkStateUpdated = (mode == INTERFACE_MODE_CLIENT) - && mFactory.updateInterfaceLinkState(iface, up, listener); - - if (factoryLinkStateUpdated) { - broadcastInterfaceStateChange(iface); - } - } - - private void maybeUpdateServerModeInterfaceState(String iface, boolean available) { - if (available == mTetheredInterfaceWasAvailable || !iface.equals(mDefaultInterface)) return; - - Log.d(TAG, (available ? "Tracking" : "No longer tracking") - + " interface in server mode: " + iface); - - final int pendingCbs = mTetheredInterfaceRequests.beginBroadcast(); - for (int i = 0; i < pendingCbs; i++) { - ITetheredInterfaceCallback item = mTetheredInterfaceRequests.getBroadcastItem(i); - if (available) { - notifyTetheredInterfaceAvailable(item, iface); - } else { - notifyTetheredInterfaceUnavailable(item); - } - } - mTetheredInterfaceRequests.finishBroadcast(); - mTetheredInterfaceWasAvailable = available; - } - - private void maybeTrackInterface(String iface) { - if (!iface.matches(mIfaceMatch)) { - return; - } - - // If we don't already track this interface, and if this interface matches - // our regex, start tracking it. - if (mFactory.hasInterface(iface) || iface.equals(mDefaultInterface)) { - if (DBG) Log.w(TAG, "Ignoring already-tracked interface " + iface); - return; - } - if (DBG) Log.i(TAG, "maybeTrackInterface: " + iface); - - // TODO: avoid making an interface default if it has configured NetworkCapabilities. - if (mDefaultInterface == null) { - mDefaultInterface = iface; - } - - if (mIpConfigForDefaultInterface != null) { - updateIpConfiguration(iface, mIpConfigForDefaultInterface); - mIpConfigForDefaultInterface = null; - } - - addInterface(iface); - - broadcastInterfaceStateChange(iface); - } - - private void trackAvailableInterfaces() { - try { - final String[] ifaces = mNetd.interfaceGetList(); - for (String iface : ifaces) { - maybeTrackInterface(iface); - } - } catch (RemoteException | ServiceSpecificException e) { - Log.e(TAG, "Could not get list of interfaces " + e); - } - } - - private class InterfaceObserver extends BaseNetdUnsolicitedEventListener { - - @Override - public void onInterfaceLinkStateChanged(String iface, boolean up) { - if (DBG) { - Log.i(TAG, "interfaceLinkStateChanged, iface: " + iface + ", up: " + up); - } - mHandler.post(() -> updateInterfaceState(iface, up)); - } - - @Override - public void onInterfaceAdded(String iface) { - if (DBG) { - Log.i(TAG, "onInterfaceAdded, iface: " + iface); - } - mHandler.post(() -> maybeTrackInterface(iface)); - } - - @Override - public void onInterfaceRemoved(String iface) { - if (DBG) { - Log.i(TAG, "onInterfaceRemoved, iface: " + iface); - } - mHandler.post(() -> stopTrackingInterface(iface)); - } - } - - private static class ListenerInfo { - - boolean canUseRestrictedNetworks = false; - - ListenerInfo(boolean canUseRestrictedNetworks) { - this.canUseRestrictedNetworks = canUseRestrictedNetworks; - } - } - - /** - * Parses an Ethernet interface configuration - * - * @param configString represents an Ethernet configuration in the following format: {@code - * <interface name|mac address>;[Network Capabilities];[IP config];[Override Transport]} - */ - private void parseEthernetConfig(String configString) { - final EthernetTrackerConfig config = createEthernetTrackerConfig(configString); - NetworkCapabilities nc = createNetworkCapabilities( - !TextUtils.isEmpty(config.mCapabilities) /* clear default capabilities */, - config.mCapabilities, config.mTransport).build(); - mNetworkCapabilities.put(config.mIface, nc); - - if (null != config.mIpConfig) { - IpConfiguration ipConfig = parseStaticIpConfiguration(config.mIpConfig); - mIpConfigurations.put(config.mIface, ipConfig); - } - } - - @VisibleForTesting - static EthernetTrackerConfig createEthernetTrackerConfig(@NonNull final String configString) { - Objects.requireNonNull(configString, "EthernetTrackerConfig requires non-null config"); - return new EthernetTrackerConfig(configString.split(";", /* limit of tokens */ 4)); - } - - private static NetworkCapabilities createDefaultNetworkCapabilities(boolean isTestIface) { - NetworkCapabilities.Builder builder = createNetworkCapabilities( - false /* clear default capabilities */, null, null) - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED) - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); - - if (isTestIface) { - builder.addTransportType(NetworkCapabilities.TRANSPORT_TEST); - } else { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); - } - - return builder.build(); - } - - /** - * Parses a static list of network capabilities - * - * @param clearDefaultCapabilities Indicates whether or not to clear any default capabilities - * @param commaSeparatedCapabilities A comma separated string list of integer encoded - * NetworkCapability.NET_CAPABILITY_* values - * @param overrideTransport A string representing a single integer encoded override transport - * type. Must be one of the NetworkCapability.TRANSPORT_* - * values. TRANSPORT_VPN is not supported. Errors with input - * will cause the override to be ignored. - */ - @VisibleForTesting - static NetworkCapabilities.Builder createNetworkCapabilities( - boolean clearDefaultCapabilities, @Nullable String commaSeparatedCapabilities, - @Nullable String overrideTransport) { - - final NetworkCapabilities.Builder builder = clearDefaultCapabilities - ? NetworkCapabilities.Builder.withoutDefaultCapabilities() - : new NetworkCapabilities.Builder(); - - // Determine the transport type. If someone has tried to define an override transport then - // attempt to add it. Since we can only have one override, all errors with it will - // gracefully default back to TRANSPORT_ETHERNET and warn the user. VPN is not allowed as an - // override type. Wifi Aware and LoWPAN are currently unsupported as well. - int transport = NetworkCapabilities.TRANSPORT_ETHERNET; - if (!TextUtils.isEmpty(overrideTransport)) { - try { - int parsedTransport = Integer.valueOf(overrideTransport); - if (parsedTransport == NetworkCapabilities.TRANSPORT_VPN - || parsedTransport == NetworkCapabilities.TRANSPORT_WIFI_AWARE - || parsedTransport == NetworkCapabilities.TRANSPORT_LOWPAN) { - Log.e(TAG, "Override transport '" + parsedTransport + "' is not supported. " - + "Defaulting to TRANSPORT_ETHERNET"); - } else { - transport = parsedTransport; - } - } catch (NumberFormatException nfe) { - Log.e(TAG, "Override transport type '" + overrideTransport + "' " - + "could not be parsed. Defaulting to TRANSPORT_ETHERNET"); - } - } - - // Apply the transport. If the user supplied a valid number that is not a valid transport - // then adding will throw an exception. Default back to TRANSPORT_ETHERNET if that happens - try { - builder.addTransportType(transport); - } catch (IllegalArgumentException iae) { - Log.e(TAG, transport + " is not a valid NetworkCapability.TRANSPORT_* value. " - + "Defaulting to TRANSPORT_ETHERNET"); - builder.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET); - } - - builder.setLinkUpstreamBandwidthKbps(100 * 1000); - builder.setLinkDownstreamBandwidthKbps(100 * 1000); - - if (!TextUtils.isEmpty(commaSeparatedCapabilities)) { - for (String strNetworkCapability : commaSeparatedCapabilities.split(",")) { - if (!TextUtils.isEmpty(strNetworkCapability)) { - try { - builder.addCapability(Integer.valueOf(strNetworkCapability)); - } catch (NumberFormatException nfe) { - Log.e(TAG, "Capability '" + strNetworkCapability + "' could not be parsed"); - } catch (IllegalArgumentException iae) { - Log.e(TAG, strNetworkCapability + " is not a valid " - + "NetworkCapability.NET_CAPABILITY_* value"); - } - } - } - } - // Ethernet networks have no way to update the following capabilities, so they always - // have them. - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); - - return builder; - } - - /** - * Parses static IP configuration. - * - * @param staticIpConfig represents static IP configuration in the following format: {@code - * ip=<ip-address/mask> gateway=<ip-address> dns=<comma-sep-ip-addresses> - * domains=<comma-sep-domains>} - */ - @VisibleForTesting - static IpConfiguration parseStaticIpConfiguration(String staticIpConfig) { - final StaticIpConfiguration.Builder staticIpConfigBuilder = - new StaticIpConfiguration.Builder(); - - for (String keyValueAsString : staticIpConfig.trim().split(" ")) { - if (TextUtils.isEmpty(keyValueAsString)) continue; - - String[] pair = keyValueAsString.split("="); - if (pair.length != 2) { - throw new IllegalArgumentException("Unexpected token: " + keyValueAsString - + " in " + staticIpConfig); - } - - String key = pair[0]; - String value = pair[1]; - - switch (key) { - case "ip": - staticIpConfigBuilder.setIpAddress(new LinkAddress(value)); - break; - case "domains": - staticIpConfigBuilder.setDomains(value); - break; - case "gateway": - staticIpConfigBuilder.setGateway(InetAddress.parseNumericAddress(value)); - break; - case "dns": { - ArrayList<InetAddress> dnsAddresses = new ArrayList<>(); - for (String address: value.split(",")) { - dnsAddresses.add(InetAddress.parseNumericAddress(address)); - } - staticIpConfigBuilder.setDnsServers(dnsAddresses); - break; - } - default : { - throw new IllegalArgumentException("Unexpected key: " + key - + " in " + staticIpConfig); - } - } - } - return createIpConfiguration(staticIpConfigBuilder.build()); - } - - private static IpConfiguration createIpConfiguration( - @NonNull final StaticIpConfiguration staticIpConfig) { - return new IpConfiguration.Builder().setStaticIpConfiguration(staticIpConfig).build(); - } - - private IpConfiguration getOrCreateIpConfiguration(String iface) { - IpConfiguration ret = mIpConfigurations.get(iface); - if (ret != null) return ret; - ret = new IpConfiguration(); - ret.setIpAssignment(IpAssignment.DHCP); - ret.setProxySettings(ProxySettings.NONE); - return ret; - } - - private void updateIfaceMatchRegexp() { - final String match = mDeps.getInterfaceRegexFromResource(mContext); - mIfaceMatch = mIncludeTestInterfaces - ? "(" + match + "|" + TEST_IFACE_REGEXP + ")" - : match; - Log.d(TAG, "Interface match regexp set to '" + mIfaceMatch + "'"); - } - - /** - * Validate if a given interface is valid for testing. - * - * @param iface the name of the interface to validate. - * @return {@code true} if test interfaces are enabled and the given {@code iface} has a test - * interface prefix, {@code false} otherwise. - */ - public boolean isValidTestInterface(@NonNull final String iface) { - return mIncludeTestInterfaces && iface.matches(TEST_IFACE_REGEXP); - } - - private void postAndWaitForRunnable(Runnable r) { - final ConditionVariable cv = new ConditionVariable(); - if (mHandler.post(() -> { - r.run(); - cv.open(); - })) { - cv.block(2000L); - } - } - - @VisibleForTesting(visibility = PACKAGE) - protected void setEthernetEnabled(boolean enabled) { - mHandler.post(() -> { - int newState = enabled ? ETHERNET_STATE_ENABLED : ETHERNET_STATE_DISABLED; - if (mEthernetState == newState) return; - - mEthernetState = newState; - - if (enabled) { - trackAvailableInterfaces(); - } else { - // TODO: maybe also disable server mode interface as well. - untrackFactoryInterfaces(); - } - broadcastEthernetStateChange(mEthernetState); - }); - } - - private void untrackFactoryInterfaces() { - for (String iface : mFactory.getAvailableInterfaces(true /* includeRestricted */)) { - stopTrackingInterface(iface); - } - } - - private void unicastEthernetStateChange(@NonNull IEthernetServiceListener listener, - int state) { - ensureRunningOnEthernetServiceThread(); - try { - listener.onEthernetStateChanged(state); - } catch (RemoteException e) { - // Do nothing here. - } - } - - private void broadcastEthernetStateChange(int state) { - ensureRunningOnEthernetServiceThread(); - final int n = mListeners.beginBroadcast(); - for (int i = 0; i < n; i++) { - try { - mListeners.getBroadcastItem(i).onEthernetStateChanged(state); - } catch (RemoteException e) { - // Do nothing here. - } - } - mListeners.finishBroadcast(); - } - - void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) { - postAndWaitForRunnable(() -> { - pw.println(getClass().getSimpleName()); - pw.println("Ethernet interface name filter: " + mIfaceMatch); - pw.println("Default interface: " + mDefaultInterface); - pw.println("Default interface mode: " + mDefaultInterfaceMode); - pw.println("Tethered interface requests: " - + mTetheredInterfaceRequests.getRegisteredCallbackCount()); - 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); - }); - } - - @VisibleForTesting - static class EthernetTrackerConfig { - final String mIface; - final String mCapabilities; - final String mIpConfig; - final String mTransport; - - EthernetTrackerConfig(@NonNull final String[] tokens) { - Objects.requireNonNull(tokens, "EthernetTrackerConfig requires non-null tokens"); - mIface = tokens[0]; - mCapabilities = tokens.length > 1 ? tokens[1] : null; - mIpConfig = tokens.length > 2 && !TextUtils.isEmpty(tokens[2]) ? tokens[2] : null; - mTransport = tokens.length > 3 ? tokens[3] : null; - } - } -} |