• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     ConnStateChangeParam stateChangeParam {
82         cb->deviceId_,
83         value,
84         false,
85         static_cast<int>(GattDisconnectReason::CONN_UNKNOWN),
86         static_cast<int>(ConnChangeCause::CONNECT_CHANGE_COMMON_CAUSE)
87     };
88     ConvertStateChangeParamToJS(cb->env_, result, stateChangeParam);
89     return result;
90 }
91 
CreateResult(const std::shared_ptr<BluetoothCallbackInfo> & cb,BluetoothOppTransferInformation & information)92 napi_value NapiEvent::CreateResult(const std::shared_ptr<BluetoothCallbackInfo> &cb,
93     BluetoothOppTransferInformation &information)
94 {
95     napi_value result = nullptr;
96     napi_create_object(cb->env_, &result);
97     ConvertOppTransferInformationToJS(cb->env_, result, information);
98     return result;
99 }
100 
101 // if callbackInfos contains specific type, new callbackInfo will cover the old.
102 // 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)103 void UpdateCallbackInfo(std::map<std::string, std::shared_ptr<BluetoothCallbackInfo>> callbackInfos,
104     const std::string &type)
105 {
106     auto it = callbackInfos.find(type);
107     if (it != callbackInfos.end() && it->second != nullptr) {
108         HILOGD("repetition type %{public}s is register, old callbackInfo will be deleted.", type.c_str());
109         // as long as the type is same, callbackInfo will be covered.
110         uint32_t refCount = INVALID_REF_COUNT;
111         napi_value handlerTemp = nullptr;
112         napi_status status = napi_get_reference_value(it->second->env_, it->second->callback_, &handlerTemp);
113         if (status != napi_ok) {
114             HILOGE("napi_get_reference_value failed. napi status is %{public}d", status);
115             return;
116         }
117         // if handlerTemp exist clear it. no exist, memory leak safe
118         if (handlerTemp != nullptr) {
119             HILOGD("napi_get_reference_value succeed");
120             napi_reference_unref(it->second->env_, it->second->callback_, &refCount);
121             HILOGD("decrements the refernce count, refCount: %{public}d", refCount);
122             // other place like EventNotify before use will add refCount, happen refCount != 0,
123             // ensure other place copy the prepare covered callbackInfo、add refCount and unref and delete refCount
124             if (refCount == 0) {
125                 HILOGD("delete the reference");
126                 napi_delete_reference(it->second->env_, it->second->callback_);
127             }
128             HILOGD("old %{public}s is deleted", type.c_str());
129         } else {
130             HILOGI("napi_get_reference_value is nullptr");
131         }
132     }
133 }
134 
OnEvent(napi_env env,napi_callback_info info,std::map<std::string,std::shared_ptr<BluetoothCallbackInfo>> & callbackInfos)135 napi_value NapiEvent::OnEvent(napi_env env, napi_callback_info info,
136     std::map<std::string, std::shared_ptr<BluetoothCallbackInfo>> &callbackInfos)
137 {
138     size_t expectedArgsCount = ARGS_SIZE_TWO;
139     size_t argc = expectedArgsCount;
140     napi_value argv[ARGS_SIZE_TWO] = {0};
141     napi_value thisVar = nullptr;
142 
143     napi_value ret = nullptr;
144     napi_get_undefined(env, &ret);
145 
146     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
147     if (argc != expectedArgsCount) {
148         HILOGE("Requires 2 argument.");
149         return ret;
150     }
151     std::string type;
152     if (!ParseString(env, type, argv[PARAM0])) {
153         HILOGE("string expected.");
154         return ret;
155     }
156     std::shared_ptr<BluetoothCallbackInfo> callbackInfo = std::make_shared<BluetoothCallbackInfo>();
157     callbackInfo->env_ = env;
158 
159     napi_valuetype valueType = napi_undefined;
160     napi_typeof(env, argv[PARAM1], &valueType);
161     if (valueType != napi_function) {
162         HILOGE("Wrong argument type. Function expected.");
163         return ret;
164     }
165 
166     UpdateCallbackInfo(callbackInfos, type);
167     napi_create_reference(env, argv[PARAM1], 1, &callbackInfo->callback_);
168     callbackInfos[type] = callbackInfo;
169     HILOGD("%{public}s is registered", type.c_str());
170     return ret;
171 }
172 
OffEvent(napi_env env,napi_callback_info info,std::map<std::string,std::shared_ptr<BluetoothCallbackInfo>> & callbackInfos)173 napi_value NapiEvent::OffEvent(napi_env env, napi_callback_info info,
174     std::map<std::string, std::shared_ptr<BluetoothCallbackInfo>> &callbackInfos)
175 {
176     size_t argc = ARGS_SIZE_ONE;
177     napi_value argv[ARGS_SIZE_TWO] = {0};
178     napi_value thisVar = nullptr;
179 
180     napi_value ret = nullptr;
181     napi_get_undefined(env, &ret);
182 
183     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
184     if (argc != ARGS_SIZE_ONE && argc != ARGS_SIZE_TWO) {
185         HILOGE("Requires 1 or 2 argument.");
186         return ret;
187     }
188     std::string type;
189     if (!ParseString(env, type, argv[PARAM0])) {
190         HILOGE("string expected.");
191         return ret;
192     }
193     auto it = callbackInfos.find(type);
194     if (it == callbackInfos.end() || it->second == nullptr) {
195         HILOGE("type %{public}s callbackInfos isn't exist.", type.c_str());
196         return ret;
197     }
198     if (env != it->second->env_) {
199         HILOGE("env doesn't match, please check.");
200         return ret;
201     }
202     napi_delete_reference(env, it->second->callback_);
203     it->second = nullptr;
204     HILOGI("%{public}s is unregistered", type.c_str());
205     return ret;
206 }
207 }  // namespace Bluetooth
208 }  // namespace OHOS