• 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 
16 #include "napi_async_work.h"
17 #include "bluetooth_errorcode.h"
18 #include "bluetooth_log.h"
19 #include "napi_async_callback.h"
20 #include "napi_bluetooth_utils.h"
21 #include "napi_timer.h"
22 #include "../parser/napi_parser_utils.h"
23 
24 namespace OHOS {
25 namespace Bluetooth {
CreateAsyncWork(napi_env env,napi_callback_info info,std::function<NapiAsyncWorkRet (void)> asyncWork,bool needCallback)26 std::shared_ptr<NapiAsyncWork> NapiAsyncWorkFactory::CreateAsyncWork(napi_env env, napi_callback_info info,
27     std::function<NapiAsyncWorkRet(void)> asyncWork, bool needCallback)
28 {
29     auto asyncCallback = NapiParseAsyncCallback(env, info);
30     if (!asyncCallback) {
31         HILOGE("asyncCallback is nullptr");
32         return nullptr;
33     }
34     auto napiAsyncWork = std::make_shared<NapiAsyncWork>(env, asyncWork, asyncCallback, needCallback);
35     return napiAsyncWork;
36 }
37 
Execute(void)38 void NapiAsyncWork::Info::Execute(void)
39 {
40     if (napiAsyncWork == nullptr) {
41         HILOGE("napiAsyncWork is nullptr");
42         errCode = BT_ERR_INTERNAL_ERROR;
43         object = nullptr;
44         return;
45     }
46     auto ret = napiAsyncWork->func_();
47     errCode = ret.errCode;
48     object = ret.object;
49 }
50 
Complete(void)51 void NapiAsyncWork::Info::Complete(void)
52 {
53     HILOGI("needCallback: %{public}d, errCode: %{public}d", needCallback, errCode);
54     if (napiAsyncWork == nullptr) {
55         HILOGE("napiAsyncWork is nullptr");
56         return;
57     }
58 
59     // need wait callback
60     if (needCallback && (errCode == BT_NO_ERROR)) {
61         if (napiAsyncWork->triggered_) {
62             HILOGE("NapiAsyncWork is triggered, Callback is earlier than Complete in thread scheduling");
63             return;
64         }
65         // start timer to avoid the callback is lost.
66         std::weak_ptr<NapiAsyncWork> asyncWorkWptr = napiAsyncWork;
67         auto func = [asyncWorkWptr]() {
68             auto asyncWorkSptr = asyncWorkWptr.lock();
69             if (asyncWorkSptr == nullptr) {
70                 HILOGE("asyncWorkSptr is nullptr");
71                 return;
72             }
73             asyncWorkSptr->TimeoutCallback();
74         };
75         NapiTimer::GetInstance()->Register(func, napiAsyncWork->timerId_);
76         return;
77     }
78 
79     if (object == nullptr) {
80         HILOGD("napi native object is nullptr");
81         object = std::make_shared<NapiNativeEmpty>();
82     }
83 
84     if (napiAsyncWork->napiAsyncCallback_) {
85         napiAsyncWork->triggered_ = true;
86         napiAsyncWork->napiAsyncCallback_->CallFunction(errCode, object);
87     }
88 }
89 
Run(void)90 void NapiAsyncWork::Run(void)
91 {
92     napi_value resource = nullptr;
93     napi_create_string_utf8(env_, "napiAsyncWork", NAPI_AUTO_LENGTH, &resource);
94 
95     NapiAsyncWork::Info *info = new NapiAsyncWork::Info();
96     info->needCallback = needCallback_.load();
97     info->napiAsyncWork = shared_from_this();
98 
99     napi_status status = napi_create_async_work(env_, nullptr, resource,
100         [](napi_env env, void* data) {
101             NapiAsyncWork::Info *info = static_cast<NapiAsyncWork::Info *>(data);
102             if (info == nullptr) {
103                 HILOGE("Async work info is nullptr");
104                 return;
105             }
106             info->Execute();
107         },
108         [](napi_env env, napi_status status, void* data) {
109             NapiAsyncWork::Info *info = static_cast<NapiAsyncWork::Info *>(data);
110             if (info == nullptr) {
111                 HILOGE("info is nullptr");
112                 return;
113             }
114             info->Complete();
115             napi_delete_async_work(env, info->asyncWork);
116             delete info;
117         },
118         static_cast<void *>(info), &info->asyncWork);
119     if (status != napi_ok) {
120         HILOGE("napi_create_async_work failed, status(%{public}d)", status);
121         delete info;
122         return;
123     }
124 
125     status = napi_queue_async_work(env_, info->asyncWork);
126     if (status != napi_ok) {
127         HILOGE("napi_queue_async_work failed, status(%{public}d)", status);
128         napi_delete_async_work(env_, info->asyncWork);
129         delete info;
130         return;
131     }
132 }
133 
TimeoutCallback(void)134 void NapiAsyncWork::TimeoutCallback(void)
135 {
136     HILOGI("enter");
137     CallFunction(BT_ERR_TIMEOUT, nullptr);
138 }
139 
CallFunction(int errCode,std::shared_ptr<NapiNativeObject> object)140 void NapiAsyncWork::CallFunction(int errCode, std::shared_ptr<NapiNativeObject> object)
141 {
142     if (!needCallback_.load()) {
143         HILOGE("Unsupported in no needCallback mode");
144         return;
145     }
146 
147     HILOGI("enter");
148     auto nativeObj = object;
149     if (nativeObj == nullptr) {
150         HILOGD("napi native object is nullptr");
151         nativeObj = std::make_shared<NapiNativeEmpty>();
152     }
153     // Check timer triggered & remove timer if supported
154     NapiTimer::GetInstance()->Unregister(timerId_);
155 
156     triggered_ = true;
157     auto func = [errCode, nativeObj, asyncWorkPtr = shared_from_this()]() {
158         if (asyncWorkPtr && asyncWorkPtr->napiAsyncCallback_) {
159             asyncWorkPtr->napiAsyncCallback_->CallFunction(errCode, nativeObj);
160         }
161     };
162     DoInJsMainThread(env_, std::move(func));
163 }
164 
GetRet(void)165 napi_value NapiAsyncWork::GetRet(void)
166 {
167     if (!napiAsyncCallback_) {
168         HILOGI("napiAsyncCallback_ is nullptr");
169         return NapiGetUndefinedRet(env_);
170     }
171     return napiAsyncCallback_->GetRet();
172 }
173 
AsyncWorkCallFunction(NapiAsyncWorkMap & map,NapiAsyncType type,std::shared_ptr<NapiNativeObject> nativeObject,int status)174 void AsyncWorkCallFunction(NapiAsyncWorkMap &map, NapiAsyncType type, std::shared_ptr<NapiNativeObject> nativeObject,
175     int status)
176 {
177     HILOGD("type: %{public}d", type);
178     auto asyncWork = map.Get(type);
179     if (!asyncWork) {
180         HILOGE("async work(%{public}d) is nullptr", type);
181         return;
182     }
183     map.Erase(type);
184 
185     asyncWork->CallFunction(status, nativeObject);
186 }
187 
TryPush(NapiAsyncType type,std::shared_ptr<NapiAsyncWork> asyncWork)188 bool NapiAsyncWorkMap::TryPush(NapiAsyncType type, std::shared_ptr<NapiAsyncWork> asyncWork)
189 {
190     if (!asyncWork) {
191         HILOGE("asyncWork is nullptr");
192         return false;
193     }
194 
195     std::lock_guard<std::mutex> lock(mutex_);
196     auto it = map_.find(type);
197     if (it != map_.end()) {
198         auto const &storedAsyncWork = it->second;
199         if (storedAsyncWork != nullptr && !storedAsyncWork->triggered_) {
200             HILOGE("Async work(%{public}d) hasn't been triggered", type);
201             return false;
202         }
203         HILOGI("Async work(%{public}d) hasn't been removed, but triggered, remove it", type);
204         map_.erase(it);
205     }
206 
207     map_[type] = std::move(asyncWork);
208     return true;
209 }
210 
Erase(NapiAsyncType type)211 void NapiAsyncWorkMap::Erase(NapiAsyncType type)
212 {
213     std::lock_guard<std::mutex> lock(mutex_);
214     map_.erase(type);
215 }
216 
Get(NapiAsyncType type)217 std::shared_ptr<NapiAsyncWork> NapiAsyncWorkMap::Get(NapiAsyncType type)
218 {
219     std::lock_guard<std::mutex> lock(mutex_);
220     auto it = map_.find(type);
221     return it != map_.end() ? it->second : nullptr;
222 }
223 
224 }  // namespace Bluetooth
225 }  // namespace OHOS