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