1 /*
2 * Copyright (C) 2022 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 #ifndef LOG_TAG
16 #define LOG_TAG "bt_napi_event"
17 #endif
18
19 #include <uv.h>
20 #include "bluetooth_utils.h"
21 #include "napi_bluetooth_ble_utils.h"
22 #include "napi_bluetooth_event.h"
23
24 namespace OHOS {
25 namespace Bluetooth {
EventNotify(AsyncEventData * asyncEvent)26 void NapiEvent::EventNotify(AsyncEventData *asyncEvent)
27 {
28 uv_loop_s *loop = nullptr;
29 napi_get_uv_event_loop(asyncEvent->env_, &loop);
30
31 uv_work_t *work = new uv_work_t;
32 if (work == nullptr) {
33 HILOGI("uv_work_t work is null.");
34 delete asyncEvent;
35 asyncEvent = nullptr;
36 return;
37 }
38 work->data = asyncEvent;
39
40 int ret = uv_queue_work(
41 loop,
42 work,
43 [](uv_work_t *work) {},
44 [](uv_work_t *work, int status) {
45 AsyncEventData *callbackInfo = static_cast<AsyncEventData*>(work->data);
46 napi_value callback = nullptr;
47 napi_status ret = napi_get_reference_value(callbackInfo->env_, callbackInfo->callback_, &callback);
48 if (ret == napi_ok && callback != nullptr) {
49 napi_value result = nullptr;
50 napi_value undefined = nullptr;
51 napi_value callResult = nullptr;
52 if (napi_get_undefined(callbackInfo->env_, &undefined) == napi_ok) {
53 result = callbackInfo->packResult();
54 }
55 if (result != nullptr) {
56 napi_call_function(callbackInfo->env_, undefined, callback, ARGS_SIZE_ONE,
57 &result, &callResult);
58 }
59 }
60 delete callbackInfo;
61 delete work;
62 work = nullptr;
63 }
64 );
65 if (ret != 0) {
66 delete asyncEvent;
67 asyncEvent = nullptr;
68 delete work;
69 work = nullptr;
70 }
71 }
72
CreateResult(const std::shared_ptr<BluetoothCallbackInfo> & cb,int value)73 napi_value NapiEvent::CreateResult(const std::shared_ptr<BluetoothCallbackInfo> &cb, int value)
74 {
75 napi_value result = nullptr;
76 if (cb == nullptr) {
77 HILOGE("CreateResult cb is null!");
78 return result;
79 }
80 napi_create_object(cb->env_, &result);
81 ConvertStateChangeParamToJS(cb->env_, result, cb->deviceId_, value,
82 static_cast<int>(ConnChangeCause::CONNECT_CHANGE_COMMON_CAUSE));
83 return result;
84 }
85
CreateResult(const std::shared_ptr<BluetoothCallbackInfo> & cb,BluetoothOppTransferInformation & information)86 napi_value NapiEvent::CreateResult(const std::shared_ptr<BluetoothCallbackInfo> &cb,
87 BluetoothOppTransferInformation &information)
88 {
89 napi_value result = nullptr;
90 napi_create_object(cb->env_, &result);
91 ConvertOppTransferInformationToJS(cb->env_, result, information);
92 return result;
93 }
94
95 // if callbackInfos contains specific type, new callbackInfo will cover the old.
96 // If exist, covered event happen, this function will clear rest reference of old callbackInfo in napi framework.
UpdateCallbackInfo(std::map<std::string,std::shared_ptr<BluetoothCallbackInfo>> callbackInfos,const std::string & type)97 void UpdateCallbackInfo(std::map<std::string, std::shared_ptr<BluetoothCallbackInfo>> callbackInfos,
98 const std::string &type)
99 {
100 auto it = callbackInfos.find(type);
101 if (it != callbackInfos.end() && it->second != nullptr) {
102 HILOGD("repetition type %{public}s is register, old callbackInfo will be deleted.", type.c_str());
103 // as long as the type is same, callbackInfo will be covered.
104 uint32_t refCount = INVALID_REF_COUNT;
105 napi_value handlerTemp = nullptr;
106 napi_status status = napi_get_reference_value(it->second->env_, it->second->callback_, &handlerTemp);
107 if (status != napi_ok) {
108 HILOGE("napi_get_reference_value failed. napi status is %{public}d", status);
109 return;
110 }
111 // if handlerTemp exist clear it. no exist, memory leak safe
112 if (handlerTemp != nullptr) {
113 HILOGD("napi_get_reference_value succeed");
114 napi_reference_unref(it->second->env_, it->second->callback_, &refCount);
115 HILOGD("decrements the refernce count, refCount: %{public}d", refCount);
116 // other place like EventNotify before use will add refCount, happen refCount != 0,
117 // ensure other place copy the prepare covered callbackInfo、add refCount and unref and delete refCount
118 if (refCount == 0) {
119 HILOGD("delete the reference");
120 napi_delete_reference(it->second->env_, it->second->callback_);
121 }
122 HILOGD("old %{public}s is deleted", type.c_str());
123 } else {
124 HILOGI("napi_get_reference_value is nullptr");
125 }
126 }
127 }
128
OnEvent(napi_env env,napi_callback_info info,std::map<std::string,std::shared_ptr<BluetoothCallbackInfo>> & callbackInfos)129 napi_value NapiEvent::OnEvent(napi_env env, napi_callback_info info,
130 std::map<std::string, std::shared_ptr<BluetoothCallbackInfo>> &callbackInfos)
131 {
132 size_t expectedArgsCount = ARGS_SIZE_TWO;
133 size_t argc = expectedArgsCount;
134 napi_value argv[ARGS_SIZE_TWO] = {0};
135 napi_value thisVar = nullptr;
136
137 napi_value ret = nullptr;
138 napi_get_undefined(env, &ret);
139
140 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
141 if (argc != expectedArgsCount) {
142 HILOGE("Requires 2 argument.");
143 return ret;
144 }
145 std::string type;
146 if (!ParseString(env, type, argv[PARAM0])) {
147 HILOGE("string expected.");
148 return ret;
149 }
150 std::shared_ptr<BluetoothCallbackInfo> callbackInfo = std::make_shared<BluetoothCallbackInfo>();
151 callbackInfo->env_ = env;
152
153 napi_valuetype valueType = napi_undefined;
154 napi_typeof(env, argv[PARAM1], &valueType);
155 if (valueType != napi_function) {
156 HILOGE("Wrong argument type. Function expected.");
157 return ret;
158 }
159
160 UpdateCallbackInfo(callbackInfos, type);
161 napi_create_reference(env, argv[PARAM1], 1, &callbackInfo->callback_);
162 callbackInfos[type] = callbackInfo;
163 HILOGD("%{public}s is registered", type.c_str());
164 return ret;
165 }
166
OffEvent(napi_env env,napi_callback_info info,std::map<std::string,std::shared_ptr<BluetoothCallbackInfo>> & callbackInfos)167 napi_value NapiEvent::OffEvent(napi_env env, napi_callback_info info,
168 std::map<std::string, std::shared_ptr<BluetoothCallbackInfo>> &callbackInfos)
169 {
170 size_t argc = ARGS_SIZE_ONE;
171 napi_value argv[ARGS_SIZE_TWO] = {0};
172 napi_value thisVar = nullptr;
173
174 napi_value ret = nullptr;
175 napi_get_undefined(env, &ret);
176
177 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
178 if (argc != ARGS_SIZE_ONE && argc != ARGS_SIZE_TWO) {
179 HILOGE("Requires 1 or 2 argument.");
180 return ret;
181 }
182 std::string type;
183 if (!ParseString(env, type, argv[PARAM0])) {
184 HILOGE("string expected.");
185 return ret;
186 }
187 auto it = callbackInfos.find(type);
188 if (it == callbackInfos.end() || it->second == nullptr) {
189 HILOGE("type %{public}s callbackInfos isn't exist.", type.c_str());
190 return ret;
191 }
192 if (env != it->second->env_) {
193 HILOGE("env doesn't match, please check.");
194 return ret;
195 }
196 napi_delete_reference(env, it->second->callback_);
197 it->second = nullptr;
198 HILOGI("%{public}s is unregistered", type.c_str());
199 return ret;
200 }
201 } // namespace Bluetooth
202 } // namespace OHOS