1 /*
2 * Copyright (c) 2021 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
17 #include "app_log_wrapper.h"
18 #include "bundle_status_callback.h"
19
20 #include "napi/native_common.h"
21
BundleStatusCallback(napi_env env,napi_ref addedCallback,napi_ref updatedCallback,napi_ref removeCallback)22 BundleStatusCallback::BundleStatusCallback(napi_env env, napi_ref addedCallback,
23 napi_ref updatedCallback,
24 napi_ref removeCallback)
25 : env_(env), addedCallback_(addedCallback),
26 updatedCallback_(updatedCallback), removeCallback_(removeCallback) {}
27
~BundleStatusCallback()28 BundleStatusCallback::~BundleStatusCallback()
29 {
30 uv_loop_s* loop = nullptr;
31 napi_get_uv_event_loop(env_, &loop);
32 uv_work_t* work = new (std::nothrow) uv_work_t;
33 if (work == nullptr) {
34 ReleaseAll();
35 return;
36 }
37 DelRefCallbackInfo* delRefCallbackInfo = new (std::nothrow) DelRefCallbackInfo {
38 .env_ = env_,
39 .addedCallback_ = addedCallback_,
40 .updatedCallback_ = updatedCallback_,
41 .removeCallback_ = removeCallback_,
42 };
43 if (delRefCallbackInfo == nullptr) {
44 delete work;
45 ReleaseAll();
46 return;
47 }
48 work->data = reinterpret_cast<void*>(delRefCallbackInfo);
49 int ret = uv_queue_work(
50 loop, work, [](uv_work_t* work) { APP_LOGI("~BundleStatusCallback asyn work done"); },
51 [](uv_work_t* work, int status) {
52 // JS Thread
53 DelRefCallbackInfo* delRefCallbackInfo = reinterpret_cast<DelRefCallbackInfo*>(work->data);
54 if (delRefCallbackInfo == nullptr) {
55 return;
56 }
57 napi_delete_reference(delRefCallbackInfo->env_, delRefCallbackInfo->addedCallback_);
58 napi_delete_reference(delRefCallbackInfo->env_, delRefCallbackInfo->updatedCallback_);
59 napi_delete_reference(delRefCallbackInfo->env_, delRefCallbackInfo->removeCallback_);
60 delete delRefCallbackInfo;
61 delRefCallbackInfo = nullptr;
62 delete work;
63 work = nullptr;
64 });
65 if (ret != 0) {
66 delete delRefCallbackInfo;
67 delete work;
68 }
69 }
70
OnBundleAdded(const std::string & bundleName,const int userId)71 void BundleStatusCallback::OnBundleAdded(const std::string& bundleName, const int userId)
72 {
73 uv_loop_s* loop = nullptr;
74 napi_get_uv_event_loop(env_, &loop);
75 uv_work_t* work = new (std::nothrow) uv_work_t;
76 if (work == nullptr) {
77 APP_LOGW("BundleStatusCallback OnBundleAdded work is nullptr bundleName : %{public}s", bundleName.c_str());
78 return;
79 }
80 AsyncCallbackInfo* asyncCallbackInfo = new (std::nothrow)AsyncCallbackInfo {
81 .userId_ = userId,
82 .bundleName_ = bundleName,
83 .env_ = env_,
84 .callback_ = addedCallback_,
85 };
86 if (asyncCallbackInfo == nullptr) {
87 APP_LOGW("BundleStatusCallback OnBundleAdded asyncCallbackInfo is nullptr bundleName : %{public}s",
88 bundleName.c_str());
89 delete work;
90 return;
91 }
92 work->data = reinterpret_cast<void*>(asyncCallbackInfo);
93 if (loop == nullptr) {
94 APP_LOGW("BundleStatusCallback OnBundleAdded loop is nullptr bundleName : %{public}s", bundleName.c_str());
95 delete asyncCallbackInfo;
96 delete work;
97 return;
98 }
99 int ret = uv_queue_work(
100 loop, work, [](uv_work_t* work) { APP_LOGI("BundleStatusCallback OnBundleAdded asyn work done"); },
101 [](uv_work_t* work, int status) {
102 // JS Thread
103 APP_LOGI("BundleStatusCallback OnBundleAdded in JS Thread");
104 AsyncCallbackInfo* asyncCallbackInfo = reinterpret_cast<AsyncCallbackInfo*>(work->data);
105 if (asyncCallbackInfo == nullptr) {
106 APP_LOGE("asyncCallbackInfo is null");
107 return;
108 }
109 std::unique_ptr<AsyncCallbackInfo> callbackPtr {asyncCallbackInfo};
110 napi_handle_scope scope = nullptr;
111 napi_open_handle_scope(asyncCallbackInfo->env_, &scope);
112 if (scope == nullptr) {
113 APP_LOGE("scope is null");
114 return;
115 }
116 napi_value callback = nullptr;
117 napi_value placeHolder = nullptr;
118 napi_value result[2] = { 0 };
119 napi_get_reference_value(asyncCallbackInfo->env_, asyncCallbackInfo->callback_, &callback);
120 napi_create_string_utf8(
121 asyncCallbackInfo->env_, asyncCallbackInfo->bundleName_.c_str(), NAPI_AUTO_LENGTH, &result[0]);
122 napi_create_uint32(asyncCallbackInfo->env_, asyncCallbackInfo->userId_, &result[1]);
123 napi_call_function(
124 asyncCallbackInfo->env_, nullptr, callback, sizeof(result) / sizeof(result[0]), result, &placeHolder);
125 napi_close_handle_scope(asyncCallbackInfo->env_, scope);
126 if (work != nullptr) {
127 delete work;
128 work = nullptr;
129 }
130 });
131 if (ret != 0) {
132 APP_LOGE("OnBundleAdded failed due to call uv_queue_work failed");
133 delete asyncCallbackInfo;
134 delete work;
135 }
136 }
137
OnBundleUpdated(const std::string & bundleName,const int userId)138 void BundleStatusCallback::OnBundleUpdated(const std::string& bundleName, const int userId)
139 {
140 uv_loop_s* loop = nullptr;
141 napi_get_uv_event_loop(env_, &loop);
142 uv_work_t* work = new (std::nothrow) uv_work_t;
143 if (work == nullptr) {
144 APP_LOGW("BundleStatusCallback OnBundleUpdated work is nullptr bundleName : %{public}s", bundleName.c_str());
145 return;
146 }
147 AsyncCallbackInfo* asyncCallbackInfo = new (std::nothrow) AsyncCallbackInfo {
148 .userId_ = userId,
149 .bundleName_ = bundleName,
150 .env_ = env_,
151 .callback_ = updatedCallback_,
152 };
153 if (asyncCallbackInfo == nullptr) {
154 APP_LOGW("BundleStatusCallback OnBundleUpdated asyncCallbackInfo is nullptr bundleName : %{public}s",
155 bundleName.c_str());
156 delete work;
157 return;
158 }
159 work->data = reinterpret_cast<void*>(asyncCallbackInfo);
160 if (loop == nullptr) {
161 APP_LOGW("BundleStatusCallback OnBundleUpdated loop is nullptr bundleName : %{public}s", bundleName.c_str());
162 delete asyncCallbackInfo;
163 delete work;
164 return;
165 }
166 int ret = uv_queue_work(
167 loop, work, [](uv_work_t* work) { APP_LOGI("BundleStatusCallback OnBundleUpdated asyn work done"); },
168 [](uv_work_t* work, int status) {
169 APP_LOGI("BundleStatusCallback OnBundleUpdated in JS Thread");
170 AsyncCallbackInfo* asyncCallbackInfo = reinterpret_cast<AsyncCallbackInfo*>(work->data);
171 if (asyncCallbackInfo == nullptr) {
172 APP_LOGE("asyncCallbackInfo is null");
173 return;
174 }
175 std::unique_ptr<AsyncCallbackInfo> callbackPtr {asyncCallbackInfo};
176 napi_handle_scope scope = nullptr;
177 napi_open_handle_scope(asyncCallbackInfo->env_, &scope);
178 if (scope == nullptr) {
179 APP_LOGE("scope is null");
180 return;
181 }
182 napi_value callback = nullptr;
183 napi_value placeHolder = nullptr;
184 napi_value result[2] = { 0 };
185 napi_get_reference_value(asyncCallbackInfo->env_, asyncCallbackInfo->callback_, &callback);
186 napi_create_string_utf8(
187 asyncCallbackInfo->env_, asyncCallbackInfo->bundleName_.c_str(), NAPI_AUTO_LENGTH, &result[0]);
188 napi_create_uint32(asyncCallbackInfo->env_, asyncCallbackInfo->userId_, &result[1]);
189 napi_call_function(
190 asyncCallbackInfo->env_, nullptr, callback, sizeof(result) / sizeof(result[0]), result, &placeHolder);
191 napi_close_handle_scope(asyncCallbackInfo->env_, scope);
192 if (work != nullptr) {
193 delete work;
194 work = nullptr;
195 }
196 });
197 if (ret != 0) {
198 APP_LOGE("OnBundleUpdated failed due to call uv_queue_work failed");
199 if (asyncCallbackInfo != nullptr) {
200 delete asyncCallbackInfo;
201 }
202 if (work != nullptr) {
203 delete work;
204 }
205 }
206 }
207
OnBundleRemoved(const std::string & bundleName,const int userId)208 void BundleStatusCallback::OnBundleRemoved(const std::string& bundleName, const int userId)
209 {
210 uv_loop_s* loop = nullptr;
211 napi_get_uv_event_loop(env_, &loop);
212 uv_work_t* work = new (std::nothrow) uv_work_t;
213 if (work == nullptr) {
214 APP_LOGW("BundleStatusCallback OnBundleRemoved work is nullptr bundleName : %{public}s", bundleName.c_str());
215 return;
216 }
217 AsyncCallbackInfo* asyncCallbackInfo = new (std::nothrow) AsyncCallbackInfo {
218 .userId_ = userId,
219 .bundleName_ = bundleName,
220 .env_ = env_,
221 .callback_ = removeCallback_,
222 };
223 if (asyncCallbackInfo == nullptr) {
224 APP_LOGW("BundleStatusCallback OnBundleUpdated asyncCallbackInfo is nullptr bundleName : %{public}s",
225 bundleName.c_str());
226 delete work;
227 return;
228 }
229 work->data = reinterpret_cast<void*>(asyncCallbackInfo);
230 if (loop == nullptr) {
231 APP_LOGW("BundleStatusCallback OnBundleRemoved loop is nullptr bundleName : %{public}s", bundleName.c_str());
232 delete asyncCallbackInfo;
233 delete work;
234 return;
235 }
236 int ret = uv_queue_work(
237 loop, work, [](uv_work_t* work) { APP_LOGI("BundleStatusCallback OnBundleRemoved asyn work done"); },
238 [](uv_work_t* work, int status) {
239 APP_LOGI("BundleStatusCallback OnBundleRemoved in JS Thread");
240 // JS Thread
241 AsyncCallbackInfo* asyncCallbackInfo = reinterpret_cast<AsyncCallbackInfo*>(work->data);
242 if (asyncCallbackInfo == nullptr) {
243 APP_LOGE("asyncCallbackInfo is null");
244 return;
245 }
246 std::unique_ptr<AsyncCallbackInfo> callbackPtr {asyncCallbackInfo};
247 napi_handle_scope scope = nullptr;
248 napi_open_handle_scope(asyncCallbackInfo->env_, &scope);
249 if (scope == nullptr) {
250 APP_LOGE("scope is null");
251 return;
252 }
253 napi_value callback = nullptr;
254 napi_value placeHolder = nullptr;
255 napi_value result[2] = { 0 };
256 napi_get_reference_value(asyncCallbackInfo->env_, asyncCallbackInfo->callback_, &callback);
257 napi_create_string_utf8(
258 asyncCallbackInfo->env_, asyncCallbackInfo->bundleName_.c_str(), NAPI_AUTO_LENGTH, &result[0]);
259 napi_create_uint32(asyncCallbackInfo->env_, asyncCallbackInfo->userId_, &result[1]);
260 napi_call_function(
261 asyncCallbackInfo->env_, nullptr, callback, sizeof(result) / sizeof(result[0]), result, &placeHolder);
262 napi_close_handle_scope(asyncCallbackInfo->env_, scope);
263 if (work != nullptr) {
264 delete work;
265 work = nullptr;
266 }
267 });
268 if (ret != 0) {
269 APP_LOGE("OnBundleRemoved failed due to call uv_queue_work failed");
270 delete asyncCallbackInfo;
271 delete work;
272 }
273 }
274
ReleaseAll()275 void BundleStatusCallback::ReleaseAll()
276 {
277 napi_delete_reference(env_, removeCallback_);
278 removeCallback_ = nullptr;
279 napi_delete_reference(env_, updatedCallback_);
280 updatedCallback_ = nullptr;
281 napi_delete_reference(env_, addedCallback_);
282 addedCallback_ = nullptr;
283 }