From e7a7ef99f94206a42388b5bf42a4c0e9f61a718e Mon Sep 17 00:00:00 2001 From: Alex Cheung Date: Tue, 20 May 2014 10:32:34 -0700 Subject: [PATCH 001/152] Initial empty repository From eb730a7ffcc43ba2a717cba97ce8a65244c5e722 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 20 May 2014 16:58:34 -0700 Subject: [PATCH 002/152] Initial EthernetService implementation. Bug: 14981801 Bug: 14993642 Change-Id: If392ef7063e096854ef830f4fe3b038439a1d307 --- Android.mk | 30 ++ .../server/ethernet/EthernetConfigStore.java | 63 +++ .../ethernet/EthernetNetworkFactory.java | 398 ++++++++++++++++++ .../server/ethernet/EthernetService.java | 45 ++ .../server/ethernet/EthernetServiceImpl.java | 177 ++++++++ 5 files changed, 713 insertions(+) create mode 100644 Android.mk create mode 100644 service-t/src/com/android/server/ethernet/EthernetConfigStore.java create mode 100644 service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java create mode 100644 service-t/src/com/android/server/ethernet/EthernetService.java create mode 100644 service-t/src/com/android/server/ethernet/EthernetServiceImpl.java diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000000..99559ac686 --- /dev/null +++ b/Android.mk @@ -0,0 +1,30 @@ +# 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. + +LOCAL_PATH := $(call my-dir) + +# Build the java code +# ============================================================ + +include $(CLEAR_VARS) + +LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/java +LOCAL_SRC_FILES := $(call all-java-files-under, java) \ + $(call all-Iaidl-files-under, java) \ + $(call all-logtags-files-under, java) + +LOCAL_JAVA_LIBRARIES := services +LOCAL_MODULE := ethernet-service + +include $(BUILD_JAVA_LIBRARY) diff --git a/service-t/src/com/android/server/ethernet/EthernetConfigStore.java b/service-t/src/com/android/server/ethernet/EthernetConfigStore.java new file mode 100644 index 0000000000..7a428a8b32 --- /dev/null +++ b/service-t/src/com/android/server/ethernet/EthernetConfigStore.java @@ -0,0 +1,63 @@ +/* + * 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.net.IpConfiguration; +import android.net.IpConfiguration.IpAssignment; +import android.net.IpConfiguration.ProxySettings; +import android.net.LinkProperties; +import android.os.Environment; +import android.util.Log; +import android.util.SparseArray; + +import com.android.server.net.IpConfigStore; + + +/** + * This class provides an API to store and manage Ethernet network configuration. + */ +public class EthernetConfigStore extends IpConfigStore { + private static final String TAG = "EthernetConfigStore"; + + private static final String ipConfigFile = Environment.getDataDirectory() + + "/misc/ethernet/ipconfig.txt"; + + public EthernetConfigStore() { + } + + public IpConfiguration readIpAndProxyConfigurations() { + SparseArray networks = readIpAndProxyConfigurations(ipConfigFile); + + if (networks.size() == 0) { + Log.w(TAG, "No Ethernet configuration found. Using default."); + return new IpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, new LinkProperties()); + } + + if (networks.size() > 1) { + // 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 writeIpAndProxyConfigurations(IpConfiguration config) { + SparseArray networks = new SparseArray(); + networks.put(0, config); + writeIpAndProxyConfigurations(ipConfigFile, networks); + } +} diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java new file mode 100644 index 0000000000..588913b18f --- /dev/null +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -0,0 +1,398 @@ +/* + * 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.ConnectivityManager; +import android.net.ConnectivityServiceProtocol.NetworkFactoryProtocol; +import android.net.DhcpResults; +import android.net.InterfaceConfiguration; +import android.net.NetworkUtils; +import android.net.IpConfiguration; +import android.net.IpConfiguration.IpAssignment; +import android.net.IpConfiguration.ProxySettings; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.NetworkAgent; +import android.net.NetworkCapabilities; +import android.net.NetworkInfo; +import android.net.NetworkInfo.DetailedState; +import android.net.NetworkRequest; +import android.net.EthernetManager; +import android.os.Handler; +import android.os.IBinder; +import android.os.INetworkManagementService; +import android.os.Looper; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.text.TextUtils; +import android.util.Log; + +import com.android.server.net.BaseNetworkObserver; + +import java.net.Inet4Address; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + + +class NetworkFactory extends Handler { + public interface Callback { + public void onRequestNetwork(NetworkRequest request, int currentScore); + public void onCancelRequest(NetworkRequest request); + } + + private String mName; + private Callback mCallback; + private ConnectivityManager mCM; + + NetworkFactory(String name, Context context, Looper looper, Callback callback) { + super(looper); + mCallback = callback; + mName = name; + mCM = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + } + + public void register() { + logi("Registering network factory"); + mCM.registerNetworkFactory(new Messenger(this), mName); + } + + @Override + public void handleMessage(Message message) { + switch(message.what) { + case NetworkFactoryProtocol.CMD_REQUEST_NETWORK: + mCallback.onRequestNetwork((NetworkRequest) message.obj, message.arg1); + break; + case NetworkFactoryProtocol.CMD_CANCEL_REQUEST: + mCallback.onCancelRequest((NetworkRequest) message.obj); + break; + default: + loge("Unhandled message " + message.what); + } + } + + private void logi(String s) { + Log.i("NetworkFactory" + mName, s); + } + + private void loge(String s) { + Log.e("NetworkFactory" + mName, s); + } +} + +/** + * This class tracks the data connection associated with Ethernet. + * @hide + */ +class EthernetNetworkFactory implements NetworkFactory.Callback { + 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 the NetworkManagementService thread. */ + private InterfaceObserver mInterfaceObserver; + + /** For static IP configuration */ + private EthernetManager mEthernetManager; + + /** To set link state and configure IP addresses. */ + private INetworkManagementService mNMService; + + /* To communicate with ConnectivityManager */ + private NetworkCapabilities mNetworkCapabilities; + private NetworkAgent mNetworkAgent; + private NetworkFactory mFactory; + + /** Product-dependent regular expression of interface names we want to track. */ + private static String mIfaceMatch = ""; + + /** Data members. All accesses must be synchronized(this). */ + private static String mIface = ""; + private String mHwAddr; + private static boolean mLinkUp; + private NetworkInfo mNetworkInfo; + private LinkProperties mLinkProperties; + + EthernetNetworkFactory() { + mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); + mLinkProperties = new LinkProperties(); + initNetworkCapabilities(); + } + + private void updateInterfaceState(String iface, boolean up) { + if (!mIface.equals(iface)) { + // We only support one interface. + return; + } + Log.d(TAG, "updateInterface: " + iface + " link " + (up ? "up" : "down")); + + synchronized(this) { + mLinkUp = up; + mNetworkInfo.setIsAvailable(up); + DetailedState state = up ? DetailedState.CONNECTED: DetailedState.DISCONNECTED; + mNetworkInfo.setDetailedState(state, null, mHwAddr); + mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0); + updateAgent(); + } + } + + private class InterfaceObserver extends BaseNetworkObserver { + @Override + public void interfaceLinkStateChanged(String iface, boolean up) { + updateInterfaceState(iface, up); + } + + @Override + public void interfaceAdded(String iface) { + maybeTrackInterface(iface); + } + + @Override + public void interfaceRemoved(String iface) { + stopTrackingInterface(iface); + } + } + + 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 iterface config for " + iface + ". Bailing out."); + return; + } + + synchronized (this) { + if (mIface.isEmpty()) { + mIface = iface; + mHwAddr = config.getHardwareAddress(); + mNetworkInfo.setIsAvailable(true); + mNetworkInfo.setExtraInfo(mHwAddr); + } else { + Log.e(TAG, "Interface unexpectedly changed from " + iface + " to " + mIface); + mNMService.setInterfaceDown(iface); + } + } + } catch (RemoteException e) { + 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) || !mIface.isEmpty()) + return false; + + Log.d(TAG, "Started tracking interface " + iface); + setInterfaceUp(iface); + return true; + } + + private void stopTrackingInterface(String iface) { + if (!iface.equals(mIface)) + return; + + Log.d(TAG, "Stopped tracking interface " + iface); + disconnect(); + synchronized (this) { + mIface = ""; + mHwAddr = null; + mNetworkInfo.setExtraInfo(null); + } + } + + private void setStaticIpAddress(LinkProperties linkProperties) { + Log.i(TAG, "Applying static IPv4 configuration to " + mIface + ": " + mLinkProperties); + try { + InterfaceConfiguration config = mNMService.getInterfaceConfig(mIface); + for (LinkAddress address: linkProperties.getLinkAddresses()) { + // IPv6 uses autoconfiguration. + if (address.getAddress() instanceof Inet4Address) { + config.setLinkAddress(address); + // This API only supports one IPv4 address. + mNMService.setInterfaceConfig(mIface, config); + break; + } + } + } catch(RemoteException e) { + Log.e(TAG, "Setting static IP address failed: " + e.getMessage()); + } catch(IllegalStateException e) { + Log.e(TAG, "Setting static IP address failed: " + e.getMessage()); + } + } + + public void updateAgent() { + if (DBG) { + Log.i(TAG, "Updating mNetworkAgent with: " + + mNetworkCapabilities + ", " + + mNetworkInfo + ", " + + mLinkProperties); + } + mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); + mNetworkAgent.sendNetworkInfo(mNetworkInfo); + mNetworkAgent.sendLinkProperties(mLinkProperties); + } + + /* Called by the NetworkAgent on the handler thread. */ + public void connect() { + // TODO: Handle DHCP renew. + Thread dhcpThread = new Thread(new Runnable() { + public void run() { + if (DBG) Log.i(TAG, "dhcpThread: mNetworkInfo=" + mNetworkInfo); + mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); + LinkProperties linkProperties; + + IpConfiguration config = mEthernetManager.getConfiguration(); + + if (config.ipAssignment == IpAssignment.STATIC) { + linkProperties = config.linkProperties; + linkProperties.setInterfaceName(mIface); + setStaticIpAddress(linkProperties); + } else { + DhcpResults dhcpResults = new DhcpResults(); + // TODO: support more than one DHCP client. + if (!NetworkUtils.runDhcp(mIface, dhcpResults)) { + Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError()); + mNetworkAgent.sendNetworkScore(0); + return; + } + linkProperties = dhcpResults.linkProperties; + } + if (config.proxySettings == ProxySettings.STATIC) { + linkProperties.setHttpProxy(config.linkProperties.getHttpProxy()); + } + + synchronized(EthernetNetworkFactory.this) { + mLinkProperties = linkProperties; + mNetworkInfo.setIsAvailable(true); + mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr); + updateAgent(); + } + } + }); + dhcpThread.start(); + } + + public void disconnect() { + NetworkUtils.stopDhcp(mIface); + + synchronized(this) { + mLinkProperties.clear(); + mNetworkInfo.setIsAvailable(false); + mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); + updateAgent(); + } + + try { + mNMService.clearInterfaceAddresses(mIface); + } catch (Exception e) { + Log.e(TAG, "Failed to clear addresses or disable ipv6" + e); + } + } + + /** + * Begin monitoring connectivity + */ + public synchronized void start(Context context, Handler target) { + // The services we use. + IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); + mNMService = INetworkManagementService.Stub.asInterface(b); + mEthernetManager = (EthernetManager) context.getSystemService(Context.ETHERNET_SERVICE); + + // Interface match regex. + mIfaceMatch = context.getResources().getString( + com.android.internal.R.string.config_ethernet_iface_regex); + + // Create our NetworkAgent. + mNetworkAgent = new NetworkAgent(target.getLooper(), context, NETWORK_TYPE) { + public synchronized void sendNetworkScore(int score) { + Log.i(TAG, "sendNetworkScore(" + score + ")"); + super.sendNetworkScore(score); + } + public void connect() { + EthernetNetworkFactory.this.connect(); + }; + public void disconnect() { + EthernetNetworkFactory.this.disconnect(); + }; + }; + mNetworkAgent.sendNetworkScore(0); + + // Create and register our NetworkFactory. + mFactory = new NetworkFactory(NETWORK_TYPE, context, target.getLooper(), this); + mFactory.register(); + + // 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. + try { + final String[] ifaces = mNMService.listInterfaces(); + for (String iface : ifaces) { + if (maybeTrackInterface(iface)) { + break; + } + } + } catch (RemoteException e) { + Log.e(TAG, "Could not get list of interfaces " + e); + } + } + + public synchronized void stop() { + disconnect(); + mIface = ""; + mHwAddr = null; + mLinkUp = false; + mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); + mLinkProperties = new LinkProperties(); + } + + public void onRequestNetwork(NetworkRequest request, int currentScore) { + Log.i(TAG, "onRequestNetwork: (" + currentScore + "): " + request); + // TODO check that the transport is compatible. + mNetworkAgent.addNetworkRequest(request, currentScore); + } + + public void onCancelRequest(NetworkRequest request) { + Log.i(TAG, "onCancelRequest: " + request); + mNetworkAgent.removeNetworkRequest(request); + } + + private void initNetworkCapabilities() { + mNetworkCapabilities = new NetworkCapabilities(); + mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET); + mNetworkCapabilities.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + mNetworkCapabilities.addNetworkCapability( + 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); + } +} diff --git a/service-t/src/com/android/server/ethernet/EthernetService.java b/service-t/src/com/android/server/ethernet/EthernetService.java new file mode 100644 index 0000000000..2448146ed5 --- /dev/null +++ b/service-t/src/com/android/server/ethernet/EthernetService.java @@ -0,0 +1,45 @@ +/* + * 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.util.Log; +import com.android.server.SystemService; + +public final class EthernetService extends SystemService { + + private static final String TAG = "EthernetService"; + final EthernetServiceImpl mImpl; + + public EthernetService(Context context) { + super(context); + mImpl = new EthernetServiceImpl(context); + } + + @Override + public void onStart() { + Log.i(TAG, "Registering service " + Context.ETHERNET_SERVICE); + publishBinderService(Context.ETHERNET_SERVICE, mImpl); + } + + @Override + public void onBootPhase(int phase) { + if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { + mImpl.start(); + } + } +} diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java new file mode 100644 index 0000000000..08a2e9afce --- /dev/null +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -0,0 +1,177 @@ +/* + * 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.content.pm.PackageManager; +import com.android.internal.util.IndentingPrintWriter; +import android.net.ConnectivityManager; +import android.net.IEthernetManager; +import android.net.IpConfiguration; +import android.net.IpConfiguration.IpAssignment; +import android.net.IpConfiguration.ProxySettings; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.NetworkAgent; +import android.net.NetworkInfo; +import android.net.NetworkRequest; +import android.net.RouteInfo; +import android.os.Binder; +import android.os.IBinder; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.os.Messenger; +import android.os.INetworkManagementService; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.text.TextUtils; +import android.util.Log; +import android.util.PrintWriterPrinter; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.concurrent.atomic.AtomicBoolean; + + +/** + * EthernetServiceImpl handles remote Ethernet operation requests by implementing + * the IEthernetManager interface. + * + * @hide + */ +public class EthernetServiceImpl extends IEthernetManager.Stub { + private static final String TAG = "EthernetServiceImpl"; + + private final Context mContext; + private final EthernetConfigStore mEthernetConfigStore; + private final INetworkManagementService mNMService; + private final AtomicBoolean mStarted = new AtomicBoolean(false); + private IpConfiguration mIpConfiguration; + private ConnectivityManager mCM; + + private Handler mHandler; + private NetworkInfo mNetworkInfo; + private EthernetNetworkFactory mTracker; + + public EthernetServiceImpl(Context context) { + mContext = context; + Log.i(TAG, "Creating EthernetConfigStore"); + mEthernetConfigStore = new EthernetConfigStore(); + mIpConfiguration = mEthernetConfigStore.readIpAndProxyConfigurations(); + + Log.i(TAG, "Read stored IP configuration: " + mIpConfiguration); + + IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); + mNMService = INetworkManagementService.Stub.asInterface(b); + + mTracker = new EthernetNetworkFactory(); + } + + private void enforceAccessPermission() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.ACCESS_NETWORK_STATE, + "EthernetService"); + } + + private void enforceChangePermission() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.CHANGE_NETWORK_STATE, + "EthernetService"); + } + + private void enforceConnectivityInternalPermission() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.CONNECTIVITY_INTERNAL, + "ConnectivityService"); + } + + public void start() { + Log.i(TAG, "Starting Ethernet service"); + mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + + HandlerThread handlerThread = new HandlerThread("EthernetServiceThread"); + handlerThread.start(); + mHandler = new Handler(handlerThread.getLooper()); + + mTracker.start(mContext, mHandler); + + mStarted.set(true); + } + + /** + * Get Ethernet configuration + * @return the Ethernet Configuration, contained in {@link IpConfiguration}. + */ + public IpConfiguration getConfiguration() { + enforceAccessPermission(); + + synchronized (mIpConfiguration) { + return new IpConfiguration(mIpConfiguration); + } + } + + /** + * Set Ethernet configuration + */ + public void setConfiguration(IpConfiguration config) { + if (!mStarted.get()) { + Log.w(TAG, "System isn't ready enough to change ethernet configuration"); + } + + enforceChangePermission(); + enforceConnectivityInternalPermission(); + + synchronized (mIpConfiguration) { + mEthernetConfigStore.writeIpAndProxyConfigurations(config); + + // TODO: this does not check proxy settings, gateways, etc. + // Fix this by making IpConfiguration a complete representation of static configuration. + if (!config.equals(mIpConfiguration)) { + mIpConfiguration.ipAssignment = config.ipAssignment; + mIpConfiguration.proxySettings = config.proxySettings; + mIpConfiguration.linkProperties = new LinkProperties(config.linkProperties); + + mTracker.stop(); + mTracker.start(mContext, mHandler); + } + } + } + + @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("Stored Ethernet configuration: "); + + pw.increaseIndent(); + pw.println(mIpConfiguration); + pw.decreaseIndent(); + + pw.println("Handler:"); + pw.increaseIndent(); + mHandler.dump(new PrintWriterPrinter(pw), "EthernetServiceImpl"); + pw.decreaseIndent(); + } +} From 21be8b6dc7c121457efc4ea18a1112cbc2e2ae00 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 22 May 2014 12:26:37 -0700 Subject: [PATCH 003/152] Make Ethernet more reliable. 1. If DHCP fails, set the score to 0. Coupled with changes in NetworkAgent, that will cause us to retry DHCP the next time the link is plugged in. 2. Send LinkProperties before sending NetworkInfo, because of a race in NetworkAgent. 3. Make Ethernet work properly after a runtime restart. 4. Improve locking. 5. Clarify how things work in comments. Bug: 15295359 Change-Id: I06cd683a1633838bca1ec177e61f1829889d3934 --- .../ethernet/EthernetNetworkFactory.java | 107 ++++++++++++++---- 1 file changed, 85 insertions(+), 22 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 588913b18f..76e0f0434d 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -97,7 +97,20 @@ class NetworkFactory extends Handler { } /** - * This class tracks the data connection associated with Ethernet. + * Manages connectivity for an Ethernet interface. + * + * Ethernet Interfaces may be present at boot time or appear after boot (e.g., + * for Ethernet adapters connected over USB). This class currently supports + * 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 config_ethernet_iface_regex + * 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 implements NetworkFactory.Callback { @@ -106,7 +119,7 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { private static final int NETWORK_SCORE = 70; private static final boolean DBG = true; - /** Tracks interface changes. Called from the NetworkManagementService thread. */ + /** Tracks interface changes. Called from NetworkManagementService. */ private InterfaceObserver mInterfaceObserver; /** For static IP configuration */ @@ -120,10 +133,10 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { private NetworkAgent mNetworkAgent; private NetworkFactory mFactory; - /** Product-dependent regular expression of interface names we want to track. */ + /** Product-dependent regular expression of interface names we track. */ private static String mIfaceMatch = ""; - /** Data members. All accesses must be synchronized(this). */ + /** Data members. All accesses to these must be synchronized(this). */ private static String mIface = ""; private String mHwAddr; private static boolean mLinkUp; @@ -136,9 +149,12 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { initNetworkCapabilities(); } + /** + * Updates interface state variables. + * Called on link state changes or on startup. + */ private void updateInterfaceState(String iface, boolean up) { if (!mIface.equals(iface)) { - // We only support one interface. return; } Log.d(TAG, "updateInterface: " + iface + " link " + (up ? "up" : "down")); @@ -146,8 +162,10 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { synchronized(this) { mLinkUp = up; mNetworkInfo.setIsAvailable(up); - DetailedState state = up ? DetailedState.CONNECTED: DetailedState.DISCONNECTED; - mNetworkInfo.setDetailedState(state, null, mHwAddr); + if (!up) { + // Tell the agent we're disconnected. It will call disconnect(). + mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); + } mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0); updateAgent(); } @@ -219,6 +237,8 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { mIface = ""; mHwAddr = null; mNetworkInfo.setExtraInfo(null); + mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); + mLinkProperties = new LinkProperties(); } } @@ -242,7 +262,7 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { } } - public void updateAgent() { + public synchronized void updateAgent() { if (DBG) { Log.i(TAG, "Updating mNetworkAgent with: " + mNetworkCapabilities + ", " + @@ -250,34 +270,65 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { mLinkProperties); } mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); - mNetworkAgent.sendNetworkInfo(mNetworkInfo); + // Send LinkProperties before NetworkInfo. + // + // This is because if we just connected, as soon as we send the agent a + // connected NetworkInfo, the agent will register with CS, and at that + // point the current LinkProperties will be empty, with no IP + // addresses, DNS servers or routes, only an interface name. (The + // agent will refuse to register if LinkProperties are null, but not if + // they are "empty" like this.) + // + // This causes two problems: + // + // 1. ConnectivityService brings up the network with empty + // LinkProperties, and thus no routes and no DNS servers. + // 2. When we do send LinkProperties immediately after that, the agent + // does not pass them on to ConnectivityService because its + // mAsyncChannel is null. + // + // TODO: Fix NetworkAgent to make sure that sending updates just after + // connecting works properly. mNetworkAgent.sendLinkProperties(mLinkProperties); + mNetworkAgent.sendNetworkInfo(mNetworkInfo); } /* Called by the NetworkAgent on the handler thread. */ public void connect() { - // TODO: Handle DHCP renew. Thread dhcpThread = new Thread(new Runnable() { public void run() { if (DBG) Log.i(TAG, "dhcpThread: mNetworkInfo=" + mNetworkInfo); - mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); + synchronized(this) { + mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); + updateAgent(); + } LinkProperties linkProperties; IpConfiguration config = mEthernetManager.getConfiguration(); if (config.ipAssignment == IpAssignment.STATIC) { linkProperties = config.linkProperties; - linkProperties.setInterfaceName(mIface); setStaticIpAddress(linkProperties); } else { DhcpResults dhcpResults = new DhcpResults(); - // TODO: support more than one DHCP client. + // TODO: Handle DHCP renewals better. + // In general runDhcp handles DHCP renewals for us, because + // the dhcp client stays running, but if the renewal fails, + // we will lose our IP address and connectivity without + // noticing. if (!NetworkUtils.runDhcp(mIface, dhcpResults)) { Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError()); - mNetworkAgent.sendNetworkScore(0); + synchronized(EthernetNetworkFactory.this) { + // DHCP failed. Tell the agent we now have a score + // of 0, and it will call disconnect for us. We'll + // attempt to reconnect when we next see a link up + // event, which resets the score to NETWORK_SCORE. + mNetworkAgent.sendNetworkScore(0); + } return; } linkProperties = dhcpResults.linkProperties; + linkProperties.setInterfaceName(mIface); } if (config.proxySettings == ProxySettings.STATIC) { linkProperties.setHttpProxy(config.linkProperties.getHttpProxy()); @@ -294,6 +345,11 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { dhcpThread.start(); } + /** + * Clears layer 3 properties and reports disconnect. + * Does not touch interface state variables such as link state and MAC address. + * Called when the tracked interface loses link or disappears. + */ public void disconnect() { NetworkUtils.stopDhcp(mIface); @@ -356,8 +412,20 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { try { final String[] ifaces = mNMService.listInterfaces(); for (String iface : ifaces) { - if (maybeTrackInterface(iface)) { - break; + synchronized(this) { + 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. Since we're already holding the lock, + // any real link up/down notification will only arrive + // after we've done this. + if (mNMService.getInterfaceConfig(iface).hasFlag("running")) { + updateInterfaceState(iface, true); + } + break; + } } } } catch (RemoteException e) { @@ -366,12 +434,7 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { } public synchronized void stop() { - disconnect(); - mIface = ""; - mHwAddr = null; - mLinkUp = false; - mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); - mLinkProperties = new LinkProperties(); + stopTrackingInterface(mIface); } public void onRequestNetwork(NetworkRequest request, int currentScore) { From 0ffeaf5c76b7ca4163cf3a7a33e3a36ef77e445e Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 22 May 2014 12:26:37 -0700 Subject: [PATCH 004/152] DO NOT MERGE - Make Ethernet more reliable. 1. If DHCP fails, set the score to 0. Coupled with changes in NetworkAgent, that will cause us to retry DHCP the next time the link is plugged in. 2. Send LinkProperties before sending NetworkInfo, because of a race in NetworkAgent. 3. Make Ethernet work properly after a runtime restart. 4. Improve locking. 5. Clarify how things work in comments. Bug: 15295359 Change-Id: I06cd683a1633838bca1ec177e61f1829889d3934 (cherry picked from commit 21be8b6dc7c121457efc4ea18a1112cbc2e2ae00) --- .../ethernet/EthernetNetworkFactory.java | 107 ++++++++++++++---- 1 file changed, 85 insertions(+), 22 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 588913b18f..76e0f0434d 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -97,7 +97,20 @@ class NetworkFactory extends Handler { } /** - * This class tracks the data connection associated with Ethernet. + * Manages connectivity for an Ethernet interface. + * + * Ethernet Interfaces may be present at boot time or appear after boot (e.g., + * for Ethernet adapters connected over USB). This class currently supports + * 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 config_ethernet_iface_regex + * 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 implements NetworkFactory.Callback { @@ -106,7 +119,7 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { private static final int NETWORK_SCORE = 70; private static final boolean DBG = true; - /** Tracks interface changes. Called from the NetworkManagementService thread. */ + /** Tracks interface changes. Called from NetworkManagementService. */ private InterfaceObserver mInterfaceObserver; /** For static IP configuration */ @@ -120,10 +133,10 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { private NetworkAgent mNetworkAgent; private NetworkFactory mFactory; - /** Product-dependent regular expression of interface names we want to track. */ + /** Product-dependent regular expression of interface names we track. */ private static String mIfaceMatch = ""; - /** Data members. All accesses must be synchronized(this). */ + /** Data members. All accesses to these must be synchronized(this). */ private static String mIface = ""; private String mHwAddr; private static boolean mLinkUp; @@ -136,9 +149,12 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { initNetworkCapabilities(); } + /** + * Updates interface state variables. + * Called on link state changes or on startup. + */ private void updateInterfaceState(String iface, boolean up) { if (!mIface.equals(iface)) { - // We only support one interface. return; } Log.d(TAG, "updateInterface: " + iface + " link " + (up ? "up" : "down")); @@ -146,8 +162,10 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { synchronized(this) { mLinkUp = up; mNetworkInfo.setIsAvailable(up); - DetailedState state = up ? DetailedState.CONNECTED: DetailedState.DISCONNECTED; - mNetworkInfo.setDetailedState(state, null, mHwAddr); + if (!up) { + // Tell the agent we're disconnected. It will call disconnect(). + mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); + } mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0); updateAgent(); } @@ -219,6 +237,8 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { mIface = ""; mHwAddr = null; mNetworkInfo.setExtraInfo(null); + mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); + mLinkProperties = new LinkProperties(); } } @@ -242,7 +262,7 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { } } - public void updateAgent() { + public synchronized void updateAgent() { if (DBG) { Log.i(TAG, "Updating mNetworkAgent with: " + mNetworkCapabilities + ", " + @@ -250,34 +270,65 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { mLinkProperties); } mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); - mNetworkAgent.sendNetworkInfo(mNetworkInfo); + // Send LinkProperties before NetworkInfo. + // + // This is because if we just connected, as soon as we send the agent a + // connected NetworkInfo, the agent will register with CS, and at that + // point the current LinkProperties will be empty, with no IP + // addresses, DNS servers or routes, only an interface name. (The + // agent will refuse to register if LinkProperties are null, but not if + // they are "empty" like this.) + // + // This causes two problems: + // + // 1. ConnectivityService brings up the network with empty + // LinkProperties, and thus no routes and no DNS servers. + // 2. When we do send LinkProperties immediately after that, the agent + // does not pass them on to ConnectivityService because its + // mAsyncChannel is null. + // + // TODO: Fix NetworkAgent to make sure that sending updates just after + // connecting works properly. mNetworkAgent.sendLinkProperties(mLinkProperties); + mNetworkAgent.sendNetworkInfo(mNetworkInfo); } /* Called by the NetworkAgent on the handler thread. */ public void connect() { - // TODO: Handle DHCP renew. Thread dhcpThread = new Thread(new Runnable() { public void run() { if (DBG) Log.i(TAG, "dhcpThread: mNetworkInfo=" + mNetworkInfo); - mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); + synchronized(this) { + mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); + updateAgent(); + } LinkProperties linkProperties; IpConfiguration config = mEthernetManager.getConfiguration(); if (config.ipAssignment == IpAssignment.STATIC) { linkProperties = config.linkProperties; - linkProperties.setInterfaceName(mIface); setStaticIpAddress(linkProperties); } else { DhcpResults dhcpResults = new DhcpResults(); - // TODO: support more than one DHCP client. + // TODO: Handle DHCP renewals better. + // In general runDhcp handles DHCP renewals for us, because + // the dhcp client stays running, but if the renewal fails, + // we will lose our IP address and connectivity without + // noticing. if (!NetworkUtils.runDhcp(mIface, dhcpResults)) { Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError()); - mNetworkAgent.sendNetworkScore(0); + synchronized(EthernetNetworkFactory.this) { + // DHCP failed. Tell the agent we now have a score + // of 0, and it will call disconnect for us. We'll + // attempt to reconnect when we next see a link up + // event, which resets the score to NETWORK_SCORE. + mNetworkAgent.sendNetworkScore(0); + } return; } linkProperties = dhcpResults.linkProperties; + linkProperties.setInterfaceName(mIface); } if (config.proxySettings == ProxySettings.STATIC) { linkProperties.setHttpProxy(config.linkProperties.getHttpProxy()); @@ -294,6 +345,11 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { dhcpThread.start(); } + /** + * Clears layer 3 properties and reports disconnect. + * Does not touch interface state variables such as link state and MAC address. + * Called when the tracked interface loses link or disappears. + */ public void disconnect() { NetworkUtils.stopDhcp(mIface); @@ -356,8 +412,20 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { try { final String[] ifaces = mNMService.listInterfaces(); for (String iface : ifaces) { - if (maybeTrackInterface(iface)) { - break; + synchronized(this) { + 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. Since we're already holding the lock, + // any real link up/down notification will only arrive + // after we've done this. + if (mNMService.getInterfaceConfig(iface).hasFlag("running")) { + updateInterfaceState(iface, true); + } + break; + } } } } catch (RemoteException e) { @@ -366,12 +434,7 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { } public synchronized void stop() { - disconnect(); - mIface = ""; - mHwAddr = null; - mLinkUp = false; - mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); - mLinkProperties = new LinkProperties(); + stopTrackingInterface(mIface); } public void onRequestNetwork(NetworkRequest request, int currentScore) { From 8af038d056e6bca4749b4c19779864bf39be628f Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 27 May 2014 17:59:24 -0700 Subject: [PATCH 005/152] Apply refactored NetworkFactory. Make NetworkFactory a concrete class and divide responsibilites between it and NetworkAgent. Factory will track requests and by default give a single connect/disconnect api for ease of use. Then NetworkAgent is created and destroyed as needed with very simple logic. Change-Id: I401c14a6e5466f2fc63b04219b97ff85bb9af291 --- .../ethernet/EthernetNetworkFactory.java | 187 +++++++----------- 1 file changed, 69 insertions(+), 118 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 76e0f0434d..bbbdacaf62 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -18,7 +18,6 @@ package com.android.server.ethernet; import android.content.Context; import android.net.ConnectivityManager; -import android.net.ConnectivityServiceProtocol.NetworkFactoryProtocol; import android.net.DhcpResults; import android.net.InterfaceConfiguration; import android.net.NetworkUtils; @@ -29,6 +28,7 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkAgent; import android.net.NetworkCapabilities; +import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkRequest; @@ -51,51 +51,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -class NetworkFactory extends Handler { - public interface Callback { - public void onRequestNetwork(NetworkRequest request, int currentScore); - public void onCancelRequest(NetworkRequest request); - } - - private String mName; - private Callback mCallback; - private ConnectivityManager mCM; - - NetworkFactory(String name, Context context, Looper looper, Callback callback) { - super(looper); - mCallback = callback; - mName = name; - mCM = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - } - - public void register() { - logi("Registering network factory"); - mCM.registerNetworkFactory(new Messenger(this), mName); - } - - @Override - public void handleMessage(Message message) { - switch(message.what) { - case NetworkFactoryProtocol.CMD_REQUEST_NETWORK: - mCallback.onRequestNetwork((NetworkRequest) message.obj, message.arg1); - break; - case NetworkFactoryProtocol.CMD_CANCEL_REQUEST: - mCallback.onCancelRequest((NetworkRequest) message.obj); - break; - default: - loge("Unhandled message " + message.what); - } - } - - private void logi(String s) { - Log.i("NetworkFactory" + mName, s); - } - - private void loge(String s) { - Log.e("NetworkFactory" + mName, s); - } -} - /** * Manages connectivity for an Ethernet interface. * @@ -113,8 +68,8 @@ class NetworkFactory extends Handler { * * @hide */ -class EthernetNetworkFactory implements NetworkFactory.Callback { - private static final String NETWORK_TYPE = "ETHERNET"; +class EthernetNetworkFactory { + 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; @@ -131,7 +86,8 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { /* To communicate with ConnectivityManager */ private NetworkCapabilities mNetworkCapabilities; private NetworkAgent mNetworkAgent; - private NetworkFactory mFactory; + private LocalNetworkFactory mFactory; + private Context mContext; /** Product-dependent regular expression of interface names we track. */ private static String mIfaceMatch = ""; @@ -149,6 +105,20 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { initNetworkCapabilities(); } + private class LocalNetworkFactory extends NetworkFactory { + LocalNetworkFactory(String name, Context context, Looper looper) { + super(looper, context, name, new NetworkCapabilities()); + } + + protected void startNetwork() { + onRequestNetwork(); + } + protected void stopNetwork() { + onCancelRequest(); + } + } + + /** * Updates interface state variables. * Called on link state changes or on startup. @@ -166,8 +136,9 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { // Tell the agent we're disconnected. It will call disconnect(). mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); } - mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0); + mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : -1); updateAgent(); + mFactory.setScoreFilter(up ? NETWORK_SCORE : -1); } } @@ -232,7 +203,7 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { return; Log.d(TAG, "Stopped tracking interface " + iface); - disconnect(); + onCancelRequest(); synchronized (this) { mIface = ""; mHwAddr = null; @@ -262,46 +233,28 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { } } - public synchronized void updateAgent() { - if (DBG) { - Log.i(TAG, "Updating mNetworkAgent with: " + - mNetworkCapabilities + ", " + - mNetworkInfo + ", " + - mLinkProperties); + public void updateAgent() { + synchronized (EthernetNetworkFactory.this) { + if (mNetworkAgent == null) return; + if (DBG) { + Log.i(TAG, "Updating mNetworkAgent with: " + + mNetworkCapabilities + ", " + + mNetworkInfo + ", " + + mLinkProperties); + } + mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); + mNetworkAgent.sendNetworkInfo(mNetworkInfo); + mNetworkAgent.sendLinkProperties(mLinkProperties); + mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : -1); } - mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); - // Send LinkProperties before NetworkInfo. - // - // This is because if we just connected, as soon as we send the agent a - // connected NetworkInfo, the agent will register with CS, and at that - // point the current LinkProperties will be empty, with no IP - // addresses, DNS servers or routes, only an interface name. (The - // agent will refuse to register if LinkProperties are null, but not if - // they are "empty" like this.) - // - // This causes two problems: - // - // 1. ConnectivityService brings up the network with empty - // LinkProperties, and thus no routes and no DNS servers. - // 2. When we do send LinkProperties immediately after that, the agent - // does not pass them on to ConnectivityService because its - // mAsyncChannel is null. - // - // TODO: Fix NetworkAgent to make sure that sending updates just after - // connecting works properly. - mNetworkAgent.sendLinkProperties(mLinkProperties); - mNetworkAgent.sendNetworkInfo(mNetworkInfo); } - /* Called by the NetworkAgent on the handler thread. */ - public void connect() { + /* Called by the NetworkFactory on the handler thread. */ + public void onRequestNetwork() { + // TODO: Handle DHCP renew. Thread dhcpThread = new Thread(new Runnable() { public void run() { - if (DBG) Log.i(TAG, "dhcpThread: mNetworkInfo=" + mNetworkInfo); - synchronized(this) { - mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); - updateAgent(); - } + if (DBG) Log.i(TAG, "dhcpThread(+" + mIface + "): mNetworkInfo=" + mNetworkInfo); LinkProperties linkProperties; IpConfiguration config = mEthernetManager.getConfiguration(); @@ -310,6 +263,11 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { linkProperties = config.linkProperties; setStaticIpAddress(linkProperties); } else { + mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); + synchronized (EthernetNetworkFactory.this) { + mNetworkAgent.sendNetworkInfo(mNetworkInfo); + } + DhcpResults dhcpResults = new DhcpResults(); // TODO: Handle DHCP renewals better. // In general runDhcp handles DHCP renewals for us, because @@ -323,8 +281,9 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { // of 0, and it will call disconnect for us. We'll // attempt to reconnect when we next see a link up // event, which resets the score to NETWORK_SCORE. - mNetworkAgent.sendNetworkScore(0); + mNetworkAgent.sendNetworkScore(-1); } + mFactory.setScoreFilter(-1); return; } linkProperties = dhcpResults.linkProperties; @@ -338,7 +297,15 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { mLinkProperties = linkProperties; mNetworkInfo.setIsAvailable(true); mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr); - updateAgent(); + + // Create our NetworkAgent. + mNetworkAgent = new NetworkAgent(mFactory.getLooper(), mContext, + NETWORK_TYPE, mNetworkInfo, mNetworkCapabilities, mLinkProperties, + NETWORK_SCORE) { + public void unwanted() { + EthernetNetworkFactory.this.onCancelRequest(); + }; + }; } } }); @@ -350,14 +317,14 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { * Does not touch interface state variables such as link state and MAC address. * Called when the tracked interface loses link or disappears. */ - public void disconnect() { + public void onCancelRequest() { NetworkUtils.stopDhcp(mIface); synchronized(this) { mLinkProperties.clear(); - mNetworkInfo.setIsAvailable(false); mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); updateAgent(); + mNetworkAgent = null; } try { @@ -380,25 +347,14 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { mIfaceMatch = context.getResources().getString( com.android.internal.R.string.config_ethernet_iface_regex); - // Create our NetworkAgent. - mNetworkAgent = new NetworkAgent(target.getLooper(), context, NETWORK_TYPE) { - public synchronized void sendNetworkScore(int score) { - Log.i(TAG, "sendNetworkScore(" + score + ")"); - super.sendNetworkScore(score); - } - public void connect() { - EthernetNetworkFactory.this.connect(); - }; - public void disconnect() { - EthernetNetworkFactory.this.disconnect(); - }; - }; - mNetworkAgent.sendNetworkScore(0); - // Create and register our NetworkFactory. - mFactory = new NetworkFactory(NETWORK_TYPE, context, target.getLooper(), this); + mFactory = new LocalNetworkFactory(NETWORK_TYPE, context, target.getLooper()); + mFactory.setCapabilityFilter(mNetworkCapabilities); + mFactory.setScoreFilter(-1); // this set high when we have an iface mFactory.register(); + mContext = context; + // Start tracking interface change events. mInterfaceObserver = new InterfaceObserver(); try { @@ -434,18 +390,13 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { } public synchronized void stop() { - stopTrackingInterface(mIface); - } - - public void onRequestNetwork(NetworkRequest request, int currentScore) { - Log.i(TAG, "onRequestNetwork: (" + currentScore + "): " + request); - // TODO check that the transport is compatible. - mNetworkAgent.addNetworkRequest(request, currentScore); - } - - public void onCancelRequest(NetworkRequest request) { - Log.i(TAG, "onCancelRequest: " + request); - mNetworkAgent.removeNetworkRequest(request); + onCancelRequest(); + mIface = ""; + mHwAddr = null; + mLinkUp = false; + mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); + mLinkProperties = new LinkProperties(); + mFactory.unregister(); } private void initNetworkCapabilities() { From 301c18a01dc3bc9f0d1e8c3e716ddf1921a0d343 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 27 May 2014 17:59:24 -0700 Subject: [PATCH 006/152] Apply refactored NetworkFactory. Make NetworkFactory a concrete class and divide responsibilites between it and NetworkAgent. Factory will track requests and by default give a single connect/disconnect api for ease of use. Then NetworkAgent is created and destroyed as needed with very simple logic. Change-Id: I401c14a6e5466f2fc63b04219b97ff85bb9af291 (cherry picked from commit 8af038d056e6bca4749b4c19779864bf39be628f) --- .../ethernet/EthernetNetworkFactory.java | 187 +++++++----------- 1 file changed, 69 insertions(+), 118 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 76e0f0434d..bbbdacaf62 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -18,7 +18,6 @@ package com.android.server.ethernet; import android.content.Context; import android.net.ConnectivityManager; -import android.net.ConnectivityServiceProtocol.NetworkFactoryProtocol; import android.net.DhcpResults; import android.net.InterfaceConfiguration; import android.net.NetworkUtils; @@ -29,6 +28,7 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkAgent; import android.net.NetworkCapabilities; +import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkRequest; @@ -51,51 +51,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -class NetworkFactory extends Handler { - public interface Callback { - public void onRequestNetwork(NetworkRequest request, int currentScore); - public void onCancelRequest(NetworkRequest request); - } - - private String mName; - private Callback mCallback; - private ConnectivityManager mCM; - - NetworkFactory(String name, Context context, Looper looper, Callback callback) { - super(looper); - mCallback = callback; - mName = name; - mCM = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - } - - public void register() { - logi("Registering network factory"); - mCM.registerNetworkFactory(new Messenger(this), mName); - } - - @Override - public void handleMessage(Message message) { - switch(message.what) { - case NetworkFactoryProtocol.CMD_REQUEST_NETWORK: - mCallback.onRequestNetwork((NetworkRequest) message.obj, message.arg1); - break; - case NetworkFactoryProtocol.CMD_CANCEL_REQUEST: - mCallback.onCancelRequest((NetworkRequest) message.obj); - break; - default: - loge("Unhandled message " + message.what); - } - } - - private void logi(String s) { - Log.i("NetworkFactory" + mName, s); - } - - private void loge(String s) { - Log.e("NetworkFactory" + mName, s); - } -} - /** * Manages connectivity for an Ethernet interface. * @@ -113,8 +68,8 @@ class NetworkFactory extends Handler { * * @hide */ -class EthernetNetworkFactory implements NetworkFactory.Callback { - private static final String NETWORK_TYPE = "ETHERNET"; +class EthernetNetworkFactory { + 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; @@ -131,7 +86,8 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { /* To communicate with ConnectivityManager */ private NetworkCapabilities mNetworkCapabilities; private NetworkAgent mNetworkAgent; - private NetworkFactory mFactory; + private LocalNetworkFactory mFactory; + private Context mContext; /** Product-dependent regular expression of interface names we track. */ private static String mIfaceMatch = ""; @@ -149,6 +105,20 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { initNetworkCapabilities(); } + private class LocalNetworkFactory extends NetworkFactory { + LocalNetworkFactory(String name, Context context, Looper looper) { + super(looper, context, name, new NetworkCapabilities()); + } + + protected void startNetwork() { + onRequestNetwork(); + } + protected void stopNetwork() { + onCancelRequest(); + } + } + + /** * Updates interface state variables. * Called on link state changes or on startup. @@ -166,8 +136,9 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { // Tell the agent we're disconnected. It will call disconnect(). mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); } - mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0); + mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : -1); updateAgent(); + mFactory.setScoreFilter(up ? NETWORK_SCORE : -1); } } @@ -232,7 +203,7 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { return; Log.d(TAG, "Stopped tracking interface " + iface); - disconnect(); + onCancelRequest(); synchronized (this) { mIface = ""; mHwAddr = null; @@ -262,46 +233,28 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { } } - public synchronized void updateAgent() { - if (DBG) { - Log.i(TAG, "Updating mNetworkAgent with: " + - mNetworkCapabilities + ", " + - mNetworkInfo + ", " + - mLinkProperties); + public void updateAgent() { + synchronized (EthernetNetworkFactory.this) { + if (mNetworkAgent == null) return; + if (DBG) { + Log.i(TAG, "Updating mNetworkAgent with: " + + mNetworkCapabilities + ", " + + mNetworkInfo + ", " + + mLinkProperties); + } + mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); + mNetworkAgent.sendNetworkInfo(mNetworkInfo); + mNetworkAgent.sendLinkProperties(mLinkProperties); + mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : -1); } - mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); - // Send LinkProperties before NetworkInfo. - // - // This is because if we just connected, as soon as we send the agent a - // connected NetworkInfo, the agent will register with CS, and at that - // point the current LinkProperties will be empty, with no IP - // addresses, DNS servers or routes, only an interface name. (The - // agent will refuse to register if LinkProperties are null, but not if - // they are "empty" like this.) - // - // This causes two problems: - // - // 1. ConnectivityService brings up the network with empty - // LinkProperties, and thus no routes and no DNS servers. - // 2. When we do send LinkProperties immediately after that, the agent - // does not pass them on to ConnectivityService because its - // mAsyncChannel is null. - // - // TODO: Fix NetworkAgent to make sure that sending updates just after - // connecting works properly. - mNetworkAgent.sendLinkProperties(mLinkProperties); - mNetworkAgent.sendNetworkInfo(mNetworkInfo); } - /* Called by the NetworkAgent on the handler thread. */ - public void connect() { + /* Called by the NetworkFactory on the handler thread. */ + public void onRequestNetwork() { + // TODO: Handle DHCP renew. Thread dhcpThread = new Thread(new Runnable() { public void run() { - if (DBG) Log.i(TAG, "dhcpThread: mNetworkInfo=" + mNetworkInfo); - synchronized(this) { - mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); - updateAgent(); - } + if (DBG) Log.i(TAG, "dhcpThread(+" + mIface + "): mNetworkInfo=" + mNetworkInfo); LinkProperties linkProperties; IpConfiguration config = mEthernetManager.getConfiguration(); @@ -310,6 +263,11 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { linkProperties = config.linkProperties; setStaticIpAddress(linkProperties); } else { + mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); + synchronized (EthernetNetworkFactory.this) { + mNetworkAgent.sendNetworkInfo(mNetworkInfo); + } + DhcpResults dhcpResults = new DhcpResults(); // TODO: Handle DHCP renewals better. // In general runDhcp handles DHCP renewals for us, because @@ -323,8 +281,9 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { // of 0, and it will call disconnect for us. We'll // attempt to reconnect when we next see a link up // event, which resets the score to NETWORK_SCORE. - mNetworkAgent.sendNetworkScore(0); + mNetworkAgent.sendNetworkScore(-1); } + mFactory.setScoreFilter(-1); return; } linkProperties = dhcpResults.linkProperties; @@ -338,7 +297,15 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { mLinkProperties = linkProperties; mNetworkInfo.setIsAvailable(true); mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr); - updateAgent(); + + // Create our NetworkAgent. + mNetworkAgent = new NetworkAgent(mFactory.getLooper(), mContext, + NETWORK_TYPE, mNetworkInfo, mNetworkCapabilities, mLinkProperties, + NETWORK_SCORE) { + public void unwanted() { + EthernetNetworkFactory.this.onCancelRequest(); + }; + }; } } }); @@ -350,14 +317,14 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { * Does not touch interface state variables such as link state and MAC address. * Called when the tracked interface loses link or disappears. */ - public void disconnect() { + public void onCancelRequest() { NetworkUtils.stopDhcp(mIface); synchronized(this) { mLinkProperties.clear(); - mNetworkInfo.setIsAvailable(false); mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); updateAgent(); + mNetworkAgent = null; } try { @@ -380,25 +347,14 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { mIfaceMatch = context.getResources().getString( com.android.internal.R.string.config_ethernet_iface_regex); - // Create our NetworkAgent. - mNetworkAgent = new NetworkAgent(target.getLooper(), context, NETWORK_TYPE) { - public synchronized void sendNetworkScore(int score) { - Log.i(TAG, "sendNetworkScore(" + score + ")"); - super.sendNetworkScore(score); - } - public void connect() { - EthernetNetworkFactory.this.connect(); - }; - public void disconnect() { - EthernetNetworkFactory.this.disconnect(); - }; - }; - mNetworkAgent.sendNetworkScore(0); - // Create and register our NetworkFactory. - mFactory = new NetworkFactory(NETWORK_TYPE, context, target.getLooper(), this); + mFactory = new LocalNetworkFactory(NETWORK_TYPE, context, target.getLooper()); + mFactory.setCapabilityFilter(mNetworkCapabilities); + mFactory.setScoreFilter(-1); // this set high when we have an iface mFactory.register(); + mContext = context; + // Start tracking interface change events. mInterfaceObserver = new InterfaceObserver(); try { @@ -434,18 +390,13 @@ class EthernetNetworkFactory implements NetworkFactory.Callback { } public synchronized void stop() { - stopTrackingInterface(mIface); - } - - public void onRequestNetwork(NetworkRequest request, int currentScore) { - Log.i(TAG, "onRequestNetwork: (" + currentScore + "): " + request); - // TODO check that the transport is compatible. - mNetworkAgent.addNetworkRequest(request, currentScore); - } - - public void onCancelRequest(NetworkRequest request) { - Log.i(TAG, "onCancelRequest: " + request); - mNetworkAgent.removeNetworkRequest(request); + onCancelRequest(); + mIface = ""; + mHwAddr = null; + mLinkUp = false; + mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); + mLinkProperties = new LinkProperties(); + mFactory.unregister(); } private void initNetworkCapabilities() { From 521b2bd4839f7dba43b8f705da5863d64b534311 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 4 Jun 2014 11:52:08 -0700 Subject: [PATCH 007/152] Fix ethernet. It was attempting to update the NetworkAgent before the NetworkAgent was created, causing NullPointerExceptions. bug:15407938 Change-Id: Ie36b906df4b12f095a16d1b30c847a55b074d60c --- .../server/ethernet/EthernetNetworkFactory.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index bbbdacaf62..820e16b566 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -136,7 +136,6 @@ class EthernetNetworkFactory { // Tell the agent we're disconnected. It will call disconnect(). mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); } - mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : -1); updateAgent(); mFactory.setScoreFilter(up ? NETWORK_SCORE : -1); } @@ -264,9 +263,6 @@ class EthernetNetworkFactory { setStaticIpAddress(linkProperties); } else { mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); - synchronized (EthernetNetworkFactory.this) { - mNetworkAgent.sendNetworkInfo(mNetworkInfo); - } DhcpResults dhcpResults = new DhcpResults(); // TODO: Handle DHCP renewals better. @@ -276,13 +272,6 @@ class EthernetNetworkFactory { // noticing. if (!NetworkUtils.runDhcp(mIface, dhcpResults)) { Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError()); - synchronized(EthernetNetworkFactory.this) { - // DHCP failed. Tell the agent we now have a score - // of 0, and it will call disconnect for us. We'll - // attempt to reconnect when we next see a link up - // event, which resets the score to NETWORK_SCORE. - mNetworkAgent.sendNetworkScore(-1); - } mFactory.setScoreFilter(-1); return; } From 694a835e89081d7a1c55e635d6a60d51abab63f9 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Mon, 9 Jun 2014 17:36:54 -0700 Subject: [PATCH 008/152] Make NetworkCapabilities publicly immutable. Applying API council comments. bug: 15142362 Change-Id: Ie0bde68b72656a676d90c0343b9756fe9268d8d6 --- .../com/android/server/ethernet/EthernetNetworkFactory.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 820e16b566..483f983fb7 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -391,9 +391,8 @@ class EthernetNetworkFactory { private void initNetworkCapabilities() { mNetworkCapabilities = new NetworkCapabilities(); mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET); - mNetworkCapabilities.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); - mNetworkCapabilities.addNetworkCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + 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); From 8b07ee36a23d5d87b40bfc2e10761051c0232498 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 19 Jun 2014 16:26:03 -0700 Subject: [PATCH 009/152] Don't tear down based on NetworkFactory input. NetworkFactory only indicates if we're interested in new connections. It shouldn't be used to tear down existing connections (they have unwanted callbacks for that). Supports linger properly as well as dealing with tie scores. bug:15612739 Change-Id: Ib3dfe673d3645b9dc4756c176958409a64ec32e4 --- .../ethernet/EthernetNetworkFactory.java | 51 +++++++++---------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 483f983fb7..b1b98d2692 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -114,7 +114,6 @@ class EthernetNetworkFactory { onRequestNetwork(); } protected void stopNetwork() { - onCancelRequest(); } } @@ -202,13 +201,13 @@ class EthernetNetworkFactory { return; Log.d(TAG, "Stopped tracking interface " + iface); - onCancelRequest(); synchronized (this) { mIface = ""; mHwAddr = null; mNetworkInfo.setExtraInfo(null); mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); mLinkProperties = new LinkProperties(); + updateAgent(); } } @@ -283,6 +282,10 @@ class EthernetNetworkFactory { } synchronized(EthernetNetworkFactory.this) { + if (mNetworkAgent != null) { + Log.e(TAG, "Already have a NetworkAgent - aborting new request"); + return; + } mLinkProperties = linkProperties; mNetworkInfo.setIsAvailable(true); mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr); @@ -292,7 +295,25 @@ class EthernetNetworkFactory { NETWORK_TYPE, mNetworkInfo, mNetworkCapabilities, mLinkProperties, NETWORK_SCORE) { public void unwanted() { - EthernetNetworkFactory.this.onCancelRequest(); + synchronized(EthernetNetworkFactory.this) { + if (this == mNetworkAgent) { + NetworkUtils.stopDhcp(mIface); + + mLinkProperties.clear(); + mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, + mHwAddr); + updateAgent(); + mNetworkAgent = null; + try { + mNMService.clearInterfaceAddresses(mIface); + } catch (Exception e) { + Log.e(TAG, "Failed to clear addresses or disable ipv6" + e); + } + } else { + Log.d(TAG, "Ignoring unwanted as we have a more modern " + + "instance"); + } + } }; }; } @@ -301,28 +322,6 @@ class EthernetNetworkFactory { dhcpThread.start(); } - /** - * Clears layer 3 properties and reports disconnect. - * Does not touch interface state variables such as link state and MAC address. - * Called when the tracked interface loses link or disappears. - */ - public void onCancelRequest() { - NetworkUtils.stopDhcp(mIface); - - synchronized(this) { - mLinkProperties.clear(); - mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); - updateAgent(); - mNetworkAgent = null; - } - - try { - mNMService.clearInterfaceAddresses(mIface); - } catch (Exception e) { - Log.e(TAG, "Failed to clear addresses or disable ipv6" + e); - } - } - /** * Begin monitoring connectivity */ @@ -379,12 +378,12 @@ class EthernetNetworkFactory { } public synchronized void stop() { - onCancelRequest(); mIface = ""; mHwAddr = null; mLinkUp = false; mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); mLinkProperties = new LinkProperties(); + updateAgent(); mFactory.unregister(); } From 62e8e4d3d5c345ec0a239eb8985e042176c35743 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 19 Jun 2014 16:26:03 -0700 Subject: [PATCH 010/152] DO NOT MERGE Don't tear down based on NetworkFactory input. NetworkFactory only indicates if we're interested in new connections. It shouldn't be used to tear down existing connections (they have unwanted callbacks for that). Supports linger properly as well as dealing with tie scores. bug:15612739 Change-Id: Ib3dfe673d3645b9dc4756c176958409a64ec32e4 (cherry picked from commit 8b07ee36a23d5d87b40bfc2e10761051c0232498) --- .../ethernet/EthernetNetworkFactory.java | 51 +++++++++---------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 483f983fb7..b1b98d2692 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -114,7 +114,6 @@ class EthernetNetworkFactory { onRequestNetwork(); } protected void stopNetwork() { - onCancelRequest(); } } @@ -202,13 +201,13 @@ class EthernetNetworkFactory { return; Log.d(TAG, "Stopped tracking interface " + iface); - onCancelRequest(); synchronized (this) { mIface = ""; mHwAddr = null; mNetworkInfo.setExtraInfo(null); mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); mLinkProperties = new LinkProperties(); + updateAgent(); } } @@ -283,6 +282,10 @@ class EthernetNetworkFactory { } synchronized(EthernetNetworkFactory.this) { + if (mNetworkAgent != null) { + Log.e(TAG, "Already have a NetworkAgent - aborting new request"); + return; + } mLinkProperties = linkProperties; mNetworkInfo.setIsAvailable(true); mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr); @@ -292,7 +295,25 @@ class EthernetNetworkFactory { NETWORK_TYPE, mNetworkInfo, mNetworkCapabilities, mLinkProperties, NETWORK_SCORE) { public void unwanted() { - EthernetNetworkFactory.this.onCancelRequest(); + synchronized(EthernetNetworkFactory.this) { + if (this == mNetworkAgent) { + NetworkUtils.stopDhcp(mIface); + + mLinkProperties.clear(); + mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, + mHwAddr); + updateAgent(); + mNetworkAgent = null; + try { + mNMService.clearInterfaceAddresses(mIface); + } catch (Exception e) { + Log.e(TAG, "Failed to clear addresses or disable ipv6" + e); + } + } else { + Log.d(TAG, "Ignoring unwanted as we have a more modern " + + "instance"); + } + } }; }; } @@ -301,28 +322,6 @@ class EthernetNetworkFactory { dhcpThread.start(); } - /** - * Clears layer 3 properties and reports disconnect. - * Does not touch interface state variables such as link state and MAC address. - * Called when the tracked interface loses link or disappears. - */ - public void onCancelRequest() { - NetworkUtils.stopDhcp(mIface); - - synchronized(this) { - mLinkProperties.clear(); - mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); - updateAgent(); - mNetworkAgent = null; - } - - try { - mNMService.clearInterfaceAddresses(mIface); - } catch (Exception e) { - Log.e(TAG, "Failed to clear addresses or disable ipv6" + e); - } - } - /** * Begin monitoring connectivity */ @@ -379,12 +378,12 @@ class EthernetNetworkFactory { } public synchronized void stop() { - onCancelRequest(); mIface = ""; mHwAddr = null; mLinkUp = false; mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); mLinkProperties = new LinkProperties(); + updateAgent(); mFactory.unregister(); } From 84502f530060beb56334a9455f95d1b6172b1f5f Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 6 Aug 2014 22:27:17 -0700 Subject: [PATCH 011/152] Add tcp buffer size data for ethernet bug: 16549611 Change-Id: I61d29bb88b9e58c50e03c39570f3ebb7712e4f37 --- .../com/android/server/ethernet/EthernetNetworkFactory.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index b1b98d2692..3f0037cccf 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -247,6 +247,9 @@ class EthernetNetworkFactory { } } + private static final String TCP_BUFFER_SIZES_ETHERNET = + "524288,1048576,3145728,524288,1048576,2097152"; + /* Called by the NetworkFactory on the handler thread. */ public void onRequestNetwork() { // TODO: Handle DHCP renew. @@ -281,6 +284,8 @@ class EthernetNetworkFactory { linkProperties.setHttpProxy(config.linkProperties.getHttpProxy()); } + linkProperties.setTcpBufferSizes(TCP_BUFFER_SIZES_ETHERNET); + synchronized(EthernetNetworkFactory.this) { if (mNetworkAgent != null) { Log.e(TAG, "Already have a NetworkAgent - aborting new request"); From c0cfe2ee04622e16e4623ffe1612e5afbbaf41ae Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 12 Aug 2014 10:49:39 +0900 Subject: [PATCH 012/152] Stop using LinkProperties for static configuration. Also make static IP configuration more robust (e.g., tear down our NetworkAgent when we switch between static and DHCP). Bug: 16114392 Bug: 16893413 Change-Id: Ib33f35c004e30b6067bb20235ffa43c247d174df --- .../server/ethernet/EthernetConfigStore.java | 3 +- .../ethernet/EthernetNetworkFactory.java | 64 +++++++++++-------- .../server/ethernet/EthernetServiceImpl.java | 7 +- 3 files changed, 41 insertions(+), 33 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetConfigStore.java b/service-t/src/com/android/server/ethernet/EthernetConfigStore.java index 7a428a8b32..676bc99d8a 100644 --- a/service-t/src/com/android/server/ethernet/EthernetConfigStore.java +++ b/service-t/src/com/android/server/ethernet/EthernetConfigStore.java @@ -19,7 +19,6 @@ package com.android.server.ethernet; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; -import android.net.LinkProperties; import android.os.Environment; import android.util.Log; import android.util.SparseArray; @@ -44,7 +43,7 @@ public class EthernetConfigStore extends IpConfigStore { if (networks.size() == 0) { Log.w(TAG, "No Ethernet configuration found. Using default."); - return new IpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, new LinkProperties()); + return new IpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, null, null); } if (networks.size() > 1) { diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 3f0037cccf..c65a5b20f5 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -33,6 +33,7 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkRequest; import android.net.EthernetManager; +import android.net.StaticIpConfiguration; import android.os.Handler; import android.os.IBinder; import android.os.INetworkManagementService; @@ -211,24 +212,23 @@ class EthernetNetworkFactory { } } - private void setStaticIpAddress(LinkProperties linkProperties) { - Log.i(TAG, "Applying static IPv4 configuration to " + mIface + ": " + mLinkProperties); - try { - InterfaceConfiguration config = mNMService.getInterfaceConfig(mIface); - for (LinkAddress address: linkProperties.getLinkAddresses()) { - // IPv6 uses autoconfiguration. - if (address.getAddress() instanceof Inet4Address) { - config.setLinkAddress(address); - // This API only supports one IPv4 address. - mNMService.setInterfaceConfig(mIface, config); - break; - } + private boolean setStaticIpAddress(StaticIpConfiguration staticConfig) { + if (staticConfig.ipAddress != null && + staticConfig.gateway != null && + staticConfig.dnsServers.size() > 0) { + try { + Log.i(TAG, "Applying static IPv4 configuration to " + mIface + ": " + staticConfig); + InterfaceConfiguration config = mNMService.getInterfaceConfig(mIface); + config.setLinkAddress(staticConfig.ipAddress); + mNMService.setInterfaceConfig(mIface, config); + return true; + } catch(RemoteException|IllegalStateException e) { + Log.e(TAG, "Setting static IP address failed: " + e.getMessage()); } - } catch(RemoteException e) { - Log.e(TAG, "Setting static IP address failed: " + e.getMessage()); - } catch(IllegalStateException e) { - Log.e(TAG, "Setting static IP address failed: " + e.getMessage()); + } else { + Log.e(TAG, "Invalid static IP configuration."); } + return false; } public void updateAgent() { @@ -260,9 +260,12 @@ class EthernetNetworkFactory { IpConfiguration config = mEthernetManager.getConfiguration(); - if (config.ipAssignment == IpAssignment.STATIC) { - linkProperties = config.linkProperties; - setStaticIpAddress(linkProperties); + if (config.getIpAssignment() == IpAssignment.STATIC) { + if (!setStaticIpAddress(config.getStaticIpConfiguration())) { + // We've already logged an error. + return; + } + linkProperties = config.getStaticIpConfiguration().toLinkProperties(mIface); } else { mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); @@ -277,11 +280,11 @@ class EthernetNetworkFactory { mFactory.setScoreFilter(-1); return; } - linkProperties = dhcpResults.linkProperties; - linkProperties.setInterfaceName(mIface); + linkProperties = dhcpResults.toLinkProperties(mIface); } - if (config.proxySettings == ProxySettings.STATIC) { - linkProperties.setHttpProxy(config.linkProperties.getHttpProxy()); + if (config.getProxySettings() == ProxySettings.STATIC || + config.getProxySettings() == ProxySettings.PAC) { + linkProperties.setHttpProxy(config.getHttpProxy()); } linkProperties.setTcpBufferSizes(TCP_BUFFER_SIZES_ETHERNET); @@ -383,12 +386,21 @@ class EthernetNetworkFactory { } public synchronized void stop() { + NetworkUtils.stopDhcp(mIface); + // 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. + // + // TODO: stop using explicit comparisons to DISCONNECTED / SUSPENDED in ConnectivityService, + // and instead use isConnectedOrConnecting(). + mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); + mLinkUp = false; + updateAgent(); + mLinkProperties = new LinkProperties(); + mNetworkAgent = null; mIface = ""; mHwAddr = null; - mLinkUp = false; mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); - mLinkProperties = new LinkProperties(); - updateAgent(); mFactory.unregister(); } diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 08a2e9afce..1534aabe3e 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -25,11 +25,11 @@ import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; import android.net.LinkAddress; -import android.net.LinkProperties; import android.net.NetworkAgent; import android.net.NetworkInfo; import android.net.NetworkRequest; import android.net.RouteInfo; +import android.net.StaticIpConfiguration; import android.os.Binder; import android.os.IBinder; import android.os.Handler; @@ -143,10 +143,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { // TODO: this does not check proxy settings, gateways, etc. // Fix this by making IpConfiguration a complete representation of static configuration. if (!config.equals(mIpConfiguration)) { - mIpConfiguration.ipAssignment = config.ipAssignment; - mIpConfiguration.proxySettings = config.proxySettings; - mIpConfiguration.linkProperties = new LinkProperties(config.linkProperties); - + mIpConfiguration = new IpConfiguration(config); mTracker.stop(); mTracker.start(mContext, mHandler); } From 1affc58cb6aeda4c566a530b17d47eca1bf68ff7 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 19 Aug 2014 11:45:46 -0700 Subject: [PATCH 013/152] Actually provide useful output in Ethernet service dump. Bug: 17133859 Change-Id: Ic8424004e48712e4dd906d5bb6a48ce7d38ff9d8 --- .../ethernet/EthernetNetworkFactory.java | 20 +++++++++++++++++++ .../server/ethernet/EthernetServiceImpl.java | 10 ++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index c65a5b20f5..26e8264a56 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -45,8 +45,11 @@ import android.os.ServiceManager; import android.text.TextUtils; import android.util.Log; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.net.BaseNetworkObserver; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.net.Inet4Address; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -413,4 +416,21 @@ class EthernetNetworkFactory { mNetworkCapabilities.setLinkUpstreamBandwidthKbps(100 * 1000); mNetworkCapabilities.setLinkDownstreamBandwidthKbps(100 * 1000); } + + synchronized void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) { + if (!TextUtils.isEmpty(mIface)) { + pw.println("Tracking interface: " + mIface); + pw.increaseIndent(); + pw.println("MAC address: " + mHwAddr); + pw.println("Link state: " + (mLinkUp ? "up" : "down")); + pw.decreaseIndent(); + } else { + pw.println("Not tracking any interface"); + } + + pw.println(); + pw.println("NetworkInfo: " + mNetworkInfo); + pw.println("LinkProperties: " + mLinkProperties); + pw.println("NetworkAgent: " + mNetworkAgent); + } } diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 1534aabe3e..42d98f65c8 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -67,7 +67,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { private Handler mHandler; private NetworkInfo mNetworkInfo; - private EthernetNetworkFactory mTracker; + private final EthernetNetworkFactory mTracker; public EthernetServiceImpl(Context context) { mContext = context; @@ -160,8 +160,14 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { + ", uid=" + Binder.getCallingUid()); return; } - pw.println("Stored Ethernet configuration: "); + pw.println("Current Ethernet state: "); + pw.increaseIndent(); + mTracker.dump(fd, pw, args); + pw.decreaseIndent(); + + pw.println(); + pw.println("Stored Ethernet configuration: "); pw.increaseIndent(); pw.println(mIpConfiguration); pw.decreaseIndent(); From eee07beb9239175a5a428701013b87ffb88b7d96 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 21 Aug 2014 16:28:18 -0700 Subject: [PATCH 014/152] Use config resource for tcp buffer size bug:16549611 Change-Id: I48426f6b746e4bd9729bdd529d81b163ff5112a9 --- .../android/server/ethernet/EthernetNetworkFactory.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 26e8264a56..83a3fa7be0 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -250,9 +250,6 @@ class EthernetNetworkFactory { } } - private static final String TCP_BUFFER_SIZES_ETHERNET = - "524288,1048576,3145728,524288,1048576,2097152"; - /* Called by the NetworkFactory on the handler thread. */ public void onRequestNetwork() { // TODO: Handle DHCP renew. @@ -290,7 +287,11 @@ class EthernetNetworkFactory { linkProperties.setHttpProxy(config.getHttpProxy()); } - linkProperties.setTcpBufferSizes(TCP_BUFFER_SIZES_ETHERNET); + String tcpBufferSizes = mContext.getResources().getString( + com.android.internal.R.string.config_ethernet_tcp_buffers); + if (TextUtils.isEmpty(tcpBufferSizes) == false) { + linkProperties.setTcpBufferSizes(tcpBufferSizes); + } synchronized(EthernetNetworkFactory.this) { if (mNetworkAgent != null) { From cf0f619a5080670415693ca772e079a494aaf7f7 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 10 Sep 2014 10:06:32 -0700 Subject: [PATCH 015/152] Don't accept score below 0. Network Factories are allowed to go below, but networks need to be constrained. Allowing the network to go below 0 meant that -1 could sometimes leak through and foul the logic. bug:17361330 Change-Id: Ife34ca0f9c233dd3c3df80f6fea580af43afcdeb --- .../android/server/ethernet/EthernetNetworkFactory.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 83a3fa7be0..a4711548cb 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -140,6 +140,9 @@ class EthernetNetworkFactory { mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); } updateAgent(); + // set our score lower than any network could go + // so we get dropped. TODO - just unregister the factory + // when link goes down. mFactory.setScoreFilter(up ? NETWORK_SCORE : -1); } } @@ -246,7 +249,8 @@ class EthernetNetworkFactory { mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); mNetworkAgent.sendNetworkInfo(mNetworkInfo); mNetworkAgent.sendLinkProperties(mLinkProperties); - mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : -1); + // never set the network score below 0. + mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0); } } @@ -277,6 +281,8 @@ class EthernetNetworkFactory { // noticing. if (!NetworkUtils.runDhcp(mIface, dhcpResults)) { Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError()); + // set our score lower than any network could go + // so we get dropped. mFactory.setScoreFilter(-1); return; } From 272be52cb7c1d61a40ac5f03084c43059bc6476e Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 1 Oct 2014 13:52:40 +0900 Subject: [PATCH 016/152] Clear all Ethernet state when our interface goes away. Previously we did not stop DHCP or try to force a disconnect. This made it impossible to reconnect by unplugging and replugging an USB Ethernet adapter. Bug: 17736828 Change-Id: Idd8576a96b063b5ca726ee9149800bdcb0f62bd1 --- .../android/server/ethernet/EthernetNetworkFactory.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index a4711548cb..2d0a95728b 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -208,13 +208,18 @@ class EthernetNetworkFactory { return; Log.d(TAG, "Stopped tracking interface " + iface); + // TODO: Unify this codepath with stop(). synchronized (this) { + NetworkUtils.stopDhcp(mIface); mIface = ""; mHwAddr = null; mNetworkInfo.setExtraInfo(null); + mLinkUp = false; + mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); + updateAgent(); + mNetworkAgent = null; mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); mLinkProperties = new LinkProperties(); - updateAgent(); } } From f4740f2d370b6458126942156245b2d39ec223f9 Mon Sep 17 00:00:00 2001 From: Jaewan Kim Date: Mon, 20 Oct 2014 12:03:46 +0900 Subject: [PATCH 017/152] Add an API to check availability of Ethernet interface. Bug: 18045481 Change-Id: I3fb517c3e7fa807e2937fda92026301e312be986 --- .../ethernet/EthernetNetworkFactory.java | 61 +++++++++++------ .../server/ethernet/EthernetServiceImpl.java | 67 ++++++++++++------- 2 files changed, 85 insertions(+), 43 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 2d0a95728b..bbb99d8c98 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -19,27 +19,25 @@ package com.android.server.ethernet; 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.NetworkUtils; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; -import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; -import android.net.NetworkRequest; -import android.net.EthernetManager; +import android.net.NetworkUtils; import android.net.StaticIpConfiguration; import android.os.Handler; import android.os.IBinder; import android.os.INetworkManagementService; import android.os.Looper; -import android.os.Message; -import android.os.Messenger; +import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ServiceManager; import android.text.TextUtils; @@ -50,9 +48,6 @@ import com.android.server.net.BaseNetworkObserver; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.net.Inet4Address; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; /** @@ -96,6 +91,9 @@ class EthernetNetworkFactory { /** Product-dependent regular expression of interface names we track. */ private static String mIfaceMatch = ""; + /** To notify Ethernet status. */ + private final RemoteCallbackList mListeners; + /** Data members. All accesses to these must be synchronized(this). */ private static String mIface = ""; private String mHwAddr; @@ -103,10 +101,11 @@ class EthernetNetworkFactory { private NetworkInfo mNetworkInfo; private LinkProperties mLinkProperties; - EthernetNetworkFactory() { + EthernetNetworkFactory(RemoteCallbackList listeners) { mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); mLinkProperties = new LinkProperties(); initNetworkCapabilities(); + mListeners = listeners; } private class LocalNetworkFactory extends NetworkFactory { @@ -177,9 +176,8 @@ class EthernetNetworkFactory { } synchronized (this) { - if (mIface.isEmpty()) { - mIface = iface; - mHwAddr = config.getHardwareAddress(); + if (!isTrackingInterface()) { + setInterfaceInfoLocked(iface, config.getHardwareAddress()); mNetworkInfo.setIsAvailable(true); mNetworkInfo.setExtraInfo(mHwAddr); } else { @@ -195,7 +193,7 @@ class EthernetNetworkFactory { 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) || !mIface.isEmpty()) + if (!iface.matches(mIfaceMatch) || isTrackingInterface()) return false; Log.d(TAG, "Started tracking interface " + iface); @@ -211,8 +209,7 @@ class EthernetNetworkFactory { // TODO: Unify this codepath with stop(). synchronized (this) { NetworkUtils.stopDhcp(mIface); - mIface = ""; - mHwAddr = null; + setInterfaceInfoLocked("", null); mNetworkInfo.setExtraInfo(null); mLinkUp = false; mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); @@ -413,8 +410,7 @@ class EthernetNetworkFactory { updateAgent(); mLinkProperties = new LinkProperties(); mNetworkAgent = null; - mIface = ""; - mHwAddr = null; + setInterfaceInfoLocked("", null); mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); mFactory.unregister(); } @@ -429,8 +425,35 @@ class EthernetNetworkFactory { mNetworkCapabilities.setLinkDownstreamBandwidthKbps(100 * 1000); } + public synchronized boolean isTrackingInterface() { + return !TextUtils.isEmpty(mIface); + } + + /** + * Set interface information and notify listeners if availability is changed. + * This should be called with the lock held. + */ + private void setInterfaceInfoLocked(String iface, String hwAddr) { + boolean oldAvailable = isTrackingInterface(); + mIface = iface; + mHwAddr = hwAddr; + boolean available = isTrackingInterface(); + + 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(); + } + } + synchronized void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) { - if (!TextUtils.isEmpty(mIface)) { + if (isTrackingInterface()) { pw.println("Tracking interface: " + mIface); pw.increaseIndent(); pw.println("MAC address: " + mHwAddr); diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 42d98f65c8..bb1cc514e4 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -18,37 +18,25 @@ package com.android.server.ethernet; import android.content.Context; import android.content.pm.PackageManager; -import com.android.internal.util.IndentingPrintWriter; -import android.net.ConnectivityManager; import android.net.IEthernetManager; +import android.net.IEthernetServiceListener; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; -import android.net.LinkAddress; -import android.net.NetworkAgent; -import android.net.NetworkInfo; -import android.net.NetworkRequest; -import android.net.RouteInfo; -import android.net.StaticIpConfiguration; import android.os.Binder; -import android.os.IBinder; import android.os.Handler; import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.os.Messenger; -import android.os.INetworkManagementService; +import android.os.RemoteCallbackList; import android.os.RemoteException; -import android.os.ServiceManager; -import android.text.TextUtils; import android.util.Log; import android.util.PrintWriterPrinter; +import com.android.internal.util.IndentingPrintWriter; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.concurrent.atomic.AtomicBoolean; - /** * EthernetServiceImpl handles remote Ethernet operation requests by implementing * the IEthernetManager interface. @@ -60,14 +48,13 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { private final Context mContext; private final EthernetConfigStore mEthernetConfigStore; - private final INetworkManagementService mNMService; private final AtomicBoolean mStarted = new AtomicBoolean(false); private IpConfiguration mIpConfiguration; - private ConnectivityManager mCM; private Handler mHandler; - private NetworkInfo mNetworkInfo; private final EthernetNetworkFactory mTracker; + private final RemoteCallbackList mListeners = + new RemoteCallbackList(); public EthernetServiceImpl(Context context) { mContext = context; @@ -77,10 +64,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { Log.i(TAG, "Read stored IP configuration: " + mIpConfiguration); - IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); - mNMService = INetworkManagementService.Stub.asInterface(b); - - mTracker = new EthernetNetworkFactory(); + mTracker = new EthernetNetworkFactory(mListeners); } private void enforceAccessPermission() { @@ -103,7 +87,6 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { public void start() { Log.i(TAG, "Starting Ethernet service"); - mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); HandlerThread handlerThread = new HandlerThread("EthernetServiceThread"); handlerThread.start(); @@ -118,6 +101,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { * Get Ethernet configuration * @return the Ethernet Configuration, contained in {@link IpConfiguration}. */ + @Override public IpConfiguration getConfiguration() { enforceAccessPermission(); @@ -129,6 +113,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { /** * Set Ethernet configuration */ + @Override public void setConfiguration(IpConfiguration config) { if (!mStarted.get()) { Log.w(TAG, "System isn't ready enough to change ethernet configuration"); @@ -150,6 +135,40 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { } } + /** + * Indicates whether the system currently has one or more + * Ethernet interfaces. + */ + @Override + public boolean isAvailable() { + enforceAccessPermission(); + return mTracker.isTrackingInterface(); + } + + /** + * Addes a listener. + * @param listener A {@link IEthernetServiceListener} to add. + */ + public void addListener(IEthernetServiceListener listener) { + if (listener == null) { + throw new IllegalArgumentException("listener must not be null"); + } + enforceAccessPermission(); + mListeners.register(listener); + } + + /** + * 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"); + } + enforceAccessPermission(); + mListeners.unregister(listener); + } + @Override protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); From 566e12ad11445a4b90d615fd823b53a2c1eba9be Mon Sep 17 00:00:00 2001 From: Pierre Couillaud Date: Wed, 11 Feb 2015 08:55:29 -0800 Subject: [PATCH 018/152] eth: make sure dhcp is stopped before bringing up interface. Signed-off-by: Pierre Couillaud Signed-off-by: Blair Prescott --- .../src/com/android/server/ethernet/EthernetNetworkFactory.java | 1 + 1 file changed, 1 insertion(+) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 2d0a95728b..2de3cea1bf 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -167,6 +167,7 @@ class EthernetNetworkFactory { private void setInterfaceUp(String iface) { // Bring up the interface so we get link status indications. try { + NetworkUtils.stopDhcp(iface); mNMService.setInterfaceUp(iface); String hwAddr = null; InterfaceConfiguration config = mNMService.getInterfaceConfig(iface); From 9830ae6d92213ee4fd1e0602cce071e350def45b Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 4 Aug 2015 13:27:28 +0900 Subject: [PATCH 019/152] Stop DHCP if it times out. This was not necessary in L, but it is necessary after https://partner-android-review.googlesource.com/#/c/205415/ . Bug: 22936203 Change-Id: I24a96c33e5bb375f36217a1c2cec2076eb5ac8b4 --- .../com/android/server/ethernet/EthernetNetworkFactory.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 0c4f57d6aa..4503197fc6 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -262,7 +262,7 @@ class EthernetNetworkFactory { // TODO: Handle DHCP renew. Thread dhcpThread = new Thread(new Runnable() { public void run() { - if (DBG) Log.i(TAG, "dhcpThread(+" + mIface + "): mNetworkInfo=" + mNetworkInfo); + if (DBG) Log.i(TAG, "dhcpThread(" + mIface + "): mNetworkInfo=" + mNetworkInfo); LinkProperties linkProperties; IpConfiguration config = mEthernetManager.getConfiguration(); @@ -287,6 +287,9 @@ class EthernetNetworkFactory { // set our score lower than any network could go // so we get dropped. mFactory.setScoreFilter(-1); + // If DHCP timed out (as opposed to failing), the DHCP client will still be + // running, because in M we changed its timeout to infinite. Stop it now. + NetworkUtils.stopDhcp(mIface); return; } linkProperties = dhcpResults.toLinkProperties(mIface); From 824a0a5050c589cc00be53fb574b060917345766 Mon Sep 17 00:00:00 2001 From: Billy Lau Date: Sat, 1 Aug 2015 18:20:04 +0100 Subject: [PATCH 020/152] Bug: 21588539 Move CHANGE_NETWORK_STATE to be in SYSTEM_SETTINGS Replaced the method where we used to enforce static permission CHANGE_NETWORK_STATE to method calls that also check for WRITE_SETTINGS. This is due to the merging of CHANGE_NETWORK_STATE permission with WRITE_SETTINGS in M. Change-Id: I104ac41733663b4f6b5cd30e7314574ec4acdc07 --- .../com/android/server/ethernet/EthernetServiceImpl.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index bb1cc514e4..0c84befbcd 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -28,6 +28,7 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.RemoteCallbackList; import android.os.RemoteException; +import android.provider.Settings; import android.util.Log; import android.util.PrintWriterPrinter; @@ -74,9 +75,9 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { } private void enforceChangePermission() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.CHANGE_NETWORK_STATE, - "EthernetService"); + int uid = Binder.getCallingUid(); + Settings.checkAndNoteChangeNetworkStateOperation(mContext, uid, Settings + .getPackageNameForUid(mContext, uid), true); } private void enforceConnectivityInternalPermission() { From baabe4134845b19bebb1e21a2b3ee34a304d9c37 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 8 Sep 2015 16:21:52 +0900 Subject: [PATCH 021/152] Don't crash on startup if we can't fetch the interface list. The intent of the code was to catch exceptions, but it wasn't actually doing that because when a netd command fails we get an IllegalStateException, not a RemoteException. Bug: 23581852 Change-Id: I66c7c33bdc7b0d0de4fa5cd92dff054797cf860f --- .../src/com/android/server/ethernet/EthernetNetworkFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 4503197fc6..6074dda6e0 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -396,7 +396,7 @@ class EthernetNetworkFactory { } } } - } catch (RemoteException e) { + } catch (RemoteException|IllegalStateException e) { Log.e(TAG, "Could not get list of interfaces " + e); } } From 189063ffb07649413d850055fe25da6b3aee3170 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 15 Oct 2015 16:59:07 +0900 Subject: [PATCH 022/152] Stop requiring CHANGE_NETWORK_STATE to change Ethernet config. Requiring CHANGE_NETWORK_STATE is pointless, since immediately after doing that we require CONNECTIVITY_INTERNAL, which is a system-only permission. Bug: 23597341 Change-Id: If4c8ecbb319e547c2c81d2dcc3c7bbb63e0bc2af --- .../com/android/server/ethernet/EthernetServiceImpl.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 0c84befbcd..42996d6826 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -74,12 +74,6 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { "EthernetService"); } - private void enforceChangePermission() { - int uid = Binder.getCallingUid(); - Settings.checkAndNoteChangeNetworkStateOperation(mContext, uid, Settings - .getPackageNameForUid(mContext, uid), true); - } - private void enforceConnectivityInternalPermission() { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CONNECTIVITY_INTERNAL, @@ -120,7 +114,6 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { Log.w(TAG, "System isn't ready enough to change ethernet configuration"); } - enforceChangePermission(); enforceConnectivityInternalPermission(); synchronized (mIpConfiguration) { From 1cb0138ad39d5fa51c8f5a3ef53e30867d18c16a Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Thu, 11 Feb 2016 22:06:48 +0900 Subject: [PATCH 023/152] Use IpManager on Ethernet Bug: 17733693 Bug: 26991160 Change-Id: Idaee8c64bf452e58b93031d8d7ad666edb0c82ae --- .../ethernet/EthernetNetworkFactory.java | 118 ++++++++++++++---- 1 file changed, 95 insertions(+), 23 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 6074dda6e0..3c230fb38a 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -31,8 +31,8 @@ import android.net.NetworkCapabilities; import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; -import android.net.NetworkUtils; import android.net.StaticIpConfiguration; +import android.net.ip.IpManager; import android.os.Handler; import android.os.IBinder; import android.os.INetworkManagementService; @@ -100,6 +100,8 @@ class EthernetNetworkFactory { private static boolean mLinkUp; private NetworkInfo mNetworkInfo; private LinkProperties mLinkProperties; + private IpManager mIpManager; + private Thread mIpProvisioningThread; EthernetNetworkFactory(RemoteCallbackList listeners) { mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); @@ -120,6 +122,21 @@ class EthernetNetworkFactory { } } + private void stopIpManagerLocked() { + if (mIpManager != null) { + mIpManager.shutdown(); + mIpManager = null; + } + } + + private void stopIpProvisioningThreadLocked() { + stopIpManagerLocked(); + + if (mIpProvisioningThread != null) { + mIpProvisioningThread.interrupt(); + mIpProvisioningThread = null; + } + } /** * Updates interface state variables. @@ -137,6 +154,7 @@ class EthernetNetworkFactory { if (!up) { // Tell the agent we're disconnected. It will call disconnect(). mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); + stopIpProvisioningThreadLocked(); } updateAgent(); // set our score lower than any network could go @@ -166,7 +184,6 @@ class EthernetNetworkFactory { private void setInterfaceUp(String iface) { // Bring up the interface so we get link status indications. try { - NetworkUtils.stopDhcp(iface); mNMService.setInterfaceUp(iface); String hwAddr = null; InterfaceConfiguration config = mNMService.getInterfaceConfig(iface); @@ -209,7 +226,7 @@ class EthernetNetworkFactory { Log.d(TAG, "Stopped tracking interface " + iface); // TODO: Unify this codepath with stop(). synchronized (this) { - NetworkUtils.stopDhcp(mIface); + stopIpProvisioningThreadLocked(); setInterfaceInfoLocked("", null); mNetworkInfo.setExtraInfo(null); mLinkUp = false; @@ -257,12 +274,52 @@ class EthernetNetworkFactory { } } + private class IpManagerCallback extends IpManager.Callback { + private LinkProperties mCallbackLinkProperties; + + public LinkProperties waitForProvisioning() { + synchronized (this) { + try { + wait(); + } catch (InterruptedException e) {} + return mCallbackLinkProperties; + } + } + + @Override + public void onProvisioningSuccess(LinkProperties newLp) { + synchronized (this) { + mCallbackLinkProperties = newLp; + notify(); + } + } + + @Override + public void onProvisioningFailure(LinkProperties newLp) { + synchronized (this) { + mCallbackLinkProperties = null; + notify(); + } + } + } + + /* Called by the NetworkFactory on the handler thread. */ public void onRequestNetwork() { + synchronized(EthernetNetworkFactory.this) { + if (mIpProvisioningThread != null) { + return; + } + } + // TODO: Handle DHCP renew. - Thread dhcpThread = new Thread(new Runnable() { + final Thread ipProvisioningThread = new Thread(new Runnable() { public void run() { - if (DBG) Log.i(TAG, "dhcpThread(" + mIface + "): mNetworkInfo=" + mNetworkInfo); + if (DBG) { + Log.d(TAG, String.format("starting ipProvisioningThread(%s): mNetworkInfo=%s", + mIface, mNetworkInfo)); + } + LinkProperties linkProperties; IpConfiguration config = mEthernetManager.getConfiguration(); @@ -275,39 +332,41 @@ class EthernetNetworkFactory { linkProperties = config.getStaticIpConfiguration().toLinkProperties(mIface); } else { mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); - - DhcpResults dhcpResults = new DhcpResults(); - // TODO: Handle DHCP renewals better. - // In general runDhcp handles DHCP renewals for us, because - // the dhcp client stays running, but if the renewal fails, - // we will lose our IP address and connectivity without - // noticing. - if (!NetworkUtils.runDhcp(mIface, dhcpResults)) { - Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError()); + IpManagerCallback blockingCallback = new IpManagerCallback(); + synchronized(EthernetNetworkFactory.this) { + stopIpManagerLocked(); + mIpManager = new IpManager(mContext, mIface, blockingCallback); + mIpManager.startProvisioning(); + } + linkProperties = blockingCallback.waitForProvisioning(); + if (linkProperties == null) { + Log.e(TAG, "IP provisioning error"); // set our score lower than any network could go // so we get dropped. mFactory.setScoreFilter(-1); - // If DHCP timed out (as opposed to failing), the DHCP client will still be - // running, because in M we changed its timeout to infinite. Stop it now. - NetworkUtils.stopDhcp(mIface); + synchronized(EthernetNetworkFactory.this) { + stopIpManagerLocked(); + } return; } - linkProperties = dhcpResults.toLinkProperties(mIface); } + if (config.getProxySettings() == ProxySettings.STATIC || config.getProxySettings() == ProxySettings.PAC) { linkProperties.setHttpProxy(config.getHttpProxy()); } - String tcpBufferSizes = mContext.getResources().getString( + final String tcpBufferSizes = mContext.getResources().getString( com.android.internal.R.string.config_ethernet_tcp_buffers); - if (TextUtils.isEmpty(tcpBufferSizes) == false) { + if (!TextUtils.isEmpty(tcpBufferSizes)) { linkProperties.setTcpBufferSizes(tcpBufferSizes); } synchronized(EthernetNetworkFactory.this) { if (mNetworkAgent != null) { Log.e(TAG, "Already have a NetworkAgent - aborting new request"); + stopIpManagerLocked(); + mIpProvisioningThread = null; return; } mLinkProperties = linkProperties; @@ -321,7 +380,7 @@ class EthernetNetworkFactory { public void unwanted() { synchronized(EthernetNetworkFactory.this) { if (this == mNetworkAgent) { - NetworkUtils.stopDhcp(mIface); + stopIpManagerLocked(); mLinkProperties.clear(); mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, @@ -340,10 +399,23 @@ class EthernetNetworkFactory { } }; }; + + mIpProvisioningThread = null; + } + + if (DBG) { + Log.d(TAG, String.format("exiting ipProvisioningThread(%s): mNetworkInfo=%s", + mIface, mNetworkInfo)); } } }); - dhcpThread.start(); + + synchronized(EthernetNetworkFactory.this) { + if (mIpProvisioningThread == null) { + mIpProvisioningThread = ipProvisioningThread; + mIpProvisioningThread.start(); + } + } } /** @@ -402,7 +474,7 @@ class EthernetNetworkFactory { } public synchronized void stop() { - NetworkUtils.stopDhcp(mIface); + stopIpProvisioningThreadLocked(); // 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. From 5774ef5328b4db040a582af6533eebc420b33df5 Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Mon, 22 Feb 2016 11:11:38 +0900 Subject: [PATCH 024/152] Use more IpManager features - WaitForProvisioningCallback - setHttpProxy - setTcpBufferSizes Bug: 26991160 Change-Id: I5e02039a35006f0466fb40c43805f0443cd758c2 --- .../ethernet/EthernetNetworkFactory.java | 71 +++++++------------ 1 file changed, 27 insertions(+), 44 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 3c230fb38a..718686344d 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -33,6 +33,7 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.StaticIpConfiguration; import android.net.ip.IpManager; +import android.net.ip.IpManager.WaitForProvisioningCallback; import android.os.Handler; import android.os.IBinder; import android.os.INetworkManagementService; @@ -274,36 +275,6 @@ class EthernetNetworkFactory { } } - private class IpManagerCallback extends IpManager.Callback { - private LinkProperties mCallbackLinkProperties; - - public LinkProperties waitForProvisioning() { - synchronized (this) { - try { - wait(); - } catch (InterruptedException e) {} - return mCallbackLinkProperties; - } - } - - @Override - public void onProvisioningSuccess(LinkProperties newLp) { - synchronized (this) { - mCallbackLinkProperties = newLp; - notify(); - } - } - - @Override - public void onProvisioningFailure(LinkProperties newLp) { - synchronized (this) { - mCallbackLinkProperties = null; - notify(); - } - } - } - - /* Called by the NetworkFactory on the handler thread. */ public void onRequestNetwork() { synchronized(EthernetNetworkFactory.this) { @@ -332,13 +303,36 @@ class EthernetNetworkFactory { linkProperties = config.getStaticIpConfiguration().toLinkProperties(mIface); } else { mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); - IpManagerCallback blockingCallback = new IpManagerCallback(); + WaitForProvisioningCallback ipmCallback = new WaitForProvisioningCallback() { + @Override + public void onLinkPropertiesChange(LinkProperties newLp) { + synchronized(EthernetNetworkFactory.this) { + if (mNetworkAgent != null && mNetworkInfo.isConnected()) { + mNetworkAgent.sendLinkProperties(newLp); + } + } + } + }; + synchronized(EthernetNetworkFactory.this) { stopIpManagerLocked(); - mIpManager = new IpManager(mContext, mIface, blockingCallback); + mIpManager = new IpManager(mContext, mIface, ipmCallback); + + if (config.getProxySettings() == ProxySettings.STATIC || + config.getProxySettings() == ProxySettings.PAC) { + mIpManager.setHttpProxy(config.getHttpProxy()); + } + + final String tcpBufferSizes = mContext.getResources().getString( + com.android.internal.R.string.config_ethernet_tcp_buffers); + if (!TextUtils.isEmpty(tcpBufferSizes)) { + mIpManager.setTcpBufferSizes(tcpBufferSizes); + } + mIpManager.startProvisioning(); } - linkProperties = blockingCallback.waitForProvisioning(); + + linkProperties = ipmCallback.waitForProvisioning(); if (linkProperties == null) { Log.e(TAG, "IP provisioning error"); // set our score lower than any network could go @@ -351,17 +345,6 @@ class EthernetNetworkFactory { } } - if (config.getProxySettings() == ProxySettings.STATIC || - config.getProxySettings() == ProxySettings.PAC) { - linkProperties.setHttpProxy(config.getHttpProxy()); - } - - final String tcpBufferSizes = mContext.getResources().getString( - com.android.internal.R.string.config_ethernet_tcp_buffers); - if (!TextUtils.isEmpty(tcpBufferSizes)) { - linkProperties.setTcpBufferSizes(tcpBufferSizes); - } - synchronized(EthernetNetworkFactory.this) { if (mNetworkAgent != null) { Log.e(TAG, "Already have a NetworkAgent - aborting new request"); From 0587321554850c1e9d0aab66116ec8a41b367647 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 28 Apr 2016 01:24:21 +0900 Subject: [PATCH 025/152] Disable the IpManager timeout on Ethernet. This fixes a longstanding bug where after a DHCP timeout, we would never restart the DHCP client and get an IP address until the link bounced. Also, two minor improvements: 1. Dump IpManager info when dump() is called. 2. When onLinkPropertiesChange is called, also update mLinkProperties. We were already sending the updated LinkProperties to the NetworkAgent, so this is really only useful for dump(), but it's just one line and safe because onLinkPropertiesChange already grabs the lock. Bug: 17733693 Change-Id: I42c3319cb4bc151c547ed721baf5e83f97e23862 --- .../server/ethernet/EthernetNetworkFactory.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 718686344d..0b091f26b1 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -33,6 +33,7 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.StaticIpConfiguration; import android.net.ip.IpManager; +import android.net.ip.IpManager.ProvisioningConfiguration; import android.net.ip.IpManager.WaitForProvisioningCallback; import android.os.Handler; import android.os.IBinder; @@ -283,7 +284,6 @@ class EthernetNetworkFactory { } } - // TODO: Handle DHCP renew. final Thread ipProvisioningThread = new Thread(new Runnable() { public void run() { if (DBG) { @@ -308,6 +308,7 @@ class EthernetNetworkFactory { public void onLinkPropertiesChange(LinkProperties newLp) { synchronized(EthernetNetworkFactory.this) { if (mNetworkAgent != null && mNetworkInfo.isConnected()) { + mLinkProperties = newLp; mNetworkAgent.sendLinkProperties(newLp); } } @@ -329,7 +330,11 @@ class EthernetNetworkFactory { mIpManager.setTcpBufferSizes(tcpBufferSizes); } - mIpManager.startProvisioning(); + final ProvisioningConfiguration provisioningConfiguration = + mIpManager.buildProvisioningConfiguration() + .withProvisioningTimeoutMs(0) + .build(); + mIpManager.startProvisioning(provisioningConfiguration); } linkProperties = ipmCallback.waitForProvisioning(); @@ -526,5 +531,11 @@ class EthernetNetworkFactory { pw.println("NetworkInfo: " + mNetworkInfo); pw.println("LinkProperties: " + mLinkProperties); pw.println("NetworkAgent: " + mNetworkAgent); + if (mIpManager != null) { + pw.println("IpManager:"); + pw.increaseIndent(); + mIpManager.dump(fd, pw, args); + pw.decreaseIndent(); + } } } From 9effed6f9ef2609a94c34699b7e2000fc1811993 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 6 Jun 2017 19:16:28 +0900 Subject: [PATCH 026/152] Make Ethernet more robust. 1. Remove the IP provisioning thread and just attempt provisioning indefinitely whenever we have an interface. 2. Make all methods run on the passed-in handler thread. This makes it easier to verify correctness by code inspection. 3. Remove the code that changes the factory score depending on whether we're tracking an interface and have link. This is unnecessary complexity, as there is no penalty to accepting a request even if we don't have an interface. 4. Remove code duplication and only have one codepath for stopping layer 3. Tested the following are tested with this CL: - Booting with an interface connected. - Disconnecting/reconnecting the Ethernet cable repeatedly, particularly at inconvenient times (e.g., during provisioning). - Similarly, disconnecting/reconnecting USB Ethernet interfaces. - Falling back to another Ethernet interface if the currently tracked Ethernet interface is unplugged. - Disconnecting and restarting provisioning when provisioning is lost (e.g., if the default route is deleted). - Crashing the system server causes Ethernet to reconnect on restart. - The above while running watch -n 0.1 adb shell dumpsys ethernet Bug: 62308954 Test: tested on marlin with USB ethernet adapters, as described Change-Id: Iad12a52a903bfaccf7e245dfe499652c752c31e9 --- .../ethernet/EthernetNetworkFactory.java | 468 +++++++++--------- 1 file changed, 227 insertions(+), 241 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 0b091f26b1..7ff3f6c310 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -34,7 +34,6 @@ import android.net.NetworkInfo.DetailedState; import android.net.StaticIpConfiguration; import android.net.ip.IpManager; import android.net.ip.IpManager.ProvisioningConfiguration; -import android.net.ip.IpManager.WaitForProvisioningCallback; import android.os.Handler; import android.os.IBinder; import android.os.INetworkManagementService; @@ -50,6 +49,8 @@ import com.android.server.net.BaseNetworkObserver; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.Arrays; +import java.util.concurrent.CountDownLatch; /** @@ -84,6 +85,9 @@ class EthernetNetworkFactory { /** To set link state and configure IP addresses. */ private INetworkManagementService mNMService; + /** All code runs here, including start(). */ + private Handler mHandler; + /* To communicate with ConnectivityManager */ private NetworkCapabilities mNetworkCapabilities; private NetworkAgent mNetworkAgent; @@ -96,19 +100,18 @@ class EthernetNetworkFactory { /** To notify Ethernet status. */ private final RemoteCallbackList mListeners; - /** Data members. All accesses to these must be synchronized(this). */ - private static String mIface = ""; + /** Data members. All accesses to these must be on the handler thread. */ + private String mIface = ""; private String mHwAddr; - private static boolean mLinkUp; + private boolean mLinkUp; private NetworkInfo mNetworkInfo; private LinkProperties mLinkProperties; private IpManager mIpManager; - private Thread mIpProvisioningThread; + private boolean mNetworkRequested = false; EthernetNetworkFactory(RemoteCallbackList listeners) { - mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); - mLinkProperties = new LinkProperties(); initNetworkCapabilities(); + clearInfo(); mListeners = listeners; } @@ -118,26 +121,40 @@ class EthernetNetworkFactory { } protected void startNetwork() { - onRequestNetwork(); + if (!mNetworkRequested) { + mNetworkRequested = true; + maybeStartIpManager(); + } } + protected void stopNetwork() { + mNetworkRequested = false; + stopIpManager(); } } - private void stopIpManagerLocked() { + private void clearInfo() { + mLinkProperties = new LinkProperties(); + mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); + mNetworkInfo.setExtraInfo(mHwAddr); + mNetworkInfo.setIsAvailable(isTrackingInterface()); + } + + private void stopIpManager() { if (mIpManager != null) { mIpManager.shutdown(); mIpManager = null; } - } - - private void stopIpProvisioningThreadLocked() { - stopIpManagerLocked(); - - if (mIpProvisioningThread != null) { - mIpProvisioningThread.interrupt(); - mIpProvisioningThread = 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(); } /** @@ -150,36 +167,36 @@ class EthernetNetworkFactory { } Log.d(TAG, "updateInterface: " + iface + " link " + (up ? "up" : "down")); - synchronized(this) { - mLinkUp = up; - mNetworkInfo.setIsAvailable(up); - if (!up) { - // Tell the agent we're disconnected. It will call disconnect(). - mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); - stopIpProvisioningThreadLocked(); - } - updateAgent(); - // set our score lower than any network could go - // so we get dropped. TODO - just unregister the factory - // when link goes down. - mFactory.setScoreFilter(up ? NETWORK_SCORE : -1); + mLinkUp = up; + if (up) { + maybeStartIpManager(); + } else { + stopIpManager(); } } private class InterfaceObserver extends BaseNetworkObserver { @Override public void interfaceLinkStateChanged(String iface, boolean up) { - updateInterfaceState(iface, up); + mHandler.post(() -> { + updateInterfaceState(iface, up); + }); } @Override public void interfaceAdded(String iface) { - maybeTrackInterface(iface); + mHandler.post(() -> { + maybeTrackInterface(iface); + }); } @Override public void interfaceRemoved(String iface) { - stopTrackingInterface(iface); + mHandler.post(() -> { + if (stopTrackingInterface(iface)) { + trackFirstAvailableInterface(); + } + }); } } @@ -195,15 +212,13 @@ class EthernetNetworkFactory { return; } - synchronized (this) { - if (!isTrackingInterface()) { - setInterfaceInfoLocked(iface, config.getHardwareAddress()); - mNetworkInfo.setIsAvailable(true); - mNetworkInfo.setExtraInfo(mHwAddr); - } else { - Log.e(TAG, "Interface unexpectedly changed from " + iface + " to " + mIface); - mNMService.setInterfaceDown(iface); - } + 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 e) { Log.e(TAG, "Error upping interface " + mIface + ": " + e); @@ -221,23 +236,14 @@ class EthernetNetworkFactory { return true; } - private void stopTrackingInterface(String iface) { + private boolean stopTrackingInterface(String iface) { if (!iface.equals(mIface)) - return; + return false; Log.d(TAG, "Stopped tracking interface " + iface); - // TODO: Unify this codepath with stop(). - synchronized (this) { - stopIpProvisioningThreadLocked(); - setInterfaceInfoLocked("", null); - mNetworkInfo.setExtraInfo(null); - mLinkUp = false; - mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); - updateAgent(); - mNetworkAgent = null; - mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); - mLinkProperties = new LinkProperties(); - } + setInterfaceInfo("", null); + stopIpManager(); + return true; } private boolean setStaticIpAddress(StaticIpConfiguration staticConfig) { @@ -260,156 +266,127 @@ class EthernetNetworkFactory { } public void updateAgent() { - synchronized (EthernetNetworkFactory.this) { - if (mNetworkAgent == null) return; - if (DBG) { - Log.i(TAG, "Updating mNetworkAgent with: " + - mNetworkCapabilities + ", " + - mNetworkInfo + ", " + - mLinkProperties); + if (mNetworkAgent == null) return; + if (DBG) { + Log.i(TAG, "Updating mNetworkAgent with: " + + 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) { + if (mNetworkAgent != null) { + Log.e(TAG, "Already have a NetworkAgent - aborting new request"); + stopIpManager(); + return; + } + mLinkProperties = linkProperties; + mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr); + + // Create our NetworkAgent. + mNetworkAgent = new NetworkAgent(mHandler.getLooper(), mContext, + NETWORK_TYPE, mNetworkInfo, mNetworkCapabilities, mLinkProperties, + NETWORK_SCORE) { + public void unwanted() { + if (this == mNetworkAgent) { + stopIpManager(); + } else if (mNetworkAgent != null) { + Log.d(TAG, "Ignoring unwanted as we have a more modern " + + "instance"); + } // Otherwise, we've already called stopIpManager. } - mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); - mNetworkAgent.sendNetworkInfo(mNetworkInfo); - mNetworkAgent.sendLinkProperties(mLinkProperties); - // never set the network score below 0. - mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0); + }; + } + + 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. + stopIpManager(); + maybeStartIpManager(); + } + + void updateLinkProperties(LinkProperties linkProperties) { + mLinkProperties = linkProperties; + if (mNetworkAgent != null) { + mNetworkAgent.sendLinkProperties(linkProperties); } } - /* Called by the NetworkFactory on the handler thread. */ - public void onRequestNetwork() { - synchronized(EthernetNetworkFactory.this) { - if (mIpProvisioningThread != null) { - return; - } + public void maybeStartIpManager() { + if (mNetworkRequested && mIpManager == null && isTrackingInterface()) { + startIpManager(); + } + } + + public void startIpManager() { + if (DBG) { + Log.d(TAG, String.format("starting IpManager(%s): mNetworkInfo=%s", mIface, + mNetworkInfo)); } - final Thread ipProvisioningThread = new Thread(new Runnable() { - public void run() { - if (DBG) { - Log.d(TAG, String.format("starting ipProvisioningThread(%s): mNetworkInfo=%s", - mIface, mNetworkInfo)); - } + LinkProperties linkProperties; - LinkProperties linkProperties; + IpConfiguration config = mEthernetManager.getConfiguration(); - IpConfiguration config = mEthernetManager.getConfiguration(); - - if (config.getIpAssignment() == IpAssignment.STATIC) { - if (!setStaticIpAddress(config.getStaticIpConfiguration())) { - // We've already logged an error. - return; - } - linkProperties = config.getStaticIpConfiguration().toLinkProperties(mIface); - } else { - mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); - WaitForProvisioningCallback ipmCallback = new WaitForProvisioningCallback() { - @Override - public void onLinkPropertiesChange(LinkProperties newLp) { - synchronized(EthernetNetworkFactory.this) { - if (mNetworkAgent != null && mNetworkInfo.isConnected()) { - mLinkProperties = newLp; - mNetworkAgent.sendLinkProperties(newLp); - } - } - } - }; - - synchronized(EthernetNetworkFactory.this) { - stopIpManagerLocked(); - mIpManager = new IpManager(mContext, mIface, ipmCallback); - - if (config.getProxySettings() == ProxySettings.STATIC || - config.getProxySettings() == ProxySettings.PAC) { - mIpManager.setHttpProxy(config.getHttpProxy()); - } - - final String tcpBufferSizes = mContext.getResources().getString( - com.android.internal.R.string.config_ethernet_tcp_buffers); - if (!TextUtils.isEmpty(tcpBufferSizes)) { - mIpManager.setTcpBufferSizes(tcpBufferSizes); - } - - final ProvisioningConfiguration provisioningConfiguration = - mIpManager.buildProvisioningConfiguration() - .withProvisioningTimeoutMs(0) - .build(); - mIpManager.startProvisioning(provisioningConfiguration); - } - - linkProperties = ipmCallback.waitForProvisioning(); - if (linkProperties == null) { - Log.e(TAG, "IP provisioning error"); - // set our score lower than any network could go - // so we get dropped. - mFactory.setScoreFilter(-1); - synchronized(EthernetNetworkFactory.this) { - stopIpManagerLocked(); - } - return; - } - } - - synchronized(EthernetNetworkFactory.this) { - if (mNetworkAgent != null) { - Log.e(TAG, "Already have a NetworkAgent - aborting new request"); - stopIpManagerLocked(); - mIpProvisioningThread = null; - return; - } - mLinkProperties = linkProperties; - mNetworkInfo.setIsAvailable(true); - mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr); - - // Create our NetworkAgent. - mNetworkAgent = new NetworkAgent(mFactory.getLooper(), mContext, - NETWORK_TYPE, mNetworkInfo, mNetworkCapabilities, mLinkProperties, - NETWORK_SCORE) { - public void unwanted() { - synchronized(EthernetNetworkFactory.this) { - if (this == mNetworkAgent) { - stopIpManagerLocked(); - - mLinkProperties.clear(); - mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, - mHwAddr); - updateAgent(); - mNetworkAgent = null; - try { - mNMService.clearInterfaceAddresses(mIface); - } catch (Exception e) { - Log.e(TAG, "Failed to clear addresses or disable ipv6" + e); - } - } else { - Log.d(TAG, "Ignoring unwanted as we have a more modern " + - "instance"); - } - } - }; - }; - - mIpProvisioningThread = null; - } - - if (DBG) { - Log.d(TAG, String.format("exiting ipProvisioningThread(%s): mNetworkInfo=%s", - mIface, mNetworkInfo)); - } + if (config.getIpAssignment() == IpAssignment.STATIC) { + if (!setStaticIpAddress(config.getStaticIpConfiguration())) { + // We've already logged an error. + return; } - }); + linkProperties = config.getStaticIpConfiguration().toLinkProperties(mIface); + } else { + mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); + IpManager.Callback ipmCallback = new IpManager.Callback() { + @Override + public void onProvisioningSuccess(LinkProperties newLp) { + mHandler.post(() -> onIpLayerStarted(newLp)); + } - synchronized(EthernetNetworkFactory.this) { - if (mIpProvisioningThread == null) { - mIpProvisioningThread = ipProvisioningThread; - mIpProvisioningThread.start(); + @Override + public void onProvisioningFailure(LinkProperties newLp) { + mHandler.post(() -> onIpLayerStopped(newLp)); + } + + @Override + public void onLinkPropertiesChange(LinkProperties newLp) { + mHandler.post(() -> updateLinkProperties(newLp)); + } + }; + + stopIpManager(); + mIpManager = new IpManager(mContext, mIface, ipmCallback); + + if (config.getProxySettings() == ProxySettings.STATIC || + config.getProxySettings() == ProxySettings.PAC) { + mIpManager.setHttpProxy(config.getHttpProxy()); } + + final String tcpBufferSizes = mContext.getResources().getString( + com.android.internal.R.string.config_ethernet_tcp_buffers); + if (!TextUtils.isEmpty(tcpBufferSizes)) { + mIpManager.setTcpBufferSizes(tcpBufferSizes); + } + + final ProvisioningConfiguration provisioningConfiguration = + mIpManager.buildProvisioningConfiguration() + .withProvisioningTimeoutMs(0) + .build(); + mIpManager.startProvisioning(provisioningConfiguration); } } /** * Begin monitoring connectivity */ - public synchronized void start(Context context, Handler target) { + public void start(Context context, Handler handler) { + mHandler = handler; + // The services we use. IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); mNMService = INetworkManagementService.Stub.asInterface(b); @@ -420,9 +397,9 @@ class EthernetNetworkFactory { com.android.internal.R.string.config_ethernet_iface_regex); // Create and register our NetworkFactory. - mFactory = new LocalNetworkFactory(NETWORK_TYPE, context, target.getLooper()); + mFactory = new LocalNetworkFactory(NETWORK_TYPE, context, mHandler.getLooper()); mFactory.setCapabilityFilter(mNetworkCapabilities); - mFactory.setScoreFilter(-1); // this set high when we have an iface + mFactory.setScoreFilter(NETWORK_SCORE); mFactory.register(); mContext = context; @@ -437,23 +414,22 @@ class EthernetNetworkFactory { // 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) { - synchronized(this) { - 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. Since we're already holding the lock, - // any real link up/down notification will only arrive - // after we've done this. - if (mNMService.getInterfaceConfig(iface).hasFlag("running")) { - updateInterfaceState(iface, true); - } - break; + 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) { @@ -461,21 +437,9 @@ class EthernetNetworkFactory { } } - public synchronized void stop() { - stopIpProvisioningThreadLocked(); - // 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. - // - // TODO: stop using explicit comparisons to DISCONNECTED / SUSPENDED in ConnectivityService, - // and instead use isConnectedOrConnecting(). - mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); - mLinkUp = false; - updateAgent(); - mLinkProperties = new LinkProperties(); - mNetworkAgent = null; - setInterfaceInfoLocked("", null); - mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); + public void stop() { + stopIpManager(); + setInterfaceInfo("", null); mFactory.unregister(); } @@ -489,20 +453,22 @@ class EthernetNetworkFactory { mNetworkCapabilities.setLinkDownstreamBandwidthKbps(100 * 1000); } - public synchronized boolean isTrackingInterface() { + public boolean isTrackingInterface() { return !TextUtils.isEmpty(mIface); } /** * Set interface information and notify listeners if availability is changed. - * This should be called with the lock held. */ - private void setInterfaceInfoLocked(String iface, String hwAddr) { + private void setInterfaceInfo(String iface, String hwAddr) { boolean oldAvailable = isTrackingInterface(); 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++) { @@ -516,26 +482,46 @@ class EthernetNetworkFactory { } } - synchronized void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) { - if (isTrackingInterface()) { - pw.println("Tracking interface: " + mIface); - pw.increaseIndent(); - pw.println("MAC address: " + mHwAddr); - pw.println("Link state: " + (mLinkUp ? "up" : "down")); - pw.decreaseIndent(); - } else { - pw.println("Not tracking any interface"); - } + private void postAndWaitForRunnable(Runnable r) throws InterruptedException { + CountDownLatch latch = new CountDownLatch(1); + mHandler.post(() -> { + try { + r.run(); + } finally { + latch.countDown(); + } + }); + latch.await(); + } - pw.println(); - pw.println("NetworkInfo: " + mNetworkInfo); - pw.println("LinkProperties: " + mLinkProperties); - pw.println("NetworkAgent: " + mNetworkAgent); - if (mIpManager != null) { - pw.println("IpManager:"); - pw.increaseIndent(); - mIpManager.dump(fd, pw, args); - pw.decreaseIndent(); + + void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) { + try { + postAndWaitForRunnable(() -> { + pw.println("Network Requested: " + mNetworkRequested); + if (isTrackingInterface()) { + pw.println("Tracking interface: " + mIface); + pw.increaseIndent(); + pw.println("MAC address: " + mHwAddr); + pw.println("Link state: " + (mLinkUp ? "up" : "down")); + pw.decreaseIndent(); + } else { + pw.println("Not tracking any interface"); + } + + pw.println(); + pw.println("NetworkInfo: " + mNetworkInfo); + pw.println("LinkProperties: " + mLinkProperties); + pw.println("NetworkAgent: " + mNetworkAgent); + if (mIpManager != null) { + pw.println("IpManager:"); + pw.increaseIndent(); + mIpManager.dump(fd, pw, args); + pw.decreaseIndent(); + } + }); + } catch (InterruptedException e) { + throw new IllegalStateException("dump() interrupted"); } } } From 62d5e744c3ab298b278834b0d711702cbb0c4326 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 6 Jun 2017 19:16:28 +0900 Subject: [PATCH 027/152] Make Ethernet more robust. 1. Remove the IP provisioning thread and just attempt provisioning indefinitely whenever we have an interface. 2. Make all methods run on the passed-in handler thread. This makes it easier to verify correctness by code inspection. 3. Remove the code that changes the factory score depending on whether we're tracking an interface and have link. This is unnecessary complexity, as there is no penalty to accepting a request even if we don't have an interface. 4. Remove code duplication and only have one codepath for stopping layer 3. Tested the following are tested with this CL: - Booting with an interface connected. - Disconnecting/reconnecting the Ethernet cable repeatedly, particularly at inconvenient times (e.g., during provisioning). - Similarly, disconnecting/reconnecting USB Ethernet interfaces. - Falling back to another Ethernet interface if the currently tracked Ethernet interface is unplugged. - Disconnecting and restarting provisioning when provisioning is lost (e.g., if the default route is deleted). - Crashing the system server causes Ethernet to reconnect on restart. - The above while running watch -n 0.1 adb shell dumpsys ethernet (cherry picked from commit 9effed6f9ef2609a94c34699b7e2000fc1811993) Bug: 62308954 Test: tested on marlin with USB ethernet adapters, as described Test: smoketested on aosp_bullhead Change-Id: Ie3041f1d453d15c81eee81adfc8593269c499d79 --- .../ethernet/EthernetNetworkFactory.java | 468 +++++++++--------- 1 file changed, 227 insertions(+), 241 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 0b091f26b1..7ff3f6c310 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -34,7 +34,6 @@ import android.net.NetworkInfo.DetailedState; import android.net.StaticIpConfiguration; import android.net.ip.IpManager; import android.net.ip.IpManager.ProvisioningConfiguration; -import android.net.ip.IpManager.WaitForProvisioningCallback; import android.os.Handler; import android.os.IBinder; import android.os.INetworkManagementService; @@ -50,6 +49,8 @@ import com.android.server.net.BaseNetworkObserver; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.Arrays; +import java.util.concurrent.CountDownLatch; /** @@ -84,6 +85,9 @@ class EthernetNetworkFactory { /** To set link state and configure IP addresses. */ private INetworkManagementService mNMService; + /** All code runs here, including start(). */ + private Handler mHandler; + /* To communicate with ConnectivityManager */ private NetworkCapabilities mNetworkCapabilities; private NetworkAgent mNetworkAgent; @@ -96,19 +100,18 @@ class EthernetNetworkFactory { /** To notify Ethernet status. */ private final RemoteCallbackList mListeners; - /** Data members. All accesses to these must be synchronized(this). */ - private static String mIface = ""; + /** Data members. All accesses to these must be on the handler thread. */ + private String mIface = ""; private String mHwAddr; - private static boolean mLinkUp; + private boolean mLinkUp; private NetworkInfo mNetworkInfo; private LinkProperties mLinkProperties; private IpManager mIpManager; - private Thread mIpProvisioningThread; + private boolean mNetworkRequested = false; EthernetNetworkFactory(RemoteCallbackList listeners) { - mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); - mLinkProperties = new LinkProperties(); initNetworkCapabilities(); + clearInfo(); mListeners = listeners; } @@ -118,26 +121,40 @@ class EthernetNetworkFactory { } protected void startNetwork() { - onRequestNetwork(); + if (!mNetworkRequested) { + mNetworkRequested = true; + maybeStartIpManager(); + } } + protected void stopNetwork() { + mNetworkRequested = false; + stopIpManager(); } } - private void stopIpManagerLocked() { + private void clearInfo() { + mLinkProperties = new LinkProperties(); + mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); + mNetworkInfo.setExtraInfo(mHwAddr); + mNetworkInfo.setIsAvailable(isTrackingInterface()); + } + + private void stopIpManager() { if (mIpManager != null) { mIpManager.shutdown(); mIpManager = null; } - } - - private void stopIpProvisioningThreadLocked() { - stopIpManagerLocked(); - - if (mIpProvisioningThread != null) { - mIpProvisioningThread.interrupt(); - mIpProvisioningThread = 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(); } /** @@ -150,36 +167,36 @@ class EthernetNetworkFactory { } Log.d(TAG, "updateInterface: " + iface + " link " + (up ? "up" : "down")); - synchronized(this) { - mLinkUp = up; - mNetworkInfo.setIsAvailable(up); - if (!up) { - // Tell the agent we're disconnected. It will call disconnect(). - mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); - stopIpProvisioningThreadLocked(); - } - updateAgent(); - // set our score lower than any network could go - // so we get dropped. TODO - just unregister the factory - // when link goes down. - mFactory.setScoreFilter(up ? NETWORK_SCORE : -1); + mLinkUp = up; + if (up) { + maybeStartIpManager(); + } else { + stopIpManager(); } } private class InterfaceObserver extends BaseNetworkObserver { @Override public void interfaceLinkStateChanged(String iface, boolean up) { - updateInterfaceState(iface, up); + mHandler.post(() -> { + updateInterfaceState(iface, up); + }); } @Override public void interfaceAdded(String iface) { - maybeTrackInterface(iface); + mHandler.post(() -> { + maybeTrackInterface(iface); + }); } @Override public void interfaceRemoved(String iface) { - stopTrackingInterface(iface); + mHandler.post(() -> { + if (stopTrackingInterface(iface)) { + trackFirstAvailableInterface(); + } + }); } } @@ -195,15 +212,13 @@ class EthernetNetworkFactory { return; } - synchronized (this) { - if (!isTrackingInterface()) { - setInterfaceInfoLocked(iface, config.getHardwareAddress()); - mNetworkInfo.setIsAvailable(true); - mNetworkInfo.setExtraInfo(mHwAddr); - } else { - Log.e(TAG, "Interface unexpectedly changed from " + iface + " to " + mIface); - mNMService.setInterfaceDown(iface); - } + 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 e) { Log.e(TAG, "Error upping interface " + mIface + ": " + e); @@ -221,23 +236,14 @@ class EthernetNetworkFactory { return true; } - private void stopTrackingInterface(String iface) { + private boolean stopTrackingInterface(String iface) { if (!iface.equals(mIface)) - return; + return false; Log.d(TAG, "Stopped tracking interface " + iface); - // TODO: Unify this codepath with stop(). - synchronized (this) { - stopIpProvisioningThreadLocked(); - setInterfaceInfoLocked("", null); - mNetworkInfo.setExtraInfo(null); - mLinkUp = false; - mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); - updateAgent(); - mNetworkAgent = null; - mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); - mLinkProperties = new LinkProperties(); - } + setInterfaceInfo("", null); + stopIpManager(); + return true; } private boolean setStaticIpAddress(StaticIpConfiguration staticConfig) { @@ -260,156 +266,127 @@ class EthernetNetworkFactory { } public void updateAgent() { - synchronized (EthernetNetworkFactory.this) { - if (mNetworkAgent == null) return; - if (DBG) { - Log.i(TAG, "Updating mNetworkAgent with: " + - mNetworkCapabilities + ", " + - mNetworkInfo + ", " + - mLinkProperties); + if (mNetworkAgent == null) return; + if (DBG) { + Log.i(TAG, "Updating mNetworkAgent with: " + + 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) { + if (mNetworkAgent != null) { + Log.e(TAG, "Already have a NetworkAgent - aborting new request"); + stopIpManager(); + return; + } + mLinkProperties = linkProperties; + mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr); + + // Create our NetworkAgent. + mNetworkAgent = new NetworkAgent(mHandler.getLooper(), mContext, + NETWORK_TYPE, mNetworkInfo, mNetworkCapabilities, mLinkProperties, + NETWORK_SCORE) { + public void unwanted() { + if (this == mNetworkAgent) { + stopIpManager(); + } else if (mNetworkAgent != null) { + Log.d(TAG, "Ignoring unwanted as we have a more modern " + + "instance"); + } // Otherwise, we've already called stopIpManager. } - mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); - mNetworkAgent.sendNetworkInfo(mNetworkInfo); - mNetworkAgent.sendLinkProperties(mLinkProperties); - // never set the network score below 0. - mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0); + }; + } + + 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. + stopIpManager(); + maybeStartIpManager(); + } + + void updateLinkProperties(LinkProperties linkProperties) { + mLinkProperties = linkProperties; + if (mNetworkAgent != null) { + mNetworkAgent.sendLinkProperties(linkProperties); } } - /* Called by the NetworkFactory on the handler thread. */ - public void onRequestNetwork() { - synchronized(EthernetNetworkFactory.this) { - if (mIpProvisioningThread != null) { - return; - } + public void maybeStartIpManager() { + if (mNetworkRequested && mIpManager == null && isTrackingInterface()) { + startIpManager(); + } + } + + public void startIpManager() { + if (DBG) { + Log.d(TAG, String.format("starting IpManager(%s): mNetworkInfo=%s", mIface, + mNetworkInfo)); } - final Thread ipProvisioningThread = new Thread(new Runnable() { - public void run() { - if (DBG) { - Log.d(TAG, String.format("starting ipProvisioningThread(%s): mNetworkInfo=%s", - mIface, mNetworkInfo)); - } + LinkProperties linkProperties; - LinkProperties linkProperties; + IpConfiguration config = mEthernetManager.getConfiguration(); - IpConfiguration config = mEthernetManager.getConfiguration(); - - if (config.getIpAssignment() == IpAssignment.STATIC) { - if (!setStaticIpAddress(config.getStaticIpConfiguration())) { - // We've already logged an error. - return; - } - linkProperties = config.getStaticIpConfiguration().toLinkProperties(mIface); - } else { - mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); - WaitForProvisioningCallback ipmCallback = new WaitForProvisioningCallback() { - @Override - public void onLinkPropertiesChange(LinkProperties newLp) { - synchronized(EthernetNetworkFactory.this) { - if (mNetworkAgent != null && mNetworkInfo.isConnected()) { - mLinkProperties = newLp; - mNetworkAgent.sendLinkProperties(newLp); - } - } - } - }; - - synchronized(EthernetNetworkFactory.this) { - stopIpManagerLocked(); - mIpManager = new IpManager(mContext, mIface, ipmCallback); - - if (config.getProxySettings() == ProxySettings.STATIC || - config.getProxySettings() == ProxySettings.PAC) { - mIpManager.setHttpProxy(config.getHttpProxy()); - } - - final String tcpBufferSizes = mContext.getResources().getString( - com.android.internal.R.string.config_ethernet_tcp_buffers); - if (!TextUtils.isEmpty(tcpBufferSizes)) { - mIpManager.setTcpBufferSizes(tcpBufferSizes); - } - - final ProvisioningConfiguration provisioningConfiguration = - mIpManager.buildProvisioningConfiguration() - .withProvisioningTimeoutMs(0) - .build(); - mIpManager.startProvisioning(provisioningConfiguration); - } - - linkProperties = ipmCallback.waitForProvisioning(); - if (linkProperties == null) { - Log.e(TAG, "IP provisioning error"); - // set our score lower than any network could go - // so we get dropped. - mFactory.setScoreFilter(-1); - synchronized(EthernetNetworkFactory.this) { - stopIpManagerLocked(); - } - return; - } - } - - synchronized(EthernetNetworkFactory.this) { - if (mNetworkAgent != null) { - Log.e(TAG, "Already have a NetworkAgent - aborting new request"); - stopIpManagerLocked(); - mIpProvisioningThread = null; - return; - } - mLinkProperties = linkProperties; - mNetworkInfo.setIsAvailable(true); - mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr); - - // Create our NetworkAgent. - mNetworkAgent = new NetworkAgent(mFactory.getLooper(), mContext, - NETWORK_TYPE, mNetworkInfo, mNetworkCapabilities, mLinkProperties, - NETWORK_SCORE) { - public void unwanted() { - synchronized(EthernetNetworkFactory.this) { - if (this == mNetworkAgent) { - stopIpManagerLocked(); - - mLinkProperties.clear(); - mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, - mHwAddr); - updateAgent(); - mNetworkAgent = null; - try { - mNMService.clearInterfaceAddresses(mIface); - } catch (Exception e) { - Log.e(TAG, "Failed to clear addresses or disable ipv6" + e); - } - } else { - Log.d(TAG, "Ignoring unwanted as we have a more modern " + - "instance"); - } - } - }; - }; - - mIpProvisioningThread = null; - } - - if (DBG) { - Log.d(TAG, String.format("exiting ipProvisioningThread(%s): mNetworkInfo=%s", - mIface, mNetworkInfo)); - } + if (config.getIpAssignment() == IpAssignment.STATIC) { + if (!setStaticIpAddress(config.getStaticIpConfiguration())) { + // We've already logged an error. + return; } - }); + linkProperties = config.getStaticIpConfiguration().toLinkProperties(mIface); + } else { + mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); + IpManager.Callback ipmCallback = new IpManager.Callback() { + @Override + public void onProvisioningSuccess(LinkProperties newLp) { + mHandler.post(() -> onIpLayerStarted(newLp)); + } - synchronized(EthernetNetworkFactory.this) { - if (mIpProvisioningThread == null) { - mIpProvisioningThread = ipProvisioningThread; - mIpProvisioningThread.start(); + @Override + public void onProvisioningFailure(LinkProperties newLp) { + mHandler.post(() -> onIpLayerStopped(newLp)); + } + + @Override + public void onLinkPropertiesChange(LinkProperties newLp) { + mHandler.post(() -> updateLinkProperties(newLp)); + } + }; + + stopIpManager(); + mIpManager = new IpManager(mContext, mIface, ipmCallback); + + if (config.getProxySettings() == ProxySettings.STATIC || + config.getProxySettings() == ProxySettings.PAC) { + mIpManager.setHttpProxy(config.getHttpProxy()); } + + final String tcpBufferSizes = mContext.getResources().getString( + com.android.internal.R.string.config_ethernet_tcp_buffers); + if (!TextUtils.isEmpty(tcpBufferSizes)) { + mIpManager.setTcpBufferSizes(tcpBufferSizes); + } + + final ProvisioningConfiguration provisioningConfiguration = + mIpManager.buildProvisioningConfiguration() + .withProvisioningTimeoutMs(0) + .build(); + mIpManager.startProvisioning(provisioningConfiguration); } } /** * Begin monitoring connectivity */ - public synchronized void start(Context context, Handler target) { + public void start(Context context, Handler handler) { + mHandler = handler; + // The services we use. IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); mNMService = INetworkManagementService.Stub.asInterface(b); @@ -420,9 +397,9 @@ class EthernetNetworkFactory { com.android.internal.R.string.config_ethernet_iface_regex); // Create and register our NetworkFactory. - mFactory = new LocalNetworkFactory(NETWORK_TYPE, context, target.getLooper()); + mFactory = new LocalNetworkFactory(NETWORK_TYPE, context, mHandler.getLooper()); mFactory.setCapabilityFilter(mNetworkCapabilities); - mFactory.setScoreFilter(-1); // this set high when we have an iface + mFactory.setScoreFilter(NETWORK_SCORE); mFactory.register(); mContext = context; @@ -437,23 +414,22 @@ class EthernetNetworkFactory { // 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) { - synchronized(this) { - 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. Since we're already holding the lock, - // any real link up/down notification will only arrive - // after we've done this. - if (mNMService.getInterfaceConfig(iface).hasFlag("running")) { - updateInterfaceState(iface, true); - } - break; + 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) { @@ -461,21 +437,9 @@ class EthernetNetworkFactory { } } - public synchronized void stop() { - stopIpProvisioningThreadLocked(); - // 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. - // - // TODO: stop using explicit comparisons to DISCONNECTED / SUSPENDED in ConnectivityService, - // and instead use isConnectedOrConnecting(). - mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); - mLinkUp = false; - updateAgent(); - mLinkProperties = new LinkProperties(); - mNetworkAgent = null; - setInterfaceInfoLocked("", null); - mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); + public void stop() { + stopIpManager(); + setInterfaceInfo("", null); mFactory.unregister(); } @@ -489,20 +453,22 @@ class EthernetNetworkFactory { mNetworkCapabilities.setLinkDownstreamBandwidthKbps(100 * 1000); } - public synchronized boolean isTrackingInterface() { + public boolean isTrackingInterface() { return !TextUtils.isEmpty(mIface); } /** * Set interface information and notify listeners if availability is changed. - * This should be called with the lock held. */ - private void setInterfaceInfoLocked(String iface, String hwAddr) { + private void setInterfaceInfo(String iface, String hwAddr) { boolean oldAvailable = isTrackingInterface(); 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++) { @@ -516,26 +482,46 @@ class EthernetNetworkFactory { } } - synchronized void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) { - if (isTrackingInterface()) { - pw.println("Tracking interface: " + mIface); - pw.increaseIndent(); - pw.println("MAC address: " + mHwAddr); - pw.println("Link state: " + (mLinkUp ? "up" : "down")); - pw.decreaseIndent(); - } else { - pw.println("Not tracking any interface"); - } + private void postAndWaitForRunnable(Runnable r) throws InterruptedException { + CountDownLatch latch = new CountDownLatch(1); + mHandler.post(() -> { + try { + r.run(); + } finally { + latch.countDown(); + } + }); + latch.await(); + } - pw.println(); - pw.println("NetworkInfo: " + mNetworkInfo); - pw.println("LinkProperties: " + mLinkProperties); - pw.println("NetworkAgent: " + mNetworkAgent); - if (mIpManager != null) { - pw.println("IpManager:"); - pw.increaseIndent(); - mIpManager.dump(fd, pw, args); - pw.decreaseIndent(); + + void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) { + try { + postAndWaitForRunnable(() -> { + pw.println("Network Requested: " + mNetworkRequested); + if (isTrackingInterface()) { + pw.println("Tracking interface: " + mIface); + pw.increaseIndent(); + pw.println("MAC address: " + mHwAddr); + pw.println("Link state: " + (mLinkUp ? "up" : "down")); + pw.decreaseIndent(); + } else { + pw.println("Not tracking any interface"); + } + + pw.println(); + pw.println("NetworkInfo: " + mNetworkInfo); + pw.println("LinkProperties: " + mLinkProperties); + pw.println("NetworkAgent: " + mNetworkAgent); + if (mIpManager != null) { + pw.println("IpManager:"); + pw.increaseIndent(); + mIpManager.dump(fd, pw, args); + pw.decreaseIndent(); + } + }); + } catch (InterruptedException e) { + throw new IllegalStateException("dump() interrupted"); } } } From 17f4e4a0276a246926f5b151099dbdb92e5d80d7 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 23 Jun 2017 01:21:25 +0900 Subject: [PATCH 028/152] Don't crash if the interface disappears just after appearing. If the interface disappears between interfaceAdded() and setInterfaceUp, we'll crash with an IllegalStateException in NetworkManagementService#setInterfaceConfig. Ignore the error instead. This should be safe because we don't modify any state unless our calls succeed. Bug: 62870779 Test: builds aosp_bullhead-eng Change-Id: If8c2375f7fffe25a9fa79dc4f1981c745384a276 --- .../com/android/server/ethernet/EthernetNetworkFactory.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 7ff3f6c310..d6d0defd32 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -208,7 +208,7 @@ class EthernetNetworkFactory { InterfaceConfiguration config = mNMService.getInterfaceConfig(iface); if (config == null) { - Log.e(TAG, "Null iterface config for " + iface + ". Bailing out."); + Log.e(TAG, "Null interface config for " + iface + ". Bailing out."); return; } @@ -220,7 +220,9 @@ class EthernetNetworkFactory { Log.e(TAG, "Interface unexpectedly changed from " + iface + " to " + mIface); mNMService.setInterfaceDown(iface); } - } catch (RemoteException e) { + } 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); } } From f851d0347ec4a655ec0857f142743d2360efd958 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 23 Jun 2017 01:21:25 +0900 Subject: [PATCH 029/152] Don't crash if the interface disappears just after appearing. If the interface disappears between interfaceAdded() and setInterfaceUp, we'll crash with an IllegalStateException in NetworkManagementService#setInterfaceConfig. Ignore the error instead. This should be safe because we don't modify any state unless our calls succeed. (cherry picked from commit 17f4e4a0276a246926f5b151099dbdb92e5d80d7) Bug: 62870779 Test: builds aosp_bullhead-eng Test: builds marlin-eng Test: exception is logged and device doesn't crash when unplugging USB ethernet adapter while it's being initialized Change-Id: If8c2375f7fffe25a9fa79dc4f1981c745384a276 --- .../com/android/server/ethernet/EthernetNetworkFactory.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 7ff3f6c310..d6d0defd32 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -208,7 +208,7 @@ class EthernetNetworkFactory { InterfaceConfiguration config = mNMService.getInterfaceConfig(iface); if (config == null) { - Log.e(TAG, "Null iterface config for " + iface + ". Bailing out."); + Log.e(TAG, "Null interface config for " + iface + ". Bailing out."); return; } @@ -220,7 +220,9 @@ class EthernetNetworkFactory { Log.e(TAG, "Interface unexpectedly changed from " + iface + " to " + mIface); mNMService.setInterfaceDown(iface); } - } catch (RemoteException e) { + } 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); } } From 89ffed793f453631621eb4da5c183dd9471b18ac Mon Sep 17 00:00:00 2001 From: Elvis Chien Date: Fri, 29 Sep 2017 15:47:05 +0800 Subject: [PATCH 030/152] ethernet: Fix the connect fail issue when switch DHCP to Static config at Ethernet interface. add different logic to handle static ip configuration. Bug: b/64914694 Test: follow the following steps to switch ethernet config 1.Plug Ethernet cable ,Ethernet succeed to access internet with DHCP mode 2.Change Ethernet IP settings to Static 3.Input correct ip , gateway, prefix length, DNS 4.UI show Connected, but failed to access Internet. Change-Id: I223bca85814e94745fbb8b50ca677eb7032e9bb3 (cherry picked from commit 44a107bc8f058c6ac1aab6fbfbf60bf8f3474711) --- .../ethernet/EthernetNetworkFactory.java | 100 +++++++----------- 1 file changed, 39 insertions(+), 61 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index d6d0defd32..2d54fd20e4 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -248,25 +248,6 @@ class EthernetNetworkFactory { return true; } - private boolean setStaticIpAddress(StaticIpConfiguration staticConfig) { - if (staticConfig.ipAddress != null && - staticConfig.gateway != null && - staticConfig.dnsServers.size() > 0) { - try { - Log.i(TAG, "Applying static IPv4 configuration to " + mIface + ": " + staticConfig); - InterfaceConfiguration config = mNMService.getInterfaceConfig(mIface); - config.setLinkAddress(staticConfig.ipAddress); - mNMService.setInterfaceConfig(mIface, config); - return true; - } catch(RemoteException|IllegalStateException e) { - Log.e(TAG, "Setting static IP address failed: " + e.getMessage()); - } - } else { - Log.e(TAG, "Invalid static IP configuration."); - } - return false; - } - public void updateAgent() { if (mNetworkAgent == null) return; if (DBG) { @@ -332,55 +313,52 @@ class EthernetNetworkFactory { mNetworkInfo)); } - LinkProperties linkProperties; - IpConfiguration config = mEthernetManager.getConfiguration(); - if (config.getIpAssignment() == IpAssignment.STATIC) { - if (!setStaticIpAddress(config.getStaticIpConfiguration())) { - // We've already logged an error. - return; - } - linkProperties = config.getStaticIpConfiguration().toLinkProperties(mIface); - } else { - mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); - IpManager.Callback ipmCallback = new IpManager.Callback() { - @Override - public void onProvisioningSuccess(LinkProperties newLp) { - mHandler.post(() -> onIpLayerStarted(newLp)); - } - - @Override - public void onProvisioningFailure(LinkProperties newLp) { - mHandler.post(() -> onIpLayerStopped(newLp)); - } - - @Override - public void onLinkPropertiesChange(LinkProperties newLp) { - mHandler.post(() -> updateLinkProperties(newLp)); - } - }; - - stopIpManager(); - mIpManager = new IpManager(mContext, mIface, ipmCallback); - - if (config.getProxySettings() == ProxySettings.STATIC || - config.getProxySettings() == ProxySettings.PAC) { - mIpManager.setHttpProxy(config.getHttpProxy()); + mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); + IpManager.Callback ipmCallback = new IpManager.Callback() { + @Override + public void onProvisioningSuccess(LinkProperties newLp) { + mHandler.post(() -> onIpLayerStarted(newLp)); } - final String tcpBufferSizes = mContext.getResources().getString( - com.android.internal.R.string.config_ethernet_tcp_buffers); - if (!TextUtils.isEmpty(tcpBufferSizes)) { - mIpManager.setTcpBufferSizes(tcpBufferSizes); + @Override + public void onProvisioningFailure(LinkProperties newLp) { + mHandler.post(() -> onIpLayerStopped(newLp)); } - final ProvisioningConfiguration provisioningConfiguration = - mIpManager.buildProvisioningConfiguration() - .withProvisioningTimeoutMs(0) - .build(); - mIpManager.startProvisioning(provisioningConfiguration); + @Override + public void onLinkPropertiesChange(LinkProperties newLp) { + mHandler.post(() -> updateLinkProperties(newLp)); + } + }; + + stopIpManager(); + mIpManager = new IpManager(mContext, mIface, ipmCallback); + + if (config.getProxySettings() == ProxySettings.STATIC || + config.getProxySettings() == ProxySettings.PAC) { + mIpManager.setHttpProxy(config.getHttpProxy()); } + + final String tcpBufferSizes = mContext.getResources().getString( + com.android.internal.R.string.config_ethernet_tcp_buffers); + if (!TextUtils.isEmpty(tcpBufferSizes)) { + mIpManager.setTcpBufferSizes(tcpBufferSizes); + } + + final ProvisioningConfiguration provisioningConfiguration; + if (config.getIpAssignment() == IpAssignment.STATIC) { + provisioningConfiguration = IpManager.buildProvisioningConfiguration() + .withStaticConfiguration(config.getStaticIpConfiguration()) + .build(); + } else { + provisioningConfiguration = mIpManager.buildProvisioningConfiguration() + .withProvisioningTimeoutMs(0) + .build(); + } + + mIpManager.startProvisioning(provisioningConfiguration); } /** From 30b747ef956aca1481bdc46562bd6dc8934aa2d1 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 27 Oct 2017 17:56:52 -0600 Subject: [PATCH 031/152] Define NOT_ROAMING network capability. The "roaming" state of a network really belongs on NetworkCapabilities instead of being published through NetworkInfo.isRoaming(). One major reason is to support developers creating NetworkRequests for a non-roaming network. Test: bit FrameworksNetTests:android.net.,com.android.server.net.,com.android.server.connectivity. Bug: 68397798, 16207332 Change-Id: I0722d7b38d0478de3834b869552f48403af9d553 --- .../src/com/android/server/ethernet/EthernetNetworkFactory.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 2d54fd20e4..0bbe3b5e3c 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -427,6 +427,8 @@ class EthernetNetworkFactory { 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_RESTRICTED); // We have no useful data on bandwidth. Say 100M up and 100M down. :-( mNetworkCapabilities.setLinkUpstreamBandwidthKbps(100 * 1000); From efe4af492669b7aeebff417cf7595a6fefe13bb3 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 17 Jan 2018 18:25:16 +0900 Subject: [PATCH 032/152] Add "not congested" network capability. Can be used by a network to indicate when it's congested, meaning that apps should defer network traffic that could be done at a later time. Test: bit FrameworksNetTests:android.net.,com.android.server.net.,com.android.server.connectivity.VpnTest,com.android.server.ConnectivityServiceTest Bug: 64133169 Change-Id: I97664d041920c8d6e3f9fb7c9e8638925b15c30e --- .../src/com/android/server/ethernet/EthernetNetworkFactory.java | 1 + 1 file changed, 1 insertion(+) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 0bbe3b5e3c..2e5d09e2ca 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -429,6 +429,7 @@ class EthernetNetworkFactory { 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); From 52d046eb8a3d29931f233f992df6df48f709c7dc Mon Sep 17 00:00:00 2001 From: Pavel Maltsev Date: Tue, 31 Oct 2017 15:42:16 -0700 Subject: [PATCH 033/152] 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 --- .../server/ethernet/EthernetConfigStore.java | 69 +- .../ethernet/EthernetNetworkFactory.java | 741 ++++++++---------- .../server/ethernet/EthernetServiceImpl.java | 89 +-- .../server/ethernet/EthernetTracker.java | 383 +++++++++ 4 files changed, 809 insertions(+), 473 deletions(-) create mode 100644 service-t/src/com/android/server/ethernet/EthernetTracker.java diff --git a/service-t/src/com/android/server/ethernet/EthernetConfigStore.java b/service-t/src/com/android/server/ethernet/EthernetConfigStore.java index 676bc99d8a..6445603b96 100644 --- a/service-t/src/com/android/server/ethernet/EthernetConfigStore.java +++ b/service-t/src/com/android/server/ethernet/EthernetConfigStore.java @@ -17,11 +17,8 @@ package com.android.server.ethernet; import android.net.IpConfiguration; -import android.net.IpConfiguration.IpAssignment; -import android.net.IpConfiguration.ProxySettings; import android.os.Environment; -import android.util.Log; -import android.util.SparseArray; +import android.util.ArrayMap; 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. */ -public class EthernetConfigStore extends IpConfigStore { - private static final String TAG = "EthernetConfigStore"; - +public class EthernetConfigStore { private static final String ipConfigFile = Environment.getDataDirectory() + "/misc/ethernet/ipconfig.txt"; + private IpConfigStore mStore = new IpConfigStore(); + private ArrayMap mIpConfigurations; + private IpConfiguration mIpConfigurationForDefaultInterface; + private final Object mSync = new Object(); + public EthernetConfigStore() { + mIpConfigurations = new ArrayMap<>(0); } - public IpConfiguration readIpAndProxyConfigurations() { - SparseArray networks = readIpAndProxyConfigurations(ipConfigFile); + public void read() { + synchronized (mSync) { + ArrayMap configs = + IpConfigStore.readIpConfigurations(ipConfigFile); - if (networks.size() == 0) { - Log.w(TAG, "No Ethernet configuration found. Using default."); - return new IpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, null, null); + // 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; } - - if (networks.size() > 1) { - // 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 writeIpAndProxyConfigurations(IpConfiguration config) { - SparseArray networks = new SparseArray(); - networks.put(0, config); - writeIpAndProxyConfigurations(ipConfigFile, networks); + 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 getIpConfigurations() { + synchronized (mSync) { + return new ArrayMap<>(mIpConfigurations); + } + } + + public IpConfiguration getIpConfigurationForDefaultInterface() { + synchronized (mSync) { + return new IpConfiguration(mIpConfigurationForDefaultInterface); + } } } diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 2e5d09e2ca..29464b78ce 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -16,12 +16,9 @@ package com.android.server.ethernet; +import static android.net.ConnectivityManager.TYPE_ETHERNET; + 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.IpAssignment; import android.net.IpConfiguration.ProxySettings; @@ -31,292 +28,215 @@ import android.net.NetworkCapabilities; import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; -import android.net.StaticIpConfiguration; -import android.net.ip.IpManager; -import android.net.ip.IpManager.ProvisioningConfiguration; +import android.net.NetworkRequest; +import android.net.NetworkSpecifier; +import android.net.StringNetworkSpecifier; +import android.net.ip.IpClient; +import android.net.ip.IpClient.ProvisioningConfiguration; 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.util.Log; import com.android.internal.util.IndentingPrintWriter; -import com.android.server.net.BaseNetworkObserver; import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.Arrays; -import java.util.concurrent.CountDownLatch; - +import java.util.concurrent.ConcurrentHashMap; /** - * 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., - * for Ethernet adapters connected over USB). This class currently supports - * 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 config_ethernet_iface_regex - * 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 + * 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. */ -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 TAG = "EthernetNetworkFactory"; - private static final int NETWORK_SCORE = 70; - private static final boolean DBG = true; - /** Tracks interface changes. Called from NetworkManagementService. */ - private InterfaceObserver mInterfaceObserver; + private final ConcurrentHashMap mTrackingInterfaces = + new ConcurrentHashMap<>(); + private final Handler mHandler; + private final Context mContext; - /** For static IP configuration */ - private EthernetManager mEthernetManager; + public EthernetNetworkFactory(Handler handler, Context context, NetworkCapabilities filter) { + super(handler.getLooper(), context, NETWORK_TYPE, filter); - /** To set link state and configure IP addresses. */ - private INetworkManagementService mNMService; + mHandler = handler; + mContext = context; - /** All code runs here, including start(). */ - 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 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 listeners) { - initNetworkCapabilities(); - clearInfo(); - mListeners = listeners; + setScoreFilter(NETWORK_SCORE); } - private class LocalNetworkFactory extends NetworkFactory { - LocalNetworkFactory(String name, Context context, Looper looper) { - super(looper, context, name, new NetworkCapabilities()); + @Override + public boolean acceptRequest(NetworkRequest request, int score) { + if (DBG) { + Log.d(TAG, "acceptRequest, request: " + request + ", score: " + score); } - protected void startNetwork() { - if (!mNetworkRequested) { - mNetworkRequested = true; - maybeStartIpManager(); - } + return networkForRequest(request) != null; + } + + @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; } - protected void stopNetwork() { - mNetworkRequested = false; - stopIpManager(); + if (++network.refCount == 1) { + network.start(); } } - private void clearInfo() { - mLinkProperties = new LinkProperties(); - mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, ""); - mNetworkInfo.setExtraInfo(mHwAddr); - mNetworkInfo.setIsAvailable(isTrackingInterface()); - } + @Override + protected void releaseNetworkFor(NetworkRequest networkRequest) { + NetworkInterfaceState network = networkForRequest(networkRequest); + if (network == null) { + Log.e(TAG, "needNetworkFor, failed to get a network for " + networkRequest); + return; + } - private void stopIpManager() { - if (mIpManager != null) { - mIpManager.shutdown(); - mIpManager = null; + if (--network.refCount == 1) { + network.stop(); } - // 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. - * Called on link state changes or on startup. + * Returns an array of available interface names. The array is sorted: unrestricted interfaces + * goes first, then sorted by name. */ - private void updateInterfaceState(String iface, boolean up) { - if (!mIface.equals(iface)) { + 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); + } + + void addInterface(String ifaceName, String hwAddress, NetworkCapabilities capabilities, + IpConfiguration ipConfiguration) { + if (mTrackingInterfaces.containsKey(ifaceName)) { + Log.e(TAG, "Interface with name " + ifaceName + " already exists."); return; } - Log.d(TAG, "updateInterface: " + iface + " link " + (up ? "up" : "down")); - mLinkUp = up; - if (up) { - maybeStartIpManager(); + if (DBG) { + Log.d(TAG, "addInterface, iface: " + ifaceName + ", capabilities: " + capabilities); + } + + NetworkInterfaceState iface = new NetworkInterfaceState( + ifaceName, hwAddress, mHandler, mContext, capabilities); + iface.setIpConfig(ipConfiguration); + mTrackingInterfaces.put(ifaceName, iface); + + updateCapabilityFilter(); + } + + private void updateCapabilityFilter() { + NetworkCapabilities capabilitiesFilter = new NetworkCapabilities(); + capabilitiesFilter.clearAll(); + + for (NetworkInterfaceState iface: mTrackingInterfaces.values()) { + capabilitiesFilter.combineCapabilities(iface.mCapabilities); + } + + if (DBG) Log.d(TAG, "updateCapabilityFilter: " + capabilitiesFilter); + setCapabilityFilter(capabilitiesFilter); + } + + void removeInterface(String interfaceName) { + NetworkInterfaceState iface = mTrackingInterfaces.remove(interfaceName); + 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; + } + + if (DBG) { + Log.d(TAG, "updateInterfaceLinkState, iface: " + ifaceName + ", up: " + up); + } + + NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName); + return iface.updateLinkState(up); + } + + boolean hasInterface(String interfacName) { + 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 { - stopIpManager(); - } - } - - private class InterfaceObserver extends BaseNetworkObserver { - @Override - public void interfaceLinkStateChanged(String iface, boolean up) { - mHandler.post(() -> { - 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(); + for (NetworkInterfaceState n : mTrackingInterfaces.values()) { + if (n.statisified(request.networkCapabilities)) { + network = n; + break; } - }); - } - } - - 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; } - - 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) { - Log.i(TAG, "Updating mNetworkAgent with: " + - 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) { - if (mNetworkAgent != null) { - Log.e(TAG, "Already have a NetworkAgent - aborting new request"); - stopIpManager(); - return; - } - mLinkProperties = linkProperties; - mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr); - - // Create our NetworkAgent. - mNetworkAgent = new NetworkAgent(mHandler.getLooper(), mContext, - NETWORK_TYPE, mNetworkInfo, mNetworkCapabilities, mLinkProperties, - NETWORK_SCORE) { - public void unwanted() { - if (this == mNetworkAgent) { - stopIpManager(); - } else if (mNetworkAgent != null) { - Log.d(TAG, "Ignoring unwanted as we have a more modern " + - "instance"); - } // Otherwise, we've already called stopIpManager. - } - }; - } - - 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. - stopIpManager(); - maybeStartIpManager(); - } - - void updateLinkProperties(LinkProperties linkProperties) { - mLinkProperties = linkProperties; - if (mNetworkAgent != null) { - mNetworkAgent.sendLinkProperties(linkProperties); - } - } - - public void maybeStartIpManager() { - if (mNetworkRequested && mIpManager == null && isTrackingInterface()) { - startIpManager(); - } - } - - public void startIpManager() { - if (DBG) { - Log.d(TAG, String.format("starting IpManager(%s): mNetworkInfo=%s", mIface, - mNetworkInfo)); + Log.i(TAG, "networkForRequest, request: " + request + ", network: " + network); } - IpConfiguration config = mEthernetManager.getConfiguration(); + return network; + } - mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); - IpManager.Callback ipmCallback = new IpManager.Callback() { + 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 public void onProvisioningSuccess(LinkProperties newLp) { mHandler.post(() -> onIpLayerStarted(newLp)); @@ -333,178 +253,191 @@ class EthernetNetworkFactory { } }; - stopIpManager(); - mIpManager = new IpManager(mContext, mIface, ipmCallback); + NetworkInterfaceState(String ifaceName, String hwAddress, Handler handler, Context context, + NetworkCapabilities capabilities) { + name = ifaceName; + mCapabilities = capabilities; + mHandler = handler; + mContext = context; - if (config.getProxySettings() == ProxySettings.STATIC || - config.getProxySettings() == ProxySettings.PAC) { - mIpManager.setHttpProxy(config.getHttpProxy()); + mHwAddress = hwAddress; + mNetworkInfo = new NetworkInfo(TYPE_ETHERNET, 0, NETWORK_TYPE, ""); + mNetworkInfo.setExtraInfo(mHwAddress); + mNetworkInfo.setIsAvailable(true); } - final String tcpBufferSizes = mContext.getResources().getString( - com.android.internal.R.string.config_ethernet_tcp_buffers); - if (!TextUtils.isEmpty(tcpBufferSizes)) { - mIpManager.setTcpBufferSizes(tcpBufferSizes); + void setIpConfig(IpConfiguration ipConfig) { + + this.mIpConfig = ipConfig; } - final ProvisioningConfiguration provisioningConfiguration; - if (config.getIpAssignment() == IpAssignment.STATIC) { - provisioningConfiguration = IpManager.buildProvisioningConfiguration() - .withStaticConfiguration(config.getStaticIpConfiguration()) - .build(); - } else { - provisioningConfiguration = mIpManager.buildProvisioningConfiguration() - .withProvisioningTimeoutMs(0) - .build(); + boolean statisified(NetworkCapabilities requestedCapabilities) { + return requestedCapabilities.satisfiedByNetworkCapabilities(mCapabilities); } - mIpManager.startProvisioning(provisioningConfiguration); - } - - /** - * Begin monitoring connectivity - */ - public void start(Context context, Handler handler) { - mHandler = handler; - - // The services we use. - IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); - mNMService = INetworkManagementService.Stub.asInterface(b); - mEthernetManager = (EthernetManager) context.getSystemService(Context.ETHERNET_SERVICE); - - // 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); + boolean isRestricted() { + return mCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); } - // If an Ethernet interface is already connected, start tracking that. - // Otherwise, the first Ethernet interface to appear will be tracked. - mHandler.post(() -> trackFirstAvailableInterface()); - } + private void start() { + if (DBG) { + Log.d(TAG, String.format("starting IpClient(%s): mNetworkInfo=%s", name, + mNetworkInfo)); + } + if (mIpClient != null) stop(); - 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; + 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); + } + 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); } - } catch (RemoteException|IllegalStateException e) { - Log.e(TAG, "Could not get list of interfaces " + e); + } + + /** 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)) { + ipClient.setTcpBufferSizes(tcpBufferSizes); + } + + final ProvisioningConfiguration provisioningConfiguration; + if (config.getIpAssignment() == IpAssignment.STATIC) { + provisioningConfiguration = IpClient.buildProvisioningConfiguration() + .withStaticConfiguration(config.getStaticIpConfiguration()) + .build(); + } else { + provisioningConfiguration = IpClient.buildProvisioningConfiguration() + .withProvisioningTimeoutMs(0) + .build(); + } + + ipClient.startProvisioning(provisioningConfiguration); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{ " + + "iface: " + name + ", " + + "up: " + mLinkUp + ", " + + "hwAddress: " + mHwAddress + ", " + + "networkInfo: " + mNetworkInfo + ", " + + "networkAgent: " + mNetworkAgent + ", " + + "ipClient: " + mIpClient + "," + + "linkProperties: " + mLinkProperties + + "}"; } } - 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) { - try { - postAndWaitForRunnable(() -> { - pw.println("Network Requested: " + mNetworkRequested); - if (isTrackingInterface()) { - pw.println("Tracking interface: " + mIface); - pw.increaseIndent(); - pw.println("MAC address: " + mHwAddr); - pw.println("Link state: " + (mLinkUp ? "up" : "down")); - pw.decreaseIndent(); - } else { - pw.println("Not tracking any interface"); - } - - pw.println(); - pw.println("NetworkInfo: " + mNetworkInfo); - pw.println("LinkProperties: " + mLinkProperties); - pw.println("NetworkAgent: " + mNetworkAgent); - if (mIpManager != null) { - pw.println("IpManager:"); - pw.increaseIndent(); - mIpManager.dump(fd, pw, args); - pw.decreaseIndent(); - } - }); - } catch (InterruptedException e) { - throw new IllegalStateException("dump() interrupted"); + 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(); + ifaceState.mIpClient.dump(fd, pw, args); + pw.decreaseIndent(); } + pw.decreaseIndent(); } } diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 42996d6826..d5beec1cb4 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -21,14 +21,10 @@ import android.content.pm.PackageManager; import android.net.IEthernetManager; import android.net.IEthernetServiceListener; import android.net.IpConfiguration; -import android.net.IpConfiguration.IpAssignment; -import android.net.IpConfiguration.ProxySettings; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; -import android.os.RemoteCallbackList; import android.os.RemoteException; -import android.provider.Settings; import android.util.Log; import android.util.PrintWriterPrinter; @@ -41,31 +37,18 @@ import java.util.concurrent.atomic.AtomicBoolean; /** * EthernetServiceImpl handles remote Ethernet operation requests by implementing * the IEthernetManager interface. - * - * @hide */ public class EthernetServiceImpl extends IEthernetManager.Stub { private static final String TAG = "EthernetServiceImpl"; private final Context mContext; - private final EthernetConfigStore mEthernetConfigStore; private final AtomicBoolean mStarted = new AtomicBoolean(false); - private IpConfiguration mIpConfiguration; private Handler mHandler; - private final EthernetNetworkFactory mTracker; - private final RemoteCallbackList mListeners = - new RemoteCallbackList(); + private EthernetTracker mTracker; public EthernetServiceImpl(Context 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() { @@ -80,6 +63,18 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { "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() { Log.i(TAG, "Starting Ethernet service"); @@ -87,60 +82,68 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { handlerThread.start(); mHandler = new Handler(handlerThread.getLooper()); - mTracker.start(mContext, mHandler); + mTracker = new EthernetTracker(mContext, mHandler); + mTracker.start(); mStarted.set(true); } + @Override + public String[] getAvailableInterfaces() throws RemoteException { + return mTracker.getInterfaces(checkUseRestrictedNetworksPermission()); + } + /** * Get Ethernet configuration * @return the Ethernet Configuration, contained in {@link IpConfiguration}. */ @Override - public IpConfiguration getConfiguration() { + public IpConfiguration getConfiguration(String iface) { enforceAccessPermission(); - synchronized (mIpConfiguration) { - return new IpConfiguration(mIpConfiguration); + if (mTracker.isRestrictedInterface(iface)) { + enforceUseRestrictedNetworksPermission(); } + + return new IpConfiguration(mTracker.getIpConfiguration(iface)); } /** * Set Ethernet configuration */ @Override - public void setConfiguration(IpConfiguration config) { + public void setConfiguration(String iface, IpConfiguration config) { if (!mStarted.get()) { Log.w(TAG, "System isn't ready enough to change ethernet configuration"); } enforceConnectivityInternalPermission(); - synchronized (mIpConfiguration) { - mEthernetConfigStore.writeIpAndProxyConfigurations(config); - - // TODO: this does not check proxy settings, gateways, etc. - // Fix this by making IpConfiguration a complete representation of static configuration. - if (!config.equals(mIpConfiguration)) { - mIpConfiguration = new IpConfiguration(config); - mTracker.stop(); - mTracker.start(mContext, mHandler); - } + if (mTracker.isRestrictedInterface(iface)) { + enforceUseRestrictedNetworksPermission(); } + + // 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 the system currently has one or more - * Ethernet interfaces. + * Indicates whether given interface is available. */ @Override - public boolean isAvailable() { + public boolean isAvailable(String iface) { 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. */ public void addListener(IEthernetServiceListener listener) { @@ -148,7 +151,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { throw new IllegalArgumentException("listener must not be null"); } 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"); } enforceAccessPermission(); - mListeners.unregister(listener); + mTracker.removeListener(listener); } @Override @@ -179,12 +182,6 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { mTracker.dump(fd, pw, args); pw.decreaseIndent(); - pw.println(); - pw.println("Stored Ethernet configuration: "); - pw.increaseIndent(); - pw.println(mIpConfiguration); - pw.decreaseIndent(); - pw.println("Handler:"); pw.increaseIndent(); mHandler.dump(new PrintWriterPrinter(pw), "EthernetServiceImpl"); diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java new file mode 100644 index 0000000000..7f893e0339 --- /dev/null +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -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. + * + *

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. + * + *

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 mNetworkCapabilities = + new ConcurrentHashMap<>(); + private final ConcurrentHashMap mIpConfigurations = + new ConcurrentHashMap<>(); + + private final INetworkManagementService mNMService; + private final Handler mHandler; + private final EthernetNetworkFactory mFactory; + private final EthernetConfigStore mConfigStore; + + private final RemoteCallbackList 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 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); + }); + } +} From de93b3eb05dcb58d5a7bec6d5385e353d66f2fa9 Mon Sep 17 00:00:00 2001 From: Luis Hector Chavez Date: Fri, 16 Feb 2018 14:59:53 -0800 Subject: [PATCH 034/152] Avoid re-creating an IpClient if the network has already started This change avoids calling start() on needNetworkFor() if an IpClient object has already been created. This is the case when the interface is connected from boot, as is the case in Chrome OS. Bug: 73396557 Test: Networking is 100% stable in Chrome OS Change-Id: Iaa073d6477aadca2e4e5233b333d717ad82c1f3d --- .../server/ethernet/EthernetNetworkFactory.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 29464b78ce..d4648795c6 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -280,11 +280,14 @@ public class EthernetNetworkFactory extends NetworkFactory { } private void start() { + if (mIpClient != null) { + if (DBG) Log.d(TAG, "IpClient already started"); + return; + } 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); @@ -325,6 +328,7 @@ public class EthernetNetworkFactory extends NetworkFactory { 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. + stop(); start(); } @@ -338,12 +342,11 @@ public class EthernetNetworkFactory extends NetworkFactory { /** Returns true if state has been modified */ boolean updateLinkState(boolean up) { if (mLinkUp == up) return false; - mLinkUp = up; + + stop(); if (up) { start(); - } else { - stop(); } return true; From 7048285cb3a9e618aea65d21f3f74c49dbde0b4d Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Wed, 21 Feb 2018 14:54:04 -0800 Subject: [PATCH 035/152] Wait for IpClient to shutdown This makes sure that we never accidentally have two IpClients vying for control of the same interface. Test: as follows - built - flashed - booted Bug: 62476366 Change-Id: Iab4ca7c2445e70b6f8beaf5dc6921cb0c6cd56ed --- .../src/com/android/server/ethernet/EthernetNetworkFactory.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index d4648795c6..f95500e6e8 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -355,8 +355,10 @@ public class EthernetNetworkFactory extends NetworkFactory { void stop() { if (mIpClient != null) { mIpClient.shutdown(); + mIpClient.awaitShutdown(); 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. From b23181bbe9275b315a4c4b448045a9e155fcee79 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 2 May 2018 14:57:06 -0600 Subject: [PATCH 036/152] Ethernet should be NOT_CONGESTED by default. Bug: 79160437 Test: builds, boots Change-Id: Iff726805a3c6b7cf2a4b741dbba93552c378a6e1 --- service-t/src/com/android/server/ethernet/EthernetTracker.java | 1 + 1 file changed, 1 insertion(+) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 7f893e0339..688d84a2d6 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -311,6 +311,7 @@ final class EthernetTracker { nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); return nc; } From 97446b8978e0c56d29329e190cadcd964e8bf93d Mon Sep 17 00:00:00 2001 From: Pavel Maltsev Date: Sat, 28 Apr 2018 23:23:26 -0700 Subject: [PATCH 037/152] Fix NPE during dumpsys ethernet Handle the case when IpClient wasn't created for network interface which may happen for virtual device Bug: 78482534 Test: dumpsys ethernet Change-Id: I3405dd4f72d4a6444448f0d6ec0497aead07bade --- .../android/server/ethernet/EthernetNetworkFactory.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index f95500e6e8..de0a691c75 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -440,7 +440,12 @@ public class EthernetNetworkFactory extends NetworkFactory { NetworkInterfaceState ifaceState = mTrackingInterfaces.get(iface); pw.println(iface + ":" + ifaceState); pw.increaseIndent(); - ifaceState.mIpClient.dump(fd, pw, args); + final IpClient ipClient = ifaceState.mIpClient; + if (ipClient != null) { + ipClient.dump(fd, pw, args); + } else { + pw.println("IpClient is null"); + } pw.decreaseIndent(); } pw.decreaseIndent(); From aea0136d01ab31ed7cde6a2bec6d4b99561d5f42 Mon Sep 17 00:00:00 2001 From: Pavel Maltsev Date: Sat, 28 Apr 2018 23:23:26 -0700 Subject: [PATCH 038/152] Fix NPE during dumpsys ethernet Handle the case when IpClient wasn't created for network interface which may happen for virtual device Bug: 78482534 Test: dumpsys ethernet Merged-In: I374a91265660e814b4f0f033b3970fd98921ca84 Merged-In: Id4ab7c9a8a5238491c8405ae260862e76a7671c1 Change-Id: I3405dd4f72d4a6444448f0d6ec0497aead07bade (cherry picked from commit 97446b8978e0c56d29329e190cadcd964e8bf93d) --- .../android/server/ethernet/EthernetNetworkFactory.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index f95500e6e8..de0a691c75 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -440,7 +440,12 @@ public class EthernetNetworkFactory extends NetworkFactory { NetworkInterfaceState ifaceState = mTrackingInterfaces.get(iface); pw.println(iface + ":" + ifaceState); pw.increaseIndent(); - ifaceState.mIpClient.dump(fd, pw, args); + final IpClient ipClient = ifaceState.mIpClient; + if (ipClient != null) { + ipClient.dump(fd, pw, args); + } else { + pw.println("IpClient is null"); + } pw.decreaseIndent(); } pw.decreaseIndent(); From a8f3c01be97d3011979d0f4083187f4a2ae01a03 Mon Sep 17 00:00:00 2001 From: Pavel Maltsev Date: Wed, 9 May 2018 14:49:33 -0700 Subject: [PATCH 039/152] Fix overriding ip configurtion with default one EthernetConfigStore should return 'null' for default interface if the default interface hasn't been configured otherwise it would be hard to distinguish not-configured vs configured with default values. Bug: 79415136 Test: verified w/o .xml overlay Ethernet continues to work Test: verified that ip config from overlay is not getting overriden Change-Id: I4eb914923f3664b12b6af0ae05f45b60c5312b02 --- .../src/com/android/server/ethernet/EthernetConfigStore.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetConfigStore.java b/service-t/src/com/android/server/ethernet/EthernetConfigStore.java index 6445603b96..6b623f48ff 100644 --- a/service-t/src/com/android/server/ethernet/EthernetConfigStore.java +++ b/service-t/src/com/android/server/ethernet/EthernetConfigStore.java @@ -16,6 +16,7 @@ package com.android.server.ethernet; +import android.annotation.Nullable; import android.net.IpConfiguration; import android.os.Environment; import android.util.ArrayMap; @@ -77,9 +78,11 @@ public class EthernetConfigStore { } } + @Nullable public IpConfiguration getIpConfigurationForDefaultInterface() { synchronized (mSync) { - return new IpConfiguration(mIpConfigurationForDefaultInterface); + return mIpConfigurationForDefaultInterface == null + ? null : new IpConfiguration(mIpConfigurationForDefaultInterface); } } } From 6c61d1013db93dc0977d1968820708ab40032ae1 Mon Sep 17 00:00:00 2001 From: Pavel Maltsev Date: Wed, 9 May 2018 14:49:33 -0700 Subject: [PATCH 040/152] Fix overriding ip configurtion with default one EthernetConfigStore should return 'null' for default interface if the default interface hasn't been configured otherwise it would be hard to distinguish not-configured vs configured with default values. Bug: 79415136 Test: verified w/o .xml overlay Ethernet continues to work Test: verified that ip config from overlay is not getting overriden Merged-In: I82933a83a7d13903bbce9a85d6e8dae1a492bf24 Merged-In: I98133ad41229b93f51ea3976d311f9896456a56c Change-Id: I4eb914923f3664b12b6af0ae05f45b60c5312b02 (cherry picked from commit a8f3c01be97d3011979d0f4083187f4a2ae01a03) --- .../src/com/android/server/ethernet/EthernetConfigStore.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetConfigStore.java b/service-t/src/com/android/server/ethernet/EthernetConfigStore.java index 6445603b96..6b623f48ff 100644 --- a/service-t/src/com/android/server/ethernet/EthernetConfigStore.java +++ b/service-t/src/com/android/server/ethernet/EthernetConfigStore.java @@ -16,6 +16,7 @@ package com.android.server.ethernet; +import android.annotation.Nullable; import android.net.IpConfiguration; import android.os.Environment; import android.util.ArrayMap; @@ -77,9 +78,11 @@ public class EthernetConfigStore { } } + @Nullable public IpConfiguration getIpConfigurationForDefaultInterface() { synchronized (mSync) { - return new IpConfiguration(mIpConfigurationForDefaultInterface); + return mIpConfigurationForDefaultInterface == null + ? null : new IpConfiguration(mIpConfigurationForDefaultInterface); } } } From e28118d0c3ddb586780013371ec8ddd469a4cfc6 Mon Sep 17 00:00:00 2001 From: Pavel Maltsev Date: Wed, 30 May 2018 11:20:46 -0700 Subject: [PATCH 041/152] Add missing features to static IP config In addition to IP address, OEMs should be able to set gateway, DNS and domains. Bug: 80090920 Test: runtest -x frameworks/opt/net/ethernet/tests Change-Id: I4e3d51a6955d7bfe5ca4e8079936ea10c28832e4 --- Android.mk | 2 + .../server/ethernet/EthernetTracker.java | 58 +++++++- tests/ethernet/Android.mk | 36 +++++ tests/ethernet/AndroidManifest.xml | 28 ++++ .../server/ethernet/EthernetTrackerTest.java | 126 ++++++++++++++++++ 5 files changed, 244 insertions(+), 6 deletions(-) create mode 100644 tests/ethernet/Android.mk create mode 100644 tests/ethernet/AndroidManifest.xml create mode 100644 tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java diff --git a/Android.mk b/Android.mk index 99559ac686..952fa9d652 100644 --- a/Android.mk +++ b/Android.mk @@ -28,3 +28,5 @@ LOCAL_JAVA_LIBRARIES := services LOCAL_MODULE := ethernet-service include $(BUILD_JAVA_LIBRARY) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 688d84a2d6..00eedd502d 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -36,10 +36,13 @@ 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.server.net.BaseNetworkObserver; import java.io.FileDescriptor; +import java.net.InetAddress; +import java.util.ArrayList; import java.util.concurrent.ConcurrentHashMap; /** @@ -300,7 +303,7 @@ final class EthernetTracker { mNetworkCapabilities.put(name, nc); if (tokens.length > 2 && !TextUtils.isEmpty(tokens[2])) { - IpConfiguration ipConfig = createStaticIpConfiguration(tokens[2]); + IpConfiguration ipConfig = parseStaticIpConfiguration(tokens[2]); mIpConfigurations.put(name, ipConfig); } } @@ -342,11 +345,54 @@ final class EthernetTracker { 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); + /** + * Parses static IP configuration. + * + * @param staticIpConfig represents static IP configuration in the following format: {@code + * ip= gateway= dns= + * domains=} + */ + @VisibleForTesting + static IpConfiguration parseStaticIpConfiguration(String staticIpConfig) { + StaticIpConfiguration ipConfig = new StaticIpConfiguration(); + + 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": + ipConfig.ipAddress = new LinkAddress(value); + break; + case "domains": + ipConfig.domains = value; + break; + case "gateway": + ipConfig.gateway = InetAddress.parseNumericAddress(value); + break; + case "dns": { + ArrayList dnsAddresses = new ArrayList<>(); + for (String address: value.split(",")) { + dnsAddresses.add(InetAddress.parseNumericAddress(address)); + } + ipConfig.dnsServers.addAll(dnsAddresses); + break; + } + default : { + throw new IllegalArgumentException("Unexpected key: " + key + + " in " + staticIpConfig); + } + } + } + return new IpConfiguration(IpAssignment.STATIC, ProxySettings.NONE, ipConfig, null); } private static IpConfiguration createDefaultIpConfiguration() { diff --git a/tests/ethernet/Android.mk b/tests/ethernet/Android.mk new file mode 100644 index 0000000000..6b2c103474 --- /dev/null +++ b/tests/ethernet/Android.mk @@ -0,0 +1,36 @@ +# 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. +# + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-java-files-under, java) + +LOCAL_PACKAGE_NAME := EthernetServiceTests + +LOCAL_CERTIFICATE := platform +LOCAL_PRIVATE_PLATFORM_APIS := true + +LOCAL_MODULE_TAGS := tests + +LOCAL_JAVA_LIBRARIES := \ + android.test.runner \ + android.test.base + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android-support-test \ + ethernet-service + +include $(BUILD_PACKAGE) diff --git a/tests/ethernet/AndroidManifest.xml b/tests/ethernet/AndroidManifest.xml new file mode 100644 index 0000000000..1bc0775310 --- /dev/null +++ b/tests/ethernet/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java new file mode 100644 index 0000000000..70d316dbff --- /dev/null +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -0,0 +1,126 @@ +/* + * 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 org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import android.net.IpConfiguration; +import android.net.IpConfiguration.IpAssignment; +import android.net.IpConfiguration.ProxySettings; +import android.net.LinkAddress; +import android.net.StaticIpConfiguration; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class EthernetTrackerTest { + + @Test + public void createStaticIpConfiguration() { + assertStaticConfiguration("", new StaticIpConfiguration()); + + assertStaticConfiguration( + "ip=192.0.2.10/24", + new StaticIpConfigBuilder().setIp("192.0.2.10/24").build()); + + assertStaticConfiguration( + "ip=192.0.2.10/24 dns=4.4.4.4,8.8.8.8 gateway=192.0.2.1 domains=android", + new StaticIpConfigBuilder() + .setIp("192.0.2.10/24") + .setDns(new String[] {"4.4.4.4", "8.8.8.8"}) + .setGateway("192.0.2.1") + .setDomains("android") + .build()); + + // Verify order doesn't matter + assertStaticConfiguration( + "domains=android ip=192.0.2.10/24 gateway=192.0.2.1 dns=4.4.4.4,8.8.8.8 ", + new StaticIpConfigBuilder() + .setIp("192.0.2.10/24") + .setDns(new String[] {"4.4.4.4", "8.8.8.8"}) + .setGateway("192.0.2.1") + .setDomains("android") + .build()); + } + + @Test + public void createStaticIpConfiguration_Bad() { + assertFails("ip=192.0.2.1/24 gateway= blah=20.20.20.20"); // Unknown key + assertFails("ip=192.0.2.1"); // mask is missing + assertFails("ip=a.b.c"); // not a valid ip address + assertFails("dns=4.4.4.4,1.2.3.A"); // not valid ip address in dns + assertFails("="); // Key and value is empty + assertFails("ip="); // Value is empty + assertFails("ip=192.0.2.1/24 gateway="); // Gateway is empty + } + + private void assertFails(String config) { + try { + EthernetTracker.parseStaticIpConfiguration(config); + fail("Expected to fail: " + config); + } catch (IllegalArgumentException e) { + // expected + } + } + + private void assertStaticConfiguration(String configAsString, + StaticIpConfiguration expectedStaticIpConfig) { + IpConfiguration expectedIpConfiguration = new IpConfiguration(IpAssignment.STATIC, + ProxySettings.NONE, expectedStaticIpConfig, null); + + assertEquals(expectedIpConfiguration, + EthernetTracker.parseStaticIpConfiguration(configAsString)); + } + + private static class StaticIpConfigBuilder { + private final StaticIpConfiguration config = new StaticIpConfiguration(); + + StaticIpConfigBuilder setIp(String address) { + config.ipAddress = new LinkAddress(address); + return this; + } + + StaticIpConfigBuilder setDns(String[] dnsArray) { + for (String dns : dnsArray) { + config.dnsServers.add(InetAddress.parseNumericAddress(dns)); + } + return this; + } + + StaticIpConfigBuilder setGateway(String gateway) { + config.gateway = InetAddress.parseNumericAddress(gateway); + return this; + } + + StaticIpConfigBuilder setDomains(String domains) { + config.domains = domains; + return this; + } + + + StaticIpConfiguration build() { + return new StaticIpConfiguration(config); + } + } +} From 8d5e3e989a329e25bad9006c4a2df66a4f985d2f Mon Sep 17 00:00:00 2001 From: Pavel Maltsev Date: Wed, 30 May 2018 11:20:46 -0700 Subject: [PATCH 042/152] Add missing features to static IP config In addition to IP address, OEMs should be able to set gateway, DNS and domains. Bug: 80090920 Test: runtest -x frameworks/opt/net/ethernet/tests Cherry picked without conflicts. Merged-in: I4e3d51a6955d7bfe5ca4e8079936ea10c28832e4 (cherry picked from commit e28118d0c3ddb586780013371ec8ddd469a4cfc6) Change-Id: Ia8f095fbbcd414c070be4d5ce79dbc70bb9b1937 --- Android.mk | 2 + .../server/ethernet/EthernetTracker.java | 58 +++++++- tests/ethernet/Android.mk | 36 +++++ tests/ethernet/AndroidManifest.xml | 28 ++++ .../server/ethernet/EthernetTrackerTest.java | 126 ++++++++++++++++++ 5 files changed, 244 insertions(+), 6 deletions(-) create mode 100644 tests/ethernet/Android.mk create mode 100644 tests/ethernet/AndroidManifest.xml create mode 100644 tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java diff --git a/Android.mk b/Android.mk index 99559ac686..952fa9d652 100644 --- a/Android.mk +++ b/Android.mk @@ -28,3 +28,5 @@ LOCAL_JAVA_LIBRARIES := services LOCAL_MODULE := ethernet-service include $(BUILD_JAVA_LIBRARY) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 7f893e0339..034b15d55c 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -36,10 +36,13 @@ 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.server.net.BaseNetworkObserver; import java.io.FileDescriptor; +import java.net.InetAddress; +import java.util.ArrayList; import java.util.concurrent.ConcurrentHashMap; /** @@ -300,7 +303,7 @@ final class EthernetTracker { mNetworkCapabilities.put(name, nc); if (tokens.length > 2 && !TextUtils.isEmpty(tokens[2])) { - IpConfiguration ipConfig = createStaticIpConfiguration(tokens[2]); + IpConfiguration ipConfig = parseStaticIpConfiguration(tokens[2]); mIpConfigurations.put(name, ipConfig); } } @@ -341,11 +344,54 @@ final class EthernetTracker { 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); + /** + * Parses static IP configuration. + * + * @param staticIpConfig represents static IP configuration in the following format: {@code + * ip= gateway= dns= + * domains=} + */ + @VisibleForTesting + static IpConfiguration parseStaticIpConfiguration(String staticIpConfig) { + StaticIpConfiguration ipConfig = new StaticIpConfiguration(); + + 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": + ipConfig.ipAddress = new LinkAddress(value); + break; + case "domains": + ipConfig.domains = value; + break; + case "gateway": + ipConfig.gateway = InetAddress.parseNumericAddress(value); + break; + case "dns": { + ArrayList dnsAddresses = new ArrayList<>(); + for (String address: value.split(",")) { + dnsAddresses.add(InetAddress.parseNumericAddress(address)); + } + ipConfig.dnsServers.addAll(dnsAddresses); + break; + } + default : { + throw new IllegalArgumentException("Unexpected key: " + key + + " in " + staticIpConfig); + } + } + } + return new IpConfiguration(IpAssignment.STATIC, ProxySettings.NONE, ipConfig, null); } private static IpConfiguration createDefaultIpConfiguration() { diff --git a/tests/ethernet/Android.mk b/tests/ethernet/Android.mk new file mode 100644 index 0000000000..6b2c103474 --- /dev/null +++ b/tests/ethernet/Android.mk @@ -0,0 +1,36 @@ +# 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. +# + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-java-files-under, java) + +LOCAL_PACKAGE_NAME := EthernetServiceTests + +LOCAL_CERTIFICATE := platform +LOCAL_PRIVATE_PLATFORM_APIS := true + +LOCAL_MODULE_TAGS := tests + +LOCAL_JAVA_LIBRARIES := \ + android.test.runner \ + android.test.base + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android-support-test \ + ethernet-service + +include $(BUILD_PACKAGE) diff --git a/tests/ethernet/AndroidManifest.xml b/tests/ethernet/AndroidManifest.xml new file mode 100644 index 0000000000..1bc0775310 --- /dev/null +++ b/tests/ethernet/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java new file mode 100644 index 0000000000..70d316dbff --- /dev/null +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -0,0 +1,126 @@ +/* + * 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 org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import android.net.IpConfiguration; +import android.net.IpConfiguration.IpAssignment; +import android.net.IpConfiguration.ProxySettings; +import android.net.LinkAddress; +import android.net.StaticIpConfiguration; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class EthernetTrackerTest { + + @Test + public void createStaticIpConfiguration() { + assertStaticConfiguration("", new StaticIpConfiguration()); + + assertStaticConfiguration( + "ip=192.0.2.10/24", + new StaticIpConfigBuilder().setIp("192.0.2.10/24").build()); + + assertStaticConfiguration( + "ip=192.0.2.10/24 dns=4.4.4.4,8.8.8.8 gateway=192.0.2.1 domains=android", + new StaticIpConfigBuilder() + .setIp("192.0.2.10/24") + .setDns(new String[] {"4.4.4.4", "8.8.8.8"}) + .setGateway("192.0.2.1") + .setDomains("android") + .build()); + + // Verify order doesn't matter + assertStaticConfiguration( + "domains=android ip=192.0.2.10/24 gateway=192.0.2.1 dns=4.4.4.4,8.8.8.8 ", + new StaticIpConfigBuilder() + .setIp("192.0.2.10/24") + .setDns(new String[] {"4.4.4.4", "8.8.8.8"}) + .setGateway("192.0.2.1") + .setDomains("android") + .build()); + } + + @Test + public void createStaticIpConfiguration_Bad() { + assertFails("ip=192.0.2.1/24 gateway= blah=20.20.20.20"); // Unknown key + assertFails("ip=192.0.2.1"); // mask is missing + assertFails("ip=a.b.c"); // not a valid ip address + assertFails("dns=4.4.4.4,1.2.3.A"); // not valid ip address in dns + assertFails("="); // Key and value is empty + assertFails("ip="); // Value is empty + assertFails("ip=192.0.2.1/24 gateway="); // Gateway is empty + } + + private void assertFails(String config) { + try { + EthernetTracker.parseStaticIpConfiguration(config); + fail("Expected to fail: " + config); + } catch (IllegalArgumentException e) { + // expected + } + } + + private void assertStaticConfiguration(String configAsString, + StaticIpConfiguration expectedStaticIpConfig) { + IpConfiguration expectedIpConfiguration = new IpConfiguration(IpAssignment.STATIC, + ProxySettings.NONE, expectedStaticIpConfig, null); + + assertEquals(expectedIpConfiguration, + EthernetTracker.parseStaticIpConfiguration(configAsString)); + } + + private static class StaticIpConfigBuilder { + private final StaticIpConfiguration config = new StaticIpConfiguration(); + + StaticIpConfigBuilder setIp(String address) { + config.ipAddress = new LinkAddress(address); + return this; + } + + StaticIpConfigBuilder setDns(String[] dnsArray) { + for (String dns : dnsArray) { + config.dnsServers.add(InetAddress.parseNumericAddress(dns)); + } + return this; + } + + StaticIpConfigBuilder setGateway(String gateway) { + config.gateway = InetAddress.parseNumericAddress(gateway); + return this; + } + + StaticIpConfigBuilder setDomains(String domains) { + config.domains = domains; + return this; + } + + + StaticIpConfiguration build() { + return new StaticIpConfiguration(config); + } + } +} From 4da7fda56bd7786a32558fca68b80ef6584598dd Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 16 Aug 2018 21:47:56 -0700 Subject: [PATCH 043/152] Convert frameworks/opt/net/ethernet to Android.bp See build/soong/README.md for more information. Test: m checkbuild Test: atest EthernetServiceTests Change-Id: Ic9243ae7719a25a8749d63a5dcac7ec5adffe303 --- Android.mk | 32 -------------------------------- tests/ethernet/Android.bp | 33 +++++++++++++++++++++++++++++++++ tests/ethernet/Android.mk | 36 ------------------------------------ 3 files changed, 33 insertions(+), 68 deletions(-) delete mode 100644 Android.mk create mode 100644 tests/ethernet/Android.bp delete mode 100644 tests/ethernet/Android.mk diff --git a/Android.mk b/Android.mk deleted file mode 100644 index 952fa9d652..0000000000 --- a/Android.mk +++ /dev/null @@ -1,32 +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. - -LOCAL_PATH := $(call my-dir) - -# Build the java code -# ============================================================ - -include $(CLEAR_VARS) - -LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/java -LOCAL_SRC_FILES := $(call all-java-files-under, java) \ - $(call all-Iaidl-files-under, java) \ - $(call all-logtags-files-under, java) - -LOCAL_JAVA_LIBRARIES := services -LOCAL_MODULE := ethernet-service - -include $(BUILD_JAVA_LIBRARY) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/tests/ethernet/Android.bp b/tests/ethernet/Android.bp new file mode 100644 index 0000000000..8c5df21dae --- /dev/null +++ b/tests/ethernet/Android.bp @@ -0,0 +1,33 @@ +// 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. +// + +android_test { + name: "EthernetServiceTests", + + srcs: ["java/**/*.java"], + + certificate: "platform", + platform_apis: true, + + libs: [ + "android.test.runner", + "android.test.base", + ], + + static_libs: [ + "android-support-test", + "ethernet-service", + ], +} diff --git a/tests/ethernet/Android.mk b/tests/ethernet/Android.mk deleted file mode 100644 index 6b2c103474..0000000000 --- a/tests/ethernet/Android.mk +++ /dev/null @@ -1,36 +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. -# - -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := $(call all-java-files-under, java) - -LOCAL_PACKAGE_NAME := EthernetServiceTests - -LOCAL_CERTIFICATE := platform -LOCAL_PRIVATE_PLATFORM_APIS := true - -LOCAL_MODULE_TAGS := tests - -LOCAL_JAVA_LIBRARIES := \ - android.test.runner \ - android.test.base - -LOCAL_STATIC_JAVA_LIBRARIES := \ - android-support-test \ - ethernet-service - -include $(BUILD_PACKAGE) From 153ef5714645abcc749d602d6f4b777200d2ac2f Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 21 Aug 2018 18:18:41 +0900 Subject: [PATCH 044/152] Tiny tiny style fix Test: none needed Change-Id: Ic6cfedf9cfe60984ce7fbd59bdaec55b0bba3001 --- .../src/com/android/server/ethernet/EthernetNetworkFactory.java | 1 - 1 file changed, 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index de0a691c75..dc42d4b0f7 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -267,7 +267,6 @@ public class EthernetNetworkFactory extends NetworkFactory { } void setIpConfig(IpConfiguration ipConfig) { - this.mIpConfig = ipConfig; } From 33893d68d4a30ad79d8c31b3f1a41f58c234d3db Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 17 Aug 2018 13:21:25 +0900 Subject: [PATCH 045/152] Strategic fix for infinite loop Bug: 111326363 Test: Manual + atest frameworks-net Change-Id: Id262df4e41de5c74784637ae4a5459c3fab9fb74 --- .../android/server/ethernet/EthernetNetworkFactory.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index dc42d4b0f7..dc94482bfd 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -33,6 +33,7 @@ import android.net.NetworkSpecifier; import android.net.StringNetworkSpecifier; import android.net.ip.IpClient; import android.net.ip.IpClient.ProvisioningConfiguration; +import android.net.util.InterfaceParams; import android.os.Handler; import android.text.TextUtils; import android.util.Log; @@ -328,7 +329,11 @@ public class EthernetNetworkFactory extends NetworkFactory { // This cannot happen due to provisioning timeout, because our timeout is 0. It can only // happen if we're provisioned and we lose provisioning. stop(); - start(); + // If the interface has disappeared provisioning will fail over and over again, so + // there is no point in starting again + if (null != InterfaceParams.getByName(name)) { + start(); + } } void updateLinkProperties(LinkProperties linkProperties) { From b3aa6187062b47f7d1674a549d9615cfae2ede8e Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 17 Aug 2018 13:21:25 +0900 Subject: [PATCH 046/152] Strategic fix for infinite loop Bug: 111326363 Test: Manual + atest frameworks-net + atest frameworks/opt/net/ethernet/tests/java/com/android/server Change-Id: Id262df4e41de5c74784637ae4a5459c3fab9fb74 --- .../android/server/ethernet/EthernetNetworkFactory.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index de0a691c75..b35e3cf132 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -33,6 +33,7 @@ import android.net.NetworkSpecifier; import android.net.StringNetworkSpecifier; import android.net.ip.IpClient; import android.net.ip.IpClient.ProvisioningConfiguration; +import android.net.util.InterfaceParams; import android.os.Handler; import android.text.TextUtils; import android.util.Log; @@ -329,7 +330,11 @@ public class EthernetNetworkFactory extends NetworkFactory { // This cannot happen due to provisioning timeout, because our timeout is 0. It can only // happen if we're provisioned and we lose provisioning. stop(); - start(); + // If the interface has disappeared provisioning will fail over and over again, so + // there is no point in starting again + if (null != InterfaceParams.getByName(name)) { + start(); + } } void updateLinkProperties(LinkProperties linkProperties) { From 4f316a4420da21791285c28122cdcb816f43aff9 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 16 Oct 2018 17:36:40 +0900 Subject: [PATCH 047/152] Don't consider TRACK_DEFAULT requests in EthernetNetworkFactory. These should not affect network refcount and thus should not be passed to the network transport. Bug: 116034205 Test: successfully established a VPN when connected to USB ethernet Change-Id: I66517d86f35b8cfc1e211cb189127187d2744b60 --- .../com/android/server/ethernet/EthernetNetworkFactory.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index dc94482bfd..54bcdc3b35 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -72,6 +72,10 @@ public class EthernetNetworkFactory extends NetworkFactory { @Override public boolean acceptRequest(NetworkRequest request, int score) { + if (request.type == NetworkRequest.Type.TRACK_DEFAULT) { + return false; + } + if (DBG) { Log.d(TAG, "acceptRequest, request: " + request + ", score: " + score); } @@ -424,6 +428,7 @@ public class EthernetNetworkFactory extends NetworkFactory { @Override public String toString() { return getClass().getSimpleName() + "{ " + + "refCount: " + refCount + ", " + "iface: " + name + ", " + "up: " + mLinkUp + ", " + "hwAddress: " + mHwAddress + ", " From d3a5c0404c3e64e331f63fd3739feaf3f8c4a72d Mon Sep 17 00:00:00 2001 From: Sal Savage Date: Wed, 9 Jan 2019 15:46:08 -0800 Subject: [PATCH 048/152] Allow network transport type override Bug: b/112588045 Test: atest EthernetServiceTests --verbose Test: kitchensink with RPi devices connected by USB -> Ethernet adapters. Edit config.xml to try different tranport overrides manually. Use dumpsys ethernet to show final final network scores. Change-Id: I482e78a76d06c9c090aa6816db14bb346eb6528b --- .../ethernet/EthernetNetworkFactory.java | 119 +++++++++- .../server/ethernet/EthernetTracker.java | 76 +++++- .../server/ethernet/EthernetTrackerTest.java | 216 ++++++++++++++++-- 3 files changed, 377 insertions(+), 34 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 54bcdc3b35..1f4f7fac90 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -16,9 +16,11 @@ package com.android.server.ethernet; -import static android.net.ConnectivityManager.TYPE_ETHERNET; +import static com.android.internal.util.Preconditions.checkNotNull; +import android.annotation.NonNull; import android.content.Context; +import android.net.ConnectivityManager; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; @@ -37,10 +39,12 @@ import android.net.util.InterfaceParams; import android.os.Handler; import android.text.TextUtils; import android.util.Log; +import android.util.SparseArray; import com.android.internal.util.IndentingPrintWriter; import java.io.FileDescriptor; +import java.lang.Math; import java.util.concurrent.ConcurrentHashMap; /** @@ -239,6 +243,52 @@ public class EthernetNetworkFactory extends NetworkFactory { private NetworkAgent mNetworkAgent; private IpConfiguration mIpConfig; + /** + * An object to contain all transport type information, including base network score and + * the legacy transport type it maps to (if any) + */ + private static class TransportInfo { + final int mLegacyType; + final int mScore; + + private TransportInfo(int legacyType, int score) { + mLegacyType = legacyType; + mScore = score; + } + } + + /** + * A map of TRANSPORT_* types to TransportInfo, making scoring and legacy type information + * available for each type an ethernet interface could propagate. + * + * Unfortunately, base scores for the various transports are not yet centrally located. + * They've been lifted from the corresponding NetworkFactory files in the meantime. + * + * Additionally, 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 sTransports = new SparseArray(); + static { + // LowpanInterfaceTracker.NETWORK_SCORE + sTransports.put(NetworkCapabilities.TRANSPORT_LOWPAN, + new TransportInfo(ConnectivityManager.TYPE_NONE, 30)); + // WifiAwareDataPathStateManager.NETWORK_FACTORY_SCORE_AVAIL + sTransports.put(NetworkCapabilities.TRANSPORT_WIFI_AWARE, + new TransportInfo(ConnectivityManager.TYPE_NONE, 1)); + // EthernetNetworkFactory.NETWORK_SCORE + sTransports.put(NetworkCapabilities.TRANSPORT_ETHERNET, + new TransportInfo(ConnectivityManager.TYPE_ETHERNET, 70)); + // BluetoothTetheringNetworkFactory.NETWORK_SCORE + sTransports.put(NetworkCapabilities.TRANSPORT_BLUETOOTH, + new TransportInfo(ConnectivityManager.TYPE_BLUETOOTH, 69)); + // WifiNetworkFactory.SCORE_FILTER / NetworkAgent.WIFI_BASE_SCORE + sTransports.put(NetworkCapabilities.TRANSPORT_WIFI, + new TransportInfo(ConnectivityManager.TYPE_WIFI, 60)); + // TelephonyNetworkFactory.TELEPHONY_NETWORK_SCORE + sTransports.put(NetworkCapabilities.TRANSPORT_CELLULAR, + new TransportInfo(ConnectivityManager.TYPE_MOBILE, 50)); + } + long refCount = 0; private final IpClient.Callback mIpClientCallback = new IpClient.Callback() { @@ -259,14 +309,23 @@ public class EthernetNetworkFactory extends NetworkFactory { }; NetworkInterfaceState(String ifaceName, String hwAddress, Handler handler, Context context, - NetworkCapabilities capabilities) { + @NonNull NetworkCapabilities capabilities) { name = ifaceName; - mCapabilities = capabilities; + mCapabilities = checkNotNull(capabilities); mHandler = handler; mContext = context; + int legacyType = ConnectivityManager.TYPE_NONE; + int[] transportTypes = mCapabilities.getTransportTypes(); + if (transportTypes.length > 0) { + legacyType = getLegacyType(transportTypes[0]); + } else { + // Should never happen as transport is always one of ETHERNET or a valid override + Log.w(TAG, "There is no transport type associated with network interface '" + + mLinkProperties.getInterfaceName() + "' -- Legacy type set to TYPE_NONE"); + } mHwAddress = hwAddress; - mNetworkInfo = new NetworkInfo(TYPE_ETHERNET, 0, NETWORK_TYPE, ""); + mNetworkInfo = new NetworkInfo(legacyType, 0, NETWORK_TYPE, ""); mNetworkInfo.setExtraInfo(mHwAddress); mNetworkInfo.setIsAvailable(true); } @@ -283,6 +342,47 @@ public class EthernetNetworkFactory extends NetworkFactory { return mCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); } + /** + * 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) { + TransportInfo transportInfo = sTransports.get(transport, /* if dne */ null); + if (transportInfo != null) { + return transportInfo.mLegacyType; + } + return ConnectivityManager.TYPE_NONE; + } + + /** + * Determines the network score based on the transport associated with the interface. + * Ethernet interfaces could propagate a transport types forward. Since we can't + * get more information about the statuses of the interfaces on the other end of the local + * interface, we'll best-effort assign the score as the base score of the assigned transport + * when the link is up. When the link is down, the score is set to zero. + * + * This function is called with the purpose of assigning and updating the network score of + * the member NetworkAgent. + */ + private int getNetworkScore() { + // never set the network score below 0. + if (!mLinkUp) { + return 0; + } + + int[] transportTypes = mCapabilities.getTransportTypes(); + if (transportTypes.length < 1) { + Log.w(TAG, "There is no transport type associated with network interface '" + + mLinkProperties.getInterfaceName() + "' -- Score set to zero"); + return 0; + } + TransportInfo transportInfo = sTransports.get(transportTypes[0], /* if dne */ null); + if (transportInfo != null) { + return transportInfo.mScore; + } + return 0; + } + private void start() { if (mIpClient != null) { if (DBG) Log.d(TAG, "IpClient already started"); @@ -317,7 +417,7 @@ public class EthernetNetworkFactory extends NetworkFactory { // Create our NetworkAgent. mNetworkAgent = new NetworkAgent(mHandler.getLooper(), mContext, NETWORK_TYPE, mNetworkInfo, mCapabilities, mLinkProperties, - NETWORK_SCORE) { + getNetworkScore()) { public void unwanted() { if (this == mNetworkAgent) { stop(); @@ -390,8 +490,11 @@ public class EthernetNetworkFactory extends NetworkFactory { mNetworkAgent.sendNetworkCapabilities(mCapabilities); mNetworkAgent.sendNetworkInfo(mNetworkInfo); mNetworkAgent.sendLinkProperties(mLinkProperties); - // never set the network score below 0. - mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0); + + // As a note, getNetworkScore() is fairly expensive to calculate. This is fine for now + // since the agent isn't update frequently. Consider caching the score in the future if + // agent updating is required more often + mNetworkAgent.sendNetworkScore(getNetworkScore()); } private void clear() { @@ -433,7 +536,9 @@ public class EthernetNetworkFactory extends NetworkFactory { + "up: " + mLinkUp + ", " + "hwAddress: " + mHwAddress + ", " + "networkInfo: " + mNetworkInfo + ", " + + "networkCapabilities: " + mCapabilities + ", " + "networkAgent: " + mNetworkAgent + ", " + + "score: " + getNetworkScore() + ", " + "ipClient: " + mIpClient + "," + "linkProperties: " + mLinkProperties + "}"; diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 00eedd502d..099e05414c 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -294,12 +294,20 @@ final class EthernetTracker { } } + /** + * Parses an Ethernet interface configuration + * + * @param configString represents an Ethernet configuration in the following format: {@code + * ;[Network Capabilities];[IP config];[Override Transport]} + */ private void parseEthernetConfig(String configString) { - String[] tokens = configString.split(";"); + String[] tokens = configString.split(";", /* limit of tokens */ 4); String name = tokens[0]; String capabilities = tokens.length > 1 ? tokens[1] : null; + String transport = tokens.length > 3 ? tokens[3] : null; NetworkCapabilities nc = createNetworkCapabilities( - !TextUtils.isEmpty(capabilities) /* clear default capabilities */, capabilities); + !TextUtils.isEmpty(capabilities) /* clear default capabilities */, capabilities, + transport); mNetworkCapabilities.put(name, nc); if (tokens.length > 2 && !TextUtils.isEmpty(tokens[2])) { @@ -320,24 +328,76 @@ final class EthernetTracker { } private static NetworkCapabilities createNetworkCapabilities(boolean clearDefaultCapabilities) { - return createNetworkCapabilities(clearDefaultCapabilities, null); + return createNetworkCapabilities(clearDefaultCapabilities, null, null); } - private static NetworkCapabilities createNetworkCapabilities( - boolean clearDefaultCapabilities, @Nullable String commaSeparatedCapabilities) { + /** + * 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 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 createNetworkCapabilities( + boolean clearDefaultCapabilities, @Nullable String commaSeparatedCapabilities, + @Nullable String overrideTransport) { NetworkCapabilities nc = new NetworkCapabilities(); if (clearDefaultCapabilities) { - nc.clearAll(); // Remove default capabilities. + nc.clearAll(); // Remove default capabilities and transports } - nc.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET); + + // 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 { + nc.addTransportType(transport); + } catch (IllegalArgumentException iae) { + Log.e(TAG, transport + " is not a valid NetworkCapability.TRANSPORT_* value" + + " -- Defaulting to TRANSPORT_ETHERNET"); + 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)); + try { + nc.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"); + } } } } diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java index 70d316dbff..a56c9fe9fa 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -23,6 +23,7 @@ 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.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -35,47 +36,55 @@ import java.net.InetAddress; @SmallTest @RunWith(AndroidJUnit4.class) public class EthernetTrackerTest { - + /** + * Test: Creation of various valid static IP configurations + */ @Test public void createStaticIpConfiguration() { - assertStaticConfiguration("", new StaticIpConfiguration()); + // Empty gives default StaticIPConfiguration object + assertStaticConfiguration(new StaticIpConfiguration(), ""); + // Setting only the IP address properly cascades and assumes defaults assertStaticConfiguration( - "ip=192.0.2.10/24", - new StaticIpConfigBuilder().setIp("192.0.2.10/24").build()); + new StaticIpConfigBuilder().setIp("192.0.2.10/24").build(), + "ip=192.0.2.10/24"); + // Setting other fields properly cascades them assertStaticConfiguration( - "ip=192.0.2.10/24 dns=4.4.4.4,8.8.8.8 gateway=192.0.2.1 domains=android", new StaticIpConfigBuilder() .setIp("192.0.2.10/24") .setDns(new String[] {"4.4.4.4", "8.8.8.8"}) .setGateway("192.0.2.1") .setDomains("android") - .build()); + .build(), + "ip=192.0.2.10/24 dns=4.4.4.4,8.8.8.8 gateway=192.0.2.1 domains=android"); // Verify order doesn't matter assertStaticConfiguration( - "domains=android ip=192.0.2.10/24 gateway=192.0.2.1 dns=4.4.4.4,8.8.8.8 ", new StaticIpConfigBuilder() .setIp("192.0.2.10/24") .setDns(new String[] {"4.4.4.4", "8.8.8.8"}) .setGateway("192.0.2.1") .setDomains("android") - .build()); + .build(), + "domains=android ip=192.0.2.10/24 gateway=192.0.2.1 dns=4.4.4.4,8.8.8.8 "); } + /** + * Test: Attempt creation of various bad static IP configurations + */ @Test public void createStaticIpConfiguration_Bad() { - assertFails("ip=192.0.2.1/24 gateway= blah=20.20.20.20"); // Unknown key - assertFails("ip=192.0.2.1"); // mask is missing - assertFails("ip=a.b.c"); // not a valid ip address - assertFails("dns=4.4.4.4,1.2.3.A"); // not valid ip address in dns - assertFails("="); // Key and value is empty - assertFails("ip="); // Value is empty - assertFails("ip=192.0.2.1/24 gateway="); // Gateway is empty + assertStaticConfigurationFails("ip=192.0.2.1/24 gateway= blah=20.20.20.20"); // Unknown key + assertStaticConfigurationFails("ip=192.0.2.1"); // mask is missing + assertStaticConfigurationFails("ip=a.b.c"); // not a valid ip address + assertStaticConfigurationFails("dns=4.4.4.4,1.2.3.A"); // not valid ip address in dns + assertStaticConfigurationFails("="); // Key and value is empty + assertStaticConfigurationFails("ip="); // Value is empty + assertStaticConfigurationFails("ip=192.0.2.1/24 gateway="); // Gateway is empty } - private void assertFails(String config) { + private void assertStaticConfigurationFails(String config) { try { EthernetTracker.parseStaticIpConfiguration(config); fail("Expected to fail: " + config); @@ -84,8 +93,8 @@ public class EthernetTrackerTest { } } - private void assertStaticConfiguration(String configAsString, - StaticIpConfiguration expectedStaticIpConfig) { + private void assertStaticConfiguration(StaticIpConfiguration expectedStaticIpConfig, + String configAsString) { IpConfiguration expectedIpConfiguration = new IpConfiguration(IpAssignment.STATIC, ProxySettings.NONE, expectedStaticIpConfig, null); @@ -118,9 +127,178 @@ public class EthernetTrackerTest { return this; } - StaticIpConfiguration build() { return new StaticIpConfiguration(config); } } + + /** + * Test: Attempt to create a capabilties with various valid sets of capabilities/transports + */ + @Test + public void createNetworkCapabilities() { + + // Particularly common expected results + NetworkCapabilities defaultEthernetCleared = new NetworkCapabilitiesBuilder() + .clearAll() + .setLinkUpstreamBandwidthKbps(100000) + .setLinkDownstreamBandwidthKbps(100000) + .addTransport(NetworkCapabilities.TRANSPORT_ETHERNET) + .build(); + + NetworkCapabilities ethernetClearedWithCommonCaps = new NetworkCapabilitiesBuilder() + .clearAll() + .setLinkUpstreamBandwidthKbps(100000) + .setLinkDownstreamBandwidthKbps(100000) + .addTransport(NetworkCapabilities.TRANSPORT_ETHERNET) + .addCapability(12) + .addCapability(13) + .addCapability(14) + .addCapability(15) + .build(); + + // Empty capabilities and transports lists with a "please clear defaults" should + // yield an empty capabilities set with TRANPORT_ETHERNET + assertNetworkCapabilities(defaultEthernetCleared, true, "", ""); + + // Empty capabilities and transports without the clear defaults flag should return the + // default capabilities set with TRANSPORT_ETHERNET + assertNetworkCapabilities( + new NetworkCapabilitiesBuilder() + .setLinkUpstreamBandwidthKbps(100000) + .setLinkDownstreamBandwidthKbps(100000) + .addTransport(NetworkCapabilities.TRANSPORT_ETHERNET) + .build(), + false, "", ""); + + // A list of capabilities without the clear defaults flag should return the default + // capabilities, mixed with the desired capabilities, and TRANSPORT_ETHERNET + assertNetworkCapabilities( + new NetworkCapabilitiesBuilder() + .setLinkUpstreamBandwidthKbps(100000) + .setLinkDownstreamBandwidthKbps(100000) + .addTransport(NetworkCapabilities.TRANSPORT_ETHERNET) + .addCapability(11) + .addCapability(12) + .build(), + false, "11,12", ""); + + // Adding a list of capabilities with a clear defaults will leave exactly those capabilities + // with a default TRANSPORT_ETHERNET since no overrides are specified + assertNetworkCapabilities(ethernetClearedWithCommonCaps, true, "12,13,14,15", ""); + + // Adding any invalid capabilities to the list will cause them to be ignored + assertNetworkCapabilities(ethernetClearedWithCommonCaps, true, "12,13,14,15,65,73", ""); + assertNetworkCapabilities(ethernetClearedWithCommonCaps, true, "12,13,14,15,abcdefg", ""); + + // Adding a valid override transport will remove the default TRANSPORT_ETHERNET transport + // and apply only the override to the capabiltities object + assertNetworkCapabilities( + new NetworkCapabilitiesBuilder() + .clearAll() + .setLinkUpstreamBandwidthKbps(100000) + .setLinkDownstreamBandwidthKbps(100000) + .addTransport(0) + .build(), + true, "", "0"); + assertNetworkCapabilities( + new NetworkCapabilitiesBuilder() + .clearAll() + .setLinkUpstreamBandwidthKbps(100000) + .setLinkDownstreamBandwidthKbps(100000) + .addTransport(1) + .build(), + true, "", "1"); + assertNetworkCapabilities( + new NetworkCapabilitiesBuilder() + .clearAll() + .setLinkUpstreamBandwidthKbps(100000) + .setLinkDownstreamBandwidthKbps(100000) + .addTransport(2) + .build(), + true, "", "2"); + assertNetworkCapabilities( + new NetworkCapabilitiesBuilder() + .clearAll() + .setLinkUpstreamBandwidthKbps(100000) + .setLinkDownstreamBandwidthKbps(100000) + .addTransport(3) + .build(), + true, "", "3"); + + // "4" is TRANSPORT_VPN, which is unsupported. Should default back to TRANPORT_ETHERNET + assertNetworkCapabilities(defaultEthernetCleared, true, "", "4"); + + // "5" is TRANSPORT_WIFI_AWARE, which is currently supported due to no legacy TYPE_NONE + // conversion. When that becomes available, this test must be updated + assertNetworkCapabilities(defaultEthernetCleared, true, "", "5"); + + // "6" is TRANSPORT_LOWPAN, which is currently supported due to no legacy TYPE_NONE + // conversion. When that becomes available, this test must be updated + assertNetworkCapabilities(defaultEthernetCleared, true, "", "6"); + + // Adding an invalid override transport will leave the transport as TRANSPORT_ETHERNET + assertNetworkCapabilities(defaultEthernetCleared,true, "", "100"); + assertNetworkCapabilities(defaultEthernetCleared, true, "", "abcdefg"); + + // Ensure the adding of both capabilities and transports work + assertNetworkCapabilities( + new NetworkCapabilitiesBuilder() + .clearAll() + .setLinkUpstreamBandwidthKbps(100000) + .setLinkDownstreamBandwidthKbps(100000) + .addCapability(12) + .addCapability(13) + .addCapability(14) + .addCapability(15) + .addTransport(3) + .build(), + true, "12,13,14,15", "3"); + + // Ensure order does not matter for capability list + assertNetworkCapabilities(ethernetClearedWithCommonCaps, true, "13,12,15,14", ""); + } + + private void assertNetworkCapabilities(NetworkCapabilities expectedNetworkCapabilities, + boolean clearCapabilties, String configCapabiltiies,String configTransports) { + assertEquals(expectedNetworkCapabilities, + EthernetTracker.createNetworkCapabilities(clearCapabilties, configCapabiltiies, + configTransports)); + } + + private static class NetworkCapabilitiesBuilder { + private final NetworkCapabilities nc = new NetworkCapabilities(); + + NetworkCapabilitiesBuilder clearAll(){ + // This is THE ONLY one that doesn't return a reference to the object so I wrapped + // everything in a builder to keep things consistent and clean above. Fix if this + // ever changes + nc.clearAll(); + return this; + } + + NetworkCapabilitiesBuilder addCapability(int capability) { + nc.addCapability(capability); + return this; + } + + NetworkCapabilitiesBuilder addTransport(int transport) { + nc.addTransportType(transport); + return this; + } + + NetworkCapabilitiesBuilder setLinkUpstreamBandwidthKbps(int upKbps) { + nc.setLinkUpstreamBandwidthKbps(upKbps); + return this; + } + + NetworkCapabilitiesBuilder setLinkDownstreamBandwidthKbps(int downKbps) { + nc.setLinkDownstreamBandwidthKbps(downKbps); + return this; + } + + NetworkCapabilities build() { + return new NetworkCapabilities(nc); + } + } } From 5060d1d1be7e098376ebe98729484a67868a7241 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 4 Dec 2018 11:54:16 +0900 Subject: [PATCH 049/152] Migrate EthernetNetworkFactory to IIpClient Test: atest EthernetServiceTests Bug: b/112869080 Change-Id: I54f32d3031e63c7dea78936b6fe5e83e5b293c33 --- .../ethernet/EthernetNetworkFactory.java | 88 +++++++++++++++---- 1 file changed, 70 insertions(+), 18 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 1f4f7fac90..4a1d6587d9 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -16,6 +16,8 @@ package com.android.server.ethernet; +import static android.net.ConnectivityManager.TYPE_ETHERNET; +import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable; import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; @@ -33,10 +35,14 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.StringNetworkSpecifier; -import android.net.ip.IpClient; -import android.net.ip.IpClient.ProvisioningConfiguration; +import android.net.ip.IIpClient; +import android.net.ip.IpClientCallbacks; +import android.net.ip.IpClientUtil; +import android.net.shared.ProvisioningConfiguration; import android.net.util.InterfaceParams; +import android.os.ConditionVariable; import android.os.Handler; +import android.os.RemoteException; import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; @@ -239,7 +245,8 @@ public class EthernetNetworkFactory extends NetworkFactory { private boolean mLinkUp; private LinkProperties mLinkProperties = new LinkProperties(); - private IpClient mIpClient; + private volatile IIpClient mIpClient; + private IpClientCallbacksImpl mIpClientCallback; private NetworkAgent mNetworkAgent; private IpConfiguration mIpConfig; @@ -291,7 +298,24 @@ public class EthernetNetworkFactory extends NetworkFactory { long refCount = 0; - private final IpClient.Callback mIpClientCallback = new IpClient.Callback() { + private class IpClientCallbacksImpl extends IpClientCallbacks { + private final ConditionVariable mIpClientStartCv = new ConditionVariable(false); + private final ConditionVariable mIpClientShutdownCv = new ConditionVariable(false); + + @Override + public void onIpClientCreated(IIpClient ipClient) { + mIpClient = ipClient; + mIpClientStartCv.open(); + } + + private void awaitIpClientStart() { + mIpClientStartCv.block(); + } + + private void awaitIpClientShutdown() { + mIpClientShutdownCv.block(); + } + @Override public void onProvisioningSuccess(LinkProperties newLp) { mHandler.post(() -> onIpLayerStarted(newLp)); @@ -306,7 +330,21 @@ public class EthernetNetworkFactory extends NetworkFactory { public void onLinkPropertiesChange(LinkProperties newLp) { mHandler.post(() -> updateLinkProperties(newLp)); } - }; + + @Override + public void onQuit() { + mIpClient = null; + mIpClientShutdownCv.open(); + } + } + + private static void shutdownIpClient(IIpClient ipClient) { + try { + ipClient.shutdown(); + } catch (RemoteException e) { + Log.e(TAG, "Error stopping IpClient", e); + } + } NetworkInterfaceState(String ifaceName, String hwAddress, Handler handler, Context context, @NonNull NetworkCapabilities capabilities) { @@ -394,9 +432,9 @@ public class EthernetNetworkFactory extends NetworkFactory { } mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddress); - - mIpClient = new IpClient(mContext, name, mIpClientCallback); - + mIpClientCallback = new IpClientCallbacksImpl(); + IpClientUtil.makeIpClient(mContext, name, mIpClientCallback); + mIpClientCallback.awaitIpClientStart(); if (sTcpBufferSizes == null) { sTcpBufferSizes = mContext.getResources().getString( com.android.internal.R.string.config_ethernet_tcp_buffers); @@ -461,11 +499,13 @@ public class EthernetNetworkFactory extends NetworkFactory { } void stop() { + // Invalidate all previous start requests if (mIpClient != null) { - mIpClient.shutdown(); - mIpClient.awaitShutdown(); + shutdownIpClient(mIpClient); + mIpClientCallback.awaitIpClientShutdown(); mIpClient = null; } + mIpClientCallback = 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: @@ -503,29 +543,41 @@ public class EthernetNetworkFactory extends NetworkFactory { mNetworkInfo.setIsAvailable(false); } - private static void provisionIpClient(IpClient ipClient, IpConfiguration config, + private static void provisionIpClient(IIpClient ipClient, IpConfiguration config, String tcpBufferSizes) { if (config.getProxySettings() == ProxySettings.STATIC || config.getProxySettings() == ProxySettings.PAC) { - ipClient.setHttpProxy(config.getHttpProxy()); + try { + ipClient.setHttpProxy(toStableParcelable(config.getHttpProxy())); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } } if (!TextUtils.isEmpty(tcpBufferSizes)) { - ipClient.setTcpBufferSizes(tcpBufferSizes); + try { + ipClient.setTcpBufferSizes(tcpBufferSizes); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } } final ProvisioningConfiguration provisioningConfiguration; if (config.getIpAssignment() == IpAssignment.STATIC) { - provisioningConfiguration = IpClient.buildProvisioningConfiguration() + provisioningConfiguration = new ProvisioningConfiguration.Builder() .withStaticConfiguration(config.getStaticIpConfiguration()) .build(); } else { - provisioningConfiguration = IpClient.buildProvisioningConfiguration() + provisioningConfiguration = new ProvisioningConfiguration.Builder() .withProvisioningTimeoutMs(0) .build(); } - ipClient.startProvisioning(provisioningConfiguration); + try { + ipClient.startProvisioning(provisioningConfiguration.toStableParcelable()); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } } @Override @@ -554,9 +606,9 @@ public class EthernetNetworkFactory extends NetworkFactory { NetworkInterfaceState ifaceState = mTrackingInterfaces.get(iface); pw.println(iface + ":" + ifaceState); pw.increaseIndent(); - final IpClient ipClient = ifaceState.mIpClient; + final IIpClient ipClient = ifaceState.mIpClient; if (ipClient != null) { - ipClient.dump(fd, pw, args); + IpClientUtil.dumpIpClient(ipClient, fd, pw, args); } else { pw.println("IpClient is null"); } From e9eff7a4501ea535145aedf340201d2d841532b1 Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Tue, 5 Mar 2019 09:10:36 -0800 Subject: [PATCH 050/152] Migrate frameworks/opt/net/ethernet to androidx.test See go/jetpack-test-android-migration Test: compile Change-Id: I20fc49dd2487af2245f060454e7f32f5e9145a9c --- tests/ethernet/Android.bp | 2 +- tests/ethernet/AndroidManifest.xml | 2 +- .../com/android/server/ethernet/EthernetTrackerTest.java | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/ethernet/Android.bp b/tests/ethernet/Android.bp index 8c5df21dae..9c776e604f 100644 --- a/tests/ethernet/Android.bp +++ b/tests/ethernet/Android.bp @@ -27,7 +27,7 @@ android_test { ], static_libs: [ - "android-support-test", + "androidx.test.rules", "ethernet-service", ], } diff --git a/tests/ethernet/AndroidManifest.xml b/tests/ethernet/AndroidManifest.xml index 1bc0775310..302bb6c9a1 100644 --- a/tests/ethernet/AndroidManifest.xml +++ b/tests/ethernet/AndroidManifest.xml @@ -22,7 +22,7 @@ - diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java index a56c9fe9fa..fa945d6659 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -25,8 +25,9 @@ import android.net.IpConfiguration.ProxySettings; import android.net.LinkAddress; import android.net.NetworkCapabilities; import android.net.StaticIpConfiguration; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; From ea26baf9ffdd10f9c6577e8ba134575afeab5727 Mon Sep 17 00:00:00 2001 From: Sal Savage Date: Wed, 23 Jan 2019 14:25:59 -0800 Subject: [PATCH 051/152] Update comments and documentation in net type prop change Bug: b/112588045 Test: atest EthernetServiceTests --verbose Test: kitchensink, dumpsys ethernet, with RPi devices and USB to ethernet adapters. Change-Id: Iaa260aabbbd7aa4b7864eba32ecff7e3f84123c3 --- .../ethernet/EthernetNetworkFactory.java | 17 ++++++--- .../server/ethernet/EthernetTracker.java | 18 +++++----- .../server/ethernet/EthernetTrackerTest.java | 36 +++++++++---------- 3 files changed, 39 insertions(+), 32 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 4a1d6587d9..b8ed845c2c 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -44,6 +44,7 @@ import android.os.ConditionVariable; import android.os.Handler; import android.os.RemoteException; import android.text.TextUtils; +import android.util.AndroidRuntimeException; import android.util.Log; import android.util.SparseArray; @@ -71,6 +72,12 @@ public class EthernetNetworkFactory extends NetworkFactory { private final Handler mHandler; private final Context mContext; + public static class ConfigurationException extends AndroidRuntimeException { + public ConfigurationException(String msg) { + super(msg); + } + } + public EthernetNetworkFactory(Handler handler, Context context, NetworkCapabilities filter) { super(handler.getLooper(), context, NETWORK_TYPE, filter); @@ -358,8 +365,8 @@ public class EthernetNetworkFactory extends NetworkFactory { legacyType = getLegacyType(transportTypes[0]); } else { // Should never happen as transport is always one of ETHERNET or a valid override - Log.w(TAG, "There is no transport type associated with network interface '" - + mLinkProperties.getInterfaceName() + "' -- Legacy type set to TYPE_NONE"); + throw new ConfigurationException("Network Capabilities do not have an associated " + + "transport type."); } mHwAddress = hwAddress; @@ -410,8 +417,8 @@ public class EthernetNetworkFactory extends NetworkFactory { int[] transportTypes = mCapabilities.getTransportTypes(); if (transportTypes.length < 1) { - Log.w(TAG, "There is no transport type associated with network interface '" - + mLinkProperties.getInterfaceName() + "' -- Score set to zero"); + Log.w(TAG, "Network interface '" + mLinkProperties.getInterfaceName() + "' has no " + + "transport type associated with it. Score set to zero"); return 0; } TransportInfo transportInfo = sTransports.get(transportTypes[0], /* if dne */ null); @@ -532,7 +539,7 @@ public class EthernetNetworkFactory extends NetworkFactory { mNetworkAgent.sendLinkProperties(mLinkProperties); // As a note, getNetworkScore() is fairly expensive to calculate. This is fine for now - // since the agent isn't update frequently. Consider caching the score in the future if + // since the agent isn't updated frequently. Consider caching the score in the future if // agent updating is required more often mNetworkAgent.sendNetworkScore(getNetworkScore()); } diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 099e05414c..4ab1dff881 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -337,10 +337,10 @@ final class EthernetTracker { * @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 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. + * @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 createNetworkCapabilities( @@ -363,14 +363,14 @@ final class EthernetTracker { if (parsedTransport == NetworkCapabilities.TRANSPORT_VPN || parsedTransport == NetworkCapabilities.TRANSPORT_WIFI_AWARE || parsedTransport == NetworkCapabilities.TRANSPORT_LOWPAN) { - Log.e(TAG, "Override transport '" + parsedTransport + "' is not supported -- " + 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"); + Log.e(TAG, "Override transport type '" + overrideTransport + "' " + + "could not be parsed. Defaulting to TRANSPORT_ETHERNET"); } } @@ -379,8 +379,8 @@ final class EthernetTracker { try { nc.addTransportType(transport); } catch (IllegalArgumentException iae) { - Log.e(TAG, transport + " is not a valid NetworkCapability.TRANSPORT_* value" - + " -- Defaulting to TRANSPORT_ETHERNET"); + Log.e(TAG, transport + " is not a valid NetworkCapability.TRANSPORT_* value. " + + "Defaulting to TRANSPORT_ETHERNET"); nc.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET); } diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java index fa945d6659..67740b666a 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -160,11 +160,11 @@ public class EthernetTrackerTest { // Empty capabilities and transports lists with a "please clear defaults" should // yield an empty capabilities set with TRANPORT_ETHERNET - assertNetworkCapabilities(defaultEthernetCleared, true, "", ""); + assertParsedNetworkCapabilities(defaultEthernetCleared, true, "", ""); // Empty capabilities and transports without the clear defaults flag should return the // default capabilities set with TRANSPORT_ETHERNET - assertNetworkCapabilities( + assertParsedNetworkCapabilities( new NetworkCapabilitiesBuilder() .setLinkUpstreamBandwidthKbps(100000) .setLinkDownstreamBandwidthKbps(100000) @@ -174,7 +174,7 @@ public class EthernetTrackerTest { // A list of capabilities without the clear defaults flag should return the default // capabilities, mixed with the desired capabilities, and TRANSPORT_ETHERNET - assertNetworkCapabilities( + assertParsedNetworkCapabilities( new NetworkCapabilitiesBuilder() .setLinkUpstreamBandwidthKbps(100000) .setLinkDownstreamBandwidthKbps(100000) @@ -186,15 +186,15 @@ public class EthernetTrackerTest { // Adding a list of capabilities with a clear defaults will leave exactly those capabilities // with a default TRANSPORT_ETHERNET since no overrides are specified - assertNetworkCapabilities(ethernetClearedWithCommonCaps, true, "12,13,14,15", ""); + assertParsedNetworkCapabilities(ethernetClearedWithCommonCaps, true, "12,13,14,15", ""); // Adding any invalid capabilities to the list will cause them to be ignored - assertNetworkCapabilities(ethernetClearedWithCommonCaps, true, "12,13,14,15,65,73", ""); - assertNetworkCapabilities(ethernetClearedWithCommonCaps, true, "12,13,14,15,abcdefg", ""); + assertParsedNetworkCapabilities(ethernetClearedWithCommonCaps, true, "12,13,14,15,65,73", ""); + assertParsedNetworkCapabilities(ethernetClearedWithCommonCaps, true, "12,13,14,15,abcdefg", ""); // Adding a valid override transport will remove the default TRANSPORT_ETHERNET transport // and apply only the override to the capabiltities object - assertNetworkCapabilities( + assertParsedNetworkCapabilities( new NetworkCapabilitiesBuilder() .clearAll() .setLinkUpstreamBandwidthKbps(100000) @@ -202,7 +202,7 @@ public class EthernetTrackerTest { .addTransport(0) .build(), true, "", "0"); - assertNetworkCapabilities( + assertParsedNetworkCapabilities( new NetworkCapabilitiesBuilder() .clearAll() .setLinkUpstreamBandwidthKbps(100000) @@ -210,7 +210,7 @@ public class EthernetTrackerTest { .addTransport(1) .build(), true, "", "1"); - assertNetworkCapabilities( + assertParsedNetworkCapabilities( new NetworkCapabilitiesBuilder() .clearAll() .setLinkUpstreamBandwidthKbps(100000) @@ -218,7 +218,7 @@ public class EthernetTrackerTest { .addTransport(2) .build(), true, "", "2"); - assertNetworkCapabilities( + assertParsedNetworkCapabilities( new NetworkCapabilitiesBuilder() .clearAll() .setLinkUpstreamBandwidthKbps(100000) @@ -228,22 +228,22 @@ public class EthernetTrackerTest { true, "", "3"); // "4" is TRANSPORT_VPN, which is unsupported. Should default back to TRANPORT_ETHERNET - assertNetworkCapabilities(defaultEthernetCleared, true, "", "4"); + assertParsedNetworkCapabilities(defaultEthernetCleared, true, "", "4"); // "5" is TRANSPORT_WIFI_AWARE, which is currently supported due to no legacy TYPE_NONE // conversion. When that becomes available, this test must be updated - assertNetworkCapabilities(defaultEthernetCleared, true, "", "5"); + assertParsedNetworkCapabilities(defaultEthernetCleared, true, "", "5"); // "6" is TRANSPORT_LOWPAN, which is currently supported due to no legacy TYPE_NONE // conversion. When that becomes available, this test must be updated - assertNetworkCapabilities(defaultEthernetCleared, true, "", "6"); + assertParsedNetworkCapabilities(defaultEthernetCleared, true, "", "6"); // Adding an invalid override transport will leave the transport as TRANSPORT_ETHERNET - assertNetworkCapabilities(defaultEthernetCleared,true, "", "100"); - assertNetworkCapabilities(defaultEthernetCleared, true, "", "abcdefg"); + assertParsedNetworkCapabilities(defaultEthernetCleared,true, "", "100"); + assertParsedNetworkCapabilities(defaultEthernetCleared, true, "", "abcdefg"); // Ensure the adding of both capabilities and transports work - assertNetworkCapabilities( + assertParsedNetworkCapabilities( new NetworkCapabilitiesBuilder() .clearAll() .setLinkUpstreamBandwidthKbps(100000) @@ -257,10 +257,10 @@ public class EthernetTrackerTest { true, "12,13,14,15", "3"); // Ensure order does not matter for capability list - assertNetworkCapabilities(ethernetClearedWithCommonCaps, true, "13,12,15,14", ""); + assertParsedNetworkCapabilities(ethernetClearedWithCommonCaps, true, "13,12,15,14", ""); } - private void assertNetworkCapabilities(NetworkCapabilities expectedNetworkCapabilities, + private void assertParsedNetworkCapabilities(NetworkCapabilities expectedNetworkCapabilities, boolean clearCapabilties, String configCapabiltiies,String configTransports) { assertEquals(expectedNetworkCapabilities, EthernetTracker.createNetworkCapabilities(clearCapabilties, configCapabiltiies, From f8a95e543f8def8b3a75cc7f59f9fde316beb399 Mon Sep 17 00:00:00 2001 From: "tank.hung" Date: Thu, 4 Apr 2019 22:37:49 +0800 Subject: [PATCH 052/152] Add reconnect flow when updateIPConfiguration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 119085164 Test: manual, test with AndroidTV device Partner gerrit review CL: https://partner-android-review.googlesource.com/c/platform/frameworks/opt/net/ethernet/+/1215654 [Analysis] APP called EthernetManager.setConfiguration API for switch DHCP to Static, setConfiguration’s flow just only update IpConfig finally but have not trigger EthernetNetworkFactory.start(). So Static IP Setting just only take effect when unplug/plug Ethernet Cable or AC Off&On. [Repeat Steps] 1. Connect Ethernet with DHCP and Network access is normal 2. Change IP settings from DHCP to Static and set Static IP. 3. After setting, you can not automatically obtain Static IP. [Recovery Method] Unplug the Ethernet and insert it or AC OFF / ON Change-Id: Idbb6a24ccfa360582f48e4f9369def7fc729fb9f Bug: 112171349 --- .../server/ethernet/EthernetNetworkFactory.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index b8ed845c2c..6ed1310d2e 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -376,7 +376,14 @@ public class EthernetNetworkFactory extends NetworkFactory { } void setIpConfig(IpConfiguration ipConfig) { + if (this.mIpConfig.equals(ipConfig)) { + if (DBG) Log.d(TAG, "ipConfig have not changed,so ignore setIpConfig"); + return; + } this.mIpConfig = ipConfig; + if (mNetworkInfo.getDetailedState() != DetailedState.DISCONNECTED) { + restart(); + } } boolean statisified(NetworkCapabilities requestedCapabilities) { @@ -587,6 +594,12 @@ public class EthernetNetworkFactory extends NetworkFactory { } } + void restart(){ + if (DBG) Log.d(TAG, "reconnecting Etherent"); + stop(); + start(); + } + @Override public String toString() { return getClass().getSimpleName() + "{ " From b95be5972e51ed4186c41af1c885a74134583561 Mon Sep 17 00:00:00 2001 From: Wally Yau Date: Wed, 22 May 2019 09:22:06 -0700 Subject: [PATCH 053/152] Fixed fatal exception in EthernetServiceThread When this.mIpConfig is not initialized, it will cause a java.lang.NullPointerException and put the device in a boot loop with the following error: FATAL EXCEPTION IN SYSTEM PROCESS: EthernetServiceThread Test: passed pre-submit boot test. Change-Id: I47df68071b4c07a4136c0abcbe69ee7ada7090e0 --- .../server/ethernet/EthernetNetworkFactory.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 6ed1310d2e..e3f114ed21 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -21,6 +21,7 @@ import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.net.ConnectivityManager; import android.net.IpConfiguration; @@ -53,6 +54,7 @@ import com.android.internal.util.IndentingPrintWriter; import java.io.FileDescriptor; import java.lang.Math; import java.util.concurrent.ConcurrentHashMap; +import java.util.Objects; /** * {@link NetworkFactory} that represents Ethernet networks. @@ -252,10 +254,10 @@ public class EthernetNetworkFactory extends NetworkFactory { private boolean mLinkUp; private LinkProperties mLinkProperties = new LinkProperties(); - private volatile IIpClient mIpClient; - private IpClientCallbacksImpl mIpClientCallback; - private NetworkAgent mNetworkAgent; - private IpConfiguration mIpConfig; + private volatile @Nullable IIpClient mIpClient; + private @Nullable IpClientCallbacksImpl mIpClientCallback; + private @Nullable NetworkAgent mNetworkAgent; + private @Nullable IpConfiguration mIpConfig; /** * An object to contain all transport type information, including base network score and @@ -376,7 +378,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } void setIpConfig(IpConfiguration ipConfig) { - if (this.mIpConfig.equals(ipConfig)) { + if (Objects.equals(this.mIpConfig, ipConfig)) { if (DBG) Log.d(TAG, "ipConfig have not changed,so ignore setIpConfig"); return; } From 6957e3a35ae1472956bd9d6ee27cdc2ad154dc91 Mon Sep 17 00:00:00 2001 From: paulhu Date: Thu, 22 Aug 2019 16:03:59 +0800 Subject: [PATCH 054/152] [Ethernet] Replace internal connectivity checks permission A number of connectivity checks that protect system-only methods check for CONNECTIVITY_INTERNAL, but CONNECTIVITY_INTERNAL is a signature|privileged permission. We should audit the permissions checks, and convert checks that protect code that should not be called outside the system to a signature permission. So replace the permission to NETWORK_STACK. Bug: 32963470 Test: atest EthernetServiceTests Change-Id: I2a88d04bbdcd7e7e624b9065372a6603d2bb45a2 --- .../com/android/server/ethernet/EthernetServiceImpl.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index d5beec1cb4..fda3c3c2f9 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -21,6 +21,7 @@ import android.content.pm.PackageManager; import android.net.IEthernetManager; import android.net.IEthernetServiceListener; import android.net.IpConfiguration; +import android.net.NetworkStack; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; @@ -57,12 +58,6 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { "EthernetService"); } - private void enforceConnectivityInternalPermission() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.CONNECTIVITY_INTERNAL, - "ConnectivityService"); - } - private void enforceUseRestrictedNetworksPermission() { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS, @@ -117,7 +112,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { Log.w(TAG, "System isn't ready enough to change ethernet configuration"); } - enforceConnectivityInternalPermission(); + NetworkStack.checkNetworkStackPermission(mContext); if (mTracker.isRestrictedInterface(iface)) { enforceUseRestrictedNetworksPermission(); From 91456a8c7abed3fb5cc9dba438a361019f4782c5 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 2 May 2018 21:36:12 +0900 Subject: [PATCH 055/152] Update Ethernet code for the NetworkFactory serial number. See aosp/708790 Bug: 18637384 Bug: 29030667 Test: manual cts runtest framework-net atest frameworks/opt/net/ethernet/tests Change-Id: I5caa4cb89ca1441f3c84b5675ceede6ecacfd132 --- .../android/server/ethernet/EthernetNetworkFactory.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index e3f114ed21..3cda13f330 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -157,7 +157,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } NetworkInterfaceState iface = new NetworkInterfaceState( - ifaceName, hwAddress, mHandler, mContext, capabilities); + ifaceName, hwAddress, mHandler, mContext, capabilities, this); iface.setIpConfig(ipConfiguration); mTrackingInterfaces.put(ifaceName, iface); @@ -248,6 +248,7 @@ public class EthernetNetworkFactory extends NetworkFactory { private final Handler mHandler; private final Context mContext; private final NetworkInfo mNetworkInfo; + private final NetworkFactory mNetworkFactory; private static String sTcpBufferSizes = null; // Lazy initialized. @@ -356,13 +357,15 @@ public class EthernetNetworkFactory extends NetworkFactory { } NetworkInterfaceState(String ifaceName, String hwAddress, Handler handler, Context context, - @NonNull NetworkCapabilities capabilities) { + @NonNull NetworkCapabilities capabilities, NetworkFactory networkFactory) { name = ifaceName; mCapabilities = checkNotNull(capabilities); mHandler = handler; mContext = context; + mNetworkFactory = networkFactory; int legacyType = ConnectivityManager.TYPE_NONE; int[] transportTypes = mCapabilities.getTransportTypes(); + if (transportTypes.length > 0) { legacyType = getLegacyType(transportTypes[0]); } else { @@ -471,7 +474,7 @@ public class EthernetNetworkFactory extends NetworkFactory { // Create our NetworkAgent. mNetworkAgent = new NetworkAgent(mHandler.getLooper(), mContext, NETWORK_TYPE, mNetworkInfo, mCapabilities, mLinkProperties, - getNetworkScore()) { + getNetworkScore(), mNetworkFactory.getSerialNumber()) { public void unwanted() { if (this == mNetworkAgent) { stop(); From 13d5b866144b4c35a53f712d0b39c4cb7904b015 Mon Sep 17 00:00:00 2001 From: kevinwk_lee Date: Fri, 18 Oct 2019 11:25:29 +0800 Subject: [PATCH 056/152] Avoid creating IpClient if ethernet cable is unplugged. This change avoids calling start() on needNetworkFor() if ethernet cable is unplugged. Fixed by adding isLinkUp validation. Test: ./cts-tradefed run cts-dev -d -m CtsSecurityTestCases -t \ android.security.cts.ListeningPortsTest#testNoRemotelyAccessibleListeningUdpPorts adb shell netstat -lnup Change-Id: I2debd7367a20b665249f9c19d2d8a61737435803 --- .../src/com/android/server/ethernet/EthernetNetworkFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 3cda13f330..090dd13f4f 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -226,7 +226,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } } else { for (NetworkInterfaceState n : mTrackingInterfaces.values()) { - if (n.statisified(request.networkCapabilities)) { + if (n.statisified(request.networkCapabilities) && n.mLinkUp) { network = n; break; } From b92d1f55133b0ffe49df89e7aab67b8db7036fa5 Mon Sep 17 00:00:00 2001 From: Junaid Babu Date: Tue, 17 Dec 2019 13:56:26 +0900 Subject: [PATCH 057/152] Fix refCount check at releaseNetworkFor When releaseNetworkFor is called, refCount should be equal to 1 for network.stop() to be called. This is the same logic that is followed by WifiNetworkFactory also. In the current code, when refCount is 2 and releaseNetworkFor() is called, network.stop() will be executed and will stop Ethernet Bug: 146089778 Test: build and boot OK Change-Id: Ib7d1b488a2943364a8ba4a89eec5de4c33cf1d5a --- .../com/android/server/ethernet/EthernetNetworkFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 3cda13f330..11c991d408 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -120,11 +120,11 @@ public class EthernetNetworkFactory extends NetworkFactory { protected void releaseNetworkFor(NetworkRequest networkRequest) { NetworkInterfaceState network = networkForRequest(networkRequest); if (network == null) { - Log.e(TAG, "needNetworkFor, failed to get a network for " + networkRequest); + Log.e(TAG, "releaseNetworkFor, failed to get a network for " + networkRequest); return; } - if (--network.refCount == 1) { + if (--network.refCount == 0) { network.stop(); } } From c750566a779e424195d13a7ec447c55986288be3 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 24 Jan 2020 17:57:27 +0900 Subject: [PATCH 058/152] Support one Ethernet interface in server mode. Currently, Ethernet only supports interfaces in client mode (e.g., to connect to the Internet). Add minimal support to Ethernet to support interfaces in server mode. This simple implementation only works on the default interface, which is the first interface that is detected on boot (even if the interface is later removed). This also provides (but does not yet unhide) a simple API for Tethering to request that the next-plugged-in interface to be placed into server mode. Test: Enabling tethering with change on top Bug: 130840861 Change-Id: I78f85bc36aaceb62ce274003a75ea99d0b6bc8b7 --- .../server/ethernet/EthernetServiceImpl.java | 14 ++ .../server/ethernet/EthernetTracker.java | 131 ++++++++++++++++-- 2 files changed, 137 insertions(+), 8 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index fda3c3c2f9..1cf38b45f4 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -20,12 +20,14 @@ import android.content.Context; import android.content.pm.PackageManager; import android.net.IEthernetManager; import android.net.IEthernetServiceListener; +import android.net.ITetheredInterfaceCallback; import android.net.IpConfiguration; import android.net.NetworkStack; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; import android.os.RemoteException; +import android.provider.Settings; import android.util.Log; import android.util.PrintWriterPrinter; @@ -161,6 +163,18 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { mTracker.removeListener(listener); } + @Override + public void requestTetheredInterface(ITetheredInterfaceCallback callback) { + NetworkStack.checkNetworkStackPermission(mContext); + mTracker.requestTetheredInterface(callback); + } + + @Override + public void releaseTetheredInterface(ITetheredInterfaceCallback callback) { + NetworkStack.checkNetworkStackPermission(mContext); + mTracker.releaseTetheredInterface(callback); + } + @Override protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 4ab1dff881..24616b78dc 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -19,6 +19,7 @@ package com.android.server.ethernet; import android.annotation.Nullable; import android.content.Context; import android.net.IEthernetServiceListener; +import android.net.ITetheredInterfaceCallback; import android.net.InterfaceConfiguration; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; @@ -61,6 +62,9 @@ import java.util.concurrent.ConcurrentHashMap; *

All public or package private methods must be thread-safe unless stated otherwise. */ final class EthernetTracker { + private static final int INTERFACE_MODE_CLIENT = 1; + private static final int INTERFACE_MODE_SERVER = 2; + private final static String TAG = EthernetTracker.class.getSimpleName(); private final static boolean DBG = EthernetNetworkFactory.DBG; @@ -73,6 +77,7 @@ final class EthernetTracker { private final ConcurrentHashMap mIpConfigurations = new ConcurrentHashMap<>(); + private final Context mContext; private final INetworkManagementService mNMService; private final Handler mHandler; private final EthernetNetworkFactory mFactory; @@ -80,10 +85,25 @@ final class EthernetTracker { private final RemoteCallbackList mListeners = new RemoteCallbackList<>(); + private final TetheredInterfaceRequestList mTetheredInterfaceRequests = + new TetheredInterfaceRequestList(); + // Used only on the handler thread + private String mDefaultInterface; + private int mDefaultInterfaceMode; + // Tracks whether clients were notified that the tethered interface is available + private boolean mTetheredInterfaceWasAvailable = false; private volatile IpConfiguration mIpConfigForDefaultInterface; + private class TetheredInterfaceRequestList extends RemoteCallbackList { + @Override + public void onCallbackDied(ITetheredInterfaceCallback cb, Object cookie) { + mHandler.post(EthernetTracker.this::maybeUntetherDefaultInterface); + } + } + EthernetTracker(Context context, Handler handler) { + mContext = context; mHandler = handler; // The services we use. @@ -167,6 +187,68 @@ final class EthernetTracker { mListeners.unregister(listener); } + 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; + // mDefaultInterface null means that there never was a default interface (it is never set + // to null). + if (mDefaultInterfaceMode == INTERFACE_MODE_CLIENT || mDefaultInterface == null) return; + + setDefaultInterfaceMode(INTERFACE_MODE_CLIENT); + } + + private void setDefaultInterfaceMode(int mode) { + mDefaultInterfaceMode = mode; + removeInterface(mDefaultInterface); + addInterface(mDefaultInterface); + } + + private int getInterfaceMode(final String iface) { + if (iface.equals(mDefaultInterface)) { + return mDefaultInterfaceMode; + } + return INTERFACE_MODE_CLIENT; + } + private void removeInterface(String iface) { mFactory.removeInterface(iface); } @@ -198,13 +280,17 @@ final class EthernetTracker { 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); + final int mode = getInterfaceMode(iface); + if (mode == INTERFACE_MODE_CLIENT) { + 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 @@ -215,8 +301,11 @@ final class EthernetTracker { } private void updateInterfaceState(String iface, boolean up) { - boolean modified = mFactory.updateInterfaceLinkState(iface, up); - if (modified) { + final int mode = getInterfaceMode(iface); + final boolean factoryLinkStateUpdated = (mode == INTERFACE_MODE_CLIENT) + && mFactory.updateInterfaceLinkState(iface, up); + + if (factoryLinkStateUpdated) { boolean restricted = isRestrictedInterface(iface); int n = mListeners.beginBroadcast(); for (int i = 0; i < n; i++) { @@ -234,6 +323,25 @@ final class EthernetTracker { } mListeners.finishBroadcast(); } + + updateServerModeInterfaceState(iface, up, mode); + } + + private void updateServerModeInterfaceState(String iface, boolean up, int mode) { + final boolean available = up && (mode == INTERFACE_MODE_SERVER); + if (available == mTetheredInterfaceWasAvailable || !iface.equals(mDefaultInterface)) return; + + 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) { @@ -244,6 +352,11 @@ final class EthernetTracker { return; } + // TODO: avoid making an interface default if it has configured NetworkCapabilities. + if (mDefaultInterface == null) { + mDefaultInterface = iface; + } + if (mIpConfigForDefaultInterface != null) { updateIpConfiguration(iface, mIpConfigForDefaultInterface); mIpConfigForDefaultInterface = null; @@ -467,6 +580,8 @@ final class EthernetTracker { 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("Listeners: " + mListeners.getRegisteredCallbackCount()); pw.println("IP Configurations:"); pw.increaseIndent(); From 32327808e1e46de98074d8bd9933852c33d010dc Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 24 Jan 2020 17:57:27 +0900 Subject: [PATCH 059/152] Support one Ethernet interface in server mode. Currently, Ethernet only supports interfaces in client mode (e.g., to connect to the Internet). Add minimal support to Ethernet to support interfaces in server mode. This simple implementation only works on the default interface, which is the first interface that is detected on boot (even if the interface is later removed). This also provides (but does not yet unhide) a simple API for Tethering to request that the next-plugged-in interface to be placed into server mode. Test: Enabling tethering with change on top Bug: 130840861 Merged-In: I78f85bc36aaceb62ce274003a75ea99d0b6bc8b7 Change-Id: I78f85bc36aaceb62ce274003a75ea99d0b6bc8b7 (clean cherry-pick from internal branch) --- .../server/ethernet/EthernetServiceImpl.java | 14 ++ .../server/ethernet/EthernetTracker.java | 131 ++++++++++++++++-- 2 files changed, 137 insertions(+), 8 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index fda3c3c2f9..1cf38b45f4 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -20,12 +20,14 @@ import android.content.Context; import android.content.pm.PackageManager; import android.net.IEthernetManager; import android.net.IEthernetServiceListener; +import android.net.ITetheredInterfaceCallback; import android.net.IpConfiguration; import android.net.NetworkStack; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; import android.os.RemoteException; +import android.provider.Settings; import android.util.Log; import android.util.PrintWriterPrinter; @@ -161,6 +163,18 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { mTracker.removeListener(listener); } + @Override + public void requestTetheredInterface(ITetheredInterfaceCallback callback) { + NetworkStack.checkNetworkStackPermission(mContext); + mTracker.requestTetheredInterface(callback); + } + + @Override + public void releaseTetheredInterface(ITetheredInterfaceCallback callback) { + NetworkStack.checkNetworkStackPermission(mContext); + mTracker.releaseTetheredInterface(callback); + } + @Override protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 4ab1dff881..24616b78dc 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -19,6 +19,7 @@ package com.android.server.ethernet; import android.annotation.Nullable; import android.content.Context; import android.net.IEthernetServiceListener; +import android.net.ITetheredInterfaceCallback; import android.net.InterfaceConfiguration; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; @@ -61,6 +62,9 @@ import java.util.concurrent.ConcurrentHashMap; *

All public or package private methods must be thread-safe unless stated otherwise. */ final class EthernetTracker { + private static final int INTERFACE_MODE_CLIENT = 1; + private static final int INTERFACE_MODE_SERVER = 2; + private final static String TAG = EthernetTracker.class.getSimpleName(); private final static boolean DBG = EthernetNetworkFactory.DBG; @@ -73,6 +77,7 @@ final class EthernetTracker { private final ConcurrentHashMap mIpConfigurations = new ConcurrentHashMap<>(); + private final Context mContext; private final INetworkManagementService mNMService; private final Handler mHandler; private final EthernetNetworkFactory mFactory; @@ -80,10 +85,25 @@ final class EthernetTracker { private final RemoteCallbackList mListeners = new RemoteCallbackList<>(); + private final TetheredInterfaceRequestList mTetheredInterfaceRequests = + new TetheredInterfaceRequestList(); + // Used only on the handler thread + private String mDefaultInterface; + private int mDefaultInterfaceMode; + // Tracks whether clients were notified that the tethered interface is available + private boolean mTetheredInterfaceWasAvailable = false; private volatile IpConfiguration mIpConfigForDefaultInterface; + private class TetheredInterfaceRequestList extends RemoteCallbackList { + @Override + public void onCallbackDied(ITetheredInterfaceCallback cb, Object cookie) { + mHandler.post(EthernetTracker.this::maybeUntetherDefaultInterface); + } + } + EthernetTracker(Context context, Handler handler) { + mContext = context; mHandler = handler; // The services we use. @@ -167,6 +187,68 @@ final class EthernetTracker { mListeners.unregister(listener); } + 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; + // mDefaultInterface null means that there never was a default interface (it is never set + // to null). + if (mDefaultInterfaceMode == INTERFACE_MODE_CLIENT || mDefaultInterface == null) return; + + setDefaultInterfaceMode(INTERFACE_MODE_CLIENT); + } + + private void setDefaultInterfaceMode(int mode) { + mDefaultInterfaceMode = mode; + removeInterface(mDefaultInterface); + addInterface(mDefaultInterface); + } + + private int getInterfaceMode(final String iface) { + if (iface.equals(mDefaultInterface)) { + return mDefaultInterfaceMode; + } + return INTERFACE_MODE_CLIENT; + } + private void removeInterface(String iface) { mFactory.removeInterface(iface); } @@ -198,13 +280,17 @@ final class EthernetTracker { 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); + final int mode = getInterfaceMode(iface); + if (mode == INTERFACE_MODE_CLIENT) { + 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 @@ -215,8 +301,11 @@ final class EthernetTracker { } private void updateInterfaceState(String iface, boolean up) { - boolean modified = mFactory.updateInterfaceLinkState(iface, up); - if (modified) { + final int mode = getInterfaceMode(iface); + final boolean factoryLinkStateUpdated = (mode == INTERFACE_MODE_CLIENT) + && mFactory.updateInterfaceLinkState(iface, up); + + if (factoryLinkStateUpdated) { boolean restricted = isRestrictedInterface(iface); int n = mListeners.beginBroadcast(); for (int i = 0; i < n; i++) { @@ -234,6 +323,25 @@ final class EthernetTracker { } mListeners.finishBroadcast(); } + + updateServerModeInterfaceState(iface, up, mode); + } + + private void updateServerModeInterfaceState(String iface, boolean up, int mode) { + final boolean available = up && (mode == INTERFACE_MODE_SERVER); + if (available == mTetheredInterfaceWasAvailable || !iface.equals(mDefaultInterface)) return; + + 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) { @@ -244,6 +352,11 @@ final class EthernetTracker { return; } + // TODO: avoid making an interface default if it has configured NetworkCapabilities. + if (mDefaultInterface == null) { + mDefaultInterface = iface; + } + if (mIpConfigForDefaultInterface != null) { updateIpConfiguration(iface, mIpConfigForDefaultInterface); mIpConfigForDefaultInterface = null; @@ -467,6 +580,8 @@ final class EthernetTracker { 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("Listeners: " + mListeners.getRegisteredCallbackCount()); pw.println("IP Configurations:"); pw.increaseIndent(); From 79eb7ba87bedd88fffa62a13ea9399c2affa1573 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 22 Jan 2020 16:47:43 +0900 Subject: [PATCH 060/152] Make NetworkScore system API Bug: 146583853 Test: FrameworksNetTests Change-Id: Ie7b70750ef0e17141080f4266dea6155c3601569 --- .../ethernet/EthernetNetworkFactory.java | 71 ++++++++----------- 1 file changed, 30 insertions(+), 41 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 28f46061af..7f12a136bc 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -16,7 +16,6 @@ package com.android.server.ethernet; -import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable; import static com.android.internal.util.Preconditions.checkNotNull; @@ -29,11 +28,11 @@ import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; import android.net.LinkProperties; import android.net.NetworkAgent; +import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkFactory; -import android.net.NetworkInfo; -import android.net.NetworkInfo.DetailedState; import android.net.NetworkRequest; +import android.net.NetworkScore; import android.net.NetworkSpecifier; import android.net.StringNetworkSpecifier; import android.net.ip.IIpClient; @@ -52,7 +51,6 @@ import android.util.SparseArray; import com.android.internal.util.IndentingPrintWriter; import java.io.FileDescriptor; -import java.lang.Math; import java.util.concurrent.ConcurrentHashMap; import java.util.Objects; @@ -68,6 +66,9 @@ public class EthernetNetworkFactory extends NetworkFactory { private final static int NETWORK_SCORE = 70; private static final String NETWORK_TYPE = "Ethernet"; + private final static NetworkScore NULL_SCORE = new NetworkScore.Builder() + .setRange(NetworkScore.RANGE_CLOSE) + .build(); private final ConcurrentHashMap mTrackingInterfaces = new ConcurrentHashMap<>(); @@ -221,12 +222,12 @@ public class EthernetNetworkFactory extends NetworkFactory { NetworkInterfaceState network = null; if (!TextUtils.isEmpty(requestedIface)) { NetworkInterfaceState n = mTrackingInterfaces.get(requestedIface); - if (n != null && n.statisified(request.networkCapabilities)) { + if (n != null && n.satisfied(request.networkCapabilities)) { network = n; } } else { for (NetworkInterfaceState n : mTrackingInterfaces.values()) { - if (n.statisified(request.networkCapabilities) && n.mLinkUp) { + if (n.satisfied(request.networkCapabilities) && n.mLinkUp) { network = n; break; } @@ -247,8 +248,8 @@ public class EthernetNetworkFactory extends NetworkFactory { private final NetworkCapabilities mCapabilities; private final Handler mHandler; private final Context mContext; - private final NetworkInfo mNetworkInfo; private final NetworkFactory mNetworkFactory; + private final int mLegacyType; private static String sTcpBufferSizes = null; // Lazy initialized. @@ -375,9 +376,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } mHwAddress = hwAddress; - mNetworkInfo = new NetworkInfo(legacyType, 0, NETWORK_TYPE, ""); - mNetworkInfo.setExtraInfo(mHwAddress); - mNetworkInfo.setIsAvailable(true); + mLegacyType = legacyType; } void setIpConfig(IpConfiguration ipConfig) { @@ -386,12 +385,12 @@ public class EthernetNetworkFactory extends NetworkFactory { return; } this.mIpConfig = ipConfig; - if (mNetworkInfo.getDetailedState() != DetailedState.DISCONNECTED) { + if (mNetworkAgent != null) { restart(); } } - boolean statisified(NetworkCapabilities requestedCapabilities) { + boolean satisfied(NetworkCapabilities requestedCapabilities) { return requestedCapabilities.satisfiedByNetworkCapabilities(mCapabilities); } @@ -421,23 +420,23 @@ public class EthernetNetworkFactory extends NetworkFactory { * This function is called with the purpose of assigning and updating the network score of * the member NetworkAgent. */ - private int getNetworkScore() { + private NetworkScore getNetworkScore() { // never set the network score below 0. if (!mLinkUp) { - return 0; + return NULL_SCORE; } int[] transportTypes = mCapabilities.getTransportTypes(); if (transportTypes.length < 1) { Log.w(TAG, "Network interface '" + mLinkProperties.getInterfaceName() + "' has no " + "transport type associated with it. Score set to zero"); - return 0; + return NULL_SCORE; } TransportInfo transportInfo = sTransports.get(transportTypes[0], /* if dne */ null); if (transportInfo != null) { - return transportInfo.mScore; + return new NetworkScore.Builder().setLegacyScore(transportInfo.mScore).build(); } - return 0; + return NULL_SCORE; } private void start() { @@ -446,11 +445,9 @@ public class EthernetNetworkFactory extends NetworkFactory { return; } if (DBG) { - Log.d(TAG, String.format("starting IpClient(%s): mNetworkInfo=%s", name, - mNetworkInfo)); + Log.d(TAG, String.format("Starting Ethernet IpClient(%s)", name)); } - mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddress); mIpClientCallback = new IpClientCallbacksImpl(); IpClientUtil.makeIpClient(mContext, name, mIpClientCallback); mIpClientCallback.awaitIpClientStart(); @@ -468,13 +465,16 @@ public class EthernetNetworkFactory extends NetworkFactory { 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, - getNetworkScore(), mNetworkFactory.getSerialNumber()) { + // STOPSHIP : use the new constructor for NetworkAgent that takes a NetworkScore + final NetworkAgentConfig config = new NetworkAgentConfig.Builder() + .setLegacyType(mLegacyType) + .setLegacyTypeName(NETWORK_TYPE) + .build(); + mNetworkAgent = new NetworkAgent(mContext, mHandler.getLooper(), + NETWORK_TYPE, mCapabilities, mLinkProperties, + getNetworkScore(), config, mNetworkFactory.getProvider()) { public void unwanted() { if (this == mNetworkAgent) { stop(); @@ -484,6 +484,9 @@ public class EthernetNetworkFactory extends NetworkFactory { } // Otherwise, we've already called stop. } }; + mNetworkAgent.register(); + mNetworkAgent.setLegacyExtraInfo(mHwAddress); + mNetworkAgent.setConnected(); } void onIpLayerStopped(LinkProperties linkProperties) { @@ -526,16 +529,11 @@ public class EthernetNetworkFactory extends NetworkFactory { } mIpClientCallback = 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.unregister(); mNetworkAgent = null; } - clear(); + mLinkProperties.clear(); } private void updateAgent() { @@ -543,11 +541,9 @@ public class EthernetNetworkFactory extends NetworkFactory { if (DBG) { Log.i(TAG, "Updating mNetworkAgent with: " + mCapabilities + ", " + - mNetworkInfo + ", " + mLinkProperties); } mNetworkAgent.sendNetworkCapabilities(mCapabilities); - mNetworkAgent.sendNetworkInfo(mNetworkInfo); mNetworkAgent.sendLinkProperties(mLinkProperties); // As a note, getNetworkScore() is fairly expensive to calculate. This is fine for now @@ -556,12 +552,6 @@ public class EthernetNetworkFactory extends NetworkFactory { mNetworkAgent.sendNetworkScore(getNetworkScore()); } - private void clear() { - mLinkProperties.clear(); - mNetworkInfo.setDetailedState(DetailedState.IDLE, null, null); - mNetworkInfo.setIsAvailable(false); - } - private static void provisionIpClient(IIpClient ipClient, IpConfiguration config, String tcpBufferSizes) { if (config.getProxySettings() == ProxySettings.STATIC || @@ -612,7 +602,6 @@ public class EthernetNetworkFactory extends NetworkFactory { + "iface: " + name + ", " + "up: " + mLinkUp + ", " + "hwAddress: " + mHwAddress + ", " - + "networkInfo: " + mNetworkInfo + ", " + "networkCapabilities: " + mCapabilities + ", " + "networkAgent: " + mNetworkAgent + ", " + "score: " + getNetworkScore() + ", " From f85c0b301c8466b2d6f92d04029a1da5d118fb04 Mon Sep 17 00:00:00 2001 From: Milim Lee Date: Fri, 31 Jan 2020 11:33:32 +0900 Subject: [PATCH 061/152] Set Ethernet default mode as CLIENT Bug: 130840861 Test: build, boot atest EthernetTrackerTest manual test (using Ethernet) Change-Id: I935ea2e5f214aced67fb60f4aec2744077177545 --- service-t/src/com/android/server/ethernet/EthernetTracker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 24616b78dc..58803d14fe 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -90,7 +90,7 @@ final class EthernetTracker { // Used only on the handler thread private String mDefaultInterface; - private int mDefaultInterfaceMode; + 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; From fd99009c529d5ee7734997f2dfecb486a4b5df22 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 21 Feb 2020 19:52:43 +0900 Subject: [PATCH 062/152] Revert part of 79eb7ba87bedd88fffa62a13ea9399c2affa1573 This reverts the parts of the above commit that have to do with NetworkScore. The parts that convert the factory to the new NetworkAgent API are conserved. Bug: 113554781 Test: FrameworksNetTests Change-Id: If2c368e084e29f9f358f43dcd547d42e8c7c4846 --- .../server/ethernet/EthernetNetworkFactory.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 7f12a136bc..1c835062ba 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -32,7 +32,6 @@ import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkFactory; import android.net.NetworkRequest; -import android.net.NetworkScore; import android.net.NetworkSpecifier; import android.net.StringNetworkSpecifier; import android.net.ip.IIpClient; @@ -66,9 +65,6 @@ public class EthernetNetworkFactory extends NetworkFactory { private final static int NETWORK_SCORE = 70; private static final String NETWORK_TYPE = "Ethernet"; - private final static NetworkScore NULL_SCORE = new NetworkScore.Builder() - .setRange(NetworkScore.RANGE_CLOSE) - .build(); private final ConcurrentHashMap mTrackingInterfaces = new ConcurrentHashMap<>(); @@ -420,23 +416,23 @@ public class EthernetNetworkFactory extends NetworkFactory { * This function is called with the purpose of assigning and updating the network score of * the member NetworkAgent. */ - private NetworkScore getNetworkScore() { + private int getNetworkScore() { // never set the network score below 0. if (!mLinkUp) { - return NULL_SCORE; + return 0; } int[] transportTypes = mCapabilities.getTransportTypes(); if (transportTypes.length < 1) { Log.w(TAG, "Network interface '" + mLinkProperties.getInterfaceName() + "' has no " + "transport type associated with it. Score set to zero"); - return NULL_SCORE; + return 0; } TransportInfo transportInfo = sTransports.get(transportTypes[0], /* if dne */ null); if (transportInfo != null) { - return new NetworkScore.Builder().setLegacyScore(transportInfo.mScore).build(); + return transportInfo.mScore; } - return NULL_SCORE; + return 0; } private void start() { @@ -467,7 +463,6 @@ public class EthernetNetworkFactory extends NetworkFactory { mLinkProperties = linkProperties; // Create our NetworkAgent. - // STOPSHIP : use the new constructor for NetworkAgent that takes a NetworkScore final NetworkAgentConfig config = new NetworkAgentConfig.Builder() .setLegacyType(mLegacyType) .setLegacyTypeName(NETWORK_TYPE) From 841195a10343931a8499206ef09b73b124782e7c Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 17 Mar 2020 00:11:37 +0900 Subject: [PATCH 063/152] Make Ethernet interfaces more testable. This CL adds a setIncludeTestInterfaces method to EthernetManager that, when called, causes the Ethernet service to recognize and manage test interfaces created by TestNetworkManager. Bug: 150644681 Test: Tested by EthernetTetheringTest in same topic Change-Id: I86eef7a93267f800dbfc8eafd307effa76a344ca --- .../server/ethernet/EthernetServiceImpl.java | 13 ++++++-- .../server/ethernet/EthernetTracker.java | 32 ++++++++++++++++--- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 1cf38b45f4..3fc6aab758 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -163,15 +163,24 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { mTracker.removeListener(listener); } + @Override + public void setIncludeTestInterfaces(boolean include) { + NetworkStack.checkNetworkStackPermissionOr(mContext, + android.Manifest.permission.NETWORK_SETTINGS); + mTracker.setIncludeTestInterfaces(include); + } + @Override public void requestTetheredInterface(ITetheredInterfaceCallback callback) { - NetworkStack.checkNetworkStackPermission(mContext); + NetworkStack.checkNetworkStackPermissionOr(mContext, + android.Manifest.permission.NETWORK_SETTINGS); mTracker.requestTetheredInterface(callback); } @Override public void releaseTetheredInterface(ITetheredInterfaceCallback callback) { - NetworkStack.checkNetworkStackPermission(mContext); + NetworkStack.checkNetworkStackPermissionOr(mContext, + android.Manifest.permission.NETWORK_SETTINGS); mTracker.releaseTetheredInterface(callback); } diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 58803d14fe..91453abe1a 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -16,6 +16,8 @@ package com.android.server.ethernet; +import static android.net.TestNetworkManager.TEST_TAP_PREFIX; + import android.annotation.Nullable; import android.content.Context; import android.net.IEthernetServiceListener; @@ -68,8 +70,12 @@ 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; + /** + * Interface names we track. This is a product-dependent regular expression, plus, + * if setIncludeTestInterfaces is true, any test interfaces. + */ + private String mIfaceMatch; + private boolean mIncludeTestInterfaces = false; /** Mapping between {iface name | mac address} -> {NetworkCapabilities} */ private final ConcurrentHashMap mNetworkCapabilities = @@ -111,8 +117,7 @@ final class EthernetTracker { mNMService = INetworkManagementService.Stub.asInterface(b); // Interface match regex. - mIfaceMatch = context.getResources().getString( - com.android.internal.R.string.config_ethernet_iface_regex); + updateIfaceMatchRegexp(); // Read default Ethernet interface configuration from resources final String[] interfaceConfigs = context.getResources().getStringArray( @@ -187,6 +192,12 @@ final class EthernetTracker { mListeners.unregister(listener); } + public void setIncludeTestInterfaces(boolean include) { + mIncludeTestInterfaces = include; + updateIfaceMatchRegexp(); + trackAvailableInterfaces(); + } + public void requestTetheredInterface(ITetheredInterfaceCallback callback) { mHandler.post(() -> { if (!mTetheredInterfaceRequests.register(callback)) { @@ -348,7 +359,8 @@ final class EthernetTracker { 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)) { + if (!iface.matches(mIfaceMatch) || mFactory.hasInterface(iface) + || iface.equals(mDefaultInterface)) { return; } @@ -572,6 +584,16 @@ final class EthernetTracker { return new IpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, null, null); } + private void updateIfaceMatchRegexp() { + final String testInterfaceMatch = TEST_TAP_PREFIX + ".*"; + final String match = mContext.getResources().getString( + com.android.internal.R.string.config_ethernet_iface_regex); + mIfaceMatch = mIncludeTestInterfaces + ? "(" + match + "|" + TEST_TAP_PREFIX + "\\d+)" + : match; + Log.d(TAG, "Interface match regexp set to '" + mIfaceMatch + "'"); + } + private void postAndWaitForRunnable(Runnable r) { mHandler.runWithScissors(r, 2000L /* timeout */); } From fb336e9296aeb7a944c0346f45c2878aed9d0a7c Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 19 Mar 2020 11:46:55 +0000 Subject: [PATCH 064/152] Make Ethernet interfaces more testable. This CL adds a setIncludeTestInterfaces method to EthernetManager that, when called, causes the Ethernet service to recognize and manage test interfaces created by TestNetworkManager. Bug: 150644681 Test: Tested by EthernetTetheringTest in same topic Change-Id: I86eef7a93267f800dbfc8eafd307effa76a344ca Merged-In: I86eef7a93267f800dbfc8eafd307effa76a344ca (cherry picked from commit 4978dbd5fb6592fc4e7be08d02783752245da634) --- .../server/ethernet/EthernetServiceImpl.java | 13 ++++++-- .../server/ethernet/EthernetTracker.java | 32 ++++++++++++++++--- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 1cf38b45f4..3fc6aab758 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -163,15 +163,24 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { mTracker.removeListener(listener); } + @Override + public void setIncludeTestInterfaces(boolean include) { + NetworkStack.checkNetworkStackPermissionOr(mContext, + android.Manifest.permission.NETWORK_SETTINGS); + mTracker.setIncludeTestInterfaces(include); + } + @Override public void requestTetheredInterface(ITetheredInterfaceCallback callback) { - NetworkStack.checkNetworkStackPermission(mContext); + NetworkStack.checkNetworkStackPermissionOr(mContext, + android.Manifest.permission.NETWORK_SETTINGS); mTracker.requestTetheredInterface(callback); } @Override public void releaseTetheredInterface(ITetheredInterfaceCallback callback) { - NetworkStack.checkNetworkStackPermission(mContext); + NetworkStack.checkNetworkStackPermissionOr(mContext, + android.Manifest.permission.NETWORK_SETTINGS); mTracker.releaseTetheredInterface(callback); } diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 58803d14fe..91453abe1a 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -16,6 +16,8 @@ package com.android.server.ethernet; +import static android.net.TestNetworkManager.TEST_TAP_PREFIX; + import android.annotation.Nullable; import android.content.Context; import android.net.IEthernetServiceListener; @@ -68,8 +70,12 @@ 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; + /** + * Interface names we track. This is a product-dependent regular expression, plus, + * if setIncludeTestInterfaces is true, any test interfaces. + */ + private String mIfaceMatch; + private boolean mIncludeTestInterfaces = false; /** Mapping between {iface name | mac address} -> {NetworkCapabilities} */ private final ConcurrentHashMap mNetworkCapabilities = @@ -111,8 +117,7 @@ final class EthernetTracker { mNMService = INetworkManagementService.Stub.asInterface(b); // Interface match regex. - mIfaceMatch = context.getResources().getString( - com.android.internal.R.string.config_ethernet_iface_regex); + updateIfaceMatchRegexp(); // Read default Ethernet interface configuration from resources final String[] interfaceConfigs = context.getResources().getStringArray( @@ -187,6 +192,12 @@ final class EthernetTracker { mListeners.unregister(listener); } + public void setIncludeTestInterfaces(boolean include) { + mIncludeTestInterfaces = include; + updateIfaceMatchRegexp(); + trackAvailableInterfaces(); + } + public void requestTetheredInterface(ITetheredInterfaceCallback callback) { mHandler.post(() -> { if (!mTetheredInterfaceRequests.register(callback)) { @@ -348,7 +359,8 @@ final class EthernetTracker { 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)) { + if (!iface.matches(mIfaceMatch) || mFactory.hasInterface(iface) + || iface.equals(mDefaultInterface)) { return; } @@ -572,6 +584,16 @@ final class EthernetTracker { return new IpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, null, null); } + private void updateIfaceMatchRegexp() { + final String testInterfaceMatch = TEST_TAP_PREFIX + ".*"; + final String match = mContext.getResources().getString( + com.android.internal.R.string.config_ethernet_iface_regex); + mIfaceMatch = mIncludeTestInterfaces + ? "(" + match + "|" + TEST_TAP_PREFIX + "\\d+)" + : match; + Log.d(TAG, "Interface match regexp set to '" + mIfaceMatch + "'"); + } + private void postAndWaitForRunnable(Runnable r) { mHandler.runWithScissors(r, 2000L /* timeout */); } From e81f99d5328063219eb61ce716f253579b3efb1f Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 17 Mar 2020 00:11:37 +0900 Subject: [PATCH 065/152] Support setting the default interface to null again. Currently, the default interface can only ever go from null to non-null. This is correct for fixed interfaces (because they don't get unplugged) and it's generally correct for USB interfaces that use ethX as their device name (because when they are unplugged and plugged in again, the device name won't change). But it is not correct if, for example, the default interface is a test interface. So, allow mDefaultInterface to go back to null. This CL also fixes a crash if a tethered interface request is added and removed when there is no default interface. Also, make dump() report tethered interface requests. Also remove an unused variable that I missed in the previous CL. Bug: 150644681 Test: tested by EthernetTetheringTest in same topic Change-Id: I5109d8da3aeb6c1f6523291d9e2ec92c64b5ad2d --- .../server/ethernet/EthernetTracker.java | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 91453abe1a..d1f1402311 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -240,17 +240,17 @@ final class EthernetTracker { private void maybeUntetherDefaultInterface() { if (mTetheredInterfaceRequests.getRegisteredCallbackCount() > 0) return; - // mDefaultInterface null means that there never was a default interface (it is never set - // to null). - if (mDefaultInterfaceMode == INTERFACE_MODE_CLIENT || mDefaultInterface == null) 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; - removeInterface(mDefaultInterface); - addInterface(mDefaultInterface); + if (mDefaultInterface != null) { + removeInterface(mDefaultInterface); + addInterface(mDefaultInterface); + } } private int getInterfaceMode(final String iface) { @@ -264,6 +264,13 @@ final class EthernetTracker { mFactory.removeInterface(iface); } + private void stopTrackingInterface(String iface) { + removeInterface(iface); + if (iface.equals(mDefaultInterface)) { + mDefaultInterface = null; + } + } + private void addInterface(String iface) { InterfaceConfiguration config = null; // Bring up the interface so we get link status indications. @@ -406,7 +413,7 @@ final class EthernetTracker { @Override public void interfaceRemoved(String iface) { - mHandler.post(() -> removeInterface(iface)); + mHandler.post(() -> stopTrackingInterface(iface)); } } @@ -585,7 +592,6 @@ final class EthernetTracker { } private void updateIfaceMatchRegexp() { - final String testInterfaceMatch = TEST_TAP_PREFIX + ".*"; final String match = mContext.getResources().getString( com.android.internal.R.string.config_ethernet_iface_regex); mIfaceMatch = mIncludeTestInterfaces @@ -604,6 +610,8 @@ final class EthernetTracker { 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(); From 165b456d92463d3edccf69ea13adb4b9977999ec Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 19 Mar 2020 14:36:24 +0900 Subject: [PATCH 066/152] Send tethered interface callbacks based on interface existence. Currently, callbacks for tethered interface availability are sent based on interface link state. This is incorrect: - It is acceptable and expected to be able to enable tethering on an interface that does not yet have link up. - It doesn't seem useful to disable Ethernet tethering if link temporarily goes down. Instead, only base the callbacks on whether an interface exists or not. Bug: 150644681 Test: WIP tests in aosp/1260100 pass Change-Id: I015219cbd03626c38fb5156d0cb2991ba7d7def7 --- .../src/com/android/server/ethernet/EthernetTracker.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index d1f1402311..336ddef23a 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -262,6 +262,7 @@ final class EthernetTracker { private void removeInterface(String iface) { mFactory.removeInterface(iface); + maybeUpdateServerModeInterfaceState(iface, false); } private void stopTrackingInterface(String iface) { @@ -308,6 +309,8 @@ final class EthernetTracker { Log.d(TAG, "Started tracking interface " + iface); mFactory.addInterface(iface, hwAddress, nc, ipConfiguration); + } else { + maybeUpdateServerModeInterfaceState(iface, true); } // Note: if the interface already has link (e.g., if we crashed and got @@ -341,12 +344,9 @@ final class EthernetTracker { } mListeners.finishBroadcast(); } - - updateServerModeInterfaceState(iface, up, mode); } - private void updateServerModeInterfaceState(String iface, boolean up, int mode) { - final boolean available = up && (mode == INTERFACE_MODE_SERVER); + private void maybeUpdateServerModeInterfaceState(String iface, boolean available) { if (available == mTetheredInterfaceWasAvailable || !iface.equals(mDefaultInterface)) return; final int pendingCbs = mTetheredInterfaceRequests.beginBroadcast(); From 876e5e16a97b4fa2532cd1920da84e20bea31a68 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 19 Mar 2020 15:52:03 +0000 Subject: [PATCH 067/152] Support setting the default interface to null again. Currently, the default interface can only ever go from null to non-null. This is correct for fixed interfaces (because they don't get unplugged) and it's generally correct for USB interfaces that use ethX as their device name (because when they are unplugged and plugged in again, the device name won't change). But it is not correct if, for example, the default interface is a test interface. So, allow mDefaultInterface to go back to null. This CL also fixes a crash if a tethered interface request is added and removed when there is no default interface. Also, make dump() report tethered interface requests. Also remove an unused variable that I missed in the previous CL. Bug: 150644681 Test: tested by EthernetTetheringTest in same topic Change-Id: I5109d8da3aeb6c1f6523291d9e2ec92c64b5ad2d Merged-In: I5109d8da3aeb6c1f6523291d9e2ec92c64b5ad2d (cherry picked from commit cc156c2f7793731b2699e194d4b164138ee4cf62) --- .../server/ethernet/EthernetTracker.java | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 91453abe1a..d1f1402311 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -240,17 +240,17 @@ final class EthernetTracker { private void maybeUntetherDefaultInterface() { if (mTetheredInterfaceRequests.getRegisteredCallbackCount() > 0) return; - // mDefaultInterface null means that there never was a default interface (it is never set - // to null). - if (mDefaultInterfaceMode == INTERFACE_MODE_CLIENT || mDefaultInterface == null) 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; - removeInterface(mDefaultInterface); - addInterface(mDefaultInterface); + if (mDefaultInterface != null) { + removeInterface(mDefaultInterface); + addInterface(mDefaultInterface); + } } private int getInterfaceMode(final String iface) { @@ -264,6 +264,13 @@ final class EthernetTracker { mFactory.removeInterface(iface); } + private void stopTrackingInterface(String iface) { + removeInterface(iface); + if (iface.equals(mDefaultInterface)) { + mDefaultInterface = null; + } + } + private void addInterface(String iface) { InterfaceConfiguration config = null; // Bring up the interface so we get link status indications. @@ -406,7 +413,7 @@ final class EthernetTracker { @Override public void interfaceRemoved(String iface) { - mHandler.post(() -> removeInterface(iface)); + mHandler.post(() -> stopTrackingInterface(iface)); } } @@ -585,7 +592,6 @@ final class EthernetTracker { } private void updateIfaceMatchRegexp() { - final String testInterfaceMatch = TEST_TAP_PREFIX + ".*"; final String match = mContext.getResources().getString( com.android.internal.R.string.config_ethernet_iface_regex); mIfaceMatch = mIncludeTestInterfaces @@ -604,6 +610,8 @@ final class EthernetTracker { 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(); From 0c30d949df02680632ce1dd33fb67efe2f92b65f Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 19 Mar 2020 15:52:09 +0000 Subject: [PATCH 068/152] Send tethered interface callbacks based on interface existence. Currently, callbacks for tethered interface availability are sent based on interface link state. This is incorrect: - It is acceptable and expected to be able to enable tethering on an interface that does not yet have link up. - It doesn't seem useful to disable Ethernet tethering if link temporarily goes down. Instead, only base the callbacks on whether an interface exists or not. Bug: 150644681 Test: WIP tests in aosp/1260100 pass Change-Id: I015219cbd03626c38fb5156d0cb2991ba7d7def7 Merged-In: I015219cbd03626c38fb5156d0cb2991ba7d7def7 (cherry picked from commit 64d12ea20ce3cd822518e0f15ed7483a2fb91a50) --- .../src/com/android/server/ethernet/EthernetTracker.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index d1f1402311..336ddef23a 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -262,6 +262,7 @@ final class EthernetTracker { private void removeInterface(String iface) { mFactory.removeInterface(iface); + maybeUpdateServerModeInterfaceState(iface, false); } private void stopTrackingInterface(String iface) { @@ -308,6 +309,8 @@ final class EthernetTracker { Log.d(TAG, "Started tracking interface " + iface); mFactory.addInterface(iface, hwAddress, nc, ipConfiguration); + } else { + maybeUpdateServerModeInterfaceState(iface, true); } // Note: if the interface already has link (e.g., if we crashed and got @@ -341,12 +344,9 @@ final class EthernetTracker { } mListeners.finishBroadcast(); } - - updateServerModeInterfaceState(iface, up, mode); } - private void updateServerModeInterfaceState(String iface, boolean up, int mode) { - final boolean available = up && (mode == INTERFACE_MODE_SERVER); + private void maybeUpdateServerModeInterfaceState(String iface, boolean available) { if (available == mTetheredInterfaceWasAvailable || !iface.equals(mDefaultInterface)) return; final int pendingCbs = mTetheredInterfaceRequests.beginBroadcast(); From bd66333a246cdaf3452ab83c79f799b2a8ec52b2 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 25 Mar 2020 01:20:03 +0900 Subject: [PATCH 069/152] Don't call maybeTrackInterface on the wrong thread. Bug: 150644681 Test: atest TetheringIntegrationTests:EthernetTetheringTest --rerun-until-failure 100 Change-Id: Ia2cb265f8d4de96210f1462339c10ad2947eec65 --- .../server/ethernet/EthernetTracker.java | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 336ddef23a..c8c3bdfb59 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -193,9 +193,11 @@ final class EthernetTracker { } public void setIncludeTestInterfaces(boolean include) { - mIncludeTestInterfaces = include; - updateIfaceMatchRegexp(); - trackAvailableInterfaces(); + mHandler.post(() -> { + mIncludeTestInterfaces = include; + updateIfaceMatchRegexp(); + mHandler.post(() -> trackAvailableInterfaces()); + }); } public void requestTetheredInterface(ITetheredInterfaceCallback callback) { @@ -307,7 +309,7 @@ final class EthernetTracker { ipConfiguration = createDefaultIpConfiguration(); } - Log.d(TAG, "Started tracking interface " + iface); + Log.d(TAG, "Tracking interface in client mode: " + iface); mFactory.addInterface(iface, hwAddress, nc, ipConfiguration); } else { maybeUpdateServerModeInterfaceState(iface, true); @@ -349,6 +351,9 @@ final class EthernetTracker { 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); @@ -363,14 +368,18 @@ final class EthernetTracker { } 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) - || iface.equals(mDefaultInterface)) { + 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; From dd397f58c7716c96843c35b40ba7ff30c60826e7 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 26 Mar 2020 22:38:21 +0900 Subject: [PATCH 070/152] Fix querying Ethernet availability for unprivileged callers. Both EthernetManager#getAvailableInterfaces() and the no-arg version of EthernetManager#isAvailable() end up calling EthernetServiceImpl#getAvailableInterfaces. This method attempts to filter out restricted interfaces if the caller does not have the CONNECTIVITY_USE_RESTRICTED_NETWORKS permission. Unfortunately EthernetNetworkFactory's notion of a restricted interface is the opposite of what it should be. This means that while privileged callers can see all interfaces, unprivileged callers can only see restricted interfaces which they cannot use. Fix this by correcting NetworkInterfaceState#isRestricted(), so that unprivileged callers can see only unrestricted interfaces. Privileged callers are unaffected. This bug probably went unnoticed because restricted Ethernet interfaces are rare (likely used only on auto devices) and because the callers that care about those restricted interfaces are generally privileged. Bug: 148824036 Test: atest android.net.EthernetTetheringTest#testPhysicalEthernet Change-Id: Idff3b05a193a80c581d80d0e4fe9c2d3fc0d8a25 --- .../src/com/android/server/ethernet/EthernetNetworkFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 28f46061af..ab2cfc772d 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -396,7 +396,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } boolean isRestricted() { - return mCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + return !mCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); } /** From dff893b275d2c55f2fc08e600a65ece6862a64b6 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 27 Mar 2020 15:02:17 +0900 Subject: [PATCH 071/152] Address further API council comments. Test: FrameworksNetTests NetworkStackTests Bug: 152238712 Change-Id: I7c27f76c54a76abeae46dcdcddaeb3ca48afa358 --- .../src/com/android/server/ethernet/EthernetNetworkFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 1c835062ba..3d5385aa48 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -481,7 +481,7 @@ public class EthernetNetworkFactory extends NetworkFactory { }; mNetworkAgent.register(); mNetworkAgent.setLegacyExtraInfo(mHwAddress); - mNetworkAgent.setConnected(); + mNetworkAgent.markConnected(); } void onIpLayerStopped(LinkProperties linkProperties) { From bc7ff5d89f5c37f0cf003c391fa2706f71bd3111 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 27 Mar 2020 09:06:27 +0000 Subject: [PATCH 072/152] Fix querying Ethernet availability for unprivileged callers. Both EthernetManager#getAvailableInterfaces() and the no-arg version of EthernetManager#isAvailable() end up calling EthernetServiceImpl#getAvailableInterfaces. This method attempts to filter out restricted interfaces if the caller does not have the CONNECTIVITY_USE_RESTRICTED_NETWORKS permission. Unfortunately EthernetNetworkFactory's notion of a restricted interface is the opposite of what it should be. This means that while privileged callers can see all interfaces, unprivileged callers can only see restricted interfaces which they cannot use. Fix this by correcting NetworkInterfaceState#isRestricted(), so that unprivileged callers can see only unrestricted interfaces. Privileged callers are unaffected. This bug probably went unnoticed because restricted Ethernet interfaces are rare (likely used only on auto devices) and because the callers that care about those restricted interfaces are generally privileged. Bug: 148824036 Test: atest android.net.EthernetTetheringTest#testPhysicalEthernet Merged-In: Idff3b05a193a80c581d80d0e4fe9c2d3fc0d8a25 Change-Id: Idff3b05a193a80c581d80d0e4fe9c2d3fc0d8a25 --- .../src/com/android/server/ethernet/EthernetNetworkFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 1c835062ba..f5ab8b7692 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -391,7 +391,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } boolean isRestricted() { - return mCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + return !mCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); } /** From 86aac0daece919032fc08f1d1990653210db817d Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 22 Jan 2020 16:47:43 +0900 Subject: [PATCH 073/152] Convert the Ethernet factory to the new network agent This is a combination of ag/10147368 and ag/10438581. ag/10147368 implemented this conversion together with using the planned NetworkScore API, while ag/10438581 reverted the parts that had to do with NetworkScore. This is just a squash of these two patches and it brings the factory in line with the code in rvc-dev. Test: FrameworksNetTests NetworkStackTests EthernetTetheringTest Change-Id: Ib214fbbd042f2c0ebd01cf5b0ec33d922629677e Merged-In: Ie7b70750ef0e17141080f4266dea6155c3601569 --- .../ethernet/EthernetNetworkFactory.java | 56 +++++++------------ 1 file changed, 20 insertions(+), 36 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index ab2cfc772d..f5ab8b7692 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -16,7 +16,6 @@ package com.android.server.ethernet; -import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable; import static com.android.internal.util.Preconditions.checkNotNull; @@ -29,10 +28,9 @@ import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; import android.net.LinkProperties; import android.net.NetworkAgent; +import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkFactory; -import android.net.NetworkInfo; -import android.net.NetworkInfo.DetailedState; import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.StringNetworkSpecifier; @@ -52,7 +50,6 @@ import android.util.SparseArray; import com.android.internal.util.IndentingPrintWriter; import java.io.FileDescriptor; -import java.lang.Math; import java.util.concurrent.ConcurrentHashMap; import java.util.Objects; @@ -221,12 +218,12 @@ public class EthernetNetworkFactory extends NetworkFactory { NetworkInterfaceState network = null; if (!TextUtils.isEmpty(requestedIface)) { NetworkInterfaceState n = mTrackingInterfaces.get(requestedIface); - if (n != null && n.statisified(request.networkCapabilities)) { + if (n != null && n.satisfied(request.networkCapabilities)) { network = n; } } else { for (NetworkInterfaceState n : mTrackingInterfaces.values()) { - if (n.statisified(request.networkCapabilities) && n.mLinkUp) { + if (n.satisfied(request.networkCapabilities) && n.mLinkUp) { network = n; break; } @@ -247,8 +244,8 @@ public class EthernetNetworkFactory extends NetworkFactory { private final NetworkCapabilities mCapabilities; private final Handler mHandler; private final Context mContext; - private final NetworkInfo mNetworkInfo; private final NetworkFactory mNetworkFactory; + private final int mLegacyType; private static String sTcpBufferSizes = null; // Lazy initialized. @@ -375,9 +372,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } mHwAddress = hwAddress; - mNetworkInfo = new NetworkInfo(legacyType, 0, NETWORK_TYPE, ""); - mNetworkInfo.setExtraInfo(mHwAddress); - mNetworkInfo.setIsAvailable(true); + mLegacyType = legacyType; } void setIpConfig(IpConfiguration ipConfig) { @@ -386,12 +381,12 @@ public class EthernetNetworkFactory extends NetworkFactory { return; } this.mIpConfig = ipConfig; - if (mNetworkInfo.getDetailedState() != DetailedState.DISCONNECTED) { + if (mNetworkAgent != null) { restart(); } } - boolean statisified(NetworkCapabilities requestedCapabilities) { + boolean satisfied(NetworkCapabilities requestedCapabilities) { return requestedCapabilities.satisfiedByNetworkCapabilities(mCapabilities); } @@ -446,11 +441,9 @@ public class EthernetNetworkFactory extends NetworkFactory { return; } if (DBG) { - Log.d(TAG, String.format("starting IpClient(%s): mNetworkInfo=%s", name, - mNetworkInfo)); + Log.d(TAG, String.format("Starting Ethernet IpClient(%s)", name)); } - mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddress); mIpClientCallback = new IpClientCallbacksImpl(); IpClientUtil.makeIpClient(mContext, name, mIpClientCallback); mIpClientCallback.awaitIpClientStart(); @@ -468,13 +461,15 @@ public class EthernetNetworkFactory extends NetworkFactory { 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, - getNetworkScore(), mNetworkFactory.getSerialNumber()) { + final NetworkAgentConfig config = new NetworkAgentConfig.Builder() + .setLegacyType(mLegacyType) + .setLegacyTypeName(NETWORK_TYPE) + .build(); + mNetworkAgent = new NetworkAgent(mContext, mHandler.getLooper(), + NETWORK_TYPE, mCapabilities, mLinkProperties, + getNetworkScore(), config, mNetworkFactory.getProvider()) { public void unwanted() { if (this == mNetworkAgent) { stop(); @@ -484,6 +479,9 @@ public class EthernetNetworkFactory extends NetworkFactory { } // Otherwise, we've already called stop. } }; + mNetworkAgent.register(); + mNetworkAgent.setLegacyExtraInfo(mHwAddress); + mNetworkAgent.setConnected(); } void onIpLayerStopped(LinkProperties linkProperties) { @@ -526,16 +524,11 @@ public class EthernetNetworkFactory extends NetworkFactory { } mIpClientCallback = 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.unregister(); mNetworkAgent = null; } - clear(); + mLinkProperties.clear(); } private void updateAgent() { @@ -543,11 +536,9 @@ public class EthernetNetworkFactory extends NetworkFactory { if (DBG) { Log.i(TAG, "Updating mNetworkAgent with: " + mCapabilities + ", " + - mNetworkInfo + ", " + mLinkProperties); } mNetworkAgent.sendNetworkCapabilities(mCapabilities); - mNetworkAgent.sendNetworkInfo(mNetworkInfo); mNetworkAgent.sendLinkProperties(mLinkProperties); // As a note, getNetworkScore() is fairly expensive to calculate. This is fine for now @@ -556,12 +547,6 @@ public class EthernetNetworkFactory extends NetworkFactory { mNetworkAgent.sendNetworkScore(getNetworkScore()); } - private void clear() { - mLinkProperties.clear(); - mNetworkInfo.setDetailedState(DetailedState.IDLE, null, null); - mNetworkInfo.setIsAvailable(false); - } - private static void provisionIpClient(IIpClient ipClient, IpConfiguration config, String tcpBufferSizes) { if (config.getProxySettings() == ProxySettings.STATIC || @@ -612,7 +597,6 @@ public class EthernetNetworkFactory extends NetworkFactory { + "iface: " + name + ", " + "up: " + mLinkUp + ", " + "hwAddress: " + mHwAddress + ", " - + "networkInfo: " + mNetworkInfo + ", " + "networkCapabilities: " + mCapabilities + ", " + "networkAgent: " + mNetworkAgent + ", " + "score: " + getNetworkScore() + ", " From 4b9a7dd13d2ca18dcf67c38c8a64a779b6462add Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 27 Mar 2020 15:02:17 +0900 Subject: [PATCH 074/152] Address further API council comments. Test: FrameworksNetTests NetworkStackTests Bug: 152238712 Copy from ag/10857997 Change-Id: I7c27f76c54a76abeae46dcdcddaeb3ca48afa358 Merged-In: I7c27f76c54a76abeae46dcdcddaeb3ca48afa358 --- .../src/com/android/server/ethernet/EthernetNetworkFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index f5ab8b7692..793b284676 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -481,7 +481,7 @@ public class EthernetNetworkFactory extends NetworkFactory { }; mNetworkAgent.register(); mNetworkAgent.setLegacyExtraInfo(mHwAddress); - mNetworkAgent.setConnected(); + mNetworkAgent.markConnected(); } void onIpLayerStopped(LinkProperties linkProperties) { From 612353381716e0096b1044751e33e306c499f2c1 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 26 Mar 2020 09:58:55 +0000 Subject: [PATCH 075/152] Don't call maybeTrackInterface on the wrong thread. Bug: 150644681 Test: atest TetheringIntegrationTests:EthernetTetheringTest --rerun-until-failure 100 Merged-In: Ia2cb265f8d4de96210f1462339c10ad2947eec65 Change-Id: Ia2cb265f8d4de96210f1462339c10ad2947eec65 --- .../server/ethernet/EthernetTracker.java | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 336ddef23a..c8c3bdfb59 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -193,9 +193,11 @@ final class EthernetTracker { } public void setIncludeTestInterfaces(boolean include) { - mIncludeTestInterfaces = include; - updateIfaceMatchRegexp(); - trackAvailableInterfaces(); + mHandler.post(() -> { + mIncludeTestInterfaces = include; + updateIfaceMatchRegexp(); + mHandler.post(() -> trackAvailableInterfaces()); + }); } public void requestTetheredInterface(ITetheredInterfaceCallback callback) { @@ -307,7 +309,7 @@ final class EthernetTracker { ipConfiguration = createDefaultIpConfiguration(); } - Log.d(TAG, "Started tracking interface " + iface); + Log.d(TAG, "Tracking interface in client mode: " + iface); mFactory.addInterface(iface, hwAddress, nc, ipConfiguration); } else { maybeUpdateServerModeInterfaceState(iface, true); @@ -349,6 +351,9 @@ final class EthernetTracker { 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); @@ -363,14 +368,18 @@ final class EthernetTracker { } 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) - || iface.equals(mDefaultInterface)) { + 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; From bddcfc0c48dd4902e11a92d38c80973f6bcd388a Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 11 May 2020 11:20:00 +0900 Subject: [PATCH 076/152] Add capability they should always have to eth networks. There is a stopgap hack in ConnectivityService doing this automatically, but individual agents should be doing this themselves. Test: FrameworksNetTests NetworkStackTests Bug: 150570873 Change-Id: I6f75e2b26eb9f554243bc418142a4dc18839aa79 --- .../src/com/android/server/ethernet/EthernetTracker.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index c8c3bdfb59..d37e0c9c86 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -464,6 +464,7 @@ final class EthernetTracker { nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); return nc; } @@ -542,6 +543,11 @@ final class EthernetTracker { } } } + // Ethernet networks have no way to update the following capabilities, so they always + // have them. + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); return nc; } From 2bdb206bc0de7a57eca97575bd763c4c01ed3f35 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 11 May 2020 12:31:01 +0000 Subject: [PATCH 077/152] Add capability they should always have to eth networks. There is a stopgap hack in ConnectivityService doing this automatically, but individual agents should be doing this themselves. Test: FrameworksNetTests NetworkStackTests Bug: 150570873 Original-Change: https://android-review.googlesource.com/1307433 Merged-In: I6f75e2b26eb9f554243bc418142a4dc18839aa79 Change-Id: I6f75e2b26eb9f554243bc418142a4dc18839aa79 --- .../src/com/android/server/ethernet/EthernetTracker.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index c8c3bdfb59..d37e0c9c86 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -464,6 +464,7 @@ final class EthernetTracker { nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); return nc; } @@ -542,6 +543,11 @@ final class EthernetTracker { } } } + // Ethernet networks have no way to update the following capabilities, so they always + // have them. + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); return nc; } From 1849ebd9c3ea50616ced35f4c624c26db94cf57e Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 27 May 2020 12:35:40 +0900 Subject: [PATCH 078/152] Add TRANSPORT_TEST to test ethernet interfaces Because they operate on test interfaces, ethernet interfaces included with setIncludeTestInterfaces should have TRANSPORT_TEST. Bug: 156319532 Test: atest CaptivePortalApiTest Change-Id: Ife3eab06432cabf3ee626de49abc31c8349b4316 --- .../android/server/ethernet/EthernetTracker.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index d37e0c9c86..d7fd408b69 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -70,6 +70,8 @@ final class EthernetTracker { private final static String TAG = EthernetTracker.class.getSimpleName(); private final static boolean DBG = EthernetNetworkFactory.DBG; + private static final String TEST_IFACE_REGEXP = TEST_TAP_PREFIX + "\\d+"; + /** * Interface names we track. This is a product-dependent regular expression, plus, * if setIncludeTestInterfaces is true, any test interfaces. @@ -298,7 +300,8 @@ final class EthernetTracker { // Try to resolve using mac address nc = mNetworkCapabilities.get(hwAddress); if (nc == null) { - nc = createDefaultNetworkCapabilities(); + final boolean isTestIface = iface.matches(TEST_IFACE_REGEXP); + nc = createDefaultNetworkCapabilities(isTestIface); } } @@ -457,15 +460,20 @@ final class EthernetTracker { } } - private static NetworkCapabilities createDefaultNetworkCapabilities() { + private static NetworkCapabilities createDefaultNetworkCapabilities(boolean isTestIface) { 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); nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); + if (isTestIface) { + nc.addTransportType(NetworkCapabilities.TRANSPORT_TEST); + } else { + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + } + return nc; } @@ -610,7 +618,7 @@ final class EthernetTracker { final String match = mContext.getResources().getString( com.android.internal.R.string.config_ethernet_iface_regex); mIfaceMatch = mIncludeTestInterfaces - ? "(" + match + "|" + TEST_TAP_PREFIX + "\\d+)" + ? "(" + match + "|" + TEST_IFACE_REGEXP + ")" : match; Log.d(TAG, "Interface match regexp set to '" + mIfaceMatch + "'"); } From ecb5efcd7645d877cd6fe63a07893ccb211ecf2f Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 29 May 2020 22:09:13 +0000 Subject: [PATCH 079/152] Add TRANSPORT_TEST to test ethernet interfaces Because they operate on test interfaces, ethernet interfaces included with setIncludeTestInterfaces should have TRANSPORT_TEST. Bug: 156319532 Test: atest CaptivePortalApiTest Original-Change: https://android-review.googlesource.com/1318214 Merged-In: Ife3eab06432cabf3ee626de49abc31c8349b4316 Change-Id: Ife3eab06432cabf3ee626de49abc31c8349b4316 --- .../android/server/ethernet/EthernetTracker.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index d37e0c9c86..d7fd408b69 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -70,6 +70,8 @@ final class EthernetTracker { private final static String TAG = EthernetTracker.class.getSimpleName(); private final static boolean DBG = EthernetNetworkFactory.DBG; + private static final String TEST_IFACE_REGEXP = TEST_TAP_PREFIX + "\\d+"; + /** * Interface names we track. This is a product-dependent regular expression, plus, * if setIncludeTestInterfaces is true, any test interfaces. @@ -298,7 +300,8 @@ final class EthernetTracker { // Try to resolve using mac address nc = mNetworkCapabilities.get(hwAddress); if (nc == null) { - nc = createDefaultNetworkCapabilities(); + final boolean isTestIface = iface.matches(TEST_IFACE_REGEXP); + nc = createDefaultNetworkCapabilities(isTestIface); } } @@ -457,15 +460,20 @@ final class EthernetTracker { } } - private static NetworkCapabilities createDefaultNetworkCapabilities() { + private static NetworkCapabilities createDefaultNetworkCapabilities(boolean isTestIface) { 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); nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); + if (isTestIface) { + nc.addTransportType(NetworkCapabilities.TRANSPORT_TEST); + } else { + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + } + return nc; } @@ -610,7 +618,7 @@ final class EthernetTracker { final String match = mContext.getResources().getString( com.android.internal.R.string.config_ethernet_iface_regex); mIfaceMatch = mIncludeTestInterfaces - ? "(" + match + "|" + TEST_TAP_PREFIX + "\\d+)" + ? "(" + match + "|" + TEST_IFACE_REGEXP + ")" : match; Log.d(TAG, "Interface match regexp set to '" + mIfaceMatch + "'"); } From be2858b9daa1a4c9a7c2743358f3b4f172d97c71 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 12 Jan 2021 16:22:32 +0900 Subject: [PATCH 080/152] [NS01.eth] Remove a useless argument Test: FrameworksNetTests Change-Id: Ib262871e4909ae65b5e6b2e52d2f25bf5a653f34 --- .../com/android/server/ethernet/EthernetNetworkFactory.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 793b284676..3c67927baa 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -87,20 +87,20 @@ public class EthernetNetworkFactory extends NetworkFactory { } @Override - public boolean acceptRequest(NetworkRequest request, int score) { + public boolean acceptRequest(NetworkRequest request) { if (request.type == NetworkRequest.Type.TRACK_DEFAULT) { return false; } if (DBG) { - Log.d(TAG, "acceptRequest, request: " + request + ", score: " + score); + Log.d(TAG, "acceptRequest, request: " + request); } return networkForRequest(request) != null; } @Override - protected void needNetworkFor(NetworkRequest networkRequest, int score) { + protected void needNetworkFor(NetworkRequest networkRequest) { NetworkInterfaceState network = networkForRequest(networkRequest); if (network == null) { From e81b053c1f51ca1e0d77731de8dfeb356d5036d6 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Wed, 20 Jan 2021 18:00:52 +0800 Subject: [PATCH 081/152] Fix EthernetTrackerTest#createNetworkCapabilities aosp/1307433 added NET_CAPABILITY_NOT_ROAMING, NET_CAPABILITY_NOT_CONGESTED and NET_CAPABILITY_NOT_SUSPENDED for ethernet but forgot to run and modify EthernetTrackerTest. Follow aosp/1307433 to add NET_CAPABILITY_NOT_ROAMING, NET_CAPABILITY_NOT_CONGESTED and NET_CAPABILITY_NOT_SUSPENDED for ethernet in test when verifying the network capabilities of ethernet. Bug: 177782157 Test: atest EthernetServiceTests Change-Id: I32c596b1b7726c47818460ea646bf5e346825887 --- .../server/ethernet/EthernetTrackerTest.java | 60 ++++++++++--------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java index 67740b666a..12187889ac 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -133,6 +133,15 @@ public class EthernetTrackerTest { } } + private NetworkCapabilitiesBuilder makeEthernetCapabilitiesBuilder(boolean clearAll) { + final NetworkCapabilitiesBuilder result = + clearAll ? new NetworkCapabilitiesBuilder().clearAll() + : new NetworkCapabilitiesBuilder(); + return result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); + } + /** * Test: Attempt to create a capabilties with various valid sets of capabilities/transports */ @@ -140,23 +149,23 @@ public class EthernetTrackerTest { public void createNetworkCapabilities() { // Particularly common expected results - NetworkCapabilities defaultEthernetCleared = new NetworkCapabilitiesBuilder() - .clearAll() - .setLinkUpstreamBandwidthKbps(100000) - .setLinkDownstreamBandwidthKbps(100000) - .addTransport(NetworkCapabilities.TRANSPORT_ETHERNET) - .build(); + NetworkCapabilities defaultEthernetCleared = + makeEthernetCapabilitiesBuilder(true /* clearAll */) + .setLinkUpstreamBandwidthKbps(100000) + .setLinkDownstreamBandwidthKbps(100000) + .addTransport(NetworkCapabilities.TRANSPORT_ETHERNET) + .build(); - NetworkCapabilities ethernetClearedWithCommonCaps = new NetworkCapabilitiesBuilder() - .clearAll() - .setLinkUpstreamBandwidthKbps(100000) - .setLinkDownstreamBandwidthKbps(100000) - .addTransport(NetworkCapabilities.TRANSPORT_ETHERNET) - .addCapability(12) - .addCapability(13) - .addCapability(14) - .addCapability(15) - .build(); + NetworkCapabilities ethernetClearedWithCommonCaps = + makeEthernetCapabilitiesBuilder(true /* clearAll */) + .setLinkUpstreamBandwidthKbps(100000) + .setLinkDownstreamBandwidthKbps(100000) + .addTransport(NetworkCapabilities.TRANSPORT_ETHERNET) + .addCapability(12) + .addCapability(13) + .addCapability(14) + .addCapability(15) + .build(); // Empty capabilities and transports lists with a "please clear defaults" should // yield an empty capabilities set with TRANPORT_ETHERNET @@ -165,7 +174,7 @@ public class EthernetTrackerTest { // Empty capabilities and transports without the clear defaults flag should return the // default capabilities set with TRANSPORT_ETHERNET assertParsedNetworkCapabilities( - new NetworkCapabilitiesBuilder() + makeEthernetCapabilitiesBuilder(false /* clearAll */) .setLinkUpstreamBandwidthKbps(100000) .setLinkDownstreamBandwidthKbps(100000) .addTransport(NetworkCapabilities.TRANSPORT_ETHERNET) @@ -175,7 +184,7 @@ public class EthernetTrackerTest { // A list of capabilities without the clear defaults flag should return the default // capabilities, mixed with the desired capabilities, and TRANSPORT_ETHERNET assertParsedNetworkCapabilities( - new NetworkCapabilitiesBuilder() + makeEthernetCapabilitiesBuilder(false /* clearAll */) .setLinkUpstreamBandwidthKbps(100000) .setLinkDownstreamBandwidthKbps(100000) .addTransport(NetworkCapabilities.TRANSPORT_ETHERNET) @@ -195,32 +204,28 @@ public class EthernetTrackerTest { // Adding a valid override transport will remove the default TRANSPORT_ETHERNET transport // and apply only the override to the capabiltities object assertParsedNetworkCapabilities( - new NetworkCapabilitiesBuilder() - .clearAll() + makeEthernetCapabilitiesBuilder(true /* clearAll */) .setLinkUpstreamBandwidthKbps(100000) .setLinkDownstreamBandwidthKbps(100000) .addTransport(0) .build(), true, "", "0"); assertParsedNetworkCapabilities( - new NetworkCapabilitiesBuilder() - .clearAll() + makeEthernetCapabilitiesBuilder(true /* clearAll */) .setLinkUpstreamBandwidthKbps(100000) .setLinkDownstreamBandwidthKbps(100000) .addTransport(1) .build(), true, "", "1"); assertParsedNetworkCapabilities( - new NetworkCapabilitiesBuilder() - .clearAll() + makeEthernetCapabilitiesBuilder(true /* clearAll */) .setLinkUpstreamBandwidthKbps(100000) .setLinkDownstreamBandwidthKbps(100000) .addTransport(2) .build(), true, "", "2"); assertParsedNetworkCapabilities( - new NetworkCapabilitiesBuilder() - .clearAll() + makeEthernetCapabilitiesBuilder(true /* clearAll */) .setLinkUpstreamBandwidthKbps(100000) .setLinkDownstreamBandwidthKbps(100000) .addTransport(3) @@ -244,8 +249,7 @@ public class EthernetTrackerTest { // Ensure the adding of both capabilities and transports work assertParsedNetworkCapabilities( - new NetworkCapabilitiesBuilder() - .clearAll() + makeEthernetCapabilitiesBuilder(true /* clearAll */) .setLinkUpstreamBandwidthKbps(100000) .setLinkDownstreamBandwidthKbps(100000) .addCapability(12) From 88f4df8e0fb20c09453841a6d72e6f828a043bbb Mon Sep 17 00:00:00 2001 From: lucaslin Date: Thu, 21 Jan 2021 12:20:00 +0800 Subject: [PATCH 082/152] Replace the usage of NetworkManagementService with NetdUtils Since NetdUtils has the same method(setInterfaceUp) as NetworkManagementService, replace the usage of NMS with NetdUtils. Bug: 170598012 Test: atest EthernetServiceTests Change-Id: Id0f8e17e9d6237fa8ab157c96dd982c47007a453 --- .../com/android/server/ethernet/EthernetTracker.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index d7fd408b69..80c3b97359 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -21,6 +21,7 @@ import static android.net.TestNetworkManager.TEST_TAP_PREFIX; import android.annotation.Nullable; import android.content.Context; import android.net.IEthernetServiceListener; +import android.net.INetd; import android.net.ITetheredInterfaceCallback; import android.net.InterfaceConfiguration; import android.net.IpConfiguration; @@ -28,6 +29,7 @@ import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; import android.net.LinkAddress; import android.net.NetworkCapabilities; +import android.net.NetworkStack; import android.net.StaticIpConfiguration; import android.os.Handler; import android.os.IBinder; @@ -38,14 +40,17 @@ import android.os.ServiceManager; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; +import android.net.util.NetdService; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; +import com.android.net.module.util.NetdUtils; import com.android.server.net.BaseNetworkObserver; import java.io.FileDescriptor; import java.net.InetAddress; import java.util.ArrayList; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; /** @@ -87,6 +92,7 @@ final class EthernetTracker { private final Context mContext; private final INetworkManagementService mNMService; + private final INetd mNetd; private final Handler mHandler; private final EthernetNetworkFactory mFactory; private final EthernetConfigStore mConfigStore; @@ -117,6 +123,7 @@ final class EthernetTracker { // The services we use. IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); mNMService = INetworkManagementService.Stub.asInterface(b); + mNetd = Objects.requireNonNull(NetdService.getInstance(), "could not get netd instance"); // Interface match regex. updateIfaceMatchRegexp(); @@ -280,7 +287,8 @@ final class EthernetTracker { InterfaceConfiguration config = null; // Bring up the interface so we get link status indications. try { - mNMService.setInterfaceUp(iface); + NetworkStack.checkNetworkStackPermission(mContext); + NetdUtils.setInterfaceUp(mNetd, iface); config = mNMService.getInterfaceConfig(iface); } catch (RemoteException | IllegalStateException e) { // Either the system is crashing or the interface has disappeared. Just ignore the From c8148a18d02cb4108f277cc9162ac5fb2ec44b3c Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 28 Jan 2021 14:42:52 +0800 Subject: [PATCH 083/152] [VCN07.4] Add NOT_VCN_MANAGED for NetworkAgent implementations Follow-up from aosp/1549897, the capability will not be in default capabilities, but will be in most of the NetworkRequests which requires internet. Thus, add the capabilities into all NetworkAgent implementations by default to provide backward compatibility. Test: TH Bug: 175662146 Change-Id: Ib6e203571946e3094e4ce534b108f796cc3b8fb7 --- service-t/src/com/android/server/ethernet/EthernetTracker.java | 1 + 1 file changed, 1 insertion(+) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index d7fd408b69..72245afdf8 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -467,6 +467,7 @@ final class EthernetTracker { nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); if (isTestIface) { nc.addTransportType(NetworkCapabilities.TRANSPORT_TEST); From 810d8f0c941b3fa02f78df722c2a07fb6a9b94b7 Mon Sep 17 00:00:00 2001 From: lifr Date: Thu, 28 Jan 2021 19:11:04 +0800 Subject: [PATCH 084/152] [CS02]Remove hidden API usage of NetworkCapabilities The connection service will become the mainline module. The mutable NetworkCapabilities is deprecated, and the NetworkCapabilities should be built through their Builder instead. Bug: 170598012 Test: atest EthernetServiceTests Change-Id: I31f12a39a924302beca980b8d920e3c5c18816d4 --- .../ethernet/EthernetNetworkFactory.java | 12 ++++++++-- .../server/ethernet/EthernetTracker.java | 22 +++++++++---------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 3c67927baa..b9ebf8974e 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -161,12 +161,20 @@ public class EthernetNetworkFactory extends NetworkFactory { 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 = new NetworkCapabilities(); capabilitiesFilter.clearAll(); for (NetworkInterfaceState iface: mTrackingInterfaces.values()) { - capabilitiesFilter.combineCapabilities(iface.mCapabilities); + capabilitiesFilter = mixInCapabilities(capabilitiesFilter, iface.mCapabilities); } if (DBG) Log.d(TAG, "updateCapabilityFilter: " + capabilitiesFilter); @@ -210,7 +218,7 @@ public class EthernetNetworkFactory extends NetworkFactory { private NetworkInterfaceState networkForRequest(NetworkRequest request) { String requestedIface = null; - NetworkSpecifier specifier = request.networkCapabilities.getNetworkSpecifier(); + NetworkSpecifier specifier = request.getNetworkSpecifier(); if (specifier instanceof StringNetworkSpecifier) { requestedIface = ((StringNetworkSpecifier) specifier).specifier; } diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 381f96163d..05b2782216 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -506,9 +506,9 @@ final class EthernetTracker { boolean clearDefaultCapabilities, @Nullable String commaSeparatedCapabilities, @Nullable String overrideTransport) { - NetworkCapabilities nc = new NetworkCapabilities(); + final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); if (clearDefaultCapabilities) { - nc.clearAll(); // Remove default capabilities and transports + builder.clearAll(); // Remove default capabilities and transports } // Determine the transport type. If someone has tried to define an override transport then @@ -536,21 +536,21 @@ final class EthernetTracker { // 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 { - nc.addTransportType(transport); + builder.addTransportType(transport); } catch (IllegalArgumentException iae) { Log.e(TAG, transport + " is not a valid NetworkCapability.TRANSPORT_* value. " + "Defaulting to TRANSPORT_ETHERNET"); - nc.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET); + builder.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET); } - nc.setLinkUpstreamBandwidthKbps(100 * 1000); - nc.setLinkDownstreamBandwidthKbps(100 * 1000); + builder.setLinkUpstreamBandwidthKbps(100 * 1000); + builder.setLinkDownstreamBandwidthKbps(100 * 1000); if (!TextUtils.isEmpty(commaSeparatedCapabilities)) { for (String strNetworkCapability : commaSeparatedCapabilities.split(",")) { if (!TextUtils.isEmpty(strNetworkCapability)) { try { - nc.addCapability(Integer.valueOf(strNetworkCapability)); + builder.addCapability(Integer.valueOf(strNetworkCapability)); } catch (NumberFormatException nfe) { Log.e(TAG, "Capability '" + strNetworkCapability + "' could not be parsed"); } catch (IllegalArgumentException iae) { @@ -562,11 +562,11 @@ final class EthernetTracker { } // Ethernet networks have no way to update the following capabilities, so they always // have them. - nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); - nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); - nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); - return nc; + return builder.build(); } /** From 7909a21be47f96124186cf6cb75472574f5413af Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Fri, 12 Feb 2021 16:14:35 -0800 Subject: [PATCH 085/152] [LSC] Add LOCAL_LICENSE_KINDS to frameworks/opt/net/ethernet Added SPDX-license-identifier-Apache-2.0 to: Android.bp tests/Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: I9e5f4513d6a737c8e31639babd7a4e6342968214 --- tests/ethernet/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/ethernet/Android.bp b/tests/ethernet/Android.bp index 9c776e604f..4b2d270769 100644 --- a/tests/ethernet/Android.bp +++ b/tests/ethernet/Android.bp @@ -13,6 +13,10 @@ // limitations under the License. // +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + android_test { name: "EthernetServiceTests", From 89f2f50aee694106a9512d33da4618a5169ecd63 Mon Sep 17 00:00:00 2001 From: lifr Date: Wed, 3 Mar 2021 23:24:12 +0800 Subject: [PATCH 086/152] [CS07]Remove hidden API usage of NetworkCapabilities The connection service will become the mainline module. The mutable NetworkCapabilities is deprecated, and the NetworkCapabilities should be built through their Builder instead. Bug: 170598012 Test: atest EthernetServiceTests Change-Id: I09661ddda24d652ed791a7c6b093541e20a15e77 --- .../server/ethernet/EthernetTracker.java | 29 ++++---- .../server/ethernet/EthernetTrackerTest.java | 66 +++++-------------- 2 files changed, 30 insertions(+), 65 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 05b2782216..a831f34a5a 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -459,7 +459,7 @@ final class EthernetTracker { String transport = tokens.length > 3 ? tokens[3] : null; NetworkCapabilities nc = createNetworkCapabilities( !TextUtils.isEmpty(capabilities) /* clear default capabilities */, capabilities, - transport); + transport).build(); mNetworkCapabilities.put(name, nc); if (tokens.length > 2 && !TextUtils.isEmpty(tokens[2])) { @@ -469,25 +469,26 @@ final class EthernetTracker { } private static NetworkCapabilities createDefaultNetworkCapabilities(boolean isTestIface) { - NetworkCapabilities nc = createNetworkCapabilities(false /* clear default capabilities */); - nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); - nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); - nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); - nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); - nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); - nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + 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) { - nc.addTransportType(NetworkCapabilities.TRANSPORT_TEST); + builder.addTransportType(NetworkCapabilities.TRANSPORT_TEST); } else { - nc.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); } - return nc; + return builder.build(); } private static NetworkCapabilities createNetworkCapabilities(boolean clearDefaultCapabilities) { - return createNetworkCapabilities(clearDefaultCapabilities, null, null); + return createNetworkCapabilities(clearDefaultCapabilities, null, null).build(); } /** @@ -502,7 +503,7 @@ final class EthernetTracker { * will cause the override to be ignored. */ @VisibleForTesting - static NetworkCapabilities createNetworkCapabilities( + static NetworkCapabilities.Builder createNetworkCapabilities( boolean clearDefaultCapabilities, @Nullable String commaSeparatedCapabilities, @Nullable String overrideTransport) { @@ -566,7 +567,7 @@ final class EthernetTracker { builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); - return builder.build(); + return builder; } /** diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java index 12187889ac..43571bbc37 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -133,11 +133,11 @@ public class EthernetTrackerTest { } } - private NetworkCapabilitiesBuilder makeEthernetCapabilitiesBuilder(boolean clearAll) { - final NetworkCapabilitiesBuilder result = - clearAll ? new NetworkCapabilitiesBuilder().clearAll() - : new NetworkCapabilitiesBuilder(); - return result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) + private NetworkCapabilities.Builder makeEthernetCapabilitiesBuilder(boolean clearAll) { + final NetworkCapabilities.Builder builder = + clearAll ? new NetworkCapabilities.Builder().clearAll() + : new NetworkCapabilities.Builder(); + return builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED) .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); } @@ -153,14 +153,14 @@ public class EthernetTrackerTest { makeEthernetCapabilitiesBuilder(true /* clearAll */) .setLinkUpstreamBandwidthKbps(100000) .setLinkDownstreamBandwidthKbps(100000) - .addTransport(NetworkCapabilities.TRANSPORT_ETHERNET) + .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) .build(); NetworkCapabilities ethernetClearedWithCommonCaps = makeEthernetCapabilitiesBuilder(true /* clearAll */) .setLinkUpstreamBandwidthKbps(100000) .setLinkDownstreamBandwidthKbps(100000) - .addTransport(NetworkCapabilities.TRANSPORT_ETHERNET) + .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) .addCapability(12) .addCapability(13) .addCapability(14) @@ -177,7 +177,7 @@ public class EthernetTrackerTest { makeEthernetCapabilitiesBuilder(false /* clearAll */) .setLinkUpstreamBandwidthKbps(100000) .setLinkDownstreamBandwidthKbps(100000) - .addTransport(NetworkCapabilities.TRANSPORT_ETHERNET) + .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) .build(), false, "", ""); @@ -187,7 +187,7 @@ public class EthernetTrackerTest { makeEthernetCapabilitiesBuilder(false /* clearAll */) .setLinkUpstreamBandwidthKbps(100000) .setLinkDownstreamBandwidthKbps(100000) - .addTransport(NetworkCapabilities.TRANSPORT_ETHERNET) + .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) .addCapability(11) .addCapability(12) .build(), @@ -207,28 +207,28 @@ public class EthernetTrackerTest { makeEthernetCapabilitiesBuilder(true /* clearAll */) .setLinkUpstreamBandwidthKbps(100000) .setLinkDownstreamBandwidthKbps(100000) - .addTransport(0) + .addTransportType(0) .build(), true, "", "0"); assertParsedNetworkCapabilities( makeEthernetCapabilitiesBuilder(true /* clearAll */) .setLinkUpstreamBandwidthKbps(100000) .setLinkDownstreamBandwidthKbps(100000) - .addTransport(1) + .addTransportType(1) .build(), true, "", "1"); assertParsedNetworkCapabilities( makeEthernetCapabilitiesBuilder(true /* clearAll */) .setLinkUpstreamBandwidthKbps(100000) .setLinkDownstreamBandwidthKbps(100000) - .addTransport(2) + .addTransportType(2) .build(), true, "", "2"); assertParsedNetworkCapabilities( makeEthernetCapabilitiesBuilder(true /* clearAll */) .setLinkUpstreamBandwidthKbps(100000) .setLinkDownstreamBandwidthKbps(100000) - .addTransport(3) + .addTransportType(3) .build(), true, "", "3"); @@ -256,7 +256,7 @@ public class EthernetTrackerTest { .addCapability(13) .addCapability(14) .addCapability(15) - .addTransport(3) + .addTransportType(3) .build(), true, "12,13,14,15", "3"); @@ -268,42 +268,6 @@ public class EthernetTrackerTest { boolean clearCapabilties, String configCapabiltiies,String configTransports) { assertEquals(expectedNetworkCapabilities, EthernetTracker.createNetworkCapabilities(clearCapabilties, configCapabiltiies, - configTransports)); - } - - private static class NetworkCapabilitiesBuilder { - private final NetworkCapabilities nc = new NetworkCapabilities(); - - NetworkCapabilitiesBuilder clearAll(){ - // This is THE ONLY one that doesn't return a reference to the object so I wrapped - // everything in a builder to keep things consistent and clean above. Fix if this - // ever changes - nc.clearAll(); - return this; - } - - NetworkCapabilitiesBuilder addCapability(int capability) { - nc.addCapability(capability); - return this; - } - - NetworkCapabilitiesBuilder addTransport(int transport) { - nc.addTransportType(transport); - return this; - } - - NetworkCapabilitiesBuilder setLinkUpstreamBandwidthKbps(int upKbps) { - nc.setLinkUpstreamBandwidthKbps(upKbps); - return this; - } - - NetworkCapabilitiesBuilder setLinkDownstreamBandwidthKbps(int downKbps) { - nc.setLinkDownstreamBandwidthKbps(downKbps); - return this; - } - - NetworkCapabilities build() { - return new NetworkCapabilities(nc); - } + configTransports).build()); } } From 12c81113109c20c730b66e8c33df948c231cb9f0 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 4 Feb 2021 16:36:24 +0900 Subject: [PATCH 087/152] Rename StringNetworkSpecifier to Ethernet The new specifier represents ethernet interfaces more specifically and is part of the public API. Bug: 179329291 Test: atest CtsNetTestCases Change-Id: I6cba1709b3007a22d95849a1281237c77e1464a4 --- .../android/server/ethernet/EthernetNetworkFactory.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index b9ebf8974e..dba152cc4e 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -23,6 +23,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.ConnectivityManager; +import android.net.EthernetNetworkSpecifier; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; @@ -33,7 +34,6 @@ import android.net.NetworkCapabilities; import android.net.NetworkFactory; import android.net.NetworkRequest; import android.net.NetworkSpecifier; -import android.net.StringNetworkSpecifier; import android.net.ip.IIpClient; import android.net.ip.IpClientCallbacks; import android.net.ip.IpClientUtil; @@ -219,8 +219,9 @@ public class EthernetNetworkFactory extends NetworkFactory { String requestedIface = null; NetworkSpecifier specifier = request.getNetworkSpecifier(); - if (specifier instanceof StringNetworkSpecifier) { - requestedIface = ((StringNetworkSpecifier) specifier).specifier; + if (specifier instanceof EthernetNetworkSpecifier) { + requestedIface = ((EthernetNetworkSpecifier) specifier) + .getInterfaceName(); } NetworkInterfaceState network = null; From a8371991954e4c3e6e4d3f482440f25968bb1075 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 4 Feb 2021 16:36:24 +0900 Subject: [PATCH 088/152] Rename StringNetworkSpecifier to Ethernet The new specifier represents ethernet interfaces more specifically and is part of the public API. Bug: 179329291 Test: atest CtsNetTestCases Merged-In: I6cba1709b3007a22d95849a1281237c77e1464a4 Change-Id: I6cba1709b3007a22d95849a1281237c77e1464a4 --- .../android/server/ethernet/EthernetNetworkFactory.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index b9ebf8974e..dba152cc4e 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -23,6 +23,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.ConnectivityManager; +import android.net.EthernetNetworkSpecifier; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; @@ -33,7 +34,6 @@ import android.net.NetworkCapabilities; import android.net.NetworkFactory; import android.net.NetworkRequest; import android.net.NetworkSpecifier; -import android.net.StringNetworkSpecifier; import android.net.ip.IIpClient; import android.net.ip.IpClientCallbacks; import android.net.ip.IpClientUtil; @@ -219,8 +219,9 @@ public class EthernetNetworkFactory extends NetworkFactory { String requestedIface = null; NetworkSpecifier specifier = request.getNetworkSpecifier(); - if (specifier instanceof StringNetworkSpecifier) { - requestedIface = ((StringNetworkSpecifier) specifier).specifier; + if (specifier instanceof EthernetNetworkSpecifier) { + requestedIface = ((EthernetNetworkSpecifier) specifier) + .getInterfaceName(); } NetworkInterfaceState network = null; From 60ce2ec1682acda638b621ea82734f77547ca017 Mon Sep 17 00:00:00 2001 From: lifr Date: Thu, 4 Mar 2021 00:35:22 +0800 Subject: [PATCH 089/152] [CS09]Remove hidden API usage of NetworkRequest The connection service will become the mainline module. So, need to remove the hidden API usage of NetworkRequest. The NetworkRequest.type(TRACK_DEFAULT) is no longer sent to the factories. So, remove the (TRACK_DEFAULT) check to avoid using hidden API. Bug: 170598012 Test: atest EthernetServiceTests Change-Id: I5b5fed864318e9ac7e190c40d4f52076ab0eece8 --- .../com/android/server/ethernet/EthernetNetworkFactory.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index b9ebf8974e..242fac8d8c 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -88,10 +88,6 @@ public class EthernetNetworkFactory extends NetworkFactory { @Override public boolean acceptRequest(NetworkRequest request) { - if (request.type == NetworkRequest.Type.TRACK_DEFAULT) { - return false; - } - if (DBG) { Log.d(TAG, "acceptRequest, request: " + request); } From df51759103a2a3dab54b56ccb25dfb5ac33f8cb4 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Thu, 18 Mar 2021 14:45:22 +0800 Subject: [PATCH 090/152] Use clearAll() of NetworkCapabilities.Builder instead NetworkCapabilities#clearAll() is a hidden API, use clearAll() of NetworkCapabilities.Builder instead. Bug: 182963415 Test: m ethernet-service Test: atest EthernetServiceTests Change-Id: I87745b5f7a5817f95cdbc623b2313c181ff48f19 --- .../com/android/server/ethernet/EthernetNetworkFactory.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index d17595ac9f..ad48844224 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -166,8 +166,9 @@ public class EthernetNetworkFactory extends NetworkFactory { } private void updateCapabilityFilter() { - NetworkCapabilities capabilitiesFilter = new NetworkCapabilities(); - capabilitiesFilter.clearAll(); + NetworkCapabilities capabilitiesFilter = new NetworkCapabilities.Builder() + .clearAll() + .build(); for (NetworkInterfaceState iface: mTrackingInterfaces.values()) { capabilitiesFilter = mixInCapabilities(capabilitiesFilter, iface.mCapabilities); From 89764da1322c40cbdc9712dfe7c89bd54cf56830 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 19 Mar 2021 14:09:44 +0800 Subject: [PATCH 091/152] Replace references of request.networkCapabilies Replaced by request.canBesatisfiedBy() to avoid direct reference of hidden member. Bug: 182963415 Test: m ethernet-service Test: atest EthernetServiceTests Change-Id: I2a27410a6148c525e17a11cb1ba3570f04e60b5d --- .../android/server/ethernet/EthernetNetworkFactory.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index ad48844224..89334ba01a 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -17,6 +17,7 @@ package com.android.server.ethernet; import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable; + import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; @@ -50,8 +51,8 @@ import android.util.SparseArray; import com.android.internal.util.IndentingPrintWriter; import java.io.FileDescriptor; -import java.util.concurrent.ConcurrentHashMap; import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; /** * {@link NetworkFactory} that represents Ethernet networks. @@ -224,12 +225,12 @@ public class EthernetNetworkFactory extends NetworkFactory { NetworkInterfaceState network = null; if (!TextUtils.isEmpty(requestedIface)) { NetworkInterfaceState n = mTrackingInterfaces.get(requestedIface); - if (n != null && n.satisfied(request.networkCapabilities)) { + if (n != null && request.canBeSatisfiedBy(n.mCapabilities)) { network = n; } } else { for (NetworkInterfaceState n : mTrackingInterfaces.values()) { - if (n.satisfied(request.networkCapabilities) && n.mLinkUp) { + if (request.canBeSatisfiedBy(n.mCapabilities) && n.mLinkUp) { network = n; break; } From c439eae5b49e7d01affd5eaa887f5e9c7b54c3df Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 19 Mar 2021 14:15:39 +0800 Subject: [PATCH 092/152] Replace reference of NetworkAgent#setLegacyExtraInfo Bug: 182963415 Test: m ethernet-service Test: atest EthernetServiceTests Change-Id: I4a66f34daa129b3158e4dd2fb720c175611eaf69 --- .../src/com/android/server/ethernet/EthernetNetworkFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 89334ba01a..75e77b9596 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -473,6 +473,7 @@ public class EthernetNetworkFactory extends NetworkFactory { final NetworkAgentConfig config = new NetworkAgentConfig.Builder() .setLegacyType(mLegacyType) .setLegacyTypeName(NETWORK_TYPE) + .setLegacyExtraInfo(mHwAddress) .build(); mNetworkAgent = new NetworkAgent(mContext, mHandler.getLooper(), NETWORK_TYPE, mCapabilities, mLinkProperties, @@ -487,7 +488,6 @@ public class EthernetNetworkFactory extends NetworkFactory { } }; mNetworkAgent.register(); - mNetworkAgent.setLegacyExtraInfo(mHwAddress); mNetworkAgent.markConnected(); } From 4a0cbe98c1bb9ef45d098abfb3ade0135a9768c2 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Fri, 19 Mar 2021 15:14:23 +0800 Subject: [PATCH 093/152] Use public API instead of hidden API in EthernetTracker - Use public API of StaticIpConfiguration.Builder to set ipaddress, domains, gateway and dnsServers. - Use public constructor to create an instance of IpConfiguration and set IpAssignment, ProxySettings, StaticIpConfiguration and HttpProxy by public API. Bug: 182963415 Test: m ethernet-service Change-Id: Idce8bfe7afc31baa644c816afa1f8004987e8c6e --- .../server/ethernet/EthernetTracker.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index a831f34a5a..a190240edb 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -579,7 +579,8 @@ final class EthernetTracker { */ @VisibleForTesting static IpConfiguration parseStaticIpConfiguration(String staticIpConfig) { - StaticIpConfiguration ipConfig = new StaticIpConfiguration(); + final StaticIpConfiguration.Builder staticIpConfigBuilder = + new StaticIpConfiguration.Builder(); for (String keyValueAsString : staticIpConfig.trim().split(" ")) { if (TextUtils.isEmpty(keyValueAsString)) continue; @@ -595,20 +596,20 @@ final class EthernetTracker { switch (key) { case "ip": - ipConfig.ipAddress = new LinkAddress(value); + staticIpConfigBuilder.setIpAddress(new LinkAddress(value)); break; case "domains": - ipConfig.domains = value; + staticIpConfigBuilder.setDomains(value); break; case "gateway": - ipConfig.gateway = InetAddress.parseNumericAddress(value); + staticIpConfigBuilder.setGateway(InetAddress.parseNumericAddress(value)); break; case "dns": { ArrayList dnsAddresses = new ArrayList<>(); for (String address: value.split(",")) { dnsAddresses.add(InetAddress.parseNumericAddress(address)); } - ipConfig.dnsServers.addAll(dnsAddresses); + staticIpConfigBuilder.setDnsServers(dnsAddresses); break; } default : { @@ -617,11 +618,18 @@ final class EthernetTracker { } } } - return new IpConfiguration(IpAssignment.STATIC, ProxySettings.NONE, ipConfig, null); + final IpConfiguration ret = new IpConfiguration(); + ret.setIpAssignment(IpAssignment.STATIC); + ret.setProxySettings(ProxySettings.NONE); + ret.setStaticIpConfiguration(staticIpConfigBuilder.build()); + return ret; } private static IpConfiguration createDefaultIpConfiguration() { - return new IpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, null, null); + final IpConfiguration ret = new IpConfiguration(); + ret.setIpAssignment(IpAssignment.DHCP); + ret.setProxySettings(ProxySettings.NONE); + return ret; } private void updateIfaceMatchRegexp() { From 19b7b3dfbd9173ff7d1b0d0226052757b02b2847 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Fri, 19 Mar 2021 15:14:23 +0800 Subject: [PATCH 094/152] Use public API instead of hidden API in EthernetTracker - Use public API of StaticIpConfiguration.Builder to set ipaddress, domains, gateway and dnsServers. - Use public constructor to create an instance of IpConfiguration and set IpAssignment, ProxySettings, StaticIpConfiguration and HttpProxy by public API. Bug: 182963415 Test: m ethernet-service Change-Id: Idce8bfe7afc31baa644c816afa1f8004987e8c6e Merged-In: Idce8bfe7afc31baa644c816afa1f8004987e8c6e --- .../server/ethernet/EthernetTracker.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index a831f34a5a..a190240edb 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -579,7 +579,8 @@ final class EthernetTracker { */ @VisibleForTesting static IpConfiguration parseStaticIpConfiguration(String staticIpConfig) { - StaticIpConfiguration ipConfig = new StaticIpConfiguration(); + final StaticIpConfiguration.Builder staticIpConfigBuilder = + new StaticIpConfiguration.Builder(); for (String keyValueAsString : staticIpConfig.trim().split(" ")) { if (TextUtils.isEmpty(keyValueAsString)) continue; @@ -595,20 +596,20 @@ final class EthernetTracker { switch (key) { case "ip": - ipConfig.ipAddress = new LinkAddress(value); + staticIpConfigBuilder.setIpAddress(new LinkAddress(value)); break; case "domains": - ipConfig.domains = value; + staticIpConfigBuilder.setDomains(value); break; case "gateway": - ipConfig.gateway = InetAddress.parseNumericAddress(value); + staticIpConfigBuilder.setGateway(InetAddress.parseNumericAddress(value)); break; case "dns": { ArrayList dnsAddresses = new ArrayList<>(); for (String address: value.split(",")) { dnsAddresses.add(InetAddress.parseNumericAddress(address)); } - ipConfig.dnsServers.addAll(dnsAddresses); + staticIpConfigBuilder.setDnsServers(dnsAddresses); break; } default : { @@ -617,11 +618,18 @@ final class EthernetTracker { } } } - return new IpConfiguration(IpAssignment.STATIC, ProxySettings.NONE, ipConfig, null); + final IpConfiguration ret = new IpConfiguration(); + ret.setIpAssignment(IpAssignment.STATIC); + ret.setProxySettings(ProxySettings.NONE); + ret.setStaticIpConfiguration(staticIpConfigBuilder.build()); + return ret; } private static IpConfiguration createDefaultIpConfiguration() { - return new IpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, null, null); + final IpConfiguration ret = new IpConfiguration(); + ret.setIpAssignment(IpAssignment.DHCP); + ret.setProxySettings(ProxySettings.NONE); + return ret; } private void updateIfaceMatchRegexp() { From 4450c1542bb79273b5e194fc3cb1a7a57eb5ed0e Mon Sep 17 00:00:00 2001 From: lucaslin Date: Tue, 30 Mar 2021 16:54:45 +0800 Subject: [PATCH 095/152] Add transport type in capabilities filter of EthernetNetworkFacotry Bug: 167544279 Test: atest EthernetServiceTests Change-Id: Ie64e3cff0ace413f14682736de7a1b65fa93e705 --- .../src/com/android/server/ethernet/EthernetNetworkFactory.java | 1 + 1 file changed, 1 insertion(+) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 75e77b9596..f9e8b00562 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -169,6 +169,7 @@ public class EthernetNetworkFactory extends NetworkFactory { private void updateCapabilityFilter() { NetworkCapabilities capabilitiesFilter = new NetworkCapabilities.Builder() .clearAll() + .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) .build(); for (NetworkInterfaceState iface: mTrackingInterfaces.values()) { From 58e0c49c2ecf0707f67b6db71471e91ee86a3d11 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Wed, 14 Apr 2021 16:31:37 +0800 Subject: [PATCH 096/152] Remove hidden connectivity methods usage in ethernet test Bug: 182859030 Test: atest EthernetTrackerTest Test: 1. remove framework-connectivity.impl from framework bp 2. cd frameworks/opt/net/ethernet/tests ; mm Change-Id: Ifaeebfca75dc77eec30dd722ddb3166610795b26 --- .../server/ethernet/EthernetTrackerTest.java | 70 ++++++------------- 1 file changed, 21 insertions(+), 49 deletions(-) diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java index 43571bbc37..22b1b6939e 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -19,6 +19,7 @@ package com.android.server.ethernet; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import android.net.InetAddresses; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; @@ -33,6 +34,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.net.InetAddress; +import java.util.ArrayList; @SmallTest @RunWith(AndroidJUnit4.class) @@ -46,28 +48,26 @@ public class EthernetTrackerTest { assertStaticConfiguration(new StaticIpConfiguration(), ""); // Setting only the IP address properly cascades and assumes defaults - assertStaticConfiguration( - new StaticIpConfigBuilder().setIp("192.0.2.10/24").build(), - "ip=192.0.2.10/24"); + assertStaticConfiguration(new StaticIpConfiguration.Builder() + .setIpAddress(new LinkAddress("192.0.2.10/24")).build(), "ip=192.0.2.10/24"); + final ArrayList dnsAddresses = new ArrayList<>(); + dnsAddresses.add(InetAddresses.parseNumericAddress("4.4.4.4")); + dnsAddresses.add(InetAddresses.parseNumericAddress("8.8.8.8")); // Setting other fields properly cascades them - assertStaticConfiguration( - new StaticIpConfigBuilder() - .setIp("192.0.2.10/24") - .setDns(new String[] {"4.4.4.4", "8.8.8.8"}) - .setGateway("192.0.2.1") - .setDomains("android") - .build(), + assertStaticConfiguration(new StaticIpConfiguration.Builder() + .setIpAddress(new LinkAddress("192.0.2.10/24")) + .setDnsServers(dnsAddresses) + .setGateway(InetAddresses.parseNumericAddress("192.0.2.1")) + .setDomains("android").build(), "ip=192.0.2.10/24 dns=4.4.4.4,8.8.8.8 gateway=192.0.2.1 domains=android"); // Verify order doesn't matter - assertStaticConfiguration( - new StaticIpConfigBuilder() - .setIp("192.0.2.10/24") - .setDns(new String[] {"4.4.4.4", "8.8.8.8"}) - .setGateway("192.0.2.1") - .setDomains("android") - .build(), + assertStaticConfiguration(new StaticIpConfiguration.Builder() + .setIpAddress(new LinkAddress("192.0.2.10/24")) + .setDnsServers(dnsAddresses) + .setGateway(InetAddresses.parseNumericAddress("192.0.2.1")) + .setDomains("android").build(), "domains=android ip=192.0.2.10/24 gateway=192.0.2.1 dns=4.4.4.4,8.8.8.8 "); } @@ -96,43 +96,15 @@ public class EthernetTrackerTest { private void assertStaticConfiguration(StaticIpConfiguration expectedStaticIpConfig, String configAsString) { - IpConfiguration expectedIpConfiguration = new IpConfiguration(IpAssignment.STATIC, - ProxySettings.NONE, expectedStaticIpConfig, null); + final IpConfiguration expectedIpConfiguration = new IpConfiguration(); + expectedIpConfiguration.setIpAssignment(IpAssignment.STATIC); + expectedIpConfiguration.setProxySettings(ProxySettings.NONE); + expectedIpConfiguration.setStaticIpConfiguration(expectedStaticIpConfig); assertEquals(expectedIpConfiguration, EthernetTracker.parseStaticIpConfiguration(configAsString)); } - private static class StaticIpConfigBuilder { - private final StaticIpConfiguration config = new StaticIpConfiguration(); - - StaticIpConfigBuilder setIp(String address) { - config.ipAddress = new LinkAddress(address); - return this; - } - - StaticIpConfigBuilder setDns(String[] dnsArray) { - for (String dns : dnsArray) { - config.dnsServers.add(InetAddress.parseNumericAddress(dns)); - } - return this; - } - - StaticIpConfigBuilder setGateway(String gateway) { - config.gateway = InetAddress.parseNumericAddress(gateway); - return this; - } - - StaticIpConfigBuilder setDomains(String domains) { - config.domains = domains; - return this; - } - - StaticIpConfiguration build() { - return new StaticIpConfiguration(config); - } - } - private NetworkCapabilities.Builder makeEthernetCapabilitiesBuilder(boolean clearAll) { final NetworkCapabilities.Builder builder = clearAll ? new NetworkCapabilities.Builder().clearAll() From 3056b7418bfc37b601b52c90fcdd8cb1fd97e37e Mon Sep 17 00:00:00 2001 From: paulhu Date: Tue, 30 Mar 2021 10:55:37 +0800 Subject: [PATCH 097/152] Enforce ACCESS_NETWORK_STATE to getAvailableInterfaces() getAvailableInterfaces() will return available ethernet interfaces which are the information about networks. So it should enforce ACCESS_NETWORK_STATE permission check to ensure the applications are allowed to access the information. Bug: 174573778 Test: TetheringTests Test: CtsTetheringTest Change-Id: I7aaa5225d56f2feecc51ba263489ed0ce02fd651 --- .../src/com/android/server/ethernet/EthernetServiceImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 3fc6aab758..c06f61e446 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -87,6 +87,8 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Override public String[] getAvailableInterfaces() throws RemoteException { + enforceAccessPermission(); + return mTracker.getInterfaces(checkUseRestrictedNetworksPermission()); } From fe134fbd9cd448c452aa28194eb5dcb9ce83d135 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Tue, 30 Mar 2021 16:54:45 +0800 Subject: [PATCH 098/152] Add transport type in capabilities filter of EthernetNetworkFacotry Bug: 167544279 Test: atest EthernetServiceTests Change-Id: Ie64e3cff0ace413f14682736de7a1b65fa93e705 Merged-In: Ie64e3cff0ace413f14682736de7a1b65fa93e705 (Cherry-picked from ag/14031548) --- .../src/com/android/server/ethernet/EthernetNetworkFactory.java | 1 + 1 file changed, 1 insertion(+) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 75e77b9596..f9e8b00562 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -169,6 +169,7 @@ public class EthernetNetworkFactory extends NetworkFactory { private void updateCapabilityFilter() { NetworkCapabilities capabilitiesFilter = new NetworkCapabilities.Builder() .clearAll() + .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) .build(); for (NetworkInterfaceState iface: mTrackingInterfaces.values()) { From 6d8141caa14772668a95375df33f60f1b84b59d7 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Thu, 13 May 2021 10:21:59 +0800 Subject: [PATCH 099/152] Replace clearAll with withoutDefaultCapabilities in NC#Builder Update the naming and usgae according to API review feedback. Bug: 184735772 Test: atest EthernetTrackerTest Change-Id: Ie8dc0bcdf46ceebda5d6062231b48c1f63b250f6 --- .../android/server/ethernet/EthernetNetworkFactory.java | 4 ++-- .../src/com/android/server/ethernet/EthernetTracker.java | 7 +++---- .../com/android/server/ethernet/EthernetTrackerTest.java | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index f9e8b00562..aa80e4de2d 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -167,8 +167,8 @@ public class EthernetNetworkFactory extends NetworkFactory { } private void updateCapabilityFilter() { - NetworkCapabilities capabilitiesFilter = new NetworkCapabilities.Builder() - .clearAll() + NetworkCapabilities capabilitiesFilter = + NetworkCapabilities.Builder.withoutDefaultCapabilities() .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) .build(); diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index a190240edb..b2b60fcb83 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -507,10 +507,9 @@ final class EthernetTracker { boolean clearDefaultCapabilities, @Nullable String commaSeparatedCapabilities, @Nullable String overrideTransport) { - final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); - if (clearDefaultCapabilities) { - builder.clearAll(); // Remove default capabilities and transports - } + 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 diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java index 22b1b6939e..ee9f349a28 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -107,7 +107,7 @@ public class EthernetTrackerTest { private NetworkCapabilities.Builder makeEthernetCapabilitiesBuilder(boolean clearAll) { final NetworkCapabilities.Builder builder = - clearAll ? new NetworkCapabilities.Builder().clearAll() + clearAll ? NetworkCapabilities.Builder.withoutDefaultCapabilities() : new NetworkCapabilities.Builder(); return builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED) From bbd8b43c93c383f785a89721f476f405579e7ba7 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Thu, 13 May 2021 10:21:59 +0800 Subject: [PATCH 100/152] Replace clearAll with withoutDefaultCapabilities in NC#Builder Update the naming and usgae according to API review feedback. Bug: 184735772 Test: atest EthernetTrackerTest Change-Id: Ie8dc0bcdf46ceebda5d6062231b48c1f63b250f6 Merged-In: Ie8dc0bcdf46ceebda5d6062231b48c1f63b250f6 --- .../android/server/ethernet/EthernetNetworkFactory.java | 4 ++-- .../src/com/android/server/ethernet/EthernetTracker.java | 7 +++---- .../com/android/server/ethernet/EthernetTrackerTest.java | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index f9e8b00562..aa80e4de2d 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -167,8 +167,8 @@ public class EthernetNetworkFactory extends NetworkFactory { } private void updateCapabilityFilter() { - NetworkCapabilities capabilitiesFilter = new NetworkCapabilities.Builder() - .clearAll() + NetworkCapabilities capabilitiesFilter = + NetworkCapabilities.Builder.withoutDefaultCapabilities() .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) .build(); diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index a190240edb..b2b60fcb83 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -507,10 +507,9 @@ final class EthernetTracker { boolean clearDefaultCapabilities, @Nullable String commaSeparatedCapabilities, @Nullable String overrideTransport) { - final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); - if (clearDefaultCapabilities) { - builder.clearAll(); // Remove default capabilities and transports - } + 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 diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java index 22b1b6939e..ee9f349a28 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -107,7 +107,7 @@ public class EthernetTrackerTest { private NetworkCapabilities.Builder makeEthernetCapabilitiesBuilder(boolean clearAll) { final NetworkCapabilities.Builder builder = - clearAll ? new NetworkCapabilities.Builder().clearAll() + clearAll ? NetworkCapabilities.Builder.withoutDefaultCapabilities() : new NetworkCapabilities.Builder(); return builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED) From 0e077cb1d59c92bc0bba13af3d0cf805ca163937 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sat, 12 Jun 2021 00:41:14 +0900 Subject: [PATCH 101/152] Stop using LinkPropertiesParcelableUtil. Its methods are all no-ops. Stop using them. Test: m Bug: 151052811 Change-Id: Iace3ba898bec2940ec3c3323c5bf8a13627d545f --- .../com/android/server/ethernet/EthernetNetworkFactory.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index aa80e4de2d..28b24f1fb1 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -16,8 +16,6 @@ package com.android.server.ethernet; -import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable; - import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; @@ -560,7 +558,7 @@ public class EthernetNetworkFactory extends NetworkFactory { if (config.getProxySettings() == ProxySettings.STATIC || config.getProxySettings() == ProxySettings.PAC) { try { - ipClient.setHttpProxy(toStableParcelable(config.getHttpProxy())); + ipClient.setHttpProxy(config.getHttpProxy()); } catch (RemoteException e) { e.rethrowFromSystemServer(); } From 75f629ace72451d2d73d3fa22e021a6325f9c20f Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 21 Jun 2021 10:34:48 +0000 Subject: [PATCH 102/152] Stop using LinkPropertiesParcelableUtil. Its methods are all no-ops. Stop using them. Test: m Bug: 151052811 Original-Change: https://android-review.googlesource.com/1733473 Merged-In: Iace3ba898bec2940ec3c3323c5bf8a13627d545f Change-Id: Iace3ba898bec2940ec3c3323c5bf8a13627d545f --- .../com/android/server/ethernet/EthernetNetworkFactory.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index aa80e4de2d..28b24f1fb1 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -16,8 +16,6 @@ package com.android.server.ethernet; -import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable; - import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; @@ -560,7 +558,7 @@ public class EthernetNetworkFactory extends NetworkFactory { if (config.getProxySettings() == ProxySettings.STATIC || config.getProxySettings() == ProxySettings.PAC) { try { - ipClient.setHttpProxy(toStableParcelable(config.getHttpProxy())); + ipClient.setHttpProxy(config.getHttpProxy()); } catch (RemoteException e) { e.rethrowFromSystemServer(); } From 007d976b7c6c96974ada1f0fd8d9a489865dea55 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 21 Jun 2021 10:34:48 +0000 Subject: [PATCH 103/152] Stop using LinkPropertiesParcelableUtil. Its methods are all no-ops. Stop using them. Test: m Bug: 151052811 Original-Change: https://android-review.googlesource.com/1733473 Merged-In: Iace3ba898bec2940ec3c3323c5bf8a13627d545f Change-Id: Iace3ba898bec2940ec3c3323c5bf8a13627d545f --- .../com/android/server/ethernet/EthernetNetworkFactory.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index aa80e4de2d..28b24f1fb1 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -16,8 +16,6 @@ package com.android.server.ethernet; -import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable; - import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; @@ -560,7 +558,7 @@ public class EthernetNetworkFactory extends NetworkFactory { if (config.getProxySettings() == ProxySettings.STATIC || config.getProxySettings() == ProxySettings.PAC) { try { - ipClient.setHttpProxy(toStableParcelable(config.getHttpProxy())); + ipClient.setHttpProxy(config.getHttpProxy()); } catch (RemoteException e) { e.rethrowFromSystemServer(); } From e78e8828d6322959240ee51e017a9fe336c8c2e1 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 4 Nov 2020 17:04:21 +0100 Subject: [PATCH 104/152] Add Tests for EthernetNetworkFactory Test: atest EthernetNetworkFactoryTest Bug: 191635995 Change-Id: I1c07bb6d30706c4e13002eb402fadfecb97b36d1 --- .../server/ethernet/EthernetNetworkAgent.java | 65 +++ .../ethernet/EthernetNetworkFactory.java | 72 +++- tests/ethernet/Android.bp | 4 + tests/ethernet/AndroidManifest.xml | 2 +- .../ethernet/EthernetNetworkFactoryTest.java | 395 ++++++++++++++++++ 5 files changed, 517 insertions(+), 21 deletions(-) create mode 100644 service-t/src/com/android/server/ethernet/EthernetNetworkAgent.java create mode 100644 tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkAgent.java b/service-t/src/com/android/server/ethernet/EthernetNetworkAgent.java new file mode 100644 index 0000000000..5598fc6a11 --- /dev/null +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkAgent.java @@ -0,0 +1,65 @@ +/* + * 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.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, + int networkScore, + @NonNull NetworkAgentConfig config, + @Nullable NetworkProvider provider, + @NonNull Callbacks cb) { + super(context, looper, TAG, nc, lp, networkScore, 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/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 28b24f1fb1..f4de23d7d3 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -27,10 +27,10 @@ import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; import android.net.LinkProperties; -import android.net.NetworkAgent; 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; @@ -40,12 +40,14 @@ import android.net.shared.ProvisioningConfiguration; import android.net.util.InterfaceParams; 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.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import java.io.FileDescriptor; @@ -69,6 +71,25 @@ public class EthernetNetworkFactory extends NetworkFactory { 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 EthernetNetworkAgent makeEthernetNetworkAgent(Context context, Looper looper, + NetworkCapabilities nc, LinkProperties lp, int networkScore, + NetworkAgentConfig config, NetworkProvider provider, + EthernetNetworkAgent.Callbacks cb) { + return new EthernetNetworkAgent(context, looper, nc, lp, networkScore, config, provider, + cb); + } + + public InterfaceParams getNetworkInterfaceByName(String name) { + return InterfaceParams.getByName(name); + } + } public static class ConfigurationException extends AndroidRuntimeException { public ConfigurationException(String msg) { @@ -77,10 +98,17 @@ public class EthernetNetworkFactory extends NetworkFactory { } public EthernetNetworkFactory(Handler handler, Context context, NetworkCapabilities filter) { + this(handler, context, filter, new Dependencies()); + } + + @VisibleForTesting + EthernetNetworkFactory(Handler handler, Context context, NetworkCapabilities filter, + Dependencies deps) { super(handler.getLooper(), context, NETWORK_TYPE, filter); mHandler = handler; mContext = context; + mDeps = deps; setScoreFilter(NETWORK_SCORE); } @@ -149,7 +177,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } NetworkInterfaceState iface = new NetworkInterfaceState( - ifaceName, hwAddress, mHandler, mContext, capabilities, this); + ifaceName, hwAddress, mHandler, mContext, capabilities, this, mDeps); iface.setIpConfig(ipConfiguration); mTrackingInterfaces.put(ifaceName, iface); @@ -251,6 +279,7 @@ public class EthernetNetworkFactory extends NetworkFactory { private final Handler mHandler; private final Context mContext; private final NetworkFactory mNetworkFactory; + private final Dependencies mDeps; private final int mLegacyType; private static String sTcpBufferSizes = null; // Lazy initialized. @@ -260,7 +289,7 @@ public class EthernetNetworkFactory extends NetworkFactory { private volatile @Nullable IIpClient mIpClient; private @Nullable IpClientCallbacksImpl mIpClientCallback; - private @Nullable NetworkAgent mNetworkAgent; + private @Nullable EthernetNetworkAgent mNetworkAgent; private @Nullable IpConfiguration mIpConfig; /** @@ -360,12 +389,14 @@ public class EthernetNetworkFactory extends NetworkFactory { } NetworkInterfaceState(String ifaceName, String hwAddress, Handler handler, Context context, - @NonNull NetworkCapabilities capabilities, NetworkFactory networkFactory) { + @NonNull NetworkCapabilities capabilities, NetworkFactory networkFactory, + Dependencies deps) { name = ifaceName; mCapabilities = checkNotNull(capabilities); mHandler = handler; mContext = context; mNetworkFactory = networkFactory; + mDeps = deps; int legacyType = ConnectivityManager.TYPE_NONE; int[] transportTypes = mCapabilities.getTransportTypes(); @@ -451,7 +482,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } mIpClientCallback = new IpClientCallbacksImpl(); - IpClientUtil.makeIpClient(mContext, name, mIpClientCallback); + mDeps.makeIpClient(mContext, name, mIpClientCallback); mIpClientCallback.awaitIpClientStart(); if (sTcpBufferSizes == null) { sTcpBufferSizes = mContext.getResources().getString( @@ -474,18 +505,19 @@ public class EthernetNetworkFactory extends NetworkFactory { .setLegacyTypeName(NETWORK_TYPE) .setLegacyExtraInfo(mHwAddress) .build(); - mNetworkAgent = new NetworkAgent(mContext, mHandler.getLooper(), - NETWORK_TYPE, mCapabilities, mLinkProperties, - getNetworkScore(), config, mNetworkFactory.getProvider()) { - 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. - } - }; + mNetworkAgent = mDeps.makeEthernetNetworkAgent(mContext, mHandler.getLooper(), + mCapabilities, mLinkProperties, getNetworkScore(), config, + mNetworkFactory.getProvider(), new EthernetNetworkAgent.Callbacks() { + @Override + public void onNetworkUnwanted() { + if (this == mNetworkAgent.getCallbacks()) { + stop(); + } else if (mNetworkAgent != null) { + Log.d(TAG, "Ignoring unwanted as we have a more modern " + + "instance"); + } // Otherwise, we've already called stop. + } + }); mNetworkAgent.register(); mNetworkAgent.markConnected(); } @@ -496,7 +528,7 @@ public class EthernetNetworkFactory extends NetworkFactory { stop(); // If the interface has disappeared provisioning will fail over and over again, so // there is no point in starting again - if (null != InterfaceParams.getByName(name)) { + if (null != mDeps.getNetworkInterfaceByName(name)) { start(); } } @@ -504,7 +536,7 @@ public class EthernetNetworkFactory extends NetworkFactory { void updateLinkProperties(LinkProperties linkProperties) { mLinkProperties = linkProperties; if (mNetworkAgent != null) { - mNetworkAgent.sendLinkProperties(linkProperties); + mNetworkAgent.sendLinkPropertiesImpl(linkProperties); } } @@ -545,7 +577,7 @@ public class EthernetNetworkFactory extends NetworkFactory { mLinkProperties); } mNetworkAgent.sendNetworkCapabilities(mCapabilities); - mNetworkAgent.sendLinkProperties(mLinkProperties); + mNetworkAgent.sendLinkPropertiesImpl(mLinkProperties); // As a note, getNetworkScore() is fairly expensive to calculate. This is fine for now // since the agent isn't updated frequently. Consider caching the score in the future if diff --git a/tests/ethernet/Android.bp b/tests/ethernet/Android.bp index 4b2d270769..1bc9352f9b 100644 --- a/tests/ethernet/Android.bp +++ b/tests/ethernet/Android.bp @@ -28,10 +28,14 @@ android_test { libs: [ "android.test.runner", "android.test.base", + "android.test.mock", ], static_libs: [ "androidx.test.rules", "ethernet-service", + "frameworks-base-testutils", + "mockito-target-minus-junit4", + "services.net", ], } diff --git a/tests/ethernet/AndroidManifest.xml b/tests/ethernet/AndroidManifest.xml index 302bb6c9a1..cd875b0209 100644 --- a/tests/ethernet/AndroidManifest.xml +++ b/tests/ethernet/AndroidManifest.xml @@ -18,7 +18,7 @@ - + diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java new file mode 100644 index 0000000000..cc03ff2817 --- /dev/null +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -0,0 +1,395 @@ +/* + * Copyright (C) 2020 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 org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.test.MockAnswerUtil.AnswerWithArguments; +import android.content.Context; +import android.content.res.Resources; +import android.net.EthernetNetworkSpecifier; +import android.net.IpConfiguration; +import android.net.LinkProperties; +import android.net.NetworkAgentConfig; +import android.net.NetworkCapabilities; +import android.net.NetworkProvider; +import android.net.NetworkRequest; +import android.net.ip.IIpClient; +import android.net.ip.IpClientCallbacks; +import android.net.util.InterfaceParams; +import android.os.Handler; +import android.os.Looper; +import android.os.test.TestLooper; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.R; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class EthernetNetworkFactoryTest { + private TestLooper mLooper = new TestLooper(); + private Handler mHandler; + private EthernetNetworkFactory mNetFactory = null; + private IpClientCallbacks mIpClientCallbacks; + private int mNetworkRequestCount = 0; + @Mock private Context mContext; + @Mock private Resources mResources; + @Mock private EthernetNetworkFactory.Dependencies mDeps; + @Mock private IIpClient mIpClient; + @Mock private EthernetNetworkAgent mNetworkAgent; + @Mock private InterfaceParams mInterfaceParams; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mHandler = new Handler(mLooper.getLooper()); + mNetworkRequestCount = 0; + + mNetFactory = new EthernetNetworkFactory(mHandler, mContext, createDefaultFilterCaps(), + mDeps); + + setupNetworkAgentMock(); + setupIpClientMock(); + setupContext(); + } + + private void setupNetworkAgentMock() { + when(mDeps.makeEthernetNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), + any())).thenAnswer(new AnswerWithArguments() { + public EthernetNetworkAgent answer( + Context context, + Looper looper, + NetworkCapabilities nc, + LinkProperties lp, + int networkScore, + NetworkAgentConfig config, + NetworkProvider provider, + EthernetNetworkAgent.Callbacks cb) { + when(mNetworkAgent.getCallbacks()).thenReturn(cb); + return mNetworkAgent; + } + } + ); + } + + private void setupIpClientMock() throws Exception { + doAnswer(inv -> { + // these tests only support one concurrent IpClient, so make sure we do not accidentally + // create a mess. + assertNull("An IpClient has already been created.", mIpClientCallbacks); + + mIpClientCallbacks = inv.getArgument(2); + mIpClientCallbacks.onIpClientCreated(mIpClient); + mLooper.dispatchAll(); + return null; + }).when(mDeps).makeIpClient(any(Context.class), anyString(), any()); + + doAnswer(inv -> { + mIpClientCallbacks.onQuit(); + mLooper.dispatchAll(); + mIpClientCallbacks = null; + return null; + }).when(mIpClient).shutdown(); + } + + private void setupContext() { + when(mContext.getResources()).thenReturn(mResources); + when(mResources.getString(R.string.config_ethernet_tcp_buffers)).thenReturn( + "524288,1048576,3145728,524288,1048576,2097152"); + } + + @After + public void tearDown() { + // looper is shared with the network agents, so there may still be messages to dispatch on + // tear down. + mLooper.dispatchAll(); + } + + private NetworkCapabilities createDefaultFilterCaps() { + return NetworkCapabilities.Builder.withoutDefaultCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) + .build(); + } + + private NetworkCapabilities.Builder createInterfaceCapsBuilder() { + return new NetworkCapabilities.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + } + + private NetworkRequest.Builder createDefaultRequestBuilder() { + return new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + } + + private NetworkRequest createDefaultRequest() { + return createDefaultRequestBuilder().build(); + } + + private IpConfiguration createDefaultIpConfig() { + IpConfiguration ipConfig = new IpConfiguration(); + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP); + ipConfig.setProxySettings(IpConfiguration.ProxySettings.NONE); + return ipConfig; + } + + // creates an interface with provisioning in progress (since updating the interface link state + // automatically starts the provisioning process) + private void createInterfaceUndergoingProvisioning(String iface) throws Exception { + mNetFactory.addInterface(iface, iface, createInterfaceCapsBuilder().build(), + createDefaultIpConfig()); + assertTrue(mNetFactory.updateInterfaceLinkState(iface, true)); + verify(mDeps).makeIpClient(any(Context.class), anyString(), any()); + verify(mIpClient).startProvisioning(any()); + clearInvocations(mDeps); + clearInvocations(mIpClient); + } + + // creates a provisioned interface + private void createProvisionedInterface(String iface) throws Exception { + createInterfaceUndergoingProvisioning(iface); + mIpClientCallbacks.onProvisioningSuccess(new LinkProperties()); + mLooper.dispatchAll(); + // provisioning succeeded, verify that the network agent is created, registered, and marked + // as connected. + verify(mDeps).makeEthernetNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), + any()); + verify(mNetworkAgent).register(); + verify(mNetworkAgent).markConnected(); + clearInvocations(mDeps); + clearInvocations(mNetworkAgent); + } + + // creates an unprovisioned interface + private void createUnprovisionedInterface(String iface) throws Exception { + // the only way to create an unprovisioned interface is by calling needNetworkFor + // followed by releaseNetworkFor which will stop the NetworkAgent and IpClient. When + // EthernetNetworkFactory#updateInterfaceLinkState(iface, true) is called, the interface + // is automatically provisioned even if nobody has ever called needNetworkFor + createProvisionedInterface(iface); + + // Interface is already provisioned, so startProvisioning / register should not be called + // again + mNetFactory.needNetworkFor(createDefaultRequest()); + verify(mIpClient, never()).startProvisioning(any()); + verify(mNetworkAgent, never()).register(); + + mNetFactory.releaseNetworkFor(createDefaultRequest()); + verify(mIpClient).shutdown(); + verify(mNetworkAgent).unregister(); + + clearInvocations(mIpClient); + clearInvocations(mNetworkAgent); + } + + @Test + public void testAcceptRequest() throws Exception { + createInterfaceUndergoingProvisioning("eth0"); + assertTrue(mNetFactory.acceptRequest(createDefaultRequest())); + + NetworkRequest wifiRequest = createDefaultRequestBuilder() + .removeTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build(); + assertFalse(mNetFactory.acceptRequest(wifiRequest)); + } + + @Test + public void testUpdateInterfaceLinkStateForActiveProvisioningInterface() throws Exception { + String iface = "eth0"; + createInterfaceUndergoingProvisioning(iface); + // verify that the IpClient gets shut down when interface state changes to down. + assertTrue(mNetFactory.updateInterfaceLinkState(iface, false)); + verify(mIpClient).shutdown(); + } + + @Test + public void testUpdateInterfaceLinkStateForProvisionedInterface() throws Exception { + String iface = "eth0"; + createProvisionedInterface(iface); + assertTrue(mNetFactory.updateInterfaceLinkState(iface, false)); + verify(mIpClient).shutdown(); + verify(mNetworkAgent).unregister(); + } + + @Test + public void testUpdateInterfaceLinkStateForUnprovisionedInterface() throws Exception { + String iface = "eth0"; + createUnprovisionedInterface(iface); + assertTrue(mNetFactory.updateInterfaceLinkState(iface, false)); + // There should not be an active IPClient or NetworkAgent. + verify(mDeps, never()).makeIpClient(any(), any(), any()); + verify(mDeps, never()).makeEthernetNetworkAgent(any(), any(), any(), any(), anyInt(), any(), + any(), any()); + } + + @Test + public void testUpdateInterfaceLinkStateForNonExistingInterface() throws Exception { + // if interface was never added, link state cannot be updated. + assertFalse(mNetFactory.updateInterfaceLinkState("eth1", true)); + verify(mDeps, never()).makeIpClient(any(), any(), any()); + } + + @Test + public void testNeedNetworkForOnProvisionedInterface() throws Exception { + createProvisionedInterface("eth0"); + mNetFactory.needNetworkFor(createDefaultRequest()); + verify(mIpClient, never()).startProvisioning(any()); + } + + @Test + public void testNeedNetworkForOnUnprovisionedInterface() throws Exception { + createUnprovisionedInterface("eth0"); + mNetFactory.needNetworkFor(createDefaultRequest()); + verify(mIpClient).startProvisioning(any()); + + mIpClientCallbacks.onProvisioningSuccess(new LinkProperties()); + mLooper.dispatchAll(); + verify(mNetworkAgent).register(); + verify(mNetworkAgent).markConnected(); + } + + @Test + public void testNeedNetworkForOnInterfaceUndergoingProvisioning() throws Exception { + createInterfaceUndergoingProvisioning("eth0"); + mNetFactory.needNetworkFor(createDefaultRequest()); + verify(mIpClient, never()).startProvisioning(any()); + + mIpClientCallbacks.onProvisioningSuccess(new LinkProperties()); + mLooper.dispatchAll(); + verify(mNetworkAgent).register(); + verify(mNetworkAgent).markConnected(); + } + + @Test + public void testProvisioningLoss() throws Exception { + String iface = "eth0"; + when(mDeps.getNetworkInterfaceByName(iface)).thenReturn(mInterfaceParams); + createProvisionedInterface(iface); + + mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); + mLooper.dispatchAll(); + verify(mIpClient).shutdown(); + verify(mNetworkAgent).unregister(); + // provisioning loss should trigger a retry, since the interface is still there + verify(mIpClient).startProvisioning(any()); + } + + @Test + public void testProvisioningLossForDisappearedInterface() throws Exception { + String iface = "eth0"; + // mocked method returns null by default, but just to be explicit in the test: + when(mDeps.getNetworkInterfaceByName(eq(iface))).thenReturn(null); + + createProvisionedInterface(iface); + mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); + mLooper.dispatchAll(); + verify(mIpClient).shutdown(); + verify(mNetworkAgent).unregister(); + // the interface disappeared and getNetworkInterfaceByName returns null, we should not retry + verify(mIpClient, never()).startProvisioning(any()); + } + + @Test + public void testIpClientIsNotStartedWhenLinkIsDown() throws Exception { + String iface = "eth0"; + createUnprovisionedInterface(iface); + mNetFactory.updateInterfaceLinkState(iface, false); + + mNetFactory.needNetworkFor(createDefaultRequest()); + + NetworkRequest specificNetRequest = new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) + .setNetworkSpecifier(new EthernetNetworkSpecifier(iface)) + .build(); + mNetFactory.needNetworkFor(specificNetRequest); + + // TODO(b/155707957): BUG: IPClient should not be started when the interface link state + // is down. + verify(mDeps).makeIpClient(any(), any(), any()); + } + + @Test + public void testLinkPropertiesChanged() throws Exception { + createProvisionedInterface("eth0"); + + LinkProperties lp = new LinkProperties(); + mIpClientCallbacks.onLinkPropertiesChange(lp); + mLooper.dispatchAll(); + verify(mNetworkAgent).sendLinkPropertiesImpl(same(lp)); + } + + @Test + public void testNetworkUnwanted() throws Exception { + createProvisionedInterface("eth0"); + + mNetworkAgent.getCallbacks().onNetworkUnwanted(); + mLooper.dispatchAll(); + verify(mIpClient).shutdown(); + verify(mNetworkAgent).unregister(); + } + + @Test + public void testNetworkUnwantedWithStaleNetworkAgent() throws Exception { + String iface = "eth0"; + // ensures provisioning is restarted after provisioning loss + when(mDeps.getNetworkInterfaceByName(iface)).thenReturn(mInterfaceParams); + createProvisionedInterface(iface); + + EthernetNetworkAgent.Callbacks oldCbs = mNetworkAgent.getCallbacks(); + // replace network agent in EthernetNetworkFactory + // Loss of provisioning will restart the ip client and network agent. + mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); + mLooper.dispatchAll(); + verify(mDeps).makeIpClient(any(), any(), any()); + + mIpClientCallbacks.onProvisioningSuccess(new LinkProperties()); + mLooper.dispatchAll(); + verify(mDeps).makeEthernetNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), + any()); + + // verify that unwanted is ignored + clearInvocations(mIpClient); + clearInvocations(mNetworkAgent); + oldCbs.onNetworkUnwanted(); + verify(mIpClient, never()).shutdown(); + verify(mNetworkAgent, never()).unregister(); + } +} From 698b59510f6286723096742ce46cea9586fdd052 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Tue, 1 Jun 2021 09:51:48 +0200 Subject: [PATCH 105/152] Remove Unused Code From EthernetNetworkFactory Test: atest EthernetNetworkFactoryTest Change-Id: Ibe0190b3108dca644da2d67bd107954cb26f41ce --- .../ethernet/EthernetNetworkFactory.java | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index f4de23d7d3..32dbd7e0b6 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -423,10 +423,6 @@ public class EthernetNetworkFactory extends NetworkFactory { } } - boolean satisfied(NetworkCapabilities requestedCapabilities) { - return requestedCapabilities.satisfiedByNetworkCapabilities(mCapabilities); - } - boolean isRestricted() { return !mCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); } @@ -569,22 +565,6 @@ public class EthernetNetworkFactory extends NetworkFactory { mLinkProperties.clear(); } - private void updateAgent() { - if (mNetworkAgent == null) return; - if (DBG) { - Log.i(TAG, "Updating mNetworkAgent with: " + - mCapabilities + ", " + - mLinkProperties); - } - mNetworkAgent.sendNetworkCapabilities(mCapabilities); - mNetworkAgent.sendLinkPropertiesImpl(mLinkProperties); - - // As a note, getNetworkScore() is fairly expensive to calculate. This is fine for now - // since the agent isn't updated frequently. Consider caching the score in the future if - // agent updating is required more often - mNetworkAgent.sendNetworkScore(getNetworkScore()); - } - private static void provisionIpClient(IIpClient ipClient, IpConfiguration config, String tcpBufferSizes) { if (config.getProxySettings() == ProxySettings.STATIC || From b94c4e74539452158b0472f1a6b645115cf9dc18 Mon Sep 17 00:00:00 2001 From: Milim Lee Date: Wed, 28 Apr 2021 13:56:11 +0900 Subject: [PATCH 106/152] Set EthernetNetworkSpecifier on each ethernet network for multi-ethernet Bug: 175199512 Test: Build and test multi-ethernet Change-Id: I6ec50b42bee89520f6f27d40e0d2b0d774b8e2e5 --- .../com/android/server/ethernet/EthernetNetworkFactory.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index aa80e4de2d..2ddc14eb0c 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -146,6 +146,10 @@ public class EthernetNetworkFactory extends NetworkFactory { return; } + capabilities = new NetworkCapabilities.Builder(capabilities) + .setNetworkSpecifier(new EthernetNetworkSpecifier(ifaceName)) + .build(); + if (DBG) { Log.d(TAG, "addInterface, iface: " + ifaceName + ", capabilities: " + capabilities); } From 7a4fecc3de65ef2c7965450cc76f4459620b9f0c Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 12 Aug 2021 17:16:51 +0000 Subject: [PATCH 107/152] Revert "Set EthernetNetworkSpecifier on each ethernet network for multi-ethernet" This reverts commit b94c4e74539452158b0472f1a6b645115cf9dc18. Reason for revert: b/196387077 Change-Id: I8e27ce915b6069b642c614a018aa5e1788ae07af --- .../com/android/server/ethernet/EthernetNetworkFactory.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 2ddc14eb0c..aa80e4de2d 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -146,10 +146,6 @@ public class EthernetNetworkFactory extends NetworkFactory { return; } - capabilities = new NetworkCapabilities.Builder(capabilities) - .setNetworkSpecifier(new EthernetNetworkSpecifier(ifaceName)) - .build(); - if (DBG) { Log.d(TAG, "addInterface, iface: " + ifaceName + ", capabilities: " + capabilities); } From c57eb8c6ad462a514f200a94093f94e902959f70 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Fri, 20 Aug 2021 10:42:52 +0800 Subject: [PATCH 108/152] Add null check for the taken callback The requestTetheredInterface() and releaseTetheredInterface() in EthernetManager is annotated as @NonNull. Basically, the taken callback parameter to the service implementation should also be @NonNull. However, it still possible to use native commands to call the method in the aidl. If a null callback is taken, it may cause unexpected results and cause crashes. Add a null check and throw NPE as a warning. Bug: 190058445 Test: adb commands Change-Id: I18fd63aba3f7326597fc3a8c93ba8c9097bf7348 --- .../src/com/android/server/ethernet/EthernetServiceImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 3fc6aab758..6b0ce32644 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -35,6 +35,7 @@ import com.android.internal.util.IndentingPrintWriter; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -172,6 +173,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Override public void requestTetheredInterface(ITetheredInterfaceCallback callback) { + Objects.requireNonNull(callback, "callback must not be null"); NetworkStack.checkNetworkStackPermissionOr(mContext, android.Manifest.permission.NETWORK_SETTINGS); mTracker.requestTetheredInterface(callback); @@ -179,6 +181,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Override public void releaseTetheredInterface(ITetheredInterfaceCallback callback) { + Objects.requireNonNull(callback, "callback must not be null"); NetworkStack.checkNetworkStackPermissionOr(mContext, android.Manifest.permission.NETWORK_SETTINGS); mTracker.releaseTetheredInterface(callback); From 4cf6809d7583c134d38f2aa5883abdbac06b32e9 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Fri, 20 Aug 2021 07:56:26 +0200 Subject: [PATCH 109/152] prevent nullptr dereference when calling unwanted When the EthernetNetworkAgent has already been stopped, a call to unwanted will cause a crash due to a nullptr derefernce. Bug: 197279734 Test: atest EthernetNetworkFactoryTest Change-Id: Ice39c603bdd3e3139aa8ece7fb897bf7b567e74b --- .../android/server/ethernet/EthernetNetworkFactory.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 32dbd7e0b6..cd086e721f 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -506,12 +506,15 @@ public class EthernetNetworkFactory extends NetworkFactory { 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 if (mNetworkAgent != null) { + } else { Log.d(TAG, "Ignoring unwanted as we have a more modern " + "instance"); - } // Otherwise, we've already called stop. + } } }); mNetworkAgent.register(); From d6789606d560135b4f29ce82db7a1f09041db089 Mon Sep 17 00:00:00 2001 From: paulhu Date: Wed, 15 Sep 2021 16:53:45 +0800 Subject: [PATCH 110/152] Stop using NetworkStack#checkNetworkStackPermission* Replace them with PermissionUtils.enforceNetworkStackPermission* since those methods are deprecated. Bug: 177187957 Test: atest EthernetServiceTests Change-Id: Ifde4a8898439b86e6cc49b7469787bc5e4a91835 --- .../android/server/ethernet/EthernetServiceImpl.java | 11 +++++------ .../com/android/server/ethernet/EthernetTracker.java | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 6b0ce32644..0d4074ea1a 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -22,16 +22,15 @@ import android.net.IEthernetManager; import android.net.IEthernetServiceListener; import android.net.ITetheredInterfaceCallback; import android.net.IpConfiguration; -import android.net.NetworkStack; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; import android.os.RemoteException; -import android.provider.Settings; import android.util.Log; import android.util.PrintWriterPrinter; import com.android.internal.util.IndentingPrintWriter; +import com.android.net.module.util.PermissionUtils; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -115,7 +114,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { Log.w(TAG, "System isn't ready enough to change ethernet configuration"); } - NetworkStack.checkNetworkStackPermission(mContext); + PermissionUtils.enforceNetworkStackPermission(mContext); if (mTracker.isRestrictedInterface(iface)) { enforceUseRestrictedNetworksPermission(); @@ -166,7 +165,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Override public void setIncludeTestInterfaces(boolean include) { - NetworkStack.checkNetworkStackPermissionOr(mContext, + PermissionUtils.enforceNetworkStackPermissionOr(mContext, android.Manifest.permission.NETWORK_SETTINGS); mTracker.setIncludeTestInterfaces(include); } @@ -174,7 +173,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Override public void requestTetheredInterface(ITetheredInterfaceCallback callback) { Objects.requireNonNull(callback, "callback must not be null"); - NetworkStack.checkNetworkStackPermissionOr(mContext, + PermissionUtils.enforceNetworkStackPermissionOr(mContext, android.Manifest.permission.NETWORK_SETTINGS); mTracker.requestTetheredInterface(callback); } @@ -182,7 +181,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Override public void releaseTetheredInterface(ITetheredInterfaceCallback callback) { Objects.requireNonNull(callback, "callback must not be null"); - NetworkStack.checkNetworkStackPermissionOr(mContext, + PermissionUtils.enforceNetworkStackPermissionOr(mContext, android.Manifest.permission.NETWORK_SETTINGS); mTracker.releaseTetheredInterface(callback); } diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index b2b60fcb83..d79c7a9dfd 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -29,7 +29,6 @@ import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; import android.net.LinkAddress; import android.net.NetworkCapabilities; -import android.net.NetworkStack; import android.net.StaticIpConfiguration; import android.os.Handler; import android.os.IBinder; @@ -45,6 +44,7 @@ import android.net.util.NetdService; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.net.module.util.NetdUtils; +import com.android.net.module.util.PermissionUtils; import com.android.server.net.BaseNetworkObserver; import java.io.FileDescriptor; @@ -287,7 +287,7 @@ final class EthernetTracker { InterfaceConfiguration config = null; // Bring up the interface so we get link status indications. try { - NetworkStack.checkNetworkStackPermission(mContext); + PermissionUtils.enforceNetworkStackPermission(mContext); NetdUtils.setInterfaceUp(mNetd, iface); config = mNMService.getInterfaceConfig(iface); } catch (RemoteException | IllegalStateException e) { From 68c4a5108b5ef17e24dfc79ad6e8109c8740d3f5 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Sun, 14 Nov 2021 14:38:07 -0800 Subject: [PATCH 111/152] Removing unused int network score from eth factory Hard coded network scores are no longer used however they still exist in EthernetNetworkFactory. This change removes this unused code in favor of the NetworkScore object. Bug: 209679953 Test: m && atest com.android.server.ethernet.EthernetNetworkFactoryTest Change-Id: Ic9035964fc0e0bdf1dbd1ee845ba3293c753dd8d --- .../server/ethernet/EthernetNetworkAgent.java | 4 +- .../ethernet/EthernetNetworkFactory.java | 99 ++++--------------- .../ethernet/EthernetNetworkFactoryTest.java | 16 ++- 3 files changed, 27 insertions(+), 92 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkAgent.java b/service-t/src/com/android/server/ethernet/EthernetNetworkAgent.java index 5598fc6a11..57fbce7e86 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkAgent.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkAgent.java @@ -22,6 +22,7 @@ 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; @@ -41,11 +42,10 @@ public class EthernetNetworkAgent extends NetworkAgent { @NonNull Looper looper, @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, - int networkScore, @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider, @NonNull Callbacks cb) { - super(context, looper, TAG, nc, lp, networkScore, config, provider); + super(context, looper, TAG, nc, lp, new NetworkScore.Builder().build(), config, provider); mCallbacks = cb; } diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index cd086e721f..26532d7355 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -79,11 +79,9 @@ public class EthernetNetworkFactory extends NetworkFactory { } public EthernetNetworkAgent makeEthernetNetworkAgent(Context context, Looper looper, - NetworkCapabilities nc, LinkProperties lp, int networkScore, - NetworkAgentConfig config, NetworkProvider provider, - EthernetNetworkAgent.Callbacks cb) { - return new EthernetNetworkAgent(context, looper, nc, lp, networkScore, config, provider, - cb); + 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) { @@ -293,49 +291,24 @@ public class EthernetNetworkFactory extends NetworkFactory { private @Nullable IpConfiguration mIpConfig; /** - * An object to contain all transport type information, including base network score and - * the legacy transport type it maps to (if any) - */ - private static class TransportInfo { - final int mLegacyType; - final int mScore; - - private TransportInfo(int legacyType, int score) { - mLegacyType = legacyType; - mScore = score; - } - } - - /** - * A map of TRANSPORT_* types to TransportInfo, making scoring and legacy type information - * available for each type an ethernet interface could propagate. + * A map of TRANSPORT_* types to legacy transport types available for each type an ethernet + * interface could propagate. * - * Unfortunately, base scores for the various transports are not yet centrally located. - * They've been lifted from the corresponding NetworkFactory files in the meantime. - * - * Additionally, 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. + * 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 sTransports = new SparseArray(); + private static final SparseArray sTransports = new SparseArray(); static { - // LowpanInterfaceTracker.NETWORK_SCORE - sTransports.put(NetworkCapabilities.TRANSPORT_LOWPAN, - new TransportInfo(ConnectivityManager.TYPE_NONE, 30)); - // WifiAwareDataPathStateManager.NETWORK_FACTORY_SCORE_AVAIL - sTransports.put(NetworkCapabilities.TRANSPORT_WIFI_AWARE, - new TransportInfo(ConnectivityManager.TYPE_NONE, 1)); - // EthernetNetworkFactory.NETWORK_SCORE sTransports.put(NetworkCapabilities.TRANSPORT_ETHERNET, - new TransportInfo(ConnectivityManager.TYPE_ETHERNET, 70)); - // BluetoothTetheringNetworkFactory.NETWORK_SCORE + ConnectivityManager.TYPE_ETHERNET); sTransports.put(NetworkCapabilities.TRANSPORT_BLUETOOTH, - new TransportInfo(ConnectivityManager.TYPE_BLUETOOTH, 69)); - // WifiNetworkFactory.SCORE_FILTER / NetworkAgent.WIFI_BASE_SCORE - sTransports.put(NetworkCapabilities.TRANSPORT_WIFI, - new TransportInfo(ConnectivityManager.TYPE_WIFI, 60)); - // TelephonyNetworkFactory.TELEPHONY_NETWORK_SCORE + ConnectivityManager.TYPE_BLUETOOTH); + sTransports.put(NetworkCapabilities.TRANSPORT_WIFI, ConnectivityManager.TYPE_WIFI); sTransports.put(NetworkCapabilities.TRANSPORT_CELLULAR, - new TransportInfo(ConnectivityManager.TYPE_MOBILE, 50)); + ConnectivityManager.TYPE_MOBILE); + sTransports.put(NetworkCapabilities.TRANSPORT_LOWPAN, ConnectivityManager.TYPE_NONE); + sTransports.put(NetworkCapabilities.TRANSPORT_WIFI_AWARE, + ConnectivityManager.TYPE_NONE); } long refCount = 0; @@ -397,7 +370,7 @@ public class EthernetNetworkFactory extends NetworkFactory { mContext = context; mNetworkFactory = networkFactory; mDeps = deps; - int legacyType = ConnectivityManager.TYPE_NONE; + final int legacyType; int[] transportTypes = mCapabilities.getTransportTypes(); if (transportTypes.length > 0) { @@ -432,40 +405,7 @@ public class EthernetNetworkFactory extends NetworkFactory { * to legacy TYPE_NONE if there is no known conversion */ private static int getLegacyType(int transport) { - TransportInfo transportInfo = sTransports.get(transport, /* if dne */ null); - if (transportInfo != null) { - return transportInfo.mLegacyType; - } - return ConnectivityManager.TYPE_NONE; - } - - /** - * Determines the network score based on the transport associated with the interface. - * Ethernet interfaces could propagate a transport types forward. Since we can't - * get more information about the statuses of the interfaces on the other end of the local - * interface, we'll best-effort assign the score as the base score of the assigned transport - * when the link is up. When the link is down, the score is set to zero. - * - * This function is called with the purpose of assigning and updating the network score of - * the member NetworkAgent. - */ - private int getNetworkScore() { - // never set the network score below 0. - if (!mLinkUp) { - return 0; - } - - int[] transportTypes = mCapabilities.getTransportTypes(); - if (transportTypes.length < 1) { - Log.w(TAG, "Network interface '" + mLinkProperties.getInterfaceName() + "' has no " - + "transport type associated with it. Score set to zero"); - return 0; - } - TransportInfo transportInfo = sTransports.get(transportTypes[0], /* if dne */ null); - if (transportInfo != null) { - return transportInfo.mScore; - } - return 0; + return sTransports.get(transport, ConnectivityManager.TYPE_NONE); } private void start() { @@ -502,8 +442,8 @@ public class EthernetNetworkFactory extends NetworkFactory { .setLegacyExtraInfo(mHwAddress) .build(); mNetworkAgent = mDeps.makeEthernetNetworkAgent(mContext, mHandler.getLooper(), - mCapabilities, mLinkProperties, getNetworkScore(), config, - mNetworkFactory.getProvider(), new EthernetNetworkAgent.Callbacks() { + mCapabilities, mLinkProperties, config, mNetworkFactory.getProvider(), + new EthernetNetworkAgent.Callbacks() { @Override public void onNetworkUnwanted() { // if mNetworkAgent is null, we have already called stop. @@ -620,7 +560,6 @@ public class EthernetNetworkFactory extends NetworkFactory { + "hwAddress: " + mHwAddress + ", " + "networkCapabilities: " + mCapabilities + ", " + "networkAgent: " + mNetworkAgent + ", " - + "score: " + getNetworkScore() + ", " + "ipClient: " + mIpClient + "," + "linkProperties: " + mLinkProperties + "}"; diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index cc03ff2817..f4bb15ec09 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -20,7 +20,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.same; @@ -90,14 +89,13 @@ public class EthernetNetworkFactoryTest { } private void setupNetworkAgentMock() { - when(mDeps.makeEthernetNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), - any())).thenAnswer(new AnswerWithArguments() { + when(mDeps.makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any())) + .thenAnswer(new AnswerWithArguments() { public EthernetNetworkAgent answer( Context context, Looper looper, NetworkCapabilities nc, LinkProperties lp, - int networkScore, NetworkAgentConfig config, NetworkProvider provider, EthernetNetworkAgent.Callbacks cb) { @@ -190,8 +188,7 @@ public class EthernetNetworkFactoryTest { mLooper.dispatchAll(); // provisioning succeeded, verify that the network agent is created, registered, and marked // as connected. - verify(mDeps).makeEthernetNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), - any()); + verify(mDeps).makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any()); verify(mNetworkAgent).register(); verify(mNetworkAgent).markConnected(); clearInvocations(mDeps); @@ -256,8 +253,8 @@ public class EthernetNetworkFactoryTest { assertTrue(mNetFactory.updateInterfaceLinkState(iface, false)); // There should not be an active IPClient or NetworkAgent. verify(mDeps, never()).makeIpClient(any(), any(), any()); - verify(mDeps, never()).makeEthernetNetworkAgent(any(), any(), any(), any(), anyInt(), any(), - any(), any()); + verify(mDeps, never()) + .makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any()); } @Test @@ -382,8 +379,7 @@ public class EthernetNetworkFactoryTest { mIpClientCallbacks.onProvisioningSuccess(new LinkProperties()); mLooper.dispatchAll(); - verify(mDeps).makeEthernetNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), - any()); + verify(mDeps).makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any()); // verify that unwanted is ignored clearInvocations(mIpClient); From 2fc1c08cb57fb188f76e744d0f43a3e1b54fa0e2 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Tue, 7 Dec 2021 15:47:11 -0800 Subject: [PATCH 112/152] Adding test coverage for eth transport overrides Added test coverage regarding how EthernetTracker consumes the xml config as set in config_ethernet_interfaces. Additionally, adding test coverage for transport override functionality in EthernetNetworkFactory. Bug: 206170402 Test: atest com.android.server.ethernet.EthernetTrackerTest && atest com.android.server.ethernet.EthernetNetworkFactoryTest Change-Id: I3d55a230d3f28154ed6fdac6d63ed57bf589d3bd --- .../server/ethernet/EthernetTracker.java | 40 +++++++--- .../ethernet/EthernetNetworkFactoryTest.java | 78 +++++++++++++++---- .../server/ethernet/EthernetTrackerTest.java | 24 ++++++ 3 files changed, 116 insertions(+), 26 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index d79c7a9dfd..86aefbcff2 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -18,6 +18,7 @@ package com.android.server.ethernet; import static android.net.TestNetworkManager.TEST_TAP_PREFIX; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.IEthernetServiceListener; @@ -453,21 +454,24 @@ final class EthernetTracker { * ;[Network Capabilities];[IP config];[Override Transport]} */ private void parseEthernetConfig(String configString) { - String[] tokens = configString.split(";", /* limit of tokens */ 4); - String name = tokens[0]; - String capabilities = tokens.length > 1 ? tokens[1] : null; - String transport = tokens.length > 3 ? tokens[3] : null; + final EthernetTrackerConfig config = createEthernetTrackerConfig(configString); NetworkCapabilities nc = createNetworkCapabilities( - !TextUtils.isEmpty(capabilities) /* clear default capabilities */, capabilities, - transport).build(); - mNetworkCapabilities.put(name, nc); + !TextUtils.isEmpty(config.mCapabilities) /* clear default capabilities */, + config.mCapabilities, config.mTransport).build(); + mNetworkCapabilities.put(config.mName, nc); - if (tokens.length > 2 && !TextUtils.isEmpty(tokens[2])) { - IpConfiguration ipConfig = parseStaticIpConfiguration(tokens[2]); - mIpConfigurations.put(name, ipConfig); + if (null != config.mIpConfig) { + IpConfiguration ipConfig = parseStaticIpConfiguration(config.mIpConfig); + mIpConfigurations.put(config.mName, 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) @@ -672,4 +676,20 @@ final class EthernetTracker { mFactory.dump(fd, pw, args); }); } + + @VisibleForTesting + static class EthernetTrackerConfig { + final String mName; + final String mCapabilities; + final String mIpConfig; + final String mTransport; + + EthernetTrackerConfig(@NonNull final String[] tokens) { + Objects.requireNonNull(tokens, "EthernetTrackerConfig requires non-null tokens"); + mName = 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; + } + } } diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index f4bb15ec09..0cd9c1811e 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.clearInvocations; @@ -29,9 +30,11 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.annotation.NonNull; import android.app.test.MockAnswerUtil.AnswerWithArguments; import android.content.Context; import android.content.res.Resources; +import android.net.ConnectivityManager; import android.net.EthernetNetworkSpecifier; import android.net.IpConfiguration; import android.net.LinkProperties; @@ -145,9 +148,9 @@ public class EthernetNetworkFactoryTest { .build(); } - private NetworkCapabilities.Builder createInterfaceCapsBuilder() { + private NetworkCapabilities.Builder createInterfaceCapsBuilder(final int transportType) { return new NetworkCapabilities.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) + .addTransportType(transportType) .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); } @@ -172,7 +175,13 @@ public class EthernetNetworkFactoryTest { // creates an interface with provisioning in progress (since updating the interface link state // automatically starts the provisioning process) private void createInterfaceUndergoingProvisioning(String iface) throws Exception { - mNetFactory.addInterface(iface, iface, createInterfaceCapsBuilder().build(), + // Default to the ethernet transport type. + createInterfaceUndergoingProvisioning(iface, NetworkCapabilities.TRANSPORT_ETHERNET); + } + + private void createInterfaceUndergoingProvisioning( + @NonNull final String iface, final int transportType) throws Exception { + mNetFactory.addInterface(iface, iface, createInterfaceCapsBuilder(transportType).build(), createDefaultIpConfig()); assertTrue(mNetFactory.updateInterfaceLinkState(iface, true)); verify(mDeps).makeIpClient(any(Context.class), anyString(), any()); @@ -182,13 +191,22 @@ public class EthernetNetworkFactoryTest { } // creates a provisioned interface - private void createProvisionedInterface(String iface) throws Exception { - createInterfaceUndergoingProvisioning(iface); + private void createAndVerifyProvisionedInterface(String iface) throws Exception { + // Default to the ethernet transport type. + createAndVerifyProvisionedInterface(iface, NetworkCapabilities.TRANSPORT_ETHERNET, + ConnectivityManager.TYPE_ETHERNET); + } + + private void createAndVerifyProvisionedInterface( + @NonNull final String iface, final int transportType, final int expectedLegacyType) + throws Exception { + createInterfaceUndergoingProvisioning(iface, transportType); mIpClientCallbacks.onProvisioningSuccess(new LinkProperties()); mLooper.dispatchAll(); - // provisioning succeeded, verify that the network agent is created, registered, and marked - // as connected. - verify(mDeps).makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any()); + // provisioning succeeded, verify that the network agent is created, registered, marked + // as connected and legacy type are correctly set. + verify(mDeps).makeEthernetNetworkAgent(any(), any(), any(), any(), + argThat(x -> x.getLegacyType() == expectedLegacyType), any(), any()); verify(mNetworkAgent).register(); verify(mNetworkAgent).markConnected(); clearInvocations(mDeps); @@ -201,7 +219,7 @@ public class EthernetNetworkFactoryTest { // followed by releaseNetworkFor which will stop the NetworkAgent and IpClient. When // EthernetNetworkFactory#updateInterfaceLinkState(iface, true) is called, the interface // is automatically provisioned even if nobody has ever called needNetworkFor - createProvisionedInterface(iface); + createAndVerifyProvisionedInterface(iface); // Interface is already provisioned, so startProvisioning / register should not be called // again @@ -240,7 +258,7 @@ public class EthernetNetworkFactoryTest { @Test public void testUpdateInterfaceLinkStateForProvisionedInterface() throws Exception { String iface = "eth0"; - createProvisionedInterface(iface); + createAndVerifyProvisionedInterface(iface); assertTrue(mNetFactory.updateInterfaceLinkState(iface, false)); verify(mIpClient).shutdown(); verify(mNetworkAgent).unregister(); @@ -266,7 +284,7 @@ public class EthernetNetworkFactoryTest { @Test public void testNeedNetworkForOnProvisionedInterface() throws Exception { - createProvisionedInterface("eth0"); + createAndVerifyProvisionedInterface("eth0"); mNetFactory.needNetworkFor(createDefaultRequest()); verify(mIpClient, never()).startProvisioning(any()); } @@ -299,7 +317,7 @@ public class EthernetNetworkFactoryTest { public void testProvisioningLoss() throws Exception { String iface = "eth0"; when(mDeps.getNetworkInterfaceByName(iface)).thenReturn(mInterfaceParams); - createProvisionedInterface(iface); + createAndVerifyProvisionedInterface(iface); mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); mLooper.dispatchAll(); @@ -315,7 +333,7 @@ public class EthernetNetworkFactoryTest { // mocked method returns null by default, but just to be explicit in the test: when(mDeps.getNetworkInterfaceByName(eq(iface))).thenReturn(null); - createProvisionedInterface(iface); + createAndVerifyProvisionedInterface(iface); mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); mLooper.dispatchAll(); verify(mIpClient).shutdown(); @@ -345,7 +363,7 @@ public class EthernetNetworkFactoryTest { @Test public void testLinkPropertiesChanged() throws Exception { - createProvisionedInterface("eth0"); + createAndVerifyProvisionedInterface("eth0"); LinkProperties lp = new LinkProperties(); mIpClientCallbacks.onLinkPropertiesChange(lp); @@ -355,7 +373,7 @@ public class EthernetNetworkFactoryTest { @Test public void testNetworkUnwanted() throws Exception { - createProvisionedInterface("eth0"); + createAndVerifyProvisionedInterface("eth0"); mNetworkAgent.getCallbacks().onNetworkUnwanted(); mLooper.dispatchAll(); @@ -368,7 +386,7 @@ public class EthernetNetworkFactoryTest { String iface = "eth0"; // ensures provisioning is restarted after provisioning loss when(mDeps.getNetworkInterfaceByName(iface)).thenReturn(mInterfaceParams); - createProvisionedInterface(iface); + createAndVerifyProvisionedInterface(iface); EthernetNetworkAgent.Callbacks oldCbs = mNetworkAgent.getCallbacks(); // replace network agent in EthernetNetworkFactory @@ -388,4 +406,32 @@ public class EthernetNetworkFactoryTest { verify(mIpClient, never()).shutdown(); verify(mNetworkAgent, never()).unregister(); } + + @Test + public void testTransportOverrideIsCorrectlySet() throws Exception { + final String iface = "eth0"; + // createProvisionedInterface() has verifications in place for transport override + // functionality which for EthernetNetworkFactory is network score and legacy type mappings. + createAndVerifyProvisionedInterface(iface, NetworkCapabilities.TRANSPORT_ETHERNET, + ConnectivityManager.TYPE_ETHERNET); + mNetFactory.removeInterface(iface); + createAndVerifyProvisionedInterface(iface, NetworkCapabilities.TRANSPORT_BLUETOOTH, + ConnectivityManager.TYPE_BLUETOOTH); + mNetFactory.removeInterface(iface); + createAndVerifyProvisionedInterface(iface, NetworkCapabilities.TRANSPORT_WIFI, + ConnectivityManager.TYPE_WIFI); + mNetFactory.removeInterface(iface); + createAndVerifyProvisionedInterface(iface, NetworkCapabilities.TRANSPORT_CELLULAR, + ConnectivityManager.TYPE_MOBILE); + mNetFactory.removeInterface(iface); + createAndVerifyProvisionedInterface(iface, NetworkCapabilities.TRANSPORT_LOWPAN, + ConnectivityManager.TYPE_NONE); + mNetFactory.removeInterface(iface); + createAndVerifyProvisionedInterface(iface, NetworkCapabilities.TRANSPORT_WIFI_AWARE, + ConnectivityManager.TYPE_NONE); + mNetFactory.removeInterface(iface); + createAndVerifyProvisionedInterface(iface, NetworkCapabilities.TRANSPORT_TEST, + ConnectivityManager.TYPE_NONE); + mNetFactory.removeInterface(iface); + } } diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java index ee9f349a28..6ea2154337 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -17,6 +17,7 @@ package com.android.server.ethernet; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.fail; import android.net.InetAddresses; @@ -242,4 +243,27 @@ public class EthernetTrackerTest { EthernetTracker.createNetworkCapabilities(clearCapabilties, configCapabiltiies, configTransports).build()); } + + @Test + public void testCreateEthernetTrackerConfigReturnsCorrectValue() { + final String name = "1"; + final String capabilities = "2"; + final String ipConfig = "3"; + final String transport = "4"; + final String configString = String.join(";", name, capabilities, ipConfig, transport); + + final EthernetTracker.EthernetTrackerConfig config = + EthernetTracker.createEthernetTrackerConfig(configString); + + assertEquals(name, config.mName); + assertEquals(capabilities, config.mCapabilities); + assertEquals(ipConfig, config.mIpConfig); + assertEquals(transport, config.mTransport); + } + + @Test + public void testCreateEthernetTrackerConfigThrowsNpeWithNullInput() { + assertThrows(NullPointerException.class, + () -> EthernetTracker.createEthernetTrackerConfig(null)); + } } From e600bef8f93405507b3c633d9559a2b38e5daf02 Mon Sep 17 00:00:00 2001 From: Pavan Kumar M Date: Mon, 8 Feb 2021 21:17:20 +0530 Subject: [PATCH 113/152] Handle neighbor lost event Neighbor lost event is received when gateway is not reachable. Ethernet Factory currently doesn't handle the neighbor lost event and network will not be brought down. This results in loss of connectivity even if there are other networks like WiFi. Restart NetworkInterfaceState when neighbor lost event is received. If there is a better network like WiFi, it will become default and apps will be able to use internet. If ethernet gets connected again, and has backhaul connectivity, it will become default. Bug: 180077540 Tests: Builds, Boots, EthernetServiceTests Change-Id: I26d720994ecb35f6529358a53e115091e7817c2f --- .../server/ethernet/EthernetNetworkFactory.java | 16 ++++++++++++++++ .../ethernet/EthernetNetworkFactoryTest.java | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 26532d7355..2886cf1e3d 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -346,6 +346,11 @@ public class EthernetNetworkFactory extends NetworkFactory { mHandler.post(() -> updateLinkProperties(newLp)); } + @Override + public void onReachabilityLost(String logMsg) { + mHandler.post(() -> updateNeighborLostEvent(logMsg)); + } + @Override public void onQuit() { mIpClient = null; @@ -479,6 +484,17 @@ public class EthernetNetworkFactory extends NetworkFactory { } } + 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(boolean up) { if (mLinkUp == up) return false; diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 0cd9c1811e..6422358068 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -434,4 +434,20 @@ public class EthernetNetworkFactoryTest { ConnectivityManager.TYPE_NONE); mNetFactory.removeInterface(iface); } + + @Test + public void testReachabilityLoss() throws Exception { + String iface = "eth0"; + createAndVerifyProvisionedInterface(iface); + + mIpClientCallbacks.onReachabilityLost("ReachabilityLost"); + mLooper.dispatchAll(); + + // Reachability loss should trigger a stop and start, since the interface is still there + verify(mIpClient).shutdown(); + verify(mNetworkAgent).unregister(); + + verify(mDeps).makeIpClient(any(Context.class), anyString(), any()); + verify(mIpClient).startProvisioning(any()); + } } From 300abdb2a8099a2d24a9882dafb15a7e5199e87d Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Thu, 16 Dec 2021 02:38:40 +0000 Subject: [PATCH 114/152] Remove NetdService usage from EthernetTracker. Ethernet service related files are going to be moved into Connectivity module. So, NetdService won't be visible to EthernetTracker since it's a hidden class. Alternatively, get the INetd instance from system service instead. Bug: 210586283 Test: atest FrameworksNetTests Test: atest EthernetServiceTests Change-Id: Iea021ac25cbe4b8836fdab2cd6b4bd3ead5bf725 --- .../src/com/android/server/ethernet/EthernetTracker.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 86aefbcff2..beb950cb9d 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -40,7 +40,6 @@ import android.os.ServiceManager; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; -import android.net.util.NetdService; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; @@ -124,7 +123,9 @@ final class EthernetTracker { // The services we use. IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); mNMService = INetworkManagementService.Stub.asInterface(b); - mNetd = Objects.requireNonNull(NetdService.getInstance(), "could not get netd instance"); + mNetd = INetd.Stub.asInterface( + (IBinder) context.getSystemService(Context.NETD_SERVICE)); + Objects.requireNonNull(mNetd, "could not get netd instance"); // Interface match regex. updateIfaceMatchRegexp(); From 31ce0a1dc7af27a9547afea88c5e4e115c87132a Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Tue, 21 Dec 2021 07:09:39 +0000 Subject: [PATCH 115/152] Replace Preconditions.checkNotNull with Objects.requireNonNull. Ethernet service related files are going to be moved into Connectivity mainline module. Replace the Preconditions.checkNotNull usage in EthernetNetworkFactory with Objects.requireNonNull. Bug: 210586283 Test: atest EthernetServiceTests Change-Id: Ibeaf687f706e8400f825cb2ca97bb1341774a97d --- .../com/android/server/ethernet/EthernetNetworkFactory.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 2886cf1e3d..a9f8b47fa1 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -16,8 +16,6 @@ package com.android.server.ethernet; -import static com.android.internal.util.Preconditions.checkNotNull; - import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; @@ -370,7 +368,7 @@ public class EthernetNetworkFactory extends NetworkFactory { @NonNull NetworkCapabilities capabilities, NetworkFactory networkFactory, Dependencies deps) { name = ifaceName; - mCapabilities = checkNotNull(capabilities); + mCapabilities = Objects.requireNonNull(capabilities); mHandler = handler; mContext = context; mNetworkFactory = networkFactory; From 3a26d1b8ed51e8fbb1b802708aa8032683ee25e4 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Tue, 21 Dec 2021 07:35:11 +0000 Subject: [PATCH 116/152] Import InterfaceParams class from f/libs/net/common. Ethernet service related files are going to be moved into Connectivity mainline module. Import InterfaceParams class in EthernetNetworkFactory from f/libs/net/common, which is visible to Connectivity module. Bug: 210586283 Test: atest EthernetServiceTests Change-Id: I98ebb04cc3c2b685464e7f2689424794957088b3 --- .../src/com/android/server/ethernet/EthernetNetworkFactory.java | 2 +- .../com/android/server/ethernet/EthernetNetworkFactoryTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 2886cf1e3d..fc26a6c135 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -37,7 +37,6 @@ import android.net.ip.IIpClient; import android.net.ip.IpClientCallbacks; import android.net.ip.IpClientUtil; import android.net.shared.ProvisioningConfiguration; -import android.net.util.InterfaceParams; import android.os.ConditionVariable; import android.os.Handler; import android.os.Looper; @@ -49,6 +48,7 @@ import android.util.SparseArray; 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; diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 6422358068..4abdf030ac 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -44,7 +44,6 @@ import android.net.NetworkProvider; import android.net.NetworkRequest; import android.net.ip.IIpClient; import android.net.ip.IpClientCallbacks; -import android.net.util.InterfaceParams; import android.os.Handler; import android.os.Looper; import android.os.test.TestLooper; @@ -53,6 +52,7 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.internal.R; +import com.android.net.module.util.InterfaceParams; import org.junit.After; import org.junit.Before; From 5fac76d3a2a3d0cf969c7874b57eee1c480f9526 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Tue, 14 Dec 2021 18:26:18 -0800 Subject: [PATCH 117/152] Stubbed net mgmt API methods in eth service Stubbed API methods in EthernetServiceImpl to be used for network management. Bug: 210487086 Bug: 210485380 Test: make, flash and boot and atest EthernetServiceTests Change-Id: I8bd5a6eca07d00e0f155b71e2960371989a13013 --- .../server/ethernet/EthernetServiceImpl.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 504b3da6cd..840806af18 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -16,11 +16,15 @@ package com.android.server.ethernet; +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.IInternalNetworkManagementListener; import android.net.ITetheredInterfaceCallback; +import android.net.InternalNetworkUpdateRequest; import android.net.IpConfiguration; import android.os.Binder; import android.os.Handler; @@ -209,4 +213,24 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { mHandler.dump(new PrintWriterPrinter(pw), "EthernetServiceImpl"); pw.decreaseIndent(); } + + @Override + public void updateConfiguration(@NonNull final String iface, + @NonNull final InternalNetworkUpdateRequest request, + @Nullable final IInternalNetworkManagementListener listener) { + Log.i(TAG, "updateConfiguration called with: iface=" + iface + + ", request=" + request + ", listener=" + listener); + } + + @Override + public void connectNetwork(@NonNull final String iface, + @Nullable final IInternalNetworkManagementListener listener) { + Log.i(TAG, "connectNetwork called with: iface=" + iface + ", listener=" + listener); + } + + @Override + public void disconnectNetwork(@NonNull final String iface, + @Nullable final IInternalNetworkManagementListener listener) { + Log.i(TAG, "disconnectNetwork called with: iface=" + iface + ", listener=" + listener); + } } From 39e7a7799131bb69688b4742aa97970013596552 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Thu, 16 Dec 2021 04:11:43 +0000 Subject: [PATCH 118/152] Remove INetworkManagementService usage from EthernetTracker. Ethernet service related files are going to be moved into Connectivity module. INetworkManagementService won't be visible to EthernetTracker since it's a hidden class. Alternatively, use INetd APIs to replace INetworkManagementService usages, including below API changes: - mNMService.listInterfaces -> mNetd.interfaceGetList - mNMService.getInterfaceConfig -> NetdUtils.getInterfaceConfigParcel - remove InterfaceConfiguration usage, use NetdUtils APIs instead. - mNMService.registerObserver -> mNetd.registerUnsolicitedEventListener - for this API change, also replace the parameter BaseNetworkObserver class with BaseNetdUnsolicitedEventListener class. Bug: 210586283 Test: atest FrameworksNetTests Test: atest EthernetServiceTests Change-Id: Ic14c55a6a36b774006931a6fbcbfdec0c51a16e9 --- .../server/ethernet/EthernetTracker.java | 51 +++++++++---------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index beb950cb9d..65c3cefe0d 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -24,7 +24,7 @@ import android.content.Context; import android.net.IEthernetServiceListener; import android.net.INetd; import android.net.ITetheredInterfaceCallback; -import android.net.InterfaceConfiguration; +import android.net.InterfaceConfigurationParcel; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; @@ -33,19 +33,18 @@ 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.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 com.android.server.net.BaseNetworkObserver; import java.io.FileDescriptor; import java.net.InetAddress; @@ -72,8 +71,8 @@ final class EthernetTracker { private static final int INTERFACE_MODE_CLIENT = 1; private static final int INTERFACE_MODE_SERVER = 2; - private final static String TAG = EthernetTracker.class.getSimpleName(); - private final static boolean DBG = EthernetNetworkFactory.DBG; + 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+"; @@ -91,7 +90,6 @@ final class EthernetTracker { new ConcurrentHashMap<>(); private final Context mContext; - private final INetworkManagementService mNMService; private final INetd mNetd; private final Handler mHandler; private final EthernetNetworkFactory mFactory; @@ -109,7 +107,8 @@ final class EthernetTracker { private boolean mTetheredInterfaceWasAvailable = false; private volatile IpConfiguration mIpConfigForDefaultInterface; - private class TetheredInterfaceRequestList extends RemoteCallbackList { + private class TetheredInterfaceRequestList extends + RemoteCallbackList { @Override public void onCallbackDied(ITetheredInterfaceCallback cb, Object cookie) { mHandler.post(EthernetTracker.this::maybeUntetherDefaultInterface); @@ -121,8 +120,6 @@ final class EthernetTracker { mHandler = handler; // The services we use. - IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); - mNMService = INetworkManagementService.Stub.asInterface(b); mNetd = INetd.Stub.asInterface( (IBinder) context.getSystemService(Context.NETD_SERVICE)); Objects.requireNonNull(mNetd, "could not get netd instance"); @@ -155,8 +152,9 @@ final class EthernetTracker { } try { - mNMService.registerObserver(new InterfaceObserver()); - } catch (RemoteException e) { + PermissionUtils.enforceNetworkStackPermission(mContext); + mNetd.registerUnsolicitedEventListener(new InterfaceObserver()); + } catch (RemoteException | ServiceSpecificException e) { Log.e(TAG, "Could not register InterfaceObserver " + e); } @@ -286,24 +284,24 @@ final class EthernetTracker { } private void addInterface(String iface) { - InterfaceConfiguration config = null; + InterfaceConfigurationParcel config = null; // Bring up the interface so we get link status indications. try { PermissionUtils.enforceNetworkStackPermission(mContext); NetdUtils.setInterfaceUp(mNetd, iface); - config = mNMService.getInterfaceConfig(iface); - } catch (RemoteException | IllegalStateException e) { + 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 for " + iface + ". Bailing out."); + Log.e(TAG, "Null interface config parcelable for " + iface + ". Bailing out."); return; } - final String hwAddress = config.getHardwareAddress(); + final String hwAddress = config.hwAddr; NetworkCapabilities nc = mNetworkCapabilities.get(iface); if (nc == null) { @@ -331,7 +329,7 @@ final class EthernetTracker { // 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")) { + if (NetdUtils.hasFlag(config, "running")) { updateInterfaceState(iface, true); } } @@ -408,20 +406,19 @@ final class EthernetTracker { private void trackAvailableInterfaces() { try { - final String[] ifaces = mNMService.listInterfaces(); + final String[] ifaces = mNetd.interfaceGetList(); for (String iface : ifaces) { maybeTrackInterface(iface); } - } catch (RemoteException | IllegalStateException e) { + } catch (RemoteException | ServiceSpecificException e) { Log.e(TAG, "Could not get list of interfaces " + e); } } - - private class InterfaceObserver extends BaseNetworkObserver { + private class InterfaceObserver extends BaseNetdUnsolicitedEventListener { @Override - public void interfaceLinkStateChanged(String iface, boolean up) { + public void onInterfaceLinkStateChanged(String iface, boolean up) { if (DBG) { Log.i(TAG, "interfaceLinkStateChanged, iface: " + iface + ", up: " + up); } @@ -429,12 +426,12 @@ final class EthernetTracker { } @Override - public void interfaceAdded(String iface) { + public void onInterfaceAdded(String iface) { mHandler.post(() -> maybeTrackInterface(iface)); } @Override - public void interfaceRemoved(String iface) { + public void onInterfaceRemoved(String iface) { mHandler.post(() -> stopTrackingInterface(iface)); } } @@ -484,9 +481,9 @@ final class EthernetTracker { .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); if (isTestIface) { - builder.addTransportType(NetworkCapabilities.TRANSPORT_TEST); + builder.addTransportType(NetworkCapabilities.TRANSPORT_TEST); } else { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); } return builder.build(); From cc1dac61b38605c6cdda8f5d645ab025d904ed80 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Sun, 26 Dec 2021 12:43:03 -0800 Subject: [PATCH 119/152] Eth Service updates to validate net mgmt calls Updates to ethernet service code to validate calls to ethernet network management APIs. Bug: 210485380 Test: atest EthernetServiceTests Change-Id: I66b91c6d12e6859de33760ab21bb00f1477720e8 --- .../server/ethernet/EthernetServiceImpl.java | 46 +++++- .../ethernet/EthernetServiceImplTest.java | 142 ++++++++++++++++++ 2 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 840806af18..fd690b5547 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -33,6 +33,7 @@ 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; @@ -49,7 +50,8 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { private static final String TAG = "EthernetServiceImpl"; private final Context mContext; - private final AtomicBoolean mStarted = new AtomicBoolean(false); + @VisibleForTesting + final AtomicBoolean mStarted = new AtomicBoolean(false); private Handler mHandler; private EthernetTracker mTracker; @@ -70,6 +72,17 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { "ConnectivityService"); } + private void enforceAutomotiveDevice(final @NonNull String methodName) { + PermissionUtils.enforceSystemFeature(mContext, PackageManager.FEATURE_AUTOMOTIVE, + methodName + " is only available on automotive devices."); + } + + private void enforceInterfaceIsTracked(final @NonNull String iface) { + if(!mTracker.isTrackingInterface(iface)) { + throw new UnsupportedOperationException("The given iface is not currently tracked."); + } + } + private boolean checkUseRestrictedNetworksPermission() { return mContext.checkCallingOrSelfPermission( android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS) @@ -89,6 +102,12 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { mStarted.set(true); } + private void logIfEthernetNotStarted() { + if (!mStarted.get()) { + throw new IllegalStateException("System isn't ready to change ethernet configurations"); + } + } + @Override public String[] getAvailableInterfaces() throws RemoteException { enforceAccessPermission(); @@ -116,9 +135,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { */ @Override public void setConfiguration(String iface, IpConfiguration config) { - if (!mStarted.get()) { - Log.w(TAG, "System isn't ready enough to change ethernet configuration"); - } + logIfEthernetNotStarted(); PermissionUtils.enforceNetworkStackPermission(mContext); @@ -214,23 +231,44 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { pw.decreaseIndent(); } + /** + * Validate the state of ethernet for APIs tied to network management. + * + * @param iface the ethernet interface name to operate on. + * @param methodName the name of the calling method. + */ + private void validateNetworkManagementState(@NonNull final String iface, + final @NonNull String methodName) { + logIfEthernetNotStarted(); + + // TODO: add permission check here for MANAGE_INTERNAL_NETWORKS when it's available. + Objects.requireNonNull(iface, "Pass a non-null iface."); + Objects.requireNonNull(methodName, "Pass a non-null methodName."); + enforceAutomotiveDevice(methodName); + enforceInterfaceIsTracked(iface); + } + @Override public void updateConfiguration(@NonNull final String iface, @NonNull final InternalNetworkUpdateRequest request, @Nullable final IInternalNetworkManagementListener listener) { Log.i(TAG, "updateConfiguration called with: iface=" + iface + ", request=" + request + ", listener=" + listener); + validateNetworkManagementState(iface, "updateConfiguration()"); + // TODO: validate that iface is listed in overlay config_ethernet_interfaces } @Override public void connectNetwork(@NonNull final String iface, @Nullable final IInternalNetworkManagementListener listener) { Log.i(TAG, "connectNetwork called with: iface=" + iface + ", listener=" + listener); + validateNetworkManagementState(iface, "connectNetwork()"); } @Override public void disconnectNetwork(@NonNull final String iface, @Nullable final IInternalNetworkManagementListener listener) { Log.i(TAG, "disconnectNetwork called with: iface=" + iface + ", listener=" + listener); + validateNetworkManagementState(iface, "disconnectNetwork()"); } } diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java new file mode 100644 index 0000000000..9869b82cb2 --- /dev/null +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java @@ -0,0 +1,142 @@ +/* + * 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 static org.junit.Assert.assertThrows; + +import static org.mockito.Mockito.doReturn; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.net.InternalNetworkUpdateRequest; +import android.net.IpConfiguration; +import android.net.StaticIpConfiguration; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class EthernetServiceImplTest { + private EthernetServiceImpl mEthernetServiceImpl; + @Mock private Context mContext; + @Mock private PackageManager mPackageManager; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + doReturn(mPackageManager).when(mContext).getPackageManager(); + mEthernetServiceImpl = new EthernetServiceImpl(mContext); + mEthernetServiceImpl.mStarted.set(true); + } + + @Test + public void testSetConfigurationRejectsWhenEthNotStarted() { + mEthernetServiceImpl.mStarted.set(false); + assertThrows(IllegalStateException.class, () -> { + mEthernetServiceImpl.setConfiguration("" /* iface */, new IpConfiguration()); + }); + } + + @Test + public void testUpdateConfigurationRejectsWhenEthNotStarted() { + mEthernetServiceImpl.mStarted.set(false); + assertThrows(IllegalStateException.class, () -> { + final InternalNetworkUpdateRequest r = + new InternalNetworkUpdateRequest(new StaticIpConfiguration(), null); + + mEthernetServiceImpl.updateConfiguration("" /* iface */, r, null /* listener */); + }); + } + + @Test + public void testConnectNetworkRejectsWhenEthNotStarted() { + mEthernetServiceImpl.mStarted.set(false); + assertThrows(IllegalStateException.class, () -> { + mEthernetServiceImpl.connectNetwork("" /* iface */, null /* listener */); + }); + } + + @Test + public void testDisconnectNetworkRejectsWhenEthNotStarted() { + mEthernetServiceImpl.mStarted.set(false); + assertThrows(IllegalStateException.class, () -> { + mEthernetServiceImpl.disconnectNetwork("" /* iface */, null /* listener */); + }); + } + + @Test + public void testUpdateConfigurationRejectsNullIface() { + assertThrows(NullPointerException.class, () -> { + final InternalNetworkUpdateRequest r = + new InternalNetworkUpdateRequest(new StaticIpConfiguration(), null); + + mEthernetServiceImpl.updateConfiguration(null /* iface */, r, null /* listener */); + }); + } + + @Test + public void testConnectNetworkRejectsNullIface() { + assertThrows(NullPointerException.class, () -> { + mEthernetServiceImpl.connectNetwork(null /* iface */, null /* listener */); + }); + } + + @Test + public void testDisconnectNetworkRejectsNullIface() { + assertThrows(NullPointerException.class, () -> { + mEthernetServiceImpl.disconnectNetwork(null /* iface */, null /* listener */); + }); + } + + @Test + public void testUpdateConfigurationRejectsWithoutAutomotiveFeature() { + disableAutomotiveFeature(); + assertThrows(UnsupportedOperationException.class, () -> { + final InternalNetworkUpdateRequest r = + new InternalNetworkUpdateRequest(new StaticIpConfiguration(), null); + + mEthernetServiceImpl.updateConfiguration("" /* iface */, r, null /* listener */); + }); + } + + @Test + public void testConnectNetworkRejectsWithoutAutomotiveFeature() { + disableAutomotiveFeature(); + assertThrows(UnsupportedOperationException.class, () -> { + mEthernetServiceImpl.connectNetwork("" /* iface */, null /* listener */); + }); + } + + @Test + public void testDisconnectNetworkRejectsWithoutAutomotiveFeature() { + disableAutomotiveFeature(); + assertThrows(UnsupportedOperationException.class, () -> { + mEthernetServiceImpl.disconnectNetwork("" /* iface */, null /* listener */); + }); + } + + private void disableAutomotiveFeature() { + doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); + } +} From a5f724dfdd751cdc9ee1e60a2d77cc30b81a01bc Mon Sep 17 00:00:00 2001 From: James Mattis Date: Tue, 28 Dec 2021 15:04:44 -0800 Subject: [PATCH 120/152] Changes to make eth service methods more testable Updates to make methods in EthernetServiceImpl that rely on EthernetTracker unit testable. This CL also includes added tests for such methods in EthernetServiceImplTest. Bug: 210485380 Test: atest EthernetServiceTests Change-Id: I63969b60cc4cf9d391e2cd21d02e1bdc8988aba8 --- .../server/ethernet/EthernetService.java | 11 +++- .../server/ethernet/EthernetServiceImpl.java | 20 +++----- .../server/ethernet/EthernetTracker.java | 10 ++-- .../ethernet/EthernetServiceImplTest.java | 51 ++++++++++++++++--- 4 files changed, 68 insertions(+), 24 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetService.java b/service-t/src/com/android/server/ethernet/EthernetService.java index 2448146ed5..467ab677d8 100644 --- a/service-t/src/com/android/server/ethernet/EthernetService.java +++ b/service-t/src/com/android/server/ethernet/EthernetService.java @@ -17,17 +17,24 @@ package com.android.server.ethernet; import android.content.Context; +import android.os.Handler; +import android.os.HandlerThread; import android.util.Log; import com.android.server.SystemService; public final class EthernetService extends SystemService { private static final String TAG = "EthernetService"; - final EthernetServiceImpl mImpl; + private static final String THREAD_NAME = "EthernetServiceThread"; + private final EthernetServiceImpl mImpl; public EthernetService(Context context) { super(context); - mImpl = new EthernetServiceImpl(context); + final HandlerThread handlerThread = new HandlerThread(THREAD_NAME); + handlerThread.start(); + mImpl = new EthernetServiceImpl( + context, handlerThread.getThreadHandler(), + new EthernetTracker(context, handlerThread.getThreadHandler())); } @Override diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index fd690b5547..3479ea4722 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -28,7 +28,6 @@ import android.net.InternalNetworkUpdateRequest; import android.net.IpConfiguration; import android.os.Binder; import android.os.Handler; -import android.os.HandlerThread; import android.os.RemoteException; import android.util.Log; import android.util.PrintWriterPrinter; @@ -49,15 +48,17 @@ import java.util.concurrent.atomic.AtomicBoolean; public class EthernetServiceImpl extends IEthernetManager.Stub { private static final String TAG = "EthernetServiceImpl"; - private final Context mContext; @VisibleForTesting final AtomicBoolean mStarted = new AtomicBoolean(false); + private final Context mContext; + private final Handler mHandler; + private final EthernetTracker mTracker; - private Handler mHandler; - private EthernetTracker mTracker; - - public EthernetServiceImpl(Context context) { + EthernetServiceImpl(@NonNull final Context context, @NonNull final Handler handler, + @NonNull final EthernetTracker tracker) { mContext = context; + mHandler = handler; + mTracker = tracker; } private void enforceAccessPermission() { @@ -91,14 +92,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { public void start() { Log.i(TAG, "Starting Ethernet service"); - - HandlerThread handlerThread = new HandlerThread("EthernetServiceThread"); - handlerThread.start(); - mHandler = new Handler(handlerThread.getLooper()); - - mTracker = new EthernetTracker(mContext, mHandler); mTracker.start(); - mStarted.set(true); } diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 65c3cefe0d..9660194508 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -18,6 +18,8 @@ package com.android.server.ethernet; 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; @@ -67,7 +69,8 @@ import java.util.concurrent.ConcurrentHashMap; * *

All public or package private methods must be thread-safe unless stated otherwise. */ -final class EthernetTracker { +@VisibleForTesting(visibility = PACKAGE) +public class EthernetTracker { private static final int INTERFACE_MODE_CLIENT = 1; private static final int INTERFACE_MODE_SERVER = 2; @@ -138,10 +141,10 @@ final class EthernetTracker { NetworkCapabilities nc = createNetworkCapabilities(true /* clear default capabilities */); mFactory = new EthernetNetworkFactory(handler, context, nc); - mFactory.register(); } void start() { + mFactory.register(); mConfigStore.read(); // Default interface is just the first one we want to track. @@ -176,7 +179,8 @@ final class EthernetTracker { return mIpConfigurations.get(iface); } - boolean isTrackingInterface(String iface) { + @VisibleForTesting(visibility = PACKAGE) + protected boolean isTrackingInterface(String iface) { return mFactory.hasInterface(iface); } diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java index 9869b82cb2..516e574522 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java @@ -20,11 +20,13 @@ import static org.junit.Assert.assertThrows; import static org.mockito.Mockito.doReturn; +import android.annotation.NonNull; import android.content.Context; import android.content.pm.PackageManager; import android.net.InternalNetworkUpdateRequest; import android.net.IpConfiguration; import android.net.StaticIpConfiguration; +import android.os.Handler; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -38,16 +40,21 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) @SmallTest public class EthernetServiceImplTest { + private static final String TEST_IFACE = "test123"; private EthernetServiceImpl mEthernetServiceImpl; @Mock private Context mContext; + @Mock private Handler mHandler; + @Mock private EthernetTracker mEthernetTracker; @Mock private PackageManager mPackageManager; @Before public void setup() { MockitoAnnotations.initMocks(this); doReturn(mPackageManager).when(mContext).getPackageManager(); - mEthernetServiceImpl = new EthernetServiceImpl(mContext); + mEthernetServiceImpl = new EthernetServiceImpl(mContext, mHandler, mEthernetTracker); mEthernetServiceImpl.mStarted.set(true); + toggleAutomotiveFeature(true); + shouldTrackIface(TEST_IFACE, true); } @Test @@ -111,7 +118,7 @@ public class EthernetServiceImplTest { @Test public void testUpdateConfigurationRejectsWithoutAutomotiveFeature() { - disableAutomotiveFeature(); + toggleAutomotiveFeature(false); assertThrows(UnsupportedOperationException.class, () -> { final InternalNetworkUpdateRequest r = new InternalNetworkUpdateRequest(new StaticIpConfiguration(), null); @@ -122,7 +129,7 @@ public class EthernetServiceImplTest { @Test public void testConnectNetworkRejectsWithoutAutomotiveFeature() { - disableAutomotiveFeature(); + toggleAutomotiveFeature(false); assertThrows(UnsupportedOperationException.class, () -> { mEthernetServiceImpl.connectNetwork("" /* iface */, null /* listener */); }); @@ -130,13 +137,45 @@ public class EthernetServiceImplTest { @Test public void testDisconnectNetworkRejectsWithoutAutomotiveFeature() { - disableAutomotiveFeature(); + toggleAutomotiveFeature(false); assertThrows(UnsupportedOperationException.class, () -> { mEthernetServiceImpl.disconnectNetwork("" /* iface */, null /* listener */); }); } - private void disableAutomotiveFeature() { - doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); + private void toggleAutomotiveFeature(final boolean isEnabled) { + doReturn(isEnabled) + .when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); + } + + @Test + public void testUpdateConfigurationRejectsWithUntrackedIface() { + shouldTrackIface(TEST_IFACE, false); + assertThrows(UnsupportedOperationException.class, () -> { + final InternalNetworkUpdateRequest r = + new InternalNetworkUpdateRequest(new StaticIpConfiguration(), null); + + mEthernetServiceImpl.updateConfiguration(TEST_IFACE, r, null /* listener */); + }); + } + + @Test + public void testConnectNetworkRejectsWithUntrackedIface() { + shouldTrackIface(TEST_IFACE, false); + assertThrows(UnsupportedOperationException.class, () -> { + mEthernetServiceImpl.connectNetwork(TEST_IFACE, null /* listener */); + }); + } + + @Test + public void testDisconnectNetworkRejectsWithUntrackedIface() { + shouldTrackIface(TEST_IFACE, false); + assertThrows(UnsupportedOperationException.class, () -> { + mEthernetServiceImpl.disconnectNetwork(TEST_IFACE, null /* listener */); + }); + } + + private void shouldTrackIface(@NonNull final String iface, final boolean shouldTrack) { + doReturn(shouldTrack).when(mEthernetTracker).isTrackingInterface(iface); } } From 54e3aebb956780bc2eccb2d37c3c233fd962db3c Mon Sep 17 00:00:00 2001 From: James Mattis Date: Tue, 28 Dec 2021 18:24:42 -0800 Subject: [PATCH 121/152] Using PermissionUtils for common net permissions Code clean-up to use PermissionUtils for common networking permissions. Should be a no-op. Bug: 210485380 Test: make, flash and boot Change-Id: I4be08243156e9d04f4b3b44ab7328d0f6f7fdda1 --- .../server/ethernet/EthernetServiceImpl.java | 37 +++++-------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 3479ea4722..f107865c30 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -61,18 +61,6 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { mTracker = tracker; } - private void enforceAccessPermission() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.ACCESS_NETWORK_STATE, - "EthernetService"); - } - - private void enforceUseRestrictedNetworksPermission() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS, - "ConnectivityService"); - } - private void enforceAutomotiveDevice(final @NonNull String methodName) { PermissionUtils.enforceSystemFeature(mContext, PackageManager.FEATURE_AUTOMOTIVE, methodName + " is only available on automotive devices."); @@ -85,9 +73,8 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { } private boolean checkUseRestrictedNetworksPermission() { - return mContext.checkCallingOrSelfPermission( - android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS) - == PackageManager.PERMISSION_GRANTED; + return PermissionUtils.checkAnyPermissionOf(mContext, + android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS); } public void start() { @@ -104,8 +91,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Override public String[] getAvailableInterfaces() throws RemoteException { - enforceAccessPermission(); - + PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); return mTracker.getInterfaces(checkUseRestrictedNetworksPermission()); } @@ -115,10 +101,9 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { */ @Override public IpConfiguration getConfiguration(String iface) { - enforceAccessPermission(); - + PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); if (mTracker.isRestrictedInterface(iface)) { - enforceUseRestrictedNetworksPermission(); + PermissionUtils.enforceRestrictedNetworkPermission(mContext, TAG); } return new IpConfiguration(mTracker.getIpConfiguration(iface)); @@ -132,9 +117,8 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { logIfEthernetNotStarted(); PermissionUtils.enforceNetworkStackPermission(mContext); - if (mTracker.isRestrictedInterface(iface)) { - enforceUseRestrictedNetworksPermission(); + PermissionUtils.enforceRestrictedNetworkPermission(mContext, TAG); } // TODO: this does not check proxy settings, gateways, etc. @@ -147,10 +131,9 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { */ @Override public boolean isAvailable(String iface) { - enforceAccessPermission(); - + PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); if (mTracker.isRestrictedInterface(iface)) { - enforceUseRestrictedNetworksPermission(); + PermissionUtils.enforceRestrictedNetworkPermission(mContext, TAG); } return mTracker.isTrackingInterface(iface); @@ -164,7 +147,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } - enforceAccessPermission(); + PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); mTracker.addListener(listener, checkUseRestrictedNetworksPermission()); } @@ -176,7 +159,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } - enforceAccessPermission(); + PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); mTracker.removeListener(listener); } From 18ed8f6680668b38f5a9baa66c40f006b11a2e74 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Fri, 31 Dec 2021 15:54:23 -0800 Subject: [PATCH 122/152] Code cleanup on EthernetNetworkFactoryTest Code cleanup on EthernetNetworkFactoryTest. Bug: 210485380 Test: atest EthernetServiceTests: com.android.server.ethernet.EthernetNetworkFactoryTest Change-Id: I38c568d0760e4273f1ca8540bac268f07876b67f --- .../ethernet/EthernetNetworkFactoryTest.java | 173 +++++++++--------- 1 file changed, 85 insertions(+), 88 deletions(-) diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 4abdf030ac..08a70a6f40 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -64,11 +64,11 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) @SmallTest public class EthernetNetworkFactoryTest { - private TestLooper mLooper = new TestLooper(); + private static final String TEST_IFACE = "test123"; + private final TestLooper mLooper = new TestLooper(); private Handler mHandler; private EthernetNetworkFactory mNetFactory = null; private IpClientCallbacks mIpClientCallbacks; - private int mNetworkRequestCount = 0; @Mock private Context mContext; @Mock private Resources mResources; @Mock private EthernetNetworkFactory.Dependencies mDeps; @@ -79,10 +79,7 @@ public class EthernetNetworkFactoryTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mHandler = new Handler(mLooper.getLooper()); - mNetworkRequestCount = 0; - mNetFactory = new EthernetNetworkFactory(mHandler, mContext, createDefaultFilterCaps(), mDeps); @@ -129,10 +126,24 @@ public class EthernetNetworkFactoryTest { }).when(mIpClient).shutdown(); } + private void triggerOnProvisioningSuccess() { + mIpClientCallbacks.onProvisioningSuccess(new LinkProperties()); + mLooper.dispatchAll(); + } + + private void triggerOnProvisioningFailure() { + mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); + mLooper.dispatchAll(); + } + + private void triggerOnReachabilityLost() { + mIpClientCallbacks.onReachabilityLost("ReachabilityLost"); + mLooper.dispatchAll(); + } + private void setupContext() { when(mContext.getResources()).thenReturn(mResources); - when(mResources.getString(R.string.config_ethernet_tcp_buffers)).thenReturn( - "524288,1048576,3145728,524288,1048576,2097152"); + when(mResources.getString(R.string.config_ethernet_tcp_buffers)).thenReturn(""); } @After @@ -184,8 +195,7 @@ public class EthernetNetworkFactoryTest { mNetFactory.addInterface(iface, iface, createInterfaceCapsBuilder(transportType).build(), createDefaultIpConfig()); assertTrue(mNetFactory.updateInterfaceLinkState(iface, true)); - verify(mDeps).makeIpClient(any(Context.class), anyString(), any()); - verify(mIpClient).startProvisioning(any()); + verifyStart(); clearInvocations(mDeps); clearInvocations(mIpClient); } @@ -197,18 +207,23 @@ public class EthernetNetworkFactoryTest { ConnectivityManager.TYPE_ETHERNET); } + private void createVerifyAndRemoveProvisionedInterface(final int transportType, + final int expectedLegacyType) throws Exception { + createAndVerifyProvisionedInterface(TEST_IFACE, transportType, + expectedLegacyType); + mNetFactory.removeInterface(TEST_IFACE); + } + private void createAndVerifyProvisionedInterface( @NonNull final String iface, final int transportType, final int expectedLegacyType) throws Exception { createInterfaceUndergoingProvisioning(iface, transportType); - mIpClientCallbacks.onProvisioningSuccess(new LinkProperties()); - mLooper.dispatchAll(); + triggerOnProvisioningSuccess(); // provisioning succeeded, verify that the network agent is created, registered, marked // as connected and legacy type are correctly set. verify(mDeps).makeEthernetNetworkAgent(any(), any(), any(), any(), argThat(x -> x.getLegacyType() == expectedLegacyType), any(), any()); - verify(mNetworkAgent).register(); - verify(mNetworkAgent).markConnected(); + verifyNetworkAgentRegistersAndConnects(); clearInvocations(mDeps); clearInvocations(mNetworkAgent); } @@ -228,8 +243,7 @@ public class EthernetNetworkFactoryTest { verify(mNetworkAgent, never()).register(); mNetFactory.releaseNetworkFor(createDefaultRequest()); - verify(mIpClient).shutdown(); - verify(mNetworkAgent).unregister(); + verifyStop(); clearInvocations(mIpClient); clearInvocations(mNetworkAgent); @@ -237,7 +251,7 @@ public class EthernetNetworkFactoryTest { @Test public void testAcceptRequest() throws Exception { - createInterfaceUndergoingProvisioning("eth0"); + createInterfaceUndergoingProvisioning(TEST_IFACE); assertTrue(mNetFactory.acceptRequest(createDefaultRequest())); NetworkRequest wifiRequest = createDefaultRequestBuilder() @@ -248,27 +262,23 @@ public class EthernetNetworkFactoryTest { @Test public void testUpdateInterfaceLinkStateForActiveProvisioningInterface() throws Exception { - String iface = "eth0"; - createInterfaceUndergoingProvisioning(iface); + createInterfaceUndergoingProvisioning(TEST_IFACE); // verify that the IpClient gets shut down when interface state changes to down. - assertTrue(mNetFactory.updateInterfaceLinkState(iface, false)); + assertTrue(mNetFactory.updateInterfaceLinkState(TEST_IFACE, false)); verify(mIpClient).shutdown(); } @Test public void testUpdateInterfaceLinkStateForProvisionedInterface() throws Exception { - String iface = "eth0"; - createAndVerifyProvisionedInterface(iface); - assertTrue(mNetFactory.updateInterfaceLinkState(iface, false)); - verify(mIpClient).shutdown(); - verify(mNetworkAgent).unregister(); + createAndVerifyProvisionedInterface(TEST_IFACE); + assertTrue(mNetFactory.updateInterfaceLinkState(TEST_IFACE, false)); + verifyStop(); } @Test public void testUpdateInterfaceLinkStateForUnprovisionedInterface() throws Exception { - String iface = "eth0"; - createUnprovisionedInterface(iface); - assertTrue(mNetFactory.updateInterfaceLinkState(iface, false)); + createUnprovisionedInterface(TEST_IFACE); + assertTrue(mNetFactory.updateInterfaceLinkState(TEST_IFACE, false)); // There should not be an active IPClient or NetworkAgent. verify(mDeps, never()).makeIpClient(any(), any(), any()); verify(mDeps, never()) @@ -284,75 +294,64 @@ public class EthernetNetworkFactoryTest { @Test public void testNeedNetworkForOnProvisionedInterface() throws Exception { - createAndVerifyProvisionedInterface("eth0"); + createAndVerifyProvisionedInterface(TEST_IFACE); mNetFactory.needNetworkFor(createDefaultRequest()); verify(mIpClient, never()).startProvisioning(any()); } @Test public void testNeedNetworkForOnUnprovisionedInterface() throws Exception { - createUnprovisionedInterface("eth0"); + createUnprovisionedInterface(TEST_IFACE); mNetFactory.needNetworkFor(createDefaultRequest()); verify(mIpClient).startProvisioning(any()); - mIpClientCallbacks.onProvisioningSuccess(new LinkProperties()); - mLooper.dispatchAll(); - verify(mNetworkAgent).register(); - verify(mNetworkAgent).markConnected(); + triggerOnProvisioningSuccess(); + verifyNetworkAgentRegistersAndConnects(); } @Test public void testNeedNetworkForOnInterfaceUndergoingProvisioning() throws Exception { - createInterfaceUndergoingProvisioning("eth0"); + createInterfaceUndergoingProvisioning(TEST_IFACE); mNetFactory.needNetworkFor(createDefaultRequest()); verify(mIpClient, never()).startProvisioning(any()); - mIpClientCallbacks.onProvisioningSuccess(new LinkProperties()); - mLooper.dispatchAll(); - verify(mNetworkAgent).register(); - verify(mNetworkAgent).markConnected(); + triggerOnProvisioningSuccess(); + verifyNetworkAgentRegistersAndConnects(); } @Test public void testProvisioningLoss() throws Exception { - String iface = "eth0"; - when(mDeps.getNetworkInterfaceByName(iface)).thenReturn(mInterfaceParams); - createAndVerifyProvisionedInterface(iface); + when(mDeps.getNetworkInterfaceByName(TEST_IFACE)).thenReturn(mInterfaceParams); + createAndVerifyProvisionedInterface(TEST_IFACE); - mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); - mLooper.dispatchAll(); - verify(mIpClient).shutdown(); - verify(mNetworkAgent).unregister(); + triggerOnProvisioningFailure(); + verifyStop(); // provisioning loss should trigger a retry, since the interface is still there verify(mIpClient).startProvisioning(any()); } @Test public void testProvisioningLossForDisappearedInterface() throws Exception { - String iface = "eth0"; // mocked method returns null by default, but just to be explicit in the test: - when(mDeps.getNetworkInterfaceByName(eq(iface))).thenReturn(null); + when(mDeps.getNetworkInterfaceByName(eq(TEST_IFACE))).thenReturn(null); - createAndVerifyProvisionedInterface(iface); - mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); - mLooper.dispatchAll(); - verify(mIpClient).shutdown(); - verify(mNetworkAgent).unregister(); + createAndVerifyProvisionedInterface(TEST_IFACE); + triggerOnProvisioningFailure(); + verifyStop(); // the interface disappeared and getNetworkInterfaceByName returns null, we should not retry verify(mIpClient, never()).startProvisioning(any()); } @Test public void testIpClientIsNotStartedWhenLinkIsDown() throws Exception { - String iface = "eth0"; - createUnprovisionedInterface(iface); - mNetFactory.updateInterfaceLinkState(iface, false); + createUnprovisionedInterface(TEST_IFACE); + mNetFactory.updateInterfaceLinkState(TEST_IFACE, false); mNetFactory.needNetworkFor(createDefaultRequest()); NetworkRequest specificNetRequest = new NetworkRequest.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) - .setNetworkSpecifier(new EthernetNetworkSpecifier(iface)) + .setNetworkSpecifier(new EthernetNetworkSpecifier(TEST_IFACE)) .build(); mNetFactory.needNetworkFor(specificNetRequest); @@ -363,7 +362,7 @@ public class EthernetNetworkFactoryTest { @Test public void testLinkPropertiesChanged() throws Exception { - createAndVerifyProvisionedInterface("eth0"); + createAndVerifyProvisionedInterface(TEST_IFACE); LinkProperties lp = new LinkProperties(); mIpClientCallbacks.onLinkPropertiesChange(lp); @@ -373,30 +372,26 @@ public class EthernetNetworkFactoryTest { @Test public void testNetworkUnwanted() throws Exception { - createAndVerifyProvisionedInterface("eth0"); + createAndVerifyProvisionedInterface(TEST_IFACE); mNetworkAgent.getCallbacks().onNetworkUnwanted(); mLooper.dispatchAll(); - verify(mIpClient).shutdown(); - verify(mNetworkAgent).unregister(); + verifyStop(); } @Test public void testNetworkUnwantedWithStaleNetworkAgent() throws Exception { - String iface = "eth0"; // ensures provisioning is restarted after provisioning loss - when(mDeps.getNetworkInterfaceByName(iface)).thenReturn(mInterfaceParams); - createAndVerifyProvisionedInterface(iface); + when(mDeps.getNetworkInterfaceByName(TEST_IFACE)).thenReturn(mInterfaceParams); + createAndVerifyProvisionedInterface(TEST_IFACE); EthernetNetworkAgent.Callbacks oldCbs = mNetworkAgent.getCallbacks(); // replace network agent in EthernetNetworkFactory // Loss of provisioning will restart the ip client and network agent. - mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); - mLooper.dispatchAll(); + triggerOnProvisioningFailure(); verify(mDeps).makeIpClient(any(), any(), any()); - mIpClientCallbacks.onProvisioningSuccess(new LinkProperties()); - mLooper.dispatchAll(); + triggerOnProvisioningSuccess(); verify(mDeps).makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any()); // verify that unwanted is ignored @@ -409,45 +404,47 @@ public class EthernetNetworkFactoryTest { @Test public void testTransportOverrideIsCorrectlySet() throws Exception { - final String iface = "eth0"; // createProvisionedInterface() has verifications in place for transport override // functionality which for EthernetNetworkFactory is network score and legacy type mappings. - createAndVerifyProvisionedInterface(iface, NetworkCapabilities.TRANSPORT_ETHERNET, + createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_ETHERNET, ConnectivityManager.TYPE_ETHERNET); - mNetFactory.removeInterface(iface); - createAndVerifyProvisionedInterface(iface, NetworkCapabilities.TRANSPORT_BLUETOOTH, + createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_BLUETOOTH, ConnectivityManager.TYPE_BLUETOOTH); - mNetFactory.removeInterface(iface); - createAndVerifyProvisionedInterface(iface, NetworkCapabilities.TRANSPORT_WIFI, + createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_WIFI, ConnectivityManager.TYPE_WIFI); - mNetFactory.removeInterface(iface); - createAndVerifyProvisionedInterface(iface, NetworkCapabilities.TRANSPORT_CELLULAR, + createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_CELLULAR, ConnectivityManager.TYPE_MOBILE); - mNetFactory.removeInterface(iface); - createAndVerifyProvisionedInterface(iface, NetworkCapabilities.TRANSPORT_LOWPAN, + createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_LOWPAN, ConnectivityManager.TYPE_NONE); - mNetFactory.removeInterface(iface); - createAndVerifyProvisionedInterface(iface, NetworkCapabilities.TRANSPORT_WIFI_AWARE, + createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_WIFI_AWARE, ConnectivityManager.TYPE_NONE); - mNetFactory.removeInterface(iface); - createAndVerifyProvisionedInterface(iface, NetworkCapabilities.TRANSPORT_TEST, + createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_TEST, ConnectivityManager.TYPE_NONE); - mNetFactory.removeInterface(iface); } @Test public void testReachabilityLoss() throws Exception { - String iface = "eth0"; - createAndVerifyProvisionedInterface(iface); + createAndVerifyProvisionedInterface(TEST_IFACE); - mIpClientCallbacks.onReachabilityLost("ReachabilityLost"); - mLooper.dispatchAll(); + triggerOnReachabilityLost(); // Reachability loss should trigger a stop and start, since the interface is still there - verify(mIpClient).shutdown(); - verify(mNetworkAgent).unregister(); + verifyStop(); + verifyStart(); + } + private void verifyStart() throws Exception { verify(mDeps).makeIpClient(any(Context.class), anyString(), any()); verify(mIpClient).startProvisioning(any()); } + + private void verifyStop() throws Exception { + verify(mIpClient).shutdown(); + verify(mNetworkAgent).unregister(); + } + + private void verifyNetworkAgentRegistersAndConnects() { + verify(mNetworkAgent).register(); + verify(mNetworkAgent).markConnected(); + } } From cfa7a08bcf9acf80db19518d4bd6e5ef435a2ca1 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Sun, 2 Jan 2022 19:53:39 -0800 Subject: [PATCH 123/152] Replacing IIpClient with Manager in ethNetFactory Replacing IIpClient with IpClientManager to reduce code duplication, increase readability and maintainability as well as making EthernetNetworkFactory easier to unit test. Bug: 210485380 Test: atest EthernetServiceTests Change-Id: I283653171c0cc47ad94a67d6dbd65b924cdf1ada --- .../ethernet/EthernetNetworkFactory.java | 59 +++++++------------ .../ethernet/EthernetNetworkFactoryTest.java | 16 ++--- 2 files changed, 30 insertions(+), 45 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 53928f7519..d7800c027a 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -33,6 +33,7 @@ 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; @@ -76,6 +77,10 @@ public class EthernetNetworkFactory extends NetworkFactory { 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) { @@ -283,7 +288,7 @@ public class EthernetNetworkFactory extends NetworkFactory { private boolean mLinkUp; private LinkProperties mLinkProperties = new LinkProperties(); - private volatile @Nullable IIpClient mIpClient; + private volatile @Nullable IpClientManager mIpClient; private @Nullable IpClientCallbacksImpl mIpClientCallback; private @Nullable EthernetNetworkAgent mNetworkAgent; private @Nullable IpConfiguration mIpConfig; @@ -317,7 +322,7 @@ public class EthernetNetworkFactory extends NetworkFactory { @Override public void onIpClientCreated(IIpClient ipClient) { - mIpClient = ipClient; + mIpClient = mDeps.makeIpClientManager(ipClient); mIpClientStartCv.open(); } @@ -356,14 +361,6 @@ public class EthernetNetworkFactory extends NetworkFactory { } } - private static void shutdownIpClient(IIpClient ipClient) { - try { - ipClient.shutdown(); - } catch (RemoteException e) { - Log.e(TAG, "Error stopping IpClient", e); - } - } - NetworkInterfaceState(String ifaceName, String hwAddress, Handler handler, Context context, @NonNull NetworkCapabilities capabilities, NetworkFactory networkFactory, Dependencies deps) { @@ -509,7 +506,7 @@ public class EthernetNetworkFactory extends NetworkFactory { void stop() { // Invalidate all previous start requests if (mIpClient != null) { - shutdownIpClient(mIpClient); + mIpClient.shutdown(); mIpClientCallback.awaitIpClientShutdown(); mIpClient = null; } @@ -522,41 +519,30 @@ public class EthernetNetworkFactory extends NetworkFactory { mLinkProperties.clear(); } - private static void provisionIpClient(IIpClient ipClient, IpConfiguration config, - String tcpBufferSizes) { + 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) { - try { - ipClient.setHttpProxy(config.getHttpProxy()); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } + ipClient.setHttpProxy(config.getHttpProxy()); } if (!TextUtils.isEmpty(tcpBufferSizes)) { - try { - ipClient.setTcpBufferSizes(tcpBufferSizes); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } + ipClient.setTcpBufferSizes(tcpBufferSizes); } - final ProvisioningConfiguration provisioningConfiguration; + ipClient.startProvisioning(createProvisioningConfiguration(config)); + } + + private static ProvisioningConfiguration createProvisioningConfiguration( + @NonNull final IpConfiguration config) { if (config.getIpAssignment() == IpAssignment.STATIC) { - provisioningConfiguration = new ProvisioningConfiguration.Builder() + return new ProvisioningConfiguration.Builder() .withStaticConfiguration(config.getStaticIpConfiguration()) .build(); - } else { - provisioningConfiguration = new ProvisioningConfiguration.Builder() + } + return new ProvisioningConfiguration.Builder() .withProvisioningTimeoutMs(0) .build(); - } - - try { - ipClient.startProvisioning(provisioningConfiguration.toStableParcelable()); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } } void restart(){ @@ -589,10 +575,7 @@ public class EthernetNetworkFactory extends NetworkFactory { NetworkInterfaceState ifaceState = mTrackingInterfaces.get(iface); pw.println(iface + ":" + ifaceState); pw.increaseIndent(); - final IIpClient ipClient = ifaceState.mIpClient; - if (ipClient != null) { - IpClientUtil.dumpIpClient(ipClient, fd, pw, args); - } else { + if (null == ifaceState.mIpClient) { pw.println("IpClient is null"); } pw.decreaseIndent(); diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 08a70a6f40..990ee5fee7 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -42,8 +42,8 @@ import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkProvider; import android.net.NetworkRequest; -import android.net.ip.IIpClient; import android.net.ip.IpClientCallbacks; +import android.net.ip.IpClientManager; import android.os.Handler; import android.os.Looper; import android.os.test.TestLooper; @@ -72,7 +72,7 @@ public class EthernetNetworkFactoryTest { @Mock private Context mContext; @Mock private Resources mResources; @Mock private EthernetNetworkFactory.Dependencies mDeps; - @Mock private IIpClient mIpClient; + @Mock private IpClientManager mIpClient; @Mock private EthernetNetworkAgent mNetworkAgent; @Mock private InterfaceParams mInterfaceParams; @@ -113,7 +113,7 @@ public class EthernetNetworkFactoryTest { assertNull("An IpClient has already been created.", mIpClientCallbacks); mIpClientCallbacks = inv.getArgument(2); - mIpClientCallbacks.onIpClientCreated(mIpClient); + mIpClientCallbacks.onIpClientCreated(null); mLooper.dispatchAll(); return null; }).when(mDeps).makeIpClient(any(Context.class), anyString(), any()); @@ -124,6 +124,8 @@ public class EthernetNetworkFactoryTest { mIpClientCallbacks = null; return null; }).when(mIpClient).shutdown(); + + when(mDeps.makeIpClientManager(any())).thenReturn(mIpClient); } private void triggerOnProvisioningSuccess() { @@ -185,13 +187,13 @@ public class EthernetNetworkFactoryTest { // creates an interface with provisioning in progress (since updating the interface link state // automatically starts the provisioning process) - private void createInterfaceUndergoingProvisioning(String iface) throws Exception { + private void createInterfaceUndergoingProvisioning(String iface) { // Default to the ethernet transport type. createInterfaceUndergoingProvisioning(iface, NetworkCapabilities.TRANSPORT_ETHERNET); } private void createInterfaceUndergoingProvisioning( - @NonNull final String iface, final int transportType) throws Exception { + @NonNull final String iface, final int transportType) { mNetFactory.addInterface(iface, iface, createInterfaceCapsBuilder(transportType).build(), createDefaultIpConfig()); assertTrue(mNetFactory.updateInterfaceLinkState(iface, true)); @@ -433,12 +435,12 @@ public class EthernetNetworkFactoryTest { verifyStart(); } - private void verifyStart() throws Exception { + private void verifyStart() { verify(mDeps).makeIpClient(any(Context.class), anyString(), any()); verify(mIpClient).startProvisioning(any()); } - private void verifyStop() throws Exception { + private void verifyStop() { verify(mIpClient).shutdown(); verify(mNetworkAgent).unregister(); } From 7f0823c15f2afa349f5fcef60d2a7eb8da04a086 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Wed, 29 Dec 2021 16:52:34 -0800 Subject: [PATCH 124/152] Implementation of Eth Service updateConfiguration EthernetServiceImpl#updateConfiguration API implementation to allow for dynamically updating the network capability or ip configuration of an ethernet based interface. Bug: 210485380 Test: atest EthernetServiceTests Change-Id: Idd3b7875a24643d245d0f4bb6f2f4c459898116e --- .../ethernet/EthernetNetworkFactory.java | 182 ++++++++++++------ .../server/ethernet/EthernetService.java | 17 +- .../server/ethernet/EthernetServiceImpl.java | 3 + .../server/ethernet/EthernetTracker.java | 61 +++--- tests/ethernet/Android.bp | 2 + .../ethernet/EthernetNetworkFactoryTest.java | 111 ++++++++++- .../ethernet/EthernetServiceImplTest.java | 50 ++--- .../server/ethernet/EthernetTrackerTest.java | 69 ++++++- 8 files changed, 378 insertions(+), 117 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index d7800c027a..b556f6c949 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.content.Context; import android.net.ConnectivityManager; import android.net.EthernetNetworkSpecifier; +import android.net.IInternalNetworkManagementListener; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; @@ -98,14 +99,13 @@ public class EthernetNetworkFactory extends NetworkFactory { } } - public EthernetNetworkFactory(Handler handler, Context context, NetworkCapabilities filter) { - this(handler, context, filter, new Dependencies()); + public EthernetNetworkFactory(Handler handler, Context context) { + this(handler, context, new Dependencies()); } @VisibleForTesting - EthernetNetworkFactory(Handler handler, Context context, NetworkCapabilities filter, - Dependencies deps) { - super(handler.getLooper(), context, NETWORK_TYPE, filter); + EthernetNetworkFactory(Handler handler, Context context, Dependencies deps) { + super(handler.getLooper(), context, NETWORK_TYPE, createDefaultNetworkCapabilities()); mHandler = handler; mContext = context; @@ -166,8 +166,9 @@ public class EthernetNetworkFactory extends NetworkFactory { .toArray(String[]::new); } - void addInterface(String ifaceName, String hwAddress, NetworkCapabilities capabilities, - IpConfiguration ipConfiguration) { + 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; @@ -177,14 +178,48 @@ public class EthernetNetworkFactory extends NetworkFactory { Log.d(TAG, "addInterface, iface: " + ifaceName + ", capabilities: " + capabilities); } - NetworkInterfaceState iface = new NetworkInterfaceState( - ifaceName, hwAddress, mHandler, mContext, capabilities, this, mDeps); - iface.setIpConfig(ipConfiguration); + final NetworkInterfaceState iface = new NetworkInterfaceState( + ifaceName, hwAddress, mHandler, mContext, ipConfig, capabilities, this, mDeps); mTrackingInterfaces.put(ifaceName, iface); - updateCapabilityFilter(); } + /** + * 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. + * @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 IInternalNetworkManagementListener} to notify callers of + * completion. + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + protected void updateInterface(@NonNull final String ifaceName, + @NonNull final IpConfiguration ipConfig, + @Nullable final NetworkCapabilities capabilities, + @Nullable final IInternalNetworkManagementListener listener) { + enforceInterfaceIsTracked(ifaceName); + final NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName); + // TODO: The listener will have issues if called in quick succession for the same interface + // before the IP layer restarts. Update the listener logic to address multiple successive + // calls for a particular interface. + iface.mNetworkManagementListener = listener; + if (iface.updateInterface(ipConfig, capabilities)) { + mTrackingInterfaces.put(ifaceName, iface); + updateCapabilityFilter(); + } + } + + private void enforceInterfaceIsTracked(@NonNull final String ifaceName) { + if (!hasInterface(ifaceName)) { + throw new UnsupportedOperationException( + "Interface with name " + ifaceName + " is not being tracked."); + } + } + private static NetworkCapabilities mixInCapabilities(NetworkCapabilities nc, NetworkCapabilities addedNc) { final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(nc); @@ -194,11 +229,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } private void updateCapabilityFilter() { - NetworkCapabilities capabilitiesFilter = - NetworkCapabilities.Builder.withoutDefaultCapabilities() - .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) - .build(); - + NetworkCapabilities capabilitiesFilter = createDefaultNetworkCapabilities(); for (NetworkInterfaceState iface: mTrackingInterfaces.values()) { capabilitiesFilter = mixInCapabilities(capabilitiesFilter, iface.mCapabilities); } @@ -207,6 +238,12 @@ public class EthernetNetworkFactory extends NetworkFactory { setCapabilityFilter(capabilitiesFilter); } + private static NetworkCapabilities createDefaultNetworkCapabilities() { + return NetworkCapabilities.Builder + .withoutDefaultCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET).build(); + } + void removeInterface(String interfaceName) { NetworkInterfaceState iface = mTrackingInterfaces.remove(interfaceName); if (iface != null) { @@ -230,15 +267,8 @@ public class EthernetNetworkFactory extends NetworkFactory { return iface.updateLinkState(up); } - boolean hasInterface(String interfacName) { - return mTrackingInterfaces.containsKey(interfacName); - } - - void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) { - NetworkInterfaceState network = mTrackingInterfaces.get(iface); - if (network != null) { - network.setIpConfig(ipConfiguration); - } + boolean hasInterface(String ifaceName) { + return mTrackingInterfaces.containsKey(ifaceName); } private NetworkInterfaceState networkForRequest(NetworkRequest request) { @@ -272,24 +302,26 @@ public class EthernetNetworkFactory extends NetworkFactory { return network; } - private static class NetworkInterfaceState { + @VisibleForTesting + static class NetworkInterfaceState { final String name; private final String mHwAddress; - private final NetworkCapabilities mCapabilities; private final Handler mHandler; private final Context mContext; private final NetworkFactory mNetworkFactory; private final Dependencies mDeps; - private final int mLegacyType; 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 IpClientCallbacksImpl mIpClientCallback; + private @Nullable IInternalNetworkManagementListener mNetworkManagementListener; private @Nullable EthernetNetworkAgent mNetworkAgent; private @Nullable IpConfiguration mIpConfig; @@ -362,42 +394,17 @@ public class EthernetNetworkFactory extends NetworkFactory { } NetworkInterfaceState(String ifaceName, String hwAddress, Handler handler, Context context, - @NonNull NetworkCapabilities capabilities, NetworkFactory networkFactory, - Dependencies deps) { + @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; - final int legacyType; - int[] transportTypes = mCapabilities.getTransportTypes(); - - if (transportTypes.length > 0) { - legacyType = getLegacyType(transportTypes[0]); - } else { - // 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."); - } - mHwAddress = hwAddress; - mLegacyType = legacyType; - } - - void setIpConfig(IpConfiguration ipConfig) { - if (Objects.equals(this.mIpConfig, ipConfig)) { - if (DBG) Log.d(TAG, "ipConfig have not changed,so ignore setIpConfig"); - return; - } - this.mIpConfig = ipConfig; - if (mNetworkAgent != null) { - restart(); - } - } - - boolean isRestricted() { - return !mCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); } /** @@ -408,6 +415,52 @@ public class EthernetNetworkFactory extends NetworkFactory { 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); + } + + boolean updateInterface(@NonNull final IpConfiguration ipConfig, + @Nullable final NetworkCapabilities capabilities) { + final boolean shouldUpdateIpConfig = !Objects.equals(mIpConfig, ipConfig); + final boolean shouldUpdateCapabilities = null != capabilities + && !Objects.equals(mCapabilities, capabilities); + if (DBG) { + Log.d(TAG, "updateInterface, iface: " + name + + ", shouldUpdateIpConfig: " + shouldUpdateIpConfig + + ", shouldUpdateCapabilities: " + shouldUpdateCapabilities + + ", ipConfig: " + ipConfig + ", old ipConfig: " + mIpConfig + + ", capabilities: " + capabilities + ", old capabilities: " + mCapabilities + ); + } + + if (shouldUpdateIpConfig) { mIpConfig = ipConfig; }; + if (shouldUpdateCapabilities) { setCapabilities(capabilities); }; + if (shouldUpdateIpConfig || shouldUpdateCapabilities) { + // 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(); + return true; + } + return false; + } + + boolean isRestricted() { + return !mCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + } + private void start() { if (mIpClient != null) { if (DBG) Log.d(TAG, "IpClient already started"); @@ -459,6 +512,19 @@ public class EthernetNetworkFactory extends NetworkFactory { }); mNetworkAgent.register(); mNetworkAgent.markConnected(); + sendNetworkManagementCallback(); + } + + private void sendNetworkManagementCallback() { + if (null != mNetworkManagementListener) { + try { + mNetworkManagementListener.onComplete(mNetworkAgent.getNetwork(), null); + } catch (RemoteException e) { + Log.e(TAG, "Can't send onComplete for network management callback", e); + } finally { + mNetworkManagementListener = null; + } + } } void onIpLayerStopped(LinkProperties linkProperties) { @@ -546,7 +612,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } void restart(){ - if (DBG) Log.d(TAG, "reconnecting Etherent"); + if (DBG) Log.d(TAG, "reconnecting Ethernet"); stop(); start(); } diff --git a/service-t/src/com/android/server/ethernet/EthernetService.java b/service-t/src/com/android/server/ethernet/EthernetService.java index 467ab677d8..492a55aff1 100644 --- a/service-t/src/com/android/server/ethernet/EthernetService.java +++ b/service-t/src/com/android/server/ethernet/EthernetService.java @@ -17,11 +17,16 @@ package com.android.server.ethernet; import android.content.Context; +import android.net.INetd; +import android.net.util.NetdService; import android.os.Handler; import android.os.HandlerThread; +import android.os.IBinder; import android.util.Log; import com.android.server.SystemService; +import java.util.Objects; + public final class EthernetService extends SystemService { private static final String TAG = "EthernetService"; @@ -32,9 +37,17 @@ public final class EthernetService extends SystemService { super(context); final HandlerThread handlerThread = new HandlerThread(THREAD_NAME); handlerThread.start(); + final Handler handler = handlerThread.getThreadHandler(); + final EthernetNetworkFactory factory = new EthernetNetworkFactory(handler, context); mImpl = new EthernetServiceImpl( - context, handlerThread.getThreadHandler(), - new EthernetTracker(context, handlerThread.getThreadHandler())); + context, handler, + new EthernetTracker(context, handler, factory, getNetd())); + } + + private INetd getNetd() { + final INetd netd = NetdService.getInstance(); + Objects.requireNonNull(netd, "could not get netd instance"); + return netd; } @Override diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index f107865c30..b2844779c8 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -233,6 +233,9 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { + ", request=" + request + ", listener=" + listener); validateNetworkManagementState(iface, "updateConfiguration()"); // TODO: validate that iface is listed in overlay config_ethernet_interfaces + + mTracker.updateConfiguration( + iface, request.getIpConfig(), request.getNetworkCapabilities(), listener); } @Override diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 9660194508..0b6547d145 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -24,6 +24,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.IEthernetServiceListener; +import android.net.IInternalNetworkManagementListener; import android.net.INetd; import android.net.ITetheredInterfaceCallback; import android.net.InterfaceConfigurationParcel; @@ -34,7 +35,6 @@ import android.net.LinkAddress; import android.net.NetworkCapabilities; import android.net.StaticIpConfiguration; import android.os.Handler; -import android.os.IBinder; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ServiceSpecificException; @@ -118,14 +118,12 @@ public class EthernetTracker { } } - EthernetTracker(Context context, Handler handler) { + EthernetTracker(@NonNull final Context context, @NonNull final Handler handler, + @NonNull final EthernetNetworkFactory factory, @NonNull final INetd netd) { mContext = context; mHandler = handler; - - // The services we use. - mNetd = INetd.Stub.asInterface( - (IBinder) context.getSystemService(Context.NETD_SERVICE)); - Objects.requireNonNull(mNetd, "could not get netd instance"); + mFactory = factory; + mNetd = netd; // Interface match regex. updateIfaceMatchRegexp(); @@ -138,9 +136,6 @@ public class EthernetTracker { } mConfigStore = new EthernetConfigStore(); - - NetworkCapabilities nc = createNetworkCapabilities(true /* clear default capabilities */); - mFactory = new EthernetNetworkFactory(handler, context, nc); } void start() { @@ -168,11 +163,30 @@ public class EthernetTracker { if (DBG) { Log.i(TAG, "updateIpConfiguration, iface: " + iface + ", cfg: " + ipConfiguration); } + writeIpConfiguration(iface, ipConfiguration); + mHandler.post(() -> mFactory.updateInterface(iface, ipConfiguration, null, null)); + } - mConfigStore.write(iface, ipConfiguration); - mIpConfigurations.put(iface, ipConfiguration); + private void writeIpConfiguration(@NonNull final String iface, + @NonNull final IpConfiguration ipConfig) { + mConfigStore.write(iface, ipConfig); + mIpConfigurations.put(iface, ipConfig); + } - mHandler.post(() -> mFactory.updateIpConfiguration(iface, ipConfiguration)); + @VisibleForTesting(visibility = PACKAGE) + protected void updateConfiguration(@NonNull final String iface, + @NonNull final StaticIpConfiguration staticIpConfig, + @NonNull final NetworkCapabilities capabilities, + @Nullable final IInternalNetworkManagementListener listener) { + if (DBG) { + Log.i(TAG, "updateConfiguration, iface: " + iface + ", capabilities: " + capabilities + + ", staticIpConfig: " + staticIpConfig); + } + final IpConfiguration ipConfig = createIpConfiguration(staticIpConfig); + writeIpConfiguration(iface, ipConfig); + mNetworkCapabilities.put(iface, capabilities); + mHandler.post(() -> + mFactory.updateInterface(iface, ipConfig, capabilities, listener)); } IpConfiguration getIpConfiguration(String iface) { @@ -325,7 +339,7 @@ public class EthernetTracker { } Log.d(TAG, "Tracking interface in client mode: " + iface); - mFactory.addInterface(iface, hwAddress, nc, ipConfiguration); + mFactory.addInterface(iface, hwAddress, ipConfiguration, nc); } else { maybeUpdateServerModeInterfaceState(iface, true); } @@ -460,11 +474,11 @@ public class EthernetTracker { NetworkCapabilities nc = createNetworkCapabilities( !TextUtils.isEmpty(config.mCapabilities) /* clear default capabilities */, config.mCapabilities, config.mTransport).build(); - mNetworkCapabilities.put(config.mName, nc); + mNetworkCapabilities.put(config.mIface, nc); if (null != config.mIpConfig) { IpConfiguration ipConfig = parseStaticIpConfiguration(config.mIpConfig); - mIpConfigurations.put(config.mName, ipConfig); + mIpConfigurations.put(config.mIface, ipConfig); } } @@ -493,10 +507,6 @@ public class EthernetTracker { return builder.build(); } - private static NetworkCapabilities createNetworkCapabilities(boolean clearDefaultCapabilities) { - return createNetworkCapabilities(clearDefaultCapabilities, null, null).build(); - } - /** * Parses a static list of network capabilities * @@ -623,10 +633,15 @@ public class EthernetTracker { } } } + return createIpConfiguration(staticIpConfigBuilder.build()); + } + + static IpConfiguration createIpConfiguration( + @NonNull final StaticIpConfiguration staticIpConfig) { final IpConfiguration ret = new IpConfiguration(); ret.setIpAssignment(IpAssignment.STATIC); ret.setProxySettings(ProxySettings.NONE); - ret.setStaticIpConfiguration(staticIpConfigBuilder.build()); + ret.setStaticIpConfiguration(staticIpConfig); return ret; } @@ -681,14 +696,14 @@ public class EthernetTracker { @VisibleForTesting static class EthernetTrackerConfig { - final String mName; + 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"); - mName = tokens[0]; + 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; diff --git a/tests/ethernet/Android.bp b/tests/ethernet/Android.bp index 1bc9352f9b..93a8f6ca45 100644 --- a/tests/ethernet/Android.bp +++ b/tests/ethernet/Android.bp @@ -36,6 +36,8 @@ android_test { "ethernet-service", "frameworks-base-testutils", "mockito-target-minus-junit4", + "net-tests-utils", + "services.core", "services.net", ], } diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 990ee5fee7..44ed26c9b4 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -16,9 +16,11 @@ package com.android.server.ethernet; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; @@ -36,17 +38,24 @@ import android.content.Context; import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.EthernetNetworkSpecifier; +import android.net.IInternalNetworkManagementListener; +import android.net.InternalNetworkManagementException; import android.net.IpConfiguration; +import android.net.LinkAddress; import android.net.LinkProperties; +import android.net.Network; import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkProvider; import android.net.NetworkRequest; +import android.net.StaticIpConfiguration; import android.net.ip.IpClientCallbacks; import android.net.ip.IpClientManager; import android.os.Handler; +import android.os.IBinder; import android.os.Looper; import android.os.test.TestLooper; +import android.util.Pair; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -61,10 +70,20 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + @RunWith(AndroidJUnit4.class) @SmallTest public class EthernetNetworkFactoryTest { + private static final int TIMEOUT_MS = 2_000; private static final String TEST_IFACE = "test123"; + private static final String IP_ADDR = "192.0.2.2/25"; + private static final LinkAddress LINK_ADDR = new LinkAddress(IP_ADDR); + private static final String HW_ADDR = "01:02:03:04:05:06"; private final TestLooper mLooper = new TestLooper(); private Handler mHandler; private EthernetNetworkFactory mNetFactory = null; @@ -75,13 +94,13 @@ public class EthernetNetworkFactoryTest { @Mock private IpClientManager mIpClient; @Mock private EthernetNetworkAgent mNetworkAgent; @Mock private InterfaceParams mInterfaceParams; + @Mock private Network mMockNetwork; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mHandler = new Handler(mLooper.getLooper()); - mNetFactory = new EthernetNetworkFactory(mHandler, mContext, createDefaultFilterCaps(), - mDeps); + mNetFactory = new EthernetNetworkFactory(mHandler, mContext, mDeps); setupNetworkAgentMock(); setupIpClientMock(); @@ -100,6 +119,8 @@ public class EthernetNetworkFactoryTest { NetworkProvider provider, EthernetNetworkAgent.Callbacks cb) { when(mNetworkAgent.getCallbacks()).thenReturn(cb); + when(mNetworkAgent.getNetwork()) + .thenReturn(mMockNetwork); return mNetworkAgent; } } @@ -185,6 +206,19 @@ public class EthernetNetworkFactoryTest { return ipConfig; } + /** + * Create an {@link IpConfiguration} with an associated {@link StaticIpConfiguration}. + * + * @return {@link IpConfiguration} with its {@link StaticIpConfiguration} set. + */ + private IpConfiguration createStaticIpConfig() { + final IpConfiguration ipConfig = new IpConfiguration(); + ipConfig.setIpAssignment(IpConfiguration.IpAssignment.STATIC); + ipConfig.setStaticIpConfiguration( + new StaticIpConfiguration.Builder().setIpAddress(LINK_ADDR).build()); + return ipConfig; + } + // creates an interface with provisioning in progress (since updating the interface link state // automatically starts the provisioning process) private void createInterfaceUndergoingProvisioning(String iface) { @@ -194,10 +228,11 @@ public class EthernetNetworkFactoryTest { private void createInterfaceUndergoingProvisioning( @NonNull final String iface, final int transportType) { - mNetFactory.addInterface(iface, iface, createInterfaceCapsBuilder(transportType).build(), - createDefaultIpConfig()); + final IpConfiguration ipConfig = createDefaultIpConfig(); + mNetFactory.addInterface(iface, HW_ADDR, ipConfig, + createInterfaceCapsBuilder(transportType).build()); assertTrue(mNetFactory.updateInterfaceLinkState(iface, true)); - verifyStart(); + verifyStart(ipConfig); clearInvocations(mDeps); clearInvocations(mIpClient); } @@ -431,13 +466,19 @@ public class EthernetNetworkFactoryTest { triggerOnReachabilityLost(); // Reachability loss should trigger a stop and start, since the interface is still there - verifyStop(); - verifyStart(); + verifyRestart(createDefaultIpConfig()); } - private void verifyStart() { + private void verifyRestart(@NonNull final IpConfiguration ipConfig) { + verifyStop(); + verifyStart(ipConfig); + } + + private void verifyStart(@NonNull final IpConfiguration ipConfig) { verify(mDeps).makeIpClient(any(Context.class), anyString(), any()); - verify(mIpClient).startProvisioning(any()); + verify(mIpClient).startProvisioning( + argThat(x -> Objects.equals(x.mStaticIpConfig, ipConfig.getStaticIpConfiguration())) + ); } private void verifyStop() { @@ -449,4 +490,56 @@ public class EthernetNetworkFactoryTest { verify(mNetworkAgent).register(); verify(mNetworkAgent).markConnected(); } + + private static final class TestNetworkManagementListener + implements IInternalNetworkManagementListener { + private final CompletableFuture> mDone + = new CompletableFuture<>(); + + @Override + public void onComplete(final Network network, + final InternalNetworkManagementException exception) { + mDone.complete(new Pair<>(network, exception)); + } + + Pair expectOnComplete() throws Exception { + return mDone.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + @Override + public IBinder asBinder() { + return null; + } + } + + @Test + public void testUpdateInterfaceCallsListenerCorrectlyOnSuccess() throws Exception { + createAndVerifyProvisionedInterface(TEST_IFACE); + final NetworkCapabilities capabilities = createDefaultFilterCaps(); + final IpConfiguration ipConfiguration = createStaticIpConfig(); + final TestNetworkManagementListener listener = new TestNetworkManagementListener(); + + mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener); + triggerOnProvisioningSuccess(); + + final Pair ret = listener.expectOnComplete(); + assertEquals(mMockNetwork, ret.first); + assertNull(ret.second); + } + + @Test + public void testUpdateInterfaceRestartsAgentCorrectly() throws Exception { + createAndVerifyProvisionedInterface(TEST_IFACE); + final NetworkCapabilities capabilities = createDefaultFilterCaps(); + final IpConfiguration ipConfiguration = createStaticIpConfig(); + final TestNetworkManagementListener listener = new TestNetworkManagementListener(); + + mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener); + triggerOnProvisioningSuccess(); + + listener.expectOnComplete(); + verify(mDeps).makeEthernetNetworkAgent(any(), any(), + eq(capabilities), any(), any(), any(), any()); + verifyRestart(ipConfiguration); + } } diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java index 516e574522..1c0888398a 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java @@ -18,13 +18,17 @@ package com.android.server.ethernet; import static org.junit.Assert.assertThrows; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; import android.annotation.NonNull; import android.content.Context; import android.content.pm.PackageManager; +import android.net.IInternalNetworkManagementListener; import android.net.InternalNetworkUpdateRequest; import android.net.IpConfiguration; +import android.net.NetworkCapabilities; import android.net.StaticIpConfiguration; import android.os.Handler; @@ -41,6 +45,10 @@ import org.mockito.MockitoAnnotations; @SmallTest public class EthernetServiceImplTest { private static final String TEST_IFACE = "test123"; + private static final InternalNetworkUpdateRequest UPDATE_REQUEST = + new InternalNetworkUpdateRequest( + new StaticIpConfiguration(), new NetworkCapabilities.Builder().build()); + private static final IInternalNetworkManagementListener NULL_LISTENER = null; private EthernetServiceImpl mEthernetServiceImpl; @Mock private Context mContext; @Mock private Handler mHandler; @@ -69,10 +77,8 @@ public class EthernetServiceImplTest { public void testUpdateConfigurationRejectsWhenEthNotStarted() { mEthernetServiceImpl.mStarted.set(false); assertThrows(IllegalStateException.class, () -> { - final InternalNetworkUpdateRequest r = - new InternalNetworkUpdateRequest(new StaticIpConfiguration(), null); - - mEthernetServiceImpl.updateConfiguration("" /* iface */, r, null /* listener */); + mEthernetServiceImpl.updateConfiguration( + "" /* iface */, UPDATE_REQUEST, null /* listener */); }); } @@ -95,24 +101,21 @@ public class EthernetServiceImplTest { @Test public void testUpdateConfigurationRejectsNullIface() { assertThrows(NullPointerException.class, () -> { - final InternalNetworkUpdateRequest r = - new InternalNetworkUpdateRequest(new StaticIpConfiguration(), null); - - mEthernetServiceImpl.updateConfiguration(null /* iface */, r, null /* listener */); + mEthernetServiceImpl.updateConfiguration(null, UPDATE_REQUEST, NULL_LISTENER); }); } @Test public void testConnectNetworkRejectsNullIface() { assertThrows(NullPointerException.class, () -> { - mEthernetServiceImpl.connectNetwork(null /* iface */, null /* listener */); + mEthernetServiceImpl.connectNetwork(null /* iface */, NULL_LISTENER); }); } @Test public void testDisconnectNetworkRejectsNullIface() { assertThrows(NullPointerException.class, () -> { - mEthernetServiceImpl.disconnectNetwork(null /* iface */, null /* listener */); + mEthernetServiceImpl.disconnectNetwork(null /* iface */, NULL_LISTENER); }); } @@ -120,10 +123,7 @@ public class EthernetServiceImplTest { public void testUpdateConfigurationRejectsWithoutAutomotiveFeature() { toggleAutomotiveFeature(false); assertThrows(UnsupportedOperationException.class, () -> { - final InternalNetworkUpdateRequest r = - new InternalNetworkUpdateRequest(new StaticIpConfiguration(), null); - - mEthernetServiceImpl.updateConfiguration("" /* iface */, r, null /* listener */); + mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER); }); } @@ -131,7 +131,7 @@ public class EthernetServiceImplTest { public void testConnectNetworkRejectsWithoutAutomotiveFeature() { toggleAutomotiveFeature(false); assertThrows(UnsupportedOperationException.class, () -> { - mEthernetServiceImpl.connectNetwork("" /* iface */, null /* listener */); + mEthernetServiceImpl.connectNetwork("" /* iface */, NULL_LISTENER); }); } @@ -139,7 +139,7 @@ public class EthernetServiceImplTest { public void testDisconnectNetworkRejectsWithoutAutomotiveFeature() { toggleAutomotiveFeature(false); assertThrows(UnsupportedOperationException.class, () -> { - mEthernetServiceImpl.disconnectNetwork("" /* iface */, null /* listener */); + mEthernetServiceImpl.disconnectNetwork("" /* iface */, NULL_LISTENER); }); } @@ -152,10 +152,7 @@ public class EthernetServiceImplTest { public void testUpdateConfigurationRejectsWithUntrackedIface() { shouldTrackIface(TEST_IFACE, false); assertThrows(UnsupportedOperationException.class, () -> { - final InternalNetworkUpdateRequest r = - new InternalNetworkUpdateRequest(new StaticIpConfiguration(), null); - - mEthernetServiceImpl.updateConfiguration(TEST_IFACE, r, null /* listener */); + mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER); }); } @@ -163,7 +160,7 @@ public class EthernetServiceImplTest { public void testConnectNetworkRejectsWithUntrackedIface() { shouldTrackIface(TEST_IFACE, false); assertThrows(UnsupportedOperationException.class, () -> { - mEthernetServiceImpl.connectNetwork(TEST_IFACE, null /* listener */); + mEthernetServiceImpl.connectNetwork(TEST_IFACE, NULL_LISTENER); }); } @@ -171,11 +168,20 @@ public class EthernetServiceImplTest { public void testDisconnectNetworkRejectsWithUntrackedIface() { shouldTrackIface(TEST_IFACE, false); assertThrows(UnsupportedOperationException.class, () -> { - mEthernetServiceImpl.disconnectNetwork(TEST_IFACE, null /* listener */); + mEthernetServiceImpl.disconnectNetwork(TEST_IFACE, NULL_LISTENER); }); } private void shouldTrackIface(@NonNull final String iface, final boolean shouldTrack) { doReturn(shouldTrack).when(mEthernetTracker).isTrackingInterface(iface); } + + @Test + public void testUpdateConfiguration() { + mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER); + verify(mEthernetTracker).updateConfiguration( + eq(TEST_IFACE), + eq(UPDATE_REQUEST.getIpConfig()), + eq(UPDATE_REQUEST.getNetworkCapabilities()), eq(NULL_LISTENER)); + } } diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java index 6ea2154337..5aca2e40a0 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -19,20 +19,35 @@ package com.android.server.ethernet; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThrows; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; +import android.content.Context; +import android.content.res.Resources; import android.net.InetAddresses; +import android.net.IInternalNetworkManagementListener; +import android.net.INetd; 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.HandlerThread; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.R; +import com.android.testutils.HandlerUtils; + +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import java.net.InetAddress; import java.util.ArrayList; @@ -40,6 +55,39 @@ import java.util.ArrayList; @SmallTest @RunWith(AndroidJUnit4.class) public class EthernetTrackerTest { + private static final int TIMEOUT_MS = 1_000; + private static final String THREAD_NAME = "EthernetServiceThread"; + private EthernetTracker tracker; + private HandlerThread mHandlerThread; + @Mock private Context mContext; + @Mock private EthernetNetworkFactory mFactory; + @Mock private INetd mNetd; + @Mock Resources mResources; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + initMockResources(); + mHandlerThread = new HandlerThread(THREAD_NAME); + mHandlerThread.start(); + tracker = new EthernetTracker(mContext, mHandlerThread.getThreadHandler(), mFactory, mNetd); + } + + @After + public void cleanUp() { + mHandlerThread.quitSafely(); + } + + private void initMockResources() { + doReturn("").when(mResources).getString(R.string.config_ethernet_iface_regex); + doReturn(new String[0]).when(mResources).getStringArray(R.array.config_ethernet_interfaces); + doReturn(mResources).when(mContext).getResources(); + } + + private void waitForIdle() { + HandlerUtils.waitForIdle(mHandlerThread, TIMEOUT_MS); + } + /** * Test: Creation of various valid static IP configurations */ @@ -246,16 +294,16 @@ public class EthernetTrackerTest { @Test public void testCreateEthernetTrackerConfigReturnsCorrectValue() { - final String name = "1"; + final String iface = "1"; final String capabilities = "2"; final String ipConfig = "3"; final String transport = "4"; - final String configString = String.join(";", name, capabilities, ipConfig, transport); + final String configString = String.join(";", iface, capabilities, ipConfig, transport); final EthernetTracker.EthernetTrackerConfig config = EthernetTracker.createEthernetTrackerConfig(configString); - assertEquals(name, config.mName); + assertEquals(iface, config.mIface); assertEquals(capabilities, config.mCapabilities); assertEquals(ipConfig, config.mIpConfig); assertEquals(transport, config.mTransport); @@ -266,4 +314,19 @@ public class EthernetTrackerTest { assertThrows(NullPointerException.class, () -> EthernetTracker.createEthernetTrackerConfig(null)); } + + @Test + public void testUpdateConfiguration() { + final String iface = "testiface"; + final NetworkCapabilities capabilities = new NetworkCapabilities.Builder().build(); + final StaticIpConfiguration staticIpConfig = new StaticIpConfiguration(); + final IInternalNetworkManagementListener listener = null; + + tracker.updateConfiguration(iface, staticIpConfig, capabilities, listener); + waitForIdle(); + + verify(mFactory).updateInterface( + eq(iface), eq(EthernetTracker.createIpConfiguration(staticIpConfig)), + eq(capabilities), eq(listener)); + } } From b63e7aebee91d3e8688daf972332bd72b7e8fcc4 Mon Sep 17 00:00:00 2001 From: Pavan Kumar M Date: Thu, 6 Jan 2022 14:19:48 +0530 Subject: [PATCH 125/152] Synchronize the IpClient events If the ipClient is stopped before handling the events in Handler thread, ethernet network factory might end up creating a network agent for a network which is already cleared. This change fixes the issue by handling the events only if ipClient is initialized. Tests: Builds, Boots, EthernetNetworkFactoryTest. Ethernet related test scenarios Bug: 207057937 Change-Id: If7ff7abf5f0dcdb0e94de0502bfdf981f9f20298 --- .../ethernet/EthernetNetworkFactory.java | 16 ++++++ .../ethernet/EthernetNetworkFactoryTest.java | 53 +++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index b556f6c949..7b727a3ce3 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -481,6 +481,10 @@ public class EthernetNetworkFactory extends NetworkFactory { } void onIpLayerStarted(LinkProperties linkProperties) { + if(mIpClient == null) { + if (DBG) Log.d(TAG, "IpClient is not initialized."); + return; + } if (mNetworkAgent != null) { Log.e(TAG, "Already have a NetworkAgent - aborting new request"); stop(); @@ -528,6 +532,10 @@ public class EthernetNetworkFactory extends NetworkFactory { } void onIpLayerStopped(LinkProperties linkProperties) { + if(mIpClient == null) { + if (DBG) Log.d(TAG, "IpClient is not initialized."); + return; + } // This cannot happen due to provisioning timeout, because our timeout is 0. It can only // happen if we're provisioned and we lose provisioning. stop(); @@ -539,6 +547,10 @@ public class EthernetNetworkFactory extends NetworkFactory { } void updateLinkProperties(LinkProperties linkProperties) { + if(mIpClient == null) { + if (DBG) Log.d(TAG, "IpClient is not initialized."); + return; + } mLinkProperties = linkProperties; if (mNetworkAgent != null) { mNetworkAgent.sendLinkPropertiesImpl(linkProperties); @@ -546,6 +558,10 @@ public class EthernetNetworkFactory extends NetworkFactory { } void updateNeighborLostEvent(String logMsg) { + if(mIpClient == null) { + if (DBG) Log.d(TAG, "IpClient is not initialized."); + return; + } 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 diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 44ed26c9b4..52ddf3c8ad 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -469,6 +469,59 @@ public class EthernetNetworkFactoryTest { verifyRestart(createDefaultIpConfig()); } + @Test + public void testIgnoreOnIpLayerStartedCallbackAfterIpClientHasStopped() throws Exception { + createAndVerifyProvisionedInterface(TEST_IFACE); + mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); + mIpClientCallbacks.onProvisioningSuccess(new LinkProperties()); + mLooper.dispatchAll(); + verifyStop(); + + // ipClient has been shut down first, we should not retry + verify(mIpClient, never()).startProvisioning(any()); + verify(mNetworkAgent, never()).register(); + } + + @Test + public void testIgnoreOnIpLayerStoppedCallbackAfterIpClientHasStopped() throws Exception { + createAndVerifyProvisionedInterface(TEST_IFACE); + when(mDeps.getNetworkInterfaceByName(TEST_IFACE)).thenReturn(mInterfaceParams); + mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); + mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); + mLooper.dispatchAll(); + verifyStop(); + + // ipClient has been shut down first, we should not retry + verify(mIpClient).startProvisioning(any()); + } + + @Test + public void testIgnoreLinkPropertiesCallbackAfterIpClientHasStopped() throws Exception { + createAndVerifyProvisionedInterface(TEST_IFACE); + LinkProperties lp = new LinkProperties(); + + mIpClientCallbacks.onProvisioningFailure(lp); + mIpClientCallbacks.onLinkPropertiesChange(lp); + mLooper.dispatchAll(); + verifyStop(); + + // ipClient has been shut down first, we should not update + verify(mNetworkAgent, never()).sendLinkPropertiesImpl(same(lp)); + } + + @Test + public void testIgnoreNeighborLossCallbackAfterIpClientHasStopped() throws Exception { + createAndVerifyProvisionedInterface(TEST_IFACE); + mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); + mIpClientCallbacks.onReachabilityLost("Neighbor Lost"); + mLooper.dispatchAll(); + verifyStop(); + + // ipClient has been shut down first, we should not update + verify(mIpClient, never()).startProvisioning(any()); + verify(mNetworkAgent, never()).register(); + } + private void verifyRestart(@NonNull final IpConfiguration ipConfig) { verifyStop(); verifyStart(ipConfig); From 6339ef0b4e007c68c62315b56830fbbb2db3d990 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 20 Jan 2022 16:22:33 +0900 Subject: [PATCH 126/152] Replace runWithScissors with a custom implementation. This is not any better than the previous code though... But it should behave the same. Test: FrameworksNetTests Change-Id: Ia3d379681cb0f17dd5f86062b7cfe84f1547fadb --- .../src/com/android/server/ethernet/EthernetTracker.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 0b6547d145..53af955d69 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -34,6 +34,7 @@ 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; @@ -662,7 +663,13 @@ public class EthernetTracker { } private void postAndWaitForRunnable(Runnable r) { - mHandler.runWithScissors(r, 2000L /* timeout */); + final ConditionVariable cv = new ConditionVariable(); + if (mHandler.post(() -> { + r.run(); + cv.open(); + })) { + cv.block(2000L); + } } void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) { From 2730f2ea2d559e7ef0b6ab7dc54229c16a6a58cd Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Mon, 24 Jan 2022 07:45:37 +0000 Subject: [PATCH 127/152] Replace the NetdService usage in the EthernetService. Ethernet service related files are going to be moved into Connectivity module. NetdService won't be visible to EthernetService. Use asInterface to get the Netd service instead. Bug: 210586283 Test: m Change-Id: I3bf504cd947f74bf5830659915483fe5331ac9eb --- .../src/com/android/server/ethernet/EthernetService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetService.java b/service-t/src/com/android/server/ethernet/EthernetService.java index 492a55aff1..e6fee9e7bc 100644 --- a/service-t/src/com/android/server/ethernet/EthernetService.java +++ b/service-t/src/com/android/server/ethernet/EthernetService.java @@ -18,7 +18,6 @@ package com.android.server.ethernet; import android.content.Context; import android.net.INetd; -import android.net.util.NetdService; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; @@ -41,11 +40,12 @@ public final class EthernetService extends SystemService { final EthernetNetworkFactory factory = new EthernetNetworkFactory(handler, context); mImpl = new EthernetServiceImpl( context, handler, - new EthernetTracker(context, handler, factory, getNetd())); + new EthernetTracker(context, handler, factory, getNetd(context))); } - private INetd getNetd() { - final INetd netd = NetdService.getInstance(); + private 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; } From 724a0aea088a17d9a29b0086446f6353abd71ae7 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Thu, 13 Jan 2022 18:36:24 -0800 Subject: [PATCH 128/152] Updates so Network Mgmt Callbacks Are Sent Updates so that network management API updates in the ethernet stack can handle concurrent requests correctly in regards to notifying caller supplied callbacks. Bug: 210485380 Test: atest EthernetServiceTests Change-Id: I8073251b2c63309da031c2b1c98d61614deadfe8 --- .../ethernet/EthernetNetworkFactory.java | 163 ++++++++++++------ .../ethernet/EthernetNetworkFactoryTest.java | 126 ++++++++++++-- 2 files changed, 221 insertions(+), 68 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 7b727a3ce3..c610f00ab1 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -22,10 +22,12 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.EthernetNetworkSpecifier; import android.net.IInternalNetworkManagementListener; +import android.net.InternalNetworkManagementException; 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; @@ -203,14 +205,9 @@ public class EthernetNetworkFactory extends NetworkFactory { @Nullable final IInternalNetworkManagementListener listener) { enforceInterfaceIsTracked(ifaceName); final NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName); - // TODO: The listener will have issues if called in quick succession for the same interface - // before the IP layer restarts. Update the listener logic to address multiple successive - // calls for a particular interface. - iface.mNetworkManagementListener = listener; - if (iface.updateInterface(ipConfig, capabilities)) { - mTrackingInterfaces.put(ifaceName, iface); - updateCapabilityFilter(); - } + iface.updateInterface(ipConfig, capabilities, listener); + mTrackingInterfaces.put(ifaceName, iface); + updateCapabilityFilter(); } private void enforceInterfaceIsTracked(@NonNull final String ifaceName) { @@ -247,6 +244,7 @@ public class EthernetNetworkFactory extends NetworkFactory { void removeInterface(String interfaceName) { NetworkInterfaceState iface = mTrackingInterfaces.remove(interfaceName); if (iface != null) { + iface.maybeSendNetworkManagementCallbackForAbort(); iface.stop(); } @@ -302,6 +300,21 @@ public class EthernetNetworkFactory extends NetworkFactory { return network; } + private static void maybeSendNetworkManagementCallback( + @Nullable final IInternalNetworkManagementListener listener, + @Nullable final Network network, + @Nullable final InternalNetworkManagementException e) { + if (null == listener) { + return; + } + + try { + listener.onComplete(network, e); + } catch (RemoteException re) { + Log.e(TAG, "Can't send onComplete for network management callback", re); + } + } + @VisibleForTesting static class NetworkInterfaceState { final String name; @@ -320,8 +333,7 @@ public class EthernetNetworkFactory extends NetworkFactory { private volatile @Nullable IpClientManager mIpClient; private @NonNull NetworkCapabilities mCapabilities; - private @Nullable IpClientCallbacksImpl mIpClientCallback; - private @Nullable IInternalNetworkManagementListener mNetworkManagementListener; + private @Nullable EthernetIpClientCallback mIpClientCallback; private @Nullable EthernetNetworkAgent mNetworkAgent; private @Nullable IpConfiguration mIpConfig; @@ -348,9 +360,14 @@ public class EthernetNetworkFactory extends NetworkFactory { long refCount = 0; - private class IpClientCallbacksImpl extends IpClientCallbacks { + private class EthernetIpClientCallback extends IpClientCallbacks { private final ConditionVariable mIpClientStartCv = new ConditionVariable(false); private final ConditionVariable mIpClientShutdownCv = new ConditionVariable(false); + @Nullable IInternalNetworkManagementListener mNetworkManagementListener; + + EthernetIpClientCallback(@Nullable final IInternalNetworkManagementListener listener) { + mNetworkManagementListener = listener; + } @Override public void onIpClientCreated(IIpClient ipClient) { @@ -368,12 +385,12 @@ public class EthernetNetworkFactory extends NetworkFactory { @Override public void onProvisioningSuccess(LinkProperties newLp) { - mHandler.post(() -> onIpLayerStarted(newLp)); + mHandler.post(() -> onIpLayerStarted(newLp, mNetworkManagementListener)); } @Override public void onProvisioningFailure(LinkProperties newLp) { - mHandler.post(() -> onIpLayerStopped(newLp)); + mHandler.post(() -> onIpLayerStopped(mNetworkManagementListener)); } @Override @@ -431,30 +448,25 @@ public class EthernetNetworkFactory extends NetworkFactory { mLegacyType = getLegacyType(mCapabilities); } - boolean updateInterface(@NonNull final IpConfiguration ipConfig, - @Nullable final NetworkCapabilities capabilities) { - final boolean shouldUpdateIpConfig = !Objects.equals(mIpConfig, ipConfig); - final boolean shouldUpdateCapabilities = null != capabilities - && !Objects.equals(mCapabilities, capabilities); + void updateInterface(@NonNull final IpConfiguration ipConfig, + @Nullable final NetworkCapabilities capabilities, + @Nullable final IInternalNetworkManagementListener listener) { if (DBG) { Log.d(TAG, "updateInterface, iface: " + name - + ", shouldUpdateIpConfig: " + shouldUpdateIpConfig - + ", shouldUpdateCapabilities: " + shouldUpdateCapabilities + ", ipConfig: " + ipConfig + ", old ipConfig: " + mIpConfig + ", capabilities: " + capabilities + ", old capabilities: " + mCapabilities + + ", listener: " + listener ); } - if (shouldUpdateIpConfig) { mIpConfig = ipConfig; }; - if (shouldUpdateCapabilities) { setCapabilities(capabilities); }; - if (shouldUpdateIpConfig || shouldUpdateCapabilities) { - // 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(); - return true; - } - return false; + mIpConfig = ipConfig; + 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() { @@ -462,6 +474,10 @@ public class EthernetNetworkFactory extends NetworkFactory { } private void start() { + start(null); + } + + private void start(@Nullable final IInternalNetworkManagementListener listener) { if (mIpClient != null) { if (DBG) Log.d(TAG, "IpClient already started"); return; @@ -470,9 +486,10 @@ public class EthernetNetworkFactory extends NetworkFactory { Log.d(TAG, String.format("Starting Ethernet IpClient(%s)", name)); } - mIpClientCallback = new IpClientCallbacksImpl(); + mIpClientCallback = new EthernetIpClientCallback(listener); mDeps.makeIpClient(mContext, name, mIpClientCallback); mIpClientCallback.awaitIpClientStart(); + if (sTcpBufferSizes == null) { sTcpBufferSizes = mContext.getResources().getString( com.android.internal.R.string.config_ethernet_tcp_buffers); @@ -480,8 +497,13 @@ public class EthernetNetworkFactory extends NetworkFactory { provisionIpClient(mIpClient, mIpConfig, sTcpBufferSizes); } - void onIpLayerStarted(LinkProperties linkProperties) { + void onIpLayerStarted(@NonNull final LinkProperties linkProperties, + @Nullable final IInternalNetworkManagementListener listener) { if(mIpClient == null) { + // This call comes from a message posted on the handler thread, but the IpClient has + // since been stopped such as may be the case if updateInterfaceLinkState() is + // queued on the handler thread prior. As network management callbacks are sent in + // stop(), there is no need to send them again here. if (DBG) Log.d(TAG, "IpClient is not initialized."); return; } @@ -516,33 +538,53 @@ public class EthernetNetworkFactory extends NetworkFactory { }); mNetworkAgent.register(); mNetworkAgent.markConnected(); - sendNetworkManagementCallback(); + realizeNetworkManagementCallback(mNetworkAgent.getNetwork(), null); } - private void sendNetworkManagementCallback() { - if (null != mNetworkManagementListener) { - try { - mNetworkManagementListener.onComplete(mNetworkAgent.getNetwork(), null); - } catch (RemoteException e) { - Log.e(TAG, "Can't send onComplete for network management callback", e); - } finally { - mNetworkManagementListener = null; - } - } - } - - void onIpLayerStopped(LinkProperties linkProperties) { + void onIpLayerStopped(@Nullable final IInternalNetworkManagementListener listener) { + // This cannot happen due to provisioning timeout, because our timeout is 0. It can + // happen due to errors while provisioning or on provisioning loss. if(mIpClient == null) { if (DBG) Log.d(TAG, "IpClient is not initialized."); return; } - // This cannot happen due to provisioning timeout, because our timeout is 0. It can only - // happen if we're provisioned and we lose provisioning. - stop(); - // If the interface has disappeared provisioning will fail over and over again, so - // there is no point in starting again - if (null != mDeps.getNetworkInterfaceByName(name)) { - start(); + // 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 InternalNetworkManagementException( + "The IP provisioning request has been aborted.")); + } + + // Must be called on the handler thread + private void realizeNetworkManagementCallback(@Nullable final Network network, + @Nullable final InternalNetworkManagementException e) { + ensureRunningOnEthernetHandlerThread(); + if (null == mIpClientCallback) { + return; + } + + EthernetNetworkFactory.maybeSendNetworkManagementCallback( + mIpClientCallback.mNetworkManagementListener, network, 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()); } } @@ -577,8 +619,11 @@ public class EthernetNetworkFactory extends NetworkFactory { if (mLinkUp == up) return false; mLinkUp = up; - stop(); - if (up) { + if (!up) { // was up, goes down + maybeSendNetworkManagementCallbackForAbort(); + stop(); + } else { // was down, goes up + stop(); start(); } @@ -627,10 +672,14 @@ public class EthernetNetworkFactory extends NetworkFactory { .build(); } - void restart(){ + void restart() { + restart(null); + } + + void restart(@Nullable final IInternalNetworkManagementListener listener){ if (DBG) Log.d(TAG, "reconnecting Ethernet"); stop(); - start(); + start(listener); } @Override diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 52ddf3c8ad..d569990a18 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -16,8 +16,11 @@ package com.android.server.ethernet; +import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -63,6 +66,8 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.R; import com.android.net.module.util.InterfaceParams; +import com.android.testutils.DevSdkIgnoreRule; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -72,9 +77,7 @@ import org.mockito.MockitoAnnotations; import java.util.Objects; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; @RunWith(AndroidJUnit4.class) @SmallTest @@ -84,7 +87,7 @@ public class EthernetNetworkFactoryTest { private static final String IP_ADDR = "192.0.2.2/25"; private static final LinkAddress LINK_ADDR = new LinkAddress(IP_ADDR); private static final String HW_ADDR = "01:02:03:04:05:06"; - private final TestLooper mLooper = new TestLooper(); + private TestLooper mLooper; private Handler mHandler; private EthernetNetworkFactory mNetFactory = null; private IpClientCallbacks mIpClientCallbacks; @@ -99,14 +102,18 @@ public class EthernetNetworkFactoryTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mHandler = new Handler(mLooper.getLooper()); - mNetFactory = new EthernetNetworkFactory(mHandler, mContext, mDeps); - setupNetworkAgentMock(); setupIpClientMock(); setupContext(); } + //TODO: Move away from usage of TestLooper in order to move this logic back into @Before. + private void initEthernetNetworkFactory() { + mLooper = new TestLooper(); + mHandler = new Handler(mLooper.getLooper()); + mNetFactory = new EthernetNetworkFactory(mHandler, mContext, mDeps); + } + private void setupNetworkAgentMock() { when(mDeps.makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any())) .thenAnswer(new AnswerWithArguments() { @@ -288,6 +295,7 @@ public class EthernetNetworkFactoryTest { @Test public void testAcceptRequest() throws Exception { + initEthernetNetworkFactory(); createInterfaceUndergoingProvisioning(TEST_IFACE); assertTrue(mNetFactory.acceptRequest(createDefaultRequest())); @@ -299,6 +307,7 @@ public class EthernetNetworkFactoryTest { @Test public void testUpdateInterfaceLinkStateForActiveProvisioningInterface() throws Exception { + initEthernetNetworkFactory(); createInterfaceUndergoingProvisioning(TEST_IFACE); // verify that the IpClient gets shut down when interface state changes to down. assertTrue(mNetFactory.updateInterfaceLinkState(TEST_IFACE, false)); @@ -307,6 +316,7 @@ public class EthernetNetworkFactoryTest { @Test public void testUpdateInterfaceLinkStateForProvisionedInterface() throws Exception { + initEthernetNetworkFactory(); createAndVerifyProvisionedInterface(TEST_IFACE); assertTrue(mNetFactory.updateInterfaceLinkState(TEST_IFACE, false)); verifyStop(); @@ -314,6 +324,7 @@ public class EthernetNetworkFactoryTest { @Test public void testUpdateInterfaceLinkStateForUnprovisionedInterface() throws Exception { + initEthernetNetworkFactory(); createUnprovisionedInterface(TEST_IFACE); assertTrue(mNetFactory.updateInterfaceLinkState(TEST_IFACE, false)); // There should not be an active IPClient or NetworkAgent. @@ -324,6 +335,7 @@ public class EthernetNetworkFactoryTest { @Test public void testUpdateInterfaceLinkStateForNonExistingInterface() throws Exception { + initEthernetNetworkFactory(); // if interface was never added, link state cannot be updated. assertFalse(mNetFactory.updateInterfaceLinkState("eth1", true)); verify(mDeps, never()).makeIpClient(any(), any(), any()); @@ -331,6 +343,7 @@ public class EthernetNetworkFactoryTest { @Test public void testNeedNetworkForOnProvisionedInterface() throws Exception { + initEthernetNetworkFactory(); createAndVerifyProvisionedInterface(TEST_IFACE); mNetFactory.needNetworkFor(createDefaultRequest()); verify(mIpClient, never()).startProvisioning(any()); @@ -338,6 +351,7 @@ public class EthernetNetworkFactoryTest { @Test public void testNeedNetworkForOnUnprovisionedInterface() throws Exception { + initEthernetNetworkFactory(); createUnprovisionedInterface(TEST_IFACE); mNetFactory.needNetworkFor(createDefaultRequest()); verify(mIpClient).startProvisioning(any()); @@ -348,6 +362,7 @@ public class EthernetNetworkFactoryTest { @Test public void testNeedNetworkForOnInterfaceUndergoingProvisioning() throws Exception { + initEthernetNetworkFactory(); createInterfaceUndergoingProvisioning(TEST_IFACE); mNetFactory.needNetworkFor(createDefaultRequest()); verify(mIpClient, never()).startProvisioning(any()); @@ -358,6 +373,7 @@ public class EthernetNetworkFactoryTest { @Test public void testProvisioningLoss() throws Exception { + initEthernetNetworkFactory(); when(mDeps.getNetworkInterfaceByName(TEST_IFACE)).thenReturn(mInterfaceParams); createAndVerifyProvisionedInterface(TEST_IFACE); @@ -369,18 +385,24 @@ public class EthernetNetworkFactoryTest { @Test public void testProvisioningLossForDisappearedInterface() throws Exception { + initEthernetNetworkFactory(); // mocked method returns null by default, but just to be explicit in the test: when(mDeps.getNetworkInterfaceByName(eq(TEST_IFACE))).thenReturn(null); createAndVerifyProvisionedInterface(TEST_IFACE); triggerOnProvisioningFailure(); - verifyStop(); + // the interface disappeared and getNetworkInterfaceByName returns null, we should not retry verify(mIpClient, never()).startProvisioning(any()); + verify(mNetworkAgent, never()).register(); + verify(mIpClient, never()).shutdown(); + verify(mNetworkAgent, never()).unregister(); + verify(mIpClient, never()).startProvisioning(any()); } @Test public void testIpClientIsNotStartedWhenLinkIsDown() throws Exception { + initEthernetNetworkFactory(); createUnprovisionedInterface(TEST_IFACE); mNetFactory.updateInterfaceLinkState(TEST_IFACE, false); @@ -399,6 +421,7 @@ public class EthernetNetworkFactoryTest { @Test public void testLinkPropertiesChanged() throws Exception { + initEthernetNetworkFactory(); createAndVerifyProvisionedInterface(TEST_IFACE); LinkProperties lp = new LinkProperties(); @@ -409,6 +432,7 @@ public class EthernetNetworkFactoryTest { @Test public void testNetworkUnwanted() throws Exception { + initEthernetNetworkFactory(); createAndVerifyProvisionedInterface(TEST_IFACE); mNetworkAgent.getCallbacks().onNetworkUnwanted(); @@ -418,6 +442,7 @@ public class EthernetNetworkFactoryTest { @Test public void testNetworkUnwantedWithStaleNetworkAgent() throws Exception { + initEthernetNetworkFactory(); // ensures provisioning is restarted after provisioning loss when(mDeps.getNetworkInterfaceByName(TEST_IFACE)).thenReturn(mInterfaceParams); createAndVerifyProvisionedInterface(TEST_IFACE); @@ -441,6 +466,7 @@ public class EthernetNetworkFactoryTest { @Test public void testTransportOverrideIsCorrectlySet() throws Exception { + initEthernetNetworkFactory(); // createProvisionedInterface() has verifications in place for transport override // functionality which for EthernetNetworkFactory is network score and legacy type mappings. createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_ETHERNET, @@ -461,6 +487,7 @@ public class EthernetNetworkFactoryTest { @Test public void testReachabilityLoss() throws Exception { + initEthernetNetworkFactory(); createAndVerifyProvisionedInterface(TEST_IFACE); triggerOnReachabilityLost(); @@ -471,6 +498,7 @@ public class EthernetNetworkFactoryTest { @Test public void testIgnoreOnIpLayerStartedCallbackAfterIpClientHasStopped() throws Exception { + initEthernetNetworkFactory(); createAndVerifyProvisionedInterface(TEST_IFACE); mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); mIpClientCallbacks.onProvisioningSuccess(new LinkProperties()); @@ -484,6 +512,7 @@ public class EthernetNetworkFactoryTest { @Test public void testIgnoreOnIpLayerStoppedCallbackAfterIpClientHasStopped() throws Exception { + initEthernetNetworkFactory(); createAndVerifyProvisionedInterface(TEST_IFACE); when(mDeps.getNetworkInterfaceByName(TEST_IFACE)).thenReturn(mInterfaceParams); mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); @@ -497,26 +526,37 @@ public class EthernetNetworkFactoryTest { @Test public void testIgnoreLinkPropertiesCallbackAfterIpClientHasStopped() throws Exception { + initEthernetNetworkFactory(); createAndVerifyProvisionedInterface(TEST_IFACE); LinkProperties lp = new LinkProperties(); - mIpClientCallbacks.onProvisioningFailure(lp); + // The test requires the two proceeding methods to happen one after the other in ENF and + // verifies onLinkPropertiesChange doesn't complete execution for a downed interface. + // Posting is necessary as updateInterfaceLinkState with false will set mIpClientCallbacks + // to null which will throw an NPE in the test if executed synchronously. + mHandler.post(() -> mNetFactory.updateInterfaceLinkState(TEST_IFACE, false)); mIpClientCallbacks.onLinkPropertiesChange(lp); mLooper.dispatchAll(); - verifyStop(); + verifyStop(); // ipClient has been shut down first, we should not update verify(mNetworkAgent, never()).sendLinkPropertiesImpl(same(lp)); } @Test public void testIgnoreNeighborLossCallbackAfterIpClientHasStopped() throws Exception { + initEthernetNetworkFactory(); createAndVerifyProvisionedInterface(TEST_IFACE); - mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); + + // The test requires the two proceeding methods to happen one after the other in ENF and + // verifies onReachabilityLost doesn't complete execution for a downed interface. + // Posting is necessary as updateInterfaceLinkState with false will set mIpClientCallbacks + // to null which will throw an NPE in the test if executed synchronously. + mHandler.post(() -> mNetFactory.updateInterfaceLinkState(TEST_IFACE, false)); mIpClientCallbacks.onReachabilityLost("Neighbor Lost"); mLooper.dispatchAll(); - verifyStop(); + verifyStop(); // ipClient has been shut down first, we should not update verify(mIpClient, never()).startProvisioning(any()); verify(mNetworkAgent, never()).register(); @@ -567,6 +607,7 @@ public class EthernetNetworkFactoryTest { @Test public void testUpdateInterfaceCallsListenerCorrectlyOnSuccess() throws Exception { + initEthernetNetworkFactory(); createAndVerifyProvisionedInterface(TEST_IFACE); final NetworkCapabilities capabilities = createDefaultFilterCaps(); final IpConfiguration ipConfiguration = createStaticIpConfig(); @@ -580,8 +621,71 @@ public class EthernetNetworkFactoryTest { assertNull(ret.second); } + @DevSdkIgnoreRule.IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available + @Test + public void testUpdateInterfaceAbortsOnConcurrentRemoveInterface() throws Exception { + initEthernetNetworkFactory(); + verifyNetworkManagementCallIsAbortedWhenInterrupted( + TEST_IFACE, + () -> mNetFactory.removeInterface(TEST_IFACE)); + } + + @DevSdkIgnoreRule.IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available + @Test + public void testUpdateInterfaceAbortsOnConcurrentUpdateInterfaceLinkState() throws Exception { + initEthernetNetworkFactory(); + verifyNetworkManagementCallIsAbortedWhenInterrupted( + TEST_IFACE, + () -> mNetFactory.updateInterfaceLinkState(TEST_IFACE, false)); + } + + @DevSdkIgnoreRule.IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available + @Test + public void testUpdateInterfaceCallsListenerCorrectlyOnConcurrentRequests() throws Exception { + initEthernetNetworkFactory(); + final NetworkCapabilities capabilities = createDefaultFilterCaps(); + final IpConfiguration ipConfiguration = createStaticIpConfig(); + final TestNetworkManagementListener successfulListener = + new TestNetworkManagementListener(); + + // If two calls come in before the first one completes, the first listener will be aborted + // and the second one will be successful. + verifyNetworkManagementCallIsAbortedWhenInterrupted( + TEST_IFACE, + () -> { + mNetFactory.updateInterface( + TEST_IFACE, ipConfiguration, capabilities, successfulListener); + triggerOnProvisioningSuccess(); + }); + + final Pair successfulResult = + successfulListener.expectOnComplete(); + assertEquals(mMockNetwork, successfulResult.first); + assertNull(successfulResult.second); + } + + private void verifyNetworkManagementCallIsAbortedWhenInterrupted( + @NonNull final String iface, + @NonNull final Runnable interruptingRunnable) throws Exception { + createAndVerifyProvisionedInterface(iface); + final NetworkCapabilities capabilities = createDefaultFilterCaps(); + final IpConfiguration ipConfiguration = createStaticIpConfig(); + final TestNetworkManagementListener failedListener = new TestNetworkManagementListener(); + + // An active update request will be aborted on interrupt prior to provisioning completion. + mNetFactory.updateInterface(iface, ipConfiguration, capabilities, failedListener); + interruptingRunnable.run(); + + final Pair failedResult = + failedListener.expectOnComplete(); + assertNull(failedResult.first); + assertNotNull(failedResult.second); + assertTrue(failedResult.second.getMessage().contains("aborted")); + } + @Test public void testUpdateInterfaceRestartsAgentCorrectly() throws Exception { + initEthernetNetworkFactory(); createAndVerifyProvisionedInterface(TEST_IFACE); final NetworkCapabilities capabilities = createDefaultFilterCaps(); final IpConfiguration ipConfiguration = createStaticIpConfig(); From 9b9952ebe1b03fbfc35e245be254a6ea513734d5 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Thu, 20 Jan 2022 16:25:05 -0800 Subject: [PATCH 129/152] Implementation of Eth Connect & Disconnect Network Implementation of EthernetService APIs for ConnectNetwork() and DisconnectNetwork(). Bug: 210485380 Test: atest EthernetServiceTests Change-Id: I4c3e361d052206cb28b97fc439bfeac8e7e0fec0 --- .../ethernet/EthernetNetworkFactory.java | 26 +++++- .../server/ethernet/EthernetServiceImpl.java | 2 + .../server/ethernet/EthernetTracker.java | 19 +++- .../ethernet/EthernetNetworkFactoryTest.java | 92 +++++++++++++++---- .../ethernet/EthernetServiceImplTest.java | 30 ++++-- .../server/ethernet/EthernetTrackerTest.java | 35 +++++-- 6 files changed, 163 insertions(+), 41 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index c610f00ab1..0832b50738 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -252,8 +252,13 @@ public class EthernetNetworkFactory extends NetworkFactory { } /** Returns true if state has been modified */ - boolean updateInterfaceLinkState(String ifaceName, boolean up) { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + protected boolean updateInterfaceLinkState(@NonNull final String ifaceName, final boolean up, + @Nullable final IInternalNetworkManagementListener listener) { if (!mTrackingInterfaces.containsKey(ifaceName)) { + maybeSendNetworkManagementCallback(listener, null, + new InternalNetworkManagementException( + ifaceName + " can't be updated as it is not available.")); return false; } @@ -262,7 +267,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName); - return iface.updateLinkState(up); + return iface.updateLinkState(up, listener); } boolean hasInterface(String ifaceName) { @@ -615,16 +620,27 @@ public class EthernetNetworkFactory extends NetworkFactory { } /** Returns true if state has been modified */ - boolean updateLinkState(boolean up) { - if (mLinkUp == up) return false; + boolean updateLinkState(final boolean up, + @Nullable final IInternalNetworkManagementListener listener) { + if (mLinkUp == up) { + EthernetNetworkFactory.maybeSendNetworkManagementCallback(listener, null, + new InternalNetworkManagementException( + "No changes with requested link state " + up + " for " + name)); + return false; + } mLinkUp = up; if (!up) { // was up, goes down + // Save an instance of the current network to use with the callback before stop(). + final Network network = mNetworkAgent != null ? mNetworkAgent.getNetwork() : null; + // 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, network, null); } else { // was down, goes up stop(); - start(); + start(listener); } return true; diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index b2844779c8..6f6a04a273 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -243,6 +243,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Nullable final IInternalNetworkManagementListener listener) { Log.i(TAG, "connectNetwork called with: iface=" + iface + ", listener=" + listener); validateNetworkManagementState(iface, "connectNetwork()"); + mTracker.connectNetwork(iface, listener); } @Override @@ -250,5 +251,6 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Nullable final IInternalNetworkManagementListener listener) { Log.i(TAG, "disconnectNetwork called with: iface=" + iface + ", listener=" + listener); validateNetworkManagementState(iface, "disconnectNetwork()"); + mTracker.disconnectNetwork(iface, listener); } } diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 53af955d69..97845120db 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -190,6 +190,18 @@ public class EthernetTracker { mFactory.updateInterface(iface, ipConfig, capabilities, listener)); } + @VisibleForTesting(visibility = PACKAGE) + protected void connectNetwork(@NonNull final String iface, + @Nullable final IInternalNetworkManagementListener listener) { + mHandler.post(() -> updateInterfaceState(iface, true, listener)); + } + + @VisibleForTesting(visibility = PACKAGE) + protected void disconnectNetwork(@NonNull final String iface, + @Nullable final IInternalNetworkManagementListener listener) { + mHandler.post(() -> updateInterfaceState(iface, false, listener)); + } + IpConfiguration getIpConfiguration(String iface) { return mIpConfigurations.get(iface); } @@ -354,9 +366,14 @@ public class EthernetTracker { } private void updateInterfaceState(String iface, boolean up) { + updateInterfaceState(iface, up, null /* listener */); + } + + private void updateInterfaceState(@NonNull final String iface, final boolean up, + @Nullable final IInternalNetworkManagementListener listener) { final int mode = getInterfaceMode(iface); final boolean factoryLinkStateUpdated = (mode == INTERFACE_MODE_CLIENT) - && mFactory.updateInterfaceLinkState(iface, up); + && mFactory.updateInterfaceLinkState(iface, up, listener); if (factoryLinkStateUpdated) { boolean restricted = isRestrictedInterface(iface); diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index d569990a18..b8f0ada5a4 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -23,7 +23,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; @@ -84,6 +83,7 @@ import java.util.concurrent.TimeUnit; public class EthernetNetworkFactoryTest { private static final int TIMEOUT_MS = 2_000; private static final String TEST_IFACE = "test123"; + private static final IInternalNetworkManagementListener NULL_LISTENER = null; private static final String IP_ADDR = "192.0.2.2/25"; private static final LinkAddress LINK_ADDR = new LinkAddress(IP_ADDR); private static final String HW_ADDR = "01:02:03:04:05:06"; @@ -238,7 +238,7 @@ public class EthernetNetworkFactoryTest { final IpConfiguration ipConfig = createDefaultIpConfig(); mNetFactory.addInterface(iface, HW_ADDR, ipConfig, createInterfaceCapsBuilder(transportType).build()); - assertTrue(mNetFactory.updateInterfaceLinkState(iface, true)); + assertTrue(mNetFactory.updateInterfaceLinkState(iface, true, NULL_LISTENER)); verifyStart(ipConfig); clearInvocations(mDeps); clearInvocations(mIpClient); @@ -309,36 +309,74 @@ public class EthernetNetworkFactoryTest { public void testUpdateInterfaceLinkStateForActiveProvisioningInterface() throws Exception { initEthernetNetworkFactory(); createInterfaceUndergoingProvisioning(TEST_IFACE); + final TestNetworkManagementListener listener = new TestNetworkManagementListener(); + // verify that the IpClient gets shut down when interface state changes to down. - assertTrue(mNetFactory.updateInterfaceLinkState(TEST_IFACE, false)); + final boolean ret = + mNetFactory.updateInterfaceLinkState(TEST_IFACE, false /* up */, listener); + + assertTrue(ret); verify(mIpClient).shutdown(); + assertSuccessfulListener(listener, null); } @Test public void testUpdateInterfaceLinkStateForProvisionedInterface() throws Exception { initEthernetNetworkFactory(); createAndVerifyProvisionedInterface(TEST_IFACE); - assertTrue(mNetFactory.updateInterfaceLinkState(TEST_IFACE, false)); + final TestNetworkManagementListener listener = new TestNetworkManagementListener(); + + final boolean ret = + mNetFactory.updateInterfaceLinkState(TEST_IFACE, false /* up */, listener); + + assertTrue(ret); verifyStop(); + assertSuccessfulListener(listener, mMockNetwork); } @Test public void testUpdateInterfaceLinkStateForUnprovisionedInterface() throws Exception { initEthernetNetworkFactory(); createUnprovisionedInterface(TEST_IFACE); - assertTrue(mNetFactory.updateInterfaceLinkState(TEST_IFACE, false)); + final TestNetworkManagementListener listener = new TestNetworkManagementListener(); + + final boolean ret = + mNetFactory.updateInterfaceLinkState(TEST_IFACE, false /* up */, listener); + + assertTrue(ret); // There should not be an active IPClient or NetworkAgent. verify(mDeps, never()).makeIpClient(any(), any(), any()); verify(mDeps, never()) .makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any()); + assertSuccessfulListener(listener, null); } @Test public void testUpdateInterfaceLinkStateForNonExistingInterface() throws Exception { initEthernetNetworkFactory(); + final TestNetworkManagementListener listener = new TestNetworkManagementListener(); + // if interface was never added, link state cannot be updated. - assertFalse(mNetFactory.updateInterfaceLinkState("eth1", true)); - verify(mDeps, never()).makeIpClient(any(), any(), any()); + final boolean ret = + mNetFactory.updateInterfaceLinkState(TEST_IFACE, true /* up */, listener); + + assertFalse(ret); + verifyNoStopOrStart(); + assertFailedListener(listener, "can't be updated as it is not configured"); + } + + @Test + public void testUpdateInterfaceLinkStateWithNoChanges() throws Exception { + initEthernetNetworkFactory(); + createAndVerifyProvisionedInterface(TEST_IFACE); + final TestNetworkManagementListener listener = new TestNetworkManagementListener(); + + final boolean ret = + mNetFactory.updateInterfaceLinkState(TEST_IFACE, true /* up */, listener); + + assertFalse(ret); + verifyNoStopOrStart(); + assertFailedListener(listener, "No changes"); } @Test @@ -394,6 +432,10 @@ public class EthernetNetworkFactoryTest { // the interface disappeared and getNetworkInterfaceByName returns null, we should not retry verify(mIpClient, never()).startProvisioning(any()); + verifyNoStopOrStart(); + } + + private void verifyNoStopOrStart() { verify(mNetworkAgent, never()).register(); verify(mIpClient, never()).shutdown(); verify(mNetworkAgent, never()).unregister(); @@ -404,7 +446,7 @@ public class EthernetNetworkFactoryTest { public void testIpClientIsNotStartedWhenLinkIsDown() throws Exception { initEthernetNetworkFactory(); createUnprovisionedInterface(TEST_IFACE); - mNetFactory.updateInterfaceLinkState(TEST_IFACE, false); + mNetFactory.updateInterfaceLinkState(TEST_IFACE, false, NULL_LISTENER); mNetFactory.needNetworkFor(createDefaultRequest()); @@ -534,7 +576,7 @@ public class EthernetNetworkFactoryTest { // verifies onLinkPropertiesChange doesn't complete execution for a downed interface. // Posting is necessary as updateInterfaceLinkState with false will set mIpClientCallbacks // to null which will throw an NPE in the test if executed synchronously. - mHandler.post(() -> mNetFactory.updateInterfaceLinkState(TEST_IFACE, false)); + mHandler.post(() -> mNetFactory.updateInterfaceLinkState(TEST_IFACE, false, NULL_LISTENER)); mIpClientCallbacks.onLinkPropertiesChange(lp); mLooper.dispatchAll(); @@ -552,7 +594,7 @@ public class EthernetNetworkFactoryTest { // verifies onReachabilityLost doesn't complete execution for a downed interface. // Posting is necessary as updateInterfaceLinkState with false will set mIpClientCallbacks // to null which will throw an NPE in the test if executed synchronously. - mHandler.post(() -> mNetFactory.updateInterfaceLinkState(TEST_IFACE, false)); + mHandler.post(() -> mNetFactory.updateInterfaceLinkState(TEST_IFACE, false, NULL_LISTENER)); mIpClientCallbacks.onReachabilityLost("Neighbor Lost"); mLooper.dispatchAll(); @@ -616,9 +658,7 @@ public class EthernetNetworkFactoryTest { mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener); triggerOnProvisioningSuccess(); - final Pair ret = listener.expectOnComplete(); - assertEquals(mMockNetwork, ret.first); - assertNull(ret.second); + assertSuccessfulListener(listener, mMockNetwork); } @DevSdkIgnoreRule.IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available @@ -636,7 +676,7 @@ public class EthernetNetworkFactoryTest { initEthernetNetworkFactory(); verifyNetworkManagementCallIsAbortedWhenInterrupted( TEST_IFACE, - () -> mNetFactory.updateInterfaceLinkState(TEST_IFACE, false)); + () -> mNetFactory.updateInterfaceLinkState(TEST_IFACE, false, NULL_LISTENER)); } @DevSdkIgnoreRule.IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available @@ -658,12 +698,28 @@ public class EthernetNetworkFactoryTest { triggerOnProvisioningSuccess(); }); + assertSuccessfulListener(successfulListener, mMockNetwork); + } + + private void assertSuccessfulListener( + @NonNull final TestNetworkManagementListener successfulListener, + @NonNull final Network expectedNetwork) throws Exception { final Pair successfulResult = successfulListener.expectOnComplete(); - assertEquals(mMockNetwork, successfulResult.first); + assertEquals(expectedNetwork, successfulResult.first); assertNull(successfulResult.second); } + private void assertFailedListener(@NonNull final TestNetworkManagementListener failedListener, + @NonNull final String errMsg) + throws Exception { + final Pair failedResult = + failedListener.expectOnComplete(); + assertNull(failedResult.first); + assertNotNull(failedResult.second); + assertTrue(failedResult.second.getMessage().contains(errMsg)); + } + private void verifyNetworkManagementCallIsAbortedWhenInterrupted( @NonNull final String iface, @NonNull final Runnable interruptingRunnable) throws Exception { @@ -676,11 +732,7 @@ public class EthernetNetworkFactoryTest { mNetFactory.updateInterface(iface, ipConfiguration, capabilities, failedListener); interruptingRunnable.run(); - final Pair failedResult = - failedListener.expectOnComplete(); - assertNull(failedResult.first); - assertNotNull(failedResult.second); - assertTrue(failedResult.second.getMessage().contains("aborted")); + assertFailedListener(failedListener, "aborted"); } @Test diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java index 1c0888398a..6593aa5898 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java @@ -65,6 +65,15 @@ public class EthernetServiceImplTest { shouldTrackIface(TEST_IFACE, true); } + private void toggleAutomotiveFeature(final boolean isEnabled) { + doReturn(isEnabled) + .when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); + } + + private void shouldTrackIface(@NonNull final String iface, final boolean shouldTrack) { + doReturn(shouldTrack).when(mEthernetTracker).isTrackingInterface(iface); + } + @Test public void testSetConfigurationRejectsWhenEthNotStarted() { mEthernetServiceImpl.mStarted.set(false); @@ -143,11 +152,6 @@ public class EthernetServiceImplTest { }); } - private void toggleAutomotiveFeature(final boolean isEnabled) { - doReturn(isEnabled) - .when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); - } - @Test public void testUpdateConfigurationRejectsWithUntrackedIface() { shouldTrackIface(TEST_IFACE, false); @@ -172,10 +176,6 @@ public class EthernetServiceImplTest { }); } - private void shouldTrackIface(@NonNull final String iface, final boolean shouldTrack) { - doReturn(shouldTrack).when(mEthernetTracker).isTrackingInterface(iface); - } - @Test public void testUpdateConfiguration() { mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER); @@ -184,4 +184,16 @@ public class EthernetServiceImplTest { eq(UPDATE_REQUEST.getIpConfig()), eq(UPDATE_REQUEST.getNetworkCapabilities()), eq(NULL_LISTENER)); } + + @Test + public void testConnectNetwork() { + mEthernetServiceImpl.connectNetwork(TEST_IFACE, NULL_LISTENER); + verify(mEthernetTracker).connectNetwork(eq(TEST_IFACE), eq(NULL_LISTENER)); + } + + @Test + public void testDisconnectNetwork() { + mEthernetServiceImpl.disconnectNetwork(TEST_IFACE, NULL_LISTENER); + verify(mEthernetTracker).disconnectNetwork(eq(TEST_IFACE), eq(NULL_LISTENER)); + } } diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java index 5aca2e40a0..5087a9bcf4 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -19,9 +19,13 @@ package com.android.server.ethernet; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThrows; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; @@ -55,8 +59,10 @@ import java.util.ArrayList; @SmallTest @RunWith(AndroidJUnit4.class) public class EthernetTrackerTest { + private static final String TEST_IFACE = "test123"; private static final int TIMEOUT_MS = 1_000; private static final String THREAD_NAME = "EthernetServiceThread"; + private static final IInternalNetworkManagementListener NULL_LISTENER = null; private EthernetTracker tracker; private HandlerThread mHandlerThread; @Mock private Context mContext; @@ -68,6 +74,7 @@ public class EthernetTrackerTest { public void setUp() { MockitoAnnotations.initMocks(this); initMockResources(); + when(mFactory.updateInterfaceLinkState(anyString(), anyBoolean(), any())).thenReturn(false); mHandlerThread = new HandlerThread(THREAD_NAME); mHandlerThread.start(); tracker = new EthernetTracker(mContext, mHandlerThread.getThreadHandler(), mFactory, mNetd); @@ -294,16 +301,15 @@ public class EthernetTrackerTest { @Test public void testCreateEthernetTrackerConfigReturnsCorrectValue() { - final String iface = "1"; final String capabilities = "2"; final String ipConfig = "3"; final String transport = "4"; - final String configString = String.join(";", iface, capabilities, ipConfig, transport); + final String configString = String.join(";", TEST_IFACE, capabilities, ipConfig, transport); final EthernetTracker.EthernetTrackerConfig config = EthernetTracker.createEthernetTrackerConfig(configString); - assertEquals(iface, config.mIface); + assertEquals(TEST_IFACE, config.mIface); assertEquals(capabilities, config.mCapabilities); assertEquals(ipConfig, config.mIpConfig); assertEquals(transport, config.mTransport); @@ -317,16 +323,33 @@ public class EthernetTrackerTest { @Test public void testUpdateConfiguration() { - final String iface = "testiface"; final NetworkCapabilities capabilities = new NetworkCapabilities.Builder().build(); final StaticIpConfiguration staticIpConfig = new StaticIpConfiguration(); final IInternalNetworkManagementListener listener = null; - tracker.updateConfiguration(iface, staticIpConfig, capabilities, listener); + tracker.updateConfiguration(TEST_IFACE, staticIpConfig, capabilities, listener); waitForIdle(); verify(mFactory).updateInterface( - eq(iface), eq(EthernetTracker.createIpConfiguration(staticIpConfig)), + eq(TEST_IFACE), eq(EthernetTracker.createIpConfiguration(staticIpConfig)), eq(capabilities), eq(listener)); } + + @Test + public void testConnectNetworkCorrectlyCallsFactory() { + tracker.connectNetwork(TEST_IFACE, NULL_LISTENER); + waitForIdle(); + + verify(mFactory).updateInterfaceLinkState(eq(TEST_IFACE), eq(true /* up */), + eq(NULL_LISTENER)); + } + + @Test + public void testDisconnectNetworkCorrectlyCallsFactory() { + tracker.disconnectNetwork(TEST_IFACE, NULL_LISTENER); + waitForIdle(); + + verify(mFactory).updateInterfaceLinkState(eq(TEST_IFACE), eq(false /* up */), + eq(NULL_LISTENER)); + } } From 5aa01c3196631690243aeb612738d3453efe79bd Mon Sep 17 00:00:00 2001 From: James Mattis Date: Fri, 28 Jan 2022 13:39:04 -0800 Subject: [PATCH 130/152] Renaming Ethernet Network Management Classes Renaming InternalNetwork* files and classes related to ethernet network management to EthernetNetwork* as ethernet is the only trasnport these particular files are used with. Bug: 210485380 Test: atest EthernetServiceTests Change-Id: I5be8543afd70f2edca76a9366cee4ccf61f0d0e7 --- .../ethernet/EthernetNetworkFactory.java | 38 +++++++++---------- .../server/ethernet/EthernetServiceImpl.java | 12 +++--- .../server/ethernet/EthernetTracker.java | 10 ++--- .../ethernet/EthernetNetworkFactoryTest.java | 18 ++++----- .../ethernet/EthernetServiceImplTest.java | 10 ++--- .../server/ethernet/EthernetTrackerTest.java | 6 +-- 6 files changed, 47 insertions(+), 47 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 0832b50738..a15fec4aba 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -21,8 +21,8 @@ import android.annotation.Nullable; import android.content.Context; import android.net.ConnectivityManager; import android.net.EthernetNetworkSpecifier; -import android.net.IInternalNetworkManagementListener; -import android.net.InternalNetworkManagementException; +import android.net.IEthernetNetworkManagementListener; +import android.net.EthernetNetworkManagementException; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; @@ -195,14 +195,14 @@ public class EthernetNetworkFactory extends NetworkFactory { * {@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 IInternalNetworkManagementListener} to notify callers of + * @param listener an optional {@link IEthernetNetworkManagementListener} to notify callers of * completion. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) protected void updateInterface(@NonNull final String ifaceName, @NonNull final IpConfiguration ipConfig, @Nullable final NetworkCapabilities capabilities, - @Nullable final IInternalNetworkManagementListener listener) { + @Nullable final IEthernetNetworkManagementListener listener) { enforceInterfaceIsTracked(ifaceName); final NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName); iface.updateInterface(ipConfig, capabilities, listener); @@ -254,10 +254,10 @@ public class EthernetNetworkFactory extends NetworkFactory { /** Returns true if state has been modified */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) protected boolean updateInterfaceLinkState(@NonNull final String ifaceName, final boolean up, - @Nullable final IInternalNetworkManagementListener listener) { + @Nullable final IEthernetNetworkManagementListener listener) { if (!mTrackingInterfaces.containsKey(ifaceName)) { maybeSendNetworkManagementCallback(listener, null, - new InternalNetworkManagementException( + new EthernetNetworkManagementException( ifaceName + " can't be updated as it is not available.")); return false; } @@ -306,9 +306,9 @@ public class EthernetNetworkFactory extends NetworkFactory { } private static void maybeSendNetworkManagementCallback( - @Nullable final IInternalNetworkManagementListener listener, + @Nullable final IEthernetNetworkManagementListener listener, @Nullable final Network network, - @Nullable final InternalNetworkManagementException e) { + @Nullable final EthernetNetworkManagementException e) { if (null == listener) { return; } @@ -368,9 +368,9 @@ public class EthernetNetworkFactory extends NetworkFactory { private class EthernetIpClientCallback extends IpClientCallbacks { private final ConditionVariable mIpClientStartCv = new ConditionVariable(false); private final ConditionVariable mIpClientShutdownCv = new ConditionVariable(false); - @Nullable IInternalNetworkManagementListener mNetworkManagementListener; + @Nullable IEthernetNetworkManagementListener mNetworkManagementListener; - EthernetIpClientCallback(@Nullable final IInternalNetworkManagementListener listener) { + EthernetIpClientCallback(@Nullable final IEthernetNetworkManagementListener listener) { mNetworkManagementListener = listener; } @@ -455,7 +455,7 @@ public class EthernetNetworkFactory extends NetworkFactory { void updateInterface(@NonNull final IpConfiguration ipConfig, @Nullable final NetworkCapabilities capabilities, - @Nullable final IInternalNetworkManagementListener listener) { + @Nullable final IEthernetNetworkManagementListener listener) { if (DBG) { Log.d(TAG, "updateInterface, iface: " + name + ", ipConfig: " + ipConfig + ", old ipConfig: " + mIpConfig @@ -482,7 +482,7 @@ public class EthernetNetworkFactory extends NetworkFactory { start(null); } - private void start(@Nullable final IInternalNetworkManagementListener listener) { + private void start(@Nullable final IEthernetNetworkManagementListener listener) { if (mIpClient != null) { if (DBG) Log.d(TAG, "IpClient already started"); return; @@ -503,7 +503,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } void onIpLayerStarted(@NonNull final LinkProperties linkProperties, - @Nullable final IInternalNetworkManagementListener listener) { + @Nullable final IEthernetNetworkManagementListener listener) { if(mIpClient == null) { // This call comes from a message posted on the handler thread, but the IpClient has // since been stopped such as may be the case if updateInterfaceLinkState() is @@ -546,7 +546,7 @@ public class EthernetNetworkFactory extends NetworkFactory { realizeNetworkManagementCallback(mNetworkAgent.getNetwork(), null); } - void onIpLayerStopped(@Nullable final IInternalNetworkManagementListener listener) { + void onIpLayerStopped(@Nullable final IEthernetNetworkManagementListener listener) { // This cannot happen due to provisioning timeout, because our timeout is 0. It can // happen due to errors while provisioning or on provisioning loss. if(mIpClient == null) { @@ -567,13 +567,13 @@ public class EthernetNetworkFactory extends NetworkFactory { private void maybeSendNetworkManagementCallbackForAbort() { realizeNetworkManagementCallback(null, - new InternalNetworkManagementException( + new EthernetNetworkManagementException( "The IP provisioning request has been aborted.")); } // Must be called on the handler thread private void realizeNetworkManagementCallback(@Nullable final Network network, - @Nullable final InternalNetworkManagementException e) { + @Nullable final EthernetNetworkManagementException e) { ensureRunningOnEthernetHandlerThread(); if (null == mIpClientCallback) { return; @@ -621,10 +621,10 @@ public class EthernetNetworkFactory extends NetworkFactory { /** Returns true if state has been modified */ boolean updateLinkState(final boolean up, - @Nullable final IInternalNetworkManagementListener listener) { + @Nullable final IEthernetNetworkManagementListener listener) { if (mLinkUp == up) { EthernetNetworkFactory.maybeSendNetworkManagementCallback(listener, null, - new InternalNetworkManagementException( + new EthernetNetworkManagementException( "No changes with requested link state " + up + " for " + name)); return false; } @@ -692,7 +692,7 @@ public class EthernetNetworkFactory extends NetworkFactory { restart(null); } - void restart(@Nullable final IInternalNetworkManagementListener listener){ + void restart(@Nullable final IEthernetNetworkManagementListener listener){ if (DBG) Log.d(TAG, "reconnecting Ethernet"); stop(); start(listener); diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 6f6a04a273..dffac37fd2 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -22,9 +22,9 @@ import android.content.Context; import android.content.pm.PackageManager; import android.net.IEthernetManager; import android.net.IEthernetServiceListener; -import android.net.IInternalNetworkManagementListener; +import android.net.IEthernetNetworkManagementListener; import android.net.ITetheredInterfaceCallback; -import android.net.InternalNetworkUpdateRequest; +import android.net.EthernetNetworkUpdateRequest; import android.net.IpConfiguration; import android.os.Binder; import android.os.Handler; @@ -227,8 +227,8 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Override public void updateConfiguration(@NonNull final String iface, - @NonNull final InternalNetworkUpdateRequest request, - @Nullable final IInternalNetworkManagementListener listener) { + @NonNull final EthernetNetworkUpdateRequest request, + @Nullable final IEthernetNetworkManagementListener listener) { Log.i(TAG, "updateConfiguration called with: iface=" + iface + ", request=" + request + ", listener=" + listener); validateNetworkManagementState(iface, "updateConfiguration()"); @@ -240,7 +240,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Override public void connectNetwork(@NonNull final String iface, - @Nullable final IInternalNetworkManagementListener listener) { + @Nullable final IEthernetNetworkManagementListener listener) { Log.i(TAG, "connectNetwork called with: iface=" + iface + ", listener=" + listener); validateNetworkManagementState(iface, "connectNetwork()"); mTracker.connectNetwork(iface, listener); @@ -248,7 +248,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Override public void disconnectNetwork(@NonNull final String iface, - @Nullable final IInternalNetworkManagementListener listener) { + @Nullable final IEthernetNetworkManagementListener listener) { Log.i(TAG, "disconnectNetwork called with: iface=" + iface + ", listener=" + listener); validateNetworkManagementState(iface, "disconnectNetwork()"); mTracker.disconnectNetwork(iface, listener); diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 97845120db..6c8e6d3a97 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -24,7 +24,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.IEthernetServiceListener; -import android.net.IInternalNetworkManagementListener; +import android.net.IEthernetNetworkManagementListener; import android.net.INetd; import android.net.ITetheredInterfaceCallback; import android.net.InterfaceConfigurationParcel; @@ -178,7 +178,7 @@ public class EthernetTracker { protected void updateConfiguration(@NonNull final String iface, @NonNull final StaticIpConfiguration staticIpConfig, @NonNull final NetworkCapabilities capabilities, - @Nullable final IInternalNetworkManagementListener listener) { + @Nullable final IEthernetNetworkManagementListener listener) { if (DBG) { Log.i(TAG, "updateConfiguration, iface: " + iface + ", capabilities: " + capabilities + ", staticIpConfig: " + staticIpConfig); @@ -192,13 +192,13 @@ public class EthernetTracker { @VisibleForTesting(visibility = PACKAGE) protected void connectNetwork(@NonNull final String iface, - @Nullable final IInternalNetworkManagementListener listener) { + @Nullable final IEthernetNetworkManagementListener listener) { mHandler.post(() -> updateInterfaceState(iface, true, listener)); } @VisibleForTesting(visibility = PACKAGE) protected void disconnectNetwork(@NonNull final String iface, - @Nullable final IInternalNetworkManagementListener listener) { + @Nullable final IEthernetNetworkManagementListener listener) { mHandler.post(() -> updateInterfaceState(iface, false, listener)); } @@ -370,7 +370,7 @@ public class EthernetTracker { } private void updateInterfaceState(@NonNull final String iface, final boolean up, - @Nullable final IInternalNetworkManagementListener listener) { + @Nullable final IEthernetNetworkManagementListener listener) { final int mode = getInterfaceMode(iface); final boolean factoryLinkStateUpdated = (mode == INTERFACE_MODE_CLIENT) && mFactory.updateInterfaceLinkState(iface, up, listener); diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index b8f0ada5a4..7a90eeedd7 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -40,8 +40,8 @@ import android.content.Context; import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.EthernetNetworkSpecifier; -import android.net.IInternalNetworkManagementListener; -import android.net.InternalNetworkManagementException; +import android.net.IEthernetNetworkManagementListener; +import android.net.EthernetNetworkManagementException; import android.net.IpConfiguration; import android.net.LinkAddress; import android.net.LinkProperties; @@ -83,7 +83,7 @@ import java.util.concurrent.TimeUnit; public class EthernetNetworkFactoryTest { private static final int TIMEOUT_MS = 2_000; private static final String TEST_IFACE = "test123"; - private static final IInternalNetworkManagementListener NULL_LISTENER = null; + private static final IEthernetNetworkManagementListener NULL_LISTENER = null; private static final String IP_ADDR = "192.0.2.2/25"; private static final LinkAddress LINK_ADDR = new LinkAddress(IP_ADDR); private static final String HW_ADDR = "01:02:03:04:05:06"; @@ -627,17 +627,17 @@ public class EthernetNetworkFactoryTest { } private static final class TestNetworkManagementListener - implements IInternalNetworkManagementListener { - private final CompletableFuture> mDone + implements IEthernetNetworkManagementListener { + private final CompletableFuture> mDone = new CompletableFuture<>(); @Override public void onComplete(final Network network, - final InternalNetworkManagementException exception) { + final EthernetNetworkManagementException exception) { mDone.complete(new Pair<>(network, exception)); } - Pair expectOnComplete() throws Exception { + Pair expectOnComplete() throws Exception { return mDone.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); } @@ -704,7 +704,7 @@ public class EthernetNetworkFactoryTest { private void assertSuccessfulListener( @NonNull final TestNetworkManagementListener successfulListener, @NonNull final Network expectedNetwork) throws Exception { - final Pair successfulResult = + final Pair successfulResult = successfulListener.expectOnComplete(); assertEquals(expectedNetwork, successfulResult.first); assertNull(successfulResult.second); @@ -713,7 +713,7 @@ public class EthernetNetworkFactoryTest { private void assertFailedListener(@NonNull final TestNetworkManagementListener failedListener, @NonNull final String errMsg) throws Exception { - final Pair failedResult = + final Pair failedResult = failedListener.expectOnComplete(); assertNull(failedResult.first); assertNotNull(failedResult.second); diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java index 6593aa5898..18d6f3b66d 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java @@ -25,8 +25,8 @@ import static org.mockito.Mockito.verify; import android.annotation.NonNull; import android.content.Context; import android.content.pm.PackageManager; -import android.net.IInternalNetworkManagementListener; -import android.net.InternalNetworkUpdateRequest; +import android.net.IEthernetNetworkManagementListener; +import android.net.EthernetNetworkUpdateRequest; import android.net.IpConfiguration; import android.net.NetworkCapabilities; import android.net.StaticIpConfiguration; @@ -45,10 +45,10 @@ import org.mockito.MockitoAnnotations; @SmallTest public class EthernetServiceImplTest { private static final String TEST_IFACE = "test123"; - private static final InternalNetworkUpdateRequest UPDATE_REQUEST = - new InternalNetworkUpdateRequest( + private static final EthernetNetworkUpdateRequest UPDATE_REQUEST = + new EthernetNetworkUpdateRequest( new StaticIpConfiguration(), new NetworkCapabilities.Builder().build()); - private static final IInternalNetworkManagementListener NULL_LISTENER = null; + private static final IEthernetNetworkManagementListener NULL_LISTENER = null; private EthernetServiceImpl mEthernetServiceImpl; @Mock private Context mContext; @Mock private Handler mHandler; diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java index 5087a9bcf4..14f34d0dab 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -30,7 +30,7 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; import android.net.InetAddresses; -import android.net.IInternalNetworkManagementListener; +import android.net.IEthernetNetworkManagementListener; import android.net.INetd; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; @@ -62,7 +62,7 @@ public class EthernetTrackerTest { private static final String TEST_IFACE = "test123"; private static final int TIMEOUT_MS = 1_000; private static final String THREAD_NAME = "EthernetServiceThread"; - private static final IInternalNetworkManagementListener NULL_LISTENER = null; + private static final IEthernetNetworkManagementListener NULL_LISTENER = null; private EthernetTracker tracker; private HandlerThread mHandlerThread; @Mock private Context mContext; @@ -325,7 +325,7 @@ public class EthernetTrackerTest { public void testUpdateConfiguration() { final NetworkCapabilities capabilities = new NetworkCapabilities.Builder().build(); final StaticIpConfiguration staticIpConfig = new StaticIpConfiguration(); - final IInternalNetworkManagementListener listener = null; + final IEthernetNetworkManagementListener listener = null; tracker.updateConfiguration(TEST_IFACE, staticIpConfig, capabilities, listener); waitForIdle(); From a2c204259d446d90d2bb0d37a60e0c778100b6a3 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Fri, 28 Jan 2022 19:46:40 -0800 Subject: [PATCH 131/152] Updating Eth Service to use Eth Network Permission Updating Ethernet Service network management APIs to require the manage ethernet networks permission. Bug: 210485380 Test: atest EthernetServiceTests Change-Id: Ibc9b2930fc0069efd7c6f4b833aba7d6c8e93311 --- .../server/ethernet/EthernetServiceImpl.java | 10 ++++-- .../ethernet/EthernetNetworkFactoryTest.java | 2 +- .../ethernet/EthernetServiceImplTest.java | 33 +++++++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index dffac37fd2..ffd6d4070e 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -208,6 +208,12 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { pw.decreaseIndent(); } + private void enforceNetworkManagementPermission() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.MANAGE_ETHERNET_NETWORKS, + "EthernetServiceImpl"); + } + /** * Validate the state of ethernet for APIs tied to network management. * @@ -216,12 +222,12 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { */ private void validateNetworkManagementState(@NonNull final String iface, final @NonNull String methodName) { + enforceAutomotiveDevice(methodName); + enforceNetworkManagementPermission(); logIfEthernetNotStarted(); - // TODO: add permission check here for MANAGE_INTERNAL_NETWORKS when it's available. Objects.requireNonNull(iface, "Pass a non-null iface."); Objects.requireNonNull(methodName, "Pass a non-null methodName."); - enforceAutomotiveDevice(methodName); enforceInterfaceIsTracked(iface); } diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 7a90eeedd7..6e7c267445 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -362,7 +362,7 @@ public class EthernetNetworkFactoryTest { assertFalse(ret); verifyNoStopOrStart(); - assertFailedListener(listener, "can't be updated as it is not configured"); + assertFailedListener(listener, "can't be updated as it is not available"); } @Test diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java index 18d6f3b66d..0ac28c43dd 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java @@ -18,10 +18,13 @@ package com.android.server.ethernet; import static org.junit.Assert.assertThrows; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.verify; +import android.Manifest; import android.annotation.NonNull; import android.content.Context; import android.content.pm.PackageManager; @@ -176,6 +179,36 @@ public class EthernetServiceImplTest { }); } + private void denyManageEthPermission() { + doThrow(new SecurityException("")).when(mContext) + .enforceCallingOrSelfPermission( + eq(Manifest.permission.MANAGE_ETHERNET_NETWORKS), anyString()); + } + + @Test + public void testUpdateConfigurationRejectsWithoutManageEthPermission() { + denyManageEthPermission(); + assertThrows(SecurityException.class, () -> { + mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER); + }); + } + + @Test + public void testConnectNetworkRejectsWithoutManageEthPermission() { + denyManageEthPermission(); + assertThrows(SecurityException.class, () -> { + mEthernetServiceImpl.connectNetwork(TEST_IFACE, NULL_LISTENER); + }); + } + + @Test + public void testDisconnectNetworkRejectsWithoutManageEthPermission() { + denyManageEthPermission(); + assertThrows(SecurityException.class, () -> { + mEthernetServiceImpl.disconnectNetwork(TEST_IFACE, NULL_LISTENER); + }); + } + @Test public void testUpdateConfiguration() { mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER); From 8ae68834c3074cef9f8f0832a05e26bf04b7bd6e Mon Sep 17 00:00:00 2001 From: Milim Lee Date: Wed, 28 Apr 2021 13:56:11 +0900 Subject: [PATCH 132/152] Set EthernetNetworkSpecifier on ethernet networks Bug: 175199512 Test: atest EthernetServiceTests Change-Id: I4a4762a6509099a5c0954296cbf1b42e3a6cfc25 --- .../android/server/ethernet/EthernetNetworkFactory.java | 8 ++++++-- .../server/ethernet/EthernetNetworkFactoryTest.java | 7 ++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index a15fec4aba..cc8103b91d 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -176,12 +176,16 @@ public class EthernetNetworkFactory extends NetworkFactory { return; } + final NetworkCapabilities nc = new NetworkCapabilities.Builder(capabilities) + .setNetworkSpecifier(new EthernetNetworkSpecifier(ifaceName)) + .build(); + if (DBG) { - Log.d(TAG, "addInterface, iface: " + ifaceName + ", capabilities: " + capabilities); + Log.d(TAG, "addInterface, iface: " + ifaceName + ", capabilities: " + nc); } final NetworkInterfaceState iface = new NetworkInterfaceState( - ifaceName, hwAddress, mHandler, mContext, ipConfig, capabilities, this, mDeps); + ifaceName, hwAddress, mHandler, mContext, ipConfig, nc, this, mDeps); mTrackingInterfaces.put(ifaceName, iface); updateCapabilityFilter(); } diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 7a90eeedd7..ae52a751b7 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -71,6 +71,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -265,8 +266,12 @@ public class EthernetNetworkFactoryTest { triggerOnProvisioningSuccess(); // provisioning succeeded, verify that the network agent is created, registered, marked // as connected and legacy type are correctly set. - verify(mDeps).makeEthernetNetworkAgent(any(), any(), any(), any(), + final ArgumentCaptor ncCaptor = ArgumentCaptor.forClass( + NetworkCapabilities.class); + verify(mDeps).makeEthernetNetworkAgent(any(), any(), ncCaptor.capture(), any(), argThat(x -> x.getLegacyType() == expectedLegacyType), any(), any()); + assertEquals( + new EthernetNetworkSpecifier(iface), ncCaptor.getValue().getNetworkSpecifier()); verifyNetworkAgentRegistersAndConnects(); clearInvocations(mDeps); clearInvocations(mNetworkAgent); From 5216fc9eefded0b7033073f2630ee5178dec8d35 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 9 Feb 2022 08:53:59 +0900 Subject: [PATCH 133/152] Fix testIpClientIsNotStartedWhenLinkIsDown. This test is failing at HEAD because the known bug it is testing for is fixed. Check that IpClient is (correctly) not started when link is down. In order to ensure that the test is correct and that not starting IpClient is not caused by some other setup problem in the test, ensure that IpClient is also (correctly) started if later on link does come up. Test: atest EthernetServiceTests Test: atest --rerun-until-failure 100 EthernetNetworkFactoryTest#testIpClientIsNotStartedWhenLinkIsDown Change-Id: Id30bc9be1fc3ecf3d10c12d0b23c64814f4dbf9c --- .../server/ethernet/EthernetNetworkFactoryTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 6e7c267445..e10497e4e3 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -456,9 +456,10 @@ public class EthernetNetworkFactoryTest { .build(); mNetFactory.needNetworkFor(specificNetRequest); - // TODO(b/155707957): BUG: IPClient should not be started when the interface link state - // is down. - verify(mDeps).makeIpClient(any(), any(), any()); + verify(mDeps, never()).makeIpClient(any(), any(), any()); + + mNetFactory.updateInterfaceLinkState(TEST_IFACE, true, NULL_LISTENER); + verify(mDeps).makeIpClient(any(), eq(TEST_IFACE), any()); } @Test From b8ab4c869f2054ca9f89a427bb07d31abff1881d Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Sun, 30 Jan 2022 13:09:17 +0000 Subject: [PATCH 134/152] Implement the new added EthernetManager APIs. EthernetManager is moving to the connectivity mainline module and some of its hidden methods are being exposed as module-lib APIs. This CL updates the implementation. 1. Rename onAvailabilityChanged to onInterfaceStateChanged in IEthernetServiceListener.aidl, to match the name of the public callback method. 2. Add the interface state, role and IpConfiguration to the callback, so that clients can use this information without having to call synchronous methods. 3. Call the new callback whenever any of the above parameters changes, or when a callback is registered. Also make some package-private methods in EthernetNetworkFactory protected @VisibleForTesting because otherwise mockito can't mock them. Bug: 210586283 Test: m Test: atest EthernetServiceTests EthernetTetheringTest Change-Id: Ib27bf119b0d61b78f19b6447a38b4468d8035c78 Merged-In: Ib27bf119b0d61b78f19b6447a38b4468d8035c78 --- .../ethernet/EthernetNetworkFactory.java | 16 ++- .../server/ethernet/EthernetServiceImpl.java | 6 +- .../server/ethernet/EthernetTracker.java | 119 +++++++++++++----- 3 files changed, 108 insertions(+), 33 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index a15fec4aba..2823391633 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.ConnectivityManager; +import android.net.EthernetManager; import android.net.EthernetNetworkSpecifier; import android.net.IEthernetNetworkManagementListener; import android.net.EthernetNetworkManagementException; @@ -186,6 +187,18 @@ public class EthernetNetworkFactory extends NetworkFactory { 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. * @@ -270,7 +283,8 @@ public class EthernetNetworkFactory extends NetworkFactory { return iface.updateLinkState(up, listener); } - boolean hasInterface(String ifaceName) { + @VisibleForTesting + protected boolean hasInterface(String ifaceName) { return mTrackingInterfaces.containsKey(ifaceName); } diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index ffd6d4070e..c1c6d3a60b 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -143,10 +143,8 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { * Adds a listener. * @param listener A {@link IEthernetServiceListener} to add. */ - public void addListener(IEthernetServiceListener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } + public void addListener(IEthernetServiceListener listener) throws RemoteException { + Objects.requireNonNull(listener, "listener must not be null"); PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); mTracker.addListener(listener, checkUseRestrictedNetworksPermission()); } diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 6c8e6d3a97..2571fe66fe 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -23,6 +23,7 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility.PACK import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.net.EthernetManager; import android.net.IEthernetServiceListener; import android.net.IEthernetNetworkManagementListener; import android.net.INetd; @@ -165,7 +166,10 @@ public class EthernetTracker { Log.i(TAG, "updateIpConfiguration, iface: " + iface + ", cfg: " + ipConfiguration); } writeIpConfiguration(iface, ipConfiguration); - mHandler.post(() -> mFactory.updateInterface(iface, ipConfiguration, null, null)); + mHandler.post(() -> { + mFactory.updateInterface(iface, ipConfiguration, null, null); + broadcastInterfaceStateChange(iface); + }); } private void writeIpConfiguration(@NonNull final String iface, @@ -174,6 +178,55 @@ public class EthernetTracker { 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, @NonNull final StaticIpConfiguration staticIpConfig, @@ -186,8 +239,10 @@ public class EthernetTracker { final IpConfiguration ipConfig = createIpConfiguration(staticIpConfig); writeIpConfiguration(iface, ipConfig); mNetworkCapabilities.put(iface, capabilities); - mHandler.post(() -> - mFactory.updateInterface(iface, ipConfig, capabilities, listener)); + mHandler.post(() -> { + mFactory.updateInterface(iface, ipConfig, capabilities, listener); + broadcastInterfaceStateChange(iface); + }); } @VisibleForTesting(visibility = PACKAGE) @@ -225,11 +280,19 @@ public class EthernetTracker { } void addListener(IEthernetServiceListener listener, boolean canUseRestrictedNetworks) { - mListeners.register(listener, new ListenerInfo(canUseRestrictedNetworks)); + mHandler.post(() -> { + if (!mListeners.register(listener, new ListenerInfo(canUseRestrictedNetworks))) { + // Remote process has already died + return; + } + for (String iface : getInterfaces(canUseRestrictedNetworks)) { + unicastInterfaceStateChange(listener, iface); + } + }); } void removeListener(IEthernetServiceListener listener) { - mListeners.unregister(listener); + mHandler.post(() -> mListeners.unregister(listener)); } public void setIncludeTestInterfaces(boolean include) { @@ -295,6 +358,14 @@ public class EthernetTracker { } } + 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; @@ -312,6 +383,7 @@ public class EthernetTracker { if (iface.equals(mDefaultInterface)) { mDefaultInterface = null; } + broadcastInterfaceStateChange(iface); } private void addInterface(String iface) { @@ -346,11 +418,7 @@ public class EthernetTracker { final int mode = getInterfaceMode(iface); if (mode == INTERFACE_MODE_CLIENT) { - IpConfiguration ipConfiguration = mIpConfigurations.get(iface); - if (ipConfiguration == null) { - ipConfiguration = createDefaultIpConfiguration(); - } - + IpConfiguration ipConfiguration = getOrCreateIpConfiguration(iface); Log.d(TAG, "Tracking interface in client mode: " + iface); mFactory.addInterface(iface, hwAddress, ipConfiguration, nc); } else { @@ -376,22 +444,7 @@ public class EthernetTracker { && mFactory.updateInterfaceLinkState(iface, up, listener); if (factoryLinkStateUpdated) { - 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(); + broadcastInterfaceStateChange(iface); } } @@ -438,6 +491,8 @@ public class EthernetTracker { } addInterface(iface); + + broadcastInterfaceStateChange(iface); } private void trackAvailableInterfaces() { @@ -463,11 +518,17 @@ public class EthernetTracker { @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)); } } @@ -663,8 +724,10 @@ public class EthernetTracker { return ret; } - private static IpConfiguration createDefaultIpConfiguration() { - final IpConfiguration ret = new IpConfiguration(); + 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; From bb36434efdaa4d4ab387d2a92d1b1599bf907ecd Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Mon, 21 Feb 2022 16:24:45 +0100 Subject: [PATCH 135/152] Fix testIpClientIsNotStartedWhenLinkIsDown This test is breaking when requesting a network with an EthernetNetworkSpecifier after aosp/1795391 was submitted (which fixed another bug that hid this one). Test: atest EthernetNetworkFactoryTest Change-Id: I31f10f48cd03cdef29f21bbce790db68add071a8 --- .../server/ethernet/EthernetNetworkFactoryTest.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 6cb13efecf..33831a56d5 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -31,6 +31,7 @@ import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -455,16 +456,21 @@ public class EthernetNetworkFactoryTest { mNetFactory.needNetworkFor(createDefaultRequest()); + verify(mDeps, never()).makeIpClient(any(), any(), any()); + + // BUG(b/191854824): requesting a network with a specifier (Android Auto use case) should + // not start an IpClient when the link is down, but fixing this may make matters worse by + // tiggering b/197548738. NetworkRequest specificNetRequest = new NetworkRequest.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) .setNetworkSpecifier(new EthernetNetworkSpecifier(TEST_IFACE)) .build(); mNetFactory.needNetworkFor(specificNetRequest); - - verify(mDeps, never()).makeIpClient(any(), any(), any()); + mNetFactory.releaseNetworkFor(specificNetRequest); mNetFactory.updateInterfaceLinkState(TEST_IFACE, true, NULL_LISTENER); - verify(mDeps).makeIpClient(any(), eq(TEST_IFACE), any()); + // TODO: change to once when b/191854824 is fixed. + verify(mDeps, times(2)).makeIpClient(any(), eq(TEST_IFACE), any()); } @Test From ef20ec8f1209e80d2de451bddb11bf2033da133d Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Mon, 10 Jan 2022 14:39:39 +0100 Subject: [PATCH 136/152] Enable EthernetServiceTests in presubmit Test: run presubmit Bug: 213863997 Change-Id: I6736198539a37d538d5d53d64c16abe572bf3982 --- tests/ethernet/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ethernet/Android.bp b/tests/ethernet/Android.bp index 93a8f6ca45..28b13c5243 100644 --- a/tests/ethernet/Android.bp +++ b/tests/ethernet/Android.bp @@ -40,4 +40,5 @@ android_test { "services.core", "services.net", ], + test_suites: ["general-tests"], } From 7448a982fa7d1e8aa9f4e9abd71052bfa279b762 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Thu, 17 Feb 2022 13:08:20 -0800 Subject: [PATCH 137/152] Using a builder for eth requests Updating ethernet classes to use a builder when creating an EthernetNetworkUpdateRequest and also changing to use IpConfiguration instead of StaticIpConfiguration for the UpdateConfiguration API. Bug: 220017952 Bug: 210487893 Bug: 210485380 Test: atest EthernetServiceTests Change-Id: I2647115bf867dfaa3f3dadf00e3c875aa7e8d88f --- .../server/ethernet/EthernetServiceImpl.java | 2 +- .../server/ethernet/EthernetTracker.java | 18 +++++++----------- .../ethernet/EthernetServiceImplTest.java | 9 +++++---- .../server/ethernet/EthernetTrackerTest.java | 11 +++++++---- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index c1c6d3a60b..fed500f367 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -239,7 +239,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { // TODO: validate that iface is listed in overlay config_ethernet_interfaces mTracker.updateConfiguration( - iface, request.getIpConfig(), request.getNetworkCapabilities(), listener); + iface, request.getIpConfiguration(), request.getNetworkCapabilities(), listener); } @Override diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 2571fe66fe..794b5d1b90 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -229,18 +229,18 @@ public class EthernetTracker { @VisibleForTesting(visibility = PACKAGE) protected void updateConfiguration(@NonNull final String iface, - @NonNull final StaticIpConfiguration staticIpConfig, + @NonNull final IpConfiguration ipConfig, @NonNull final NetworkCapabilities capabilities, @Nullable final IEthernetNetworkManagementListener listener) { if (DBG) { Log.i(TAG, "updateConfiguration, iface: " + iface + ", capabilities: " + capabilities - + ", staticIpConfig: " + staticIpConfig); + + ", ipConfig: " + ipConfig); } - final IpConfiguration ipConfig = createIpConfiguration(staticIpConfig); - writeIpConfiguration(iface, ipConfig); + final IpConfiguration localIpConfig = new IpConfiguration(ipConfig); + writeIpConfiguration(iface, localIpConfig); mNetworkCapabilities.put(iface, capabilities); mHandler.post(() -> { - mFactory.updateInterface(iface, ipConfig, capabilities, listener); + mFactory.updateInterface(iface, localIpConfig, capabilities, listener); broadcastInterfaceStateChange(iface); }); } @@ -715,13 +715,9 @@ public class EthernetTracker { return createIpConfiguration(staticIpConfigBuilder.build()); } - static IpConfiguration createIpConfiguration( + private static IpConfiguration createIpConfiguration( @NonNull final StaticIpConfiguration staticIpConfig) { - final IpConfiguration ret = new IpConfiguration(); - ret.setIpAssignment(IpAssignment.STATIC); - ret.setProxySettings(ProxySettings.NONE); - ret.setStaticIpConfiguration(staticIpConfig); - return ret; + return new IpConfiguration.Builder().setStaticIpConfiguration(staticIpConfig).build(); } private IpConfiguration getOrCreateIpConfiguration(String iface) { diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java index 0ac28c43dd..28297537ea 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java @@ -32,7 +32,6 @@ import android.net.IEthernetNetworkManagementListener; import android.net.EthernetNetworkUpdateRequest; import android.net.IpConfiguration; import android.net.NetworkCapabilities; -import android.net.StaticIpConfiguration; import android.os.Handler; import androidx.test.filters.SmallTest; @@ -49,8 +48,10 @@ import org.mockito.MockitoAnnotations; public class EthernetServiceImplTest { private static final String TEST_IFACE = "test123"; private static final EthernetNetworkUpdateRequest UPDATE_REQUEST = - new EthernetNetworkUpdateRequest( - new StaticIpConfiguration(), new NetworkCapabilities.Builder().build()); + new EthernetNetworkUpdateRequest.Builder() + .setIpConfiguration(new IpConfiguration()) + .setNetworkCapabilities(new NetworkCapabilities.Builder().build()) + .build(); private static final IEthernetNetworkManagementListener NULL_LISTENER = null; private EthernetServiceImpl mEthernetServiceImpl; @Mock private Context mContext; @@ -214,7 +215,7 @@ public class EthernetServiceImplTest { mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER); verify(mEthernetTracker).updateConfiguration( eq(TEST_IFACE), - eq(UPDATE_REQUEST.getIpConfig()), + eq(UPDATE_REQUEST.getIpConfiguration()), eq(UPDATE_REQUEST.getNetworkCapabilities()), eq(NULL_LISTENER)); } diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java index 14f34d0dab..e1a1a8e7e9 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -324,15 +324,18 @@ public class EthernetTrackerTest { @Test public void testUpdateConfiguration() { final NetworkCapabilities capabilities = new NetworkCapabilities.Builder().build(); - final StaticIpConfiguration staticIpConfig = new StaticIpConfiguration(); + final LinkAddress linkAddr = new LinkAddress("192.0.2.2/25"); + final StaticIpConfiguration staticIpConfig = + new StaticIpConfiguration.Builder().setIpAddress(linkAddr).build(); + final IpConfiguration ipConfig = + new IpConfiguration.Builder().setStaticIpConfiguration(staticIpConfig).build(); final IEthernetNetworkManagementListener listener = null; - tracker.updateConfiguration(TEST_IFACE, staticIpConfig, capabilities, listener); + tracker.updateConfiguration(TEST_IFACE, ipConfig, capabilities, listener); waitForIdle(); verify(mFactory).updateInterface( - eq(TEST_IFACE), eq(EthernetTracker.createIpConfiguration(staticIpConfig)), - eq(capabilities), eq(listener)); + eq(TEST_IFACE), eq(ipConfig), eq(capabilities), eq(listener)); } @Test From ed41dfeb44fa117db968b675cea138bfad0e0693 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Mon, 28 Feb 2022 14:08:12 -0800 Subject: [PATCH 138/152] Ethernet validate if iface is tracked on handler Removing synchronous validation of whether a particular interface is tracked or not and instead relying on asynchronous validation and callbacks. An interface can be in the midst of being provisioned and checking if it is tracked sychronously before provisioning is complete will erroneously throw an error for a call that would have been successful when executed on the ethernet handler thread. Bug: 210487893 Bug: 210485380 Test: atest EthernetServiceTests Change-Id: Ib70312a240cab412a54ca7f598893aa9b1e108fd --- .../ethernet/EthernetNetworkFactory.java | 26 ++++++++++--------- .../server/ethernet/EthernetServiceImpl.java | 13 +++------- .../ethernet/EthernetNetworkFactoryTest.java | 14 ++++++++++ .../ethernet/EthernetServiceImplTest.java | 24 ----------------- 4 files changed, 31 insertions(+), 46 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index f266386024..8ce27a64b1 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -220,20 +220,17 @@ public class EthernetNetworkFactory extends NetworkFactory { @NonNull final IpConfiguration ipConfig, @Nullable final NetworkCapabilities capabilities, @Nullable final IEthernetNetworkManagementListener listener) { - enforceInterfaceIsTracked(ifaceName); + if (!hasInterface(ifaceName)) { + maybeSendNetworkManagementCallbackForUntracked(ifaceName, listener); + return; + } + final NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName); iface.updateInterface(ipConfig, capabilities, listener); mTrackingInterfaces.put(ifaceName, iface); updateCapabilityFilter(); } - private void enforceInterfaceIsTracked(@NonNull final String ifaceName) { - if (!hasInterface(ifaceName)) { - throw new UnsupportedOperationException( - "Interface with name " + ifaceName + " is not being tracked."); - } - } - private static NetworkCapabilities mixInCapabilities(NetworkCapabilities nc, NetworkCapabilities addedNc) { final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(nc); @@ -272,10 +269,8 @@ public class EthernetNetworkFactory extends NetworkFactory { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) protected boolean updateInterfaceLinkState(@NonNull final String ifaceName, final boolean up, @Nullable final IEthernetNetworkManagementListener listener) { - if (!mTrackingInterfaces.containsKey(ifaceName)) { - maybeSendNetworkManagementCallback(listener, null, - new EthernetNetworkManagementException( - ifaceName + " can't be updated as it is not available.")); + if (!hasInterface(ifaceName)) { + maybeSendNetworkManagementCallbackForUntracked(ifaceName, listener); return false; } @@ -287,6 +282,13 @@ public class EthernetNetworkFactory extends NetworkFactory { return iface.updateLinkState(up, listener); } + private void maybeSendNetworkManagementCallbackForUntracked( + String ifaceName, IEthernetNetworkManagementListener 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); diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index fed500f367..f80f6a05b8 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -66,12 +66,6 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { methodName + " is only available on automotive devices."); } - private void enforceInterfaceIsTracked(final @NonNull String iface) { - if(!mTracker.isTrackingInterface(iface)) { - throw new UnsupportedOperationException("The given iface is not currently tracked."); - } - } - private boolean checkUseRestrictedNetworksPermission() { return PermissionUtils.checkAnyPermissionOf(mContext, android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS); @@ -220,13 +214,12 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { */ private void validateNetworkManagementState(@NonNull final String iface, final @NonNull String methodName) { + Objects.requireNonNull(iface, "Pass a non-null iface."); + Objects.requireNonNull(methodName, "Pass a non-null methodName."); + enforceAutomotiveDevice(methodName); enforceNetworkManagementPermission(); logIfEthernetNotStarted(); - - Objects.requireNonNull(iface, "Pass a non-null iface."); - Objects.requireNonNull(methodName, "Pass a non-null methodName."); - enforceInterfaceIsTracked(iface); } @Override diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 33831a56d5..61425bf171 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -763,4 +763,18 @@ public class EthernetNetworkFactoryTest { eq(capabilities), any(), any(), any(), any()); verifyRestart(ipConfiguration); } + + @Test + public void testUpdateInterfaceForNonExistingInterface() throws Exception { + initEthernetNetworkFactory(); + // No interface exists due to not calling createAndVerifyProvisionedInterface(...). + final NetworkCapabilities capabilities = createDefaultFilterCaps(); + final IpConfiguration ipConfiguration = createStaticIpConfig(); + final TestNetworkManagementListener listener = new TestNetworkManagementListener(); + + mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener); + + verifyNoStopOrStart(); + assertFailedListener(listener, "can't be updated as it is not available"); + } } diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java index 28297537ea..e74a5a366c 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java @@ -156,30 +156,6 @@ public class EthernetServiceImplTest { }); } - @Test - public void testUpdateConfigurationRejectsWithUntrackedIface() { - shouldTrackIface(TEST_IFACE, false); - assertThrows(UnsupportedOperationException.class, () -> { - mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER); - }); - } - - @Test - public void testConnectNetworkRejectsWithUntrackedIface() { - shouldTrackIface(TEST_IFACE, false); - assertThrows(UnsupportedOperationException.class, () -> { - mEthernetServiceImpl.connectNetwork(TEST_IFACE, NULL_LISTENER); - }); - } - - @Test - public void testDisconnectNetworkRejectsWithUntrackedIface() { - shouldTrackIface(TEST_IFACE, false); - assertThrows(UnsupportedOperationException.class, () -> { - mEthernetServiceImpl.disconnectNetwork(TEST_IFACE, NULL_LISTENER); - }); - } - private void denyManageEthPermission() { doThrow(new SecurityException("")).when(mContext) .enforceCallingOrSelfPermission( From b0cc8f09a4eb5e4a1c9c3bf073f9ac14dde60744 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Sat, 26 Feb 2022 22:16:46 -0800 Subject: [PATCH 139/152] Eth Management APIs to Support TEST Interfaces Updating Ethernet Network Management APIs to allow support for test interfaces when the caller has the MANAGE_TEST_NETWORKS permission, test interfaces are being tracked in ethernet and if updating a network's capabilities, they include the TEST transport. Bug: 210487893 Test: atest EthernetServiceTests atest CtsNetTestCasesLatestSdk :android.net.cts.EthernetManagerTest Change-Id: I0e0bc9632d9b3d5d61f23e74150586f42c0b5bd2 --- .../server/ethernet/EthernetServiceImpl.java | 34 ++++++- .../server/ethernet/EthernetTracker.java | 14 +++ .../ethernet/EthernetServiceImplTest.java | 92 +++++++++++++++++++ .../server/ethernet/EthernetTrackerTest.java | 41 ++++++++- 4 files changed, 176 insertions(+), 5 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index f80f6a05b8..7f77e5e633 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -16,6 +16,8 @@ package com.android.server.ethernet; +import static android.net.NetworkCapabilities.TRANSPORT_TEST; + import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; @@ -26,6 +28,7 @@ import android.net.IEthernetNetworkManagementListener; 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; @@ -206,6 +209,12 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { "EthernetServiceImpl"); } + private void enforceManageTestNetworksPermission() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.MANAGE_TEST_NETWORKS, + "EthernetServiceImpl"); + } + /** * Validate the state of ethernet for APIs tied to network management. * @@ -217,18 +226,35 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { Objects.requireNonNull(iface, "Pass a non-null iface."); Objects.requireNonNull(methodName, "Pass a non-null methodName."); - enforceAutomotiveDevice(methodName); - enforceNetworkManagementPermission(); + // Only bypass the permission/device checks if this is a valid test interface. + if (mTracker.isValidTestInterface(iface)) { + enforceManageTestNetworksPermission(); + Log.i(TAG, "Ethernet network management API used with test interface " + iface); + } else { + enforceAutomotiveDevice(methodName); + enforceNetworkManagementPermission(); + } logIfEthernetNotStarted(); } + private void validateTestCapabilities(@NonNull final NetworkCapabilities nc) { + if (nc.hasTransport(TRANSPORT_TEST)) { + return; + } + throw new IllegalArgumentException( + "Updates to test interfaces must have NetworkCapabilities.TRANSPORT_TEST."); + } + @Override public void updateConfiguration(@NonNull final String iface, @NonNull final EthernetNetworkUpdateRequest request, @Nullable final IEthernetNetworkManagementListener listener) { - Log.i(TAG, "updateConfiguration called with: iface=" + iface - + ", request=" + request + ", listener=" + listener); validateNetworkManagementState(iface, "updateConfiguration()"); + if (mTracker.isValidTestInterface(iface)) { + validateTestCapabilities(request.getNetworkCapabilities()); + // TODO: use NetworkCapabilities#restrictCapabilitiesForTestNetwork when available on a + // local NetworkCapabilities copy to pass to mTracker.updateConfiguration. + } // TODO: validate that iface is listed in overlay config_ethernet_interfaces mTracker.updateConfiguration( diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 794b5d1b90..9070a7e090 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -86,6 +86,9 @@ public class EthernetTracker { * if setIncludeTestInterfaces is true, any test interfaces. */ private String mIfaceMatch; + /** + * Track test interfaces if true, don't track otherwise. + */ private boolean mIncludeTestInterfaces = false; /** Mapping between {iface name | mac address} -> {NetworkCapabilities} */ @@ -738,6 +741,17 @@ public class EthernetTracker { 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(() -> { diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java index e74a5a366c..012f07aca1 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java @@ -16,6 +16,8 @@ package com.android.server.ethernet; +import static android.net.NetworkCapabilities.TRANSPORT_TEST; + import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.anyString; @@ -23,6 +25,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.Manifest; import android.annotation.NonNull; @@ -162,6 +165,12 @@ public class EthernetServiceImplTest { eq(Manifest.permission.MANAGE_ETHERNET_NETWORKS), anyString()); } + private void denyManageTestNetworksPermission() { + doThrow(new SecurityException("")).when(mContext) + .enforceCallingOrSelfPermission( + eq(Manifest.permission.MANAGE_TEST_NETWORKS), anyString()); + } + @Test public void testUpdateConfigurationRejectsWithoutManageEthPermission() { denyManageEthPermission(); @@ -186,6 +195,37 @@ public class EthernetServiceImplTest { }); } + private void enableTestInterface() { + when(mEthernetTracker.isValidTestInterface(eq(TEST_IFACE))).thenReturn(true); + } + + @Test + public void testUpdateConfigurationRejectsTestRequestWithoutTestPermission() { + enableTestInterface(); + denyManageTestNetworksPermission(); + assertThrows(SecurityException.class, () -> { + mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER); + }); + } + + @Test + public void testConnectNetworkRejectsTestRequestWithoutTestPermission() { + enableTestInterface(); + denyManageTestNetworksPermission(); + assertThrows(SecurityException.class, () -> { + mEthernetServiceImpl.connectNetwork(TEST_IFACE, NULL_LISTENER); + }); + } + + @Test + public void testDisconnectNetworkRejectsTestRequestWithoutTestPermission() { + enableTestInterface(); + denyManageTestNetworksPermission(); + assertThrows(SecurityException.class, () -> { + mEthernetServiceImpl.disconnectNetwork(TEST_IFACE, NULL_LISTENER); + }); + } + @Test public void testUpdateConfiguration() { mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER); @@ -206,4 +246,56 @@ public class EthernetServiceImplTest { mEthernetServiceImpl.disconnectNetwork(TEST_IFACE, NULL_LISTENER); verify(mEthernetTracker).disconnectNetwork(eq(TEST_IFACE), eq(NULL_LISTENER)); } + + @Test + public void testUpdateConfigurationRejectsInvalidTestRequest() { + enableTestInterface(); + assertThrows(IllegalArgumentException.class, () -> { + mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER); + }); + } + + private EthernetNetworkUpdateRequest createTestNetworkUpdateRequest() { + final NetworkCapabilities nc = new NetworkCapabilities + .Builder(UPDATE_REQUEST.getNetworkCapabilities()) + .addTransportType(TRANSPORT_TEST).build(); + + return new EthernetNetworkUpdateRequest + .Builder(UPDATE_REQUEST) + .setNetworkCapabilities(nc).build(); + } + + @Test + public void testUpdateConfigurationForTestRequestDoesNotRequireAutoOrEthernetPermission() { + enableTestInterface(); + toggleAutomotiveFeature(false); + denyManageEthPermission(); + final EthernetNetworkUpdateRequest request = createTestNetworkUpdateRequest(); + + mEthernetServiceImpl.updateConfiguration(TEST_IFACE, request, NULL_LISTENER); + verify(mEthernetTracker).updateConfiguration( + eq(TEST_IFACE), + eq(request.getIpConfiguration()), + eq(request.getNetworkCapabilities()), eq(NULL_LISTENER)); + } + + @Test + public void testConnectNetworkForTestRequestDoesNotRequireAutoOrNetPermission() { + enableTestInterface(); + toggleAutomotiveFeature(false); + denyManageEthPermission(); + + mEthernetServiceImpl.connectNetwork(TEST_IFACE, NULL_LISTENER); + verify(mEthernetTracker).connectNetwork(eq(TEST_IFACE), eq(NULL_LISTENER)); + } + + @Test + public void testDisconnectNetworkForTestRequestDoesNotRequireAutoOrNetPermission() { + enableTestInterface(); + toggleAutomotiveFeature(false); + denyManageEthPermission(); + + mEthernetServiceImpl.disconnectNetwork(TEST_IFACE, NULL_LISTENER); + verify(mEthernetTracker).disconnectNetwork(eq(TEST_IFACE), eq(NULL_LISTENER)); + } } diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java index e1a1a8e7e9..d86cc0f60d 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -16,8 +16,12 @@ package com.android.server.ethernet; +import static android.net.TestNetworkManager.TEST_TAP_PREFIX; + import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; @@ -39,6 +43,7 @@ import android.net.LinkAddress; import android.net.NetworkCapabilities; import android.net.StaticIpConfiguration; import android.os.HandlerThread; +import android.os.RemoteException; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -71,10 +76,11 @@ public class EthernetTrackerTest { @Mock Resources mResources; @Before - public void setUp() { + public void setUp() throws RemoteException { MockitoAnnotations.initMocks(this); initMockResources(); when(mFactory.updateInterfaceLinkState(anyString(), anyBoolean(), any())).thenReturn(false); + when(mNetd.interfaceGetList()).thenReturn(new String[0]); mHandlerThread = new HandlerThread(THREAD_NAME); mHandlerThread.start(); tracker = new EthernetTracker(mContext, mHandlerThread.getThreadHandler(), mFactory, mNetd); @@ -355,4 +361,37 @@ public class EthernetTrackerTest { verify(mFactory).updateInterfaceLinkState(eq(TEST_IFACE), eq(false /* up */), eq(NULL_LISTENER)); } + + @Test + public void testIsValidTestInterfaceIsFalseWhenTestInterfacesAreNotIncluded() { + final String validIfaceName = TEST_TAP_PREFIX + "123"; + tracker.setIncludeTestInterfaces(false); + waitForIdle(); + + final boolean isValidTestInterface = tracker.isValidTestInterface(validIfaceName); + + assertFalse(isValidTestInterface); + } + + @Test + public void testIsValidTestInterfaceIsFalseWhenTestInterfaceNameIsInvalid() { + final String invalidIfaceName = "123" + TEST_TAP_PREFIX; + tracker.setIncludeTestInterfaces(true); + waitForIdle(); + + final boolean isValidTestInterface = tracker.isValidTestInterface(invalidIfaceName); + + assertFalse(isValidTestInterface); + } + + @Test + public void testIsValidTestInterfaceIsTrueWhenTestInterfacesIncludedAndValidName() { + final String validIfaceName = TEST_TAP_PREFIX + "123"; + tracker.setIncludeTestInterfaces(true); + waitForIdle(); + + final boolean isValidTestInterface = tracker.isValidTestInterface(validIfaceName); + + assertTrue(isValidTestInterface); + } } From 3e12496b6028428c896d1e78ecd838508de42f34 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Thu, 3 Mar 2022 16:19:04 -0800 Subject: [PATCH 140/152] Allowing for null net caps in updateConfiguration Marking NetworkCapabilities as nullable in updateConfiguration and updating where needed to support this. This will allow callers of the ethernet network management updateConfiguration API to use it primarily for setting an ethernet network's IP configuration. Bug: 222565654 Bug: 220017952 Bug: 210485380 Test: atest EthernetServiceTests Change-Id: Ifd908639a00470e599fe1a15487cc6383a56b2f5 --- .../server/ethernet/EthernetNetworkFactory.java | 4 +++- .../android/server/ethernet/EthernetServiceImpl.java | 4 ++-- .../com/android/server/ethernet/EthernetTracker.java | 6 ++++-- .../server/ethernet/EthernetServiceImplTest.java | 12 ++++++++++++ 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 8ce27a64b1..875fc102c0 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -485,7 +485,9 @@ public class EthernetNetworkFactory extends NetworkFactory { } mIpConfig = ipConfig; - setCapabilities(capabilities); + 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 diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 7f77e5e633..9987b3e00c 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -237,8 +237,8 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { logIfEthernetNotStarted(); } - private void validateTestCapabilities(@NonNull final NetworkCapabilities nc) { - if (nc.hasTransport(TRANSPORT_TEST)) { + private void validateTestCapabilities(@Nullable final NetworkCapabilities nc) { + if (null != nc && nc.hasTransport(TRANSPORT_TEST)) { return; } throw new IllegalArgumentException( diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 9070a7e090..ea241e1d3f 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -233,7 +233,7 @@ public class EthernetTracker { @VisibleForTesting(visibility = PACKAGE) protected void updateConfiguration(@NonNull final String iface, @NonNull final IpConfiguration ipConfig, - @NonNull final NetworkCapabilities capabilities, + @Nullable final NetworkCapabilities capabilities, @Nullable final IEthernetNetworkManagementListener listener) { if (DBG) { Log.i(TAG, "updateConfiguration, iface: " + iface + ", capabilities: " + capabilities @@ -241,7 +241,9 @@ public class EthernetTracker { } final IpConfiguration localIpConfig = new IpConfiguration(ipConfig); writeIpConfiguration(iface, localIpConfig); - mNetworkCapabilities.put(iface, capabilities); + if (null != capabilities) { + mNetworkCapabilities.put(iface, capabilities); + } mHandler.post(() -> { mFactory.updateInterface(iface, localIpConfig, capabilities, listener); broadcastInterfaceStateChange(iface); diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java index 012f07aca1..e814c84f5b 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java @@ -247,6 +247,18 @@ public class EthernetServiceImplTest { verify(mEthernetTracker).disconnectNetwork(eq(TEST_IFACE), eq(NULL_LISTENER)); } + @Test + public void testUpdateConfigurationRejectsTestRequestWithNullCapabilities() { + enableTestInterface(); + final EthernetNetworkUpdateRequest request = + new EthernetNetworkUpdateRequest + .Builder() + .setIpConfiguration(new IpConfiguration()).build(); + assertThrows(IllegalArgumentException.class, () -> { + mEthernetServiceImpl.updateConfiguration(TEST_IFACE, request, NULL_LISTENER); + }); + } + @Test public void testUpdateConfigurationRejectsInvalidTestRequest() { enableTestInterface(); From 24fb1ef5b0ee92d641f5814ca4b515c1d74b0480 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Tue, 8 Mar 2022 13:10:18 +0100 Subject: [PATCH 141/152] Allow all device types to call updateConfiguration Usage of this API should not be limited to Automotive devices as TvSettings also needs to update the IpConfiguration. Test: TH Change-Id: I838a0a8684e9f944801718a4d688666de45f42fb --- .../server/ethernet/EthernetServiceImpl.java | 67 +++++++++++-------- .../ethernet/EthernetServiceImplTest.java | 26 +++++-- 2 files changed, 59 insertions(+), 34 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 9987b3e00c..782ee0fad4 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -215,45 +215,34 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { "EthernetServiceImpl"); } - /** - * Validate the state of ethernet for APIs tied to network management. - * - * @param iface the ethernet interface name to operate on. - * @param methodName the name of the calling method. - */ - private void validateNetworkManagementState(@NonNull final String iface, - final @NonNull String methodName) { - Objects.requireNonNull(iface, "Pass a non-null iface."); - Objects.requireNonNull(methodName, "Pass a non-null methodName."); - - // Only bypass the permission/device checks if this is a valid test interface. - if (mTracker.isValidTestInterface(iface)) { - enforceManageTestNetworksPermission(); - Log.i(TAG, "Ethernet network management API used with test interface " + iface); - } else { - enforceAutomotiveDevice(methodName); - enforceNetworkManagementPermission(); - } - logIfEthernetNotStarted(); - } - private void validateTestCapabilities(@Nullable final NetworkCapabilities nc) { - if (null != nc && nc.hasTransport(TRANSPORT_TEST)) { - return; + // For test capabilities, 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."); } - throw new IllegalArgumentException( - "Updates to test interfaces must have NetworkCapabilities.TRANSPORT_TEST."); } @Override public void updateConfiguration(@NonNull final String iface, @NonNull final EthernetNetworkUpdateRequest request, @Nullable final IEthernetNetworkManagementListener listener) { - validateNetworkManagementState(iface, "updateConfiguration()"); + Objects.requireNonNull(iface); + Objects.requireNonNull(request); + // TODO: rename to throwIfEthernetNotStarted. + logIfEthernetNotStarted(); + if (mTracker.isValidTestInterface(iface)) { + enforceManageTestNetworksPermission(); validateTestCapabilities(request.getNetworkCapabilities()); // TODO: use NetworkCapabilities#restrictCapabilitiesForTestNetwork when available on a // local NetworkCapabilities copy to pass to mTracker.updateConfiguration. + } else { + enforceNetworkManagementPermission(); + if (request.getNetworkCapabilities() != null) { + // only automotive devices are allowed to set the NetworkCapabilities using this API + enforceAutomotiveDevice("updateConfiguration() with non-null capabilities"); + } } // TODO: validate that iface is listed in overlay config_ethernet_interfaces @@ -265,7 +254,17 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { public void connectNetwork(@NonNull final String iface, @Nullable final IEthernetNetworkManagementListener listener) { Log.i(TAG, "connectNetwork called with: iface=" + iface + ", listener=" + listener); - validateNetworkManagementState(iface, "connectNetwork()"); + Objects.requireNonNull(iface); + logIfEthernetNotStarted(); + + if (mTracker.isValidTestInterface(iface)) { + enforceManageTestNetworksPermission(); + } else { + // only automotive devices are allowed to use this API. + enforceNetworkManagementPermission(); + enforceAutomotiveDevice("connectNetwork()"); + } + mTracker.connectNetwork(iface, listener); } @@ -273,7 +272,17 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { public void disconnectNetwork(@NonNull final String iface, @Nullable final IEthernetNetworkManagementListener listener) { Log.i(TAG, "disconnectNetwork called with: iface=" + iface + ", listener=" + listener); - validateNetworkManagementState(iface, "disconnectNetwork()"); + Objects.requireNonNull(iface); + logIfEthernetNotStarted(); + + if (mTracker.isValidTestInterface(iface)) { + enforceManageTestNetworksPermission(); + } else { + // only automotive devices are allowed to use this API. + enforceNetworkManagementPermission(); + enforceAutomotiveDevice("disconnectNetwork()"); + } + mTracker.disconnectNetwork(iface, listener); } } diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java index e814c84f5b..175a97d070 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.verify; @@ -55,6 +56,10 @@ public class EthernetServiceImplTest { .setIpConfiguration(new IpConfiguration()) .setNetworkCapabilities(new NetworkCapabilities.Builder().build()) .build(); + private static final EthernetNetworkUpdateRequest UPDATE_REQUEST_WITHOUT_CAPABILITIES = + new EthernetNetworkUpdateRequest.Builder() + .setIpConfiguration(new IpConfiguration()) + .build(); private static final IEthernetNetworkManagementListener NULL_LISTENER = null; private EthernetServiceImpl mEthernetServiceImpl; @Mock private Context mContext; @@ -136,13 +141,23 @@ public class EthernetServiceImplTest { } @Test - public void testUpdateConfigurationRejectsWithoutAutomotiveFeature() { + public void testUpdateConfigurationWithCapabilitiesRejectsWithoutAutomotiveFeature() { toggleAutomotiveFeature(false); assertThrows(UnsupportedOperationException.class, () -> { mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER); }); } + @Test + public void testUpdateConfigurationWithCapabilitiesWithAutomotiveFeature() { + toggleAutomotiveFeature(false); + mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST_WITHOUT_CAPABILITIES, + NULL_LISTENER); + verify(mEthernetTracker).updateConfiguration(eq(TEST_IFACE), + eq(UPDATE_REQUEST_WITHOUT_CAPABILITIES.getIpConfiguration()), + eq(UPDATE_REQUEST_WITHOUT_CAPABILITIES.getNetworkCapabilities()), isNull()); + } + @Test public void testConnectNetworkRejectsWithoutAutomotiveFeature() { toggleAutomotiveFeature(false); @@ -248,15 +263,16 @@ public class EthernetServiceImplTest { } @Test - public void testUpdateConfigurationRejectsTestRequestWithNullCapabilities() { + public void testUpdateConfigurationAcceptsTestRequestWithNullCapabilities() { enableTestInterface(); final EthernetNetworkUpdateRequest request = new EthernetNetworkUpdateRequest .Builder() .setIpConfiguration(new IpConfiguration()).build(); - assertThrows(IllegalArgumentException.class, () -> { - mEthernetServiceImpl.updateConfiguration(TEST_IFACE, request, NULL_LISTENER); - }); + mEthernetServiceImpl.updateConfiguration(TEST_IFACE, request, NULL_LISTENER); + verify(mEthernetTracker).updateConfiguration(eq(TEST_IFACE), + eq(request.getIpConfiguration()), + eq(request.getNetworkCapabilities()), isNull()); } @Test From 6a77e5d15bc20b776fb906fc3997ea50faff0d9f Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 9 Mar 2022 13:58:28 +0100 Subject: [PATCH 142/152] Rename logIfEthernetNotStarted to throwIfEthernetNotStarted The functions does not log but throws an exception instead. Changing the name to reflect that. Test: TH Change-Id: I6207aababaccc9bc553f7f731e3b8a1d26eb16a1 --- .../android/server/ethernet/EthernetServiceImpl.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 782ee0fad4..89ac6e4816 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -80,7 +80,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { mStarted.set(true); } - private void logIfEthernetNotStarted() { + private void throwIfEthernetNotStarted() { if (!mStarted.get()) { throw new IllegalStateException("System isn't ready to change ethernet configurations"); } @@ -111,7 +111,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { */ @Override public void setConfiguration(String iface, IpConfiguration config) { - logIfEthernetNotStarted(); + throwIfEthernetNotStarted(); PermissionUtils.enforceNetworkStackPermission(mContext); if (mTracker.isRestrictedInterface(iface)) { @@ -229,8 +229,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Nullable final IEthernetNetworkManagementListener listener) { Objects.requireNonNull(iface); Objects.requireNonNull(request); - // TODO: rename to throwIfEthernetNotStarted. - logIfEthernetNotStarted(); + throwIfEthernetNotStarted(); if (mTracker.isValidTestInterface(iface)) { enforceManageTestNetworksPermission(); @@ -255,7 +254,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Nullable final IEthernetNetworkManagementListener listener) { Log.i(TAG, "connectNetwork called with: iface=" + iface + ", listener=" + listener); Objects.requireNonNull(iface); - logIfEthernetNotStarted(); + throwIfEthernetNotStarted(); if (mTracker.isValidTestInterface(iface)) { enforceManageTestNetworksPermission(); @@ -273,7 +272,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Nullable final IEthernetNetworkManagementListener listener) { Log.i(TAG, "disconnectNetwork called with: iface=" + iface + ", listener=" + listener); Objects.requireNonNull(iface); - logIfEthernetNotStarted(); + throwIfEthernetNotStarted(); if (mTracker.isValidTestInterface(iface)) { enforceManageTestNetworksPermission(); From ac8977acad045d216432f9ec40cc2425dbd90edf Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 9 Mar 2022 21:37:14 +0100 Subject: [PATCH 143/152] Clean up permission validation in EthernetServiceImpl Test: atest EthernetServiceImplTest Change-Id: I0ca54e09dd98cab348fc855e8a0bf70a703fffed --- .../server/ethernet/EthernetServiceImpl.java | 53 +++++++++---------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 89ac6e4816..50b46845be 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -215,14 +215,31 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { "EthernetServiceImpl"); } - private void validateTestCapabilities(@Nullable final NetworkCapabilities nc) { - // For test capabilities, only null or capabilities that include TRANSPORT_TEST are allowed. + 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, @@ -231,19 +248,11 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { Objects.requireNonNull(request); throwIfEthernetNotStarted(); - if (mTracker.isValidTestInterface(iface)) { - enforceManageTestNetworksPermission(); - validateTestCapabilities(request.getNetworkCapabilities()); - // TODO: use NetworkCapabilities#restrictCapabilitiesForTestNetwork when available on a - // local NetworkCapabilities copy to pass to mTracker.updateConfiguration. - } else { - enforceNetworkManagementPermission(); - if (request.getNetworkCapabilities() != null) { - // only automotive devices are allowed to set the NetworkCapabilities using this API - enforceAutomotiveDevice("updateConfiguration() with non-null capabilities"); - } - } // 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); @@ -256,13 +265,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { Objects.requireNonNull(iface); throwIfEthernetNotStarted(); - if (mTracker.isValidTestInterface(iface)) { - enforceManageTestNetworksPermission(); - } else { - // only automotive devices are allowed to use this API. - enforceNetworkManagementPermission(); - enforceAutomotiveDevice("connectNetwork()"); - } + enforceAdminPermission(iface, true, "connectNetwork()"); mTracker.connectNetwork(iface, listener); } @@ -274,13 +277,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { Objects.requireNonNull(iface); throwIfEthernetNotStarted(); - if (mTracker.isValidTestInterface(iface)) { - enforceManageTestNetworksPermission(); - } else { - // only automotive devices are allowed to use this API. - enforceNetworkManagementPermission(); - enforceAutomotiveDevice("disconnectNetwork()"); - } + enforceAdminPermission(iface, true, "connectNetwork()"); mTracker.disconnectNetwork(iface, listener); } From 81f0f74e65fd9a902e9cda0854794d9e3f92b2d0 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Mon, 24 Jan 2022 03:54:55 +0000 Subject: [PATCH 144/152] Build ethernet service into service-connectivity-tiramisu-pre-jarjar. Along with ethernet service is going to be moved into Connectivity module, this CL contains the corresponding changes as below: 1. deprecate the etherent-service lib and create a new filegroup: When the ethernet mainline code migration completes, ethernet-service lib won't be kept any more, instead the ethernet service should be started from ConnectivityServiceInitializer. So deprecate the current ethernet-service lib and cleanup the usages on other places later. Create a new filegroup which includes all ethernet service code, that will be built into service-connectivity-tiramisu-pre-jarjar. 2. Move the implementation of starting ethernet service: ConnectivityServiceInitializer should take responsibility to start ethernet service and EthernetTracker on boot phase. Move this code to ConnectivityServiceInitializer and remove the current onStart and onBootPhase implemenation. 3. Move below ethernet service related config resources: - config_ethernet_tcp_buffers - config_ethernet_interfaces - config_ethernet_iface_regex Move the definition of these resource from frameworks/base/core to p/m/Connectivity/service/ServiceConnectivityResources, and import the ServiceConnectivityResources lib to adapt the ethernet update. 4. Update the EthernetServiceTests dependencies and refactor the code which uses ConnectivityResources instead of internal Resource to make the tests pass. Bug: 210586283 Test: m Test: atest FrameworksNetTests atest EthernetServiceTests Change-Id: I0bbecfb64f720213ee2b02417bc8357ccf4725b6 Merged-In: I0bbecfb64f720213ee2b02417bc8357ccf4725b6 --- .../ethernet/EthernetNetworkFactory.java | 29 ++++++++- .../server/ethernet/EthernetService.java | 38 +++-------- .../server/ethernet/EthernetTracker.java | 64 +++++++++++++++++-- tests/ethernet/Android.bp | 13 +++- .../ethernet/EthernetNetworkFactoryTest.java | 5 +- .../server/ethernet/EthernetTrackerTest.java | 13 ++-- 6 files changed, 116 insertions(+), 46 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 875fc102c0..ce0d77c18e 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -19,7 +19,9 @@ 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.IEthernetNetworkManagementListener; @@ -49,6 +51,7 @@ 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; @@ -69,6 +72,8 @@ public class EthernetNetworkFactory extends NetworkFactory { 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 mTrackingInterfaces = new ConcurrentHashMap<>(); @@ -94,6 +99,27 @@ public class EthernetNetworkFactory extends NetworkFactory { 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 { @@ -518,8 +544,7 @@ public class EthernetNetworkFactory extends NetworkFactory { mIpClientCallback.awaitIpClientStart(); if (sTcpBufferSizes == null) { - sTcpBufferSizes = mContext.getResources().getString( - com.android.internal.R.string.config_ethernet_tcp_buffers); + sTcpBufferSizes = mDeps.getTcpBufferSizesFromResource(mContext); } provisionIpClient(mIpClient, mIpConfig, sTcpBufferSizes); } diff --git a/service-t/src/com/android/server/ethernet/EthernetService.java b/service-t/src/com/android/server/ethernet/EthernetService.java index e6fee9e7bc..d405fd59fb 100644 --- a/service-t/src/com/android/server/ethernet/EthernetService.java +++ b/service-t/src/com/android/server/ethernet/EthernetService.java @@ -21,45 +21,27 @@ import android.net.INetd; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; -import android.util.Log; -import com.android.server.SystemService; import java.util.Objects; -public final class EthernetService extends SystemService { - +// 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 final EthernetServiceImpl mImpl; - public EthernetService(Context context) { - super(context); - final HandlerThread handlerThread = new HandlerThread(THREAD_NAME); - handlerThread.start(); - final Handler handler = handlerThread.getThreadHandler(); - final EthernetNetworkFactory factory = new EthernetNetworkFactory(handler, context); - mImpl = new EthernetServiceImpl( - context, handler, - new EthernetTracker(context, handler, factory, getNetd(context))); - } - - private INetd getNetd(Context context) { + 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; } - @Override - public void onStart() { - Log.i(TAG, "Registering service " + Context.ETHERNET_SERVICE); - publishBinderService(Context.ETHERNET_SERVICE, mImpl); - } - - @Override - public void onBootPhase(int phase) { - if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { - mImpl.start(); - } + 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/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index ea241e1d3f..1b696a4587 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -23,6 +23,8 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility.PACK 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.IEthernetNetworkManagementListener; @@ -80,6 +82,7 @@ public class EthernetTracker { 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, @@ -102,6 +105,7 @@ public class EthernetTracker { private final Handler mHandler; private final EthernetNetworkFactory mFactory; private final EthernetConfigStore mConfigStore; + private final Dependencies mDeps; private final RemoteCallbackList mListeners = new RemoteCallbackList<>(); @@ -123,19 +127,72 @@ public class EthernetTracker { } } + 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 = context.getResources().getStringArray( - com.android.internal.R.array.config_ethernet_interfaces); + final String[] interfaceConfigs = mDeps.getInterfaceConfigFromResource(context); for (String strConfig : interfaceConfigs) { parseEthernetConfig(strConfig); } @@ -735,8 +792,7 @@ public class EthernetTracker { } private void updateIfaceMatchRegexp() { - final String match = mContext.getResources().getString( - com.android.internal.R.string.config_ethernet_iface_regex); + final String match = mDeps.getInterfaceRegexFromResource(mContext); mIfaceMatch = mIncludeTestInterfaces ? "(" + match + "|" + TEST_IFACE_REGEXP + ")" : match; diff --git a/tests/ethernet/Android.bp b/tests/ethernet/Android.bp index 28b13c5243..6cfebdcc83 100644 --- a/tests/ethernet/Android.bp +++ b/tests/ethernet/Android.bp @@ -17,10 +17,17 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } +// TODO: merge the tests into service-connectivity tests after +// ethernet service migration completes. So far just import the +// ethernet service source to fix the dependencies. android_test { name: "EthernetServiceTests", - srcs: ["java/**/*.java"], + srcs: [ + ":ethernet-service-updatable-sources", + ":services.connectivity-ethernet-sources", + "java/**/*.java", + ], certificate: "platform", platform_apis: true, @@ -29,11 +36,13 @@ android_test { "android.test.runner", "android.test.base", "android.test.mock", + "framework-connectivity.impl", + "framework-connectivity-t.impl", + "ServiceConnectivityResources", ], static_libs: [ "androidx.test.rules", - "ethernet-service", "frameworks-base-testutils", "mockito-target-minus-junit4", "net-tests-utils", diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 61425bf171..501324a2fe 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -63,7 +63,7 @@ import android.util.Pair; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.internal.R; +import com.android.connectivity.resources.R; import com.android.net.module.util.InterfaceParams; import com.android.testutils.DevSdkIgnoreRule; @@ -174,8 +174,7 @@ public class EthernetNetworkFactoryTest { } private void setupContext() { - when(mContext.getResources()).thenReturn(mResources); - when(mResources.getString(R.string.config_ethernet_tcp_buffers)).thenReturn(""); + when(mDeps.getTcpBufferSizesFromResource(eq(mContext))).thenReturn(""); } @After diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java index d86cc0f60d..ef70d94391 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -27,7 +27,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -48,7 +47,7 @@ import android.os.RemoteException; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.internal.R; +import com.android.connectivity.resources.R; import com.android.testutils.HandlerUtils; import org.junit.After; @@ -73,7 +72,7 @@ public class EthernetTrackerTest { @Mock private Context mContext; @Mock private EthernetNetworkFactory mFactory; @Mock private INetd mNetd; - @Mock Resources mResources; + @Mock private EthernetTracker.Dependencies mDeps; @Before public void setUp() throws RemoteException { @@ -83,7 +82,8 @@ public class EthernetTrackerTest { when(mNetd.interfaceGetList()).thenReturn(new String[0]); mHandlerThread = new HandlerThread(THREAD_NAME); mHandlerThread.start(); - tracker = new EthernetTracker(mContext, mHandlerThread.getThreadHandler(), mFactory, mNetd); + tracker = new EthernetTracker(mContext, mHandlerThread.getThreadHandler(), mFactory, mNetd, + mDeps); } @After @@ -92,9 +92,8 @@ public class EthernetTrackerTest { } private void initMockResources() { - doReturn("").when(mResources).getString(R.string.config_ethernet_iface_regex); - doReturn(new String[0]).when(mResources).getStringArray(R.array.config_ethernet_interfaces); - doReturn(mResources).when(mContext).getResources(); + when(mDeps.getInterfaceRegexFromResource(eq(mContext))).thenReturn(""); + when(mDeps.getInterfaceConfigFromResource(eq(mContext))).thenReturn(new String[0]); } private void waitForIdle() { From 4617cc9e46379d88846403dbe5816ea3f3dc391e Mon Sep 17 00:00:00 2001 From: James Mattis Date: Tue, 8 Mar 2022 18:05:14 -0800 Subject: [PATCH 145/152] Cleaning EthernetNetworkFactoryTest Unprovisioned Clearing up the EthernetNetworkFactoryTest unprovisioned helped method a bit to accomplish the same thing with fewer lines of code and not rely on the ref count to stop an interface. Bug: 197548738 Test: atest EthernetServiceTests Change-Id: I0fb80b569b6f59ee82fbd528ffad044278ab80c8 --- .../ethernet/EthernetNetworkFactoryTest.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 61425bf171..28fcf3e80e 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -280,19 +280,13 @@ public class EthernetNetworkFactoryTest { // creates an unprovisioned interface private void createUnprovisionedInterface(String iface) throws Exception { - // the only way to create an unprovisioned interface is by calling needNetworkFor - // followed by releaseNetworkFor which will stop the NetworkAgent and IpClient. When - // EthernetNetworkFactory#updateInterfaceLinkState(iface, true) is called, the interface - // is automatically provisioned even if nobody has ever called needNetworkFor + // To create an unprovisioned interface, provision and then "stop" it, i.e. stop its + // NetworkAgent and IpClient. One way this can be done is by provisioning an interface and + // then calling onNetworkUnwanted. createAndVerifyProvisionedInterface(iface); - // Interface is already provisioned, so startProvisioning / register should not be called - // again - mNetFactory.needNetworkFor(createDefaultRequest()); - verify(mIpClient, never()).startProvisioning(any()); - verify(mNetworkAgent, never()).register(); - - mNetFactory.releaseNetworkFor(createDefaultRequest()); + mNetworkAgent.getCallbacks().onNetworkUnwanted(); + mLooper.dispatchAll(); verifyStop(); clearInvocations(mIpClient); From 40b3ff8cfffe82565cb6fff323241b9467df6c0c Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Mon, 14 Mar 2022 17:30:18 +0100 Subject: [PATCH 146/152] Add support for Nullable IpConfiguration Test: atest EthernetServiceTests Change-Id: I6b415ffb2f5825a9dffda1366b60c1e0d26f4e64 --- .../ethernet/EthernetNetworkFactory.java | 11 +++++---- .../server/ethernet/EthernetTracker.java | 11 ++++++--- .../ethernet/EthernetNetworkFactoryTest.java | 24 +++++++++++++++++++ .../ethernet/EthernetServiceImplTest.java | 13 ++++++++++ 4 files changed, 52 insertions(+), 7 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index ce0d77c18e..ef3abbaec0 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -233,7 +233,8 @@ public class EthernetNetworkFactory extends NetworkFactory { * 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. + * @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 @@ -243,7 +244,7 @@ public class EthernetNetworkFactory extends NetworkFactory { */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) protected void updateInterface(@NonNull final String ifaceName, - @NonNull final IpConfiguration ipConfig, + @Nullable final IpConfiguration ipConfig, @Nullable final NetworkCapabilities capabilities, @Nullable final IEthernetNetworkManagementListener listener) { if (!hasInterface(ifaceName)) { @@ -499,7 +500,7 @@ public class EthernetNetworkFactory extends NetworkFactory { mLegacyType = getLegacyType(mCapabilities); } - void updateInterface(@NonNull final IpConfiguration ipConfig, + void updateInterface(@Nullable final IpConfiguration ipConfig, @Nullable final NetworkCapabilities capabilities, @Nullable final IEthernetNetworkManagementListener listener) { if (DBG) { @@ -510,7 +511,9 @@ public class EthernetNetworkFactory extends NetworkFactory { ); } - mIpConfig = ipConfig; + if (null != ipConfig){ + mIpConfig = ipConfig; + } if (null != capabilities) { setCapabilities(capabilities); } diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 1b696a4587..074c81bcb0 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -289,15 +289,20 @@ public class EthernetTracker { @VisibleForTesting(visibility = PACKAGE) protected void updateConfiguration(@NonNull final String iface, - @NonNull final IpConfiguration ipConfig, + @Nullable final IpConfiguration ipConfig, @Nullable final NetworkCapabilities capabilities, @Nullable final IEthernetNetworkManagementListener listener) { if (DBG) { Log.i(TAG, "updateConfiguration, iface: " + iface + ", capabilities: " + capabilities + ", ipConfig: " + ipConfig); } - final IpConfiguration localIpConfig = new IpConfiguration(ipConfig); - writeIpConfiguration(iface, localIpConfig); + + final IpConfiguration localIpConfig = ipConfig == null + ? null : new IpConfiguration(ipConfig); + if (ipConfig != null) { + writeIpConfiguration(iface, localIpConfig); + } + if (null != capabilities) { mNetworkCapabilities.put(iface, capabilities); } diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 501324a2fe..726833f8ee 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -776,4 +776,28 @@ public class EthernetNetworkFactoryTest { verifyNoStopOrStart(); assertFailedListener(listener, "can't be updated as it is not available"); } + + @Test + public void testUpdateInterfaceWithNullIpConfiguration() throws Exception { + initEthernetNetworkFactory(); + createAndVerifyProvisionedInterface(TEST_IFACE); + + final IpConfiguration initialIpConfig = createStaticIpConfig(); + mNetFactory.updateInterface(TEST_IFACE, initialIpConfig, null /*capabilities*/, + null /*listener*/); + triggerOnProvisioningSuccess(); + verifyRestart(initialIpConfig); + + // TODO: have verifyXyz functions clear invocations. + clearInvocations(mDeps); + clearInvocations(mIpClient); + clearInvocations(mNetworkAgent); + + + // verify that sending a null ipConfig does not update the current ipConfig. + mNetFactory.updateInterface(TEST_IFACE, null /*ipConfig*/, null /*capabilities*/, + null /*listener*/); + triggerOnProvisioningSuccess(); + verifyRestart(initialIpConfig); + } } diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java index 175a97d070..2131f7fcdb 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java @@ -60,6 +60,10 @@ public class EthernetServiceImplTest { new EthernetNetworkUpdateRequest.Builder() .setIpConfiguration(new IpConfiguration()) .build(); + private static final EthernetNetworkUpdateRequest UPDATE_REQUEST_WITHOUT_IP_CONFIG = + new EthernetNetworkUpdateRequest.Builder() + .setNetworkCapabilities(new NetworkCapabilities.Builder().build()) + .build(); private static final IEthernetNetworkManagementListener NULL_LISTENER = null; private EthernetServiceImpl mEthernetServiceImpl; @Mock private Context mContext; @@ -275,6 +279,15 @@ public class EthernetServiceImplTest { eq(request.getNetworkCapabilities()), isNull()); } + @Test + public void testUpdateConfigurationAcceptsRequestWithNullIpConfiguration() { + mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST_WITHOUT_IP_CONFIG, + NULL_LISTENER); + verify(mEthernetTracker).updateConfiguration(eq(TEST_IFACE), + eq(UPDATE_REQUEST_WITHOUT_IP_CONFIG.getIpConfiguration()), + eq(UPDATE_REQUEST_WITHOUT_IP_CONFIG.getNetworkCapabilities()), isNull()); + } + @Test public void testUpdateConfigurationRejectsInvalidTestRequest() { enableTestInterface(); From b1352749713ba06e55efd16b08ea24cfe39d7a01 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 16 Mar 2022 10:49:18 +0100 Subject: [PATCH 147/152] Change network management listener to outcome receiver Adopts new API according to API review feedback. The outcome receiver can later be removed from most of the ethernet code; in a perfect world, a result can be generated and an exception captured directly from EthernetServiceImpl. This will greatly simplify the current implementation. Bug: 220017952 Test: atest EthernetServiceTests Change-Id: Id8fadfed9fcfd22f04f6d7c3460b5956e571e01f --- .../ethernet/EthernetNetworkFactory.java | 46 ++++++------ .../server/ethernet/EthernetServiceImpl.java | 8 +-- .../server/ethernet/EthernetTracker.java | 10 +-- .../ethernet/EthernetNetworkFactoryTest.java | 72 +++++++++---------- .../ethernet/EthernetServiceImplTest.java | 4 +- .../server/ethernet/EthernetTrackerTest.java | 6 +- 6 files changed, 71 insertions(+), 75 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index ef3abbaec0..4f153553d9 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -24,8 +24,8 @@ import android.net.ConnectivityManager; import android.net.ConnectivityResources; import android.net.EthernetManager; import android.net.EthernetNetworkSpecifier; -import android.net.IEthernetNetworkManagementListener; import android.net.EthernetNetworkManagementException; +import android.net.INetworkInterfaceOutcomeReceiver; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; @@ -239,14 +239,14 @@ public class EthernetNetworkFactory extends NetworkFactory { * {@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 IEthernetNetworkManagementListener} to notify callers of + * @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 IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { if (!hasInterface(ifaceName)) { maybeSendNetworkManagementCallbackForUntracked(ifaceName, listener); return; @@ -295,7 +295,7 @@ public class EthernetNetworkFactory extends NetworkFactory { /** Returns true if state has been modified */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) protected boolean updateInterfaceLinkState(@NonNull final String ifaceName, final boolean up, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { if (!hasInterface(ifaceName)) { maybeSendNetworkManagementCallbackForUntracked(ifaceName, listener); return false; @@ -310,7 +310,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } private void maybeSendNetworkManagementCallbackForUntracked( - String ifaceName, IEthernetNetworkManagementListener listener) { + String ifaceName, INetworkInterfaceOutcomeReceiver listener) { maybeSendNetworkManagementCallback(listener, null, new EthernetNetworkManagementException( ifaceName + " can't be updated as it is not available.")); @@ -353,15 +353,19 @@ public class EthernetNetworkFactory extends NetworkFactory { } private static void maybeSendNetworkManagementCallback( - @Nullable final IEthernetNetworkManagementListener listener, - @Nullable final Network network, + @Nullable final INetworkInterfaceOutcomeReceiver listener, + @Nullable final String iface, @Nullable final EthernetNetworkManagementException e) { if (null == listener) { return; } try { - listener.onComplete(network, e); + 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); } @@ -415,9 +419,9 @@ public class EthernetNetworkFactory extends NetworkFactory { private class EthernetIpClientCallback extends IpClientCallbacks { private final ConditionVariable mIpClientStartCv = new ConditionVariable(false); private final ConditionVariable mIpClientShutdownCv = new ConditionVariable(false); - @Nullable IEthernetNetworkManagementListener mNetworkManagementListener; + @Nullable INetworkInterfaceOutcomeReceiver mNetworkManagementListener; - EthernetIpClientCallback(@Nullable final IEthernetNetworkManagementListener listener) { + EthernetIpClientCallback(@Nullable final INetworkInterfaceOutcomeReceiver listener) { mNetworkManagementListener = listener; } @@ -502,7 +506,7 @@ public class EthernetNetworkFactory extends NetworkFactory { void updateInterface(@Nullable final IpConfiguration ipConfig, @Nullable final NetworkCapabilities capabilities, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { if (DBG) { Log.d(TAG, "updateInterface, iface: " + name + ", ipConfig: " + ipConfig + ", old ipConfig: " + mIpConfig @@ -533,7 +537,7 @@ public class EthernetNetworkFactory extends NetworkFactory { start(null); } - private void start(@Nullable final IEthernetNetworkManagementListener listener) { + private void start(@Nullable final INetworkInterfaceOutcomeReceiver listener) { if (mIpClient != null) { if (DBG) Log.d(TAG, "IpClient already started"); return; @@ -553,7 +557,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } void onIpLayerStarted(@NonNull final LinkProperties linkProperties, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { if(mIpClient == null) { // This call comes from a message posted on the handler thread, but the IpClient has // since been stopped such as may be the case if updateInterfaceLinkState() is @@ -593,10 +597,10 @@ public class EthernetNetworkFactory extends NetworkFactory { }); mNetworkAgent.register(); mNetworkAgent.markConnected(); - realizeNetworkManagementCallback(mNetworkAgent.getNetwork(), null); + realizeNetworkManagementCallback(name, null); } - void onIpLayerStopped(@Nullable final IEthernetNetworkManagementListener listener) { + void onIpLayerStopped(@Nullable final INetworkInterfaceOutcomeReceiver listener) { // This cannot happen due to provisioning timeout, because our timeout is 0. It can // happen due to errors while provisioning or on provisioning loss. if(mIpClient == null) { @@ -622,7 +626,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } // Must be called on the handler thread - private void realizeNetworkManagementCallback(@Nullable final Network network, + private void realizeNetworkManagementCallback(@Nullable final String iface, @Nullable final EthernetNetworkManagementException e) { ensureRunningOnEthernetHandlerThread(); if (null == mIpClientCallback) { @@ -630,7 +634,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } EthernetNetworkFactory.maybeSendNetworkManagementCallback( - mIpClientCallback.mNetworkManagementListener, network, e); + mIpClientCallback.mNetworkManagementListener, iface, e); // Only send a single callback per listener. mIpClientCallback.mNetworkManagementListener = null; } @@ -671,7 +675,7 @@ public class EthernetNetworkFactory extends NetworkFactory { /** Returns true if state has been modified */ boolean updateLinkState(final boolean up, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { if (mLinkUp == up) { EthernetNetworkFactory.maybeSendNetworkManagementCallback(listener, null, new EthernetNetworkManagementException( @@ -681,13 +685,11 @@ public class EthernetNetworkFactory extends NetworkFactory { mLinkUp = up; if (!up) { // was up, goes down - // Save an instance of the current network to use with the callback before stop(). - final Network network = mNetworkAgent != null ? mNetworkAgent.getNetwork() : null; // 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, network, null); + EthernetNetworkFactory.maybeSendNetworkManagementCallback(listener, name, null); } else { // was down, goes up stop(); start(listener); @@ -742,7 +744,7 @@ public class EthernetNetworkFactory extends NetworkFactory { restart(null); } - void restart(@Nullable final IEthernetNetworkManagementListener listener){ + void restart(@Nullable final INetworkInterfaceOutcomeReceiver listener) { if (DBG) Log.d(TAG, "reconnecting Ethernet"); stop(); start(listener); diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 50b46845be..edda321494 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -24,7 +24,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.net.IEthernetManager; import android.net.IEthernetServiceListener; -import android.net.IEthernetNetworkManagementListener; +import android.net.INetworkInterfaceOutcomeReceiver; import android.net.ITetheredInterfaceCallback; import android.net.EthernetNetworkUpdateRequest; import android.net.IpConfiguration; @@ -243,7 +243,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Override public void updateConfiguration(@NonNull final String iface, @NonNull final EthernetNetworkUpdateRequest request, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { Objects.requireNonNull(iface); Objects.requireNonNull(request); throwIfEthernetNotStarted(); @@ -260,7 +260,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Override public void connectNetwork(@NonNull final String iface, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { Log.i(TAG, "connectNetwork called with: iface=" + iface + ", listener=" + listener); Objects.requireNonNull(iface); throwIfEthernetNotStarted(); @@ -272,7 +272,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Override public void disconnectNetwork(@NonNull final String iface, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { Log.i(TAG, "disconnectNetwork called with: iface=" + iface + ", listener=" + listener); Objects.requireNonNull(iface); throwIfEthernetNotStarted(); diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 074c81bcb0..0a0e327f45 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -27,7 +27,7 @@ import android.content.res.Resources; import android.net.ConnectivityResources; import android.net.EthernetManager; import android.net.IEthernetServiceListener; -import android.net.IEthernetNetworkManagementListener; +import android.net.INetworkInterfaceOutcomeReceiver; import android.net.INetd; import android.net.ITetheredInterfaceCallback; import android.net.InterfaceConfigurationParcel; @@ -291,7 +291,7 @@ public class EthernetTracker { protected void updateConfiguration(@NonNull final String iface, @Nullable final IpConfiguration ipConfig, @Nullable final NetworkCapabilities capabilities, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { if (DBG) { Log.i(TAG, "updateConfiguration, iface: " + iface + ", capabilities: " + capabilities + ", ipConfig: " + ipConfig); @@ -314,13 +314,13 @@ public class EthernetTracker { @VisibleForTesting(visibility = PACKAGE) protected void connectNetwork(@NonNull final String iface, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { mHandler.post(() -> updateInterfaceState(iface, true, listener)); } @VisibleForTesting(visibility = PACKAGE) protected void disconnectNetwork(@NonNull final String iface, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { mHandler.post(() -> updateInterfaceState(iface, false, listener)); } @@ -505,7 +505,7 @@ public class EthernetTracker { } private void updateInterfaceState(@NonNull final String iface, final boolean up, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { final int mode = getInterfaceMode(iface); final boolean factoryLinkStateUpdated = (mode == INTERFACE_MODE_CLIENT) && mFactory.updateInterfaceLinkState(iface, up, listener); diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 726833f8ee..5d23aaf0da 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -41,8 +41,8 @@ import android.content.Context; import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.EthernetNetworkSpecifier; -import android.net.IEthernetNetworkManagementListener; import android.net.EthernetNetworkManagementException; +import android.net.INetworkInterfaceOutcomeReceiver; import android.net.IpConfiguration; import android.net.LinkAddress; import android.net.LinkProperties; @@ -85,7 +85,7 @@ import java.util.concurrent.TimeUnit; public class EthernetNetworkFactoryTest { private static final int TIMEOUT_MS = 2_000; private static final String TEST_IFACE = "test123"; - private static final IEthernetNetworkManagementListener NULL_LISTENER = null; + private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null; private static final String IP_ADDR = "192.0.2.2/25"; private static final LinkAddress LINK_ADDR = new LinkAddress(IP_ADDR); private static final String HW_ADDR = "01:02:03:04:05:06"; @@ -322,7 +322,7 @@ public class EthernetNetworkFactoryTest { assertTrue(ret); verify(mIpClient).shutdown(); - assertSuccessfulListener(listener, null); + assertEquals(listener.expectOnResult(), TEST_IFACE); } @Test @@ -336,7 +336,7 @@ public class EthernetNetworkFactoryTest { assertTrue(ret); verifyStop(); - assertSuccessfulListener(listener, mMockNetwork); + assertEquals(listener.expectOnResult(), TEST_IFACE); } @Test @@ -353,7 +353,7 @@ public class EthernetNetworkFactoryTest { verify(mDeps, never()).makeIpClient(any(), any(), any()); verify(mDeps, never()) .makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any()); - assertSuccessfulListener(listener, null); + assertEquals(listener.expectOnResult(), TEST_IFACE); } @Test @@ -367,7 +367,7 @@ public class EthernetNetworkFactoryTest { assertFalse(ret); verifyNoStopOrStart(); - assertFailedListener(listener, "can't be updated as it is not available"); + listener.expectOnErrorWithMessage("can't be updated as it is not available"); } @Test @@ -381,7 +381,7 @@ public class EthernetNetworkFactoryTest { assertFalse(ret); verifyNoStopOrStart(); - assertFailedListener(listener, "No changes"); + listener.expectOnErrorWithMessage("No changes"); } @Test @@ -638,18 +638,31 @@ public class EthernetNetworkFactoryTest { } private static final class TestNetworkManagementListener - implements IEthernetNetworkManagementListener { - private final CompletableFuture> mDone - = new CompletableFuture<>(); + implements INetworkInterfaceOutcomeReceiver { + private final CompletableFuture mResult = new CompletableFuture<>(); + private final CompletableFuture mError = + new CompletableFuture<>(); @Override - public void onComplete(final Network network, - final EthernetNetworkManagementException exception) { - mDone.complete(new Pair<>(network, exception)); + public void onResult(@NonNull String iface) { + mResult.complete(iface); } - Pair expectOnComplete() throws Exception { - return mDone.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + @Override + public void onError(@NonNull EthernetNetworkManagementException exception) { + mError.complete(exception); + } + + String expectOnResult() throws Exception { + return mResult.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + EthernetNetworkManagementException expectOnError() throws Exception { + return mError.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + void expectOnErrorWithMessage(String msg) throws Exception { + assertTrue(expectOnError().getMessage().contains(msg)); } @Override @@ -669,7 +682,7 @@ public class EthernetNetworkFactoryTest { mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener); triggerOnProvisioningSuccess(); - assertSuccessfulListener(listener, mMockNetwork); + assertEquals(listener.expectOnResult(), TEST_IFACE); } @DevSdkIgnoreRule.IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available @@ -709,26 +722,7 @@ public class EthernetNetworkFactoryTest { triggerOnProvisioningSuccess(); }); - assertSuccessfulListener(successfulListener, mMockNetwork); - } - - private void assertSuccessfulListener( - @NonNull final TestNetworkManagementListener successfulListener, - @NonNull final Network expectedNetwork) throws Exception { - final Pair successfulResult = - successfulListener.expectOnComplete(); - assertEquals(expectedNetwork, successfulResult.first); - assertNull(successfulResult.second); - } - - private void assertFailedListener(@NonNull final TestNetworkManagementListener failedListener, - @NonNull final String errMsg) - throws Exception { - final Pair failedResult = - failedListener.expectOnComplete(); - assertNull(failedResult.first); - assertNotNull(failedResult.second); - assertTrue(failedResult.second.getMessage().contains(errMsg)); + assertEquals(successfulListener.expectOnResult(), TEST_IFACE); } private void verifyNetworkManagementCallIsAbortedWhenInterrupted( @@ -743,7 +737,7 @@ public class EthernetNetworkFactoryTest { mNetFactory.updateInterface(iface, ipConfiguration, capabilities, failedListener); interruptingRunnable.run(); - assertFailedListener(failedListener, "aborted"); + failedListener.expectOnErrorWithMessage("aborted"); } @Test @@ -757,7 +751,7 @@ public class EthernetNetworkFactoryTest { mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener); triggerOnProvisioningSuccess(); - listener.expectOnComplete(); + assertEquals(listener.expectOnResult(), TEST_IFACE); verify(mDeps).makeEthernetNetworkAgent(any(), any(), eq(capabilities), any(), any(), any(), any()); verifyRestart(ipConfiguration); @@ -774,7 +768,7 @@ public class EthernetNetworkFactoryTest { mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener); verifyNoStopOrStart(); - assertFailedListener(listener, "can't be updated as it is not available"); + listener.expectOnErrorWithMessage("can't be updated as it is not available"); } @Test diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java index 2131f7fcdb..e67c4c8b95 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java @@ -32,7 +32,7 @@ import android.Manifest; import android.annotation.NonNull; import android.content.Context; import android.content.pm.PackageManager; -import android.net.IEthernetNetworkManagementListener; +import android.net.INetworkInterfaceOutcomeReceiver; import android.net.EthernetNetworkUpdateRequest; import android.net.IpConfiguration; import android.net.NetworkCapabilities; @@ -64,7 +64,7 @@ public class EthernetServiceImplTest { new EthernetNetworkUpdateRequest.Builder() .setNetworkCapabilities(new NetworkCapabilities.Builder().build()) .build(); - private static final IEthernetNetworkManagementListener NULL_LISTENER = null; + private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null; private EthernetServiceImpl mEthernetServiceImpl; @Mock private Context mContext; @Mock private Handler mHandler; diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java index ef70d94391..bab9643d23 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -33,7 +33,7 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; import android.net.InetAddresses; -import android.net.IEthernetNetworkManagementListener; +import android.net.INetworkInterfaceOutcomeReceiver; import android.net.INetd; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; @@ -66,7 +66,7 @@ public class EthernetTrackerTest { private static final String TEST_IFACE = "test123"; private static final int TIMEOUT_MS = 1_000; private static final String THREAD_NAME = "EthernetServiceThread"; - private static final IEthernetNetworkManagementListener NULL_LISTENER = null; + private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null; private EthernetTracker tracker; private HandlerThread mHandlerThread; @Mock private Context mContext; @@ -334,7 +334,7 @@ public class EthernetTrackerTest { new StaticIpConfiguration.Builder().setIpAddress(linkAddr).build(); final IpConfiguration ipConfig = new IpConfiguration.Builder().setStaticIpConfiguration(staticIpConfig).build(); - final IEthernetNetworkManagementListener listener = null; + final INetworkInterfaceOutcomeReceiver listener = null; tracker.updateConfiguration(TEST_IFACE, ipConfig, capabilities, listener); waitForIdle(); From b6f3b8a4e563c9495c5c6e3ae87cab1111ae5ea8 Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Thu, 17 Mar 2022 15:20:53 +0000 Subject: [PATCH 148/152] Revert "Change network management listener to outcome receiver" Revert submission 2028203-ethernet-outcomereceiver Reason for revert: BuildMonitor investigating b/225169800 Reverted Changes: I4c204a848:Change Ethernet API to use OutcomeReceiver I7c46545a4:Change Ethernet API to use OutcomeReceiver Id8fadfed9:Change network management listener to outcome rece... Change-Id: I45ba68452b9dccedf72b68fdea6e31c07b86546d --- .../ethernet/EthernetNetworkFactory.java | 46 ++++++------ .../server/ethernet/EthernetServiceImpl.java | 8 +-- .../server/ethernet/EthernetTracker.java | 10 +-- .../ethernet/EthernetNetworkFactoryTest.java | 72 ++++++++++--------- .../ethernet/EthernetServiceImplTest.java | 4 +- .../server/ethernet/EthernetTrackerTest.java | 6 +- 6 files changed, 75 insertions(+), 71 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 4f153553d9..ef3abbaec0 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -24,8 +24,8 @@ import android.net.ConnectivityManager; import android.net.ConnectivityResources; import android.net.EthernetManager; import android.net.EthernetNetworkSpecifier; +import android.net.IEthernetNetworkManagementListener; import android.net.EthernetNetworkManagementException; -import android.net.INetworkInterfaceOutcomeReceiver; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; @@ -239,14 +239,14 @@ public class EthernetNetworkFactory extends NetworkFactory { * {@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 + * @param listener an optional {@link IEthernetNetworkManagementListener} 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) { + @Nullable final IEthernetNetworkManagementListener listener) { if (!hasInterface(ifaceName)) { maybeSendNetworkManagementCallbackForUntracked(ifaceName, listener); return; @@ -295,7 +295,7 @@ public class EthernetNetworkFactory extends NetworkFactory { /** 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) { + @Nullable final IEthernetNetworkManagementListener listener) { if (!hasInterface(ifaceName)) { maybeSendNetworkManagementCallbackForUntracked(ifaceName, listener); return false; @@ -310,7 +310,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } private void maybeSendNetworkManagementCallbackForUntracked( - String ifaceName, INetworkInterfaceOutcomeReceiver listener) { + String ifaceName, IEthernetNetworkManagementListener listener) { maybeSendNetworkManagementCallback(listener, null, new EthernetNetworkManagementException( ifaceName + " can't be updated as it is not available.")); @@ -353,19 +353,15 @@ public class EthernetNetworkFactory extends NetworkFactory { } private static void maybeSendNetworkManagementCallback( - @Nullable final INetworkInterfaceOutcomeReceiver listener, - @Nullable final String iface, + @Nullable final IEthernetNetworkManagementListener listener, + @Nullable final Network network, @Nullable final EthernetNetworkManagementException e) { if (null == listener) { return; } try { - if (iface != null) { - listener.onResult(iface); - } else { - listener.onError(e); - } + listener.onComplete(network, e); } catch (RemoteException re) { Log.e(TAG, "Can't send onComplete for network management callback", re); } @@ -419,9 +415,9 @@ public class EthernetNetworkFactory extends NetworkFactory { private class EthernetIpClientCallback extends IpClientCallbacks { private final ConditionVariable mIpClientStartCv = new ConditionVariable(false); private final ConditionVariable mIpClientShutdownCv = new ConditionVariable(false); - @Nullable INetworkInterfaceOutcomeReceiver mNetworkManagementListener; + @Nullable IEthernetNetworkManagementListener mNetworkManagementListener; - EthernetIpClientCallback(@Nullable final INetworkInterfaceOutcomeReceiver listener) { + EthernetIpClientCallback(@Nullable final IEthernetNetworkManagementListener listener) { mNetworkManagementListener = listener; } @@ -506,7 +502,7 @@ public class EthernetNetworkFactory extends NetworkFactory { void updateInterface(@Nullable final IpConfiguration ipConfig, @Nullable final NetworkCapabilities capabilities, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { + @Nullable final IEthernetNetworkManagementListener listener) { if (DBG) { Log.d(TAG, "updateInterface, iface: " + name + ", ipConfig: " + ipConfig + ", old ipConfig: " + mIpConfig @@ -537,7 +533,7 @@ public class EthernetNetworkFactory extends NetworkFactory { start(null); } - private void start(@Nullable final INetworkInterfaceOutcomeReceiver listener) { + private void start(@Nullable final IEthernetNetworkManagementListener listener) { if (mIpClient != null) { if (DBG) Log.d(TAG, "IpClient already started"); return; @@ -557,7 +553,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } void onIpLayerStarted(@NonNull final LinkProperties linkProperties, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { + @Nullable final IEthernetNetworkManagementListener listener) { if(mIpClient == null) { // This call comes from a message posted on the handler thread, but the IpClient has // since been stopped such as may be the case if updateInterfaceLinkState() is @@ -597,10 +593,10 @@ public class EthernetNetworkFactory extends NetworkFactory { }); mNetworkAgent.register(); mNetworkAgent.markConnected(); - realizeNetworkManagementCallback(name, null); + realizeNetworkManagementCallback(mNetworkAgent.getNetwork(), null); } - void onIpLayerStopped(@Nullable final INetworkInterfaceOutcomeReceiver listener) { + void onIpLayerStopped(@Nullable final IEthernetNetworkManagementListener listener) { // This cannot happen due to provisioning timeout, because our timeout is 0. It can // happen due to errors while provisioning or on provisioning loss. if(mIpClient == null) { @@ -626,7 +622,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } // Must be called on the handler thread - private void realizeNetworkManagementCallback(@Nullable final String iface, + private void realizeNetworkManagementCallback(@Nullable final Network network, @Nullable final EthernetNetworkManagementException e) { ensureRunningOnEthernetHandlerThread(); if (null == mIpClientCallback) { @@ -634,7 +630,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } EthernetNetworkFactory.maybeSendNetworkManagementCallback( - mIpClientCallback.mNetworkManagementListener, iface, e); + mIpClientCallback.mNetworkManagementListener, network, e); // Only send a single callback per listener. mIpClientCallback.mNetworkManagementListener = null; } @@ -675,7 +671,7 @@ public class EthernetNetworkFactory extends NetworkFactory { /** Returns true if state has been modified */ boolean updateLinkState(final boolean up, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { + @Nullable final IEthernetNetworkManagementListener listener) { if (mLinkUp == up) { EthernetNetworkFactory.maybeSendNetworkManagementCallback(listener, null, new EthernetNetworkManagementException( @@ -685,11 +681,13 @@ public class EthernetNetworkFactory extends NetworkFactory { mLinkUp = up; if (!up) { // was up, goes down + // Save an instance of the current network to use with the callback before stop(). + final Network network = mNetworkAgent != null ? mNetworkAgent.getNetwork() : null; // 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); + EthernetNetworkFactory.maybeSendNetworkManagementCallback(listener, network, null); } else { // was down, goes up stop(); start(listener); @@ -744,7 +742,7 @@ public class EthernetNetworkFactory extends NetworkFactory { restart(null); } - void restart(@Nullable final INetworkInterfaceOutcomeReceiver listener) { + void restart(@Nullable final IEthernetNetworkManagementListener listener){ if (DBG) Log.d(TAG, "reconnecting Ethernet"); stop(); start(listener); diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index edda321494..50b46845be 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -24,7 +24,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.net.IEthernetManager; import android.net.IEthernetServiceListener; -import android.net.INetworkInterfaceOutcomeReceiver; +import android.net.IEthernetNetworkManagementListener; import android.net.ITetheredInterfaceCallback; import android.net.EthernetNetworkUpdateRequest; import android.net.IpConfiguration; @@ -243,7 +243,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Override public void updateConfiguration(@NonNull final String iface, @NonNull final EthernetNetworkUpdateRequest request, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { + @Nullable final IEthernetNetworkManagementListener listener) { Objects.requireNonNull(iface); Objects.requireNonNull(request); throwIfEthernetNotStarted(); @@ -260,7 +260,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Override public void connectNetwork(@NonNull final String iface, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { + @Nullable final IEthernetNetworkManagementListener listener) { Log.i(TAG, "connectNetwork called with: iface=" + iface + ", listener=" + listener); Objects.requireNonNull(iface); throwIfEthernetNotStarted(); @@ -272,7 +272,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Override public void disconnectNetwork(@NonNull final String iface, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { + @Nullable final IEthernetNetworkManagementListener listener) { Log.i(TAG, "disconnectNetwork called with: iface=" + iface + ", listener=" + listener); Objects.requireNonNull(iface); throwIfEthernetNotStarted(); diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 0a0e327f45..074c81bcb0 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -27,7 +27,7 @@ import android.content.res.Resources; import android.net.ConnectivityResources; import android.net.EthernetManager; import android.net.IEthernetServiceListener; -import android.net.INetworkInterfaceOutcomeReceiver; +import android.net.IEthernetNetworkManagementListener; import android.net.INetd; import android.net.ITetheredInterfaceCallback; import android.net.InterfaceConfigurationParcel; @@ -291,7 +291,7 @@ public class EthernetTracker { protected void updateConfiguration(@NonNull final String iface, @Nullable final IpConfiguration ipConfig, @Nullable final NetworkCapabilities capabilities, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { + @Nullable final IEthernetNetworkManagementListener listener) { if (DBG) { Log.i(TAG, "updateConfiguration, iface: " + iface + ", capabilities: " + capabilities + ", ipConfig: " + ipConfig); @@ -314,13 +314,13 @@ public class EthernetTracker { @VisibleForTesting(visibility = PACKAGE) protected void connectNetwork(@NonNull final String iface, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { + @Nullable final IEthernetNetworkManagementListener listener) { mHandler.post(() -> updateInterfaceState(iface, true, listener)); } @VisibleForTesting(visibility = PACKAGE) protected void disconnectNetwork(@NonNull final String iface, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { + @Nullable final IEthernetNetworkManagementListener listener) { mHandler.post(() -> updateInterfaceState(iface, false, listener)); } @@ -505,7 +505,7 @@ public class EthernetTracker { } private void updateInterfaceState(@NonNull final String iface, final boolean up, - @Nullable final INetworkInterfaceOutcomeReceiver listener) { + @Nullable final IEthernetNetworkManagementListener listener) { final int mode = getInterfaceMode(iface); final boolean factoryLinkStateUpdated = (mode == INTERFACE_MODE_CLIENT) && mFactory.updateInterfaceLinkState(iface, up, listener); diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 5d23aaf0da..726833f8ee 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -41,8 +41,8 @@ import android.content.Context; import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.EthernetNetworkSpecifier; +import android.net.IEthernetNetworkManagementListener; import android.net.EthernetNetworkManagementException; -import android.net.INetworkInterfaceOutcomeReceiver; import android.net.IpConfiguration; import android.net.LinkAddress; import android.net.LinkProperties; @@ -85,7 +85,7 @@ import java.util.concurrent.TimeUnit; public class EthernetNetworkFactoryTest { private static final int TIMEOUT_MS = 2_000; private static final String TEST_IFACE = "test123"; - private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null; + private static final IEthernetNetworkManagementListener NULL_LISTENER = null; private static final String IP_ADDR = "192.0.2.2/25"; private static final LinkAddress LINK_ADDR = new LinkAddress(IP_ADDR); private static final String HW_ADDR = "01:02:03:04:05:06"; @@ -322,7 +322,7 @@ public class EthernetNetworkFactoryTest { assertTrue(ret); verify(mIpClient).shutdown(); - assertEquals(listener.expectOnResult(), TEST_IFACE); + assertSuccessfulListener(listener, null); } @Test @@ -336,7 +336,7 @@ public class EthernetNetworkFactoryTest { assertTrue(ret); verifyStop(); - assertEquals(listener.expectOnResult(), TEST_IFACE); + assertSuccessfulListener(listener, mMockNetwork); } @Test @@ -353,7 +353,7 @@ public class EthernetNetworkFactoryTest { verify(mDeps, never()).makeIpClient(any(), any(), any()); verify(mDeps, never()) .makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any()); - assertEquals(listener.expectOnResult(), TEST_IFACE); + assertSuccessfulListener(listener, null); } @Test @@ -367,7 +367,7 @@ public class EthernetNetworkFactoryTest { assertFalse(ret); verifyNoStopOrStart(); - listener.expectOnErrorWithMessage("can't be updated as it is not available"); + assertFailedListener(listener, "can't be updated as it is not available"); } @Test @@ -381,7 +381,7 @@ public class EthernetNetworkFactoryTest { assertFalse(ret); verifyNoStopOrStart(); - listener.expectOnErrorWithMessage("No changes"); + assertFailedListener(listener, "No changes"); } @Test @@ -638,31 +638,18 @@ public class EthernetNetworkFactoryTest { } private static final class TestNetworkManagementListener - implements INetworkInterfaceOutcomeReceiver { - private final CompletableFuture mResult = new CompletableFuture<>(); - private final CompletableFuture mError = - new CompletableFuture<>(); + implements IEthernetNetworkManagementListener { + private final CompletableFuture> mDone + = new CompletableFuture<>(); @Override - public void onResult(@NonNull String iface) { - mResult.complete(iface); + public void onComplete(final Network network, + final EthernetNetworkManagementException exception) { + mDone.complete(new Pair<>(network, exception)); } - @Override - public void onError(@NonNull EthernetNetworkManagementException exception) { - mError.complete(exception); - } - - String expectOnResult() throws Exception { - return mResult.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); - } - - EthernetNetworkManagementException expectOnError() throws Exception { - return mError.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); - } - - void expectOnErrorWithMessage(String msg) throws Exception { - assertTrue(expectOnError().getMessage().contains(msg)); + Pair expectOnComplete() throws Exception { + return mDone.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); } @Override @@ -682,7 +669,7 @@ public class EthernetNetworkFactoryTest { mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener); triggerOnProvisioningSuccess(); - assertEquals(listener.expectOnResult(), TEST_IFACE); + assertSuccessfulListener(listener, mMockNetwork); } @DevSdkIgnoreRule.IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available @@ -722,7 +709,26 @@ public class EthernetNetworkFactoryTest { triggerOnProvisioningSuccess(); }); - assertEquals(successfulListener.expectOnResult(), TEST_IFACE); + assertSuccessfulListener(successfulListener, mMockNetwork); + } + + private void assertSuccessfulListener( + @NonNull final TestNetworkManagementListener successfulListener, + @NonNull final Network expectedNetwork) throws Exception { + final Pair successfulResult = + successfulListener.expectOnComplete(); + assertEquals(expectedNetwork, successfulResult.first); + assertNull(successfulResult.second); + } + + private void assertFailedListener(@NonNull final TestNetworkManagementListener failedListener, + @NonNull final String errMsg) + throws Exception { + final Pair failedResult = + failedListener.expectOnComplete(); + assertNull(failedResult.first); + assertNotNull(failedResult.second); + assertTrue(failedResult.second.getMessage().contains(errMsg)); } private void verifyNetworkManagementCallIsAbortedWhenInterrupted( @@ -737,7 +743,7 @@ public class EthernetNetworkFactoryTest { mNetFactory.updateInterface(iface, ipConfiguration, capabilities, failedListener); interruptingRunnable.run(); - failedListener.expectOnErrorWithMessage("aborted"); + assertFailedListener(failedListener, "aborted"); } @Test @@ -751,7 +757,7 @@ public class EthernetNetworkFactoryTest { mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener); triggerOnProvisioningSuccess(); - assertEquals(listener.expectOnResult(), TEST_IFACE); + listener.expectOnComplete(); verify(mDeps).makeEthernetNetworkAgent(any(), any(), eq(capabilities), any(), any(), any(), any()); verifyRestart(ipConfiguration); @@ -768,7 +774,7 @@ public class EthernetNetworkFactoryTest { mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener); verifyNoStopOrStart(); - listener.expectOnErrorWithMessage("can't be updated as it is not available"); + assertFailedListener(listener, "can't be updated as it is not available"); } @Test diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java index e67c4c8b95..2131f7fcdb 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java @@ -32,7 +32,7 @@ import android.Manifest; import android.annotation.NonNull; import android.content.Context; import android.content.pm.PackageManager; -import android.net.INetworkInterfaceOutcomeReceiver; +import android.net.IEthernetNetworkManagementListener; import android.net.EthernetNetworkUpdateRequest; import android.net.IpConfiguration; import android.net.NetworkCapabilities; @@ -64,7 +64,7 @@ public class EthernetServiceImplTest { new EthernetNetworkUpdateRequest.Builder() .setNetworkCapabilities(new NetworkCapabilities.Builder().build()) .build(); - private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null; + private static final IEthernetNetworkManagementListener NULL_LISTENER = null; private EthernetServiceImpl mEthernetServiceImpl; @Mock private Context mContext; @Mock private Handler mHandler; diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java index bab9643d23..ef70d94391 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -33,7 +33,7 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; import android.net.InetAddresses; -import android.net.INetworkInterfaceOutcomeReceiver; +import android.net.IEthernetNetworkManagementListener; import android.net.INetd; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; @@ -66,7 +66,7 @@ public class EthernetTrackerTest { private static final String TEST_IFACE = "test123"; private static final int TIMEOUT_MS = 1_000; private static final String THREAD_NAME = "EthernetServiceThread"; - private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null; + private static final IEthernetNetworkManagementListener NULL_LISTENER = null; private EthernetTracker tracker; private HandlerThread mHandlerThread; @Mock private Context mContext; @@ -334,7 +334,7 @@ public class EthernetTrackerTest { new StaticIpConfiguration.Builder().setIpAddress(linkAddr).build(); final IpConfiguration ipConfig = new IpConfiguration.Builder().setStaticIpConfiguration(staticIpConfig).build(); - final INetworkInterfaceOutcomeReceiver listener = null; + final IEthernetNetworkManagementListener listener = null; tracker.updateConfiguration(TEST_IFACE, ipConfig, capabilities, listener); waitForIdle(); From 0de5fb2323fd78f5514abe1851db6459788f2e4c Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Thu, 17 Mar 2022 19:19:21 +0000 Subject: [PATCH 149/152] Revert "Revert "Change network management listener to outcome re..." Revert submission 2030087-revert-2028203-ethernet-outcomereceiver-WFKWDORBPY Reason for revert: Reinstate changes Reverted Changes: Ibd1d70ac3:Revert "Change Ethernet API to use OutcomeReceiver... I45af594f7:Revert "Change Ethernet API to use OutcomeReceiver... I45ba68452:Revert "Change network management listener to outc... Merged-In: Id8fadfed9fcfd22f04f6d7c3460b5956e571e01f Change-Id: If3854c1c3a39aa6de84807c6bde267cf88f3d277 --- .../ethernet/EthernetNetworkFactory.java | 46 ++++++------ .../server/ethernet/EthernetServiceImpl.java | 8 +-- .../server/ethernet/EthernetTracker.java | 10 +-- .../ethernet/EthernetNetworkFactoryTest.java | 72 +++++++++---------- .../ethernet/EthernetServiceImplTest.java | 4 +- .../server/ethernet/EthernetTrackerTest.java | 6 +- 6 files changed, 71 insertions(+), 75 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index ef3abbaec0..4f153553d9 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -24,8 +24,8 @@ import android.net.ConnectivityManager; import android.net.ConnectivityResources; import android.net.EthernetManager; import android.net.EthernetNetworkSpecifier; -import android.net.IEthernetNetworkManagementListener; import android.net.EthernetNetworkManagementException; +import android.net.INetworkInterfaceOutcomeReceiver; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; @@ -239,14 +239,14 @@ public class EthernetNetworkFactory extends NetworkFactory { * {@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 IEthernetNetworkManagementListener} to notify callers of + * @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 IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { if (!hasInterface(ifaceName)) { maybeSendNetworkManagementCallbackForUntracked(ifaceName, listener); return; @@ -295,7 +295,7 @@ public class EthernetNetworkFactory extends NetworkFactory { /** Returns true if state has been modified */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) protected boolean updateInterfaceLinkState(@NonNull final String ifaceName, final boolean up, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { if (!hasInterface(ifaceName)) { maybeSendNetworkManagementCallbackForUntracked(ifaceName, listener); return false; @@ -310,7 +310,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } private void maybeSendNetworkManagementCallbackForUntracked( - String ifaceName, IEthernetNetworkManagementListener listener) { + String ifaceName, INetworkInterfaceOutcomeReceiver listener) { maybeSendNetworkManagementCallback(listener, null, new EthernetNetworkManagementException( ifaceName + " can't be updated as it is not available.")); @@ -353,15 +353,19 @@ public class EthernetNetworkFactory extends NetworkFactory { } private static void maybeSendNetworkManagementCallback( - @Nullable final IEthernetNetworkManagementListener listener, - @Nullable final Network network, + @Nullable final INetworkInterfaceOutcomeReceiver listener, + @Nullable final String iface, @Nullable final EthernetNetworkManagementException e) { if (null == listener) { return; } try { - listener.onComplete(network, e); + 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); } @@ -415,9 +419,9 @@ public class EthernetNetworkFactory extends NetworkFactory { private class EthernetIpClientCallback extends IpClientCallbacks { private final ConditionVariable mIpClientStartCv = new ConditionVariable(false); private final ConditionVariable mIpClientShutdownCv = new ConditionVariable(false); - @Nullable IEthernetNetworkManagementListener mNetworkManagementListener; + @Nullable INetworkInterfaceOutcomeReceiver mNetworkManagementListener; - EthernetIpClientCallback(@Nullable final IEthernetNetworkManagementListener listener) { + EthernetIpClientCallback(@Nullable final INetworkInterfaceOutcomeReceiver listener) { mNetworkManagementListener = listener; } @@ -502,7 +506,7 @@ public class EthernetNetworkFactory extends NetworkFactory { void updateInterface(@Nullable final IpConfiguration ipConfig, @Nullable final NetworkCapabilities capabilities, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { if (DBG) { Log.d(TAG, "updateInterface, iface: " + name + ", ipConfig: " + ipConfig + ", old ipConfig: " + mIpConfig @@ -533,7 +537,7 @@ public class EthernetNetworkFactory extends NetworkFactory { start(null); } - private void start(@Nullable final IEthernetNetworkManagementListener listener) { + private void start(@Nullable final INetworkInterfaceOutcomeReceiver listener) { if (mIpClient != null) { if (DBG) Log.d(TAG, "IpClient already started"); return; @@ -553,7 +557,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } void onIpLayerStarted(@NonNull final LinkProperties linkProperties, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { if(mIpClient == null) { // This call comes from a message posted on the handler thread, but the IpClient has // since been stopped such as may be the case if updateInterfaceLinkState() is @@ -593,10 +597,10 @@ public class EthernetNetworkFactory extends NetworkFactory { }); mNetworkAgent.register(); mNetworkAgent.markConnected(); - realizeNetworkManagementCallback(mNetworkAgent.getNetwork(), null); + realizeNetworkManagementCallback(name, null); } - void onIpLayerStopped(@Nullable final IEthernetNetworkManagementListener listener) { + void onIpLayerStopped(@Nullable final INetworkInterfaceOutcomeReceiver listener) { // This cannot happen due to provisioning timeout, because our timeout is 0. It can // happen due to errors while provisioning or on provisioning loss. if(mIpClient == null) { @@ -622,7 +626,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } // Must be called on the handler thread - private void realizeNetworkManagementCallback(@Nullable final Network network, + private void realizeNetworkManagementCallback(@Nullable final String iface, @Nullable final EthernetNetworkManagementException e) { ensureRunningOnEthernetHandlerThread(); if (null == mIpClientCallback) { @@ -630,7 +634,7 @@ public class EthernetNetworkFactory extends NetworkFactory { } EthernetNetworkFactory.maybeSendNetworkManagementCallback( - mIpClientCallback.mNetworkManagementListener, network, e); + mIpClientCallback.mNetworkManagementListener, iface, e); // Only send a single callback per listener. mIpClientCallback.mNetworkManagementListener = null; } @@ -671,7 +675,7 @@ public class EthernetNetworkFactory extends NetworkFactory { /** Returns true if state has been modified */ boolean updateLinkState(final boolean up, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { if (mLinkUp == up) { EthernetNetworkFactory.maybeSendNetworkManagementCallback(listener, null, new EthernetNetworkManagementException( @@ -681,13 +685,11 @@ public class EthernetNetworkFactory extends NetworkFactory { mLinkUp = up; if (!up) { // was up, goes down - // Save an instance of the current network to use with the callback before stop(). - final Network network = mNetworkAgent != null ? mNetworkAgent.getNetwork() : null; // 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, network, null); + EthernetNetworkFactory.maybeSendNetworkManagementCallback(listener, name, null); } else { // was down, goes up stop(); start(listener); @@ -742,7 +744,7 @@ public class EthernetNetworkFactory extends NetworkFactory { restart(null); } - void restart(@Nullable final IEthernetNetworkManagementListener listener){ + void restart(@Nullable final INetworkInterfaceOutcomeReceiver listener) { if (DBG) Log.d(TAG, "reconnecting Ethernet"); stop(); start(listener); diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index 50b46845be..edda321494 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -24,7 +24,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.net.IEthernetManager; import android.net.IEthernetServiceListener; -import android.net.IEthernetNetworkManagementListener; +import android.net.INetworkInterfaceOutcomeReceiver; import android.net.ITetheredInterfaceCallback; import android.net.EthernetNetworkUpdateRequest; import android.net.IpConfiguration; @@ -243,7 +243,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Override public void updateConfiguration(@NonNull final String iface, @NonNull final EthernetNetworkUpdateRequest request, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { Objects.requireNonNull(iface); Objects.requireNonNull(request); throwIfEthernetNotStarted(); @@ -260,7 +260,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Override public void connectNetwork(@NonNull final String iface, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { Log.i(TAG, "connectNetwork called with: iface=" + iface + ", listener=" + listener); Objects.requireNonNull(iface); throwIfEthernetNotStarted(); @@ -272,7 +272,7 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { @Override public void disconnectNetwork(@NonNull final String iface, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { Log.i(TAG, "disconnectNetwork called with: iface=" + iface + ", listener=" + listener); Objects.requireNonNull(iface); throwIfEthernetNotStarted(); diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 074c81bcb0..0a0e327f45 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -27,7 +27,7 @@ import android.content.res.Resources; import android.net.ConnectivityResources; import android.net.EthernetManager; import android.net.IEthernetServiceListener; -import android.net.IEthernetNetworkManagementListener; +import android.net.INetworkInterfaceOutcomeReceiver; import android.net.INetd; import android.net.ITetheredInterfaceCallback; import android.net.InterfaceConfigurationParcel; @@ -291,7 +291,7 @@ public class EthernetTracker { protected void updateConfiguration(@NonNull final String iface, @Nullable final IpConfiguration ipConfig, @Nullable final NetworkCapabilities capabilities, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { if (DBG) { Log.i(TAG, "updateConfiguration, iface: " + iface + ", capabilities: " + capabilities + ", ipConfig: " + ipConfig); @@ -314,13 +314,13 @@ public class EthernetTracker { @VisibleForTesting(visibility = PACKAGE) protected void connectNetwork(@NonNull final String iface, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { mHandler.post(() -> updateInterfaceState(iface, true, listener)); } @VisibleForTesting(visibility = PACKAGE) protected void disconnectNetwork(@NonNull final String iface, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { mHandler.post(() -> updateInterfaceState(iface, false, listener)); } @@ -505,7 +505,7 @@ public class EthernetTracker { } private void updateInterfaceState(@NonNull final String iface, final boolean up, - @Nullable final IEthernetNetworkManagementListener listener) { + @Nullable final INetworkInterfaceOutcomeReceiver listener) { final int mode = getInterfaceMode(iface); final boolean factoryLinkStateUpdated = (mode == INTERFACE_MODE_CLIENT) && mFactory.updateInterfaceLinkState(iface, up, listener); diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 726833f8ee..5d23aaf0da 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -41,8 +41,8 @@ import android.content.Context; import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.EthernetNetworkSpecifier; -import android.net.IEthernetNetworkManagementListener; import android.net.EthernetNetworkManagementException; +import android.net.INetworkInterfaceOutcomeReceiver; import android.net.IpConfiguration; import android.net.LinkAddress; import android.net.LinkProperties; @@ -85,7 +85,7 @@ import java.util.concurrent.TimeUnit; public class EthernetNetworkFactoryTest { private static final int TIMEOUT_MS = 2_000; private static final String TEST_IFACE = "test123"; - private static final IEthernetNetworkManagementListener NULL_LISTENER = null; + private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null; private static final String IP_ADDR = "192.0.2.2/25"; private static final LinkAddress LINK_ADDR = new LinkAddress(IP_ADDR); private static final String HW_ADDR = "01:02:03:04:05:06"; @@ -322,7 +322,7 @@ public class EthernetNetworkFactoryTest { assertTrue(ret); verify(mIpClient).shutdown(); - assertSuccessfulListener(listener, null); + assertEquals(listener.expectOnResult(), TEST_IFACE); } @Test @@ -336,7 +336,7 @@ public class EthernetNetworkFactoryTest { assertTrue(ret); verifyStop(); - assertSuccessfulListener(listener, mMockNetwork); + assertEquals(listener.expectOnResult(), TEST_IFACE); } @Test @@ -353,7 +353,7 @@ public class EthernetNetworkFactoryTest { verify(mDeps, never()).makeIpClient(any(), any(), any()); verify(mDeps, never()) .makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any()); - assertSuccessfulListener(listener, null); + assertEquals(listener.expectOnResult(), TEST_IFACE); } @Test @@ -367,7 +367,7 @@ public class EthernetNetworkFactoryTest { assertFalse(ret); verifyNoStopOrStart(); - assertFailedListener(listener, "can't be updated as it is not available"); + listener.expectOnErrorWithMessage("can't be updated as it is not available"); } @Test @@ -381,7 +381,7 @@ public class EthernetNetworkFactoryTest { assertFalse(ret); verifyNoStopOrStart(); - assertFailedListener(listener, "No changes"); + listener.expectOnErrorWithMessage("No changes"); } @Test @@ -638,18 +638,31 @@ public class EthernetNetworkFactoryTest { } private static final class TestNetworkManagementListener - implements IEthernetNetworkManagementListener { - private final CompletableFuture> mDone - = new CompletableFuture<>(); + implements INetworkInterfaceOutcomeReceiver { + private final CompletableFuture mResult = new CompletableFuture<>(); + private final CompletableFuture mError = + new CompletableFuture<>(); @Override - public void onComplete(final Network network, - final EthernetNetworkManagementException exception) { - mDone.complete(new Pair<>(network, exception)); + public void onResult(@NonNull String iface) { + mResult.complete(iface); } - Pair expectOnComplete() throws Exception { - return mDone.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + @Override + public void onError(@NonNull EthernetNetworkManagementException exception) { + mError.complete(exception); + } + + String expectOnResult() throws Exception { + return mResult.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + EthernetNetworkManagementException expectOnError() throws Exception { + return mError.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + void expectOnErrorWithMessage(String msg) throws Exception { + assertTrue(expectOnError().getMessage().contains(msg)); } @Override @@ -669,7 +682,7 @@ public class EthernetNetworkFactoryTest { mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener); triggerOnProvisioningSuccess(); - assertSuccessfulListener(listener, mMockNetwork); + assertEquals(listener.expectOnResult(), TEST_IFACE); } @DevSdkIgnoreRule.IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available @@ -709,26 +722,7 @@ public class EthernetNetworkFactoryTest { triggerOnProvisioningSuccess(); }); - assertSuccessfulListener(successfulListener, mMockNetwork); - } - - private void assertSuccessfulListener( - @NonNull final TestNetworkManagementListener successfulListener, - @NonNull final Network expectedNetwork) throws Exception { - final Pair successfulResult = - successfulListener.expectOnComplete(); - assertEquals(expectedNetwork, successfulResult.first); - assertNull(successfulResult.second); - } - - private void assertFailedListener(@NonNull final TestNetworkManagementListener failedListener, - @NonNull final String errMsg) - throws Exception { - final Pair failedResult = - failedListener.expectOnComplete(); - assertNull(failedResult.first); - assertNotNull(failedResult.second); - assertTrue(failedResult.second.getMessage().contains(errMsg)); + assertEquals(successfulListener.expectOnResult(), TEST_IFACE); } private void verifyNetworkManagementCallIsAbortedWhenInterrupted( @@ -743,7 +737,7 @@ public class EthernetNetworkFactoryTest { mNetFactory.updateInterface(iface, ipConfiguration, capabilities, failedListener); interruptingRunnable.run(); - assertFailedListener(failedListener, "aborted"); + failedListener.expectOnErrorWithMessage("aborted"); } @Test @@ -757,7 +751,7 @@ public class EthernetNetworkFactoryTest { mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener); triggerOnProvisioningSuccess(); - listener.expectOnComplete(); + assertEquals(listener.expectOnResult(), TEST_IFACE); verify(mDeps).makeEthernetNetworkAgent(any(), any(), eq(capabilities), any(), any(), any(), any()); verifyRestart(ipConfiguration); @@ -774,7 +768,7 @@ public class EthernetNetworkFactoryTest { mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener); verifyNoStopOrStart(); - assertFailedListener(listener, "can't be updated as it is not available"); + listener.expectOnErrorWithMessage("can't be updated as it is not available"); } @Test diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java index 2131f7fcdb..e67c4c8b95 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java @@ -32,7 +32,7 @@ import android.Manifest; import android.annotation.NonNull; import android.content.Context; import android.content.pm.PackageManager; -import android.net.IEthernetNetworkManagementListener; +import android.net.INetworkInterfaceOutcomeReceiver; import android.net.EthernetNetworkUpdateRequest; import android.net.IpConfiguration; import android.net.NetworkCapabilities; @@ -64,7 +64,7 @@ public class EthernetServiceImplTest { new EthernetNetworkUpdateRequest.Builder() .setNetworkCapabilities(new NetworkCapabilities.Builder().build()) .build(); - private static final IEthernetNetworkManagementListener NULL_LISTENER = null; + private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null; private EthernetServiceImpl mEthernetServiceImpl; @Mock private Context mContext; @Mock private Handler mHandler; diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java index ef70d94391..bab9643d23 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -33,7 +33,7 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; import android.net.InetAddresses; -import android.net.IEthernetNetworkManagementListener; +import android.net.INetworkInterfaceOutcomeReceiver; import android.net.INetd; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; @@ -66,7 +66,7 @@ public class EthernetTrackerTest { private static final String TEST_IFACE = "test123"; private static final int TIMEOUT_MS = 1_000; private static final String THREAD_NAME = "EthernetServiceThread"; - private static final IEthernetNetworkManagementListener NULL_LISTENER = null; + private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null; private EthernetTracker tracker; private HandlerThread mHandlerThread; @Mock private Context mContext; @@ -334,7 +334,7 @@ public class EthernetTrackerTest { new StaticIpConfiguration.Builder().setIpAddress(linkAddr).build(); final IpConfiguration ipConfig = new IpConfiguration.Builder().setStaticIpConfiguration(staticIpConfig).build(); - final IEthernetNetworkManagementListener listener = null; + final INetworkInterfaceOutcomeReceiver listener = null; tracker.updateConfiguration(TEST_IFACE, ipConfig, capabilities, listener); waitForIdle(); From de503c5a44b32161e236ae9ee86aa8bc164b2293 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Tue, 15 Mar 2022 21:42:10 -0700 Subject: [PATCH 150/152] Fixing multithreading issues in Ethernet Factory IP client callbacks could be executed updating the state of an ethernet interface even if they were no longer the callbacks for the currently active interface. This can happen as IP client callbacks were being called from a thread separate from ethernet. Bug: 224890356 Test: atest EthernetServiceTests atest CtsNetTestCasesLatestSdk :android.net.cts.EthernetManagerTest --iterations 30 Change-Id: I238cb75caa01472bccc79db5bafa82bccdaeba52 --- .../ethernet/EthernetNetworkFactory.java | 50 +++++++------- .../ethernet/EthernetNetworkFactoryTest.java | 66 ++++++++----------- 2 files changed, 53 insertions(+), 63 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 4f153553d9..9c3148b14c 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -439,24 +439,44 @@ public class EthernetNetworkFactory extends NetworkFactory { 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) { - mHandler.post(() -> onIpLayerStarted(newLp, mNetworkManagementListener)); + handleIpEvent(() -> onIpLayerStarted(newLp, mNetworkManagementListener)); } @Override public void onProvisioningFailure(LinkProperties newLp) { - mHandler.post(() -> onIpLayerStopped(mNetworkManagementListener)); + // 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) { - mHandler.post(() -> updateLinkProperties(newLp)); + handleIpEvent(() -> updateLinkProperties(newLp)); } @Override public void onReachabilityLost(String logMsg) { - mHandler.post(() -> updateNeighborLostEvent(logMsg)); + handleIpEvent(() -> updateNeighborLostEvent(logMsg)); } @Override @@ -558,14 +578,6 @@ public class EthernetNetworkFactory extends NetworkFactory { void onIpLayerStarted(@NonNull final LinkProperties linkProperties, @Nullable final INetworkInterfaceOutcomeReceiver listener) { - if(mIpClient == null) { - // This call comes from a message posted on the handler thread, but the IpClient has - // since been stopped such as may be the case if updateInterfaceLinkState() is - // queued on the handler thread prior. As network management callbacks are sent in - // stop(), there is no need to send them again here. - if (DBG) Log.d(TAG, "IpClient is not initialized."); - return; - } if (mNetworkAgent != null) { Log.e(TAG, "Already have a NetworkAgent - aborting new request"); stop(); @@ -601,12 +613,6 @@ public class EthernetNetworkFactory extends NetworkFactory { } void onIpLayerStopped(@Nullable final INetworkInterfaceOutcomeReceiver listener) { - // This cannot happen due to provisioning timeout, because our timeout is 0. It can - // happen due to errors while provisioning or on provisioning loss. - if(mIpClient == null) { - if (DBG) Log.d(TAG, "IpClient is not initialized."); - return; - } // 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. @@ -648,10 +654,6 @@ public class EthernetNetworkFactory extends NetworkFactory { } void updateLinkProperties(LinkProperties linkProperties) { - if(mIpClient == null) { - if (DBG) Log.d(TAG, "IpClient is not initialized."); - return; - } mLinkProperties = linkProperties; if (mNetworkAgent != null) { mNetworkAgent.sendLinkPropertiesImpl(linkProperties); @@ -659,10 +661,6 @@ public class EthernetNetworkFactory extends NetworkFactory { } void updateNeighborLostEvent(String logMsg) { - if(mIpClient == null) { - if (DBG) Log.d(TAG, "IpClient is not initialized."); - return; - } 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 diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 2d5bd1d988..4d3e4d36d2 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -21,6 +21,7 @@ import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -543,68 +544,59 @@ public class EthernetNetworkFactoryTest { verifyRestart(createDefaultIpConfig()); } - @Test - public void testIgnoreOnIpLayerStartedCallbackAfterIpClientHasStopped() throws Exception { - initEthernetNetworkFactory(); + private IpClientCallbacks getStaleIpClientCallbacks() throws Exception { createAndVerifyProvisionedInterface(TEST_IFACE); - mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); - mIpClientCallbacks.onProvisioningSuccess(new LinkProperties()); - mLooper.dispatchAll(); + final IpClientCallbacks staleIpClientCallbacks = mIpClientCallbacks; + mNetFactory.removeInterface(TEST_IFACE); verifyStop(); + assertNotSame(mIpClientCallbacks, staleIpClientCallbacks); + return staleIpClientCallbacks; + } + + @Test + public void testIgnoreOnIpLayerStartedCallbackForStaleCallback() throws Exception { + initEthernetNetworkFactory(); + final IpClientCallbacks staleIpClientCallbacks = getStaleIpClientCallbacks(); + + staleIpClientCallbacks.onProvisioningSuccess(new LinkProperties()); + mLooper.dispatchAll(); - // ipClient has been shut down first, we should not retry verify(mIpClient, never()).startProvisioning(any()); verify(mNetworkAgent, never()).register(); } @Test - public void testIgnoreOnIpLayerStoppedCallbackAfterIpClientHasStopped() throws Exception { + public void testIgnoreOnIpLayerStoppedCallbackForStaleCallback() throws Exception { initEthernetNetworkFactory(); - createAndVerifyProvisionedInterface(TEST_IFACE); when(mDeps.getNetworkInterfaceByName(TEST_IFACE)).thenReturn(mInterfaceParams); - mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); - mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); - mLooper.dispatchAll(); - verifyStop(); + final IpClientCallbacks staleIpClientCallbacks = getStaleIpClientCallbacks(); - // ipClient has been shut down first, we should not retry - verify(mIpClient).startProvisioning(any()); + staleIpClientCallbacks.onProvisioningFailure(new LinkProperties()); + mLooper.dispatchAll(); + + verify(mIpClient, never()).startProvisioning(any()); } @Test - public void testIgnoreLinkPropertiesCallbackAfterIpClientHasStopped() throws Exception { + public void testIgnoreLinkPropertiesCallbackForStaleCallback() throws Exception { initEthernetNetworkFactory(); - createAndVerifyProvisionedInterface(TEST_IFACE); - LinkProperties lp = new LinkProperties(); + final IpClientCallbacks staleIpClientCallbacks = getStaleIpClientCallbacks(); + final LinkProperties lp = new LinkProperties(); - // The test requires the two proceeding methods to happen one after the other in ENF and - // verifies onLinkPropertiesChange doesn't complete execution for a downed interface. - // Posting is necessary as updateInterfaceLinkState with false will set mIpClientCallbacks - // to null which will throw an NPE in the test if executed synchronously. - mHandler.post(() -> mNetFactory.updateInterfaceLinkState(TEST_IFACE, false, NULL_LISTENER)); - mIpClientCallbacks.onLinkPropertiesChange(lp); + staleIpClientCallbacks.onLinkPropertiesChange(lp); mLooper.dispatchAll(); - verifyStop(); - // ipClient has been shut down first, we should not update - verify(mNetworkAgent, never()).sendLinkPropertiesImpl(same(lp)); + verify(mNetworkAgent, never()).sendLinkPropertiesImpl(eq(lp)); } @Test - public void testIgnoreNeighborLossCallbackAfterIpClientHasStopped() throws Exception { + public void testIgnoreNeighborLossCallbackForStaleCallback() throws Exception { initEthernetNetworkFactory(); - createAndVerifyProvisionedInterface(TEST_IFACE); + final IpClientCallbacks staleIpClientCallbacks = getStaleIpClientCallbacks(); - // The test requires the two proceeding methods to happen one after the other in ENF and - // verifies onReachabilityLost doesn't complete execution for a downed interface. - // Posting is necessary as updateInterfaceLinkState with false will set mIpClientCallbacks - // to null which will throw an NPE in the test if executed synchronously. - mHandler.post(() -> mNetFactory.updateInterfaceLinkState(TEST_IFACE, false, NULL_LISTENER)); - mIpClientCallbacks.onReachabilityLost("Neighbor Lost"); + staleIpClientCallbacks.onReachabilityLost("Neighbor Lost"); mLooper.dispatchAll(); - verifyStop(); - // ipClient has been shut down first, we should not update verify(mIpClient, never()).startProvisioning(any()); verify(mNetworkAgent, never()).register(); } From c0939b76f0f8231cd1ac524744b2ce4745f172d8 Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 16 Mar 2022 15:59:33 +0800 Subject: [PATCH 151/152] Add global change ethernet state API Provide a new API to enable or disable ethernet. Also have a listener for call to check whether enable state is sucessful. Bug: 171872016 Test: atest EthernetServiceTests Change-Id: Iee4b48511ff668a2a7df90fd9bfe563d7ff23940 Merged-In: Iee4b48511ff668a2a7df90fd9bfe563d7ff23940 --- .../ethernet/EthernetNetworkFactory.java | 9 ++- .../server/ethernet/EthernetServiceImpl.java | 8 +++ .../server/ethernet/EthernetTracker.java | 53 ++++++++++++++++ .../ethernet/EthernetServiceImplTest.java | 30 ++++++++++ .../server/ethernet/EthernetTrackerTest.java | 60 +++++++++++++++++++ 5 files changed, 157 insertions(+), 3 deletions(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index 4f153553d9..342d5072a7 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -183,7 +183,8 @@ public class EthernetNetworkFactory extends NetworkFactory { * Returns an array of available interface names. The array is sorted: unrestricted interfaces * goes first, then sorted by name. */ - String[] getAvailableInterfaces(boolean includeRestricted) { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + protected String[] getAvailableInterfaces(boolean includeRestricted) { return mTrackingInterfaces.values() .stream() .filter(iface -> !iface.isRestricted() || includeRestricted) @@ -195,7 +196,8 @@ public class EthernetNetworkFactory extends NetworkFactory { .toArray(String[]::new); } - void addInterface(@NonNull final String ifaceName, @NonNull final String hwAddress, + @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)) { @@ -282,7 +284,8 @@ public class EthernetNetworkFactory extends NetworkFactory { .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET).build(); } - void removeInterface(String interfaceName) { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + protected void removeInterface(String interfaceName) { NetworkInterfaceState iface = mTrackingInterfaces.remove(interfaceName); if (iface != null) { iface.maybeSendNetworkManagementCallbackForAbort(); diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index edda321494..afed01a258 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -281,4 +281,12 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { mTracker.disconnectNetwork(iface, listener); } + + @Override + public void setEthernetEnabled(boolean enabled) { + PermissionUtils.enforceNetworkStackPermissionOr(mContext, + android.Manifest.permission.NETWORK_SETTINGS); + + mTracker.setEthernetEnabled(enabled); + } } diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index 0a0e327f45..c38c900d03 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -16,6 +16,8 @@ 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; @@ -119,6 +121,8 @@ public class EthernetTracker { private boolean mTetheredInterfaceWasAvailable = false; private volatile IpConfiguration mIpConfigForDefaultInterface; + private int mEthernetState = ETHERNET_STATE_ENABLED; + private class TetheredInterfaceRequestList extends RemoteCallbackList { @Override @@ -355,6 +359,8 @@ public class EthernetTracker { for (String iface : getInterfaces(canUseRestrictedNetworks)) { unicastInterfaceStateChange(listener, iface); } + + unicastEthernetStateChange(listener, mEthernetState); }); } @@ -825,6 +831,53 @@ public class EthernetTracker { } } + @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()); diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java index e67c4c8b95..dd1f1edba7 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java @@ -19,12 +19,15 @@ package com.android.server.ethernet; import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static org.junit.Assert.assertThrows; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -339,4 +342,31 @@ public class EthernetServiceImplTest { mEthernetServiceImpl.disconnectNetwork(TEST_IFACE, NULL_LISTENER); verify(mEthernetTracker).disconnectNetwork(eq(TEST_IFACE), eq(NULL_LISTENER)); } + + private void denyPermissions(String... permissions) { + for (String permission: permissions) { + doReturn(PackageManager.PERMISSION_DENIED).when(mContext) + .checkCallingOrSelfPermission(eq(permission)); + } + } + + @Test + public void testSetEthernetEnabled() { + denyPermissions(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); + mEthernetServiceImpl.setEthernetEnabled(true); + verify(mEthernetTracker).setEthernetEnabled(true); + reset(mEthernetTracker); + + denyPermissions(Manifest.permission.NETWORK_STACK); + mEthernetServiceImpl.setEthernetEnabled(false); + verify(mEthernetTracker).setEthernetEnabled(false); + reset(mEthernetTracker); + + denyPermissions(Manifest.permission.NETWORK_SETTINGS); + try { + mEthernetServiceImpl.setEthernetEnabled(true); + fail("Should get SecurityException"); + } catch (SecurityException e) { } + verify(mEthernetTracker, never()).setEthernetEnabled(false); + } } diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java index bab9643d23..b1831c411b 100644 --- a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java +++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java @@ -25,19 +25,26 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; +import android.net.EthernetManager; import android.net.InetAddresses; import android.net.INetworkInterfaceOutcomeReceiver; +import android.net.IEthernetServiceListener; import android.net.INetd; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; +import android.net.InterfaceConfigurationParcel; import android.net.LinkAddress; import android.net.NetworkCapabilities; import android.net.StaticIpConfiguration; @@ -393,4 +400,57 @@ public class EthernetTrackerTest { assertTrue(isValidTestInterface); } + + public static class EthernetStateListener extends IEthernetServiceListener.Stub { + @Override + public void onEthernetStateChanged(int state) { } + + @Override + public void onInterfaceStateChanged(String iface, int state, int role, + IpConfiguration configuration) { } + } + + @Test + public void testListenEthernetStateChange() throws Exception { + final String testIface = "testtap123"; + final String testHwAddr = "11:22:33:44:55:66"; + final InterfaceConfigurationParcel ifaceParcel = new InterfaceConfigurationParcel(); + ifaceParcel.ifName = testIface; + ifaceParcel.hwAddr = testHwAddr; + ifaceParcel.flags = new String[] {INetd.IF_STATE_UP}; + + tracker.setIncludeTestInterfaces(true); + waitForIdle(); + + when(mNetd.interfaceGetList()).thenReturn(new String[] {testIface}); + when(mNetd.interfaceGetCfg(eq(testIface))).thenReturn(ifaceParcel); + doReturn(new String[] {testIface}).when(mFactory).getAvailableInterfaces(anyBoolean()); + doReturn(EthernetManager.STATE_LINK_UP).when(mFactory).getInterfaceState(eq(testIface)); + + final EthernetStateListener listener = spy(new EthernetStateListener()); + tracker.addListener(listener, true /* canUseRestrictedNetworks */); + // Check default state. + waitForIdle(); + verify(listener).onInterfaceStateChanged(eq(testIface), eq(EthernetManager.STATE_LINK_UP), + anyInt(), any()); + verify(listener).onEthernetStateChanged(eq(EthernetManager.ETHERNET_STATE_ENABLED)); + reset(listener); + + doReturn(EthernetManager.STATE_ABSENT).when(mFactory).getInterfaceState(eq(testIface)); + tracker.setEthernetEnabled(false); + waitForIdle(); + verify(mFactory).removeInterface(eq(testIface)); + verify(listener).onEthernetStateChanged(eq(EthernetManager.ETHERNET_STATE_DISABLED)); + verify(listener).onInterfaceStateChanged(eq(testIface), eq(EthernetManager.STATE_ABSENT), + anyInt(), any()); + reset(listener); + + doReturn(EthernetManager.STATE_LINK_UP).when(mFactory).getInterfaceState(eq(testIface)); + tracker.setEthernetEnabled(true); + waitForIdle(); + verify(mFactory).addInterface(eq(testIface), eq(testHwAddr), any(), any()); + verify(listener).onEthernetStateChanged(eq(EthernetManager.ETHERNET_STATE_ENABLED)); + verify(listener).onInterfaceStateChanged(eq(testIface), eq(EthernetManager.STATE_LINK_UP), + anyInt(), any()); + } } From 846bbc9167146782900a72cfea408bb2c751b304 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Thu, 17 Mar 2022 05:57:25 +0000 Subject: [PATCH 152/152] Add getInterfaceList API implementation in Ethernet service. Bug: 171872016 Test: m Merged-In: I8eeb2cd211c6a2ec6bc997c5e18995b585c6118a Change-Id: Ic36d26be7dae5fd3f72abce3cea1ee845813a6e5 --- .../server/ethernet/EthernetServiceImpl.java | 7 +++++++ .../server/ethernet/EthernetTracker.java | 19 ++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java index afed01a258..5e830ad83a 100644 --- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java +++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java @@ -41,6 +41,7 @@ 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; @@ -289,4 +290,10 @@ public class EthernetServiceImpl extends IEthernetManager.Stub { mTracker.setEthernetEnabled(enabled); } + + @Override + public List getInterfaceList() { + PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); + return mTracker.getInterfaceList(); + } } diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java index c38c900d03..c291b3ff66 100644 --- a/service-t/src/com/android/server/ethernet/EthernetTracker.java +++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java @@ -57,6 +57,7 @@ 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; @@ -90,7 +91,7 @@ public class EthernetTracker { * Interface names we track. This is a product-dependent regular expression, plus, * if setIncludeTestInterfaces is true, any test interfaces. */ - private String mIfaceMatch; + private volatile String mIfaceMatch; /** * Track test interfaces if true, don't track otherwise. */ @@ -341,6 +342,22 @@ public class EthernetTracker { return mFactory.getAvailableInterfaces(includeRestricted); } + List getInterfaceList() { + final List interfaceList = new ArrayList(); + 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.