1 /*
2 * Copyright (C) 2025 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
16 #include "bluetooth_scan_result_callback_napi.h"
17
18 #include "ipc_object_stub.h"
19 #include "ipc_skeleton.h"
20 #include "js_native_api.h"
21 #include "message_option.h"
22 #include "message_parcel.h"
23 #include "napi/native_common.h"
24 #include "uv.h"
25
26 #include "constant_definition.h"
27 #include "napi_util.h"
28
29 namespace OHOS {
30 namespace Location {
31 static std::mutex g_regCallbackMutex;
32 static std::vector<napi_ref> g_registerCallbacks;
BluetoothScanResultCallbackNapi()33 BluetoothScanResultCallbackNapi::BluetoothScanResultCallbackNapi()
34 {
35 env_ = nullptr;
36 handlerCb_ = nullptr;
37 }
38
~BluetoothScanResultCallbackNapi()39 BluetoothScanResultCallbackNapi::~BluetoothScanResultCallbackNapi()
40 {
41 }
42
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)43 int BluetoothScanResultCallbackNapi::OnRemoteRequest(
44 uint32_t code, MessageParcel& data, MessageParcel& reply, MessageOption& option)
45 {
46 LBSLOGD(BLUETOOTH_CALLBACK, "BluetoothScanResultCallbackNapi::OnRemoteRequest!");
47 if (data.ReadInterfaceToken() != GetDescriptor()) {
48 LBSLOGE(BLUETOOTH_CALLBACK, "invalid token.");
49 return -1;
50 }
51 switch (code) {
52 case RECEIVE_INFO_EVENT: {
53 std::unique_ptr<BluetoothScanResult> res = BluetoothScanResult::Unmarshalling(data);
54 OnBluetoothScanResultChange(res);
55 break;
56 }
57 default: {
58 IPCObjectStub::OnRemoteRequest(code, data, reply, option);
59 break;
60 }
61 }
62 return 0;
63 }
64
GetEnv()65 napi_env BluetoothScanResultCallbackNapi::GetEnv()
66 {
67 std::unique_lock<std::mutex> guard(mutex_);
68 return env_;
69 }
70
SetEnv(const napi_env & env)71 void BluetoothScanResultCallbackNapi::SetEnv(const napi_env& env)
72 {
73 std::unique_lock<std::mutex> guard(mutex_);
74 env_ = env;
75 }
76
GetHandleCb()77 napi_ref BluetoothScanResultCallbackNapi::GetHandleCb()
78 {
79 std::unique_lock<std::mutex> guard(mutex_);
80 return handlerCb_;
81 }
82
SetHandleCb(const napi_ref & handlerCb)83 void BluetoothScanResultCallbackNapi::SetHandleCb(const napi_ref& handlerCb)
84 {
85 {
86 std::unique_lock<std::mutex> guard(mutex_);
87 handlerCb_ = handlerCb;
88 }
89 std::unique_lock<std::mutex> guard(g_regCallbackMutex);
90 g_registerCallbacks.emplace_back(handlerCb);
91 }
92
FindBlueToothCallback(napi_ref cb)93 bool FindBlueToothCallback(napi_ref cb)
94 {
95 std::unique_lock<std::mutex> guard(g_regCallbackMutex);
96 auto iter = std::find(g_registerCallbacks.begin(), g_registerCallbacks.end(), cb);
97 if (iter == g_registerCallbacks.end()) {
98 return false;
99 }
100 return true;
101 }
102
DeleteBlueToothCallback(napi_ref cb)103 void DeleteBlueToothCallback(napi_ref cb)
104 {
105 std::unique_lock<std::mutex> guard(g_regCallbackMutex);
106 for (auto iter = g_registerCallbacks.begin(); iter != g_registerCallbacks.end(); iter++) {
107 if (*iter == cb) {
108 iter = g_registerCallbacks.erase(iter);
109 break;
110 }
111 }
112 }
113
DoSendWork(uv_loop_s * & loop,uv_work_t * & work)114 void BluetoothScanResultCallbackNapi::DoSendWork(uv_loop_s*& loop, uv_work_t*& work)
115 {
116 uv_queue_work(loop, work, [](uv_work_t* work) {}, [](uv_work_t* work, int status) {
117 if (work == nullptr) {
118 return;
119 }
120 napi_handle_scope scope = nullptr;
121 auto context = static_cast<BluetoothScanResultAsyncContext*>(work->data);
122 if (context == nullptr) {
123 LBSLOGE(BLUETOOTH_CALLBACK, "context == nullptr");
124 delete work;
125 return;
126 }
127 if (context->env == nullptr || context->bluetoothScanResult == nullptr) {
128 LBSLOGE(BLUETOOTH_CALLBACK, "bluetoothScanResult == nullptr");
129 delete context;
130 delete work;
131 return;
132 }
133 if (!FindBlueToothCallback(context->callback[0])) {
134 LBSLOGE(BLUETOOTH_CALLBACK, "no valid callback");
135 delete context;
136 delete work;
137 return;
138 }
139 napi_open_handle_scope(context->env, &scope);
140 if (scope == nullptr) {
141 LBSLOGE(BLUETOOTH_CALLBACK, "scope == nullptr");
142 DELETE_SCOPE_CONTEXT_WORK(context->env, scope, context, work);
143 return;
144 }
145 napi_value jsEvent = nullptr;
146 CHK_NAPI_ERR_CLOSE_SCOPE(context->env, napi_create_object(context->env, &jsEvent), scope, context, work);
147 BluetoothScanResultToJs(context->env, context->bluetoothScanResult, jsEvent);
148 if (context->callback[0] != nullptr) {
149 napi_value undefine = nullptr;
150 napi_value handler = nullptr;
151 CHK_NAPI_ERR_CLOSE_SCOPE(context->env, napi_get_undefined(context->env, &undefine),
152 scope, context, work);
153 CHK_NAPI_ERR_CLOSE_SCOPE(context->env,
154 napi_get_reference_value(context->env, context->callback[0], &handler), scope, context, work);
155 if (napi_call_function(context->env, nullptr, handler, 1, &jsEvent, &undefine) != napi_ok) {
156 LBSLOGE(BLUETOOTH_CALLBACK, "Report location failed");
157 }
158 }
159 NAPI_CALL_RETURN_VOID(context->env, napi_close_handle_scope(context->env, scope));
160 delete context;
161 delete work;
162 });
163 }
164
OnBluetoothScanResultChange(const std::unique_ptr<BluetoothScanResult> & bluetoothScanResult)165 void BluetoothScanResultCallbackNapi::OnBluetoothScanResultChange(
166 const std::unique_ptr<BluetoothScanResult>& bluetoothScanResult)
167 {
168 std::unique_lock<std::mutex> guard(mutex_);
169 uv_loop_s *loop = nullptr;
170 if (env_ == nullptr) {
171 LBSLOGD(BLUETOOTH_CALLBACK, "env_ is nullptr.");
172 return;
173 }
174 if (handlerCb_ == nullptr) {
175 LBSLOGE(BLUETOOTH_CALLBACK, "handler is nullptr.");
176 return;
177 }
178 NAPI_CALL_RETURN_VOID(env_, napi_get_uv_event_loop(env_, &loop));
179 if (loop == nullptr) {
180 LBSLOGE(BLUETOOTH_CALLBACK, "loop == nullptr.");
181 return;
182 }
183 uv_work_t *work = new (std::nothrow) uv_work_t;
184 if (work == nullptr) {
185 LBSLOGE(BLUETOOTH_CALLBACK, "work == nullptr.");
186 return;
187 }
188 auto context = new (std::nothrow) BluetoothScanResultAsyncContext(env_);
189 if (context == nullptr) {
190 LBSLOGE(BLUETOOTH_CALLBACK, "context == nullptr.");
191 delete work;
192 return;
193 }
194 if (!InitContext(context)) {
195 LBSLOGE(BLUETOOTH_CALLBACK, "InitContext fail");
196 delete work;
197 delete context;
198 return;
199 }
200 context->bluetoothScanResult = std::make_unique<BluetoothScanResult>(*bluetoothScanResult);
201 work->data = context;
202 DoSendWork(loop, work);
203 }
204
DeleteHandler()205 void BluetoothScanResultCallbackNapi::DeleteHandler()
206 {
207 LBSLOGD(BLUETOOTH_CALLBACK, "before DeleteHandler");
208 std::unique_lock<std::mutex> guard(mutex_);
209 if (env_ == nullptr) {
210 LBSLOGE(BLUETOOTH_CALLBACK, "env is nullptr.");
211 return;
212 }
213 DeleteBlueToothCallback(handlerCb_);
214 if (handlerCb_ != nullptr) {
215 NAPI_CALL_RETURN_VOID(env_, napi_delete_reference(env_, handlerCb_));
216 handlerCb_ = nullptr;
217 }
218 }
219 } // namespace Location
220 } // namespace OHOS
221