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