• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "napi_bluetooth_gatt_server.h"
16 #include "bluetooth_errorcode.h"
17 #include "bluetooth_gatt_service.h"
18 #include "bluetooth_host.h"
19 #include "bluetooth_log.h"
20 #include "bluetooth_utils.h"
21 #include "napi_bluetooth_ble.h"
22 #include "napi_bluetooth_ble_utils.h"
23 #include "napi_bluetooth_error.h"
24 #include "napi_bluetooth_utils.h"
25 #include "../parser/napi_parser_utils.h"
26 
27 namespace OHOS {
28 namespace Bluetooth {
29 using namespace std;
30 
31 std::vector<std::string> NapiGattServer::deviceList;
32 thread_local napi_ref NapiGattServer::consRef_ = nullptr;
33 
CreateGattServer(napi_env env,napi_callback_info info)34 napi_value NapiGattServer::CreateGattServer(napi_env env, napi_callback_info info)
35 {
36     HILOGI("enter");
37     napi_value result;
38     napi_value constructor = nullptr;
39     napi_get_reference_value(env, consRef_, &constructor);
40     napi_new_instance(env, constructor, 0, nullptr, &result);
41 
42     return result;
43 }
44 
DefineGattServerJSClass(napi_env env)45 void NapiGattServer::DefineGattServerJSClass(napi_env env)
46 {
47     napi_property_descriptor gattserverDesc[] = {
48 #ifdef BLUETOOTH_API_SINCE_10
49         DECLARE_NAPI_FUNCTION("notifyCharacteristicChanged", NotifyCharacteristicChangedEx),
50 #else
51         DECLARE_NAPI_FUNCTION("startAdvertising", StartAdvertising),
52         DECLARE_NAPI_FUNCTION("stopAdvertising", StopAdvertising),
53         DECLARE_NAPI_FUNCTION("notifyCharacteristicChanged", NotifyCharacteristicChanged),
54 #endif
55         DECLARE_NAPI_FUNCTION("addService", AddService),
56         DECLARE_NAPI_FUNCTION("removeService", RemoveGattService),
57         DECLARE_NAPI_FUNCTION("close", Close),
58         DECLARE_NAPI_FUNCTION("sendResponse", SendResponse),
59         DECLARE_NAPI_FUNCTION("on", On),
60         DECLARE_NAPI_FUNCTION("off", Off),
61     };
62 
63     napi_value constructor = nullptr;
64     napi_define_class(env, "GattServer", NAPI_AUTO_LENGTH, GattServerConstructor, nullptr,
65         sizeof(gattserverDesc) / sizeof(gattserverDesc[0]), gattserverDesc, &constructor);
66     napi_create_reference(env, constructor, 1, &consRef_);
67 }
68 
GattServerConstructor(napi_env env,napi_callback_info info)69 napi_value NapiGattServer::GattServerConstructor(napi_env env, napi_callback_info info)
70 {
71     napi_value thisVar = nullptr;
72     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
73     NapiGattServer* gattServer = new NapiGattServer();
74 
75     napi_wrap(
76         env, thisVar, gattServer,
77         [](napi_env env, void* data, void* hint) {
78             NapiGattServer* server = static_cast<NapiGattServer*>(data);
79             if (server) {
80                 delete server;
81                 server = nullptr;
82             }
83         },
84         nullptr,
85         nullptr);
86 
87     return thisVar;
88 }
89 
NapiGetGattServer(napi_env env,napi_value thisVar)90 static NapiGattServer *NapiGetGattServer(napi_env env, napi_value thisVar)
91 {
92     NapiGattServer *gattServer = nullptr;
93     auto status = napi_unwrap(env, thisVar, (void **)&gattServer);
94     if (status != napi_ok) {
95         return nullptr;
96     }
97     return gattServer;
98 }
99 
CheckGattsOn(napi_env env,napi_callback_info info)100 napi_status CheckGattsOn(napi_env env, napi_callback_info info)
101 {
102     size_t argc = ARGS_SIZE_TWO;
103     napi_value argv[ARGS_SIZE_TWO] = {nullptr};
104     napi_value thisVar = nullptr;
105     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
106     NAPI_BT_RETURN_IF(argc != ARGS_SIZE_TWO, "Requires 2 arguments.", napi_invalid_arg);
107 
108     std::string type {};
109     NAPI_BT_CALL_RETURN(NapiParseString(env, argv[PARAM0], type));
110     std::shared_ptr<BluetoothCallbackInfo> callbackInfo {nullptr};
111 
112     if (type == STR_BT_GATT_SERVER_CALLBACK_CHARACTERISTIC_READ ||
113         type == STR_BT_GATT_SERVER_CALLBACK_CHARACTERISTIC_WRITE) {
114         callbackInfo = std::make_shared<GattCharacteristicCallbackInfo>();
115     } else if (type == STR_BT_GATT_SERVER_CALLBACK_DESCRIPTOR_WRITE ||
116         type == STR_BT_GATT_SERVER_CALLBACK_DESCRIPTOR_READ) {
117         callbackInfo = std::make_shared<GattDescriptorCallbackInfo>();
118     } else {
119         callbackInfo = std::make_shared<BluetoothCallbackInfo>();
120     }
121     callbackInfo->env_ = env;
122 
123     auto gattServer = NapiGetGattServer(env, thisVar);
124     NAPI_BT_RETURN_IF(gattServer == nullptr, "gattServer is nullptr.", napi_invalid_arg);
125 
126     NAPI_BT_CALL_RETURN(NapiIsFunction(env, argv[PARAM1]));
127     NAPI_BT_CALL_RETURN(napi_create_reference(env, argv[PARAM1], 1, &callbackInfo->callback_));
128     gattServer->GetCallback().SetCallbackInfo(type, callbackInfo);
129     HILOGI("%{public}s is registered", type.c_str());
130     return napi_ok;
131 }
132 
On(napi_env env,napi_callback_info info)133 napi_value NapiGattServer::On(napi_env env, napi_callback_info info)
134 {
135     HILOGI("enter");
136     auto status = CheckGattsOn(env, info);
137     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
138     return NapiGetUndefinedRet(env);
139 }
140 
CheckGattsOff(napi_env env,napi_callback_info info)141 napi_status CheckGattsOff(napi_env env, napi_callback_info info)
142 {
143     size_t argc = ARGS_SIZE_TWO;
144     napi_value argv[ARGS_SIZE_TWO] = {nullptr};  // argv[PARAM1] is not used.
145     napi_value thisVar = nullptr;
146     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
147     NAPI_BT_RETURN_IF(argc != ARGS_SIZE_ONE && argc != ARGS_SIZE_TWO, "Requires 1 or 2 arguments.", napi_invalid_arg);
148 
149     std::string type {};
150     NAPI_BT_CALL_RETURN(NapiParseString(env, argv[PARAM0], type));
151 
152     auto gattServer = NapiGetGattServer(env, thisVar);
153     NAPI_BT_RETURN_IF(gattServer == nullptr, "gattServer is nullptr.", napi_invalid_arg);
154     // callback_ need unref before, see napi_bluetooth_gatt_client
155     auto &gattServerCallback = gattServer->GetCallback();
156     gattServerCallback.SetCallbackInfo(type, nullptr);
157     HILOGI("%{public}s is removed", type.c_str());
158     return napi_ok;
159 }
160 
Off(napi_env env,napi_callback_info info)161 napi_value NapiGattServer::Off(napi_env env, napi_callback_info info)
162 {
163     HILOGI("enter");
164     auto status = CheckGattsOff(env, info);
165     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
166     return NapiGetUndefinedRet(env);
167 }
168 
CheckGattsAddService(napi_env env,napi_callback_info info,std::shared_ptr<GattServer> & outServer,std::unique_ptr<GattService> & outService)169 static napi_status CheckGattsAddService(napi_env env, napi_callback_info info, std::shared_ptr<GattServer> &outServer,
170     std::unique_ptr<GattService> &outService)
171 {
172     size_t argc = ARGS_SIZE_ONE;
173     napi_value argv[ARGS_SIZE_ONE] = {nullptr};
174     napi_value thisVar = nullptr;
175     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
176     NAPI_BT_RETURN_IF(argc != ARGS_SIZE_ONE, "Requires 1 arguments.", napi_invalid_arg);
177 
178     // std::unique_ptr<GattService> service {nullptr};
179     NapiGattService napiGattService;
180     NAPI_BT_CALL_RETURN(NapiParseGattService(env, argv[PARAM0], napiGattService));
181 
182     NapiGattServer *gattServer = NapiGetGattServer(env, thisVar);
183     NAPI_BT_RETURN_IF(gattServer == nullptr, "gattServer is nullptr.", napi_invalid_arg);
184     outServer = gattServer->GetServer();
185 
186     GattServiceType type = napiGattService.isPrimary ? GattServiceType::PRIMARY : GattServiceType::SECONDARY;
187     outService = std::make_unique<GattService>(napiGattService.serviceUuid, type);
188     for (const auto &napiCharacter : napiGattService.characteristics) {
189         int charPermissions = napiCharacter.permissions;
190         int charProperties = napiCharacter.properties;
191         GattCharacteristic character(napiCharacter.characteristicUuid, charPermissions, charProperties);
192         character.SetValue(napiCharacter.characteristicValue.data(), napiCharacter.characteristicValue.size());
193 
194         for (const auto &napiDescriptor : napiCharacter.descriptors) {
195             GattDescriptor descriptor(napiDescriptor.descriptorUuid, napiDescriptor.permissions);
196             descriptor.SetValue(napiDescriptor.descriptorValue.data(), napiDescriptor.descriptorValue.size());
197             character.AddDescriptor(descriptor);
198         }
199         outService->AddCharacteristic(character);
200     }
201 
202     return napi_ok;
203 }
204 
AddService(napi_env env,napi_callback_info info)205 napi_value NapiGattServer::AddService(napi_env env, napi_callback_info info)
206 {
207     HILOGI("enter");
208     std::shared_ptr<GattServer> server {nullptr};
209     std::unique_ptr<GattService> gattService {nullptr};
210     auto status = CheckGattsAddService(env, info, server, gattService);
211     NAPI_BT_ASSERT_RETURN_FALSE(env, (status == napi_ok && server != nullptr), BT_ERR_INVALID_PARAM);
212 
213     int ret = server->AddService(*gattService);
214     NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
215     return NapiGetBooleanTrue(env);
216 }
217 
CheckGattsClose(napi_env env,napi_callback_info info,std::shared_ptr<GattServer> & outServer)218 static napi_status CheckGattsClose(napi_env env, napi_callback_info info, std::shared_ptr<GattServer> &outServer)
219 {
220     size_t argc = 0;
221     napi_value thisVar = nullptr;
222     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, nullptr, &thisVar, NULL));
223     NAPI_BT_RETURN_IF(argc > 0, "no needed arguments.", napi_invalid_arg);
224     NapiGattServer *gattServer = NapiGetGattServer(env, thisVar);
225     NAPI_BT_RETURN_IF(gattServer == nullptr, "gattServer is nullptr.", napi_invalid_arg);
226 
227     outServer = gattServer->GetServer();
228     return napi_ok;
229 }
230 
Close(napi_env env,napi_callback_info info)231 napi_value NapiGattServer::Close(napi_env env, napi_callback_info info)
232 {
233     HILOGI("enter");
234     std::shared_ptr<GattServer> server {nullptr};
235     auto status = CheckGattsClose(env, info, server);
236     NAPI_BT_ASSERT_RETURN_UNDEF(env, (status == napi_ok && server != nullptr), BT_ERR_INVALID_PARAM);
237 
238     int ret = server->Close();
239     NAPI_BT_ASSERT_RETURN_UNDEF(env, ret == BT_NO_ERROR, ret);
240     return NapiGetUndefinedRet(env);
241 }
242 
CheckGattsRemoveService(napi_env env,napi_callback_info info,std::shared_ptr<GattServer> & outServer,UUID & outUuid)243 static napi_status CheckGattsRemoveService(napi_env env, napi_callback_info info,
244     std::shared_ptr<GattServer> &outServer, UUID &outUuid)
245 {
246     size_t argc = 1;
247     napi_value argv[1] = {nullptr};
248     napi_value thisVar = nullptr;
249     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
250     NAPI_BT_RETURN_IF(argc != 1, "Requires 1 arguments.", napi_invalid_arg);
251 
252     std::string uuid {};
253     NAPI_BT_CALL_RETURN(NapiParseUuid(env, argv[0], uuid));
254 
255     NapiGattServer *gattServer = NapiGetGattServer(env, thisVar);
256     NAPI_BT_RETURN_IF(gattServer == nullptr, "gattServer is nullptr.", napi_invalid_arg);
257     outServer = gattServer->GetServer();
258     outUuid = UUID::FromString(uuid);
259     return napi_ok;
260 }
261 
RemoveGattService(napi_env env,napi_callback_info info)262 napi_value NapiGattServer::RemoveGattService(napi_env env, napi_callback_info info)
263 {
264     HILOGI("enter");
265     std::shared_ptr<GattServer> server {nullptr};
266     UUID serviceUuid;
267     auto status = CheckGattsRemoveService(env, info, server, serviceUuid);
268     NAPI_BT_ASSERT_RETURN_FALSE(env, (status == napi_ok && server != nullptr), BT_ERR_INVALID_PARAM);
269 
270     int ret = BT_ERR_INTERNAL_ERROR;
271     auto primaryService = server->GetService(serviceUuid, true);
272     if (primaryService.has_value()) {
273         ret = server->RemoveGattService(*primaryService);
274         NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
275     }
276     auto secondService = server->GetService(serviceUuid, false);
277     if (secondService.has_value()) {
278         ret = server->RemoveGattService(*secondService);
279         NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
280     }
281     NAPI_BT_ASSERT_RETURN_FALSE(env, (primaryService.has_value() || secondService.has_value()), BT_ERR_INVALID_PARAM);
282     return NapiGetBooleanRet(env, ret == BT_NO_ERROR);
283 }
284 
CheckGattsSendRsp(napi_env env,napi_callback_info info,std::shared_ptr<GattServer> & outServer,NapiGattsServerResponse & outRsp)285 static napi_status CheckGattsSendRsp(napi_env env, napi_callback_info info, std::shared_ptr<GattServer> &outServer,
286     NapiGattsServerResponse &outRsp)
287 {
288     size_t argc = 1;
289     napi_value argv[1] = {nullptr};
290     napi_value thisVar = nullptr;
291     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
292     NAPI_BT_RETURN_IF(argc != 1, "Requires 1 arguments.", napi_invalid_arg);
293 
294     NapiGattsServerResponse rsp;
295     NAPI_BT_CALL_RETURN(NapiParseGattsServerResponse(env, argv[0], rsp));
296 
297     NapiGattServer *gattServer = NapiGetGattServer(env, thisVar);
298     NAPI_BT_RETURN_IF(gattServer == nullptr, "gattServer is nullptr.", napi_invalid_arg);
299     outServer = gattServer->GetServer();
300     outRsp = std::move(rsp);
301     return napi_ok;
302 }
303 
SendResponse(napi_env env,napi_callback_info info)304 napi_value NapiGattServer::SendResponse(napi_env env, napi_callback_info info)
305 {
306     HILOGI("enter");
307     std::shared_ptr<GattServer> server {nullptr};
308     NapiGattsServerResponse rsp;
309     auto status = CheckGattsSendRsp(env, info, server, rsp);
310     NAPI_BT_ASSERT_RETURN_FALSE(env, (status == napi_ok && server != nullptr), BT_ERR_INVALID_PARAM);
311 
312     BluetoothRemoteDevice remoteDevice(rsp.deviceId, BTTransport::ADAPTER_BLE);
313     HILOGI("Remote device address: %{public}s", GET_ENCRYPT_ADDR(remoteDevice));
314     int ret = server->SendResponse(remoteDevice, rsp.transId, rsp.status, rsp.offset, rsp.value.data(),
315         static_cast<int>(rsp.value.size()));
316     NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
317     return NapiGetBooleanTrue(env);
318 }
319 
GetGattCharacteristic(const std::shared_ptr<GattServer> & server,const UUID & serviceUuid,const UUID & characterUuid)320 static GattCharacteristic *GetGattCharacteristic(const std::shared_ptr<GattServer> &server, const UUID &serviceUuid,
321     const UUID &characterUuid)
322 {
323     auto service = server->GetService(serviceUuid, true);
324     if (!service.has_value()) {
325         service = server->GetService(serviceUuid, false);
326     }
327     if (!service.has_value()) {
328         HILOGE("not found service uuid: %{public}s", serviceUuid.ToString().c_str());
329         return nullptr;
330     }
331     GattCharacteristic *character = service.value().get().GetCharacteristic(characterUuid);
332     return character;
333 }
334 
335 #ifdef BLUETOOTH_API_SINCE_10
CheckNotifyCharacteristicChangedEx(napi_env env,napi_callback_info info,NapiGattServer ** outServer,std::string & outDeviceId,NapiNotifyCharacteristic & outCharacter)336 static napi_status CheckNotifyCharacteristicChangedEx(napi_env env, napi_callback_info info,
337     NapiGattServer **outServer, std::string &outDeviceId, NapiNotifyCharacteristic &outCharacter)
338 {
339     size_t argc = ARGS_SIZE_THREE;
340     napi_value argv[ARGS_SIZE_THREE] = {0};
341     napi_value thisVar = nullptr;
342     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
343     NAPI_BT_RETURN_IF(argc != ARGS_SIZE_TWO && argc != ARGS_SIZE_THREE, "Requires 2 or 3 arguments.", napi_invalid_arg);
344 
345     std::string deviceId {};
346     NapiNotifyCharacteristic character;
347     NAPI_BT_CALL_RETURN(NapiParseBdAddr(env, argv[PARAM0], deviceId));
348     NAPI_BT_CALL_RETURN(NapiParseNotifyCharacteristic(env, argv[PARAM1], character));
349 
350     NapiGattServer *gattServer = NapiGetGattServer(env, thisVar);
351     NAPI_BT_RETURN_IF(gattServer == nullptr || outServer ==nullptr, "gattServer is nullptr.", napi_invalid_arg);
352     *outServer = gattServer;
353     outDeviceId = std::move(deviceId);
354     outCharacter = std::move(character);
355     return napi_ok;
356 }
357 
NotifyCharacteristicChangedEx(napi_env env,napi_callback_info info)358 napi_value NapiGattServer::NotifyCharacteristicChangedEx(napi_env env, napi_callback_info info)
359 {
360     HILOGI("enter");
361     NapiGattServer* napiServer = nullptr;
362     std::string deviceId {};
363     NapiNotifyCharacteristic notifyCharacter;
364     auto status = CheckNotifyCharacteristicChangedEx(env, info, &napiServer, deviceId, notifyCharacter);
365     NAPI_BT_ASSERT_RETURN_FALSE(env, (status == napi_ok && napiServer && napiServer->GetServer()),
366         BT_ERR_INVALID_PARAM);
367 
368     auto func = [server = napiServer->GetServer(), notifyCharacter, deviceId]() {
369         int ret = BT_ERR_INTERNAL_ERROR;
370         auto character = GetGattCharacteristic(server, notifyCharacter.serviceUuid, notifyCharacter.characterUuid);
371         if (character == nullptr) {
372             HILOGI("character is null!");
373             return NapiAsyncWorkRet(ret);
374         }
375         character->SetValue(notifyCharacter.characterValue.data(), notifyCharacter.characterValue.size());
376         BluetoothRemoteDevice remoteDevice(deviceId, BTTransport::ADAPTER_BLE);
377         ret = server->NotifyCharacteristicChanged(remoteDevice, *character, notifyCharacter.confirm);
378         return NapiAsyncWorkRet(ret);
379     };
380     auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NEED_CALLBACK);
381     NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
382 
383     bool success = napiServer->GetCallback().asyncWorkMap_.TryPush(NapiAsyncType::GATT_SERVER_NOTIFY_CHARACTERISTIC,
384         asyncWork);
385     NAPI_BT_ASSERT_RETURN_UNDEF(env, success, BT_ERR_INTERNAL_ERROR);
386 
387     asyncWork->Run();
388     return asyncWork->GetRet();
389 }
390 #else
CheckGattsNotify(napi_env env,napi_callback_info info,std::shared_ptr<GattServer> & outServer,std::string & outDeviceId,NapiNotifyCharacteristic & outCharacter)391 static napi_status CheckGattsNotify(napi_env env, napi_callback_info info, std::shared_ptr<GattServer> &outServer,
392     std::string &outDeviceId, NapiNotifyCharacteristic &outCharacter)
393 {
394     size_t argc = ARGS_SIZE_TWO;
395     napi_value argv[ARGS_SIZE_TWO] = {nullptr};
396     napi_value thisVar = nullptr;
397     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
398     NAPI_BT_RETURN_IF(argc != ARGS_SIZE_TWO, "Requires 2 arguments.", napi_invalid_arg);
399 
400     std::string deviceId {};
401     NapiNotifyCharacteristic character;
402     NAPI_BT_CALL_RETURN(NapiParseBdAddr(env, argv[PARAM0], deviceId));
403     NAPI_BT_CALL_RETURN(NapiParseNotifyCharacteristic(env, argv[PARAM1], character));
404 
405     NapiGattServer *gattServer = NapiGetGattServer(env, thisVar);
406     NAPI_BT_RETURN_IF(gattServer == nullptr, "gattServer is nullptr.", napi_invalid_arg);
407     outServer = gattServer->GetServer();
408     outDeviceId = std::move(deviceId);
409     outCharacter = std::move(character);
410     return napi_ok;
411 }
412 
NotifyCharacteristicChanged(napi_env env,napi_callback_info info)413 napi_value NapiGattServer::NotifyCharacteristicChanged(napi_env env, napi_callback_info info)
414 {
415     HILOGI("enter");
416     std::shared_ptr<GattServer> server {nullptr};
417     std::string deviceId {};
418     NapiNotifyCharacteristic notifyCharacter;
419     auto status = CheckGattsNotify(env, info, server, deviceId, notifyCharacter);
420     NAPI_BT_ASSERT_RETURN_FALSE(env, (status == napi_ok && server != nullptr), BT_ERR_INVALID_PARAM);
421 
422     auto character = GetGattCharacteristic(server, notifyCharacter.serviceUuid, notifyCharacter.characterUuid);
423     NAPI_BT_ASSERT_RETURN_FALSE(env, character != nullptr, BT_ERR_INVALID_PARAM);
424     character->SetValue(notifyCharacter.characterValue.data(), notifyCharacter.characterValue.size());
425 
426     BluetoothRemoteDevice remoteDevice(deviceId, BTTransport::ADAPTER_BLE);
427     int ret = server->NotifyCharacteristicChanged(remoteDevice, *character, notifyCharacter.confirm);
428     NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
429     return NapiGetBooleanTrue(env);
430 }
431 #endif
432 } // namespace Bluetooth
433 } // namespace OHOS
434