diff --git a/bundle.json b/bundle.json index b77272fde39fbdb7b3a2706a22abc0d35b93e814..100865c57157e08d8fcad18ff4be471f114186d1 100644 --- a/bundle.json +++ b/bundle.json @@ -221,6 +221,27 @@ "header_files": [] }, "name": "//foundation/communication/bluetooth/frameworks/cj/connection:cj_bluetooth_connection_ffi" + }, + { + "header": { + "header_base": "//foundation/communication/bluetooth/frameworks/cj/hfp/include", + "header_files": [] + }, + "name": "//foundation/communication/bluetooth/frameworks/cj/hfp:cj_bluetooth_hfp_ffi" + }, + { + "header": { + "header_base": "//foundation/communication/bluetooth/frameworks/cj/hid/include", + "header_files": [] + }, + "name": "//foundation/communication/bluetooth/frameworks/cj/hid:cj_bluetooth_hid_ffi" + }, + { + "header": { + "header_base": "//foundation/communication/bluetooth/frameworks/cj/socket/include", + "header_files": [] + }, + "name": "//foundation/communication/bluetooth/frameworks/cj/socket:cj_bluetooth_socket_ffi" } ] } diff --git a/frameworks/cj/BUILD.gn b/frameworks/cj/BUILD.gn index d31cef2a49e9f9e0bbec94b40118b572819eb291..af4d3c911163811a9c2980fa1e8af9b5a6eeab4c 100644 --- a/frameworks/cj/BUILD.gn +++ b/frameworks/cj/BUILD.gn @@ -19,5 +19,8 @@ group("bluetooth_ffi") { "$SUBSYSTEM_DIR/bluetooth/frameworks/cj/access:cj_bluetooth_access_ffi", "$SUBSYSTEM_DIR/bluetooth/frameworks/cj/ble:cj_bluetooth_ble_ffi", "$SUBSYSTEM_DIR/bluetooth/frameworks/cj/connection:cj_bluetooth_connection_ffi", + "$SUBSYSTEM_DIR/bluetooth/frameworks/cj/hfp:cj_bluetooth_hfp_ffi", + "$SUBSYSTEM_DIR/bluetooth/frameworks/cj/hid:cj_bluetooth_hid_ffi", + "$SUBSYSTEM_DIR/bluetooth/frameworks/cj/socket:cj_bluetooth_socket_ffi", ] } diff --git a/frameworks/cj/hfp/BUILD.gn b/frameworks/cj/hfp/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..de30240c7bc60b0bfdf77a82636e657200f3542c --- /dev/null +++ b/frameworks/cj/hfp/BUILD.gn @@ -0,0 +1,69 @@ +# Copyright (C) 2025 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") + +ohos_shared_library("cj_bluetooth_hfp_ffi") { + branch_protector_ret = "pac_ret" # Enable PAC CFI + sanitize = { + cfi = true # Enable/disable control flow integrity detection + boundary_sanitize = true # Enable boundary san detection + cfi_cross_dso = true # Cross-SO CFI Checks + integer_overflow = true # Enable integer overflow detection + ubsan = true # Enable some Ubsan options + debug = false + } + + if (!defined(defines)) { + defines = [] + } + include_dirs = [ + "include", + "../../js/napi/include", + "../../../frameworks/inner/include", + ] + + deps = [ + "../../../frameworks/inner:btframework", + "../../../frameworks/js/napi/src/common:bt_napi_common", + ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_single", + "napi:ace_napi", + "napi:cj_bind_ffi", + "napi:cj_bind_native", + ] + + sources = [ + "src/bluetooth_hfp_ag_impl.cpp", + "src/bluetooth_hfp_ffi.cpp", + "src/bluetooth_hfp_hf_observer_impl.cpp", + "src/bluetooth_hfp_utils.cpp", + ] + + if (is_ohos) { + defines += [ "OHOS_PLATFORM" ] + } + + if (is_mingw) { + defines += [ "WINDOWS_PLATFORM" ] + } + + innerapi_tags = [ "platformsdk" ] + + part_name = "bluetooth" + subsystem_name = "communication" +} diff --git a/frameworks/cj/hfp/include/bluetooth_hfp_ag_impl.h b/frameworks/cj/hfp/include/bluetooth_hfp_ag_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..fe49fc6aa57085659a8801cb869ab0aab1f663f2 --- /dev/null +++ b/frameworks/cj/hfp/include/bluetooth_hfp_ag_impl.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef BLUETOOTH_HFP_AG_IMPL_H +#define BLUETOOTH_HFP_AG_IMPL_H + +#include "bluetooth_hfp_ag.h" +#include "bluetooth_hfp_hf_observer_impl.h" +#include "cj_common_ffi.h" +#include "ffi_remote_data.h" + +namespace OHOS { +namespace Bluetooth { +class HandsFreeAudioGatewayImpl : public OHOS::FFI::FFIData { + DECL_TYPE(HandsFreeAudioGatewayImpl, OHOS::FFI::FFIData) +public: + explicit HandsFreeAudioGatewayImpl() {}; + ~HandsFreeAudioGatewayImpl() {}; + static CArrString GetConnectionDevices(int32_t* errCode); + static int32_t GetConnectionState(char* device, int32_t* errCode); + static void On(int32_t type, int64_t id, int32_t* errCode); + static std::shared_ptr observer_; + static bool isRegistered_; +}; + +} // namespace Bluetooth +} // namespace OHOS +#endif /* BLUETOOTH_HFP_AG_IMPL_H */ \ No newline at end of file diff --git a/frameworks/cj/hfp/include/bluetooth_hfp_ffi.h b/frameworks/cj/hfp/include/bluetooth_hfp_ffi.h new file mode 100644 index 0000000000000000000000000000000000000000..3188d4f565ed3e4a06b8cc05f1660d1991c51c00 --- /dev/null +++ b/frameworks/cj/hfp/include/bluetooth_hfp_ffi.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef BLUETOOTH_HFP_FFI_H +#define BLUETOOTH_HFP_FFI_H + +#include "cj_common_ffi.h" + +extern "C" { +FFI_EXPORT CArrString FfiBluetoothHfpGetConnectedDevices(int32_t* errCode); +FFI_EXPORT int32_t FfiBluetoothHfpGetConnectionState(char* device, int32_t* errCode); +FFI_EXPORT void FfiBluetoothHfpOn(int32_t type, int64_t id, int32_t* errCode); +} + +#endif diff --git a/frameworks/cj/hfp/include/bluetooth_hfp_hf_observer_impl.h b/frameworks/cj/hfp/include/bluetooth_hfp_hf_observer_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..1a08934a8aeca73446d13068439eb20616e622a1 --- /dev/null +++ b/frameworks/cj/hfp/include/bluetooth_hfp_hf_observer_impl.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef BLUETOOTH_HFP_HF_OBSERVER_IMPL_H +#define BLUETOOTH_HFP_HF_OBSERVER_IMPL_H + +#include + +#include "bluetooth_hfp_ag.h" +#include "bluetooth_hfp_utils.h" +#include "ffi_remote_data.h" + +namespace OHOS { +namespace Bluetooth { +const char* const STR_BT_HANDS_FREE_UNIT_OBSERVER_CONNECTION_STATE_CHANGE = "connectionStateChange"; + +class HandsFreeUnitObserverImpl : public HandsFreeAudioGatewayObserver, public OHOS::FFI::FFIData { + DECL_TYPE(HandsFreeUnitObserverImpl, OHOS::FFI::FFIData); + +public: + HandsFreeUnitObserverImpl() {}; + ~HandsFreeUnitObserverImpl() override = default; + void RegisterStateChangeFunc(std::function cjCallback); + void OnConnectionStateChanged(const BluetoothRemoteDevice& device, int state, int cause) override; + void OnScoStateChanged(const BluetoothRemoteDevice& device, int state, int reason = 0) override {}; + + void OnActiveDeviceChanged(const BluetoothRemoteDevice& device) override {} + void OnHfEnhancedDriverSafetyChanged(const BluetoothRemoteDevice& device, int indValue) override {} + void OnHfpStackChanged(const BluetoothRemoteDevice& device, int action) override {} + +private: + std::function stateChangeFunc { nullptr }; +}; + +} // namespace Bluetooth +} // namespace OHOS +#endif /* BLUETOOTH_HFP_HF_OBSERVER_IMPL_H */ \ No newline at end of file diff --git a/frameworks/cj/hfp/include/bluetooth_hfp_utils.h b/frameworks/cj/hfp/include/bluetooth_hfp_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..adbab5ad3d338bb534ae4b4c1b5a9119c07b99b2 --- /dev/null +++ b/frameworks/cj/hfp/include/bluetooth_hfp_utils.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef BLUETOOTH_HFP_UTILS_H +#define BLUETOOTH_HFP_UTILS_H + +#include + +namespace OHOS { +namespace Bluetooth { +char* MallocCString(const std::string& origin); + +struct StateChangeParam { + char* deviceId; + int32_t state; + int32_t cause; +}; +} // namespace Bluetooth +} // namespace OHOS + +#endif // BLUETOOTH_HFP_UTILS_H \ No newline at end of file diff --git a/frameworks/cj/hfp/src/bluetooth_hfp_ag_impl.cpp b/frameworks/cj/hfp/src/bluetooth_hfp_ag_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8ee904f759c1654d6b460f4f475c74f5d7dbec8a --- /dev/null +++ b/frameworks/cj/hfp/src/bluetooth_hfp_ag_impl.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * 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. + */ +#ifndef LOG_TAG +#define LOG_TAG "bt_cj_hfp_ag" +#endif + +#include "bluetooth_hfp_ag_impl.h" + +#include + +#include "bluetooth_errorcode.h" +#include "bluetooth_utils.h" +#include "cj_lambda.h" +#include "napi_bluetooth_utils.h" + +using namespace OHOS::FFI; + +namespace OHOS { +namespace Bluetooth { +std::shared_ptr HandsFreeAudioGatewayImpl::observer_ = + std::make_shared(); +bool HandsFreeAudioGatewayImpl::isRegistered_ = false; + +CArrString HandsFreeAudioGatewayImpl::GetConnectionDevices(int32_t* errCode) +{ + HILOGD("enter"); + HandsFreeAudioGateway* profile = HandsFreeAudioGateway::GetProfile(); + if (profile == nullptr) { + HILOGE("profile is nullptr."); + *errCode = BT_ERR_INTERNAL_ERROR; + return CArrString { 0 }; + } + std::vector devices; + int errorCode = profile->GetConnectedDevices(devices); + if (errorCode != BT_NO_ERROR) { + HILOGE("bluetooth assert failed."); + *errCode = static_cast(errorCode); + return CArrString { 0 }; + } + if (devices.size() <= 0) { + return CArrString { 0 }; + } + char** deviceVector = static_cast(malloc(sizeof(char*) * devices.size())); + if (deviceVector == nullptr) { + HILOGE("deviceVector malloc failed."); + *errCode = BT_ERR_INTERNAL_ERROR; + return CArrString { 0 }; + } + int64_t i = 0; + for (auto& device : devices) { + deviceVector[i] = MallocCString(device.GetDeviceAddr()); + i++; + } + CArrString ret = CArrString { .head = deviceVector, .size = i }; + return ret; +} + +int32_t HandsFreeAudioGatewayImpl::GetConnectionState(char* device, int32_t* errCode) +{ + HILOGD("enter"); + int32_t profileState = ProfileConnectionState::STATE_DISCONNECTED; + std::string remoteAddr = device; + if (!IsValidAddress(remoteAddr)) { + HILOGE("Invalid addr"); + *errCode = static_cast(BT_ERR_INVALID_PARAM); + return profileState; + } + HandsFreeAudioGateway* profile = HandsFreeAudioGateway::GetProfile(); + if (profile == nullptr) { + HILOGE("profile is nullptr."); + *errCode = BT_ERR_INTERNAL_ERROR; + return profileState; + } + BluetoothRemoteDevice remoteDevice(remoteAddr, BT_TRANSPORT_BREDR); + int32_t state = static_cast(BTConnectState::DISCONNECTED); + int32_t errorCode = profile->GetDeviceState(remoteDevice, state); + if (errorCode != BT_NO_ERROR) { + HILOGE("bluetooth assert failed."); + *errCode = errorCode; + return profileState; + } + profileState = GetProfileConnectionState(state); + return profileState; +} + +void HandsFreeAudioGatewayImpl::On(int32_t type, int64_t id, int32_t* errCode) +{ + if (observer_) { + auto observerFunc = CJLambda::Create(reinterpret_cast(id)); + if (!observerFunc) { + HILOGE("Register state change event failed"); + *errCode = BT_ERR_INVALID_PARAM; + return; + } + observer_->RegisterStateChangeFunc(observerFunc); + } + + if (!isRegistered_) { + HandsFreeAudioGateway* profile = HandsFreeAudioGateway::GetProfile(); + if (profile == nullptr) { + HILOGE("profile is nullptr."); + *errCode = BT_ERR_INVALID_PARAM; + return; + } + profile->RegisterObserver(observer_); + isRegistered_ = true; + } + return; +} +} // namespace Bluetooth +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/cj/hfp/src/bluetooth_hfp_ffi.cpp b/frameworks/cj/hfp/src/bluetooth_hfp_ffi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..db56b343ca0b383f95ea2726dd62f67699ffc83d --- /dev/null +++ b/frameworks/cj/hfp/src/bluetooth_hfp_ffi.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * 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. + */ +#ifndef LOG_TAG +#define LOG_TAG "bt_cj_hfp_ffi" +#endif + +#include "bluetooth_hfp_ffi.h" + +#include "bluetooth_hfp_ag_impl.h" + +using namespace OHOS::FFI; + +namespace OHOS { +namespace Bluetooth { +extern "C" { +CArrString FfiBluetoothHfpGetConnectedDevices(int32_t* errCode) +{ + return HandsFreeAudioGatewayImpl::GetConnectionDevices(errCode); +} + +int32_t FfiBluetoothHfpGetConnectionState(char* device, int32_t* errCode) +{ + return HandsFreeAudioGatewayImpl::GetConnectionState(device, errCode); +} + +void FfiBluetoothHfpOn(int32_t type, int64_t id, int32_t* errCode) +{ + HandsFreeAudioGatewayImpl::On(type, id, errCode); +} +} +} // namespace Bluetooth +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/cj/hfp/src/bluetooth_hfp_hf_observer_impl.cpp b/frameworks/cj/hfp/src/bluetooth_hfp_hf_observer_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a9869fa9c081671665378e020fb4043191c37cbe --- /dev/null +++ b/frameworks/cj/hfp/src/bluetooth_hfp_hf_observer_impl.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * 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. + */ +#ifndef LOG_TAG +#define LOG_TAG "bt_cj_hfp_ag_observer" +#endif + +#include "bluetooth_hfp_hf_observer_impl.h" + +#include "bluetooth_log.h" +#include "bluetooth_utils.h" + +namespace OHOS { +namespace Bluetooth { +void HandsFreeUnitObserverImpl::RegisterStateChangeFunc(std::function cjCallback) +{ + stateChangeFunc = cjCallback; +} + +void HandsFreeUnitObserverImpl::OnConnectionStateChanged(const BluetoothRemoteDevice& device, int state, int cause) +{ + HILOGD("enter, remote device address: %{public}s, state: %{public}d, cause: %{public}d", GET_ENCRYPT_ADDR(device), + state, cause); + if (!stateChangeFunc) { + HILOGE("failed to register state change callback"); + return; + } + char* deviceId = MallocCString(device.GetDeviceAddr()); + if (deviceId == nullptr) { + HILOGE("failed to malloc memory"); + return; + } + StateChangeParam param = StateChangeParam { + .deviceId = deviceId, .state = static_cast(state), .cause = static_cast(cause) + }; + stateChangeFunc(param); + free(deviceId); + return; +} +} // namespace Bluetooth +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/cj/hfp/src/bluetooth_hfp_utils.cpp b/frameworks/cj/hfp/src/bluetooth_hfp_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..98fe633351a4913d20c5034a65f0a9d1c65410ec --- /dev/null +++ b/frameworks/cj/hfp/src/bluetooth_hfp_utils.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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 "bluetooth_hfp_utils.h" + +namespace OHOS { +namespace Bluetooth { +char* MallocCString(const std::string& origin) +{ + if (origin.empty()) { + return nullptr; + } + auto len = origin.length() + 1; + char* res = static_cast(malloc(sizeof(char) * len)); + if (res == nullptr) { + return nullptr; + } + return std::char_traits::copy(res, origin.c_str(), len); +} +} // namespace Bluetooth +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/cj/hid/BUILD.gn b/frameworks/cj/hid/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..e4e55ddb62334d08305ef17d74eb631244b8d70d --- /dev/null +++ b/frameworks/cj/hid/BUILD.gn @@ -0,0 +1,69 @@ +# Copyright (C) 2025 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") + +ohos_shared_library("cj_bluetooth_hid_ffi") { + branch_protector_ret = "pac_ret" # Enable PAC CFI + sanitize = { + cfi = true # Enable/disable control flow integrity detection + boundary_sanitize = true # Enable boundary san detection + cfi_cross_dso = true # Cross-SO CFI Checks + integer_overflow = true # Enable integer overflow detection + ubsan = true # Enable some Ubsan options + debug = false + } + + if (!defined(defines)) { + defines = [] + } + include_dirs = [ + "include", + "../../js/napi/include", + "../../../frameworks/inner/include", + ] + + deps = [ + "../../../frameworks/inner:btframework", + "../../../frameworks/js/napi/src/common:bt_napi_common", + ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_single", + "napi:ace_napi", + "napi:cj_bind_ffi", + "napi:cj_bind_native", + ] + + sources = [ + "src/bluetooth_hid_host_ffi.cpp", + "src/bluetooth_hid_host_impl.cpp", + "src/bluetooth_hid_host_observer_impl.cpp", + "src/bluetooth_hid_host_utils.cpp", + ] + + if (is_ohos) { + defines += [ "OHOS_PLATFORM" ] + } + + if (is_mingw) { + defines += [ "WINDOWS_PLATFORM" ] + } + + innerapi_tags = [ "platformsdk" ] + + part_name = "bluetooth" + subsystem_name = "communication" +} diff --git a/frameworks/cj/hid/include/bluetooth_hid_host_ffi.h b/frameworks/cj/hid/include/bluetooth_hid_host_ffi.h new file mode 100644 index 0000000000000000000000000000000000000000..3b41d389daa0e3fed7f6939eef46d223faf149a6 --- /dev/null +++ b/frameworks/cj/hid/include/bluetooth_hid_host_ffi.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef BLUETOOTH_HID_HOST_FFI_H +#define BLUETOOTH_HID_HOST_FFI_H + +#include "cj_common_ffi.h" + +extern "C" { +FFI_EXPORT CArrString FfiBluetoothHidHostGetConnectedDevices(int32_t* errCode); +FFI_EXPORT int32_t FfiBluetoothHidHostGetConnectionState(char* device, int32_t* errCode); +FFI_EXPORT void FfiBluetoothHidHostOn(int32_t type, int64_t id, int32_t* errCode); +} + +#endif diff --git a/frameworks/cj/hid/include/bluetooth_hid_host_impl.h b/frameworks/cj/hid/include/bluetooth_hid_host_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..40367ccb6b685226d0d0f263a02dd50837fef97a --- /dev/null +++ b/frameworks/cj/hid/include/bluetooth_hid_host_impl.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * 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. + */ +#ifndef BLUETOOTH_HID_HOST_IMPL_H +#define BLUETOOTH_HID_HOST_IMPL_H + +#include "bluetooth_hid_host.h" +#include "bluetooth_hid_host_observer_impl.h" +#include "cj_common_ffi.h" +#include "ffi_remote_data.h" + +namespace OHOS { +namespace Bluetooth { +class BluetoothHidHostImpl : public OHOS::FFI::FFIData { + DECL_TYPE(BluetoothHidHostImpl, OHOS::FFI::FFIData) +public: + explicit BluetoothHidHostImpl() {}; + ~BluetoothHidHostImpl() {}; + static CArrString GetConnectionDevices(int32_t* errCode); + static int32_t GetConnectionState(char* device, int32_t* errCode); + static void On(int32_t type, int64_t id, int32_t* errCode); + static std::shared_ptr observer_; + static bool isRegistered_; +}; +} // namespace Bluetooth +} // namespace OHOS +#endif // BLUETOOTH_HID_HOST_IMPL_H \ No newline at end of file diff --git a/frameworks/cj/hid/include/bluetooth_hid_host_observer_impl.h b/frameworks/cj/hid/include/bluetooth_hid_host_observer_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..54d163a3fa5f1ac07d7a0c6b8c801ee381b9834e --- /dev/null +++ b/frameworks/cj/hid/include/bluetooth_hid_host_observer_impl.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef BLUETOOTH_HID_HOST_OBSERVER_IMPL_H +#define BLUETOOTH_HID_HOST_OBSERVER_IMPL_H + +#include "bluetooth_hid_host.h" +#include "bluetooth_hid_host_utils.h" +#include "ffi_remote_data.h" + +namespace OHOS { +namespace Bluetooth { +const char* const STR_BT_HID_HOST_OBSERVER_CONNECTION_STATE_CHANGE = "connectionStateChange"; + +class BluetoothHidHostObserverImpl : public HidHostObserver, public OHOS::FFI::FFIData { + DECL_TYPE(BluetoothHidHostObserverImpl, OHOS::FFI::FFIData); + +public: + BluetoothHidHostObserverImpl() {}; + ~BluetoothHidHostObserverImpl() override = default; + void RegisterStateChangeFunc(std::function cjCallback); + void OnConnectionStateChanged(const BluetoothRemoteDevice& device, int state, int cause) override; + +private: + std::function stateChangeFunc { nullptr }; +}; +} // namespace Bluetooth +} // namespace OHOS +#endif // BLUETOOTH_HID_HOST_OBSERVER_IMPL_H diff --git a/frameworks/cj/hid/include/bluetooth_hid_host_utils.h b/frameworks/cj/hid/include/bluetooth_hid_host_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..a1527aa9eed9768dd0230ea9b3a17022162c066c --- /dev/null +++ b/frameworks/cj/hid/include/bluetooth_hid_host_utils.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef BLUETOOTH_HID_HOST_UTILS_H +#define BLUETOOTH_HID_HOST_UTILS_H + +#include + +namespace OHOS { +namespace Bluetooth { +char* MallocCString(const std::string& origin); + +struct StateChangeParam { + char* deviceId; + int32_t state; + int32_t cause; +}; +} // namespace Bluetooth +} // namespace OHOS + +#endif // BLUETOOTH_HID_HOST_UTILS_H \ No newline at end of file diff --git a/frameworks/cj/hid/src/bluetooth_hid_host_ffi.cpp b/frameworks/cj/hid/src/bluetooth_hid_host_ffi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9c8a7f0da809ed1d6b36e6c057d6eb0e835b605a --- /dev/null +++ b/frameworks/cj/hid/src/bluetooth_hid_host_ffi.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * 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. + */ +#ifndef LOG_TAG +#define LOG_TAG "bt_cj_hid_host_ffi" +#endif + +#include "bluetooth_hid_host_ffi.h" + +#include "bluetooth_hid_host_impl.h" + +using namespace OHOS::FFI; + +namespace OHOS { +namespace Bluetooth { +extern "C" { +CArrString FfiBluetoothHidHostGetConnectedDevices(int32_t* errCode) +{ + return BluetoothHidHostImpl::GetConnectionDevices(errCode); +} + +int32_t FfiBluetoothHidHostGetConnectionState(char* device, int32_t* errCode) +{ + return BluetoothHidHostImpl::GetConnectionState(device, errCode); +} + +void FfiBluetoothHidHostOn(int32_t type, int64_t id, int32_t* errCode) +{ + BluetoothHidHostImpl::On(type, id, errCode); +} +} +} // namespace Bluetooth +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/cj/hid/src/bluetooth_hid_host_impl.cpp b/frameworks/cj/hid/src/bluetooth_hid_host_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eeb848c75731b4a5cb351456f86ec857b9fa8e17 --- /dev/null +++ b/frameworks/cj/hid/src/bluetooth_hid_host_impl.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * 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. + */ +#ifndef LOG_TAG +#define LOG_TAG "bt_cj_hid_host" +#endif + +#include "bluetooth_hid_host_impl.h" + +#include + +#include "bluetooth_errorcode.h" +#include "bluetooth_hid_host_utils.h" +#include "bluetooth_utils.h" +#include "cj_lambda.h" +#include "napi_bluetooth_utils.h" + +using namespace OHOS::FFI; + +namespace OHOS { +namespace Bluetooth { +std::shared_ptr BluetoothHidHostImpl::observer_ = + std::make_shared(); +bool BluetoothHidHostImpl::isRegistered_ = false; + +CArrString BluetoothHidHostImpl::GetConnectionDevices(int32_t* errCode) +{ + HILOGD("enter"); + HidHost* profile = HidHost::GetProfile(); + if (profile == nullptr) { + HILOGE("profile is nullptr."); + *errCode = BT_ERR_INTERNAL_ERROR; + return CArrString { 0 }; + } + std::vector states = { static_cast(BTConnectState::CONNECTED) }; + std::vector devices; + int errorCode = profile->GetDevicesByStates(states, devices); + if (errorCode != BT_NO_ERROR) { + HILOGE("bluetooth assert failed."); + *errCode = static_cast(errorCode); + return CArrString { 0 }; + } + if (devices.size() <= 0) { + return CArrString { 0 }; + } + char** deviceVector = static_cast(malloc(sizeof(char*) * devices.size())); + if (deviceVector == nullptr) { + HILOGE("deviceVector malloc failed."); + *errCode = BT_ERR_INTERNAL_ERROR; + return CArrString { 0 }; + } + int64_t i = 0; + for (auto& device : devices) { + deviceVector[i] = MallocCString(device.GetDeviceAddr()); + i++; + } + CArrString ret = CArrString { .head = deviceVector, .size = i }; + return ret; +} + +int32_t BluetoothHidHostImpl::GetConnectionState(char* device, int32_t* errCode) +{ + HILOGD("enter"); + int32_t profileState = ProfileConnectionState::STATE_DISCONNECTED; + std::string remoteAddr = device; + if (!IsValidAddress(remoteAddr)) { + HILOGE("Invalid addr"); + *errCode = static_cast(BT_ERR_INVALID_PARAM); + return profileState; + } + HidHost* profile = HidHost::GetProfile(); + if (profile == nullptr) { + HILOGE("profile is nullptr."); + *errCode = BT_ERR_INTERNAL_ERROR; + return profileState; + } + BluetoothRemoteDevice remoteDevice(remoteAddr, BT_TRANSPORT_BREDR); + int32_t state = static_cast(BTConnectState::DISCONNECTED); + int32_t errorCode = profile->GetDeviceState(remoteDevice, state); + if (errorCode != BT_NO_ERROR) { + HILOGE("bluetooth assert failed."); + *errCode = errorCode; + return profileState; + } + profileState = GetProfileConnectionState(state); + return profileState; +} + +void BluetoothHidHostImpl::On(int32_t type, int64_t id, int32_t* errCode) +{ + if (observer_) { + auto observerFunc = CJLambda::Create(reinterpret_cast(id)); + if (!observerFunc) { + HILOGD("Register state change event failed"); + *errCode = BT_ERR_INVALID_PARAM; + return; + } + observer_->RegisterStateChangeFunc(observerFunc); + } + + if (!isRegistered_) { + HidHost* profile = HidHost::GetProfile(); + if (profile == nullptr) { + HILOGE("profile is nullptr."); + *errCode = BT_ERR_INVALID_PARAM; + return; + } + profile->RegisterObserver(observer_); + isRegistered_ = true; + } + return; +} +} // namespace Bluetooth +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/cj/hid/src/bluetooth_hid_host_observer_impl.cpp b/frameworks/cj/hid/src/bluetooth_hid_host_observer_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6955f02e0329809257d45df1afd87fe037e72950 --- /dev/null +++ b/frameworks/cj/hid/src/bluetooth_hid_host_observer_impl.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * 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. + */ +#ifndef LOG_TAG +#define LOG_TAG "bt_cj_hid_host_observer" +#endif + +#include "bluetooth_hid_host_observer_impl.h" + +#include "bluetooth_log.h" +#include "bluetooth_utils.h" + +namespace OHOS { +namespace Bluetooth { +void BluetoothHidHostObserverImpl::RegisterStateChangeFunc(std::function cjCallback) +{ + stateChangeFunc = cjCallback; +} + +void BluetoothHidHostObserverImpl::OnConnectionStateChanged(const BluetoothRemoteDevice& device, int state, int cause) +{ + HILOGD("enter, remote device address: %{public}s, state: %{public}d, cause: %{public}d", GET_ENCRYPT_ADDR(device), + state, cause); + if (!stateChangeFunc) { + HILOGE("failed to register state change callback"); + return; + } + char* deviceId = MallocCString(device.GetDeviceAddr()); + if (deviceId == nullptr) { + HILOGE("failed to malloc memory"); + return; + } + StateChangeParam param = StateChangeParam { + .deviceId = deviceId, .state = static_cast(state), .cause = static_cast(cause) + }; + stateChangeFunc(param); + free(deviceId); + return; +} +} // namespace Bluetooth +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/cj/hid/src/bluetooth_hid_host_utils.cpp b/frameworks/cj/hid/src/bluetooth_hid_host_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8d263c96950902cc094b889c7aa9505cf7fcca82 --- /dev/null +++ b/frameworks/cj/hid/src/bluetooth_hid_host_utils.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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 "bluetooth_hid_host_utils.h" + +namespace OHOS { +namespace Bluetooth { +char* MallocCString(const std::string& origin) +{ + if (origin.empty()) { + return nullptr; + } + auto len = origin.length() + 1; + char* res = static_cast(malloc(sizeof(char) * len)); + if (res == nullptr) { + return nullptr; + } + return std::char_traits::copy(res, origin.c_str(), len); +} +} // namespace Bluetooth +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/cj/socket/BUILD.gn b/frameworks/cj/socket/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..119280c3ae124ef3681399a244edc8fb7ef0150d --- /dev/null +++ b/frameworks/cj/socket/BUILD.gn @@ -0,0 +1,68 @@ +# Copyright (C) 2025 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") + +ohos_shared_library("cj_bluetooth_socket_ffi") { + branch_protector_ret = "pac_ret" # Enable PAC CFI + sanitize = { + cfi = true # Enable/disable control flow integrity detection + boundary_sanitize = true # Enable boundary san detection + cfi_cross_dso = true # Cross-SO CFI Checks + integer_overflow = true # Enable integer overflow detection + ubsan = true # Enable some Ubsan options + debug = false + } + + if (!defined(defines)) { + defines = [] + } + include_dirs = [ + "include", + "../../js/napi/include", + "../../../frameworks/inner/include", + ] + + deps = [ + "../../../frameworks/inner:btframework", + "../../../frameworks/js/napi/src/common:bt_napi_common", + ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "napi:ace_napi", + "napi:cj_bind_ffi", + "napi:cj_bind_native", + ] + + sources = [ + "src/bluetooth_spp_client_impl.cpp", + "src/bluetooth_spp_ffi.cpp", + "src/bluetooth_spp_server_impl.cpp", + "src/bluetooth_spp_utils.cpp", + ] + + if (is_ohos) { + defines += [ "OHOS_PLATFORM" ] + } + + if (is_mingw) { + defines += [ "WINDOWS_PLATFORM" ] + } + + innerapi_tags = [ "platformsdk" ] + + part_name = "bluetooth" + subsystem_name = "communication" +} diff --git a/frameworks/cj/socket/include/bluetooth_spp_client_impl.h b/frameworks/cj/socket/include/bluetooth_spp_client_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..f0ff7e21c49dffbfaf195f6e032aeadf46eb1ad5 --- /dev/null +++ b/frameworks/cj/socket/include/bluetooth_spp_client_impl.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * 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. + */ +#ifndef BLUETOOTH_SPP_CLIENT_IMPL_H +#define BLUETOOTH_SPP_CLIENT_IMPL_H + +#include +#include +#include + +#include "bluetooth_socket.h" +#include "bluetooth_spp_utils.h" +#include "cj_common_ffi.h" +#include "napi_bluetooth_utils.h" + +namespace OHOS { +namespace Bluetooth { +struct CjBluetoothCallbackInfo { + int64_t callback_ = 0; + std::string deviceId_; +}; + +struct SppCallbackBuffer { + ssize_t len_; + char data_[1024]; +}; + +struct BufferCallbackInfo : public CjBluetoothCallbackInfo { + void PushData(const std::shared_ptr& data) + { + std::lock_guard lock(bufferLock_); + buffer_.push(data); + } + + std::shared_ptr PopData() + { + std::lock_guard lock(bufferLock_); + if (buffer_.empty()) { + return nullptr; + } + std::shared_ptr ret = buffer_.front(); + buffer_.pop(); + return ret; + } + +private: + std::mutex bufferLock_; + std::queue> buffer_; +}; + +constexpr const char* REGISTER_SPP_READ_TYPE = "sppRead"; + +struct SppClientImpl { + static int32_t SppConnect(std::string deviceId, SppOption sppOption, int32_t* errCode); + static int32_t SppCloseClientSocket(int32_t socket); + static int32_t SppWrite(int32_t clientSocket, CArrUI8 data); + static int32_t On(std::string type, int32_t clientSocket, int64_t cbId); + static int32_t Off(std::string type, int32_t clientSocket, int64_t cbId); + static void SppRead(int id); + static std::string GetDeviceId(int32_t clientSocket, int32_t* errCode); + + static int count; + static std::map> clientMap; + + int id_ = -1; + bool sppReadFlag = false; + std::map> callbackInfos_ = {}; + + std::shared_ptr client_ = nullptr; + std::shared_ptr device_ = nullptr; + std::shared_ptr thread_; +}; +} // namespace Bluetooth +} // namespace OHOS +#endif /* BLUETOOTH_SPP_CLIENT_IMPL_H */ \ No newline at end of file diff --git a/frameworks/cj/socket/include/bluetooth_spp_ffi.h b/frameworks/cj/socket/include/bluetooth_spp_ffi.h new file mode 100644 index 0000000000000000000000000000000000000000..253cdc86b6680010fe97cea80c4e38ae25f5ef7b --- /dev/null +++ b/frameworks/cj/socket/include/bluetooth_spp_ffi.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef BLUETOOTH_SPP_FFI_H +#define BLUETOOTH_SPP_FFI_H + +#include "cj_common_ffi.h" + +extern "C" { +struct CSppOption { + char* uuid; + bool secure; + int32_t type; +}; + +FFI_EXPORT int32_t FfiBluetoothSocketSppListen(char* name, CSppOption options, int32_t* errCode); +FFI_EXPORT int32_t FfiBluetoothSocketSppAccept(int32_t serverSocket, int32_t* errCode); +FFI_EXPORT int32_t FfiBluetoothSocketSppConnect(char* deviceId, CSppOption options, int32_t* errCode); +FFI_EXPORT char* FfiBluetoothSocketGetDeviceId(int32_t clientSocket, int32_t* errCode); +FFI_EXPORT void FfiBluetoothSocketSppCloseServerSocket(int32_t socket, int32_t* errCode); +FFI_EXPORT void FfiBluetoothSocketSppCloseClientSocket(int32_t socket, int32_t* errCode); +FFI_EXPORT void FfiBluetoothSocketSppWrite(int32_t clientSocket, CArrUI8 data, int32_t* errCode); +FFI_EXPORT void FfiBluetoothSocketOn(char* type, int32_t clientSocket, int64_t cbId, int32_t* errCode); +FFI_EXPORT void FfiBluetoothSocketOff(char* type, int32_t clientSocket, int64_t cbId, int32_t* errCode); +} + +#endif diff --git a/frameworks/cj/socket/include/bluetooth_spp_server_impl.h b/frameworks/cj/socket/include/bluetooth_spp_server_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..9a8f4904c2da34b1d2ec89605bed35a18d6524c9 --- /dev/null +++ b/frameworks/cj/socket/include/bluetooth_spp_server_impl.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * 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. + */ +#ifndef BLUETOOTH_SPP_SERVER_IMPL_H +#define BLUETOOTH_SPP_SERVER_IMPL_H + +#include + +#include "bluetooth_socket.h" +#include "bluetooth_spp_client_impl.h" + +namespace OHOS { +namespace Bluetooth { +struct SppServerImpl { + static int32_t SppListen(std::string name, SppOption sppOption, int32_t* errCode); + static int32_t SppAccept(int32_t serverSocket, int32_t* errCode); + static int32_t SppCloseServerSocket(int32_t socket); + static int32_t RegisterSocketObserver(std::string type, int32_t clientSocket, int64_t cbId); + static int32_t DeRegisterSocketObserver(std::string type, int32_t clientSocket, int64_t cbId); + + static std::map> serverMap; + static int count; + + std::shared_ptr server_ = nullptr; + int id_ = -1; +}; +} // namespace Bluetooth +} // namespace OHOS +#endif /* BLUETOOTH_SPP_SERVER_IMPL_H */ \ No newline at end of file diff --git a/frameworks/cj/socket/include/bluetooth_spp_utils.h b/frameworks/cj/socket/include/bluetooth_spp_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..af49b7d7936a10c5a68ae671c628beaa15838a05 --- /dev/null +++ b/frameworks/cj/socket/include/bluetooth_spp_utils.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef BLUETOOTH_HID_HOST_UTILS_H +#define BLUETOOTH_HID_HOST_UTILS_H + +#include + +namespace OHOS { +namespace Bluetooth { +char* MallocCString(const std::string& origin); +} // namespace Bluetooth +} // namespace OHOS + +#endif // BLUETOOTH_HID_HOST_UTILS_H \ No newline at end of file diff --git a/frameworks/cj/socket/src/bluetooth_spp_client_impl.cpp b/frameworks/cj/socket/src/bluetooth_spp_client_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..80f11776b2dcfa396eeeb494377cb93da150c822 --- /dev/null +++ b/frameworks/cj/socket/src/bluetooth_spp_client_impl.cpp @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * 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. + */ +#ifndef LOG_TAG +#define LOG_TAG "bt_cj_socket_spp_client" +#endif + +#include "bluetooth_spp_client_impl.h" + +#include "bluetooth_errorcode.h" +#include "bluetooth_host.h" +#include "cj_lambda.h" +#include "datetime_ex.h" +#include "napi_bluetooth_utils.h" +#include "securec.h" + +namespace OHOS { +namespace Bluetooth { +std::map> SppClientImpl::clientMap; +int SppClientImpl::count = 0; +const int SOCKET_BUFFER_SIZE = 1024; + +int32_t SppClientImpl::SppConnect(std::string deviceId, SppOption sppOption, int32_t* errCode) +{ + HILOGD("enter"); + std::shared_ptr device_ = std::make_shared(deviceId, 0); + std::shared_ptr client_ = + std::make_shared(*device_, UUID::FromString(sppOption.uuid_), sppOption.type_, sppOption.secure_); + int errorCode = client_->Connect(SPP_SOCKET_PSM_VALUE); + if (errorCode != BtStatus::BT_SUCCESS) { + HILOGE("SppConnect failed"); + *errCode = errorCode; + return -1; + } + std::shared_ptr client = std::make_shared(); + client->device_ = device_; + client->id_ = SppClientImpl::count++; + client->client_ = client_; + clientMap.insert(std::make_pair(client->id_, client)); + HILOGD("SppConnect execute back successfully"); + return client->id_; +} + +int32_t SppClientImpl::SppCloseClientSocket(int32_t socket) +{ + HILOGD("enter"); + std::shared_ptr client = nullptr; + bool isOK = false; + + if (clientMap[socket]) { + client = clientMap[socket]; + } else { + HILOGE("invalid socket."); + return BT_ERR_INVALID_PARAM; + } + + if (client->client_) { + client->client_->Close(); + isOK = true; + } + clientMap.erase(socket); + return isOK ? 0 : BT_ERR_INVALID_PARAM; +} + +int32_t SppClientImpl::SppWrite(int32_t clientSocket, CArrUI8 data) +{ + HILOGD("enter"); + BluetoothHost* host = &BluetoothHost::GetDefaultHost(); + auto prohibitedTime = host->GetRefusePolicyProhibitedTime(); + if (prohibitedTime < 0 || prohibitedTime > GetSecondsSince1970ToNow()) { + HILOGE("socket refuse because of Refuse Policy"); + return BT_ERR_INVALID_PARAM; + } + auto client = clientMap[clientSocket]; + if (client == nullptr) { + HILOGE("client is nullptr."); + return BT_ERR_INVALID_PARAM; + } + if (client->client_ == nullptr) { + HILOGE("client_ is nullptr."); + return BT_ERR_INVALID_PARAM; + } + std::shared_ptr outputStream = client->client_->GetOutputStream(); + size_t totalSize = static_cast(data.size); + bool isOK = false; + while (totalSize) { + int result = outputStream->Write(data.head, totalSize); + if (result <= 0) { + HILOGE("outputStream.Write failed, ret = %{public}d", result); + return BT_ERR_SPP_IO; + } + totalSize = totalSize - static_cast(result); + data.head += static_cast(result); + isOK = true; + } + return isOK ? 0 : BT_ERR_INVALID_PARAM; +} + +int32_t SppClientImpl::On(std::string type, int32_t clientSocket, int64_t cbId) +{ + HILOGD("enter"); + std::shared_ptr callbackInfo = std::make_shared(); + callbackInfo->callback_ = cbId; + std::shared_ptr client = SppClientImpl::clientMap[clientSocket]; + if (client == nullptr) { + HILOGE("client is nullptr."); + return BT_ERR_INVALID_PARAM; + } + if (client->sppReadFlag) { + HILOGE("client is reading... please off first"); + return BT_ERR_INVALID_PARAM; + } + client->sppReadFlag = true; + client->callbackInfos_[type] = callbackInfo; + client->thread_ = std::make_shared(SppClientImpl::SppRead, clientSocket); + client->thread_->detach(); + return 0; +} + +int32_t SppClientImpl::Off(std::string type, int32_t clientSocket, int64_t cbId) +{ + HILOGD("enter"); + std::shared_ptr client = SppClientImpl::clientMap[clientSocket]; + if (client == nullptr) { + HILOGE("client is nullptr."); + return BT_ERR_INVALID_PARAM; + } + client->callbackInfos_[type] = nullptr; + client->sppReadFlag = false; + return 0; +} + +void SppClientImpl::SppRead(int id) +{ + auto client = clientMap[id]; + if (client == nullptr || !client->sppReadFlag || client->callbackInfos_[REGISTER_SPP_READ_TYPE] == nullptr) { + HILOGE("thread start failed."); + return; + } + std::shared_ptr inputStream = client->client_->GetInputStream(); + uint8_t buf[SOCKET_BUFFER_SIZE]; + + while (true) { + HILOGD("thread start."); + (void)memset_s(buf, SOCKET_BUFFER_SIZE, 0, SOCKET_BUFFER_SIZE); + int ret = inputStream->Read(buf, sizeof(buf)); + if (ret <= 0) { + HILOGE("inputStream.Read failed, ret = %{public}d", ret); + return; + } else { + if (client == nullptr || !client->sppReadFlag || !client->callbackInfos_[REGISTER_SPP_READ_TYPE]) { + HILOGE("failed"); + return; + } + std::shared_ptr callbackInfo = + std::static_pointer_cast(client->callbackInfos_[REGISTER_SPP_READ_TYPE]); + if (callbackInfo == nullptr) { + HILOGE("callbackInfo nullptr"); + return; + } + + CArrUI8 buffer {}; + buffer.head = static_cast(malloc(sizeof(uint8_t) * ret)); + if (buffer.head == nullptr) { + HILOGE("malloc failed!"); + return; + } + buffer.size = ret; + if (memcpy_s(buffer.head, ret, buf, ret) != EOK) { + HILOGE("memcpy_s failed!"); + free(buffer.head) + return; + } + + auto cFunc = reinterpret_cast(callbackInfo->callback_); + std::function func = CJLambda::Create(cFunc); + func(buffer); + free(buffer.head); + } + } + return; +} + +std::string SppClientImpl::GetDeviceId(int32_t clientSocket, int32_t* errCode) +{ + HILOGD("enter"); + auto client = clientMap[clientSocket]; + if (client == nullptr) { + *errCode = BT_ERR_INVALID_PARAM; + return std::string(); + } + if (client->client_ == nullptr) { + *errCode = BT_ERR_INVALID_PARAM; + return std::string(); + } + BluetoothRemoteDevice remoteDevice = client->client_->GetRemoteDevice(); + std::string addr = remoteDevice.GetDeviceAddr(); + return addr; +} +} // namespace Bluetooth +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/cj/socket/src/bluetooth_spp_ffi.cpp b/frameworks/cj/socket/src/bluetooth_spp_ffi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..251f29b764323061a257e5903c476477fdc410a9 --- /dev/null +++ b/frameworks/cj/socket/src/bluetooth_spp_ffi.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * 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. + */ +#ifndef LOG_TAG +#define LOG_TAG "bt_cj_socket_spp_ffi" +#endif + +#include "bluetooth_spp_ffi.h" + +#include "bluetooth_spp_server_impl.h" +#include "bluetooth_spp_utils.h" + +namespace OHOS { +namespace Bluetooth { +extern "C" { +static SppOption parseCSppOptions(CSppOption options) +{ + SppOption ret = { .uuid_ = options.uuid, .secure_ = options.secure, .type_ = BtSocketType(options.type) }; + return ret; +} + +int32_t FfiBluetoothSocketSppListen(char* name, CSppOption options, int32_t* errCode) +{ + return SppServerImpl::SppListen(name, parseCSppOptions(options), errCode); +} + +int32_t FfiBluetoothSocketSppAccept(int32_t serverSocket, int32_t* errCode) +{ + return SppServerImpl::SppAccept(serverSocket, errCode); +} + +int32_t FfiBluetoothSocketSppConnect(char* deviceId, CSppOption options, int32_t* errCode) +{ + return SppClientImpl::SppConnect(deviceId, parseCSppOptions(options), errCode); +} + +char* FfiBluetoothSocketGetDeviceId(int32_t clientSocket, int32_t* errCode) +{ + std::string deviceId = SppClientImpl::GetDeviceId(clientSocket, errCode); + if (*errCode != SUCCESS_CODE) { + return nullptr; + } + return MallocCString(deviceId); +} + +void FfiBluetoothSocketSppCloseServerSocket(int32_t socket, int32_t* errCode) +{ + *errCode = SppServerImpl::SppCloseServerSocket(socket); +} + +void FfiBluetoothSocketSppCloseClientSocket(int32_t socket, int32_t* errCode) +{ + *errCode = SppClientImpl::SppCloseClientSocket(socket); +} + +void FfiBluetoothSocketSppWrite(int32_t clientSocket, CArrUI8 data, int32_t* errCode) +{ + *errCode = SppClientImpl::SppWrite(clientSocket, data); +} + +void FfiBluetoothSocketOn(char* type, int32_t clientSocket, int64_t cbId, int32_t* errCode) +{ + *errCode = SppServerImpl::RegisterSocketObserver(type, clientSocket, cbId); +} + +void FfiBluetoothSocketOff(char* type, int32_t clientSocket, int64_t cbId, int32_t* errCode) +{ + *errCode = SppServerImpl::DeRegisterSocketObserver(type, clientSocket, cbId); +} +} +} // namespace Bluetooth +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/cj/socket/src/bluetooth_spp_server_impl.cpp b/frameworks/cj/socket/src/bluetooth_spp_server_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2d8ab6b2342df0e53231a0372b9deed437561572 --- /dev/null +++ b/frameworks/cj/socket/src/bluetooth_spp_server_impl.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * 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. + */ +#ifndef LOG_TAG +#define LOG_TAG "bt_cj_socket_spp_server" +#endif + +#include "bluetooth_spp_server_impl.h" + +#include "bluetooth_errorcode.h" +#include "napi_bluetooth_utils.h" + +namespace OHOS { +namespace Bluetooth { +const int NUM_20 = 20; +int SppServerImpl::count = 0; +std::map> SppServerImpl::serverMap; + +int32_t SppServerImpl::SppListen(std::string name, SppOption sppOption, int32_t* errCode) +{ + HILOGD("enter"); + std::shared_ptr server_ = + std::make_shared(name, UUID::FromString(sppOption.uuid_), sppOption.type_, sppOption.secure_); + int errorCode = server_->Listen(); + if (server_->GetStringTag() != "") { + HILOGD("SppListen execute listen success"); + } else { + HILOGE("SppListen execute listen failed"); + *errCode = static_cast(errorCode); + return -1; + } + std::shared_ptr server = std::make_shared(); + server->id_ = SppServerImpl::count++; + server->server_ = server_; + serverMap.insert(std::make_pair(server->id_, server)); + return static_cast(server->id_); +} + +int32_t SppServerImpl::SppAccept(int32_t serverSocket, int32_t* errCode) +{ + HILOGD("enter"); + std::shared_ptr server = SppServerImpl::serverMap[serverSocket]; + if (!server) { + HILOGE("server is null"); + *errCode = BT_ERR_INVALID_PARAM; + return -1; + } + std::shared_ptr server_ = server->server_; + std::shared_ptr client_ = server_->Accept(NUM_20); + if (client_ == nullptr) { + HILOGE("client_ is null"); + *errCode = BT_ERR_INVALID_PARAM; + return -1; + } + std::shared_ptr client = std::make_shared(); + client->id_ = SppClientImpl::count++; + client->client_ = client_; + SppClientImpl::clientMap.insert(std::make_pair(client->id_, client)); + return static_cast(client->id_); +} + +int32_t SppServerImpl::RegisterSocketObserver(std::string type, int32_t clientSocket, int64_t cbId) +{ + return SppClientImpl::On(type, clientSocket, cbId); +} + +int32_t SppServerImpl::DeRegisterSocketObserver(std::string type, int32_t clientSocket, int64_t cbId) +{ + return SppClientImpl::Off(type, clientSocket, cbId); +} + +int32_t SppServerImpl::SppCloseServerSocket(int32_t socket) +{ + HILOGD("enter"); + bool isOK = false; + + std::shared_ptr server = nullptr; + std::shared_ptr client = nullptr; + if (SppClientImpl::clientMap[socket] != nullptr) { + client = SppClientImpl::clientMap[socket]; + if (client->client_) { + client->client_->Close(); + SppClientImpl::clientMap.erase(socket); + } + } else { + HILOGE("invalid socket."); + } + if (serverMap[socket] != nullptr) { + server = serverMap[socket]; + if (server->server_) { + server->server_->Close(); + serverMap.erase(socket); + isOK = true; + } + } else { + HILOGE("invalid socket."); + } + return isOK ? 0 : BT_ERR_INVALID_PARAM; +} +} // namespace Bluetooth +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/cj/socket/src/bluetooth_spp_utils.cpp b/frameworks/cj/socket/src/bluetooth_spp_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..79d2b985b2b5e4d3d064835f66f21683504cbea6 --- /dev/null +++ b/frameworks/cj/socket/src/bluetooth_spp_utils.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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 "bluetooth_spp_utils.h" + +namespace OHOS { +namespace Bluetooth { +char* MallocCString(const std::string& origin) +{ + if (origin.empty()) { + return nullptr; + } + auto len = origin.length() + 1; + char* res = static_cast(malloc(sizeof(char) * len)); + if (res == nullptr) { + return nullptr; + } + return std::char_traits::copy(res, origin.c_str(), len); +} +} // namespace Bluetooth +} // namespace OHOS \ No newline at end of file