/* * Copyright (C) 2024 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. */ #include #include #include #include #include #include #include #include #include #include #include using ::aidl::android::hardware::bluetooth::socket::BnBluetoothSocketCallback; using ::aidl::android::hardware::bluetooth::socket::IBluetoothSocket; using ::aidl::android::hardware::bluetooth::socket::SocketCapabilities; using ::aidl::android::hardware::bluetooth::socket::SocketContext; using ::ndk::ScopedAStatus; namespace { constexpr static int kCallbackTimeoutMs = 250; constexpr static int kOpenedCallbackTimeoutMs = 5000; } // namespace class BluetoothSocketCallback : public BnBluetoothSocketCallback { public: BluetoothSocketCallback( const std::function< void(int64_t in_socketId, ::aidl::android::hardware::bluetooth::socket::Status in_status, const std::string& in_reason)>& on_hal_opened_complete_cb) : on_hal_opened_complete_cb_(on_hal_opened_complete_cb) {} ScopedAStatus openedComplete( int64_t in_socketId, ::aidl::android::hardware::bluetooth::socket::Status in_status, const std::string& in_reason) override { on_hal_opened_complete_cb_(in_socketId, in_status, in_reason); return ::ndk::ScopedAStatus::ok(); } ScopedAStatus close(int64_t /* in_socketId */, const std::string& /* in_reason */) override { return ::ndk::ScopedAStatus::ok(); } private: std::function on_hal_opened_complete_cb_; }; class BluetoothSocketTest : public ::testing::TestWithParam { public: virtual void SetUp() override { ALOGI("SetUp Socket Test"); bluetooth_socket_ = IBluetoothSocket::fromBinder( ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str()))); ASSERT_NE(bluetooth_socket_, nullptr); } virtual void TearDown() override { ALOGI("TearDown Socket Test"); bluetooth_socket_ = nullptr; ASSERT_EQ(bluetooth_socket_, nullptr); } std::shared_ptr bluetooth_socket_; }; TEST_P(BluetoothSocketTest, registerCallback) { std::promise open_cb_promise; std::future open_cb_future{open_cb_promise.get_future()}; std::shared_ptr callback = ndk::SharedRefBase::make( [&open_cb_promise](auto /* socket_id */, auto /* status */, auto /* reason */) { open_cb_promise.set_value(); }); ScopedAStatus status = bluetooth_socket_->registerCallback(callback); ASSERT_TRUE(status.isOk()); } TEST_P(BluetoothSocketTest, GetSocketCapabilities) { SocketCapabilities socket_capabilities; ScopedAStatus status = bluetooth_socket_->getSocketCapabilities(&socket_capabilities); ASSERT_TRUE(status.isOk()); ASSERT_TRUE(socket_capabilities.leCocCapabilities.numberOfSupportedSockets >= 0); if (socket_capabilities.leCocCapabilities.numberOfSupportedSockets) { // When LE COC is supported, the local MTU must be configured within the // valid range defined in the L2CAP specification. ASSERT_TRUE(socket_capabilities.leCocCapabilities.mtu >= 23 && socket_capabilities.leCocCapabilities.mtu <= 65535); } ASSERT_TRUE(socket_capabilities.rfcommCapabilities.numberOfSupportedSockets >= 0); if (socket_capabilities.rfcommCapabilities.numberOfSupportedSockets) { // When RFCOMM is supported, the maximum frame size must be configured // within the valid range defined in the RFCOMM specification. ASSERT_TRUE(socket_capabilities.rfcommCapabilities.maxFrameSize >= 23 && socket_capabilities.rfcommCapabilities.maxFrameSize <= 32767); } } TEST_P(BluetoothSocketTest, Opened) { std::promise open_cb_promise; std::future open_cb_future{open_cb_promise.get_future()}; std::shared_ptr callback = ndk::SharedRefBase::make( [&open_cb_promise](auto /* socket_id */, auto /* status */, auto /* reason */) { open_cb_promise.set_value(); }); bluetooth_socket_->registerCallback(callback); SocketCapabilities socket_capabilities; bluetooth_socket_->getSocketCapabilities(&socket_capabilities); SocketContext socket_context; ScopedAStatus status = bluetooth_socket_->opened(socket_context); std::chrono::milliseconds timeout{kOpenedCallbackTimeoutMs}; if (status.isOk()) { // If IBluetoothSocket.opened() returns success, the callback // BluetoothSocketCallback.openedComplete() must be called within the // timeout. EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready); } else { // If IBluetoothSocket.opened() returns failure, the callback // BluetoothSocketCallback.openedComplete() must not be called. EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::timeout); } } TEST_P(BluetoothSocketTest, Closed) { std::promise open_cb_promise; std::future open_cb_future{open_cb_promise.get_future()}; std::shared_ptr callback = ndk::SharedRefBase::make( [&open_cb_promise](auto /* socket_id */, auto /* status */, auto /* reason */) { open_cb_promise.set_value(); }); bluetooth_socket_->registerCallback(callback); SocketCapabilities socket_capabilities; bluetooth_socket_->getSocketCapabilities(&socket_capabilities); long socket_id = 1; bluetooth_socket_->closed(socket_id); } GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BluetoothSocketTest); INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothSocketTest, testing::ValuesIn(android::getAidlHalInstanceNames( IBluetoothSocket::descriptor)), android::PrintInstanceNameToString); int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); ABinderProcess_startThreadPool(); int status = RUN_ALL_TESTS(); ALOGI("Test result = %d", status); return status; }