From 9beb4a79bb84fce8eb4e69ff417ed310bc7272c9 Mon Sep 17 00:00:00 2001 From: lilong32 Date: Tue, 21 Jul 2026 21:34:53 +0800 Subject: [PATCH] add nearlink driver Signed-off-by: lilong32 --- nearlink/README.md | 67 ++ nearlink/README_zh.md | 69 ++ nearlink/bundle.json | 47 ++ nearlink/dli/BUILD.gn | 22 + nearlink/dli/dli_service/BUILD.gn | 164 +++++ .../dli/dli_service/implement/dli_internal.h | 44 ++ .../dli_service/implement/dli_protocol.cpp | 86 +++ .../dli/dli_service/implement/dli_protocol.h | 50 ++ .../dli/dli_service/implement/dli_watcher.cpp | 205 ++++++ .../dli/dli_service/implement/dli_watcher.h | 68 ++ .../dli/dli_service/implement/h4_protocol.cpp | 176 +++++ .../dli/dli_service/implement/h4_protocol.h | 54 ++ .../dli_service/implement/nearlink_hdf_log.h | 42 ++ .../implement/ohos_sle_vendor_lib.h | 152 +++++ .../dli/dli_service/implement/sle_address.cpp | 259 ++++++++ .../dli/dli_service/implement/sle_address.h | 55 ++ .../dli_service/implement/sle_hal_constant.h | 38 ++ .../dli/dli_service/implement/thread_util.cpp | 109 +++ .../dli/dli_service/implement/thread_util.h | 55 ++ .../implement/vendor_interface.cpp | 461 +++++++++++++ .../dli_service/implement/vendor_interface.h | 70 ++ .../dli/dli_service/remote_death_recipient.h | 55 ++ .../dli_service/sle_dli_interface_driver.cpp | 125 ++++ .../dli_service/sle_hci_interface_impl.cpp | 178 +++++ .../dli/dli_service/sle_hci_interface_impl.h | 56 ++ nearlink/dli/test/BUILD.gn | 44 ++ nearlink/dli/test/nearlink_hdi_test.cpp | 131 ++++ nearlink/drivers_peripheral_nearlink.gni | 17 + nearlink/off_find/BUILD.gn | 26 + nearlink/off_find/hdi_service/BUILD.gn | 158 +++++ .../hdi_service/implement/dli_internal.h | 43 ++ .../hdi_service/implement/dli_protocol.cpp | 84 +++ .../hdi_service/implement/dli_protocol.h | 50 ++ .../hdi_service/implement/dli_watcher.cpp | 186 ++++++ .../hdi_service/implement/dli_watcher.h | 65 ++ .../hdi_service/implement/h4_protocol.cpp | 125 ++++ .../hdi_service/implement/h4_protocol.h | 50 ++ .../implement/off_find_hdi_constant.h | 69 ++ .../hdi_service/implement/off_find_log.h | 30 + .../implement/ohos_off_find_vendor_lib.h | 114 ++++ .../hdi_service/implement/thread_util.cpp | 109 +++ .../hdi_service/implement/thread_util.h | 52 ++ .../implement/vendor_interface.cpp | 620 ++++++++++++++++++ .../hdi_service/implement/vendor_interface.h | 99 +++ .../hdi_service/off_find_interface_driver.cpp | 124 ++++ .../hdi_service/off_find_interface_impl.cpp | 172 +++++ .../hdi_service/off_find_interface_impl.h | 54 ++ .../hdi_service/remote_death_recipient.h | 55 ++ 48 files changed, 5184 insertions(+) create mode 100644 nearlink/README.md create mode 100644 nearlink/README_zh.md create mode 100644 nearlink/bundle.json create mode 100644 nearlink/dli/BUILD.gn create mode 100644 nearlink/dli/dli_service/BUILD.gn create mode 100644 nearlink/dli/dli_service/implement/dli_internal.h create mode 100644 nearlink/dli/dli_service/implement/dli_protocol.cpp create mode 100644 nearlink/dli/dli_service/implement/dli_protocol.h create mode 100644 nearlink/dli/dli_service/implement/dli_watcher.cpp create mode 100644 nearlink/dli/dli_service/implement/dli_watcher.h create mode 100644 nearlink/dli/dli_service/implement/h4_protocol.cpp create mode 100644 nearlink/dli/dli_service/implement/h4_protocol.h create mode 100644 nearlink/dli/dli_service/implement/nearlink_hdf_log.h create mode 100644 nearlink/dli/dli_service/implement/ohos_sle_vendor_lib.h create mode 100644 nearlink/dli/dli_service/implement/sle_address.cpp create mode 100644 nearlink/dli/dli_service/implement/sle_address.h create mode 100644 nearlink/dli/dli_service/implement/sle_hal_constant.h create mode 100644 nearlink/dli/dli_service/implement/thread_util.cpp create mode 100644 nearlink/dli/dli_service/implement/thread_util.h create mode 100644 nearlink/dli/dli_service/implement/vendor_interface.cpp create mode 100644 nearlink/dli/dli_service/implement/vendor_interface.h create mode 100644 nearlink/dli/dli_service/remote_death_recipient.h create mode 100644 nearlink/dli/dli_service/sle_dli_interface_driver.cpp create mode 100644 nearlink/dli/dli_service/sle_hci_interface_impl.cpp create mode 100644 nearlink/dli/dli_service/sle_hci_interface_impl.h create mode 100644 nearlink/dli/test/BUILD.gn create mode 100644 nearlink/dli/test/nearlink_hdi_test.cpp create mode 100644 nearlink/drivers_peripheral_nearlink.gni create mode 100644 nearlink/off_find/BUILD.gn create mode 100644 nearlink/off_find/hdi_service/BUILD.gn create mode 100644 nearlink/off_find/hdi_service/implement/dli_internal.h create mode 100644 nearlink/off_find/hdi_service/implement/dli_protocol.cpp create mode 100644 nearlink/off_find/hdi_service/implement/dli_protocol.h create mode 100644 nearlink/off_find/hdi_service/implement/dli_watcher.cpp create mode 100644 nearlink/off_find/hdi_service/implement/dli_watcher.h create mode 100644 nearlink/off_find/hdi_service/implement/h4_protocol.cpp create mode 100644 nearlink/off_find/hdi_service/implement/h4_protocol.h create mode 100644 nearlink/off_find/hdi_service/implement/off_find_hdi_constant.h create mode 100644 nearlink/off_find/hdi_service/implement/off_find_log.h create mode 100644 nearlink/off_find/hdi_service/implement/ohos_off_find_vendor_lib.h create mode 100644 nearlink/off_find/hdi_service/implement/thread_util.cpp create mode 100644 nearlink/off_find/hdi_service/implement/thread_util.h create mode 100644 nearlink/off_find/hdi_service/implement/vendor_interface.cpp create mode 100644 nearlink/off_find/hdi_service/implement/vendor_interface.h create mode 100644 nearlink/off_find/hdi_service/off_find_interface_driver.cpp create mode 100644 nearlink/off_find/hdi_service/off_find_interface_impl.cpp create mode 100644 nearlink/off_find/hdi_service/off_find_interface_impl.h create mode 100644 nearlink/off_find/hdi_service/remote_death_recipient.h diff --git a/nearlink/README.md b/nearlink/README.md new file mode 100644 index 0000000000..b0318fd5fe --- /dev/null +++ b/nearlink/README.md @@ -0,0 +1,67 @@ +# NearLink + +- [Introduction](#section11660541593) +- [Directory Structure](#section161941989596) +- [Constraints](#section119744591305) +- [Usage](#section1312121216216) + - [DLI APIs](#section129654513264) + +- [Repositories Involved](#section1371113476307) + +## Introduction + +The NearLink driver module provides APIs for accessing and using the NearLink short-range communication protocol, including DLI initialization, data sending and receiving, and closing the NearLink DLI. + +## Directory Structure + +``` +/foundation/drivers/peripheral/nearlink +├── bundle.json # Component description and dependency configuration +├── drivers_peripheral_nearlink.gni # Build feature parameter configuration +├── dli # DLI module +│ └── test # DLI test cases +└── LICENSE # Copyright statement +└── bundle.json # Component description file +``` + +## Constraints + +The NearLink driver module is written in C++ and based on the DLI framework. It supports the standard system only. + +## Usage + +NearLink DLI APIs are provided. The DLI APIs include initialization, sending and receiving DLI packets, and close. + +### DLI APIs + +- Initialize the NearLink HAL: + +``` +/* Initialize the NearLink HAL and register the callback. */ +int32_t SleHalInit(const sptr& callbackObj); +``` + +- Send a packet: + +``` +/* Send a packet to the chip. */ +int32_t SleSendHciPacket(const std::vector& data); +``` + +- Receive a packet: + +``` +/* Receive a packet from the chip. */ +int32_t hciPacketReceived(uint32_t type, const std::vector &data); +``` + +- Close the NearLink DLI: + +``` +/* Close the NearLink DLI and release resources. */ +int32_t Close(); +``` + +## Repositories Involved + +drivers\_peripheral\_nearlink diff --git a/nearlink/README_zh.md b/nearlink/README_zh.md new file mode 100644 index 0000000000..01c17ad6a8 --- /dev/null +++ b/nearlink/README_zh.md @@ -0,0 +1,69 @@ +# 星闪组件 + +- [简介](#section11660541593) +- [目录](#section161941989596) +- [约束](#section119744591305) +- [说明](#section1312121216216) + - [DLI接口使用说明](#section129654513264) + +- [相关仓](#section1371113476307) + +## 简介 + +星闪(NearLink)驱动组件为设备提供接入与使用星闪短距通信协议的相关接口,包括DLI初始化,数据收发以及关闭星闪DLI等。 + +## 目录 + +``` +/foundation/drivers/peripheral/nearlink +├── bundle.json # 组件描述及依赖配置 +├── drivers_peripheral_nearlink.gni # 编译特性参数配置 +├── dli # DLI模块 +│ └── test # DLI测试用例 +└── LICENSE # 版权声明文件 +└── bundle.json # 部件描述文件 +``` + +## 约束 + +星闪驱动组件使用C++语言编写,基于DLI框架,仅支持标准系统。 + +## 说明 + +目前提供星闪DLI接口,DLI接口包括初始化、发送接收DLI数据包、关闭等功能。 + + +### DLI接口使用说明 + +- 初始化星闪HAL: + +``` +/* 初始化星闪HAL,注册回调 */ +int32_t SleHalInit(const sptr& callbackObj); +``` + +- 发送数据包: + +``` +/* 向芯片发送数据包 */ +int32_t SleSendHciPacket(const std::vector& data); +``` + +- 接收数据包: + +``` +/* 接收来自芯片的数据包 */ +int32_t hciPacketReceived(uint32_t type, const std::vector &data); +``` + + +- 关闭星闪DLI: + +``` +/* 关闭星闪DLI,释放资源 */ +int32_t Close(); +``` + +## 相关仓 + +drivers\_peripheral\_nearlink diff --git a/nearlink/bundle.json b/nearlink/bundle.json new file mode 100644 index 0000000000..d19ebeea56 --- /dev/null +++ b/nearlink/bundle.json @@ -0,0 +1,47 @@ +{ + "name": "@ohos/drivers_peripheral_nearlink", + "description": "nearlink device driver", + "version": "4.1", + "license": "Apache License 2.0", + "publishAs": "code-segment", + "segment": { + "destPath": "drivers/peripheral/nearlink" + }, + "dirs": {}, + "scripts": {}, + "component": { + "name": "drivers_peripheral_nearlink", + "subsystem": "hdf", + "features": [ + "drivers_peripheral_nearlink_feature_support_send_disable_hci", + "drivers_peripheral_nearlink_reload_address" + ], + "adapted_system_type": ["standard"], + "rom": "", + "ram": "", + "deps": { + "components": [ + "c_utils", + "hdf_core", + "hilog", + "drivers_interface_nearlink", + "samgr", + "ipc", + "ffrt", + "bounds_checking_function", + "init" + ], + "third_party": [ + ] + }, + "build": { + "sub_component": [ + "//drivers/peripheral/nearlink/dli:nearlink_entry", + "//drivers/peripheral/nearlink/off_find:off_find_entry" + ], + "test": [ + "//drivers/peripheral/nearlink/dli/test:nearlink_hdi_test" + ] + } + } +} diff --git a/nearlink/dli/BUILD.gn b/nearlink/dli/BUILD.gn new file mode 100644 index 0000000000..a7e8055647 --- /dev/null +++ b/nearlink/dli/BUILD.gn @@ -0,0 +1,22 @@ +# Copyright (C) 2026 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. + +if (defined(ohos_lite)) { + group("nearlink_entry") { + deps = [] + } +} else { + group("nearlink_entry") { + deps = [ "dli_service:hdf_nearlink_service" ] + } +} \ No newline at end of file diff --git a/nearlink/dli/dli_service/BUILD.gn b/nearlink/dli/dli_service/BUILD.gn new file mode 100644 index 0000000000..97d9a3fef3 --- /dev/null +++ b/nearlink/dli/dli_service/BUILD.gn @@ -0,0 +1,164 @@ +# Copyright (C) 2026 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/config/components/hdi/hdi.gni") +import("../../drivers_peripheral_nearlink.gni") + + +ohos_shared_library("libsle_hci_interface_service_1.1") { + 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 + } + branch_protector_ret = "pac_ret" + + cflags = [ + "-Os", + "-fdata-sections", + "-ffunction-sections", + "-fno-unwind-tables", + "-fno-asynchronous-unwind-tables", + "-fno-exceptions", + "-fno-rtti", + "-fPIC", + "-fno-common", + "-fstack-protector-strong", + "-fvisibility-inlines-hidden", + "-flto", + ] + cflags_cc = cflags + ldflags = [ + "-Wl,--as-needed", + "-Wl,--gc-sections", + "-Wl,--no-whole-archive", + ] + + include_dirs = [ + ".", + "implement", + ] + + sources = [ + "sle_hci_interface_impl.cpp", + "implement/sle_address.cpp", + "implement/h4_protocol.cpp", + "implement/dli_protocol.cpp", + "implement/dli_watcher.cpp", + "implement/vendor_interface.cpp", + "implement/thread_util.cpp", + ] + + defines = [] + + if (drivers_peripheral_nearlink_reload_address) { + defines += [ "RELOAD_ADDRESS" ] + } + + if (is_standard_system) { + external_deps = [ + "c_utils:utils", + "drivers_interface_nearlink:nearlink_hci_idl_headers", + "hdf_core:libhdf_host", + "hdf_core:libhdf_utils", + "hilog:libhilog", + "ipc:ipc_core", + "ffrt:libffrt", + ] + } else { + external_deps = [ + "hilog:libhilog", + "ipc:ipc_core", + ] + } + + external_deps += [ "init:libbegetutil" ] + install_images = [ chipset_base_dir ] + subsystem_name = "hdf" + part_name = "drivers_peripheral_nearlink" +} + +ohos_shared_library("libnearlink_hci_hdi_driver") { + 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 + } + branch_protector_ret = "pac_ret" + + cflags = [ + "-Os", + "-fdata-sections", + "-ffunction-sections", + "-fno-unwind-tables", + "-fno-asynchronous-unwind-tables", + "-fno-exceptions", + "-fno-rtti", + "-fPIC", + "-fno-common", + "-fstack-protector-strong", + "-fvisibility-inlines-hidden", + "-flto", + ] + cflags_cc = cflags + ldflags = [ + "-Wl,--as-needed", + "-Wl,--gc-sections", + "-Wl,--no-whole-archive", + ] + + include_dirs = [ + ".", + ] + + sources = [ "sle_dli_interface_driver.cpp" ] + + if (is_standard_system) { + external_deps = [ + "c_utils:utils", + "hdf_core:libhdf_host", + "hdf_core:libhdf_ipc_adapter", + "hdf_core:libhdf_utils", + "hdf_core:libhdi", + "hilog:libhilog", + "ipc:ipc_single", + ] + } else { + external_deps = [ + "hilog:libhilog", + "ipc:ipc_single", + ] + } + + external_deps += [ + "drivers_interface_nearlink:libnearlink_hci_stub_1.0", + "drivers_interface_nearlink:libnearlink_hci_stub_1.1", + ] + + shlib_type = "hdi" + install_images = [ chipset_base_dir ] + subsystem_name = "hdf" + part_name = "drivers_peripheral_nearlink" +} + +group("hdf_nearlink_service") { + deps = [ + ":libnearlink_hci_hdi_driver", + ":libsle_hci_interface_service_1.1", + ] +} diff --git a/nearlink/dli/dli_service/implement/dli_internal.h b/nearlink/dli/dli_service/implement/dli_internal.h new file mode 100644 index 0000000000..9349f42932 --- /dev/null +++ b/nearlink/dli/dli_service/implement/dli_internal.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2026 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 OHOS_HDI_NEARLINK_DLI_INTERNAL_H +#define OHOS_HDI_NEARLINK_DLI_INTERNAL_H + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace Dli { +typedef enum { + DLI_PACKET_TYPE_UNKNOWN = 0, + DLI_PACKET_TYPE_SLE_CMD = 0xA1, + DLI_PACKET_TYPE_SLE_EVENT = 0xA2, + DLI_PACKET_TYPE_SLE_ACB_DATA = 0xA3, + DLI_PACKET_TYPE_SLE_ICB_DATA = 0xA4, + DLI_PACKET_TYPE_MAX, +} DliPacketType; + +struct PacketHeader { + uint8_t headerSize; + uint8_t dataLengthOffset; + uint8_t dataLengthSize; +}; + +// opcode (DLI_SLE_Cmd_Complete_Evt opcode) +const uint16_t SLE_DLI_COMMAND_COMPLETE_EVENT = 0x0002; +} // namespace Dli +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS +#endif /* OHOS_HDI_NEARLINK_DLI_INTERNAL_H */ \ No newline at end of file diff --git a/nearlink/dli/dli_service/implement/dli_protocol.cpp b/nearlink/dli/dli_service/implement/dli_protocol.cpp new file mode 100644 index 0000000000..57859380a6 --- /dev/null +++ b/nearlink/dli/dli_service/implement/dli_protocol.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2026 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 +#include +#include +#include "nearlink_hdf_log.h" +#include "dli_protocol.h" +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace Dli { +const PacketHeader DliProtocol::header_[DLI_PACKET_TYPE_MAX] = { + {.headerSize = 0, .dataLengthOffset = 0, .dataLengthSize = 0}, /* 0 */ + {.headerSize = 4, .dataLengthOffset = 2, .dataLengthSize = 2}, /* 1 */ + {.headerSize = 4, .dataLengthOffset = 2, .dataLengthSize = 2}, /* 2 */ + {.headerSize = 4, .dataLengthOffset = 2, .dataLengthSize = 2}, /* 3 */ + {.headerSize = 4, .dataLengthOffset = 2, .dataLengthSize = 2}, /* 4 */ +}; + +const PacketHeader &DliProtocol::GetPacketHeaderInfo(DliPacketType packetType) +{ + if (packetType >= DLI_PACKET_TYPE_MAX) { + return header_[DLI_PACKET_TYPE_UNKNOWN]; + } + return header_[DliProtocol::TypeConvert(packetType)]; +} + +ssize_t DliProtocol::Read(int fd, uint8_t *data, size_t length) +{ + const int bufsize = 256; + char buf[bufsize] = {0}; + ssize_t ret = TEMP_FAILURE_RETRY(read(fd, data, length)); + if (ret == -1) { + strerror_r(errno, buf, sizeof(buf)); + HDF_LOGE("read failed"); + ret = 0; + } + return ret; +} + +ssize_t DliProtocol::Write(int fd, const uint8_t *data, size_t length) +{ + const int bufsize = 256; + char buf[bufsize] = {0}; + ssize_t ret = 0; + do { + ret = TEMP_FAILURE_RETRY(write(fd, data, length)); + } while (ret == -1 && errno == EAGAIN); + + if (ret == -1) { + strerror_r(errno, buf, sizeof(buf)); + HDF_LOGE("write failed"); + } else if (static_cast(ret) != length) { + HDF_LOGE("write data %{public}zd less than %{public}zu.", ret, length); + } + return ret; +} + +uint8_t DliProtocol::TypeConvert(DliPacketType packetType) +{ + switch (packetType) { + case DLI_PACKET_TYPE_SLE_EVENT: + return static_cast(DLI_PACKET_TYPE_SLE_EVENT) & 0x0F; + default: + HDF_LOGE("type convert error."); + return 0; + } +} +} // namespace Dli +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS \ No newline at end of file diff --git a/nearlink/dli/dli_service/implement/dli_protocol.h b/nearlink/dli/dli_service/implement/dli_protocol.h new file mode 100644 index 0000000000..427747c64b --- /dev/null +++ b/nearlink/dli/dli_service/implement/dli_protocol.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2026 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 OHOS_HDI_NEARLINK_DLI_PROTOCOL_H +#define OHOS_HDI_NEARLINK_DLI_PROTOCOL_H + +#include +#include + +#include +#include "dli_internal.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace Dli { +class DliProtocol { +public: + using DliDataCallback = std::function &data)>; + + DliProtocol() = default; + virtual ~DliProtocol() = default; + + virtual ssize_t SendPacket(const std::vector &packetData) = 0; + + const PacketHeader& GetPacketHeaderInfo(DliPacketType packetType); + +protected: + static ssize_t Read(int fd, uint8_t *data, size_t length); + static ssize_t Write(int fd, const uint8_t *data, size_t length); + static uint8_t TypeConvert(DliPacketType packetType); + static const PacketHeader header_[DLI_PACKET_TYPE_MAX]; +}; +} // namespace Dli +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS +#endif /* OHOS_HDI_NEARLINK_DLI_PROTOCOL_H */ \ No newline at end of file diff --git a/nearlink/dli/dli_service/implement/dli_watcher.cpp b/nearlink/dli/dli_service/implement/dli_watcher.cpp new file mode 100644 index 0000000000..34c9bccc09 --- /dev/null +++ b/nearlink/dli/dli_service/implement/dli_watcher.cpp @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2026 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 +#include +#include +#include +#include "nearlink_hdf_log.h" +#include "sle_hal_constant.h" +#include "dli_watcher.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace Dli { +DliWatcher::DliWatcher() +{} + +DliWatcher::~DliWatcher() +{ + Stop(); +} + +bool DliWatcher::AddFdToWatcher(int fd, DliDataCallback callback) +{ + std::lock_guard lock(fdsMutex_); + fds_[fd] = callback; + ThreadWakeup(); + return true; +} + +bool DliWatcher::RemoveFdToWatcher(int fd) +{ + std::lock_guard lock(fdsMutex_); + fds_.erase(fd); + ThreadWakeup(); + return true; +} + +bool DliWatcher::SetTimeout(std::chrono::milliseconds timeout, TimeoutCallback callback) +{ + std::chrono::seconds seconds = std::chrono::duration_cast(timeout); + std::lock_guard lock(timeoutMutex_); + timeoutTimer_.tv_sec = seconds.count(); + timeoutTimer_.tv_usec = (timeout - seconds).count(); + timeoutCallback_ = callback; + ThreadWakeup(); + return true; +} + +bool DliWatcher::Start() +{ + if (running_.exchange(true)) { + return true; + } + + { + std::lock_guard lock(wakeupPipeMutex_); + if (pipe(wakeupPipe_) != 0) { + HDF_LOGE("DliWatcher create pipe failed."); + running_.exchange(false); + return false; + } + } + + thread_ = std::thread(std::bind(&DliWatcher::WatcherThread, this)); + if (!thread_.joinable()) { + HDF_LOGE("thread is not joinable."); + running_.exchange(false); + return false; + } + + int policy = SLE_THREAD_POLICY; + sched_param params = {.sched_priority = SLE_THREAD_PRIORITY}; + if (pthread_setschedparam(thread_.native_handle(), policy, ¶ms) != 0) { + HDF_LOGW("pthread_setschedparam failed tid[%{public}lu] policy[%{public}d]", thread_.native_handle(), policy); + } + + return true; +} + +bool DliWatcher::Stop() +{ + if (!running_.exchange(false)) { + return true; + } + + ThreadWakeup(); + thread_.join(); + + { + std::lock_guard lock(wakeupPipeMutex_); + close(wakeupPipe_[0]); + close(wakeupPipe_[1]); + } + HDF_LOGI("DliWatcher stop"); + return true; +} + +void DliWatcher::CheckFdReady(std::map& fds, fd_set &readFds) +{ + std::lock_guard lock(fdsMutex_); + for (auto &&fd : fds_) { + if (FD_ISSET(fd.first, &readFds)) { + fd.second(fd.first); + } + } +} + +void DliWatcher::InitReadFds(fd_set &readFds, int &nfds) +{ + FD_ZERO(&readFds); + { + std::lock_guard lock(wakeupPipeMutex_); + FD_SET(wakeupPipe_[0], &readFds); + nfds = wakeupPipe_[0]; + } + { + std::lock_guard lock(fdsMutex_); + for (auto &&fd : fds_) { + FD_SET(fd.first, &readFds); + nfds = std::max(fd.first, nfds); + } + } +} + +void DliWatcher::HandleTimeout() +{ + TimeoutCallback callback; + { + std::lock_guard lock(timeoutMutex_); + callback = timeoutCallback_; + } + if (callback) { + callback(); + } +} + +void DliWatcher::HandleSelectEvent(fd_set &readFds) +{ + { + std::lock_guard lock(wakeupPipeMutex_); + if (FD_ISSET(wakeupPipe_[0], &readFds)) { + uint8_t buff = 0; + TEMP_FAILURE_RETRY(read(wakeupPipe_[0], &buff, sizeof(buff))); + } + } + if (running_) { + CheckFdReady(fds_, readFds); + } +} + +void DliWatcher::WatcherThread() +{ + fd_set readFds; + int nfds; + timeval *timeout = nullptr; + + while (running_) { + InitReadFds(readFds, nfds); + { + std::lock_guard lock(timeoutMutex_); + if (timeoutTimer_.tv_sec == 0 && timeoutTimer_.tv_usec == 0) { + timeout = nullptr; + } else { + timeout = &timeoutTimer_; + } + } + int ret = select(nfds + 1, &readFds, nullptr, nullptr, timeout); + if (ret < 0) { + continue; + } else if (ret == 0) { + HandleTimeout(); + } else { + HandleSelectEvent(readFds); + } + } + HDF_LOGI("DliWatcher thread is stop!"); +} + +void DliWatcher::ThreadWakeup() +{ + std::lock_guard lock(wakeupPipeMutex_); + uint8_t buff = 0; + ssize_t ret = TEMP_FAILURE_RETRY(write(wakeupPipe_[1], &buff, sizeof(buff))); + if (ret == -1) { + HDF_LOGE("wake up failed err:%{public}s", strerror(errno)); + } +} +} // namespace Dli +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS \ No newline at end of file diff --git a/nearlink/dli/dli_service/implement/dli_watcher.h b/nearlink/dli/dli_service/implement/dli_watcher.h new file mode 100644 index 0000000000..8117ef49ce --- /dev/null +++ b/nearlink/dli/dli_service/implement/dli_watcher.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2026 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 OHOS_HDI_NEARLINK_DLI_WATCHER_H +#define OHOS_HDI_NEARLINK_DLI_WATCHER_H + +#include +#include +#include +#include +#include +#include +#include + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace Dli { +class DliWatcher { +public: + using DliDataCallback = std::function; + using TimeoutCallback = std::function; + + DliWatcher(); + ~DliWatcher(); + + bool AddFdToWatcher(int fd, DliDataCallback callback); + bool RemoveFdToWatcher(int fd); + bool SetTimeout(std::chrono::milliseconds timeout, TimeoutCallback callback); + bool Start(); + bool Stop(); + +private: + void CheckFdReady(std::map& fds, fd_set &readFds); + void InitReadFds(fd_set &readFds, int &nfds); + void HandleTimeout(); + void HandleSelectEvent(fd_set &readFds); + void WatcherThread(); + void ThreadWakeup(); + +private: + std::atomic_bool running_ = {false}; + std::map fds_; + std::mutex fdsMutex_; + std::mutex wakeupPipeMutex_; + int wakeupPipe_[2] = {0}; + timeval timeoutTimer_ = {}; + TimeoutCallback timeoutCallback_; + std::mutex timeoutMutex_; + std::thread thread_; +}; +} // namespace Dli +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS +#endif /* OHOS_HDI_NEARLINK_DLI_WATCHER_H */ \ No newline at end of file diff --git a/nearlink/dli/dli_service/implement/h4_protocol.cpp b/nearlink/dli/dli_service/implement/h4_protocol.cpp new file mode 100644 index 0000000000..6a01e233d1 --- /dev/null +++ b/nearlink/dli/dli_service/implement/h4_protocol.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2026 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 +#include +#include +#include "nearlink_hdf_log.h" +#include "h4_protocol.h" +#include +#include "sle_hal_constant.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace Dli { +constexpr const char *SLE_MAC_LIB = "libnearlink_mac.z.so"; +constexpr const char *SET_VIP_PRIO = "SetVipPrio"; +constexpr int NEARLINK_HOST_PRIORITY = 10; + +thread_local bool H4Protocol::isThreadPromoted = false; + +H4Protocol::H4Protocol( + int fd, DliDataCallback onAcbReceive, DliDataCallback onIcbReceive, DliDataCallback onEventReceive) + : dliFd_(fd), onAcbReceive_(onAcbReceive), onIcbReceive_(onIcbReceive), onEventReceive_(onEventReceive) +{} + +ssize_t H4Protocol::SendPacket(const std::vector &packetData) +{ + SetRTSchedule(); + ssize_t writtenNumber = 0; + ssize_t ret = 0; + do { + ret = Write(dliFd_, packetData.data() + writtenNumber, packetData.size() - writtenNumber); + if (ret > 0) { + writtenNumber += ret; + } else if (ret < 0) { + return ret; + } + } while (static_cast(writtenNumber) != packetData.size()); + return writtenNumber; +} + +static bool ReadLengthCheck(ssize_t readLen, char *buf, int fd) +{ + const int bufsize = 256; + if (readLen < 0) { + strerror_r(errno, buf, bufsize); + HDF_LOGE("read fd[%{public}d] fail", fd); + return false; + } else if (readLen == 0) { + HDF_LOGE("read fd[%{public}d] readLen = 0.", fd); + return false; + } + return true; +} + +void H4Protocol::ReadData(int fd) +{ + SetRTSchedule(); + const int bufsize = 256; + char buf[bufsize] = {0}; + static uint8_t typeNo{0}; + ssize_t readLen = 0; + if (dliPacket_.size() == 0) { + readLen = Read(fd, &packetType_, sizeof(packetType_)); + NL_HDF_CHECK_RETURN(readLen > 0, "read fd[%{public}d], readLen[%{public}zd]", fd, readLen); + typeNo = (packetType_) & 0x0F; + if (packetType_ > DLI_PACKET_TYPE_UNKNOWN && packetType_ < DLI_PACKET_TYPE_MAX) { + dliPacket_.resize(header_[typeNo].headerSize); + } + } else if (dliPacket_.size() == header_[typeNo].headerSize) { + readLen = Read(fd, dliPacket_.data() + readLength_, dliPacket_.size() - readLength_); + NL_HDF_CHECK_RETURN(ReadLengthCheck(readLen, buf, fd), + "hciPacket size[%{public}zu], readLength[%{public}u]", dliPacket_.size(), readLength_); + readLength_ += readLen; + if (readLength_ == dliPacket_.size()) { + size_t dataLen = 0; + for (int ii = 0; ii < header_[typeNo].dataLengthSize; ii++) { + dataLen += (dliPacket_[header_[typeNo].dataLengthOffset + ii] << (ii * 0x08)); + } + if (dataLen == 0) { + HDF_LOGE("dataLen == 0, proc data error."); + dliPacket_.clear(); + readLength_ = 0; + typeNo = 0; + } else { + dliPacket_.resize(dliPacket_.size() + dataLen); + } + } + } else { + readLen = Read(fd, dliPacket_.data() + readLength_, dliPacket_.size() - readLength_); + NL_HDF_CHECK_RETURN(ReadLengthCheck(readLen, buf, fd), + "hciPacket size[%{public}zu], readLength[%{public}u]", dliPacket_.size(), readLength_); + readLength_ += readLen; + if (readLength_ == dliPacket_.size()) { + PacketCallback(); + dliPacket_.clear(); + readLength_ = 0; + typeNo = 0; + } + } +} + +H4Protocol::~H4Protocol() {} + +void H4Protocol::PacketCallback() +{ + switch (packetType_) { + case DLI_PACKET_TYPE_SLE_ACB_DATA: + if (onAcbReceive_) { + onAcbReceive_(dliPacket_); + } + break; + case DLI_PACKET_TYPE_SLE_ICB_DATA: + if (onIcbReceive_) { + onIcbReceive_(dliPacket_); + } + break; + case DLI_PACKET_TYPE_SLE_EVENT: + if (onEventReceive_) { + onEventReceive_(dliPacket_); + } + break; + default: + HDF_LOGE("PacketCallback type[%{public}d] error.", packetType_); + break; + } +} + +bool SetVipPrio(unsigned int vipPrio) +{ + void *libMac = dlopen(SLE_MAC_LIB, RTLD_LAZY); + if (libMac == nullptr) { + HDF_LOGI("SetVipPrio no mac lib ready for dlopen"); + return false; + } + using GetMacFun = bool (*)(unsigned int); + GetMacFun setVipPrio = reinterpret_cast(dlsym(libMac, SET_VIP_PRIO)); + if (setVipPrio == nullptr) { + HDF_LOGE("SetVipPrio dlsym error"); + dlclose(libMac); + return false; + } + bool result = false; + result = setVipPrio(vipPrio); + dlclose(libMac); + return result; +} + +void H4Protocol::SetRTSchedule() +{ + if (isThreadPromoted) { + return; + } + SetVipPrio(NEARLINK_HOST_PRIORITY); + pid_t tid = gettid(); + struct sched_param rtParams = {.sched_priority = SLE_THREAD_PRIORITY}; + int rc = sched_setscheduler(tid, SCHED_FIFO, &rtParams); + isThreadPromoted = (rc != 0) ? false : true; +} +} // namespace Dli +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS \ No newline at end of file diff --git a/nearlink/dli/dli_service/implement/h4_protocol.h b/nearlink/dli/dli_service/implement/h4_protocol.h new file mode 100644 index 0000000000..bb6bc894f8 --- /dev/null +++ b/nearlink/dli/dli_service/implement/h4_protocol.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2026 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 OHOS_HDI_NEARLINK_DLI_H4_PROTOCOL_H +#define OHOS_HDI_NEARLINK_DLI_H4_PROTOCOL_H + +#include "dli_protocol.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace Dli { +class H4Protocol : public DliProtocol { +public: + H4Protocol(int fd, DliDataCallback onAcbReceive, DliDataCallback onIcbReceive, DliDataCallback onEventReceive); + + ssize_t SendPacket(const std::vector &packetData) override; + void ReadData(int fd); + ~H4Protocol() override; + +private: + void PacketCallback(); + void SetRTSchedule(); + +private: + int dliFd_ = 0; + DliDataCallback onAcbReceive_; + DliDataCallback onIcbReceive_; + DliDataCallback onEventReceive_; + thread_local static bool isThreadPromoted; + + uint8_t packetType_ = 0; + + std::vector dliPacket_; + uint32_t readLength_ = 0; +}; +} // namespace Dli +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS + +#endif /* OHOS_HDI_NEARLINK_DLI_H4_PROTOCOL_H */ \ No newline at end of file diff --git a/nearlink/dli/dli_service/implement/nearlink_hdf_log.h b/nearlink/dli/dli_service/implement/nearlink_hdf_log.h new file mode 100644 index 0000000000..db090cb4a2 --- /dev/null +++ b/nearlink/dli/dli_service/implement/nearlink_hdf_log.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2026 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 NARLINK_HDF_LOG_H +#define NARLINK_HDF_LOG_H + +#include + +#ifdef LOG_DOMAIN +#undef LOG_DOMAIN +#endif +#define LOG_DOMAIN 0xD000154 + +#ifndef HDF_LOG_TAG +#define HDF_LOG_TAG nearlink_hdf +#endif + +#ifdef NL_HDF_CHECK_RETURN +#undef NL_HDF_CHECK_RETURN +#endif + +#define NL_HDF_CHECK_RETURN(cond, fmt, ...) \ + do { \ + if (!(cond)) { \ + HDF_LOGE(fmt, ##__VA_ARGS__); \ + return; \ + } \ + } while (0) + +#endif // NARLINK_HDF_LOG_H \ No newline at end of file diff --git a/nearlink/dli/dli_service/implement/ohos_sle_vendor_lib.h b/nearlink/dli/dli_service/implement/ohos_sle_vendor_lib.h new file mode 100644 index 0000000000..959362ae02 --- /dev/null +++ b/nearlink/dli/dli_service/implement/ohos_sle_vendor_lib.h @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2026 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 SLE_VENDOR_LIB_H +#define SLE_VENDOR_LIB_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Define DLI channel descriptors array used in SLE_OP_DLI_CHANNEL_OPEN operation. + */ +typedef enum { + DLI_CMD, // DLI Command channel + DLI_EVT, // DLI Event channel + DLI_ACB_OUT, // DLI ACB downstream channel + DLI_ACB_IN, // DLI ACB upstream channel + DLI_MAX_CHANNEL // Total channels +} DliChannelsT; + +typedef enum { + SLE_OP_RESULT_SUCCESS, + SLE_OP_RESULT_FAIL, +} SleOpResultT; + +/** + * SLE vendor lib cmd. + */ +typedef enum { + /** + * Power on the SLE Controller. + * @return 0 if success. + */ + SLE_OP_POWER_ON, + + /** + * Power off the SLE Controller. + * @return 0 if success. + */ + SLE_OP_POWER_OFF, + + /** + * Establish dli channels. it will be called after SLE_OP_POWER_ON. + * @param int (*)[DLI_MAX_CHANNEL]. + * @return fd count. + */ + SLE_OP_DLI_CHANNEL_OPEN, + + /** + * Close all the dli channels which is opened. + */ + SLE_OP_DLI_CHANNEL_CLOSE, + + /** + * initialization the SLE Controller. it will be called after SLE_OP_DLI_CHANNEL_OPEN. + * Controller Must call initCb to notify the host once it has been done. + */ + SLE_OP_INIT, + + /** + * Get the LPM idle timeout in milliseconds. + * @param (uint_32 *)milliseconds, slec will return the value of lpm timer. + * @return 0 if success. + */ + SLE_OP_GET_LPM_TIMER, + + /** + * Enable LPM mode on SLE Controller. + */ + SLE_OP_LPM_ENABLE, + + /** + * Disable LPM mode on SLE Controller. + */ + SLE_OP_LPM_DISABLE, + + /** + * Wakeup lock the SLEC. + */ + SLE_OP_WAKEUP_LOCK, + + /** + * Wakeup unlock the SLEC. + */ + SLE_OP_WAKEUP_UNLOCK, + + /** + * transmit event response to vendor lib. + * @param (void *)buf, struct of HC_SLE_HDR. + */ + SLE_OP_EVENT_CALLBACK +} SleOpcodeT; + +/** + * initialization callback. + */ +typedef void (*InitCallback)(SleOpResultT result); + +/** + * Nearlink Host/Controller VENDOR Interface + */ +typedef struct { + /** + * Set to sizeof(sle_vndor_interface_t) + */ + size_t size; + + /** + * Caller will open the interface and pass in the callback routines + * to the implementation of this interface. + */ + int (*init)(void); + + /** + * Vendor specific operations + */ + int (*op)(int opcode, void* param); + + /** + * Closes the interface + */ + void (*close)(void); +} SleVendorInterfaceT; + +typedef struct { + uint16_t event; + uint16_t len; + uint16_t offset; + uint16_t layerSpecific; + uint8_t data[]; +} HC_SLE_HDR; + +#ifdef __cplusplus +} +#endif + +#endif /* SLE_VENDOR_LIB_H */ diff --git a/nearlink/dli/dli_service/implement/sle_address.cpp b/nearlink/dli/dli_service/implement/sle_address.cpp new file mode 100644 index 0000000000..c0f9ba32a7 --- /dev/null +++ b/nearlink/dli/dli_service/implement/sle_address.cpp @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2026 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 +#include +#include +#include +#include +#include +#include "securec.h" +#include "dli_internal.h" +#include "nearlink_hdf_log.h" +#include "sle_address.h" +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace Dli { +namespace { +constexpr int ADDRESS_STR_LEN = 17; +constexpr int ADDRESS_SIZE = 6; +constexpr const char *SLE_MAC_LIB = "libnearlink_mac.z.so"; +constexpr const char *GET_SLE_MAC_SYMBOL_NAME = "GetConstantMac"; +} // namespace + +SleAddress::SleAddress() +{ + address_.resize(ADDRESS_SIZE); +} + +constexpr int START_POS = 6; +constexpr int END_POS = 13; +constexpr int ADDR_BYTE = 18; +std::string SleAddress::GetEncryptAddr(std::string addr) +{ + if (addr.empty() || addr.length() != ADDRESS_STR_LEN) { + HDF_LOGE("addr is invalid, length= %{public}zu", addr.length()); + return std::string(""); + } + std::string tmp = "**:**:**:**:**:**"; + std::string out = addr; + for (int i = START_POS; i <= END_POS; i++) { + out[i] = tmp[i]; + } + return out; +} + +void SleAddress::ParseAddressToString(std::vector &address, std::string &outString) +{ + char temp[ADDR_BYTE] = {0}; + int ret = sprintf_s(temp, sizeof(temp), "%02X:%02X:%02X:%02X:%02X:%02X", + address[0], address[1], address[2], address[3], address[4], address[5]); + if (ret == -1) { + HDF_LOGE("ConvertAddr sprintf_s return error, ret -1"); + } + outString = temp; +} + +int SleAddress::ParseAddressFromString(const std::string &string) const +{ + size_t offset = 0; + int bytesIndex = 0; + int readCount = 0; + for (bytesIndex = 0; bytesIndex < ADDRESS_SIZE && offset < string.size(); bytesIndex++) { + readCount = 0; + if (sscanf_s(&string[offset], "%02hhx:%n", &address_[bytesIndex], &readCount) > 0) { + if (readCount == 0 && bytesIndex != ADDRESS_SIZE - 1) { + return bytesIndex; + } + offset += static_cast(readCount); + } else { + break; + } + } + + return bytesIndex; +} + +bool SleAddress::GetConstantAddress(char *address, int len) +{ + if (address == nullptr || len < ADDRESS_STR_LEN + 1) { + HDF_LOGE("GetConstantAddress buf error"); + return false; + } + + void *libMac = dlopen(SLE_MAC_LIB, RTLD_LAZY); + if (libMac == nullptr) { + HDF_LOGI("GetConstantAddress no mac lib ready for dlopen"); + return false; + } + + using GetMacFun = int (*)(char*, int); + GetMacFun getMac = reinterpret_cast(dlsym(libMac, GET_SLE_MAC_SYMBOL_NAME)); + if (getMac == nullptr) { + HDF_LOGE("GetConstantAddress dlsym error"); + dlclose(libMac); + return false; + } + + int ret = getMac(address, len); + HDF_LOGI("GetConstantAddress ret: %{public}d", ret); + dlclose(libMac); + return (ret == 0); +} + +#ifdef RELOAD_ADDRESS +// system boot less 2min, need ReadSleAddress from NV +bool SleAddress::NeedReloadAddress() +{ + const int64_t maxNeedReloadTime = 120000; // 120s + constexpr int64_t msPerSecond = 1000; + constexpr int64_t nsPerMs = 1000000; + struct timespec times = {0}; + if (clock_gettime(CLOCK_MONOTONIC, ×) < 0) { + HDF_LOGE("Failed clock_gettime:%{public}s, needReloadAddress:false", strerror(errno)); + return false; + } + int64_t relativeTime = ((times.tv_sec * msPerSecond) + (times.tv_nsec / nsPerMs)); + HDF_LOGI("relativeTime:%{public}lu", relativeTime); + return relativeTime < maxNeedReloadTime; +} +#endif + +std::shared_ptr SleAddress::UpdateAddressFromNV(const std::string &path) +{ + const int bufsize = 256; + char buf[bufsize] = {0}; + int newFd = open(path.c_str(), O_RDWR | O_CREAT, 00644); + HDF_LOGI("GetDeviceAddress open newFd %{public}d.", newFd); + char addressStr[ADDRESS_STR_LEN + 1] = {"00:11:22:33:44:55"}; + bool readNVSucc = GetConstantAddress(addressStr, ADDRESS_STR_LEN + 1); + bool needUpdateTxt = true; + if (newFd < 0) { + auto ptr = std::make_shared(); + int ret = ptr->ParseAddressFromString(addressStr); + if (ret != ADDRESS_SIZE) { + HDF_LOGE("UpdateAddressFromNV ParseAddressFromString failed, ret:%{public}d.", ret); + return nullptr; + } + return ptr; + } + if (!readNVSucc) { + // read NV fail ,if slemac.txt exsit mac, not update, needUpdateTxt = false + if (read(newFd, addressStr, ADDRESS_STR_LEN) != ADDRESS_STR_LEN) { + auto tmpPtr = GenerateDeviceAddress(); + std::string strAddress; + ParseAddressToString(tmpPtr->address_, strAddress); + HDF_LOGI("device mac addr: %{public}s", GetEncryptAddr(strAddress).c_str()); + int ret = strcpy_s(addressStr, ADDRESS_STR_LEN + 1, strAddress.c_str()); + if (ret != 0) { + HDF_LOGE("ParseAddressToString strcpy_s err!"); + } + } else { + HDF_LOGI("newFd %{public}d not update", newFd); + needUpdateTxt = false; + } + } + if (needUpdateTxt) { + int fdRet = write(newFd, addressStr, ADDRESS_STR_LEN); + if (fdRet < 0) { + strerror_r(errno, buf, sizeof(buf)); + HDF_LOGE("GetDeviceAddress addr write failed, err:%{public}s.", buf); + } + } + close(newFd); + auto ptr = std::make_shared(); + int result = ptr->ParseAddressFromString(addressStr); + if (result != ADDRESS_SIZE) { + HDF_LOGE("UpdateAddressFromNV ParseAddressFromString failed, result:%{public}d.", result); + return nullptr; + } + return ptr; +} + +std::shared_ptr SleAddress::GetDeviceAddress(const std::string &path) +{ +#ifdef RELOAD_ADDRESS + if (NeedReloadAddress()) { + return UpdateAddressFromNV(path); + } +#endif + int addrFd = open(path.c_str(), O_RDONLY); + if (addrFd < 0) { + return UpdateAddressFromNV(path); + } + char addressStr[ADDRESS_STR_LEN + 1] = {0}; + if (read(addrFd, addressStr, ADDRESS_STR_LEN) != ADDRESS_STR_LEN) { + HDF_LOGE("read %{public}s failed.", path.c_str()); + close(addrFd); + return UpdateAddressFromNV(path); + } + close(addrFd); + auto ptr = std::make_shared(); + int result = ptr->ParseAddressFromString(addressStr); + if (result != ADDRESS_SIZE) { + HDF_LOGE("GetDeviceAddress ParseAddressFromString failed, result:%{public}d.", result); + return UpdateAddressFromNV(path); + } + return ptr; +} + +std::shared_ptr SleAddress::GenerateDeviceAddress(const std::string &prefix) +{ + const int bufsize = 256; + char buf[bufsize] = {0}; + auto ptr = std::make_shared(); + char addressStr[ADDRESS_STR_LEN + 1] = {"00:11:22:33:44:55"}; + ptr->ParseAddressFromString(addressStr); + int prefixCount = ptr->ParseAddressFromString(prefix); + if (prefixCount < ADDRESS_SIZE) { + int fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + strerror_r(errno, buf, sizeof(buf)); + HDF_LOGE("open /dev/urandom failed err:%{public}s.", buf); + return ptr; + } + if (read(fd, &ptr->address_[prefixCount], ADDRESS_SIZE - prefixCount) != ADDRESS_SIZE - prefixCount) { + strerror_r(errno, buf, sizeof(buf)); + HDF_LOGE("read /dev/urandom failed err:%{public}s.", buf); + } + close(fd); + } + return ptr; +} + +void SleAddress::ReadAddress(std::vector &address) const +{ + address = address_; +} + +void SleAddress::ReadAddress(std::string &address) const +{ + address.resize(ADDRESS_STR_LEN + 1); + + int offset = 0; + for (int ii = 0; ii < ADDRESS_SIZE; ii++) { + int ret = snprintf_s( + &address[offset], (ADDRESS_STR_LEN + 1) - offset, ADDRESS_STR_LEN - offset, "%02x:", address_[ii]); + if (ret < 0) { + break; + } + offset += ret; + } +} +} // namespace Dli +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS \ No newline at end of file diff --git a/nearlink/dli/dli_service/implement/sle_address.h b/nearlink/dli/dli_service/implement/sle_address.h new file mode 100644 index 0000000000..f961856173 --- /dev/null +++ b/nearlink/dli/dli_service/implement/sle_address.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2026 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 OHOS_HDI_NEARLINK_HCI_NEARLINK_ADDRESS_H +#define OHOS_HDI_NEARLINK_HCI_NEARLINK_ADDRESS_H + +#include +#include +#include + +#include "sle_hal_constant.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace Dli { +class SleAddress { +public: + SleAddress(); + ~SleAddress() = default; + static std::shared_ptr GetDeviceAddress(const std::string &path = SLE_DEVICE_ADDRESS_PATH); + static std::shared_ptr GenerateDeviceAddress(const std::string &prefix = ""); + static void ParseAddressToString(std::vector &address, std::string &outString); + static std::string GetEncryptAddr(std::string addr); + void ReadAddress(std::vector &address) const; + void ReadAddress(std::string &address) const; + +private: + int ParseAddressFromString(const std::string &string) const; + static bool GetConstantAddress(char *address, int len); +#ifdef RELOAD_ADDRESS + static bool NeedReloadAddress(); +#endif + static std::shared_ptr UpdateAddressFromNV(const std::string &path); + +private: + std::vector address_; +}; +} // namespace Dli +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS +#endif /* OHOS_HDI_NEARLINK_HCI_NEARLINK_ADDRESS_H */ \ No newline at end of file diff --git a/nearlink/dli/dli_service/implement/sle_hal_constant.h b/nearlink/dli/dli_service/implement/sle_hal_constant.h new file mode 100644 index 0000000000..dc69509626 --- /dev/null +++ b/nearlink/dli/dli_service/implement/sle_hal_constant.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2026 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 OHOS_HDI_NEARLINK_HCI_CONSTANT_H +#define OHOS_HDI_NEARLINK_HCI_CONSTANT_H + +#include + +#include + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace Dli { +constexpr const char *SLE_VENDOR_NAME = "libnearlink_sle_vendor"; +constexpr const char *SLE_CHIP_TYPE = "const.nearlink.slechiptype"; +constexpr const char *SLE_VENDOR_INTERFACE_SYMBOL_NAME = "NEARLINK_VENDOR_LIB_INTERFACE"; +constexpr const char *SLE_DEVICE_ADDRESS_PATH = "/data/vendor/nearlink/slemac.txt"; +constexpr int SLE_THREAD_POLICY = SCHED_RR; +constexpr int SLE_THREAD_PRIORITY = 1; +} // namespace Dli +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS + +#endif /* OHOS_HDI_NEARLINK_HCI_CONSTANT_H */ \ No newline at end of file diff --git a/nearlink/dli/dli_service/implement/thread_util.cpp b/nearlink/dli/dli_service/implement/thread_util.cpp new file mode 100644 index 0000000000..985abfd185 --- /dev/null +++ b/nearlink/dli/dli_service/implement/thread_util.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2026 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 "thread_util.h" +#include +#include "ffrt_inner.h" +#include +#include "nearlink_hdf_log.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { + +void DoInDliThread(const ThreadUtilFunc &func) +{ + ThreadUtil::GetInstance().PostTask(func); +} + +struct ThreadUtil::impl { + class TaskQueue { + public: + explicit TaskQueue(const char *name) : queue_(name, ffrt::queue_attr().qos(ffrt::qos_user_interactive)) {} + ~TaskQueue() = default; + + void PostTask(const ThreadUtilFunc &func); + int GetQueueId(void); + + private: + ffrt::queue queue_; + }; + + impl(); + ~impl() = default; + std::shared_ptr CreateTaskQueue(); + + std::shared_ptr taskQueue; +}; + +ThreadUtil::impl::impl() +{} + +ThreadUtil::ThreadUtil() : pimpl(std::make_unique()) +{} + +ThreadUtil::~ThreadUtil() +{} + +void ThreadUtil::impl::TaskQueue::PostTask(const ThreadUtilFunc &func) +{ + queue_.submit(func); +} + +int ThreadUtil::impl::TaskQueue::GetQueueId(void) +{ + int id = -1; + auto handle = queue_.submit_h([&id]() { + id = ffrt::get_queue_id(); + }); + queue_.wait(handle); + return id; +} + +void ThreadUtil::PostTask(const ThreadUtilFunc &func) +{ + std::shared_ptr taskQueue = pimpl->taskQueue; + if (taskQueue != nullptr) { + taskQueue->PostTask(func); + return; + } + // If the thread not found, create it. + taskQueue = pimpl->CreateTaskQueue(); + // Execute the first task. + if (taskQueue) { + taskQueue->PostTask(func); + } +} + +std::shared_ptr ThreadUtil::impl::CreateTaskQueue() +{ + std::string threadName = "sle_hci"; + auto taskQueue_ = std::make_shared(threadName.c_str()); + + int queueId = taskQueue_->GetQueueId(); + HDF_LOGI("sle_ffrt_queue: queueId(%{public}d), name(%{public}s)", queueId, threadName.c_str()); + + taskQueue = taskQueue_; + return taskQueue_; +} + +ThreadUtil &ThreadUtil::GetInstance() +{ + static ThreadUtil instance; + return instance; +} +} // namespace Nearlink +} // namepsace HDI +} // namespace OHOS \ No newline at end of file diff --git a/nearlink/dli/dli_service/implement/thread_util.h b/nearlink/dli/dli_service/implement/thread_util.h new file mode 100644 index 0000000000..afc3ac7f31 --- /dev/null +++ b/nearlink/dli/dli_service/implement/thread_util.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2026 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 SLE_THREAD_UTIL_H +#define SLE_THREAD_UTIL_H + +#include +#ifdef RESOURCESCHEDULE_FFRT_ENABLE +#include "ffrt_inner.h" +#include +#include "nearlink_hdf_log.h" +#else +#include +#endif // RESOURCESCHEDULE_FFRT_ENABLE + +namespace OHOS { +namespace HDI { +namespace Nearlink { + +using ThreadUtilFunc = std::function; + +/** + * @brief Post the task to the dli thread. + * @param func The task to be executed. + */ +void DoInDliThread(const ThreadUtilFunc &func); + +class ThreadUtil { +public: + void PostTask(const ThreadUtilFunc &func); + static ThreadUtil &GetInstance(); +private: + ThreadUtil(); + ~ThreadUtil(); + + struct impl; + std::unique_ptr pimpl; +}; +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS + +#endif // SLE_THREAD_UTIL_H \ No newline at end of file diff --git a/nearlink/dli/dli_service/implement/vendor_interface.cpp b/nearlink/dli/dli_service/implement/vendor_interface.cpp new file mode 100644 index 0000000000..e85ee6d59e --- /dev/null +++ b/nearlink/dli/dli_service/implement/vendor_interface.cpp @@ -0,0 +1,461 @@ +/* + * Copyright (C) 2026 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 +#include +#include +#include +#include "common_timer_errors.h" +#include "nearlink_hdf_log.h" +#include "sle_address.h" +#include "sle_hal_constant.h" +#include "timer.h" +#include "h4_protocol.h" +#include "vendor_interface.h" +#include "parameters.h" +#include "thread_util.h" +#include +#include +#include + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace Dli { +namespace V1_1 { + +constexpr size_t DLI_PACKET_TYPE_SIZE = 1; +constexpr uint16_t DLI_SET_SLE_ADDR = 0x0405; +/* Define the preamble length for all DLI Commands. This is 2-bytes for opcode and 2 byte for length */ +constexpr size_t DLIC_PREAMBLE_SIZE = 4; +/* Device address length */ +constexpr int BD_ADDR_LEN = 6; +constexpr int OFFSET_EIGHT_BITS = 8; +constexpr int OFFSET_STATUS = 3; +constexpr size_t SLE_VENDOR_INVALID_DATA_LEN = 0; +constexpr int DLI_INTERFACE_CLOSED = 0; +constexpr int DLI_INTERFACE_OPENING = 1; +constexpr int DLI_INTERFACE_OPENED = 2; +constexpr int SET_ADDR_TIME_OUT_MS = 200; + +struct InternalCommand { + uint16_t cb; + uint16_t opcode; +}; + +struct TaskConfig { + pid_t pid; + unsigned int value; +}; + +#define SET_VIP_PRIO 25 +#define PERF_CTRL_MAGIC 'x' +#define PERF_CTRL_SET_VIP_PRIO \ + _IOW(PERF_CTRL_MAGIC, SET_VIP_PRIO, struct TaskConfig) + +class VendorInterface::Impl { +public: + bool Initialize(VendorInterface::InitializeCompleteCallback initializeCompleteCallback, + const VendorInterface::ReceiveCallback &receiveCallback); + void CleanUp(); + size_t SendPacket(const std::vector &packet); + void SetSleAddress(uint8_t *localSleAddr); + uint8_t *TransformAddress(uint8_t *addr); + void OnEventReceived(const std::vector &data); + void OnAcbReceived(const std::vector &data); + void OnIcbReceived(const std::vector &data); + void SetSleAddressTimeOut(); + +public: + std::mutex setAddrFinishedMutex_ {}; + bool isSetAddrFinished_ = false; // guarded by setAddrFinishedMutex_ + std::condition_variable setAddrConditionVariable_ {}; + std::shared_ptr dli_ = nullptr; + +private: + void OnInitCallback(SleOpResultT result); + bool WatchDliChannel(const VendorInterface::ReceiveCallback &receiveCallback); + void WatcherTimeout(); + void GetFullVendorName(std::string &name); + +private: + VendorInterface::InitializeCompleteCallback initializeCompleteCallback_; + ReceiveDataCallback eventDataCallback_ = nullptr; + ReceiveDataCallback acbDataCallback_ = nullptr; + ReceiveDataCallback icbDataCallback_ = nullptr; + void* vendorHandle_ = nullptr; + SleVendorInterfaceT *vendorInterface_ = nullptr; + DliWatcher watcher_; + uint32_t lpmTimer_ = 0; + InternalCommand internalCommand_ = {0, 0}; + std::shared_ptr sleAddress_ = nullptr; + int dliInterfaceState_ = DLI_INTERFACE_CLOSED; +}; + +VendorInterface::VendorInterface() : impl_(std::make_unique()) +{ + HDF_LOGI("VendorInterface Constructor."); +} + +VendorInterface::~VendorInterface() +{ + HDF_LOGW("VendorInterface destructor."); + CleanUp(); +} + +bool VendorInterface::Initialize(InitializeCompleteCallback initializeCompleteCallback, + const ReceiveCallback &receiveCallback) +{ + std::promise promise; + vendorInterfaceWeak_ = shared_from_this(); + Nearlink::DoInDliThread([this, &initializeCompleteCallback, cb = receiveCallback, &promise]() { + const ReceiveCallback &safeReceiveCallback = cb; + bool result = impl_->Initialize(initializeCompleteCallback, safeReceiveCallback); + promise.set_value(result); + }); + return promise.get_future().get(); +} + +void VendorInterface::CleanUp() +{ + std::promise promise; + Nearlink::DoInDliThread([this, &promise]() { + this->impl_->CleanUp(); + promise.set_value(); + }); + promise.get_future().get(); + return; +} + +size_t VendorInterface::SendPacket(const std::vector &packet) +{ + std::promise promise; + Nearlink::DoInDliThread([this, packet_ = packet, &promise]() { + const std::vector &safePacket = packet_; + size_t result = this->impl_->SendPacket(safePacket); + promise.set_value(result); + }); + return promise.get_future().get(); +} + +void VendorInterface::OnEventReceived(const std::vector &data) +{ + { + std::lock_guard lock(impl_->setAddrFinishedMutex_); + if (impl_->isSetAddrFinished_ == false && impl_->dli_ != nullptr) { + size_t opcodeOffset = impl_->dli_->GetPacketHeaderInfo(DLI_PACKET_TYPE_SLE_EVENT).headerSize; + uint16_t opcode = data[opcodeOffset] | (data[opcodeOffset + 1] << OFFSET_EIGHT_BITS); + if (opcode == DLI_SET_SLE_ADDR) { + HDF_LOGI("SetSleAddress received the response"); + impl_->isSetAddrFinished_ = true; + impl_->setAddrConditionVariable_.notify_all(); + } + } + } + + Nearlink::DoInDliThread([weakPtr = vendorInterfaceWeak_, data_ = data]() { + auto vendorInterface = weakPtr.lock(); + if (vendorInterface == nullptr) { + HDF_LOGE("VendorInterface::OnEventReceived: vendorInterface is nullptr"); + return; + } + vendorInterface->impl_->OnEventReceived(data_); + }); + return; +} + +void VendorInterface::OnAcbReceived(const std::vector &data) +{ + if (!impl_) { + return; + } + impl_->OnAcbReceived(data); +} + +void VendorInterface::OnIcbReceived(const std::vector &data) +{ + Nearlink::DoInDliThread([weakPtr = vendorInterfaceWeak_, icbData = data]() { + auto vendorInterface = weakPtr.lock(); + if (vendorInterface == nullptr) { + HDF_LOGE("VendorInterface::OnIcbReceived: vendorInterface is nullptr"); + return; + } + vendorInterface->impl_->OnIcbReceived(icbData); + }); + return; +} + +bool VendorInterface::Impl::WatchDliChannel(const VendorInterface::ReceiveCallback &receiveCallback) +{ + HDF_LOGI("VendorInterface %{public}s", __func__); + int channel[DLI_MAX_CHANNEL] = {0}; + int channelCount = vendorInterface_->op(SleOpcodeT::SLE_OP_DLI_CHANNEL_OPEN, static_cast(channel)); + if (channelCount < 1 || channelCount > DLI_MAX_CHANNEL) { + HDF_LOGE("VendorInterface vendorInterface_->op SLE_OP_DLI_CHANNEL_OPEN failed ret:%{public}d.", channelCount); + return false; + } + + if (channelCount == 1) { + auto h4 = std::make_shared(channel[0], + std::bind(&VendorInterface::OnAcbReceived, VendorInterface::GetInstance(), + std::placeholders::_1), + std::bind(&VendorInterface::OnIcbReceived, VendorInterface::GetInstance(), + std::placeholders::_1), + std::bind(&VendorInterface::OnEventReceived, VendorInterface::GetInstance(), + std::placeholders::_1)); + watcher_.AddFdToWatcher(channel[0], std::bind(&Dli::H4Protocol::ReadData, h4, std::placeholders::_1)); + dli_ = h4; + } else { + HDF_LOGE("VendorInterface invalid channel count:%{public}d.", channelCount); + return false; + } + return true; +} + +uint8_t *VendorInterface::Impl::TransformAddress(uint8_t *addr) +{ + HDF_LOGI("VendorInterface %{public}s", __func__); + uint8_t* data = new (std::nothrow) uint8_t[DLI_PACKET_TYPE_SIZE + DLIC_PREAMBLE_SIZE + BD_ADDR_LEN]; + if (data == nullptr) { + HDF_LOGE("failed to create data"); + return nullptr; + } + uint8_t* p = data; + *(p)++ = static_cast(DLI_PACKET_TYPE_SLE_CMD); + *(p)++ = static_cast(DLI_SET_SLE_ADDR); + *(p)++ = static_cast(DLI_SET_SLE_ADDR >> OFFSET_EIGHT_BITS); + *(p)++ = static_cast(BD_ADDR_LEN); + *(p)++ = static_cast(0x00); // length domain is 2 bytes + for (int i = 0; i < BD_ADDR_LEN; i++) { + *(p)++ = static_cast(addr[BD_ADDR_LEN - 1 - i]); + } + + return data; +} + +void VendorInterface::Impl::SetSleAddress(uint8_t *localSleAddr) +{ + HDF_LOGI("VendorInterface %{public}s", __func__); + if (dli_ == nullptr) { + HDF_LOGE("VendorInterface SetSleAddress dli_ is nullptr"); + return; + } + uint8_t *hciAddrPacket = TransformAddress(localSleAddr); + if (hciAddrPacket == nullptr) { + HDF_LOGE("VendorInterface SetSleAddress hciAddrPacket is nullptr"); + return; + } + std::vector hciData(&hciAddrPacket[0], + &hciAddrPacket[DLI_PACKET_TYPE_SIZE + DLIC_PREAMBLE_SIZE + BD_ADDR_LEN]); + internalCommand_.cb = 1; + internalCommand_.opcode = DLI_SET_SLE_ADDR; + dli_->SendPacket(hciData); + delete[] reinterpret_cast(hciAddrPacket); + HDF_LOGI("VendorInterface send mac address complete. opcode: 0x%{public}04X, cb: %{public}hu", + internalCommand_.opcode, internalCommand_.cb); +} + +void VendorInterface::Impl::GetFullVendorName(std::string &name) +{ + std::string sleChipType = OHOS::system::GetParameter(SLE_CHIP_TYPE, ""); + HDF_LOGI("slechiptype is %{public}s", sleChipType.c_str()); + if (!sleChipType.empty()) { + name.append("_"); + name.append(sleChipType.c_str()); + } + name.append(".z.so"); + HDF_LOGI("sle vendor library name is %{public}s", name.c_str()); +} + +bool VendorInterface::Impl::Initialize(VendorInterface::InitializeCompleteCallback initializeCompleteCallback, + const VendorInterface::ReceiveCallback &receiveCallback) +{ + HDF_LOGI("VendorInterface %{public}s", __func__); + dliInterfaceState_ = DLI_INTERFACE_OPENING; + initializeCompleteCallback_ = initializeCompleteCallback; + eventDataCallback_ = receiveCallback.onEventReceive; + acbDataCallback_ = receiveCallback.onAcbReceive; + icbDataCallback_ = receiveCallback.onIcbReceive; + std::string sleVendorFullName = SLE_VENDOR_NAME; + GetFullVendorName(sleVendorFullName); + vendorHandle_ = dlopen(sleVendorFullName.c_str(), RTLD_NOW); + if (vendorHandle_ == nullptr) { + HDF_LOGE("Vendor dlopen %{public}s failed, error code: %{public}s", sleVendorFullName.c_str(), dlerror()); + return false; + } + vendorInterface_ = reinterpret_cast(dlsym(vendorHandle_, SLE_VENDOR_INTERFACE_SYMBOL_NAME)); + if (vendorInterface_ == nullptr) { + HDF_LOGE("VendorInterface dlsym %{public}s failed.", SLE_VENDOR_INTERFACE_SYMBOL_NAME); + return false; + } + sleAddress_ = SleAddress::GetDeviceAddress(); + std::vector address = { 0, 0, 0, 0, 0, 0 }; + if (sleAddress_ != nullptr) { + sleAddress_->ReadAddress(address); + } + vendorInterface_->init(); + if (!WatchDliChannel(receiveCallback)) { + HDF_LOGE("VendorInterface WatchDliChannel failed."); + return false; + } + if (!watcher_.Start()) { + HDF_LOGE("VendorInterface watcher start failed."); + return false; + } + + if (sleAddress_ != nullptr) { + std::string strAddress; + sleAddress_->ParseAddressToString(address, strAddress); + HDF_LOGI("VendorInterface local addr: %{public}s", sleAddress_->GetEncryptAddr(strAddress).c_str()); + } + SetSleAddress(address.data()); + std::unique_lock lock(setAddrFinishedMutex_); + if (!setAddrConditionVariable_.wait_for(lock, std::chrono::milliseconds(SET_ADDR_TIME_OUT_MS), + [this]() -> bool { return isSetAddrFinished_; })) { + Nearlink::DoInDliThread([this]() -> void { + SetSleAddressTimeOut(); + }); + } + return true; +} + +void VendorInterface::Impl::CleanUp() +{ + HDF_LOGI("VendorInterface %{public}s", __func__); + if (vendorInterface_ == nullptr) { + HDF_LOGE("VendorInterface::CleanUp, vendorInterface_ is nullptr."); + return; + } + watcher_.Stop(); + vendorInterface_->op(SleOpcodeT::SLE_OP_DLI_CHANNEL_CLOSE, nullptr); + vendorInterface_->close(); + dli_ = nullptr; + vendorInterface_ = nullptr; + initializeCompleteCallback_ = nullptr; + eventDataCallback_ = nullptr; + acbDataCallback_ = nullptr; + icbDataCallback_ = nullptr; + if ((vendorHandle_ == nullptr) || dlclose(vendorHandle_)) { + HDF_LOGE("VendorInterface vendorHandle_ is wrong."); + } + vendorHandle_ = nullptr; + dliInterfaceState_ = DLI_INTERFACE_CLOSED; + { + std::unique_lock lock(setAddrFinishedMutex_); + isSetAddrFinished_ = false; + } +} + +size_t VendorInterface::Impl::SendPacket(const std::vector &packet) +{ + HDF_LOGI("VendorInterface %{public}s", __func__); + if (vendorInterface_ == nullptr || dli_ == nullptr) { + HDF_LOGE("VendorInterface::SendPacket, vendorInterface_ is nullptr."); + return SLE_VENDOR_INVALID_DATA_LEN; + } + + watcher_.SetTimeout(std::chrono::milliseconds(lpmTimer_), std::bind(&Impl::WatcherTimeout, this)); + + return dli_->SendPacket(packet); +} + +// No lock is required through OnEventReceived invoking. +void VendorInterface::Impl::OnInitCallback(SleOpResultT result) +{ + HDF_LOGI("VendorInterface %{public}s, ", __func__); + if (initializeCompleteCallback_) { + initializeCompleteCallback_(result == SLE_OP_RESULT_SUCCESS); + initializeCompleteCallback_ = nullptr; + } + + uint32_t lpmTimer = 0; + lpmTimer_ = lpmTimer; + watcher_.SetTimeout(std::chrono::milliseconds(lpmTimer), std::bind(&Impl::WatcherTimeout, this)); +} + +void VendorInterface::Impl::OnEventReceived(const std::vector &data) +{ + HDF_LOGI("VendorInterface %{public}s", __func__); + if (dliInterfaceState_ == DLI_INTERFACE_OPENED) { + eventDataCallback_(data); + return; + } + if (dli_ == nullptr) { + HDF_LOGE("VendorInterface OnEventReceived dli_ is nullptr"); + return; + } + + size_t opcodeOffset = dli_->GetPacketHeaderInfo(DLI_PACKET_TYPE_SLE_EVENT).headerSize; + if (data.size() <= opcodeOffset + OFFSET_STATUS) { + HDF_LOGE("Invalid data length: %{public}zu", data.size()); + return; + } + uint16_t eventOpcode = data[0] | (data[1] << OFFSET_EIGHT_BITS); + uint16_t opcode = data[opcodeOffset] | (data[opcodeOffset + 1] << OFFSET_EIGHT_BITS); + if (internalCommand_.cb != 0 && (internalCommand_.opcode == opcode)) { + internalCommand_.cb = 0; + if (data[opcodeOffset + OFFSET_STATUS] == 0) { + dliInterfaceState_ = DLI_INTERFACE_OPENED; + OnInitCallback(SLE_OP_RESULT_SUCCESS); + } else { + HDF_LOGE("VendorInterface Invalid status: %{public}d", data[opcodeOffset + OFFSET_STATUS]); + OnInitCallback(SLE_OP_RESULT_FAIL); + CleanUp(); + } + } else { + HDF_LOGI("recv unexpected eventOpcode:0x%{public}x opcode:0x%{public}x", eventOpcode, opcode); + } +} + +void VendorInterface::Impl::OnAcbReceived(const std::vector &data) +{ + if (acbDataCallback_ == nullptr) { + HDF_LOGE("acbDataCallback_ is nullptr"); + return; + } + HDF_LOGD("VendorInterface %{public}s", __func__); + acbDataCallback_(data); +} + +void VendorInterface::Impl::OnIcbReceived(const std::vector &data) +{ + if (icbDataCallback_ == nullptr) { + HDF_LOGE("icbDataCallback_ is nullptr"); + return; + } + HDF_LOGD("VendorInterface %{public}s", __func__); + icbDataCallback_(data); +} + +void VendorInterface::Impl::WatcherTimeout() +{ + HDF_LOGI("fd wait out of time, no data ready"); +} + +void VendorInterface::Impl::SetSleAddressTimeOut() +{ + HDF_LOGI("SetSleAddressTimeOut, retry SetSleAddress"); + std::vector address = { 0, 0, 0, 0, 0, 0 }; + if (sleAddress_ != nullptr) { + sleAddress_->ReadAddress(address); + } + SetSleAddress(address.data()); +} + +} // namespace V1_1 +} // namespace Dli +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS \ No newline at end of file diff --git a/nearlink/dli/dli_service/implement/vendor_interface.h b/nearlink/dli/dli_service/implement/vendor_interface.h new file mode 100644 index 0000000000..88352301c9 --- /dev/null +++ b/nearlink/dli/dli_service/implement/vendor_interface.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2026 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 OHOS_HDI_NEARLINK_DLI_V1_1_VENDOR_INTERFACE_H +#define OHOS_HDI_NEARLINK_DLI_V1_1_VENDOR_INTERFACE_H + +#include +#include +#include + +#include "singleton.h" + +#include "dli_internal.h" +#include "dli_protocol.h" +#include "dli_watcher.h" +#include "ohos_sle_vendor_lib.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace Dli { +namespace V1_1 { +class VendorInterface : public DelayedSingleton, + public std::enable_shared_from_this { +public: + using InitializeCompleteCallback = std::function; + using ReceiveDataCallback = Dli::DliProtocol::DliDataCallback; + struct ReceiveCallback { + ReceiveDataCallback onAcbReceive; + ReceiveDataCallback onIcbReceive; + ReceiveDataCallback onEventReceive; + }; + + bool Initialize(InitializeCompleteCallback initializeCompleteCallback, const ReceiveCallback &receiveCallback); + void CleanUp(); + size_t SendPacket(const std::vector &packet); + +private: + // callback function + void OnEventReceived(const std::vector &data); + void OnAcbReceived(const std::vector &data); + void OnIcbReceived(const std::vector &data); + +private: + class Impl; + std::unique_ptr impl_; + std::shared_mutex vendorMutex_; + std::weak_ptr vendorInterfaceWeak_; + + DECLARE_DELAYED_SINGLETON(VendorInterface); + DISALLOW_COPY_AND_MOVE(VendorInterface); +}; +} // namespace V1_1 +} // namespace Dli +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS +#endif /* OHOS_HDI_Nearlink_DLI_V1_1_VENDOR_INTERFACE_H */ \ No newline at end of file diff --git a/nearlink/dli/dli_service/remote_death_recipient.h b/nearlink/dli/dli_service/remote_death_recipient.h new file mode 100644 index 0000000000..541869b900 --- /dev/null +++ b/nearlink/dli/dli_service/remote_death_recipient.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2026 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 OHOS_HDI_NEARLINK_HCI_V1_1_REMOTE_DEATH_RECIPIENT_H +#define OHOS_HDI_NEARLINK_HCI_V1_1_REMOTE_DEATH_RECIPIENT_H + +#include + +#include "iremote_object.h" +#include "refbase.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace Dli { +namespace V1_1 { +class RemoteDeathRecipient : public IRemoteObject::DeathRecipient { +public: + explicit RemoteDeathRecipient(std::function &)> callback) + { + callback_ = callback; + } + ~RemoteDeathRecipient() + { + callback_ = nullptr; + } + + void OnRemoteDied(const wptr &object) + { + if (callback_ != nullptr) { + callback_(object); + } + } + +private: + std::function &)> callback_; +}; +} // namespace V1_1 +} // namespace Dli +} // namespace Nearlink +} // namespace HDI +} // OHOS + +#endif // OHOS_HDI_NEARLINK_HCI_V1_1_REMOTE_DEATH_RECIPIENT_H diff --git a/nearlink/dli/dli_service/sle_dli_interface_driver.cpp b/nearlink/dli/dli_service/sle_dli_interface_driver.cpp new file mode 100644 index 0000000000..af595b3e8f --- /dev/null +++ b/nearlink/dli/dli_service/sle_dli_interface_driver.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2026 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 +#include +#include +#include +#include "v1_1/sle_hci_interface_stub.h" + +#define HDF_LOG_TAG sle_dli_interface_driver + +using namespace OHOS::HDI::Nearlink::Hci::V1_1; + +struct HdfSleDliInterfaceHost { + struct IDeviceIoService ioService; + OHOS::sptr stub; + HdfSleDliInterfaceHost() + { + ioService.object.objectId = 0; + ioService.Open = nullptr; + ioService.Release = nullptr; + ioService.Dispatch = nullptr; + } +}; + +static int32_t SleDliInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, + struct HdfSBuf *reply) +{ + auto *hdfSleDliInterfaceHost = CONTAINER_OF(client->device->service, struct HdfSleDliInterfaceHost, ioService); + + OHOS::MessageParcel *dataParcel = nullptr; + OHOS::MessageParcel *replyParcel = nullptr; + OHOS::MessageOption option; + + if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) { + HDF_LOGE("%{public}s: invalid data sbuf object to dispatch", __func__); + return HDF_ERR_INVALID_PARAM; + } + if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) { + HDF_LOGE("%{public}s: invalid reply sbuf object to dispatch", __func__); + return HDF_ERR_INVALID_PARAM; + } + + return hdfSleDliInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option); +} + +static int HdfSleDliInterfaceDriverInit(struct HdfDeviceObject *deviceObject) +{ + HDF_LOGI("%{public}s: driver init start", __func__); + return HDF_SUCCESS; +} + +static int HdfSleDliInterfaceDriverBind(struct HdfDeviceObject *deviceObject) +{ + HDF_LOGI("%{public}s: driver bind start", __func__); + auto *hdfSleDliInterfaceHost = new (std::nothrow) HdfSleDliInterfaceHost; + if (hdfSleDliInterfaceHost == nullptr) { + HDF_LOGE("%{public}s: failed to create create HdfSleDliInterfaceHost object", __func__); + return HDF_FAILURE; + } + + hdfSleDliInterfaceHost->ioService.Dispatch = SleDliInterfaceDriverDispatch; + hdfSleDliInterfaceHost->ioService.Open = NULL; + hdfSleDliInterfaceHost->ioService.Release = NULL; + + auto serviceImpl = OHOS::HDI::Nearlink::Hci::V1_1::ISleHciInterface::Get(true); + if (serviceImpl == nullptr) { + HDF_LOGE("%{public}s: failed to get of implement service", __func__); + delete hdfSleDliInterfaceHost; + return HDF_FAILURE; + } + + hdfSleDliInterfaceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl, + OHOS::HDI::Nearlink::Hci::V1_1::ISleHciInterface::GetDescriptor()); + if (hdfSleDliInterfaceHost->stub == nullptr) { + HDF_LOGE("%{public}s: failed to get stub object", __func__); + delete hdfSleDliInterfaceHost; + return HDF_FAILURE; + } + + deviceObject->service = &hdfSleDliInterfaceHost->ioService; + return HDF_SUCCESS; +} + +static void HdfSleDliInterfaceDriverRelease(struct HdfDeviceObject *deviceObject) +{ + HDF_LOGI("%{public}s: driver release start", __func__); + if (deviceObject->service == nullptr) { + HDF_LOGE("HdfSleDliInterfaceDriverRelease not initted"); + return; + } + + auto *hdfSleDliInterfaceHost = CONTAINER_OF(deviceObject->service, struct HdfSleDliInterfaceHost, ioService); + if (hdfSleDliInterfaceHost != nullptr) { + delete hdfSleDliInterfaceHost; + } +} + +struct HdfDriverEntry g_sledliinterfaceDriverEntry = { + .moduleVersion = 1, + .moduleName = "nearlink_dli", + .Bind = HdfSleDliInterfaceDriverBind, + .Init = HdfSleDliInterfaceDriverInit, + .Release = HdfSleDliInterfaceDriverRelease, +}; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +HDF_INIT(g_sledliinterfaceDriverEntry); +#ifdef __cplusplus +} +#endif /* __cplusplus */ diff --git a/nearlink/dli/dli_service/sle_hci_interface_impl.cpp b/nearlink/dli/dli_service/sle_hci_interface_impl.cpp new file mode 100644 index 0000000000..a8034f1d2b --- /dev/null +++ b/nearlink/dli/dli_service/sle_hci_interface_impl.cpp @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2026 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 "sle_hci_interface_impl.h" +#include +#include +#include "nearlink_hdf_log.h" +#include +#include "vendor_interface.h" +#include "sle_hal_constant.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace Hci { +namespace V1_1 { + using VendorInterface = OHOS::HDI::Nearlink::Dli::V1_1::VendorInterface; + using DliPacketType = OHOS::HDI::Nearlink::Dli::DliPacketType; + thread_local bool SleHciInterfaceImpl::isThreadPromoted = false; + using namespace OHOS::HDI::Nearlink::Dli; + + +extern "C" ISleHciInterface *SleHciInterfaceImplGetInstance(void) +{ + return new (std::nothrow) SleHciInterfaceImpl(); +} + +SleHciInterfaceImpl::SleHciInterfaceImpl() +{ + remoteDeathRecipient_ = + new RemoteDeathRecipient(std::bind(&SleHciInterfaceImpl::OnRemoteDied, this, std::placeholders::_1)); +} + +SleHciInterfaceImpl::~SleHciInterfaceImpl() +{ + std::lock_guard lock(dliCallbackMutex_); + if (callbacks_ != nullptr) { + RemoveDliDeathRecipient(callbacks_); + callbacks_ = nullptr; + } +} + +int32_t SleHciInterfaceImpl::SleHalInit(const sptr& callbackObj) +{ + HDF_LOGI("SleHciInterfaceImpl %{public}s", __func__); + if (callbackObj == nullptr) { + HDF_LOGE("SleHciInterfaceImpl %{public}s callbackObj null", __func__); + return HDF_FAILURE; + } + + VendorInterface::ReceiveCallback callback = { + .onAcbReceive = + [callbackObj]( + const std::vector &packet) { callbackObj->hciPacketReceived(SleType::ACB_DATA, packet); }, + .onIcbReceive = + [callbackObj]( + const std::vector &packet) { callbackObj->hciPacketReceived(SleType::ICB_DATA, packet); }, + .onEventReceive = + [callbackObj]( + const std::vector &packet) { callbackObj->hciPacketReceived(SleType::HCI_EVENT, packet); }, + }; + + bool result = VendorInterface::GetInstance()->Initialize( + [callbackObj](bool status) { + callbackObj->initializationComplete(status ? SleStatus::SUCCESS : SleStatus::INITIALIZATION_ERROR); + }, callback); + if (result) { + std::lock_guard lock(dliCallbackMutex_); + callbacks_ = callbackObj; + AddDliDeathRecipient(callbacks_); + } + return result ? HDF_SUCCESS : HDF_FAILURE; +} + +int32_t SleHciInterfaceImpl::SleSendHciPacket(const std::vector& data) +{ + HDF_LOGD("SleHciInterfaceImpl %{public}s", __func__); + if (data.empty()) { + return HDF_FAILURE; + } + SetRTSchedule(); + + size_t result = VendorInterface::GetInstance()->SendPacket(data); + return result ? HDF_SUCCESS : HDF_FAILURE; +} + +int32_t SleHciInterfaceImpl::CheckOnBoardState(bool& result) +{ + HDF_LOGI("SleHciInterfaceImpl %{public}s", __func__); + result = true; + return HDF_SUCCESS; +} + +int32_t SleHciInterfaceImpl::Close() +{ + HDF_LOGI("SleHciInterfaceImpl %{public}s", __func__); + { + std::lock_guard lock(dliCallbackMutex_); + if (callbacks_ != nullptr) { + RemoveDliDeathRecipient(callbacks_); + callbacks_ = nullptr; + } + } + VendorInterface::GetInstance()->CleanUp(); + VendorInterface::DestroyInstance(); + return HDF_SUCCESS; +} + +void SleHciInterfaceImpl::OnRemoteDied(const wptr &object) +{ + HDF_LOGI("SleHciInterfaceImpl %{public}s", __func__); + { + std::lock_guard lock(dliCallbackMutex_); + callbacks_ = nullptr; + } + VendorInterface::GetInstance()->CleanUp(); + VendorInterface::DestroyInstance(); +} + +int32_t SleHciInterfaceImpl::AddDliDeathRecipient(const sptr& callbackObj) +{ + HDF_LOGI("SleHciInterfaceImpl %{public}s", __func__); + const sptr& remote = OHOS::HDI::hdi_objcast(callbackObj); + if (!remote) { + HDF_LOGE("remote is nullptr"); + return HDF_FAILURE; + } + bool result = remote->AddDeathRecipient(remoteDeathRecipient_); + if (!result) { + HDF_LOGE("SleHciInterfaceImpl AddDeathRecipient fail"); + return HDF_FAILURE; + } + return HDF_SUCCESS; +} + +int32_t SleHciInterfaceImpl::RemoveDliDeathRecipient(const sptr& callbackObj) +{ + HDF_LOGI("SleHciInterfaceImpl %{public}s", __func__); + const sptr& remote = OHOS::HDI::hdi_objcast(callbackObj); + if (!remote) { + HDF_LOGE("remote is nullptr"); + return HDF_FAILURE; + } + bool result = remote->RemoveDeathRecipient(remoteDeathRecipient_); + if (!result) { + HDF_LOGE("SleHciInterfaceImpl RemoveDeathRecipient fail"); + return HDF_FAILURE; + } + return HDF_SUCCESS; +} + +void SleHciInterfaceImpl::SetRTSchedule() +{ + if (isThreadPromoted) { + return; + } + pid_t tid = gettid(); + struct sched_param rtParams = {.sched_priority = SLE_THREAD_PRIORITY}; + int rc = sched_setscheduler(tid, SCHED_FIFO, &rtParams); + isThreadPromoted = (rc != 0) ? false : true; +} +} // V1_1 +} // Hci +} // Nearlink +} // HDI +} // OHOS \ No newline at end of file diff --git a/nearlink/dli/dli_service/sle_hci_interface_impl.h b/nearlink/dli/dli_service/sle_hci_interface_impl.h new file mode 100644 index 0000000000..43f28cdaf1 --- /dev/null +++ b/nearlink/dli/dli_service/sle_hci_interface_impl.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2026 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 OHOS_HDI_NEARLINK_DLI_V1_1_SLEDLIINTERFACEIMPL_H +#define OHOS_HDI_NEARLINK_DLI_V1_1_SLEDLIINTERFACEIMPL_H + +#include "v1_1/isle_hci_interface.h" +#include "v1_0/isle_hci_callback.h" +#include "remote_death_recipient.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace Hci { +namespace V1_1 { + using namespace OHOS::HDI::Nearlink::Dli::V1_1; +class SleHciInterfaceImpl : public OHOS::HDI::Nearlink::Hci::V1_1::ISleHciInterface { +public: + SleHciInterfaceImpl(); + virtual ~SleHciInterfaceImpl(); + + int32_t SleHalInit(const sptr& callbackObj) override; + + int32_t SleSendHciPacket(const std::vector& data) override; + + int32_t Close() override; + + int32_t CheckOnBoardState(bool& result) override; +private: + void OnRemoteDied(const wptr &object); + sptr callbacks_ = nullptr; + sptr remoteDeathRecipient_ = nullptr; + int32_t AddDliDeathRecipient(const sptr& callbackObj); + int32_t RemoveDliDeathRecipient(const sptr& callbackObj); + void SetRTSchedule(); + std::mutex dliCallbackMutex_; + thread_local static bool isThreadPromoted; +}; +} // V1_1 +} // Hci +} // Nearlink +} // HDI +} // OHOS + +#endif // OHOS_HDI_NEARLINK_DLI_V1_1_SleHciInterfaceImplE_H \ No newline at end of file diff --git a/nearlink/dli/test/BUILD.gn b/nearlink/dli/test/BUILD.gn new file mode 100644 index 0000000000..d4b28521f9 --- /dev/null +++ b/nearlink/dli/test/BUILD.gn @@ -0,0 +1,44 @@ +# Copyright (C) 2026 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/test.gni") + +group("nearlink_hdi_test") { + testonly = true + deps = [ + ":NearlinkHdiTest", + ] +} + +ohos_unittest("NearlinkHdiTest") { + module_out_path = "drivers_peripheral_nearlink/drivers_peripheral_nearlink/" + + sources = [ + "nearlink_hdi_test.cpp", + ] + + include_dirs = [ + "../dli_service", + ] + + external_deps = [ + "c_utils:utils", + "hdf_core:libhdf_host", + "hdf_core:libhdf_utils", + "hilog:libhilog", + "ipc:ipc_single", + "drivers_interface_nearlink:libnearlink_hci_proxy_1.0", + "drivers_interface_nearlink:libnearlink_hci_proxy_1.1", + ] +} \ No newline at end of file diff --git a/nearlink/dli/test/nearlink_hdi_test.cpp b/nearlink/dli/test/nearlink_hdi_test.cpp new file mode 100644 index 0000000000..655aca79c4 --- /dev/null +++ b/nearlink/dli/test/nearlink_hdi_test.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2026 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 +#include +#include +#include "v1_1/isle_hci_interface.h" +#include "v1_0/isle_hci_callback.h" + +using namespace testing::ext; + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace Hci { +namespace V1_1 { + +sptr nearlinkDliInterface = nullptr; + +class NearlinkDliHdiTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + + +class NearlinkDliCallbacksForTest : public ISleHciCallback { +public: + NearlinkDliCallbacksForTest() + {} + ~NearlinkDliCallbacksForTest() + {} + + int32_t initializationComplete(SleStatus status) + { + GTEST_LOG_(INFO) << "NeearlinkDliCallbacksForTest::initializationComplete called"; + return 0; + } + + int32_t hciPacketReceived(uint32_t type, const std::vector &data) + { + GTEST_LOG_(INFO) << "NeearlinkDliCallbacksForTest::hciPacketReceived called"; + return 0; + } +}; + +void NearlinkDliHdiTest::SetUpTestCase(void) +{ + // input testsuit setup step,setup invoked before all testcases + nearlinkDliInterface = OHOS::HDI::Nearlink::Hci::V1_1::ISleHciInterface::Get(true); + if (nearlinkDliInterface == nullptr) { + HDF_LOGE("nearlinkDliHdiTest nearlinkDliInterface is nullptr\n"); + } +} + +void NearlinkDliHdiTest::TearDownTestCase(void) +{ + // input testsuit teardown step,teardown invoked after all testcases +} + +void NearlinkDliHdiTest::SetUp(void) +{ + // input testcase setup step,setup invoked before each testcases +} + +void NearlinkDliHdiTest::TearDown(void) +{ + // input testcase teardown step,teardown invoked after each testcases +} + +/** + * @tc.name: HDI_nearlinkDliInterface_001_SleHalInitTest + * @tc.desc: Test nearlinkDliInterface SleHalInit. + * @tc.type: FUNC + */ +HWTEST_F(NearlinkDliHdiTest, HDI_nearlinkDliInterface_001_SleHalInitTest, TestSize.Level1) +{ + sptr callback_ = new NearlinkDliCallbacksForTest(); + int ret = nearlinkDliInterface->SleHalInit(callback_); + EXPECT_EQ(-1, ret); +} + +/** + * @tc.name: HDI_nearlinkDliInterface_002_SleSendHciPacketTest + * @tc.desc: Test nearlinkDliInterface SleSendHciPacket. + * @tc.type: FUNC + */ +HWTEST_F(NearlinkDliHdiTest, HDI_nearlinkDliInterface_002_SleSendHciPacketTest, TestSize.Level1) +{ + sptr callback_ = new NearlinkDliCallbacksForTest(); + int ret = nearlinkDliInterface->SleHalInit(callback_); + EXPECT_EQ(-1, ret); + std::vector sleHciTestData = {0xA1, 0x07, 0x10, 0x02, 0x00, 0x00, 0x00}; + ret = nearlinkDliInterface->SleSendHciPacket(sleHciTestData); + EXPECT_EQ(-1, ret); +} + +/** + * @tc.name: HDI_nearlinkDliInterface_003_SleCloseTest + * @tc.desc: Test nearlinkDliInterface SleClose. + * @tc.type: FUNC + */ +HWTEST_F(NearlinkDliHdiTest, HDI_nearlinkDliInterface_003_SleCloseTest, TestSize.Level1) +{ + sptr callback_ = new NearlinkDliCallbacksForTest(); + int ret = nearlinkDliInterface->SleHalInit(callback_); + EXPECT_EQ(-1, ret); + ret = nearlinkDliInterface->Close(); + EXPECT_EQ(0, ret); +} + +} // V1_1 +} // Hci +} // Nearlink +} // HDI +} // OHOS diff --git a/nearlink/drivers_peripheral_nearlink.gni b/nearlink/drivers_peripheral_nearlink.gni new file mode 100644 index 0000000000..98bd231b18 --- /dev/null +++ b/nearlink/drivers_peripheral_nearlink.gni @@ -0,0 +1,17 @@ +# Copyright (C) 2026 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. + +declare_args() { + drivers_peripheral_nearlink_feature_support_send_disable_hci = false + drivers_peripheral_nearlink_reload_address = false +} \ No newline at end of file diff --git a/nearlink/off_find/BUILD.gn b/nearlink/off_find/BUILD.gn new file mode 100644 index 0000000000..631aca8f0c --- /dev/null +++ b/nearlink/off_find/BUILD.gn @@ -0,0 +1,26 @@ +# Copyright (C) 2026 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") + +if (defined(ohos_lite)) { + group("off_find_entry") { + deps = [] + } +} else { + group("off_find_entry") { + deps = [ + "hdi_service:hdf_off_find_service", + ] + } +} \ No newline at end of file diff --git a/nearlink/off_find/hdi_service/BUILD.gn b/nearlink/off_find/hdi_service/BUILD.gn new file mode 100644 index 0000000000..b95a5d581b --- /dev/null +++ b/nearlink/off_find/hdi_service/BUILD.gn @@ -0,0 +1,158 @@ +# Copyright (C) 2026 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/config/components/hdi/hdi.gni") +import("//out/products_ext/hmos_ext_var.gni") +import("../../drivers_peripheral_nearlink.gni") + +ohos_shared_library("liboff_find_interface_service_1.0") { + 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 + } + branch_protector_ret = "pac_ret" + + cflags = [ + "-Os", + "-fdata-sections", + "-ffunction-sections", + "-fno-unwind-tables", + "-fno-asynchronous-unwind-tables", + "-fno-exceptions", + "-fno-rtti", + "-fPIC", + "-fno-common", + "-fstack-protector-strong", + "-fvisibility-inlines-hidden", + "-flto", + ] + cflags_cc = cflags + ldflags = [ + "-Wl,--as-needed", + "-Wl,--gc-sections", + "-Wl,--no-whole-archive", + ] + + include_dirs = [ + ".", + "implement", + ] + + sources = [ + "off_find_interface_impl.cpp", + "implement/h4_protocol.cpp", + "implement/dli_protocol.cpp", + "implement/dli_watcher.cpp", + "implement/vendor_interface.cpp", + "implement/thread_util.cpp", + ] + + defines = [] + + if (drivers_peripheral_nearlink_feature_support_send_disable_hci) { + defines += [ "SEND_DISABLE_OFF_FIND_DLI" ] + } + + if (is_standard_system) { + external_deps = [ + "c_utils:utils", + "drivers_interface_nearlink:off_find_idl_headers", + "hdf_core:libhdf_host", + "hdf_core:libhdf_utils", + "hilog:libhilog", + "ipc:ipc_core", + "ffrt:libffrt", + "init:libbegetutil" + ] + } else { + external_deps = [ + "hilog:libhilog", + "ipc:ipc_core", + ] + } + + install_images = [ chipset_base_dir ] + subsystem_name = "hdf" + part_name = "drivers_peripheral_nearlink" +} + +ohos_shared_library("liboff_find_hdi_driver") { + 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 + } + branch_protector_ret = "pac_ret" + + cflags = [ + "-Os", + "-fdata-sections", + "-ffunction-sections", + "-fno-unwind-tables", + "-fno-asynchronous-unwind-tables", + "-fno-exceptions", + "-fno-rtti", + "-fPIC", + "-fno-common", + "-fstack-protector-strong", + "-fvisibility-inlines-hidden", + "-flto", + ] + cflags_cc = cflags + ldflags = [ + "-Wl,--as-needed", + "-Wl,--gc-sections", + "-Wl,--no-whole-archive", + ] + + include_dirs = [ "." ] + + sources = [ "off_find_interface_driver.cpp" ] + + if (is_standard_system) { + external_deps = [ + "c_utils:utils", + "hdf_core:libhdf_host", + "hdf_core:libhdf_ipc_adapter", + "hdf_core:libhdf_utils", + "hdf_core:libhdi", + "hilog:libhilog", + "ipc:ipc_single", + ] + } else { + external_deps = [ + "hilog:libhilog", + "ipc:ipc_single", + ] + } + + external_deps += [ "drivers_interface_nearlink:liboff_find_stub_1.0" ] + + shlib_type = "hdi" + install_images = [ chipset_base_dir ] + subsystem_name = "hdf" + part_name = "drivers_peripheral_nearlink" +} + +group("hdf_off_find_service") { + deps = [ + ":liboff_find_hdi_driver", + ":liboff_find_interface_service_1.0", + ] +} diff --git a/nearlink/off_find/hdi_service/implement/dli_internal.h b/nearlink/off_find/hdi_service/implement/dli_internal.h new file mode 100644 index 0000000000..2101b4ae21 --- /dev/null +++ b/nearlink/off_find/hdi_service/implement/dli_internal.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2026 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 OHOS_HDI_NEARLINK_DLI_INTERNAL_H +#define OHOS_HDI_NEARLINK_DLI_INTERNAL_H + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace OffFind { +typedef enum { + DLI_PACKET_TYPE_UNKNOWN = 0, + DLI_PACKET_TYPE_SLE_CMD = 0xA1, + DLI_PACKET_TYPE_SLE_EVENT = 0xA2, + DLI_PACKET_TYPE_MAX, +} DliPacketType; + +struct PacketHeader { + uint8_t headerSize; + uint8_t dataLengthOffset; + uint8_t dataLengthSize; +}; + +// opcode (DLI_SLE_Cmd_Complete_Evt opcode) +const uint16_t SLE_DLI_COMMAND_COMPLETE_EVENT = 0x0002; + +} // namespace OffFind +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS +#endif /* OHOS_HDI_NEARLINK_DLI_INTERNAL_H */ \ No newline at end of file diff --git a/nearlink/off_find/hdi_service/implement/dli_protocol.cpp b/nearlink/off_find/hdi_service/implement/dli_protocol.cpp new file mode 100644 index 0000000000..3fc8e52417 --- /dev/null +++ b/nearlink/off_find/hdi_service/implement/dli_protocol.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2026 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 +#include +#include +#include "off_find_log.h" +#include "dli_protocol.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace OffFind { +const PacketHeader DliProtocol::header_[DLI_PACKET_TYPE_MAX] = { + {.headerSize = 0, .dataLengthOffset = 0, .dataLengthSize = 0}, /* 0 */ + {.headerSize = 4, .dataLengthOffset = 2, .dataLengthSize = 2}, /* 1 */ + {.headerSize = 4, .dataLengthOffset = 2, .dataLengthSize = 2}, /* 4 */ +}; + +const PacketHeader &DliProtocol::GetPacketHeaderInfo(DliPacketType packetType) +{ + if (packetType >= DLI_PACKET_TYPE_MAX) { + return header_[DLI_PACKET_TYPE_UNKNOWN]; + } + return header_[DliProtocol::TypeConvert(packetType)]; +} + +ssize_t DliProtocol::Read(int fd, uint8_t *data, size_t length) +{ + const int bufsize = 256; + char buf[bufsize] = {0}; + ssize_t ret = TEMP_FAILURE_RETRY(read(fd, data, length)); + if (ret == -1) { + strerror_r(errno, buf, sizeof(buf)); + HDF_LOGE("read failed err:%s", buf); + ret = 0; + } + return ret; +} + +ssize_t DliProtocol::Write(int fd, const uint8_t *data, size_t length) +{ + const int bufsize = 256; + char buf[bufsize] = {0}; + ssize_t ret = 0; + do { + ret = TEMP_FAILURE_RETRY(write(fd, data, length)); + } while (ret == -1 && errno == EAGAIN); + + if (ret == -1) { + strerror_r(errno, buf, sizeof(buf)); + HDF_LOGE("write failed err:%s", buf); + } else if (static_cast(ret) != length) { + HDF_LOGE("write data %zd less than %zu.", ret, length); + } + return ret; +} + +uint8_t DliProtocol::TypeConvert(DliPacketType packetType) +{ + switch (packetType) { + case DLI_PACKET_TYPE_SLE_EVENT: + return static_cast(DLI_PACKET_TYPE_SLE_EVENT) & 0x0F; + default: + HDF_LOGE("type convert error."); + return 0; + } +} +} // namespace OffFind +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS \ No newline at end of file diff --git a/nearlink/off_find/hdi_service/implement/dli_protocol.h b/nearlink/off_find/hdi_service/implement/dli_protocol.h new file mode 100644 index 0000000000..0ad4b28c35 --- /dev/null +++ b/nearlink/off_find/hdi_service/implement/dli_protocol.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2026 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 OHOS_HDI_NEARLINK_DLI_PROTOCOL_H +#define OHOS_HDI_NEARLINK_DLI_PROTOCOL_H + +#include +#include + +#include +#include "dli_internal.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace OffFind { +class DliProtocol { +public: + using DliDataCallback = std::function &data)>; + + DliProtocol() = default; + virtual ~DliProtocol() = default; + + virtual ssize_t SendPacket(const std::vector &packetData) = 0; + + const PacketHeader& GetPacketHeaderInfo(DliPacketType packetType); + +protected: + static ssize_t Read(int fd, uint8_t *data, size_t length); + static ssize_t Write(int fd, const uint8_t *data, size_t length); + static uint8_t TypeConvert(DliPacketType packetType); + static const PacketHeader header_[DLI_PACKET_TYPE_MAX]; +}; +} // namespace OffFind +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS +#endif /* OHOS_HDI_NEARLINK_DLI_PROTOCOL_H */ \ No newline at end of file diff --git a/nearlink/off_find/hdi_service/implement/dli_watcher.cpp b/nearlink/off_find/hdi_service/implement/dli_watcher.cpp new file mode 100644 index 0000000000..de7f90a1ce --- /dev/null +++ b/nearlink/off_find/hdi_service/implement/dli_watcher.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2026 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 +#include +#include +#include +#include "off_find_log.h" +#include "off_find_hdi_constant.h" +#include "dli_watcher.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace OffFind { +DliWatcher::DliWatcher() +{} + +DliWatcher::~DliWatcher() +{ + Stop(); +} + +bool DliWatcher::AddFdToWatcher(int fd, DliDataCallback callback) +{ + std::lock_guard lock(fdsMutex_); + fds_[fd] = callback; + ThreadWakeup(); + return true; +} + +bool DliWatcher::RemoveFdToWatcher(int fd) +{ + std::lock_guard lock(fdsMutex_); + fds_.erase(fd); + ThreadWakeup(); + return true; +} + +bool DliWatcher::SetTimeout(std::chrono::milliseconds timeout, TimeoutCallback callback) +{ + std::chrono::seconds seconds = std::chrono::duration_cast(timeout); + std::lock_guard lock(timeoutMutex_); + timeoutTimer_.tv_sec = seconds.count(); + timeoutTimer_.tv_usec = (timeout - seconds).count(); + timeoutCallback_ = callback; + ThreadWakeup(); + return true; +} + +bool DliWatcher::Start() +{ + if (running_.exchange(true)) { + return true; + } + + { + std::lock_guard lock(wakeupPipeMutex_); + if (pipe(wakeupPipe_) != 0) { + HDF_LOGE("DliWatcher create pipe failed."); + running_.exchange(false); + return false; + } + } + + thread_ = std::thread(std::bind(&DliWatcher::WatcherThread, this)); + if (!thread_.joinable()) { + HDF_LOGE("thread is not joinable."); + running_.exchange(false); + return false; + } + + int policy = SLE_THREAD_POLICY; + sched_param params = {.sched_priority = SLE_THREAD_PRIORITY}; + if (pthread_setschedparam(thread_.native_handle(), policy, ¶ms) != 0) { + HDF_LOGW("pthread_setschedparam failed tid[%lu] policy[%d]", thread_.native_handle(), policy); + } + + return true; +} + +bool DliWatcher::Stop() +{ + if (!running_.exchange(false)) { + return true; + } + + ThreadWakeup(); + thread_.join(); + + { + std::lock_guard lock(wakeupPipeMutex_); + close(wakeupPipe_[0]); + close(wakeupPipe_[1]); + } + + return true; +} + +void DliWatcher::CheckFdReady(std::map& fds, fd_set &readFds) +{ + std::lock_guard lock(fdsMutex_); + for (auto &&fd : fds_) { + if (FD_ISSET(fd.first, &readFds)) { + fd.second(fd.first); + } + } +} + +void DliWatcher::WatcherThread() +{ + fd_set readFds; + int nfds; + timeval *timeout = nullptr; + + while (running_) { + FD_ZERO(&readFds); + { + std::lock_guard lock(wakeupPipeMutex_); + FD_SET(wakeupPipe_[0], &readFds); + nfds = wakeupPipe_[0]; + } + { + std::lock_guard lock(fdsMutex_); + for (auto &&fd : fds_) { + FD_SET(fd.first, &readFds); + nfds = std::max(fd.first, nfds); + } + } + + { + std::lock_guard lock(timeoutMutex_); + if (timeoutTimer_.tv_sec == 0 && timeoutTimer_.tv_usec == 0) { + timeout = nullptr; + } else { + timeout = &timeoutTimer_; + } + } + + int ret = select(nfds + 1, &readFds, nullptr, nullptr, timeout); + if (ret < 0) { + continue; + } else if (ret == 0) { + TimeoutCallback callback; + { + std::lock_guard lock(timeoutMutex_); + callback = timeoutCallback_; + } + if (callback) { + callback(); + } + } else { + { + std::lock_guard lock(wakeupPipeMutex_); + if (FD_ISSET(wakeupPipe_[0], &readFds)) { + uint8_t buff = 0; + TEMP_FAILURE_RETRY(read(wakeupPipe_[0], &buff, sizeof(buff))); + } + } + CheckFdReady(fds_, readFds); + } + } +} + +void DliWatcher::ThreadWakeup() +{ + std::lock_guard lock(wakeupPipeMutex_); + uint8_t buff = 0; + TEMP_FAILURE_RETRY(write(wakeupPipe_[1], &buff, sizeof(buff))); +} +} // namespace Dli +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS \ No newline at end of file diff --git a/nearlink/off_find/hdi_service/implement/dli_watcher.h b/nearlink/off_find/hdi_service/implement/dli_watcher.h new file mode 100644 index 0000000000..1cf40edc13 --- /dev/null +++ b/nearlink/off_find/hdi_service/implement/dli_watcher.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2026 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 OHOS_HDI_NEARLINK_HCI_WATCHER_H +#define OHOS_HDI_NEARLINK_HCI_WATCHER_H + +#include +#include +#include +#include +#include +#include +#include + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace OffFind { +class DliWatcher { +public: + using DliDataCallback = std::function; + using TimeoutCallback = std::function; + + DliWatcher(); + ~DliWatcher(); + + bool AddFdToWatcher(int fd, DliDataCallback callback); + bool RemoveFdToWatcher(int fd); + bool SetTimeout(std::chrono::milliseconds timeout, TimeoutCallback callback); + bool Start(); + bool Stop(); + +private: + void CheckFdReady(std::map& fds, fd_set &readFds); + void WatcherThread(); + void ThreadWakeup(); + +private: + std::atomic_bool running_ = {false}; + std::map fds_; + std::mutex fdsMutex_; + std::mutex wakeupPipeMutex_; + int wakeupPipe_[2] = {0}; + timeval timeoutTimer_ = {}; + TimeoutCallback timeoutCallback_; + std::mutex timeoutMutex_; + std::thread thread_; +}; +} // namespace OffFind +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS +#endif /* OHOS_HDI_NEARLINK_HCI_WATCHER_H */ \ No newline at end of file diff --git a/nearlink/off_find/hdi_service/implement/h4_protocol.cpp b/nearlink/off_find/hdi_service/implement/h4_protocol.cpp new file mode 100644 index 0000000000..e860dff67c --- /dev/null +++ b/nearlink/off_find/hdi_service/implement/h4_protocol.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2026 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 +#include +#include "off_find_log.h" +#include "h4_protocol.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace OffFind { +H4Protocol::H4Protocol( + int fd, DliDataCallback onEventReceive) + : dliFd_(fd), onEventReceive_(onEventReceive) +{} + +ssize_t H4Protocol::SendPacket(const std::vector &packetData) +{ + ssize_t writtenNumber = 0; + ssize_t ret = 0; + do { + ret = Write(dliFd_, packetData.data() + writtenNumber, packetData.size() - writtenNumber); + if (ret > 0) { + writtenNumber += ret; + } else if (ret < 0) { + return ret; + } + } while (static_cast(writtenNumber) < packetData.size()); + return writtenNumber; +} + +static bool ReadLengthCheck(ssize_t readLen, char *buf, int fd) +{ + const int bufsize = 256; + if (readLen < 0) { + strerror_r(errno, buf, bufsize); + HDF_LOGE("read fd[%d] err:%s", fd, buf); + return false; + } else if (readLen == 0) { + HDF_LOGE("read fd[%d] readLen = 0.", fd); + return false; + } + return true; +} + +void H4Protocol::ReadData(int fd) +{ + const int bufsize = 256; + char buf[bufsize] = {0}; + static uint8_t typeNo{0}; + ssize_t readLen = 0; + if (dliPacket_.size() == 0) { + readLen = Read(fd, &packetType_, sizeof(packetType_)); + if (readLen < 0) { + HDF_LOGE("read fd[%d]", fd); + return; + } else if (readLen == 0) { + HDF_LOGE("read fd[%d] readLen = 0.", fd); + return; + } + typeNo = (packetType_) & 0x0F; + if (packetType_ > DLI_PACKET_TYPE_UNKNOWN && packetType_ < DLI_PACKET_TYPE_MAX) { + dliPacket_.resize(header_[typeNo].headerSize); + } + } else if (dliPacket_.size() == header_[typeNo].headerSize) { + readLen = Read(fd, dliPacket_.data() + readLength_, dliPacket_.size() - readLength_); + if (!ReadLengthCheck(readLen, buf, fd)) { + return; + } + readLength_ += readLen; + if (readLength_ == dliPacket_.size()) { + size_t dataLen = 0; + for (int ii = 0; ii < header_[typeNo].dataLengthSize; ii++) { + dataLen += (dliPacket_[header_[typeNo].dataLengthOffset + ii] << (ii * 0x08)); + } + dliPacket_.resize(dliPacket_.size() + dataLen); + } + } else { + readLen = Read(fd, dliPacket_.data() + readLength_, dliPacket_.size() - readLength_); + if (!ReadLengthCheck(readLen, buf, fd)) { + return; + } + readLength_ += readLen; + if (readLength_ == dliPacket_.size()) { + PacketCallback(); + dliPacket_.clear(); + readLength_ = 0; + typeNo = 0; + } + } +} + +H4Protocol::~H4Protocol() {} + +void H4Protocol::PacketCallback() +{ + switch (packetType_) { + case DLI_PACKET_TYPE_SLE_EVENT: + if (onEventReceive_) { + onEventReceive_(dliPacket_); + } + break; + default: + HDF_LOGE("PacketCallback type[%d] error.", packetType_); + break; + } +} +} // namespace OffFind +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS \ No newline at end of file diff --git a/nearlink/off_find/hdi_service/implement/h4_protocol.h b/nearlink/off_find/hdi_service/implement/h4_protocol.h new file mode 100644 index 0000000000..177d9b2a6e --- /dev/null +++ b/nearlink/off_find/hdi_service/implement/h4_protocol.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2026 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 OHOS_HDI_NEARLINK_HCI_H4_PROTOCOL_H +#define OHOS_HDI_NEARLINK_HCI_H4_PROTOCOL_H + +#include "dli_protocol.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace OffFind { +class H4Protocol : public DliProtocol { +public: + H4Protocol(int fd, DliDataCallback onEventReceive); + + ssize_t SendPacket(const std::vector &packetData) override; + void ReadData(int fd); + ~H4Protocol() override; + +private: + void PacketCallback(); + +private: + int dliFd_ = 0; + DliDataCallback onEventReceive_; + + uint8_t packetType_ = 0; + + std::vector dliPacket_; + uint32_t readLength_ = 0; +}; +} // namespace OffFind +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS + +#endif /* OHOS_HDI_NEARLINK_HCI_H4_PROTOCOL_H */ \ No newline at end of file diff --git a/nearlink/off_find/hdi_service/implement/off_find_hdi_constant.h b/nearlink/off_find/hdi_service/implement/off_find_hdi_constant.h new file mode 100644 index 0000000000..c9aae8a184 --- /dev/null +++ b/nearlink/off_find/hdi_service/implement/off_find_hdi_constant.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2026 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 OHOS_HDI_NEARLINK_OFF_FIND_CONSTANT_H +#define OHOS_HDI_NEARLINK_OFF_FIND_CONSTANT_H + +#include + +#include + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace OffFind { +constexpr const char *OFF_FIND_VENDOR_NAME = "liboff_find_vendor"; +constexpr const char *SLE_OFF_FIND_CHIP_TYPE = "const.nearlink.off_find.slechiptype"; +constexpr const char *OFF_FIND_VENDOR_INTERFACE_SYMBOL_NAME = "NEARLINK_OFF_FIND_VENDOR_LIB_INTERFACE"; +constexpr const char *OFF_FIND_VENDOR_COMMON_NAME = "liboff_find_vendor_common_ext.z.so"; +constexpr const char *OFF_FIND_VENDOR_COMMON_INTERFACE_SYMBOL_NAME = "NEARLINK_OFF_FIND_VENDOR_COMMON_LIB_INTERFACE"; +constexpr int SLE_THREAD_POLICY = SCHED_RR; +constexpr int SLE_THREAD_PRIORITY = 1; +/** + * Define OFF FIND MODEL ENABLE OR DISABLE RESULT. + */ +typedef enum { + SUCCESS, // HCI Command channel + INITIALIZATION_ERROR, // HCI Event channel +} OffFindSwitchResult; + +typedef enum { + OFF_FIND_SUCCESS, + OFF_FIND_FAIL, + OFF_FIND_SYNC_FAIL, +} OffFindErrorCode; + +/** + * Define POWER MODE CMD. + */ +typedef enum { + CLEAR_RESERVED_POWER, + SET_RESERVED_POWER +} PmuPowerMode; + +/** + * Define off find capability. + */ +typedef enum { + OF_SLE_ADV_ENABLE = 0x01, + OF_SLE_RING_SUPPORT = 0X02, +} OfSleFeatureFlag; + +} // namespace OffFind +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS + +#endif /* OHOS_HDI_NEARLINK_OFF_FIND_CONSTANT_H */ \ No newline at end of file diff --git a/nearlink/off_find/hdi_service/implement/off_find_log.h b/nearlink/off_find/hdi_service/implement/off_find_log.h new file mode 100644 index 0000000000..45f2487588 --- /dev/null +++ b/nearlink/off_find/hdi_service/implement/off_find_log.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2026 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 OFF_FIND_LOG_H +#define OFF_FIND_LOG_H + +#include + +#ifdef LOG_DOMAIN +#undef LOG_DOMAIN +#endif +#define LOG_DOMAIN 0xD000154 + +#ifndef HDF_LOG_TAG +#define HDF_LOG_TAG hdf_off_find +#endif + +#endif // OFF_FIND_LOG_H \ No newline at end of file diff --git a/nearlink/off_find/hdi_service/implement/ohos_off_find_vendor_lib.h b/nearlink/off_find/hdi_service/implement/ohos_off_find_vendor_lib.h new file mode 100644 index 0000000000..481988d2ba --- /dev/null +++ b/nearlink/off_find/hdi_service/implement/ohos_off_find_vendor_lib.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2026 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 OFF_FIND_VENDOR_LIB_H +#define OFF_FIND_VENDOR_LIB_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Define DLI channel descriptors array used in SLE_OP_DLI_CHANNEL_OPEN operation. + */ +typedef enum { + DLI_CMD, // DLI Command channel + DLI_EVT, // DLI Event channel + DLI_MAX_CHANNEL // Total channels +} DliChannelsT; + +/** + * SLE vendor lib cmd. + */ +typedef enum { + /** + * Set Resvered Power for off find mode,it will be called when findnetwork enable. + */ + SLE_OP_RESERVERD_POWER_SET, + /** + * Establish dli channels. it will be called after SLE_OP_POWER_ON. + * @param int (*)[DLI_MAX_CHANNEL]. + * @return fd count. + */ + SLE_OP_DLI_CHANNEL_OPEN, + + /** + * Close all the dli channels which is opened. + */ + SLE_OP_DLI_CHANNEL_CLOSE, + /** + * Set off find mode. + * @param int *powerTime. + */ + SLE_OP_OFF_FIND_MODE_ENABLE, + /** + * Disable off find mode. + */ + SLE_OP_OFF_FIND_MODE_DISABLE, + /** + * Enable Leakage Prevention Mode mode. + */ + SLE_OP_OFF_FIND_POWER_PROTECT_ENABLE, +} OffFindOpcodeT; + +/** + * Nearlink Host/Controller VENDOR Interface + */ +typedef struct { + /** + * Set to sizeof(sle_vndor_interface_t) + */ + size_t size; + + /** + * Caller will open the interface and pass in the callback routines + * to the implementation of this interface. + */ + int (*init)(void); + + /** + * Vendor specific operations + */ + int (*op)(int opcode, void* param); + + /** + * Closes the interface + */ + void (*close)(void); +} OffFindVendorInterfaceT; + +typedef struct { + size_t size; + int (*modifyPowerProtect)(int powerTime, int power); + bool (*isNeedWatcherStart)(std::string chipType); + uint32_t (*getRegisterTimerDuration)(std::string chipType); + void (*close)(void); +} OffFindVendorCommInterfaceT; + +typedef struct { + uint16_t event; + uint16_t len; + uint16_t offset; + uint16_t layerSpecific; + uint8_t data[]; +} HC_SLE_HDR; + +#ifdef __cplusplus +} +#endif + +#endif /* SLE_VENDOR_LIB_H */ diff --git a/nearlink/off_find/hdi_service/implement/thread_util.cpp b/nearlink/off_find/hdi_service/implement/thread_util.cpp new file mode 100644 index 0000000000..60c71b5bb3 --- /dev/null +++ b/nearlink/off_find/hdi_service/implement/thread_util.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2026 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 "thread_util.h" +#include +#include "ffrt_inner.h" +#include + +namespace OHOS { +namespace HDI { +namespace Nearlink { + +void DoInDliThread(const ThreadUtilFunc &func) +{ + ThreadUtil::GetInstance().PostTask(func); +} + +struct ThreadUtil::impl { + class TaskQueue { + public: + explicit TaskQueue(const char *name) : queue_(name, ffrt::queue_attr().qos(ffrt::qos_user_interactive)) {} + ~TaskQueue() = default; + + void PostTask(const ThreadUtilFunc &func); + int GetQueueId(void); + + private: + ffrt::queue queue_; + }; + + impl(); + ~impl() = default; + std::shared_ptr CreateTaskQueue(); + + std::shared_ptr taskQueue; +}; + +ThreadUtil::impl::impl() +{} + +ThreadUtil::ThreadUtil() : pimpl(std::make_unique()) +{} + +ThreadUtil::~ThreadUtil() +{} + +void ThreadUtil::impl::TaskQueue::PostTask(const ThreadUtilFunc &func) +{ + queue_.submit(func); +} + +int ThreadUtil::impl::TaskQueue::GetQueueId(void) +{ + int id = -1; + auto handle = queue_.submit_h([&id]() { + id = ffrt::get_queue_id(); + }); + queue_.wait(handle); + return id; +} + +void ThreadUtil::PostTask(const ThreadUtilFunc &func) +{ + std::lock_guard lock(taskQueueMutex_); + std::shared_ptr taskQueue = pimpl->taskQueue; + if (taskQueue != nullptr) { + taskQueue->PostTask(func); + return; + } + // If the thread not found, create it. + taskQueue = pimpl->CreateTaskQueue(); + // Execute the first task. + if (taskQueue) { + taskQueue->PostTask(func); + } +} + +std::shared_ptr ThreadUtil::impl::CreateTaskQueue() +{ + std::string threadName = "sle_hci"; + auto taskQueue_ = std::make_shared(threadName.c_str()); + + int queueId = taskQueue_->GetQueueId(); + HDF_LOGI("sle_ffrt_queue: queueId(%{public}d), name(%{public}s)", queueId, threadName.c_str()); + + taskQueue = taskQueue_; + return taskQueue_; +} + +ThreadUtil &ThreadUtil::GetInstance() +{ + static ThreadUtil instance; + return instance; +} +} // namespace Nearlink +} // namepsace HDI +} // namespace OHOS \ No newline at end of file diff --git a/nearlink/off_find/hdi_service/implement/thread_util.h b/nearlink/off_find/hdi_service/implement/thread_util.h new file mode 100644 index 0000000000..a9512283a5 --- /dev/null +++ b/nearlink/off_find/hdi_service/implement/thread_util.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2026 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 SLE_THREAD_UTIL_H +#define SLE_THREAD_UTIL_H + +#include +#include "ffrt_inner.h" +#include +#include "off_find_log.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { + +using ThreadUtilFunc = std::function; + +/** + * @brief Post the task to the dli thread. + * @param func The task to be executed. + */ +void DoInDliThread(const ThreadUtilFunc &func); + +class ThreadUtil { +public: + void PostTask(const ThreadUtilFunc &func); + static ThreadUtil &GetInstance(); +private: + ThreadUtil(); + ~ThreadUtil(); + + struct impl; + std::unique_ptr pimpl; + ffrt::mutex taskQueueMutex_ {}; +}; +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS + +#endif // SLE_THREAD_UTIL_H \ No newline at end of file diff --git a/nearlink/off_find/hdi_service/implement/vendor_interface.cpp b/nearlink/off_find/hdi_service/implement/vendor_interface.cpp new file mode 100644 index 0000000000..59c2fa434f --- /dev/null +++ b/nearlink/off_find/hdi_service/implement/vendor_interface.cpp @@ -0,0 +1,620 @@ +/* + * Copyright (C) 2026 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 +#include +#include +#include +#include +#include +#include +#include + +#include "off_find_log.h" +#include "h4_protocol.h" +#include "common_timer_errors.h" +#include "parameters.h" +#include "vendor_interface.h" +#include "thread_util.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace OffFind { +namespace V1_0 { + +// disable off find cmd +#ifdef SEND_DISABLE_OFF_FIND_DLI +constexpr uint8_t DLI_DISABLE_OFFFIDN_CMD = 0x16; +constexpr uint8_t DLI_DISABLE_OFFFIDN_PARAM = 0x19; +#endif + +// Opcode +constexpr uint16_t DLI_SWITCH_HOST = 0xFC92; +constexpr uint16_t DLI_SET_POWER_OFF_PARAM = 0xFC91; + +// Power off parm +constexpr size_t DLI_PACKET_MIN_SIZE = 8; +constexpr size_t DLI_PACKET_HEADER_SIZE = 5; +constexpr size_t DLI_DATA_LEN_SIZE = 3; +constexpr size_t DLI_ADVTIME_SIZE = 4; +constexpr size_t ADV_FLAG_SIZE = 2; // ble and sle adv enable flag 1 on 0 off + +// User and device Id len LIMIT +constexpr size_t DEVICE_ID_LEN = 64; +constexpr size_t USER_ID_LEN = 32; + +// Advtising data len limit +constexpr size_t ADV_KEY_LEN = 32; +constexpr size_t ADV_CMAC_LEN = 2; + +constexpr int OFFSET_EIGHT_BITS = 8; + +// battery and correspond pwoerTime +constexpr int BATTERY_ENTRY = 3; +constexpr int BATTERY_HIGH_ENTRY = 10; // 关机七天可找电池阈值 + +constexpr int DEFAULT_CHIP_STEP = 1; // 默认芯片步长 + +constexpr int HIGH_POWER_TIME = 168; // 关机七天 7 day = 7*24h +constexpr int UP_POWER_TIME = 48; +constexpr int DOWN_POWER_TIME = 12; +constexpr int AIR_OTA_POWER_TIME = 168; // 隔空升级 7 day = 7*24h +constexpr size_t DEFAULT_ADV_DATA_LEN = 3; // 关机3d下发广播数组长度 +constexpr size_t SEVEN_DAYS_ADV_DATA_LEN = 8; // 关机7d下发广播数组长度 +// Data len dli position +constexpr int THIRD_BYTE = 3; +constexpr int FOURTH_BYTE = 4; +constexpr int FIFTH_BYTE = 5; +constexpr int SIXTH_BYTE = 6; +constexpr int OFFSET_STATUS = 3; + +// Data len limit +constexpr size_t DATA_LEN_BYTE = 2; + +constexpr int TIME_OUT_MAX = 3000; + +// Timeot ms +constexpr int TIME_OUT_INIT_CHMOD = 500; + +typedef struct InternalCommand { + uint16_t cbsh; + uint16_t cbofp; + uint16_t opcode; +} InternalCommand; + +InternalCommand g_internalCommand = {0, 0, 0}; + +constexpr size_t SLE_VENDOR_INVALID_DATA_LEN = 0; + +VendorInterface::VendorInterface() +{ + timer_ = std::make_unique("NearlinkOffFindTimer"); + timer_->Setup(); + offFindTimerId_ = 0; +} + +VendorInterface::~VendorInterface() +{ + if (timer_) { + timer_->Shutdown(); + } + CleanUp(); +} + +bool VendorInterface::SetSwitchHostTimer() +{ + if (timer_ == nullptr) { + HDF_LOGE("timer_ is nulptr"); + return false; + } + auto func = []() { + HDF_LOGI("SetSwitchHost TimeOut"); + VendorInterface::GetInstance()->OnInitCallback(OFF_FIND_FAIL); + }; + uint32_t timeOut = TIME_OUT_MAX; + if (LoadVendorCommonLibrary() == OFF_FIND_SUCCESS && + vendorCommInterface_->getRegisterTimerDuration != NULL) { + timeOut = vendorCommInterface_->getRegisterTimerDuration(chipType_); + } + uint32_t ret = timer_->Register(func, timeOut, true); // only support once timer now + if (ret == OHOS::Utils::TIMER_ERR_DEAL_FAILED) { + HDF_LOGE("Register timer failed"); + return false; + } + offFindTimerId_ = ret; + HDF_LOGI("offFindTimerId_ set: %{public}u", offFindTimerId_); + return true; +} + +void VendorInterface::DliPacketHearderGet(uint16_t paramLen) +{ + offFindDli_.push_back(DLI_PACKET_TYPE_SLE_CMD); + offFindDli_.push_back(static_cast(DLI_SET_POWER_OFF_PARAM)); + offFindDli_.push_back(static_cast((DLI_SET_POWER_OFF_PARAM) >> OFFSET_EIGHT_BITS)); + + // Total data len in header + offFindDli_.push_back(static_cast(paramLen - DLI_PACKET_HEADER_SIZE)); + offFindDli_.push_back(static_cast((paramLen - DLI_PACKET_HEADER_SIZE) >> OFFSET_EIGHT_BITS)); + + // Total data len in data head + offFindDli_.push_back(static_cast(paramLen - DLI_PACKET_HEADER_SIZE)); + offFindDli_.push_back(static_cast((paramLen - DLI_PACKET_HEADER_SIZE) >> OFFSET_EIGHT_BITS)); +} + +#ifdef SEND_DISABLE_OFF_FIND_DLI +void VendorInterface::DisableDliPacketHearderGet() +{ + // disable offfind cmd + offFindDli_.push_back(DLI_PACKET_TYPE_SLE_CMD); + offFindDli_.push_back(DLI_DISABLE_OFFFIDN_CMD); + offFindDli_.push_back(DLI_DISABLE_OFFFIDN_PARAM); +} +#endif + +uint8_t VendorInterface::GetSleCapability(int power) +{ + uint8_t sleCapability = power <= BATTERY_ENTRY ? 0 : OF_SLE_ADV_ENABLE; + if (OHOS::system::GetBoolParameter("const.nearlink.support.off_ring", false) && sleCapability != 0) { + sleCapability = sleCapability | OF_SLE_RING_SUPPORT; + } + return sleCapability; +} + +bool VendorInterface::PowerOffDliGet( + const std::vector& data, const OffFindExtraInfo& info, size_t paramsCnt) +{ + HDF_LOGI("data[%{public}zu]udid[%{public}zu]uid[%{public}zu]", data.size(), info.udid.size(), info.uid.size()); + if (data.size() != paramsCnt || info.udid.size() > DEVICE_ID_LEN || info.uid.size() > USER_ID_LEN) { + return false; + } + uint8_t sleCapability = GetSleCapability(info.battery); + HDF_LOGI("power[%{public}d] sle[%{public}d]", info.battery, sleCapability); + uint16_t paramLen = DLI_PACKET_HEADER_SIZE + ADV_FLAG_SIZE + DLI_DATA_LEN_SIZE + info.udid.size() + info.uid.size() + + data.size() * DLI_DATA_LEN_SIZE; + uint16_t dataLen = 0; + offFindDli_.reserve(static_cast(paramLen)); + DliPacketHearderGet(paramLen); + offFindDli_.push_back(1); // ble adv flag (default on) + offFindDli_.push_back(sleCapability); // sle capability + offFindDli_.push_back(info.udid.size()); + offFindDli_.insert(offFindDli_.end(), info.udid.begin(), info.udid.end()); + offFindDli_.push_back(info.uid.size()); + offFindDli_.insert(offFindDli_.end(), info.uid.begin(), info.uid.end()); + offFindDli_.insert(offFindDli_.end(), data.size()); + for (size_t i = 0; i < data.size(); i++) { + HDF_LOGI("advertising key or cmac len [%{public}zu][%{public}zu][%{public}zu]", + data[i].publicKey.size(), data[i].cmac.size(), data[i].aesKey.size()); + if (data[i].publicKey.size() > ADV_KEY_LEN || data[i].cmac.size() > ADV_CMAC_LEN || + data[i].aesKey.size() > ADV_KEY_LEN) { + return false; + } + offFindDli_.push_back(data[i].publicKey.size()); + offFindDli_.insert(offFindDli_.end(), data[i].publicKey.begin(), data[i].publicKey.end()); + offFindDli_.push_back(data[i].cmac.size()); + offFindDli_.insert(offFindDli_.end(), data[i].cmac.begin(), data[i].cmac.end()); + offFindDli_.push_back(data[i].aesKey.size()); + offFindDli_.insert(offFindDli_.end(), data[i].aesKey.begin(), data[i].aesKey.end()); + std::vector advTime(DLI_ADVTIME_SIZE); + for (size_t j = 0; j < DLI_ADVTIME_SIZE; j++) { + advTime[DLI_ADVTIME_SIZE - j - 1] = + (data[i].advTime >> ((DLI_ADVTIME_SIZE-1 - j) * OFFSET_EIGHT_BITS)) & 0xFF; + } + offFindDli_.insert(offFindDli_.end(), advTime.begin(), advTime.end()); + dataLen += data[i].publicKey.size() + data[i].cmac.size() + data[i].aesKey.size() + DLI_ADVTIME_SIZE; + } + offFindDli_[THIRD_BYTE] = static_cast(paramLen + dataLen + DATA_LEN_BYTE - DLI_PACKET_HEADER_SIZE); + offFindDli_[FOURTH_BYTE] = static_cast( + (paramLen + dataLen + DATA_LEN_BYTE - DLI_PACKET_HEADER_SIZE) >> OFFSET_EIGHT_BITS); + offFindDli_[FIFTH_BYTE] = static_cast(paramLen + dataLen - DLI_PACKET_HEADER_SIZE); + offFindDli_[SIXTH_BYTE] = static_cast( + (paramLen + dataLen - DLI_PACKET_HEADER_SIZE) >> OFFSET_EIGHT_BITS); + return true; +} + +void VendorInterface::SwitchHostDliGet(std::vector& data) +{ + data.push_back(DLI_PACKET_TYPE_SLE_CMD); + data.push_back(static_cast(DLI_SWITCH_HOST)); + data.push_back(static_cast((DLI_SWITCH_HOST) >> OFFSET_EIGHT_BITS)); + data.push_back(0x00); + data.push_back(0x00); + g_internalCommand.cbsh = 1; + g_internalCommand.opcode = DLI_SWITCH_HOST; +} + +bool VendorInterface::WatchDliChannel() +{ + int channel[DLI_MAX_CHANNEL] = {0}; + int channelCount = vendorInterface_->op(OffFindOpcodeT::SLE_OP_DLI_CHANNEL_OPEN, static_cast(channel)); + if (channelCount < 1 || channelCount > DLI_MAX_CHANNEL) { + HDF_LOGE("vendorInterface_->op SLE_OP_DLI_CHANNEL_OPEN failed ret:%{public}d.", channelCount); + return false; + } + if (channelCount == 1) { + auto h4 = std::make_shared(channel[0], + std::bind(&VendorInterface::OnEventReceived, this, std::placeholders::_1)); + watcher_.AddFdToWatcher(channel[0], std::bind(&OffFind::H4Protocol::ReadData, h4, std::placeholders::_1)); + dli_ = h4; + } else { + HDF_LOGE("invalid channel count:%d.", channelCount); + return false; + } + return true; +} + +void VendorInterface::SetReservedPower() +{ + if (isInitialized_.load()) { + HDF_LOGE("already Initialized"); + return; + } + std::lock_guard lock(processMutex_); + if (vendorHandle_ == nullptr || vendorInterface_ == nullptr) { + vendorHandle_ = dlopen(GetFullVendorName(), RTLD_NOW); + if (vendorHandle_ == nullptr) { + HDF_LOGE("VendorInterface dlopen %{public}s failed, error code: %{public}s", offFindVendorName_.c_str(), + dlerror()); + return; + } + vendorInterface_ = + reinterpret_cast(dlsym(vendorHandle_, OFF_FIND_VENDOR_INTERFACE_SYMBOL_NAME)); + if (vendorInterface_ == nullptr) { + HDF_LOGE("VendorInterface dlsym %{public}s failed.", OFF_FIND_VENDOR_INTERFACE_SYMBOL_NAME); + return; + } + } + + // dev_offfind node init time sometimes later than findnetwork process init when startup + std::this_thread::sleep_for(std::chrono::milliseconds(TIME_OUT_INIT_CHMOD)); + vendorInterface_->init(); + int powerSetFlag = SET_RESERVED_POWER; + vendorInterface_->op(OffFindOpcodeT::SLE_OP_RESERVERD_POWER_SET, static_cast(&powerSetFlag)); + CleanUp(); +} + +int VendorInterface::GetPowerTimeParameter(const OffFindExtraInfo& info, size_t paramsCnt) +{ + int power = info.battery <= BATTERY_ENTRY ? + OHOS::system::GetIntParameter("const.nearlink.off_find.low_battery_time", DOWN_POWER_TIME) + : OHOS::system::GetIntParameter("const.nearlink.off_find.high_battery_time", UP_POWER_TIME); + + if (paramsCnt == SEVEN_DAYS_ADV_DATA_LEN && info.battery > BATTERY_HIGH_ENTRY) { + power = HIGH_POWER_TIME; + } + + bool isAirOta = std::all_of(info.uid.begin(), info.uid.end(), [](unsigned char c) { + return c == 0xFF; + }); + if (!info.uid.empty() && isAirOta) { + power = AIR_OTA_POWER_TIME; + } + + int chipStep = OHOS::system::GetIntParameter("const.nearlink.off_find.chip_step", DEFAULT_CHIP_STEP); + if (chipStep <= 0) { + chipStep = DEFAULT_CHIP_STEP; + } + if (chipStep > 0) { + power /= chipStep; + } + return power; +} + +OffFindErrorCode VendorInterface::OpenAndSymDl() +{ + if (vendorHandle_ == nullptr || vendorInterface_ == nullptr) { + vendorHandle_ = dlopen(GetFullVendorName(), RTLD_NOW); + if (vendorHandle_ == nullptr) { + HDF_LOGE("dlopen %{public}s failed, error code: %{public}s", offFindVendorName_.c_str(), dlerror()); + return OFF_FIND_SYNC_FAIL; + } + vendorInterface_ = + reinterpret_cast(dlsym(vendorHandle_, OFF_FIND_VENDOR_INTERFACE_SYMBOL_NAME)); + if (vendorInterface_ == nullptr) { + HDF_LOGE("VendorInterface dlsym %{public}s failed.", OFF_FIND_VENDOR_INTERFACE_SYMBOL_NAME); + return OFF_FIND_SYNC_FAIL; + } + } + return OFF_FIND_SUCCESS; +} + +OffFindErrorCode VendorInterface::LoadVendorCommonLibrary() +{ + if (vendorCommHandle_ != nullptr && vendorCommInterface_ != nullptr) { + return OFF_FIND_SUCCESS; + } + vendorCommHandle_ = dlopen(OFF_FIND_VENDOR_COMMON_NAME, RTLD_NOW); + if (vendorCommHandle_ == nullptr) { + HDF_LOGE("dlopen %{public}s failed, errCode: %{public}s", OFF_FIND_VENDOR_COMMON_NAME, dlerror()); + return OFF_FIND_SYNC_FAIL; + } + vendorCommInterface_ = reinterpret_cast(dlsym(vendorCommHandle_, + OFF_FIND_VENDOR_COMMON_INTERFACE_SYMBOL_NAME)); + if (vendorCommInterface_ == nullptr) { + HDF_LOGE("dlsym failed %{public}s, err: %{public}s", OFF_FIND_VENDOR_COMMON_INTERFACE_SYMBOL_NAME, dlerror()); + dlclose(vendorCommHandle_); + return OFF_FIND_SYNC_FAIL; + } + HDF_LOGI("LoadVendorCommonLibrary success %{public}s", OFF_FIND_VENDOR_COMMON_NAME); + return OFF_FIND_SUCCESS; +} + +OffFindErrorCode VendorInterface::EnableOffFindMode(InitializeCompleteCallback initializeCompleteCallback, + const std::vector& data, const OffFindExtraInfo& info) +{ + std::lock_guard lock(processMutex_); + size_t paramsCnt = + OHOS::system::GetUintParameter("const.findnetwork.shutdown_params.count", DEFAULT_ADV_DATA_LEN); + HDF_LOGI("EnableOffFindMode Begin, %{public}zu params", paramsCnt); + if (!PowerOffDliGet(data, info, paramsCnt)) { + HDF_LOGE("PowerOffDliGet ERROR"); + return OFF_FIND_SYNC_FAIL; + } + initializeCompleteCallback_ = initializeCompleteCallback; + if (OpenAndSymDl() != OFF_FIND_SUCCESS || LoadVendorCommonLibrary() != OFF_FIND_SUCCESS) { + return OFF_FIND_SYNC_FAIL; + } + vendorInterface_->init(); + if (!WatchDliChannel()) { + HDF_LOGE("WatchDliChannel Init Fail"); + return OFF_FIND_SYNC_FAIL; + } + if (vendorCommInterface_->isNeedWatcherStart != NULL && + vendorCommInterface_->isNeedWatcherStart(chipType_) && !watcher_.Start()) { + HDF_LOGE("watcher start failed."); + return OFF_FIND_SYNC_FAIL; + } + int powerTime = GetPowerTimeParameter(info, paramsCnt); + HDF_LOGI("battery[%{public}d] and powerTime[%{public}d]", info.battery, powerTime); + + if (vendorCommInterface_->modifyPowerProtect != NULL && + vendorCommInterface_->modifyPowerProtect(powerTime, info.battery) != OFF_FIND_SUCCESS) { + HDF_LOGE("modifyPowerProtect failed"); + return OFF_FIND_SYNC_FAIL; + } + + if (!SetSwitchHostTimer()) { + HDF_LOGE("OffFind Mode SetTimer failed"); + return OFF_FIND_SYNC_FAIL; + } + int ret = vendorInterface_->op(OffFindOpcodeT::SLE_OP_OFF_FIND_MODE_ENABLE, static_cast(&powerTime)); + if (ret < 0) { + HDF_LOGE("OffFind Mode Enable failed"); + return OFF_FIND_FAIL; + } + g_internalCommand.cbofp = 1; + dliCompleteFlag_ = false; + dli_->SendPacket(offFindDli_); + offFindDli_.clear(); + return OFF_FIND_SUCCESS; +} + +void VendorInterface::RegisterClearOffFindCallback(ClearIpcCallback clearIpcCallback) +{ + clearIpcCallback_ = clearIpcCallback; +} + +bool VendorInterface::Initialize(InitializeCompleteCallback initializeCompleteCallback, + const std::vector& data, const OffFindExtraInfo& info) +{ + if (isInitialized_.load()) { + HDF_LOGE("already Initialized"); + return false; + } + isInitialized_.store(true); + OffFindErrorCode ret = OFF_FIND_SUCCESS; + ret = EnableOffFindMode(initializeCompleteCallback, data, info); + if (ret == OFF_FIND_SUCCESS) { + return true; + } + OnInitCallback(ret); + return false; +} + +const char* VendorInterface::GetFullVendorName() +{ + if (offFindVendorName_ != "") { + return offFindVendorName_.c_str(); + } + offFindVendorName_ = OFF_FIND_VENDOR_NAME; + std::string sleChipType = OHOS::system::GetParameter(SLE_OFF_FIND_CHIP_TYPE, ""); + HDF_LOGI("sleChipType is %{public}s", sleChipType.c_str()); + if (!sleChipType.empty()) { + offFindVendorName_.append("_"); + offFindVendorName_.append(sleChipType.c_str()); + chipType_.append(sleChipType); + } + offFindVendorName_.append(".z.so"); + HDF_LOGI("vendor name is %{public}s", offFindVendorName_.c_str()); + return offFindVendorName_.c_str(); +} + +void VendorInterface::DisableOffFindMode() +{ + std::lock_guard lock(processMutex_); + if (vendorHandle_ == nullptr || vendorInterface_ == nullptr) { + vendorHandle_ = dlopen(GetFullVendorName(), RTLD_NOW); + if (vendorHandle_ == nullptr) { + HDF_LOGE("VendorInterface dlopen %{public}s failed, error code: %{public}s", offFindVendorName_.c_str(), + dlerror()); + return; + } + vendorInterface_ = + reinterpret_cast(dlsym(vendorHandle_, OFF_FIND_VENDOR_INTERFACE_SYMBOL_NAME)); + if (vendorInterface_ == nullptr) { + HDF_LOGE("VendorInterface dlsym %{public}s failed.", OFF_FIND_VENDOR_INTERFACE_SYMBOL_NAME); + return; + } + } + vendorInterface_->init(); +#ifdef SEND_DISABLE_OFF_FIND_DLI + if (!WatchDliChannel()) { + HDF_LOGE("WatchDliChannel Init Fail"); + } + DisableDliPacketHearderGet(); + if (dli_ != nullptr) { + dli_->SendPacket(offFindDli_); + } + offFindDli_.clear(); + vendorInterface_->op(OffFindOpcodeT::SLE_OP_DLI_CHANNEL_CLOSE, nullptr); +#endif + int powerSetFlag = CLEAR_RESERVED_POWER; + vendorInterface_->op(OffFindOpcodeT::SLE_OP_RESERVERD_POWER_SET, static_cast(&powerSetFlag)); + isInitialized_.store(false); + vendorInterface_->op(OffFindOpcodeT::SLE_OP_OFF_FIND_MODE_DISABLE, nullptr); + vendorInterface_->close(); + CleanUp(); +} + +void VendorInterface::CleanUp() +{ + std::lock_guard lock(processMutex_); + if (vendorInterface_ == nullptr) { + HDF_LOGE("VendorInterface::CleanUp, vendorInterface_ is nullptr."); + return; + } + HDF_LOGI("off find clean up"); + watcher_.Stop(); + dli_ = nullptr; + vendorInterface_ = nullptr; + initializeCompleteCallback_ = nullptr; + eventDataCallback_ = nullptr; + dlclose(vendorHandle_); + vendorCommInterface_ = nullptr; + dlclose(vendorCommHandle_); +} + +size_t VendorInterface::SendPacket(const std::vector &packet) +{ + if (vendorInterface_ == nullptr || dli_ == nullptr) { + HDF_LOGE("VendorInterface::SendPacket, vendorInterface_ is nullptr."); + return SLE_VENDOR_INVALID_DATA_LEN; + } + + watcher_.SetTimeout(std::chrono::milliseconds(lpmTimer_), std::bind(&VendorInterface::WatcherTimeout, this)); + + return dli_->SendPacket(packet); +} + +void VendorInterface::OnInitCallback(OffFindErrorCode result) +{ + HDF_LOGI("OnInitCallback %{public}d", result); + OffFindSwitchResult status = OffFindSwitchResult::INITIALIZATION_ERROR; + if (result != OFF_FIND_SYNC_FAIL) { + if (offFindTimerId_ == 0) { + HDF_LOGE("offFindTimerId_ is 0, no registered timer"); + } else { + HDF_LOGI("OnInitCallback offFindTimerId_: %{public}d", offFindTimerId_); + if (timer_ == nullptr) { + HDF_LOGE("timer_ is nulptr"); + } else { + timer_->Unregister(offFindTimerId_); + } + } + if (result == OFF_FIND_SUCCESS) { + status = OffFindSwitchResult::SUCCESS; + } else { + vendorInterface_->op(OffFindOpcodeT::SLE_OP_OFF_FIND_MODE_DISABLE, nullptr); + } + } + isInitialized_.store(false); + if (initializeCompleteCallback_) { + initializeCompleteCallback_(status); + initializeCompleteCallback_ = nullptr; + if (clearIpcCallback_) { + clearIpcCallback_(); + } + } + CleanUp(); +} + +bool VendorInterface::EventReceivedHandler(const std::vector &data) +{ + if (data.size() < DLI_PACKET_MIN_SIZE) { + HDF_LOGE("packet len err , [%{public}zu]", data.size()); + return false; + } + uint16_t eventOpcode = data[0] | (data[1] << OFFSET_EIGHT_BITS); + // 如果 eventOpcode 不是 SLE_DLI_COMMAND_COMPLETE_EVENT,可能是残留数据不做任何处理,直接返回 true,后续正常的COMPLETE_EVENT会继续返回 + if (eventOpcode != SLE_DLI_COMMAND_COMPLETE_EVENT) { + HDF_LOGW("eventOpcode[%{public}04X] is not complete event", eventOpcode); + return true; + } + size_t opcodeOffset = dli_->GetPacketHeaderInfo(DLI_PACKET_TYPE_SLE_EVENT).headerSize; + uint16_t opcode = data[opcodeOffset] + (data[opcodeOffset + 1] << OFFSET_EIGHT_BITS); + HDF_LOGI("opcode[%{public}04X], cbofp[%{public}d], cbsh[%{public}d], status[%{public}d]", + opcode, g_internalCommand.cbofp, g_internalCommand.cbsh, data[opcodeOffset + OFFSET_STATUS]); + if (g_internalCommand.cbofp != 0 && opcode == DLI_SET_POWER_OFF_PARAM) { + if (data[opcodeOffset + OFFSET_STATUS] != 0) { + HDF_LOGE("set param event status[%{public}d] error", data[opcodeOffset + OFFSET_STATUS]); + return false; + } + g_internalCommand.cbofp = 0; + g_internalCommand.cbsh = 1; + g_internalCommand.opcode = DLI_SWITCH_HOST; + std::vector switchHostDli; + switchHostDli.reserve(DLI_PACKET_HEADER_SIZE); + SwitchHostDliGet(switchHostDli); + dli_->SendPacket(switchHostDli); + return true; + } else if (g_internalCommand.cbsh != 0 && opcode == DLI_SWITCH_HOST) { + if (data[opcodeOffset + OFFSET_STATUS] != 0) { + HDF_LOGE("switch host status[%{public}d] error", data[opcodeOffset + OFFSET_STATUS]); + return false; + } + int ret = vendorInterface_->op(OffFindOpcodeT::SLE_OP_OFF_FIND_POWER_PROTECT_ENABLE, nullptr); + if (ret < 0) { + HDF_LOGE("OffFind power cfg config failed"); + return false; + } + dliCompleteFlag_ = true; + g_internalCommand.cbsh = 0; + return true; + } else { + HDF_LOGE("unknown dli"); + return false; + } +} + +void VendorInterface::OnEventReceived(const std::vector &data) +{ + Nearlink::DoInDliThread([this, acbData = data]() { + this->OnEventReceivedTask(acbData); + }); + return; +} + +void VendorInterface::OnEventReceivedTask(const std::vector &data) +{ + HDF_LOGI("OnEventReceivedTask"); + bool ret = EventReceivedHandler(data); + if (ret && dliCompleteFlag_) { + OnInitCallback(OFF_FIND_SUCCESS); + } else if (!ret) { + OnInitCallback(OFF_FIND_FAIL); + } else { + return ; + } +} + +void VendorInterface::WatcherTimeout() +{ + HDF_LOGI("fd wait out of time, no data ready"); +} +} // namespace V1_0 +} // namespace OffFind +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS \ No newline at end of file diff --git a/nearlink/off_find/hdi_service/implement/vendor_interface.h b/nearlink/off_find/hdi_service/implement/vendor_interface.h new file mode 100644 index 0000000000..1dd981b865 --- /dev/null +++ b/nearlink/off_find/hdi_service/implement/vendor_interface.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2026 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 OHOS_HDI_NEARLINK_OFF_FIND_V1_0_VENDOR_INTERFACE_H +#define OHOS_HDI_NEARLINK_OFF_FIND_V1_0_VENDOR_INTERFACE_H + +#include +#include +#include "timer.h" +#include "singleton.h" +#include "off_find_hdi_constant.h" +#include "dli_internal.h" +#include "dli_protocol.h" +#include "dli_watcher.h" +#include "ffrt_inner.h" +#include "v1_0/off_find_types.h" +#include "ohos_off_find_vendor_lib.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace OffFind { +namespace V1_0 { +class VendorInterface : public DelayedSingleton { +public: + using InitializeCompleteCallback = std::function; + using ClearIpcCallback = std::function; + using ReceiveDataCallback = DliProtocol::DliDataCallback; + void SetReservedPower(); + void RegisterClearOffFindCallback(ClearIpcCallback clearIpcCallback + ); + bool Initialize(InitializeCompleteCallback initializeCompleteCallback, const std::vector& data, + const OffFindExtraInfo& info); + void DisableOffFindMode(); + void CleanUp(); + size_t SendPacket(const std::vector &packet); + void SetSleAddress(uint8_t *localSleAddr); + uint8_t *SetAddress(uint8_t *addr); +private: + OffFindErrorCode EnableOffFindMode(InitializeCompleteCallback initializeCompleteCallback, + const std::vector& data, const OffFindExtraInfo& info); + OffFindErrorCode OpenAndSymDl(); + OffFindErrorCode LoadVendorCommonLibrary(); + bool EventReceivedHandler(const std::vector &data); + void OnInitCallback(OffFindErrorCode result); + void OnEventReceived(const std::vector &data); + void OnEventReceivedTask(const std::vector &data); + bool WatchDliChannel(); + void WatcherTimeout(); + InitializeCompleteCallback initializeCompleteCallback_; + ClearIpcCallback clearIpcCallback_; + ReceiveDataCallback eventDataCallback_; + void* vendorHandle_ = nullptr; + OffFindVendorInterfaceT *vendorInterface_ = nullptr; + void* vendorCommHandle_ = nullptr; + OffFindVendorCommInterfaceT *vendorCommInterface_ = nullptr; + DliWatcher watcher_; + std::shared_ptr dli_ = nullptr; + std::vector offFindDli_; + uint16_t vendorSentOpcode_ = 0; + uint32_t lpmTimer_ = 0; + std::unique_ptr timer_ {nullptr}; + uint32_t offFindTimerId_; + std::string offFindVendorName_ = ""; + std::string chipType_ = ""; + bool dliCompleteFlag_ = false; + void DliPacketHearderGet(uint16_t paramLen); +#ifdef SEND_DISABLE_OFF_FIND_DLI + void DisableDliPacketHearderGet(); +#endif + bool SetSwitchHostTimer(); + uint8_t GetSleCapability(int power); + bool PowerOffDliGet(const std::vector& data, const OffFindExtraInfo& info, size_t paramsCnt); + void SwitchHostDliGet(std::vector& data); + int GetPowerTimeParameter(const OffFindExtraInfo& info, size_t paramsCnt); + DECLARE_DELAYED_SINGLETON(VendorInterface); + DISALLOW_COPY_AND_MOVE(VendorInterface); + ffrt::recursive_mutex processMutex_; + const char* GetFullVendorName(); + std::atomic_bool isInitialized_ = false; +}; +} // namespace V1_0 +} // namespace OffFind +} // namespace Nearlink +} // namespace HDI +} // namespace OHOS +#endif /* OHOS_HDI_NEARLINK_OFF_FIND_V1_0_VENDOR_INTERFACE_H */ \ No newline at end of file diff --git a/nearlink/off_find/hdi_service/off_find_interface_driver.cpp b/nearlink/off_find/hdi_service/off_find_interface_driver.cpp new file mode 100644 index 0000000000..4d7ee0d993 --- /dev/null +++ b/nearlink/off_find/hdi_service/off_find_interface_driver.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2026 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 +#include +#include +#include +#include "v1_0/off_find_interface_stub.h" + +#define HDF_LOG_TAG off_find_interface_driver + +using namespace OHOS::HDI::Nearlink::OffFind::V1_0; + +struct HdfOffFindInterfaceHost { + struct IDeviceIoService ioService; + OHOS::sptr stub; + HdfOffFindInterfaceHost() + { + ioService.object.objectId = 0; + ioService.Open = nullptr; + ioService.Release = nullptr; + ioService.Dispatch = nullptr; + } +}; + +static int32_t OffFindInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, + struct HdfSBuf *reply) +{ + auto *hdfOffFindInterfaceHost = CONTAINER_OF(client->device->service, struct HdfOffFindInterfaceHost, ioService); + + OHOS::MessageParcel *dataParcel = nullptr; + OHOS::MessageParcel *replyParcel = nullptr; + OHOS::MessageOption option; + + if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) { + HDF_LOGE("%{public}s: invalid data sbuf object to dispatch", __func__); + return HDF_ERR_INVALID_PARAM; + } + if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) { + HDF_LOGE("%{public}s: invalid reply sbuf object to dispatch", __func__); + return HDF_ERR_INVALID_PARAM; + } + + return hdfOffFindInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option); +} + +static int HdfOffFindInterfaceDriverInit(struct HdfDeviceObject *deviceObject) +{ + HDF_LOGI("%{public}s: driver init start", __func__); + return HDF_SUCCESS; +} + +static int HdfOffFindInterfaceDriverBind(struct HdfDeviceObject *deviceObject) +{ + HDF_LOGI("%{public}s: driver bind start", __func__); + auto *hdfOffFindInterfaceHost = new (std::nothrow) HdfOffFindInterfaceHost; + if (hdfOffFindInterfaceHost == nullptr) { + HDF_LOGE("%{public}s: failed to create create HdfOffFindInterfaceHost object", __func__); + return HDF_FAILURE; + } + + hdfOffFindInterfaceHost->ioService.Dispatch = OffFindInterfaceDriverDispatch; + hdfOffFindInterfaceHost->ioService.Open = NULL; + hdfOffFindInterfaceHost->ioService.Release = NULL; + + auto serviceImpl = OHOS::HDI::Nearlink::OffFind::V1_0::IOffFindInterface::Get(true); + if (serviceImpl == nullptr) { + HDF_LOGE("%{public}s: failed to get of implement service", __func__); + delete hdfOffFindInterfaceHost; + return HDF_FAILURE; + } + + hdfOffFindInterfaceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl, + OHOS::HDI::Nearlink::OffFind::V1_0::IOffFindInterface::GetDescriptor()); + if (hdfOffFindInterfaceHost->stub == nullptr) { + HDF_LOGE("%{public}s: failed to get stub object", __func__); + delete hdfOffFindInterfaceHost; + return HDF_FAILURE; + } + + deviceObject->service = &hdfOffFindInterfaceHost->ioService; + return HDF_SUCCESS; +} + +static void HdfOffFindInterfaceDriverRelease(struct HdfDeviceObject *deviceObject) +{ + HDF_LOGI("%{public}s: driver release start", __func__); + if (deviceObject->service == nullptr) { + return; + } + + auto *hdfOffFindInterfaceHost = CONTAINER_OF(deviceObject->service, struct HdfOffFindInterfaceHost, ioService); + if (hdfOffFindInterfaceHost != nullptr) { + delete hdfOffFindInterfaceHost; + } +} + +struct HdfDriverEntry g_offfindinterfaceDriverEntry = { + .moduleVersion = 1, + .moduleName = "off_find", + .Bind = HdfOffFindInterfaceDriverBind, + .Init = HdfOffFindInterfaceDriverInit, + .Release = HdfOffFindInterfaceDriverRelease, +}; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +HDF_INIT(g_offfindinterfaceDriverEntry); +#ifdef __cplusplus +} +#endif /* __cplusplus */ \ No newline at end of file diff --git a/nearlink/off_find/hdi_service/off_find_interface_impl.cpp b/nearlink/off_find/hdi_service/off_find_interface_impl.cpp new file mode 100644 index 0000000000..b5762fd00c --- /dev/null +++ b/nearlink/off_find/hdi_service/off_find_interface_impl.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2026 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 +#include +#include "off_find_log.h" +#include "vendor_interface.h" +#include "off_find_interface_impl.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace OffFind { +namespace V1_0 { +using VendorInterface = OHOS::HDI::Nearlink::OffFind::V1_0::VendorInterface; +const std::string OFF_FIND_FFRT_THREAD = "OffFindHdf"; + +extern "C" IOffFindInterface *OffFindInterfaceImplGetInstance(void) +{ + return new (std::nothrow) OffFindInterfaceImpl(); +} + + +OffFindInterfaceImpl::OffFindInterfaceImpl() +{ + remoteDeathRecipient_ = + new RemoteDeathRecipient(std::bind(&OffFindInterfaceImpl::OnRemoteDied, this, std::placeholders::_1)); + if (eventQueue_ != nullptr) { + HDF_LOGI("eventQueue already init"); + } else { + eventQueue_ = std::make_shared(OFF_FIND_FFRT_THREAD.c_str()); + HDF_LOGI("Create a new eventQueue, threadName:%{public}s", OFF_FIND_FFRT_THREAD.c_str()); + } +} + +OffFindInterfaceImpl::~OffFindInterfaceImpl() +{ + if (callbacks_ != nullptr) { + RemoveHciDeathRecipient(callbacks_); + callbacks_ = nullptr; + } + if (eventQueue_) { + eventQueue_.reset(); + } +} + +int32_t OffFindInterfaceImpl::SetReservedPower() +{ + HDF_LOGI("OffFindInterfaceImpl::SetReservedPower"); + auto func = []() { + HDF_LOGI("asyc SetReservedPower work start"); + VendorInterface::GetInstance()->SetReservedPower(); + }; + + if (eventQueue_ == nullptr) { + HDF_LOGE("eventQueue is nullptr!"); + return HDF_FAILURE; + } + eventQueue_->submit(func); + return HDF_SUCCESS; +} + +int32_t OffFindInterfaceImpl::EnableOffFind( + const sptr& callbackObj, + const std::vector& data, + const OHOS::HDI::Nearlink::OffFind::V1_0::OffFindExtraInfo& info) +{ + HDF_LOGI("OffFindInterfaceImpl::EnableOffFind"); + auto func = [callbackObj, data, info, this]() { + HDF_LOGI("Enter EnableOffFind"); + if (callbackObj == nullptr) { + HDF_LOGE("OffFindInterfaceImpl callbackObj null"); + return ; + } + VendorInterface::GetInstance()->RegisterClearOffFindCallback( + [this]() { + HDF_LOGI("clear callbacks is success !"); + if (callbacks_ != nullptr) { + RemoveHciDeathRecipient(callbacks_); + callbacks_ = nullptr; + } + } + ); + bool result = VendorInterface::GetInstance()->Initialize( + [callbackObj](int32_t result) {callbackObj->OnOffFindEnableResult(result); }, data, info); + if (result) { + callbacks_ = callbackObj; + AddHciDeathRecipient(callbacks_); + } + }; + if (eventQueue_ == nullptr) { + HDF_LOGE("eventQueue is nullptr!"); + return HDF_FAILURE; + } + eventQueue_->submit(func); + return HDF_SUCCESS; +} + +int32_t OffFindInterfaceImpl::DisableOffFind() +{ + HDF_LOGI("OffFindInterfaceImpl::DisableOffFind"); + auto func = []() { + HDF_LOGI("asyc disable work start"); + VendorInterface::GetInstance()->DisableOffFindMode(); + }; + + if (eventQueue_ == nullptr) { + HDF_LOGE("eventQueue is nullptr!"); + return HDF_FAILURE; + } + eventQueue_->submit(func); + VendorInterface::DestroyInstance(); + return HDF_SUCCESS; +} + +void OffFindInterfaceImpl::OnRemoteDied(const wptr &object) +{ + HDF_LOGI("OffFindInterfaceImpl"); + callbacks_ = nullptr; + VendorInterface::GetInstance()->CleanUp(); + VendorInterface::DestroyInstance(); +} + +int32_t OffFindInterfaceImpl::AddHciDeathRecipient(const sptr& callbackObj) +{ + HDF_LOGI("OffFindInterfaceImpl"); + const sptr& remote = OHOS::HDI::hdi_objcast(callbackObj); + if (!remote) { + HDF_LOGE("remote is nullptr"); + return HDF_FAILURE; + } + bool result = remote->AddDeathRecipient(remoteDeathRecipient_); + if (!result) { + HDF_LOGE("OffFindInterfaceImpl AddDeathRecipient fail"); + return HDF_FAILURE; + } + return HDF_SUCCESS; +} + +int32_t OffFindInterfaceImpl::RemoveHciDeathRecipient(const sptr& callbackObj) +{ + HDF_LOGI("OffFindInterfaceImpl"); + const sptr& remote = OHOS::HDI::hdi_objcast(callbackObj); + if (!remote) { + HDF_LOGE("remote is nullptr"); + return HDF_FAILURE; + } + bool result = remote->RemoveDeathRecipient(remoteDeathRecipient_); + if (!result) { + HDF_LOGE("OffFindInterfaceImpl RemoveDeathRecipient fail"); + return HDF_FAILURE; + } + return HDF_SUCCESS; +} + +} // V1_0 +} // OffFind +} // Nearlink +} // HDI +} // OHOS \ No newline at end of file diff --git a/nearlink/off_find/hdi_service/off_find_interface_impl.h b/nearlink/off_find/hdi_service/off_find_interface_impl.h new file mode 100644 index 0000000000..63714e32ba --- /dev/null +++ b/nearlink/off_find/hdi_service/off_find_interface_impl.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2026 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 OHOS_HDI_NEARLINK_OFF_FIND_V1_0_OFF_FINDINTERFACEIMPL_H +#define OHOS_HDI_NEARLINK_OFF_FIND_V1_0_OFF_FINDINTERFACEIMPL_H + +#include "v1_0/ioff_find_interface.h" +#include "v1_0/ioff_find_callback.h" +#include "remote_death_recipient.h" +#include "ffrt_inner.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace OffFind { +namespace V1_0 { +class OffFindInterfaceImpl : public OHOS::HDI::Nearlink::OffFind::V1_0::IOffFindInterface { +public: + OffFindInterfaceImpl(); + virtual ~OffFindInterfaceImpl(); + + int32_t SetReservedPower() override; + int32_t EnableOffFind(const sptr& callbackObj, + const std::vector& data, + const OHOS::HDI::Nearlink::OffFind::V1_0::OffFindExtraInfo& info) override; + + int32_t DisableOffFind() override; + +private: + void OnRemoteDied(const wptr &object); + sptr callbacks_ = nullptr; + sptr remoteDeathRecipient_ = nullptr; + int32_t AddHciDeathRecipient(const sptr& callbackObj); + int32_t RemoveHciDeathRecipient(const sptr& callbackObj); + std::shared_ptr eventQueue_ = nullptr; +}; +} // V1_0 +} // OffFind +} // Nearlink +} // HDI +} // OHOS + +#endif // OHOS_HDI_NEARLINK_OFF_FIND_V1_0_OffFindInterfaceImplE_H \ No newline at end of file diff --git a/nearlink/off_find/hdi_service/remote_death_recipient.h b/nearlink/off_find/hdi_service/remote_death_recipient.h new file mode 100644 index 0000000000..0f51e0ade7 --- /dev/null +++ b/nearlink/off_find/hdi_service/remote_death_recipient.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2026 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 OHOS_HDI_NEARLINK_OFF_FIND_V1_0_REMOTE_DEATH_RECIPIENT_H +#define OHOS_HDI_NEARLINK_OFF_FIND_V1_0_REMOTE_DEATH_RECIPIENT_H + +#include + +#include "iremote_object.h" +#include "refbase.h" + +namespace OHOS { +namespace HDI { +namespace Nearlink { +namespace OffFind { +namespace V1_0 { +class RemoteDeathRecipient : public IRemoteObject::DeathRecipient { +public: + explicit RemoteDeathRecipient(std::function &)> callback) + { + callback_ = callback; + } + ~RemoteDeathRecipient() + { + callback_ = nullptr; + } + + void OnRemoteDied(const wptr &object) + { + if (callback_ != nullptr) { + callback_(object); + } + } + +private: + std::function &)> callback_; +}; +} // namespace V1_0 +} // namespace OffFind +} // namespace Nearlink +} // namespace HDI +} // OHOS + +#endif // OHOS_HDI_NEARLINK_OFF_FIND_V1_0_REMOTE_DEATH_RECIPIENT_H