Loading android/app/src/com/android/bluetooth/pbap/BluetoothPbapMethodProxy.java +19 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,9 @@ import android.util.Log; import com.android.bluetooth.Utils; import com.android.internal.annotations.VisibleForTesting; import com.android.obex.HeaderSet; import java.io.IOException; /** * Proxy class for method calls to help with unit testing Loading Loading @@ -63,11 +66,26 @@ public class BluetoothPbapMethodProxy { } /** * Return the result of {@link ContentResolver#query(Uri, String[], String, String[], String)}. * Proxies {@link ContentResolver#query(Uri, String[], String, String[], String)}. */ public Cursor contentResolverQuery(ContentResolver contentResolver, final Uri contentUri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder) { return contentResolver.query(contentUri, projection, selection, selectionArgs, sortOrder); } /** * Proxies {@link HeaderSet#setHeader}. */ public void setHeader(HeaderSet headerSet, int headerId, Object headerValue) throws IOException { headerSet.setHeader(headerId, headerValue); } /** * Proxies {@link HeaderSet#getHeader}. */ public Object getHeader(HeaderSet headerSet, int headerId) throws IOException { return headerSet.getHeader(headerId); } } android/app/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java +9 −5 Original line number Diff line number Diff line Loading @@ -223,6 +223,8 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { private PbapStateMachine mStateMachine; private BluetoothPbapMethodProxy mPbapMethodProxy; private enum ContactsType { TYPE_PHONEBOOK , TYPE_SIM ; } Loading Loading @@ -251,6 +253,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { mVcardManager = new BluetoothPbapVcardManager(mContext); mVcardSimManager = new BluetoothPbapSimVcardManager(mContext); mStateMachine = stateMachine; mPbapMethodProxy = BluetoothPbapMethodProxy.getInstance(); } @Override Loading @@ -260,7 +263,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { } notifyUpdateWakeLock(); try { byte[] uuid = (byte[]) request.getHeader(HeaderSet.TARGET); byte[] uuid = (byte[]) mPbapMethodProxy.getHeader(request, HeaderSet.TARGET); if (uuid == null) { return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE; } Loading @@ -278,19 +281,19 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE; } } reply.setHeader(HeaderSet.WHO, uuid); mPbapMethodProxy.setHeader(reply, HeaderSet.WHO, uuid); } catch (IOException e) { Log.e(TAG, e.toString()); return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; } try { byte[] remote = (byte[]) request.getHeader(HeaderSet.WHO); byte[] remote = (byte[]) mPbapMethodProxy.getHeader(request, HeaderSet.WHO); if (remote != null) { if (D) { Log.d(TAG, "onConnect(): remote=" + Arrays.toString(remote)); } reply.setHeader(HeaderSet.TARGET, remote); mPbapMethodProxy.setHeader(reply, HeaderSet.TARGET, remote); } } catch (IOException e) { Log.e(TAG, e.toString()); Loading @@ -300,7 +303,8 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { try { byte[] appParam = null; mConnAppParamValue = new AppParamValue(); appParam = (byte[]) request.getHeader(HeaderSet.APPLICATION_PARAMETER); appParam = (byte[]) mPbapMethodProxy.getHeader(request, HeaderSet.APPLICATION_PARAMETER); if ((appParam != null) && !parseApplicationParameter(appParam, mConnAppParamValue)) { return ResponseCodes.OBEX_HTTP_BAD_REQUEST; } Loading android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapObexServerTest.java 0 → 100644 +299 −0 Original line number Diff line number Diff line /* * Copyright 2022 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.bluetooth.pbap; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import android.os.Handler; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.obex.HeaderSet; import com.android.obex.Operation; import com.android.obex.ResponseCodes; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; import java.io.IOException; import java.io.OutputStream; @SmallTest @RunWith(AndroidJUnit4.class) public class BluetoothPbapObexServerTest { @Mock Handler mMockHandler; @Mock PbapStateMachine mMockStateMachine; @Spy BluetoothPbapMethodProxy mPbapMethodProxy = BluetoothPbapMethodProxy.getInstance(); BluetoothPbapObexServer mServer; // 128 bit UUID for PBAP private static final byte[] PBAP_TARGET_UUID = new byte[] { 0x79, 0x61, 0x35, (byte) 0xf0, (byte) 0xf0, (byte) 0xc5, 0x11, (byte) 0xd8, 0x09, 0x66, 0x08, 0x00, 0x20, 0x0c, (byte) 0x9a, 0x66 }; private static final byte[] WRONG_UUID = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; private static final byte[] WRONG_LENGTH_UUID = new byte[] { 0x79, 0x61, 0x35, }; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); BluetoothPbapMethodProxy.setInstanceForTesting(mPbapMethodProxy); mServer = new BluetoothPbapObexServer( mMockHandler, InstrumentationRegistry.getTargetContext(), mMockStateMachine); } @After public void tearDown() throws Exception { BluetoothPbapMethodProxy.setInstanceForTesting(null); } @Test public void testOnConnect_whenUuidIsNull() { // Create an empty header set. HeaderSet request = new HeaderSet(); HeaderSet reply = new HeaderSet(); assertThat(mServer.onConnect(request, reply)) .isEqualTo(ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE); } @Test public void testOnConnect_whenUuidLengthIsWrong() { HeaderSet request = new HeaderSet(); request.setHeader(HeaderSet.TARGET, WRONG_LENGTH_UUID); HeaderSet reply = new HeaderSet(); assertThat(mServer.onConnect(request, reply)) .isEqualTo(ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE); } @Test public void testOnConnect_whenUuidIsWrong() { HeaderSet request = new HeaderSet(); request.setHeader(HeaderSet.TARGET, WRONG_UUID); HeaderSet reply = new HeaderSet(); assertThat(mServer.onConnect(request, reply)) .isEqualTo(ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE); } @Test public void testOnConnect_whenIoExceptionIsThrownFromSettingWhoHeader() throws Exception { HeaderSet request = new HeaderSet(); request.setHeader(HeaderSet.TARGET, PBAP_TARGET_UUID); HeaderSet reply = new HeaderSet(); doThrow(IOException.class).when(mPbapMethodProxy) .setHeader(eq(reply), eq(HeaderSet.WHO), any()); assertThat(mServer.onConnect(request, reply)) .isEqualTo(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR); } @Test public void testOnConnect_whenIoExceptionIsThrownFromSettingTargetHeader() throws Exception { HeaderSet request = new HeaderSet(); byte[] whoHeader = new byte[] {0x00, 0x01, 0x02}; request.setHeader(HeaderSet.WHO, whoHeader); request.setHeader(HeaderSet.TARGET, PBAP_TARGET_UUID); HeaderSet reply = new HeaderSet(); doThrow(IOException.class).when(mPbapMethodProxy) .setHeader(eq(reply), eq(HeaderSet.TARGET), any()); assertThat(mServer.onConnect(request, reply)) .isEqualTo(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR); } @Test public void testOnConnect_whenIoExceptionIsThrownFromGettingApplicationParameterHeader() throws Exception { HeaderSet request = new HeaderSet(); request.setHeader(HeaderSet.TARGET, PBAP_TARGET_UUID); HeaderSet reply = new HeaderSet(); doThrow(IOException.class).when(mPbapMethodProxy) .getHeader(request, HeaderSet.APPLICATION_PARAMETER); assertThat(mServer.onConnect(request, reply)) .isEqualTo(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR); } @Test public void testOnConnect_whenApplicationParameterIsWrong() { HeaderSet request = new HeaderSet(); request.setHeader(HeaderSet.TARGET, PBAP_TARGET_UUID); HeaderSet reply = new HeaderSet(); byte[] badApplicationParameter = new byte[] {0x00, 0x01, 0x02}; request.setHeader(HeaderSet.APPLICATION_PARAMETER, badApplicationParameter); assertThat(mServer.onConnect(request, reply)) .isEqualTo(ResponseCodes.OBEX_HTTP_BAD_REQUEST); } @Test public void testOnConnect_success() { HeaderSet request = new HeaderSet(); request.setHeader(HeaderSet.TARGET, PBAP_TARGET_UUID); HeaderSet reply = new HeaderSet(); assertThat(mServer.onConnect(request, reply)).isEqualTo(ResponseCodes.OBEX_HTTP_OK); } @Test public void testOnDisconnect() throws Exception { HeaderSet request = new HeaderSet(); HeaderSet response = new HeaderSet(); mServer.onDisconnect(request, response); assertThat(response.getResponseCode()).isEqualTo(ResponseCodes.OBEX_HTTP_OK); } @Test public void testOnAbort() throws Exception { HeaderSet request = new HeaderSet(); HeaderSet reply = new HeaderSet(); assertThat(mServer.onAbort(request, reply)).isEqualTo(ResponseCodes.OBEX_HTTP_OK); assertThat(mServer.sIsAborted).isTrue(); } @Test public void testOnPut_notSupported() { Operation operation = mock(Operation.class); assertThat(mServer.onPut(operation)).isEqualTo(ResponseCodes.OBEX_HTTP_BAD_REQUEST); } @Test public void testOnDelete_notSupported() { HeaderSet request = new HeaderSet(); HeaderSet reply = new HeaderSet(); assertThat(mServer.onDelete(request, reply)).isEqualTo(ResponseCodes.OBEX_HTTP_BAD_REQUEST); } @Test public void testOnClose() { mServer.onClose(); verify(mMockStateMachine).sendMessage(PbapStateMachine.DISCONNECT); } @Test public void testCloseStream_success() throws Exception{ OutputStream outputStream = mock(OutputStream.class); Operation operation = mock(Operation.class); assertThat(BluetoothPbapObexServer.closeStream(outputStream, operation)).isTrue(); verify(outputStream).close(); verify(operation).close(); } @Test public void testCloseStream_failOnClosingOutputStream() throws Exception { OutputStream outputStream = mock(OutputStream.class); doThrow(IOException.class).when(outputStream).close(); Operation operation = mock(Operation.class); assertThat(BluetoothPbapObexServer.closeStream(outputStream, operation)).isFalse(); } @Test public void testCloseStream_failOnClosingOperation() throws Exception { OutputStream outputStream = mock(OutputStream.class); Operation operation = mock(Operation.class); doThrow(IOException.class).when(operation).close(); assertThat(BluetoothPbapObexServer.closeStream(outputStream, operation)).isFalse(); } @Test public void testOnAuthenticationFailure() { byte[] userName = {0x57, 0x68, 0x79}; try { mServer.onAuthenticationFailure(userName); } catch (Exception ex) { assertWithMessage("Exception should not happen.").fail(); } } @Test public void testLogHeader() throws Exception{ HeaderSet headerSet = new HeaderSet(); try { BluetoothPbapObexServer.logHeader(headerSet); } catch (Exception ex) { assertWithMessage("Exception should not happen.").fail(); } } } system/gd/hci/le_scanning_manager.cc +65 −2 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ #include "module.h" #include "os/handler.h" #include "os/log.h" #include "storage/storage_module.h" namespace bluetooth { namespace hci { Loading Loading @@ -235,12 +236,14 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback hci::HciLayer* hci_layer, hci::Controller* controller, hci::AclManager* acl_manager, hci::VendorSpecificEventManager* vendor_specific_event_manager) { hci::VendorSpecificEventManager* vendor_specific_event_manager, storage::StorageModule* storage_module) { module_handler_ = handler; hci_layer_ = hci_layer; controller_ = controller; acl_manager_ = acl_manager; vendor_specific_event_manager_ = vendor_specific_event_manager; storage_module_ = storage_module; le_address_manager_ = acl_manager->GetLeAddressManager(); le_scanning_interface_ = hci_layer_->GetLeScanningInterface( module_handler_->BindOn(this, &LeScanningManager::impl::handle_scan_results)); Loading Loading @@ -711,6 +714,17 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); } bool is_bonded(Address target_address) { for (auto device : storage_module_->GetBondedDevices()) { if (device.GetAddress() == target_address) { LOG_DEBUG("Addresses match!"); return true; } } LOG_DEBUG("Addresse DON'Ts match!"); return false; } void scan_filter_parameter_setup( ApcfAction action, uint8_t filter_index, AdvertisingFilterParameter advertising_filter_parameter) { if (!is_filter_support_) { Loading @@ -718,6 +732,7 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback return; } auto entry = remove_me_later_map_.find(filter_index); switch (action) { case ApcfAction::ADD: le_scanning_interface_->EnqueueCommand( Loading @@ -740,11 +755,33 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback le_scanning_interface_->EnqueueCommand( LeAdvFilterDeleteFilteringParametersBuilder::Create(filter_index), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); // IRK Scanning if (entry != remove_me_later_map_.end()) { // Don't want to remove for a bonded device if (!is_bonded(entry->second.GetAddress())) { le_address_manager_->RemoveDeviceFromResolvingList( static_cast<PeerAddressType>(entry->second.GetAddressType()), entry->second.GetAddress()); } remove_me_later_map_.erase(filter_index); } break; case ApcfAction::CLEAR: le_scanning_interface_->EnqueueCommand( LeAdvFilterClearFilteringParametersBuilder::Create(), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); // IRK Scanning if (entry != remove_me_later_map_.end()) { // Don't want to remove for a bonded device if (!is_bonded(entry->second.GetAddress())) { le_address_manager_->RemoveDeviceFromResolvingList( static_cast<PeerAddressType>(entry->second.GetAddressType()), entry->second.GetAddress()); } remove_me_later_map_.erase(filter_index); } break; default: LOG_ERROR("Unknown action type: %d", (uint16_t)action); Loading Loading @@ -796,6 +833,8 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback } } std::unordered_map<uint8_t, AddressWithType> remove_me_later_map_; void update_address_filter( ApcfAction action, uint8_t filter_index, Loading Loading @@ -823,14 +862,35 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback action, filter_index, address, ApcfApplicationAddressType::NOT_APPLICABLE), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); if (!is_empty_128bit(irk)) { // If an entry exists for this filter index, replace data because the filter has been // updated. auto entry = remove_me_later_map_.find(filter_index); // IRK Scanning if (entry != remove_me_later_map_.end()) { // Don't want to remove for a bonded device if (!is_bonded(entry->second.GetAddress())) { le_address_manager_->RemoveDeviceFromResolvingList( static_cast<PeerAddressType>(entry->second.GetAddressType()), entry->second.GetAddress()); } remove_me_later_map_.erase(filter_index); } // Now replace it with a new one std::array<uint8_t, 16> empty_irk; le_address_manager_->AddDeviceToResolvingList( static_cast<PeerAddressType>(address_type), address, irk, empty_irk); remove_me_later_map_.emplace(filter_index, AddressWithType(address, static_cast<AddressType>(address_type))); } } else { le_scanning_interface_->EnqueueCommand( LeAdvFilterClearBroadcasterAddressBuilder::Create(filter_index), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); auto entry = remove_me_later_map_.find(filter_index); if (entry != remove_me_later_map_.end()) { // TODO(optedoblivion): If not bonded le_address_manager_->RemoveDeviceFromResolvingList(static_cast<PeerAddressType>(address_type), address); remove_me_later_map_.erase(filter_index); } } } Loading Loading @@ -1444,6 +1504,7 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback hci::Controller* controller_; hci::AclManager* acl_manager_; hci::VendorSpecificEventManager* vendor_specific_event_manager_; storage::StorageModule* storage_module_; hci::LeScanningInterface* le_scanning_interface_; hci::LeAddressManager* le_address_manager_; bool address_manager_registered_ = false; Loading Loading @@ -1502,6 +1563,7 @@ void LeScanningManager::ListDependencies(ModuleList* list) const { list->add<hci::VendorSpecificEventManager>(); list->add<hci::Controller>(); list->add<hci::AclManager>(); list->add<storage::StorageModule>(); } void LeScanningManager::Start() { Loading @@ -1510,7 +1572,8 @@ void LeScanningManager::Start() { GetDependency<hci::HciLayer>(), GetDependency<hci::Controller>(), GetDependency<AclManager>(), GetDependency<VendorSpecificEventManager>()); GetDependency<VendorSpecificEventManager>(), GetDependency<storage::StorageModule>()); } void LeScanningManager::Stop() { Loading Loading
android/app/src/com/android/bluetooth/pbap/BluetoothPbapMethodProxy.java +19 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,9 @@ import android.util.Log; import com.android.bluetooth.Utils; import com.android.internal.annotations.VisibleForTesting; import com.android.obex.HeaderSet; import java.io.IOException; /** * Proxy class for method calls to help with unit testing Loading Loading @@ -63,11 +66,26 @@ public class BluetoothPbapMethodProxy { } /** * Return the result of {@link ContentResolver#query(Uri, String[], String, String[], String)}. * Proxies {@link ContentResolver#query(Uri, String[], String, String[], String)}. */ public Cursor contentResolverQuery(ContentResolver contentResolver, final Uri contentUri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder) { return contentResolver.query(contentUri, projection, selection, selectionArgs, sortOrder); } /** * Proxies {@link HeaderSet#setHeader}. */ public void setHeader(HeaderSet headerSet, int headerId, Object headerValue) throws IOException { headerSet.setHeader(headerId, headerValue); } /** * Proxies {@link HeaderSet#getHeader}. */ public Object getHeader(HeaderSet headerSet, int headerId) throws IOException { return headerSet.getHeader(headerId); } }
android/app/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java +9 −5 Original line number Diff line number Diff line Loading @@ -223,6 +223,8 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { private PbapStateMachine mStateMachine; private BluetoothPbapMethodProxy mPbapMethodProxy; private enum ContactsType { TYPE_PHONEBOOK , TYPE_SIM ; } Loading Loading @@ -251,6 +253,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { mVcardManager = new BluetoothPbapVcardManager(mContext); mVcardSimManager = new BluetoothPbapSimVcardManager(mContext); mStateMachine = stateMachine; mPbapMethodProxy = BluetoothPbapMethodProxy.getInstance(); } @Override Loading @@ -260,7 +263,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { } notifyUpdateWakeLock(); try { byte[] uuid = (byte[]) request.getHeader(HeaderSet.TARGET); byte[] uuid = (byte[]) mPbapMethodProxy.getHeader(request, HeaderSet.TARGET); if (uuid == null) { return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE; } Loading @@ -278,19 +281,19 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE; } } reply.setHeader(HeaderSet.WHO, uuid); mPbapMethodProxy.setHeader(reply, HeaderSet.WHO, uuid); } catch (IOException e) { Log.e(TAG, e.toString()); return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; } try { byte[] remote = (byte[]) request.getHeader(HeaderSet.WHO); byte[] remote = (byte[]) mPbapMethodProxy.getHeader(request, HeaderSet.WHO); if (remote != null) { if (D) { Log.d(TAG, "onConnect(): remote=" + Arrays.toString(remote)); } reply.setHeader(HeaderSet.TARGET, remote); mPbapMethodProxy.setHeader(reply, HeaderSet.TARGET, remote); } } catch (IOException e) { Log.e(TAG, e.toString()); Loading @@ -300,7 +303,8 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { try { byte[] appParam = null; mConnAppParamValue = new AppParamValue(); appParam = (byte[]) request.getHeader(HeaderSet.APPLICATION_PARAMETER); appParam = (byte[]) mPbapMethodProxy.getHeader(request, HeaderSet.APPLICATION_PARAMETER); if ((appParam != null) && !parseApplicationParameter(appParam, mConnAppParamValue)) { return ResponseCodes.OBEX_HTTP_BAD_REQUEST; } Loading
android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapObexServerTest.java 0 → 100644 +299 −0 Original line number Diff line number Diff line /* * Copyright 2022 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.bluetooth.pbap; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import android.os.Handler; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.obex.HeaderSet; import com.android.obex.Operation; import com.android.obex.ResponseCodes; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; import java.io.IOException; import java.io.OutputStream; @SmallTest @RunWith(AndroidJUnit4.class) public class BluetoothPbapObexServerTest { @Mock Handler mMockHandler; @Mock PbapStateMachine mMockStateMachine; @Spy BluetoothPbapMethodProxy mPbapMethodProxy = BluetoothPbapMethodProxy.getInstance(); BluetoothPbapObexServer mServer; // 128 bit UUID for PBAP private static final byte[] PBAP_TARGET_UUID = new byte[] { 0x79, 0x61, 0x35, (byte) 0xf0, (byte) 0xf0, (byte) 0xc5, 0x11, (byte) 0xd8, 0x09, 0x66, 0x08, 0x00, 0x20, 0x0c, (byte) 0x9a, 0x66 }; private static final byte[] WRONG_UUID = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; private static final byte[] WRONG_LENGTH_UUID = new byte[] { 0x79, 0x61, 0x35, }; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); BluetoothPbapMethodProxy.setInstanceForTesting(mPbapMethodProxy); mServer = new BluetoothPbapObexServer( mMockHandler, InstrumentationRegistry.getTargetContext(), mMockStateMachine); } @After public void tearDown() throws Exception { BluetoothPbapMethodProxy.setInstanceForTesting(null); } @Test public void testOnConnect_whenUuidIsNull() { // Create an empty header set. HeaderSet request = new HeaderSet(); HeaderSet reply = new HeaderSet(); assertThat(mServer.onConnect(request, reply)) .isEqualTo(ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE); } @Test public void testOnConnect_whenUuidLengthIsWrong() { HeaderSet request = new HeaderSet(); request.setHeader(HeaderSet.TARGET, WRONG_LENGTH_UUID); HeaderSet reply = new HeaderSet(); assertThat(mServer.onConnect(request, reply)) .isEqualTo(ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE); } @Test public void testOnConnect_whenUuidIsWrong() { HeaderSet request = new HeaderSet(); request.setHeader(HeaderSet.TARGET, WRONG_UUID); HeaderSet reply = new HeaderSet(); assertThat(mServer.onConnect(request, reply)) .isEqualTo(ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE); } @Test public void testOnConnect_whenIoExceptionIsThrownFromSettingWhoHeader() throws Exception { HeaderSet request = new HeaderSet(); request.setHeader(HeaderSet.TARGET, PBAP_TARGET_UUID); HeaderSet reply = new HeaderSet(); doThrow(IOException.class).when(mPbapMethodProxy) .setHeader(eq(reply), eq(HeaderSet.WHO), any()); assertThat(mServer.onConnect(request, reply)) .isEqualTo(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR); } @Test public void testOnConnect_whenIoExceptionIsThrownFromSettingTargetHeader() throws Exception { HeaderSet request = new HeaderSet(); byte[] whoHeader = new byte[] {0x00, 0x01, 0x02}; request.setHeader(HeaderSet.WHO, whoHeader); request.setHeader(HeaderSet.TARGET, PBAP_TARGET_UUID); HeaderSet reply = new HeaderSet(); doThrow(IOException.class).when(mPbapMethodProxy) .setHeader(eq(reply), eq(HeaderSet.TARGET), any()); assertThat(mServer.onConnect(request, reply)) .isEqualTo(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR); } @Test public void testOnConnect_whenIoExceptionIsThrownFromGettingApplicationParameterHeader() throws Exception { HeaderSet request = new HeaderSet(); request.setHeader(HeaderSet.TARGET, PBAP_TARGET_UUID); HeaderSet reply = new HeaderSet(); doThrow(IOException.class).when(mPbapMethodProxy) .getHeader(request, HeaderSet.APPLICATION_PARAMETER); assertThat(mServer.onConnect(request, reply)) .isEqualTo(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR); } @Test public void testOnConnect_whenApplicationParameterIsWrong() { HeaderSet request = new HeaderSet(); request.setHeader(HeaderSet.TARGET, PBAP_TARGET_UUID); HeaderSet reply = new HeaderSet(); byte[] badApplicationParameter = new byte[] {0x00, 0x01, 0x02}; request.setHeader(HeaderSet.APPLICATION_PARAMETER, badApplicationParameter); assertThat(mServer.onConnect(request, reply)) .isEqualTo(ResponseCodes.OBEX_HTTP_BAD_REQUEST); } @Test public void testOnConnect_success() { HeaderSet request = new HeaderSet(); request.setHeader(HeaderSet.TARGET, PBAP_TARGET_UUID); HeaderSet reply = new HeaderSet(); assertThat(mServer.onConnect(request, reply)).isEqualTo(ResponseCodes.OBEX_HTTP_OK); } @Test public void testOnDisconnect() throws Exception { HeaderSet request = new HeaderSet(); HeaderSet response = new HeaderSet(); mServer.onDisconnect(request, response); assertThat(response.getResponseCode()).isEqualTo(ResponseCodes.OBEX_HTTP_OK); } @Test public void testOnAbort() throws Exception { HeaderSet request = new HeaderSet(); HeaderSet reply = new HeaderSet(); assertThat(mServer.onAbort(request, reply)).isEqualTo(ResponseCodes.OBEX_HTTP_OK); assertThat(mServer.sIsAborted).isTrue(); } @Test public void testOnPut_notSupported() { Operation operation = mock(Operation.class); assertThat(mServer.onPut(operation)).isEqualTo(ResponseCodes.OBEX_HTTP_BAD_REQUEST); } @Test public void testOnDelete_notSupported() { HeaderSet request = new HeaderSet(); HeaderSet reply = new HeaderSet(); assertThat(mServer.onDelete(request, reply)).isEqualTo(ResponseCodes.OBEX_HTTP_BAD_REQUEST); } @Test public void testOnClose() { mServer.onClose(); verify(mMockStateMachine).sendMessage(PbapStateMachine.DISCONNECT); } @Test public void testCloseStream_success() throws Exception{ OutputStream outputStream = mock(OutputStream.class); Operation operation = mock(Operation.class); assertThat(BluetoothPbapObexServer.closeStream(outputStream, operation)).isTrue(); verify(outputStream).close(); verify(operation).close(); } @Test public void testCloseStream_failOnClosingOutputStream() throws Exception { OutputStream outputStream = mock(OutputStream.class); doThrow(IOException.class).when(outputStream).close(); Operation operation = mock(Operation.class); assertThat(BluetoothPbapObexServer.closeStream(outputStream, operation)).isFalse(); } @Test public void testCloseStream_failOnClosingOperation() throws Exception { OutputStream outputStream = mock(OutputStream.class); Operation operation = mock(Operation.class); doThrow(IOException.class).when(operation).close(); assertThat(BluetoothPbapObexServer.closeStream(outputStream, operation)).isFalse(); } @Test public void testOnAuthenticationFailure() { byte[] userName = {0x57, 0x68, 0x79}; try { mServer.onAuthenticationFailure(userName); } catch (Exception ex) { assertWithMessage("Exception should not happen.").fail(); } } @Test public void testLogHeader() throws Exception{ HeaderSet headerSet = new HeaderSet(); try { BluetoothPbapObexServer.logHeader(headerSet); } catch (Exception ex) { assertWithMessage("Exception should not happen.").fail(); } } }
system/gd/hci/le_scanning_manager.cc +65 −2 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ #include "module.h" #include "os/handler.h" #include "os/log.h" #include "storage/storage_module.h" namespace bluetooth { namespace hci { Loading Loading @@ -235,12 +236,14 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback hci::HciLayer* hci_layer, hci::Controller* controller, hci::AclManager* acl_manager, hci::VendorSpecificEventManager* vendor_specific_event_manager) { hci::VendorSpecificEventManager* vendor_specific_event_manager, storage::StorageModule* storage_module) { module_handler_ = handler; hci_layer_ = hci_layer; controller_ = controller; acl_manager_ = acl_manager; vendor_specific_event_manager_ = vendor_specific_event_manager; storage_module_ = storage_module; le_address_manager_ = acl_manager->GetLeAddressManager(); le_scanning_interface_ = hci_layer_->GetLeScanningInterface( module_handler_->BindOn(this, &LeScanningManager::impl::handle_scan_results)); Loading Loading @@ -711,6 +714,17 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); } bool is_bonded(Address target_address) { for (auto device : storage_module_->GetBondedDevices()) { if (device.GetAddress() == target_address) { LOG_DEBUG("Addresses match!"); return true; } } LOG_DEBUG("Addresse DON'Ts match!"); return false; } void scan_filter_parameter_setup( ApcfAction action, uint8_t filter_index, AdvertisingFilterParameter advertising_filter_parameter) { if (!is_filter_support_) { Loading @@ -718,6 +732,7 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback return; } auto entry = remove_me_later_map_.find(filter_index); switch (action) { case ApcfAction::ADD: le_scanning_interface_->EnqueueCommand( Loading @@ -740,11 +755,33 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback le_scanning_interface_->EnqueueCommand( LeAdvFilterDeleteFilteringParametersBuilder::Create(filter_index), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); // IRK Scanning if (entry != remove_me_later_map_.end()) { // Don't want to remove for a bonded device if (!is_bonded(entry->second.GetAddress())) { le_address_manager_->RemoveDeviceFromResolvingList( static_cast<PeerAddressType>(entry->second.GetAddressType()), entry->second.GetAddress()); } remove_me_later_map_.erase(filter_index); } break; case ApcfAction::CLEAR: le_scanning_interface_->EnqueueCommand( LeAdvFilterClearFilteringParametersBuilder::Create(), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); // IRK Scanning if (entry != remove_me_later_map_.end()) { // Don't want to remove for a bonded device if (!is_bonded(entry->second.GetAddress())) { le_address_manager_->RemoveDeviceFromResolvingList( static_cast<PeerAddressType>(entry->second.GetAddressType()), entry->second.GetAddress()); } remove_me_later_map_.erase(filter_index); } break; default: LOG_ERROR("Unknown action type: %d", (uint16_t)action); Loading Loading @@ -796,6 +833,8 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback } } std::unordered_map<uint8_t, AddressWithType> remove_me_later_map_; void update_address_filter( ApcfAction action, uint8_t filter_index, Loading Loading @@ -823,14 +862,35 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback action, filter_index, address, ApcfApplicationAddressType::NOT_APPLICABLE), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); if (!is_empty_128bit(irk)) { // If an entry exists for this filter index, replace data because the filter has been // updated. auto entry = remove_me_later_map_.find(filter_index); // IRK Scanning if (entry != remove_me_later_map_.end()) { // Don't want to remove for a bonded device if (!is_bonded(entry->second.GetAddress())) { le_address_manager_->RemoveDeviceFromResolvingList( static_cast<PeerAddressType>(entry->second.GetAddressType()), entry->second.GetAddress()); } remove_me_later_map_.erase(filter_index); } // Now replace it with a new one std::array<uint8_t, 16> empty_irk; le_address_manager_->AddDeviceToResolvingList( static_cast<PeerAddressType>(address_type), address, irk, empty_irk); remove_me_later_map_.emplace(filter_index, AddressWithType(address, static_cast<AddressType>(address_type))); } } else { le_scanning_interface_->EnqueueCommand( LeAdvFilterClearBroadcasterAddressBuilder::Create(filter_index), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); auto entry = remove_me_later_map_.find(filter_index); if (entry != remove_me_later_map_.end()) { // TODO(optedoblivion): If not bonded le_address_manager_->RemoveDeviceFromResolvingList(static_cast<PeerAddressType>(address_type), address); remove_me_later_map_.erase(filter_index); } } } Loading Loading @@ -1444,6 +1504,7 @@ struct LeScanningManager::impl : public bluetooth::hci::LeAddressManagerCallback hci::Controller* controller_; hci::AclManager* acl_manager_; hci::VendorSpecificEventManager* vendor_specific_event_manager_; storage::StorageModule* storage_module_; hci::LeScanningInterface* le_scanning_interface_; hci::LeAddressManager* le_address_manager_; bool address_manager_registered_ = false; Loading Loading @@ -1502,6 +1563,7 @@ void LeScanningManager::ListDependencies(ModuleList* list) const { list->add<hci::VendorSpecificEventManager>(); list->add<hci::Controller>(); list->add<hci::AclManager>(); list->add<storage::StorageModule>(); } void LeScanningManager::Start() { Loading @@ -1510,7 +1572,8 @@ void LeScanningManager::Start() { GetDependency<hci::HciLayer>(), GetDependency<hci::Controller>(), GetDependency<AclManager>(), GetDependency<VendorSpecificEventManager>()); GetDependency<VendorSpecificEventManager>(), GetDependency<storage::StorageModule>()); } void LeScanningManager::Stop() { Loading