diff options
5 files changed, 272 insertions, 29 deletions
diff --git a/service/java/com/android/server/wifi/HalDeviceManager.java b/service/java/com/android/server/wifi/HalDeviceManager.java index 5bc52d429..a5e461eaf 100644 --- a/service/java/com/android/server/wifi/HalDeviceManager.java +++ b/service/java/com/android/server/wifi/HalDeviceManager.java @@ -76,6 +76,9 @@ public class HalDeviceManager { private final Clock mClock; + // cache the value for supporting vendor HAL or not + private boolean mIsVendorHalSupported = false; + // public API public HalDeviceManager(Clock clock) { mClock = clock; @@ -134,7 +137,7 @@ public class HalDeviceManager { * Returns whether the vendor HAL is supported on this device or not. */ public boolean isSupported() { - return isSupportedInternal(); + return mIsVendorHalSupported; } /** @@ -611,7 +614,7 @@ public class HalDeviceManager { private void initializeInternal() { initIServiceManagerIfNecessary(); - if (isSupportedInternal()) { + if (mIsVendorHalSupported) { initIWifiIfNecessary(); } } @@ -685,6 +688,9 @@ public class HalDeviceManager { Log.wtf(TAG, "Exception while operating on IServiceManager: " + e); mServiceManager = null; } + + // Cache the result for the supporting vendor hal or not + mIsVendorHalSupported = isSupportedInternal(); } } } diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index c03c46aad..9826a4cc8 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -210,7 +210,8 @@ public class WifiInjector { mWifiP2pMonitor = new WifiP2pMonitor(this); mSupplicantP2pIfaceHal = new SupplicantP2pIfaceHal(mWifiP2pMonitor); mWifiP2pNative = new WifiP2pNative( - mWifiVendorHal, mSupplicantP2pIfaceHal, mHalDeviceManager); + mWifiVendorHal, mSupplicantP2pIfaceHal, mHalDeviceManager, + mPropertyService); // Now get instances of all the objects that depend on the HandlerThreads mWifiTrafficPoller = new WifiTrafficPoller(clientModeImplLooper); diff --git a/service/java/com/android/server/wifi/p2p/WifiP2pNative.java b/service/java/com/android/server/wifi/p2p/WifiP2pNative.java index 3e0aaa145..58ebb60e8 100644 --- a/service/java/com/android/server/wifi/p2p/WifiP2pNative.java +++ b/service/java/com/android/server/wifi/p2p/WifiP2pNative.java @@ -28,6 +28,7 @@ import android.text.TextUtils; import android.util.Log; import com.android.server.wifi.HalDeviceManager; +import com.android.server.wifi.PropertyService; import com.android.server.wifi.WifiVendorHal; /** @@ -41,6 +42,7 @@ public class WifiP2pNative { private boolean mVerboseLoggingEnabled = false; private final SupplicantP2pIfaceHal mSupplicantP2pIfaceHal; private final HalDeviceManager mHalDeviceManager; + private final PropertyService mPropertyService; private final WifiVendorHal mWifiVendorHal; private IWifiP2pIface mIWifiP2pIface; private InterfaceAvailableListenerInternal mInterfaceAvailableListener; @@ -104,10 +106,12 @@ public class WifiP2pNative { } public WifiP2pNative(WifiVendorHal wifiVendorHal, - SupplicantP2pIfaceHal p2pIfaceHal, HalDeviceManager halDeviceManager) { + SupplicantP2pIfaceHal p2pIfaceHal, HalDeviceManager halDeviceManager, + PropertyService propertyService) { mWifiVendorHal = wifiVendorHal; mSupplicantP2pIfaceHal = p2pIfaceHal; mHalDeviceManager = halDeviceManager; + mPropertyService = propertyService; } /** @@ -153,6 +157,41 @@ public class WifiP2pNative { } /** + * Returns whether HAL (HIDL) is supported on this device or not. + */ + public boolean isHalInterfaceSupported() { + return mHalDeviceManager.isSupported(); + } + + private static final String P2P_IFACE_NAME = "p2p0"; + private static final String P2P_INTERFACE_PROPERTY = "wifi.direct.interface"; + /** + * Helper function to handle creation of P2P iface. + * For devices which do not the support the HAL, this will bypass HalDeviceManager & + * teardown any existing iface. + */ + private String createP2pIface(Handler handler) { + if (mHalDeviceManager.isSupported()) { + mIWifiP2pIface = mHalDeviceManager + .createP2pIface(mInterfaceDestroyedListener, handler); + if (mIWifiP2pIface == null) { + Log.e(TAG, "Failed to create P2p iface in HalDeviceManager"); + return null; + } + String ifaceName = HalDeviceManager.getName(mIWifiP2pIface); + if (TextUtils.isEmpty(ifaceName)) { + Log.e(TAG, "Failed to get p2p iface name"); + teardownInterface(); + return null; + } + return ifaceName; + } else { + Log.i(TAG, "Vendor Hal is not supported, ignoring createP2pIface."); + return mPropertyService.getString(P2P_INTERFACE_PROPERTY, P2P_IFACE_NAME); + } + } + + /** * Register for an interface available callbacks from HalDeviceManager. * * @param listener callback to be invoked when the interface is available/not available. @@ -187,10 +226,11 @@ public class WifiP2pNative { Handler handler) { Log.d(TAG, "Setup P2P interface"); if (mIWifiP2pIface == null) { - mInterfaceDestroyedListener = new InterfaceDestroyedListenerInternal(destroyedListener); - mIWifiP2pIface = mHalDeviceManager.createP2pIface(mInterfaceDestroyedListener, handler); - if (mIWifiP2pIface == null) { - Log.e(TAG, "Failed to create P2p iface in HalDeviceManager"); + mInterfaceDestroyedListener = + new InterfaceDestroyedListenerInternal(destroyedListener); + String ifaceName = createP2pIface(handler); + if (ifaceName == null) { + Log.e(TAG, "Failed to create P2p iface"); return null; } if (!waitForSupplicantConnection()) { @@ -198,20 +238,19 @@ public class WifiP2pNative { teardownInterface(); return null; } - String ifaceName = HalDeviceManager.getName(mIWifiP2pIface); - if (TextUtils.isEmpty(ifaceName)) { - Log.e(TAG, "Failed to get p2p iface name"); - teardownInterface(); - return null; - } if (!mSupplicantP2pIfaceHal.setupIface(ifaceName)) { Log.e(TAG, "Failed to setup P2p iface in supplicant"); teardownInterface(); return null; } Log.i(TAG, "P2P interface setup completed"); + return ifaceName; + } else { + Log.i(TAG, "P2P interface is already existed"); + return mHalDeviceManager.isSupported() + ? HalDeviceManager.getName(mIWifiP2pIface) + : mPropertyService.getString(P2P_INTERFACE_PROPERTY, P2P_IFACE_NAME); } - return HalDeviceManager.getName(mIWifiP2pIface); } /** @@ -219,11 +258,17 @@ public class WifiP2pNative { */ public void teardownInterface() { Log.d(TAG, "Teardown P2P interface"); - if (mIWifiP2pIface != null) { - String ifaceName = HalDeviceManager.getName(mIWifiP2pIface); - mHalDeviceManager.removeIface(mIWifiP2pIface); + if (mHalDeviceManager.isSupported()) { + if (mIWifiP2pIface != null) { + String ifaceName = HalDeviceManager.getName(mIWifiP2pIface); + mHalDeviceManager.removeIface(mIWifiP2pIface); + mInterfaceDestroyedListener.teardownAndInvalidate(ifaceName); + Log.i(TAG, "P2P interface teardown completed"); + } + } else { + Log.i(TAG, "HAL (HIDL) is not supported. Destroy listener for the interface."); + String ifaceName = mPropertyService.getString(P2P_INTERFACE_PROPERTY, P2P_IFACE_NAME); mInterfaceDestroyedListener.teardownAndInvalidate(ifaceName); - Log.i(TAG, "P2P interface teardown completed"); } } diff --git a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java index 3e3da2326..430c5fd20 100644 --- a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java +++ b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java @@ -765,8 +765,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { }); private final WifiP2pInfo mWifiP2pInfo = new WifiP2pInfo(); private WifiP2pGroup mGroup; - // Is the P2P interface available for use. - private boolean mIsInterfaceAvailable = false; + // Is the HAL (HIDL) interface available for use. + private boolean mIsHalInterfaceAvailable = false; // Is wifi on or off. private boolean mIsWifiEnabled = false; @@ -836,7 +836,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { }, new IntentFilter(LocationManager.MODE_CHANGED_ACTION)); // Register for interface availability from HalDeviceManager mWifiNative.registerInterfaceAvailableListener((boolean isAvailable) -> { - mIsInterfaceAvailable = isAvailable; + mIsHalInterfaceAvailable = isAvailable; if (isAvailable) { checkAndReEnableP2p(); } @@ -1058,7 +1058,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { break; case WifiP2pManager.REQUEST_P2P_STATE: replyToMessage(message, WifiP2pManager.RESPONSE_P2P_STATE, - (mIsWifiEnabled && mIsInterfaceAvailable && isLocationModeEnabled()) + (mIsWifiEnabled && isHalInterfaceAvailable() + && isLocationModeEnabled()) ? WifiP2pManager.WIFI_P2P_STATE_ENABLED : WifiP2pManager.WIFI_P2P_STATE_DISABLED); break; @@ -2916,15 +2917,16 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { // Check & re-enable P2P if needed. // P2P interface will be created if all of the below are true: // a) Wifi is enabled. - // b) P2P interface is available. + // b) HAL (HIDL) interface is available. // c) There is atleast 1 client app which invoked initialize(). // d) Location is enabled. private void checkAndReEnableP2p() { boolean isLocationEnabled = isLocationModeEnabled(); + boolean isHalInterfaceAvailable = isHalInterfaceAvailable(); Log.d(TAG, "Wifi enabled=" + mIsWifiEnabled + ", P2P Interface availability=" - + mIsInterfaceAvailable + ", Number of clients=" + mDeathDataByBinder.size() - + ", Location enabled=" + isLocationEnabled); - if (mIsWifiEnabled && mIsInterfaceAvailable + + isHalInterfaceAvailable + ", Number of clients=" + + mDeathDataByBinder.size() + ", Location enabled=" + isLocationEnabled); + if (mIsWifiEnabled && isHalInterfaceAvailable && isLocationEnabled && !mDeathDataByBinder.isEmpty()) { sendMessage(ENABLE_P2P); } @@ -2934,11 +2936,17 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { return mWifiPermissionsUtil.isLocationModeEnabled(); } + // Ignore judgement if the device do not support HAL (HIDL) interface + private boolean isHalInterfaceAvailable() { + return mWifiNative.isHalInterfaceSupported() ? mIsHalInterfaceAvailable : true; + } + private void checkAndSendP2pStateChangedBroadcast() { boolean isLocationEnabled = isLocationModeEnabled(); + boolean isHalInterfaceAvailable = isHalInterfaceAvailable(); Log.d(TAG, "Wifi enabled=" + mIsWifiEnabled + ", P2P Interface availability=" - + mIsInterfaceAvailable + ", Location enabled=" + isLocationEnabled); - sendP2pStateChangedBroadcast(mIsWifiEnabled && mIsInterfaceAvailable + + isHalInterfaceAvailable + ", Location enabled=" + isLocationEnabled); + sendP2pStateChangedBroadcast(mIsWifiEnabled && isHalInterfaceAvailable && isLocationEnabled); } diff --git a/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pNativeInterfaceManagementTest.java b/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pNativeInterfaceManagementTest.java new file mode 100644 index 000000000..962acd01e --- /dev/null +++ b/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pNativeInterfaceManagementTest.java @@ -0,0 +1,183 @@ +/* + * 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.p2p; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.test.MockAnswerUtil; +import android.hardware.wifi.V1_0.IWifiIface; +import android.hardware.wifi.V1_0.IWifiP2pIface; +import android.hardware.wifi.V1_0.IfaceType; +import android.hardware.wifi.V1_0.WifiStatus; +import android.hardware.wifi.V1_0.WifiStatusCode; +import android.os.Handler; +import android.os.RemoteException; + +import androidx.test.filters.SmallTest; + +import com.android.server.wifi.HalDeviceManager; +import com.android.server.wifi.HalDeviceManager.InterfaceAvailableForRequestListener; +import com.android.server.wifi.HalDeviceManager.InterfaceDestroyedListener; +import com.android.server.wifi.HalDeviceManager.ManagerStatusListener; +import com.android.server.wifi.PropertyService; +import com.android.server.wifi.WifiVendorHal; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Unit tests for the interface management operations in + * {@link com.android.server.wifi.WifiP2pNative}. + */ +@SmallTest +public class WifiP2pNativeInterfaceManagementTest { + private static final String P2P_IFACE_NAME = "p2p0"; + private static final String P2P_INTERFACE_PROPERTY = "wifi.direct.interface"; + + @Mock private SupplicantP2pIfaceHal mSupplicantP2pIfaceHal; + @Mock private HalDeviceManager mHalDeviceManager; + @Mock private PropertyService mPropertyService; + @Mock private Handler mHandler; + @Mock private InterfaceAvailableForRequestListener mInterfaceRequestListener; + @Mock private InterfaceDestroyedListener mHalDeviceInterfaceDestroyedListener; + @Mock private IWifiP2pIface mIWifiP2pIface; + @Mock private IWifiIface mIWifiIface; + @Mock private WifiVendorHal mWifiVendorHal; + private WifiP2pNative mWifiP2pNative; + private WifiStatus mWifiStatusSuccess; + private ManagerStatusListener mManagerStatusListener; + + /** + * Sets up for unit test + */ + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mWifiStatusSuccess = new WifiStatus(); + mWifiStatusSuccess.code = WifiStatusCode.SUCCESS; + + when(mHalDeviceManager.isSupported()).thenReturn(true); + when(mHalDeviceManager.createP2pIface(any(InterfaceDestroyedListener.class), + any(Handler.class))).thenReturn(mIWifiP2pIface); + doAnswer(new MockAnswerUtil.AnswerWithArguments() { + public void answer(IWifiIface.getNameCallback cb) + throws RemoteException { + cb.onValues(mWifiStatusSuccess, P2P_IFACE_NAME); + } + }).when(mIWifiP2pIface).getName(any(IWifiIface.getNameCallback.class)); + + when(mSupplicantP2pIfaceHal.isInitializationStarted()).thenReturn(true); + when(mSupplicantP2pIfaceHal.initialize()).thenReturn(true); + when(mSupplicantP2pIfaceHal.isInitializationComplete()).thenReturn(true); + when(mSupplicantP2pIfaceHal.setupIface(P2P_IFACE_NAME)).thenReturn(true); + when(mPropertyService.getString(P2P_INTERFACE_PROPERTY, P2P_IFACE_NAME)) + .thenReturn(P2P_IFACE_NAME); + + mWifiP2pNative = new WifiP2pNative( + mWifiVendorHal, mSupplicantP2pIfaceHal, mHalDeviceManager, + mPropertyService); + } + + /** + * Verifies the HAL (HIDL) interface listener. + */ + @Test + public void testRegisterInterfaceAvailableListener() throws Exception { + when(mHalDeviceManager.isStarted()).thenReturn(false); + + mWifiP2pNative.registerInterfaceAvailableListener(mInterfaceRequestListener, mHandler); + when(mHalDeviceManager.isStarted()).thenReturn(true); + + ArgumentCaptor<ManagerStatusListener> hdmCallbackCaptor = + ArgumentCaptor.forClass(ManagerStatusListener.class); + verify(mHalDeviceManager).registerStatusListener(hdmCallbackCaptor.capture(), eq(mHandler)); + // Simulate to call status callback from device hal manager + hdmCallbackCaptor.getValue().onStatusChanged(); + + verify(mHalDeviceManager).registerInterfaceAvailableForRequestListener(eq(IfaceType.P2P), + any(InterfaceAvailableForRequestListener.class), eq(mHandler)); + } + + /** + * Verifies the setup of a p2p interface. + */ + @Test + public void testSetUpInterface() throws Exception { + assertEquals(P2P_IFACE_NAME, + mWifiP2pNative.setupInterface(mHalDeviceInterfaceDestroyedListener, mHandler)); + + verify(mHalDeviceManager).createP2pIface(any(InterfaceDestroyedListener.class), + eq(mHandler)); + verify(mSupplicantP2pIfaceHal).setupIface(eq(P2P_IFACE_NAME)); + } + + /** + * Verifies the setup of a p2p interface with no HAL (HIDL) support. + */ + @Test + public void testSetUpInterfaceWithNoVendorHal() throws Exception { + when(mHalDeviceManager.isSupported()).thenReturn(false); + + assertEquals(P2P_IFACE_NAME, mWifiP2pNative.setupInterface( + mHalDeviceInterfaceDestroyedListener, mHandler)); + + verify(mHalDeviceManager, never()) + .createP2pIface(any(InterfaceDestroyedListener.class), any(Handler.class)); + verify(mSupplicantP2pIfaceHal).setupIface(eq(P2P_IFACE_NAME)); + } + + /** + * Verifies the teardown of a p2p interface. + */ + @Test + public void testTeardownInterface() throws Exception { + assertEquals(P2P_IFACE_NAME, + mWifiP2pNative.setupInterface(mHalDeviceInterfaceDestroyedListener, + mHandler)); + + mWifiP2pNative.teardownInterface(); + + verify(mHalDeviceManager).removeIface(any(IWifiIface.class)); + verify(mSupplicantP2pIfaceHal).teardownIface(eq(P2P_IFACE_NAME)); + } + + /** + * Verifies the teardown of a p2p interface with no HAL (HIDL) support. + */ + @Test + public void testTeardownInterfaceWithNoVendorHal() throws Exception { + when(mHalDeviceManager.isSupported()).thenReturn(false); + + assertEquals(P2P_IFACE_NAME, mWifiP2pNative.setupInterface( + mHalDeviceInterfaceDestroyedListener, mHandler)); + + mWifiP2pNative.teardownInterface(); + + verify(mHalDeviceManager, never()).removeIface(any(IWifiIface.class)); + verify(mSupplicantP2pIfaceHal).teardownIface(eq(P2P_IFACE_NAME)); + } +} |