diff options
author | Roshan Pius <rpius@google.com> | 2019-12-10 23:11:53 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2019-12-10 23:11:53 +0000 |
commit | b647449216e4d202fcadd327e6c603a95dd7723c (patch) | |
tree | 2487b010d67b6cb50fb0380297be53a02a718400 /service | |
parent | 65262bc0def1b44cdcf385456184534cb8b53ef8 (diff) | |
parent | 520ff1c59262a21c36f14a3825e665413e91b2c9 (diff) |
Merge changes from topic "nw_mgmt_svc"
* changes:
wifi: Create local wrapper for INetworkManagementService
Wifi: Handle SystemService events in wifi service threads
Diffstat (limited to 'service')
14 files changed, 706 insertions, 221 deletions
diff --git a/service/Android.bp b/service/Android.bp index 219321022..a90128b4f 100644 --- a/service/Android.bp +++ b/service/Android.bp @@ -124,6 +124,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/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java index 304ad1b87..46d36758f 100644 --- a/service/java/com/android/server/wifi/ClientModeImpl.java +++ b/service/java/com/android/server/wifi/ClientModeImpl.java @@ -3103,8 +3103,7 @@ public class ClientModeImpl extends StateMachine { } break; case CMD_INITIALIZE: - ok = mWifiNative.initialize(); - replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); + mWifiNative.initialize(); break; case CMD_BOOT_COMPLETED: // get other services that we need to manage @@ -5560,14 +5559,9 @@ public class ClientModeImpl extends StateMachine { /** * Sends a message to initialize the ClientModeImpl. - * - * @return true if succeeded, false otherwise. */ - public boolean syncInitialize(AsyncChannel channel) { - Message resultMsg = channel.sendMessageSynchronously(CMD_INITIALIZE); - boolean result = (resultMsg.arg1 != FAILURE); - resultMsg.recycle(); - return result; + public void initialize() { + sendMessage(CMD_INITIALIZE); } /** 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/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java index 165df13bc..43a200686 100644 --- a/service/java/com/android/server/wifi/WifiServiceImpl.java +++ b/service/java/com/android/server/wifi/WifiServiceImpl.java @@ -310,75 +310,77 @@ public class WifiServiceImpl extends BaseWifiService { * This function is used only at boot time. */ public void checkAndStartWifi() { - // Check if wi-fi needs to be enabled - boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled(); - Log.i(TAG, "WifiService starting up with Wi-Fi " + (wifiEnabled ? "enabled" : "disabled")); - - registerForScanModeChange(); - mContext.registerReceiver( - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (mSettingsStore.handleAirplaneModeToggled()) { - mActiveModeWarden.airplaneModeToggled(); + mWifiThreadRunner.post(() -> { + // Check if wi-fi needs to be enabled + boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled(); + Log.i(TAG, + "WifiService starting up with Wi-Fi " + (wifiEnabled ? "enabled" : "disabled")); + + registerForScanModeChange(); + mContext.registerReceiver( + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (mSettingsStore.handleAirplaneModeToggled()) { + mActiveModeWarden.airplaneModeToggled(); + } } - } - }, - new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)); - - mContext.registerReceiver( - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String state = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); - if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(state)) { - Log.d(TAG, "resetting networks because SIM was removed"); - mClientModeImpl.resetSimAuthNetworks(false); - } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(state)) { - Log.d(TAG, "resetting networks because SIM was loaded"); - mClientModeImpl.resetSimAuthNetworks(true); + }, + new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)); + + mContext.registerReceiver( + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String state = intent.getStringExtra( + IccCardConstants.INTENT_KEY_ICC_STATE); + if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(state)) { + Log.d(TAG, "resetting networks because SIM was removed"); + mClientModeImpl.resetSimAuthNetworks(false); + } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(state)) { + Log.d(TAG, "resetting networks because SIM was loaded"); + mClientModeImpl.resetSimAuthNetworks(true); + } } - } - }, - new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED)); + }, + new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED)); - // Adding optimizations of only receiving broadcasts when wifi is enabled - // can result in race conditions when apps toggle wifi in the background - // without active user involvement. Always receive broadcasts. - registerForBroadcasts(); - mInIdleMode = mPowerManager.isDeviceIdleMode(); + // Adding optimizations of only receiving broadcasts when wifi is enabled + // can result in race conditions when apps toggle wifi in the background + // without active user involvement. Always receive broadcasts. + registerForBroadcasts(); + mInIdleMode = mPowerManager.isDeviceIdleMode(); - if (!mClientModeImpl.syncInitialize(mClientModeImplChannel)) { - Log.wtf(TAG, "Failed to initialize ClientModeImpl"); - } - mActiveModeWarden.start(); + mClientModeImpl.initialize(); + mActiveModeWarden.start(); + }); } public void handleBootCompleted() { - Log.d(TAG, "Handle boot completed"); - - // Register for system broadcasts. - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(Intent.ACTION_USER_REMOVED); - intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); - intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); - intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); - boolean trackEmergencyCallState = mContext.getResources().getBoolean( - R.bool.config_wifi_turn_off_during_emergency_call); - if (trackEmergencyCallState) { - intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED); - } - mContext.registerReceiver(mReceiver, intentFilter); - mWifiThreadRunner.post(() -> { + Log.d(TAG, "Handle boot completed"); + + // Register for system broadcasts. + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_USER_REMOVED); + intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); + intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); + intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); + boolean trackEmergencyCallState = mContext.getResources().getBoolean( + R.bool.config_wifi_turn_off_during_emergency_call); + if (trackEmergencyCallState) { + intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED); + } + mContext.registerReceiver(mReceiver, intentFilter); + new MemoryStoreImpl(mContext, mWifiInjector, mWifiInjector.getWifiScoreCard()).start(); if (!mWifiConfigManager.loadFromStore()) { Log.e(TAG, "Failed to load from config store"); } mPasspointManager.initializeProvisioner( mWifiInjector.getPasspointProvisionerHandlerThread().getLooper()); + mClientModeImpl.handleBootCompleted(); }); - mClientModeImpl.handleBootCompleted(); } public void handleUserSwitch(int userId) { 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 fbfa50ce0..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; @@ -69,6 +70,7 @@ public class WifiAwareServiceImpl extends IWifiAwareManager.Stub { private WifiPermissionsUtil mWifiPermissionsUtil; private WifiAwareStateManager mStateManager; private WifiAwareShellCommand mShellCommand; + private Handler mHandler; private final Object mLock = new Object(); private final SparseArray<IBinder.DeathRecipient> mDeathRecipientsByClientId = @@ -98,29 +100,34 @@ 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; mStateManager = awareStateManager; mShellCommand = awareShellCommand; - mStateManager.start(mContext, handlerThread.getLooper(), awareMetrics, wifiPermissionsUtil, - permissionsWrapper, new Clock()); - - frameworkFacade.registerContentObserver(mContext, - Settings.Global.getUriFor(Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED), true, - new ContentObserver(new Handler(handlerThread.getLooper())) { - @Override - public void onChange(boolean selfChange) { - enableVerboseLogging(frameworkFacade.getIntegerSetting(mContext, - Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0), awareStateManager, - wifiAwareNativeManager, wifiAwareNativeApi, - wifiAwareNativeCallback); - } - }); - enableVerboseLogging(frameworkFacade.getIntegerSetting(mContext, - Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0), awareStateManager, - wifiAwareNativeManager, wifiAwareNativeApi, wifiAwareNativeCallback); + mHandler = new Handler(handlerThread.getLooper()); + + mHandler.post(() -> { + mStateManager.start(mContext, handlerThread.getLooper(), awareMetrics, + wifiPermissionsUtil, permissionsWrapper, new Clock(), netdWrapper); + + frameworkFacade.registerContentObserver(mContext, + Settings.Global.getUriFor(Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED), true, + new ContentObserver(new Handler(handlerThread.getLooper())) { + @Override + public void onChange(boolean selfChange) { + enableVerboseLogging(frameworkFacade.getIntegerSetting(mContext, + Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0), + awareStateManager, + wifiAwareNativeManager, wifiAwareNativeApi, + wifiAwareNativeCallback); + } + }); + enableVerboseLogging(frameworkFacade.getIntegerSetting(mContext, + Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0), awareStateManager, + wifiAwareNativeManager, wifiAwareNativeApi, wifiAwareNativeCallback); + }); } private void enableVerboseLogging(int verbose, WifiAwareStateManager awareStateManager, @@ -154,7 +161,7 @@ public class WifiAwareServiceImpl extends IWifiAwareManager.Stub { public void startLate() { Log.i(TAG, "Late initialization of Wi-Fi Aware service"); - mStateManager.startLate(); + mHandler.post(() -> mStateManager.startLate()); } @Override 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/rtt/RttServiceImpl.java b/service/java/com/android/server/wifi/rtt/RttServiceImpl.java index 6e35eb5ad..659553656 100644 --- a/service/java/com/android/server/wifi/rtt/RttServiceImpl.java +++ b/service/java/com/android/server/wifi/rtt/RttServiceImpl.java @@ -250,67 +250,67 @@ public class RttServiceImpl extends IWifiRttManager.Stub { mRttMetrics = rttMetrics; mWifiPermissionsUtil = wifiPermissionsUtil; mRttServiceSynchronized = new RttServiceSynchronized(looper, rttNative); - mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); mPowerManager = mContext.getSystemService(PowerManager.class); - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); - mContext.registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (mDbg) Log.v(TAG, "BroadcastReceiver: action=" + action); - if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) { - if (mPowerManager.isDeviceIdleMode()) { - disable(); - } else { - enableIfPossible(); + mRttServiceSynchronized.mHandler.post(() -> { + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (mDbg) Log.v(TAG, "BroadcastReceiver: action=" + action); + + if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) { + if (mPowerManager.isDeviceIdleMode()) { + disable(); + } else { + enableIfPossible(); + } } } - } - }, intentFilter); - - frameworkFacade.registerContentObserver(mContext, - Settings.Global.getUriFor(Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED), true, - new ContentObserver(mRttServiceSynchronized.mHandler) { - @Override - public void onChange(boolean selfChange) { - enableVerboseLogging(frameworkFacade.getIntegerSetting(mContext, - Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0)); - } - }); + }, intentFilter); - enableVerboseLogging(frameworkFacade.getIntegerSetting(mContext, - Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0)); + frameworkFacade.registerContentObserver(mContext, + Settings.Global.getUriFor(Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED), true, + new ContentObserver(mRttServiceSynchronized.mHandler) { + @Override + public void onChange(boolean selfChange) { + enableVerboseLogging(frameworkFacade.getIntegerSetting(mContext, + Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0)); + } + }); - frameworkFacade.registerContentObserver(mContext, - Settings.Global.getUriFor(Settings.Global.WIFI_RTT_BACKGROUND_EXEC_GAP_MS), - true, - new ContentObserver(mRttServiceSynchronized.mHandler) { - @Override - public void onChange(boolean selfChange) { - updateBackgroundThrottlingInterval(frameworkFacade); - } - }); + enableVerboseLogging(frameworkFacade.getIntegerSetting(mContext, + Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0)); - updateBackgroundThrottlingInterval(frameworkFacade); + frameworkFacade.registerContentObserver(mContext, + Settings.Global.getUriFor(Settings.Global.WIFI_RTT_BACKGROUND_EXEC_GAP_MS), + true, + new ContentObserver(mRttServiceSynchronized.mHandler) { + @Override + public void onChange(boolean selfChange) { + updateBackgroundThrottlingInterval(frameworkFacade); + } + }); - intentFilter = new IntentFilter(); - intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION); - mContext.registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (mDbg) Log.v(TAG, "onReceive: MODE_CHANGED_ACTION: intent=" + intent); - if (mWifiPermissionsUtil.isLocationModeEnabled()) { - enableIfPossible(); - } else { - disable(); + updateBackgroundThrottlingInterval(frameworkFacade); + + intentFilter = new IntentFilter(); + intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (mDbg) Log.v(TAG, "onReceive: MODE_CHANGED_ACTION: intent=" + intent); + if (mWifiPermissionsUtil.isLocationModeEnabled()) { + enableIfPossible(); + } else { + disable(); + } } - } - }, intentFilter); + }, intentFilter); - mRttServiceSynchronized.mHandler.post(() -> { rttNative.start(mRttServiceSynchronized.mHandler); }); } diff --git a/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java b/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java index f6345ec12..bc727591e 100644 --- a/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java +++ b/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java @@ -36,6 +36,7 @@ import android.os.BadParcelableException; import android.os.BatteryStatsManager; import android.os.Binder; import android.os.Bundle; +import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.Messenger; @@ -404,16 +405,18 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub { } public void startService() { - mBackgroundScanStateMachine = new WifiBackgroundScanStateMachine(mLooper); - mSingleScanStateMachine = new WifiSingleScanStateMachine(mLooper); - mPnoScanStateMachine = new WifiPnoScanStateMachine(mLooper); - - mBackgroundScanStateMachine.start(); - mSingleScanStateMachine.start(); - mPnoScanStateMachine.start(); - - // Create client handler only after StateMachines are ready. - mClientHandler = new ClientHandler(TAG, mLooper); + new Handler(mLooper).post(() -> { + mBackgroundScanStateMachine = new WifiBackgroundScanStateMachine(mLooper); + mSingleScanStateMachine = new WifiSingleScanStateMachine(mLooper); + mPnoScanStateMachine = new WifiPnoScanStateMachine(mLooper); + + mBackgroundScanStateMachine.start(); + mSingleScanStateMachine.start(); + mPnoScanStateMachine.start(); + + // Create client handler only after StateMachines are ready. + mClientHandler = new ClientHandler(TAG, mLooper); + }); } /** 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); + } + } +} + |