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