diff options
author | Roshan Pius <rpius@google.com> | 2019-12-09 06:56:15 -0800 |
---|---|---|
committer | Roshan Pius <rpius@google.com> | 2019-12-10 13:25:57 -0800 |
commit | 520ff1c59262a21c36f14a3825e665413e91b2c9 (patch) | |
tree | 7454d9815cdf54652286a0c34429dfd7ceb8b4d9 /service | |
parent | 68d2f9f53e5eb7146a0fb46239109bce1b6c3cac (diff) |
wifi: Create local wrapper for INetworkManagementService
INetworkManagementService is essentially a wrapper over the versioned
netd AIDL interface. Copy over the methods that are used by wifi stack
into a wrapper class called NetdWrapper. Migrate all of the wifi usage
to this new wrapper class.
Also,
a) include the netd AIDL stubs as dependency on wifi service.
b) jarjar InterfaceConfiguration class.
Bug: 145904524
Test: Device boots up and connects to wifi networks.
Test: Ensured @hide usage in INetworkManagementService no longer shows
up.
Test: atest com.android.server.wifi
Change-Id: I9966ab37c02d3cd95c968dfb62a4b8b6294fb3cc
Diffstat (limited to 'service')
10 files changed, 561 insertions, 81 deletions
diff --git a/service/Android.bp b/service/Android.bp index 40e8aec87..ab861e2f0 100644 --- a/service/Android.bp +++ b/service/Android.bp @@ -123,6 +123,7 @@ java_library { // the necessary core platform APIs. "libprotobuf-java-lite", "libnanohttpd", + "netd_aidl_interface-V2-java", "services.net", "wifi_proto_scorecard", "wifi_proto_metrics", diff --git a/service/jarjar-rules-shared.txt b/service/jarjar-rules-shared.txt index f17d0c3ac..7faeb64e8 100644 --- a/service/jarjar-rules-shared.txt +++ b/service/jarjar-rules-shared.txt @@ -1,3 +1,6 @@ +rule android.net.InterfaceConfigurationParcel* @0 +rule android.net.InterfaceConfiguration* com.android.server.x.wifi.net.InterfaceConfiguration@1 + # We don't jar-jar the entire package because, we still use some classes (like # AsyncChannel in com.android.internal.util) from these packages which are not # inside our jar (currently in framework.jar, but will be in wifisdk.jar in the future). diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index 0b0a30517..bde949f4f 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -35,7 +35,6 @@ import android.os.Handler; import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.IBinder; -import android.os.INetworkManagementService; import android.os.Looper; import android.os.Process; import android.os.SystemProperties; @@ -56,6 +55,7 @@ import com.android.server.wifi.p2p.WifiP2pMetrics; import com.android.server.wifi.p2p.WifiP2pMonitor; import com.android.server.wifi.p2p.WifiP2pNative; import com.android.server.wifi.rtt.RttMetrics; +import com.android.server.wifi.util.NetdWrapper; import com.android.server.wifi.util.TelephonyUtil; import com.android.server.wifi.util.WifiPermissionsUtil; import com.android.server.wifi.util.WifiPermissionsWrapper; @@ -141,7 +141,6 @@ public class WifiInjector { private final WifiStateTracker mWifiStateTracker; private final SelfRecovery mSelfRecovery; private final WakeupController mWakeupController; - private final INetworkManagementService mNwManagementService; private final ScanRequestProxy mScanRequestProxy; private final SarManager mSarManager; private final BaseWifiDiagnostics mWifiDiagnostics; @@ -161,6 +160,7 @@ public class WifiInjector { private final KeyStore mKeyStore; private final ConnectionFailureNotificationBuilder mConnectionFailureNotificationBuilder; private final ThroughputPredictor mThroughputPredictor; + private NetdWrapper mNetdWrapper; public WifiInjector(Context context) { if (context == null) { @@ -229,13 +229,10 @@ public class WifiInjector { mWificondControl = new WificondControl(this, (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE), wifiHandler, mClock); - mNwManagementService = INetworkManagementService.Stub.asInterface( - mFrameworkFacade.getService(Context.NETWORKMANAGEMENT_SERVICE)); mWifiNative = new WifiNative( mWifiVendorHal, mSupplicantStaIfaceHal, mHostapdHal, mWificondControl, - mWifiMonitor, mNwManagementService, mPropertyService, mWifiMetrics, - mCarrierNetworkConfig, - wifiHandler, new Random()); + mWifiMonitor, mPropertyService, mWifiMetrics, + mCarrierNetworkConfig, wifiHandler, new Random(), this); mWifiP2pMonitor = new WifiP2pMonitor(this); mSupplicantP2pIfaceHal = new SupplicantP2pIfaceHal(mWifiP2pMonitor); mWifiP2pNative = new WifiP2pNative( @@ -801,4 +798,11 @@ public class WifiInjector { public WifiNetworkScoreCache getWifiNetworkScoreCache() { return mWifiNetworkScoreCache; } + + public NetdWrapper makeNetdWrapper() { + if (mNetdWrapper == null) { + mNetdWrapper = new NetdWrapper(mContext, new Handler(mWifiHandlerThread.getLooper())); + } + return mNetdWrapper; + } } diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java index 3dde35ed9..5005c1c6c 100644 --- a/service/java/com/android/server/wifi/WifiNative.java +++ b/service/java/com/android/server/wifi/WifiNative.java @@ -20,7 +20,6 @@ import static android.net.wifi.WifiManager.WIFI_FEATURE_OWE; import android.annotation.IntDef; import android.annotation.NonNull; -import android.net.InterfaceConfiguration; import android.net.MacAddress; import android.net.TrafficStats; import android.net.apf.ApfCapabilities; @@ -30,8 +29,6 @@ import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiScanner; import android.net.wifi.WifiSsid; import android.os.Handler; -import android.os.INetworkManagementService; -import android.os.RemoteException; import android.os.SystemClock; import android.text.TextUtils; import android.util.ArraySet; @@ -39,11 +36,12 @@ import android.util.Log; import com.android.internal.annotations.Immutable; import com.android.internal.util.HexDump; -import com.android.server.net.BaseNetworkObserver; import com.android.server.wifi.hotspot2.NetworkDetail; import com.android.server.wifi.util.FrameParser; import com.android.server.wifi.util.InformationElementUtil; import com.android.server.wifi.util.NativeUtil; +import com.android.server.wifi.util.NetdWrapper; +import com.android.server.wifi.util.NetdWrapper.NetdEventObserver; import com.android.server.wifi.util.ScanResultUtil; import com.android.server.wifi.wificond.NativeScanResult; import com.android.server.wifi.wificond.RadioChainInfo; @@ -87,31 +85,32 @@ public class WifiNative { private final WifiVendorHal mWifiVendorHal; private final WificondControl mWificondControl; private final WifiMonitor mWifiMonitor; - private final INetworkManagementService mNwManagementService; private final PropertyService mPropertyService; private final WifiMetrics mWifiMetrics; private final CarrierNetworkConfig mCarrierNetworkConfig; private final Handler mHandler; private final Random mRandom; + private final WifiInjector mWifiInjector; + private NetdWrapper mNetdWrapper; private boolean mVerboseLoggingEnabled = false; public WifiNative(WifiVendorHal vendorHal, SupplicantStaIfaceHal staIfaceHal, HostapdHal hostapdHal, WificondControl condControl, WifiMonitor wifiMonitor, - INetworkManagementService nwService, PropertyService propertyService, WifiMetrics wifiMetrics, - CarrierNetworkConfig carrierNetworkConfig, Handler handler, Random random) { + CarrierNetworkConfig carrierNetworkConfig, Handler handler, Random random, + WifiInjector wifiInjector) { mWifiVendorHal = vendorHal; mSupplicantStaIfaceHal = staIfaceHal; mHostapdHal = hostapdHal; mWificondControl = condControl; mWifiMonitor = wifiMonitor; - mNwManagementService = nwService; mPropertyService = propertyService; mWifiMetrics = wifiMetrics; mCarrierNetworkConfig = carrierNetworkConfig; mHandler = handler; mRandom = random; + mWifiInjector = wifiInjector; } /** @@ -504,24 +503,14 @@ public class WifiNative { /** Helper method to register a network observer and return it */ private boolean registerNetworkObserver(NetworkObserverInternal observer) { if (observer == null) return false; - try { - mNwManagementService.registerObserver(observer); - } catch (RemoteException | IllegalStateException e) { - Log.e(TAG, "Unable to register observer", e); - return false; - } + mNetdWrapper.registerObserver(observer); return true; } /** Helper method to unregister a network observer */ private boolean unregisterNetworkObserver(NetworkObserverInternal observer) { if (observer == null) return false; - try { - mNwManagementService.unregisterObserver(observer); - } catch (RemoteException | IllegalStateException e) { - Log.e(TAG, "Unable to unregister observer", e); - return false; - } + mNetdWrapper.unregisterObserver(observer); return true; } @@ -722,7 +711,7 @@ public class WifiNative { /** * Network observer to use for all interface up/down notifications. */ - private class NetworkObserverInternal extends BaseNetworkObserver { + private class NetworkObserverInternal implements NetdEventObserver { /** Identifier allocated for the interface */ private final int mInterfaceId; @@ -732,7 +721,7 @@ public class WifiNative { /** * Note: We should ideally listen to - * {@link BaseNetworkObserver#interfaceStatusChanged(String, boolean)} here. But, that + * {@link NetdEventObserver#interfaceStatusChanged(String, boolean)} here. But, that * callback is not working currently (broken in netd). So, instead listen to link state * change callbacks as triggers to query the real interface state. We should get rid of * this workaround if we get the |interfaceStatusChanged| callback to work in netd. @@ -764,6 +753,11 @@ public class WifiNative { } }); } + + @Override + public void interfaceStatusChanged(String ifaceName, boolean unusedIsLinkUp) { + // unused currently. Look at note above. + } } /** @@ -909,6 +903,7 @@ public class WifiNative { } mWifiVendorHal.registerRadioModeChangeHandler( new VendorHalRadioModeChangeHandlerInternal()); + mNetdWrapper = mWifiInjector.makeNetdWrapper(); return true; } } @@ -968,17 +963,17 @@ public class WifiNative { // IP addresses configured, and this affects // connectivity when supplicant starts up. // Ensure we have no IP addresses before a supplicant start. - mNwManagementService.clearInterfaceAddresses(ifaceName); + mNetdWrapper.clearInterfaceAddresses(ifaceName); // Set privacy extensions - mNwManagementService.setInterfaceIpv6PrivacyExtensions(ifaceName, true); + mNetdWrapper.setInterfaceIpv6PrivacyExtensions(ifaceName, true); // IPv6 is enabled only as long as access point is connected since: // - IPv6 addresses and routes stick around after disconnection // - kernel is unaware when connected and fails to start IPv6 negotiation // - kernel can start autoconfiguration when 802.1x is not complete - mNwManagementService.disableIpv6(ifaceName); - } catch (RemoteException | IllegalStateException e) { + mNetdWrapper.disableIpv6(ifaceName); + } catch (IllegalStateException e) { Log.e(TAG, "Unable to change interface settings", e); } } @@ -1248,16 +1243,12 @@ public class WifiNative { Log.e(TAG, "Trying to get iface state on invalid iface=" + ifaceName); return false; } - InterfaceConfiguration config = null; try { - config = mNwManagementService.getInterfaceConfig(ifaceName); - } catch (RemoteException | IllegalStateException e) { + return mNetdWrapper.isInterfaceUp(ifaceName); + } catch (IllegalStateException e) { Log.e(TAG, "Unable to get interface config", e); - } - if (config == null) { return false; } - return config.isUp(); } } diff --git a/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java b/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java index 0bb0131f5..5e07205ab 100644 --- a/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java +++ b/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java @@ -44,10 +44,7 @@ import android.net.wifi.aware.WifiAwareUtils; import android.net.wifi.util.HexEncoding; import android.os.Build; import android.os.Handler; -import android.os.IBinder; -import android.os.INetworkManagementService; import android.os.Looper; -import android.os.ServiceManager; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; @@ -55,6 +52,7 @@ import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import com.android.server.wifi.Clock; +import com.android.server.wifi.util.NetdWrapper; import com.android.server.wifi.util.WifiPermissionsUtil; import com.android.server.wifi.util.WifiPermissionsWrapper; @@ -117,7 +115,7 @@ public class WifiAwareDataPathStateManager { private Looper mLooper; private Handler mHandler; private WifiAwareNetworkFactory mNetworkFactory; - public INetworkManagementService mNwService; + public NetdWrapper mNetdWrapper; // internal debug flag to override API check /* package */ boolean mAllowNdpResponderFromAnyOverride = false; @@ -132,13 +130,15 @@ public class WifiAwareDataPathStateManager { * connectivity service. */ public void start(Context context, Looper looper, WifiAwareMetrics awareMetrics, - WifiPermissionsUtil wifiPermissionsUtil, WifiPermissionsWrapper permissionsWrapper) { + WifiPermissionsUtil wifiPermissionsUtil, WifiPermissionsWrapper permissionsWrapper, + NetdWrapper netdWrapper) { if (VDBG) Log.v(TAG, "start"); mContext = context; mAwareMetrics = awareMetrics; mWifiPermissionsUtil = wifiPermissionsUtil; mPermissionsWrapper = permissionsWrapper; + mNetdWrapper = netdWrapper; mLooper = looper; mHandler = new Handler(mLooper); @@ -159,9 +159,6 @@ public class WifiAwareDataPathStateManager { mNetworkFactory = new WifiAwareNetworkFactory(looper, context, sNetworkCapabilitiesFilter); mNetworkFactory.setScoreFilter(NETWORK_FACTORY_SCORE_AVAIL); mNetworkFactory.register(); - - IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); - mNwService = INetworkManagementService.Stub.asInterface(b); } private Map.Entry<WifiAwareNetworkSpecifier, AwareNetworkRequestInformation> @@ -568,8 +565,8 @@ public class WifiAwareDataPathStateManager { boolean interfaceUsedByAnotherNdp = isInterfaceUpAndUsedByAnotherNdp(nnri); if (!interfaceUsedByAnotherNdp) { try { - mNwService.setInterfaceUp(nnri.interfaceName); - mNwService.enableIpv6(nnri.interfaceName); + mNetdWrapper.setInterfaceUp(nnri.interfaceName); + mNetdWrapper.enableIpv6(nnri.interfaceName); } catch (Exception e) { // NwService throws runtime exceptions for errors Log.e(TAG, "onDataPathConfirm: ACCEPT nnri=" + nnri + ": can't configure network - " @@ -1070,7 +1067,7 @@ public class WifiAwareDataPathStateManager { } } else { try { - mNwService.setInterfaceDown(nnri.interfaceName); + mNetdWrapper.setInterfaceDown(nnri.interfaceName); } catch (Exception e) { // NwService throws runtime exceptions for errors Log.e(TAG, "tearDownInterfaceIfPossible: nnri=" + nnri + ": can't bring interface down - " + e); diff --git a/service/java/com/android/server/wifi/aware/WifiAwareService.java b/service/java/com/android/server/wifi/aware/WifiAwareService.java index f1aa0e4d4..94d8bc77d 100644 --- a/service/java/com/android/server/wifi/aware/WifiAwareService.java +++ b/service/java/com/android/server/wifi/aware/WifiAwareService.java @@ -72,7 +72,8 @@ public final class WifiAwareService extends SystemService { wifiInjector.getWifiMetrics().getWifiAwareMetrics(), wifiInjector.getWifiPermissionsUtil(), wifiInjector.getWifiPermissionsWrapper(), wifiInjector.getFrameworkFacade(), - wifiAwareNativeManager, wifiAwareNativeApi, wifiAwareNativeCallback); + wifiAwareNativeManager, wifiAwareNativeApi, wifiAwareNativeCallback, + wifiInjector.makeNetdWrapper()); } else if (phase == SystemService.PHASE_BOOT_COMPLETED) { mImpl.startLate(); } diff --git a/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java b/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java index 623846fae..cd697ceac 100644 --- a/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java +++ b/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java @@ -46,6 +46,7 @@ import android.util.SparseIntArray; import com.android.server.wifi.Clock; import com.android.server.wifi.FrameworkFacade; import com.android.server.wifi.WifiInjector; +import com.android.server.wifi.util.NetdWrapper; import com.android.server.wifi.util.WifiPermissionsUtil; import com.android.server.wifi.util.WifiPermissionsWrapper; @@ -99,7 +100,7 @@ public class WifiAwareServiceImpl extends IWifiAwareManager.Stub { WifiPermissionsUtil wifiPermissionsUtil, WifiPermissionsWrapper permissionsWrapper, FrameworkFacade frameworkFacade, WifiAwareNativeManager wifiAwareNativeManager, WifiAwareNativeApi wifiAwareNativeApi, - WifiAwareNativeCallback wifiAwareNativeCallback) { + WifiAwareNativeCallback wifiAwareNativeCallback, NetdWrapper netdWrapper) { Log.i(TAG, "Starting Wi-Fi Aware service"); mWifiPermissionsUtil = wifiPermissionsUtil; @@ -109,7 +110,7 @@ public class WifiAwareServiceImpl extends IWifiAwareManager.Stub { mHandler.post(() -> { mStateManager.start(mContext, handlerThread.getLooper(), awareMetrics, - wifiPermissionsUtil, permissionsWrapper, new Clock()); + wifiPermissionsUtil, permissionsWrapper, new Clock(), netdWrapper); frameworkFacade.registerContentObserver(mContext, Settings.Global.getUriFor(Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED), true, diff --git a/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java b/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java index 924a222ff..bdf1b728e 100644 --- a/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java +++ b/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java @@ -55,6 +55,7 @@ import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.WakeupMessage; import com.android.server.wifi.Clock; +import com.android.server.wifi.util.NetdWrapper; import com.android.server.wifi.util.WifiPermissionsUtil; import com.android.server.wifi.util.WifiPermissionsWrapper; @@ -381,7 +382,7 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe */ public void start(Context context, Looper looper, WifiAwareMetrics awareMetrics, WifiPermissionsUtil wifiPermissionsUtil, WifiPermissionsWrapper permissionsWrapper, - Clock clock) { + Clock clock, NetdWrapper netdWrapper) { Log.i(TAG, "start()"); mContext = context; @@ -393,7 +394,7 @@ public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShe mDataPathMgr = new WifiAwareDataPathStateManager(this, clock); mDataPathMgr.start(mContext, mSm.getHandler().getLooper(), awareMetrics, - wifiPermissionsUtil, permissionsWrapper); + wifiPermissionsUtil, permissionsWrapper, netdWrapper); mPowerManager = mContext.getSystemService(PowerManager.class); mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); diff --git a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java index 217adfedc..8f3bb98be 100644 --- a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java +++ b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java @@ -32,7 +32,6 @@ import android.location.LocationManager; import android.net.ConnectivityManager; import android.net.DhcpResults; import android.net.InetAddresses; -import android.net.InterfaceConfiguration; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkInfo; @@ -61,13 +60,11 @@ import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; -import android.os.INetworkManagementService; import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.os.Process; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -91,6 +88,7 @@ import com.android.server.wifi.FrameworkFacade; import com.android.server.wifi.WifiInjector; import com.android.server.wifi.WifiLog; import com.android.server.wifi.proto.nano.WifiMetricsProto.P2pConnectionEvent; +import com.android.server.wifi.util.NetdWrapper; import com.android.server.wifi.util.WifiAsyncChannel; import com.android.server.wifi.util.WifiHandler; import com.android.server.wifi.util.WifiPermissionsUtil; @@ -123,7 +121,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { private Context mContext; - INetworkManagementService mNwService; + NetdWrapper mNetdWrapper; private IIpClient mIpClient; private int mIpClientStartIndex = 0; private DhcpResults mDhcpResults; @@ -481,8 +479,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { * Obtains the service interface for Managements services */ public void connectivityServiceReady() { - IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); - mNwService = INetworkManagementService.Stub.asInterface(b); + mNetdWrapper = mWifiInjector.makeNetdWrapper(); } private void enforceAccessPermission() { @@ -1412,9 +1409,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { } setupInterfaceFeatures(mInterfaceName); try { - mNwService.setInterfaceUp(mInterfaceName); - } catch (RemoteException re) { - loge("Unable to change interface settings: " + re); + mNetdWrapper.setInterfaceUp(mInterfaceName); } catch (IllegalStateException ie) { loge("Unable to change interface settings: " + ie); } @@ -2735,7 +2730,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { try { final String ifname = mGroup.getInterface(); if (mDhcpResults != null) { - mNwService.addInterfaceToLocalNetwork( + mNetdWrapper.addInterfaceToLocalNetwork( ifname, mDhcpResults.getRoutes(ifname)); } } catch (Exception e) { @@ -3093,23 +3088,20 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { private void startDhcpServer(String intf) { if (!isDhcpServerHostedByDnsmasq()) return; - InterfaceConfiguration ifcg = null; try { - ifcg = mNwService.getInterfaceConfig(intf); - ifcg.setLinkAddress(new LinkAddress(InetAddresses.parseNumericAddress( - SERVER_ADDRESS), 24)); - ifcg.setInterfaceUp(); - mNwService.setInterfaceConfig(intf, ifcg); + mNetdWrapper.setInterfaceLinkAddress( + intf, + new LinkAddress(InetAddresses.parseNumericAddress(SERVER_ADDRESS), 24)); // This starts the dnsmasq server ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService( Context.CONNECTIVITY_SERVICE); String[] tetheringDhcpRanges = cm.getTetheredDhcpRanges(); - if (mNwService.isTetheringStarted()) { + if (mNetdWrapper.isTetheringStarted()) { if (mVerboseLoggingEnabled) logd("Stop existing tethering and restart it"); - mNwService.stopTethering(); + mNetdWrapper.stopTethering(); } - mNwService.tetherInterface(intf); - mNwService.startTethering(tetheringDhcpRanges); + mNetdWrapper.tetherInterface(intf); + mNetdWrapper.startTethering(tetheringDhcpRanges); } catch (Exception e) { loge("Error configuring interface " + intf + ", :" + e); return; @@ -3122,15 +3114,15 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { if (!isDhcpServerHostedByDnsmasq()) return; try { - mNwService.untetherInterface(intf); - for (String temp : mNwService.listTetheredInterfaces()) { + mNetdWrapper.untetherInterface(intf); + for (String temp : mNetdWrapper.listTetheredInterfaces()) { logd("List all interfaces " + temp); if (temp.compareTo(intf) != 0) { logd("Found other tethering interfaces, so keep tethering alive"); return; } } - mNwService.stopTethering(); + mNetdWrapper.stopTethering(); } catch (Exception e) { loge("Error stopping Dhcp server" + e); return; @@ -3770,14 +3762,14 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { if (mVerboseLoggingEnabled) logd("stop IpClient"); stopIpClient(); try { - mNwService.removeInterfaceFromLocalNetwork(mGroup.getInterface()); - } catch (RemoteException e) { + mNetdWrapper.removeInterfaceFromLocalNetwork(mGroup.getInterface()); + } catch (IllegalStateException e) { loge("Failed to remove iface from local network " + e); } } try { - mNwService.clearInterfaceAddresses(mGroup.getInterface()); + mNetdWrapper.clearInterfaceAddresses(mGroup.getInterface()); } catch (Exception e) { loge("Failed to clear addresses " + e); } diff --git a/service/java/com/android/server/wifi/util/NetdWrapper.java b/service/java/com/android/server/wifi/util/NetdWrapper.java new file mode 100644 index 000000000..88d65dd1f --- /dev/null +++ b/service/java/com/android/server/wifi/util/NetdWrapper.java @@ -0,0 +1,489 @@ +/* + * Copyright (C) 2019 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.wifi.util; + +import android.content.Context; +import android.net.INetd; +import android.net.INetdUnsolicitedEventListener; +import android.net.InterfaceConfiguration; +import android.net.InterfaceConfigurationParcel; +import android.net.IpPrefix; +import android.net.LinkAddress; +import android.net.NetworkUtils; +import android.net.RouteInfo; +import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceSpecificException; +import android.text.TextUtils; +import android.util.Log; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * This is a simple wrapper over INetd calls used by wifi stack. + * + * Based on {@link com.android.server.NetworkManagementService} + */ +public class NetdWrapper { + private static final String TAG = "NetdWrapper"; + static final boolean MODIFY_OPERATION_ADD = true; + static final boolean MODIFY_OPERATION_REMOVE = false; + + private final INetd mNetdService; + private final NetdUnsolicitedEventListener mNetdUnsolicitedEventListener; + private final Handler mHandler; + private final Set<NetdEventObserver> mObservers = new HashSet<>(); + + /** + * Observer for iface events. + */ + public interface NetdEventObserver { + /** + * Interface configuration status has changed. + * + * @param iface The interface. + * @param up True if the interface has been enabled. + */ + void interfaceStatusChanged(String iface, boolean up); + /** + * Interface physical-layer link state has changed. For Ethernet, + * this method is invoked when the cable is plugged in or unplugged. + * + * @param iface The interface. + * @param up True if the physical link-layer connection signal is valid. + */ + void interfaceLinkStateChanged(String iface, boolean up); + } + + private class NetdUnsolicitedEventListener extends INetdUnsolicitedEventListener.Stub { + @Override + public void onInterfaceClassActivityChanged(boolean isActive, + int label, long timestamp, int uid) throws RemoteException { + // Unused. + } + + @Override + public void onQuotaLimitReached(String alertName, String ifName) + throws RemoteException { + // Unused. + } + + @Override + public void onInterfaceDnsServerInfo(String ifName, + long lifetime, String[] servers) throws RemoteException { + // Unused. + } + + @Override + public void onInterfaceAddressUpdated(String addr, + String ifName, int flags, int scope) throws RemoteException { + // Unused. + } + + @Override + public void onInterfaceAddressRemoved(String addr, + String ifName, int flags, int scope) throws RemoteException { + // Unused. + } + + @Override + public void onInterfaceAdded(String ifName) throws RemoteException { + // Unused. + } + + @Override + public void onInterfaceRemoved(String ifName) throws RemoteException { + // Unused. + } + + @Override + public void onInterfaceChanged(String ifName, boolean up) + throws RemoteException { + mHandler.post(() -> notifyInterfaceStatusChanged(ifName, up)); + } + + @Override + public void onInterfaceLinkStateChanged(String ifName, boolean up) + throws RemoteException { + mHandler.post(() -> notifyInterfaceLinkStateChanged(ifName, up)); + } + + @Override + public void onRouteChanged(boolean updated, + String route, String gateway, String ifName) throws RemoteException { + // Unused. + } + + @Override + public void onStrictCleartextDetected(int uid, String hex) throws RemoteException { + // Unused. + } + + @Override + public int getInterfaceVersion() { + return INetdUnsolicitedEventListener.VERSION; + } + } + + public NetdWrapper(Context context, Handler handler) { + mNetdService = INetd.Stub.asInterface( + (IBinder) context.getSystemService(Context.NETD_SERVICE)); + mNetdUnsolicitedEventListener = new NetdUnsolicitedEventListener(); + mHandler = handler; + + try { + mNetdService.registerUnsolicitedEventListener(mNetdUnsolicitedEventListener); + } catch (RemoteException | ServiceSpecificException e) { + Log.e(TAG, "Failed to set Netd unsolicited event listener " + e); + } + } + + private void modifyInterfaceInNetwork(boolean add, int netId, String iface) { + try { + if (add) { + mNetdService.networkAddInterface(netId, iface); + } else { + mNetdService.networkRemoveInterface(netId, iface); + } + } catch (RemoteException | ServiceSpecificException e) { + throw new IllegalStateException(e); + } + } + + private void modifyRoute(boolean add, int netId, RouteInfo route) { + final String ifName = route.getInterface(); + final String dst = route.getDestination().toString(); + final String nextHop; + + switch (route.getType()) { + case RouteInfo.RTN_UNICAST: + if (route.hasGateway()) { + nextHop = route.getGateway().getHostAddress(); + } else { + nextHop = INetd.NEXTHOP_NONE; + } + break; + case RouteInfo.RTN_UNREACHABLE: + nextHop = INetd.NEXTHOP_UNREACHABLE; + break; + case RouteInfo.RTN_THROW: + nextHop = INetd.NEXTHOP_THROW; + break; + default: + nextHop = INetd.NEXTHOP_NONE; + break; + } + try { + if (add) { + mNetdService.networkAddRoute(netId, ifName, dst, nextHop); + } else { + mNetdService.networkRemoveRoute(netId, ifName, dst, nextHop); + } + } catch (RemoteException | ServiceSpecificException e) { + throw new IllegalStateException(e); + } + } + + /** + * Add iface to local network. + */ + public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) { + modifyInterfaceInNetwork(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID, iface); + + for (RouteInfo route : routes) { + if (!route.isDefaultRoute()) { + modifyRoute(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID, route); + } + } + + // IPv6 link local should be activated always. + modifyRoute(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID, + new RouteInfo(new IpPrefix("fe80::/64"), null, iface)); + } + + /** + * Remove iface from local network. + */ + public void removeInterfaceFromLocalNetwork(String iface) { + modifyInterfaceInNetwork(MODIFY_OPERATION_REMOVE, INetd.LOCAL_NET_ID, iface); + } + + /** + * Clear iface addresses. + */ + public void clearInterfaceAddresses(String iface) { + try { + mNetdService.interfaceClearAddrs(iface); + } catch (RemoteException | ServiceSpecificException e) { + throw new IllegalStateException(e); + } + } + + /** + * Enable IPv6 on iface. + */ + public void enableIpv6(String iface) { + try { + mNetdService.interfaceSetEnableIPv6(iface, true); + } catch (RemoteException | ServiceSpecificException e) { + throw new IllegalStateException(e); + } + } + + /** + * Disable IPv6 on iface. + */ + public void disableIpv6(String iface) { + try { + mNetdService.interfaceSetEnableIPv6(iface, false); + } catch (RemoteException | ServiceSpecificException e) { + throw new IllegalStateException(e); + } + } + + /** + * Convert InterfaceConfiguration to InterfaceConfigurationParcel with given ifname. + */ + private static InterfaceConfigurationParcel toStableParcel(InterfaceConfiguration cfg, + String iface) { + InterfaceConfigurationParcel cfgParcel = new InterfaceConfigurationParcel(); + cfgParcel.ifName = iface; + String hwAddr = cfg.getHardwareAddress(); + if (!TextUtils.isEmpty(hwAddr)) { + cfgParcel.hwAddr = hwAddr; + } else { + cfgParcel.hwAddr = ""; + } + cfgParcel.ipv4Addr = cfg.getLinkAddress().getAddress().getHostAddress(); + cfgParcel.prefixLength = cfg.getLinkAddress().getPrefixLength(); + ArrayList<String> flags = new ArrayList<>(); + for (String flag : cfg.getFlags()) { + flags.add(flag); + } + cfgParcel.flags = flags.toArray(new String[0]); + + return cfgParcel; + } + + /** + * Construct InterfaceConfiguration from InterfaceConfigurationParcel. + */ + private static InterfaceConfiguration fromStableParcel(InterfaceConfigurationParcel p) { + InterfaceConfiguration cfg = new InterfaceConfiguration(); + cfg.setHardwareAddress(p.hwAddr); + + final InetAddress addr = NetworkUtils.numericToInetAddress(p.ipv4Addr); + cfg.setLinkAddress(new LinkAddress(addr, p.prefixLength)); + for (String flag : p.flags) { + cfg.setFlag(flag); + } + + return cfg; + } + + private InterfaceConfiguration getInterfaceConfig(String iface) { + final InterfaceConfigurationParcel result; + try { + result = mNetdService.interfaceGetCfg(iface); + } catch (RemoteException | ServiceSpecificException e) { + throw new IllegalStateException(e); + } + + try { + final InterfaceConfiguration cfg = fromStableParcel(result); + return cfg; + } catch (IllegalArgumentException iae) { + throw new IllegalStateException("Invalid InterfaceConfigurationParcel", iae); + } + } + + private void setInterfaceConfig(String iface, InterfaceConfiguration cfg) { + LinkAddress linkAddr = cfg.getLinkAddress(); + if (linkAddr == null || linkAddr.getAddress() == null) { + throw new IllegalStateException("Null LinkAddress given"); + } + final InterfaceConfigurationParcel cfgParcel = toStableParcel(cfg, iface); + + try { + mNetdService.interfaceSetCfg(cfgParcel); + } catch (RemoteException | ServiceSpecificException e) { + throw new IllegalStateException(e); + } + } + + /** + * List all tethered interfaces. + */ + public String[] listTetheredInterfaces() { + try { + return mNetdService.tetherInterfaceList(); + } catch (RemoteException | ServiceSpecificException e) { + throw new IllegalStateException(e); + } + } + + /** + * Register a new netd event observer. + */ + public void registerObserver(NetdEventObserver observer) { + mObservers.add(observer); + } + + /** + * Unregister a new netd event observer. + */ + public void unregisterObserver(NetdEventObserver observer) { + mObservers.remove(observer); + } + + /** + * Set iface down. + */ + public void setInterfaceDown(String iface) { + final InterfaceConfiguration ifcg = getInterfaceConfig(iface); + ifcg.setInterfaceDown(); + setInterfaceConfig(iface, ifcg); + } + + /** + * Set iface up. + */ + public void setInterfaceUp(String iface) { + final InterfaceConfiguration ifcg = getInterfaceConfig(iface); + ifcg.setInterfaceUp(); + setInterfaceConfig(iface, ifcg); + } + + /** + * Returns whether iface is up. + */ + public boolean isInterfaceUp(String iface) { + final InterfaceConfiguration ifcg = getInterfaceConfig(iface); + return ifcg.isUp(); + } + + /** + * Set iface link address. + */ + public void setInterfaceLinkAddress(String iface, LinkAddress linkAddress) { + final InterfaceConfiguration ifcg = getInterfaceConfig(iface); + ifcg.setLinkAddress(linkAddress); + ifcg.setInterfaceUp(); + setInterfaceConfig(iface, ifcg); + } + + /** + * Set iface IPv6 privacy extensions. + */ + public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable) { + try { + mNetdService.interfaceSetIPv6PrivacyExtensions(iface, enable); + } catch (RemoteException | ServiceSpecificException e) { + throw new IllegalStateException(e); + } + } + + /** + * Start tethering. + */ + public void startTethering(String[] dhcpRange) { + // an odd number of addrs will fail + try { + mNetdService.tetherStart(dhcpRange); + } catch (RemoteException | ServiceSpecificException e) { + throw new IllegalStateException(e); + } + } + + /** + * Stop tethering. + */ + public void stopTethering() { + try { + mNetdService.tetherStop(); + } catch (RemoteException | ServiceSpecificException e) { + throw new IllegalStateException(e); + } + } + + /** + * Add tethering on iface. + */ + public void tetherInterface(String iface) { + try { + mNetdService.tetherInterfaceAdd(iface); + } catch (RemoteException | ServiceSpecificException e) { + throw new IllegalStateException(e); + } + List<RouteInfo> routes = new ArrayList<>(); + // The RouteInfo constructor truncates the LinkAddress to a network prefix, thus making it + // suitable to use as a route destination. + routes.add(new RouteInfo(getInterfaceConfig(iface).getLinkAddress(), null, iface)); + addInterfaceToLocalNetwork(iface, routes); + } + + /** + * Remove tethering on iface. + */ + public void untetherInterface(String iface) { + try { + mNetdService.tetherInterfaceRemove(iface); + } catch (RemoteException | ServiceSpecificException e) { + throw new IllegalStateException(e); + } finally { + removeInterfaceFromLocalNetwork(iface); + } + } + + /** + * Returns whether tethering has been started. + */ + public boolean isTetheringStarted() { + try { + final boolean isEnabled = mNetdService.tetherIsEnabled(); + return isEnabled; + } catch (RemoteException | ServiceSpecificException e) { + throw new IllegalStateException(e); + } + } + + + /** + * Notify our observers of an interface status change + */ + private void notifyInterfaceStatusChanged(String iface, boolean up) { + for (NetdEventObserver observer : mObservers) { + observer.interfaceStatusChanged(iface, up); + } + } + + /** + * Notify our observers of an interface link state change + * (typically, an Ethernet cable has been plugged-in or unplugged). + */ + private void notifyInterfaceLinkStateChanged(String iface, boolean up) { + for (NetdEventObserver observer : mObservers) { + observer.interfaceLinkStateChanged(iface, up); + } + } +} + |