1 /*
2 * Copyright (c) 2023-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 "js_free_install_observer.h"
17
18 #include "hilog_tag_wrapper.h"
19 #include "hitrace_meter.h"
20 #include "js_error_utils.h"
21 #include "js_runtime.h"
22 #include "js_runtime_utils.h"
23 #include "napi/native_api.h"
24
25 namespace OHOS {
26 namespace AbilityRuntime {
JsFreeInstallObserver(napi_env env)27 JsFreeInstallObserver::JsFreeInstallObserver(napi_env env) : env_(env) {}
28
29 JsFreeInstallObserver::~JsFreeInstallObserver() = default;
30
OnInstallFinished(const std::string & bundleName,const std::string & abilityName,const std::string & startTime,const int & resultCode)31 void JsFreeInstallObserver::OnInstallFinished(const std::string &bundleName, const std::string &abilityName,
32 const std::string &startTime, const int &resultCode)
33 {
34 TAG_LOGD(AAFwkTag::FREE_INSTALL, "call");
35 wptr<JsFreeInstallObserver> jsObserver = this;
36 std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback>
37 ([jsObserver, bundleName, abilityName, startTime, resultCode](napi_env env, NapiAsyncTask &task,
38 int32_t status) {
39 sptr<JsFreeInstallObserver> jsObserverSptr = jsObserver.promote();
40 if (jsObserverSptr) {
41 jsObserverSptr->HandleOnInstallFinished(bundleName, abilityName, startTime, resultCode);
42 }
43 });
44 napi_ref callback = nullptr;
45 std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
46 NapiAsyncTask::Schedule("JsFreeInstallObserver::OnInstallFinished", env_, std::make_unique<NapiAsyncTask>(callback,
47 std::move(execute), std::move(complete)));
48 }
49
OnInstallFinishedByUrl(const std::string & startTime,const std::string & url,const int & resultCode)50 void JsFreeInstallObserver::OnInstallFinishedByUrl(const std::string &startTime, const std::string& url,
51 const int &resultCode)
52 {
53 TAG_LOGD(AAFwkTag::FREE_INSTALL, "call");
54 wptr<JsFreeInstallObserver> jsObserver = this;
55 std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback>
56 ([jsObserver, startTime, url, resultCode](napi_env env, NapiAsyncTask &task,
57 int32_t status) {
58 sptr<JsFreeInstallObserver> jsObserverSptr = jsObserver.promote();
59 if (jsObserverSptr) {
60 jsObserverSptr->HandleOnInstallFinishedByUrl(startTime, url, resultCode);
61 }
62 });
63 napi_ref callback = nullptr;
64 std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
65 NapiAsyncTask::Schedule("JsFreeInstallObserver::OnInstallFinished", env_, std::make_unique<NapiAsyncTask>(callback,
66 std::move(execute), std::move(complete)));
67 }
68
OnInstallFinished(const std::string & bundleName,const std::string & abilityName,const std::string & startTime,napi_value abilityResult)69 void JsFreeInstallObserver::OnInstallFinished(const std::string &bundleName, const std::string &abilityName,
70 const std::string &startTime, napi_value abilityResult)
71 {
72 TAG_LOGD(AAFwkTag::FREE_INSTALL, "call");
73 std::vector<napi_deferred> promises;
74 std::vector<napi_ref> callbacks;
75 {
76 std::unique_lock<std::mutex> lock(jsObserverObjectListLock_);
77 for (auto it = jsObserverObjectList_.begin(); it != jsObserverObjectList_.end();) {
78 if ((it->bundleName != bundleName) || (it->abilityName != abilityName) || (it->startTime != startTime)) {
79 it++;
80 continue;
81 }
82 if (it->callback == nullptr && it->deferred == nullptr) {
83 it++;
84 continue;
85 }
86 if (!it->isAbilityResult) {
87 it++;
88 continue;
89 }
90 if (it->deferred != nullptr) {
91 promises.emplace_back(it->deferred);
92 } else {
93 callbacks.emplace_back(it->callback);
94 }
95 it = jsObserverObjectList_.erase(it);
96 TAG_LOGD(AAFwkTag::FREE_INSTALL,
97 "jsObserverObjectList_ size:%{public}zu", jsObserverObjectList_.size());
98 }
99 }
100
101 for (const napi_deferred& promise : promises) {
102 CallPromise(promise, abilityResult);
103 FinishAsyncTrace(HITRACE_TAG_ABILITY_MANAGER, "StartFreeInstall", atoi(startTime.c_str()));
104 }
105 for (const napi_ref& callback : callbacks) {
106 CallCallback(callback, abilityResult);
107 FinishAsyncTrace(HITRACE_TAG_ABILITY_MANAGER, "StartFreeInstall", atoi(startTime.c_str()));
108 }
109 }
110
HandleOnInstallFinished(const std::string & bundleName,const std::string & abilityName,const std::string & startTime,const int & resultCode)111 void JsFreeInstallObserver::HandleOnInstallFinished(const std::string &bundleName, const std::string &abilityName,
112 const std::string &startTime, const int &resultCode)
113 {
114 TAG_LOGD(AAFwkTag::FREE_INSTALL, "call");
115 std::vector<napi_deferred> promises;
116 std::vector<napi_ref> callbacks;
117 {
118 std::unique_lock<std::mutex> lock(jsObserverObjectListLock_);
119 for (auto it = jsObserverObjectList_.begin(); it != jsObserverObjectList_.end();) {
120 if ((it->bundleName != bundleName) || (it->abilityName != abilityName) || (it->startTime != startTime)) {
121 it++;
122 continue;
123 }
124 if (it->callback == nullptr && it->deferred == nullptr) {
125 it++;
126 continue;
127 }
128 if (it->isAbilityResult && resultCode == ERR_OK) {
129 it++;
130 continue;
131 }
132 if (it->deferred != nullptr) {
133 promises.emplace_back(it->deferred);
134 } else {
135 callbacks.emplace_back(it->callback);
136 }
137 it = jsObserverObjectList_.erase(it);
138 }
139 }
140
141 for (const napi_deferred& promise : promises) {
142 CallPromise(promise, resultCode);
143 FinishAsyncTrace(HITRACE_TAG_ABILITY_MANAGER, "StartFreeInstall", atoi(startTime.c_str()));
144 }
145 for (const napi_ref& callback : callbacks) {
146 CallCallback(callback, resultCode);
147 FinishAsyncTrace(HITRACE_TAG_ABILITY_MANAGER, "StartFreeInstall", atoi(startTime.c_str()));
148 }
149 }
150
HandleOnInstallFinishedByUrl(const std::string & startTime,const std::string & url,const int & resultCode)151 void JsFreeInstallObserver::HandleOnInstallFinishedByUrl(const std::string &startTime, const std::string& url,
152 const int &resultCode)
153 {
154 TAG_LOGD(AAFwkTag::FREE_INSTALL, "call");
155 std::vector<napi_deferred> promises;
156 std::vector<napi_ref> callbacks;
157 {
158 std::unique_lock<std::mutex> lock(jsObserverObjectListLock_);
159 for (auto it = jsObserverObjectList_.begin(); it != jsObserverObjectList_.end();) {
160 if ((it->startTime != startTime) || (it->url != url)) {
161 it++;
162 continue;
163 }
164 if (it->callback == nullptr && it->deferred == nullptr) {
165 it++;
166 continue;
167 }
168 if (it->isAbilityResult && resultCode == ERR_OK) {
169 it++;
170 continue;
171 }
172 if (it->deferred != nullptr) {
173 promises.emplace_back(it->deferred);
174 } else {
175 callbacks.emplace_back(it->callback);
176 }
177 it = jsObserverObjectList_.erase(it);
178 }
179 }
180
181 for (const napi_deferred& promise : promises) {
182 CallPromise(promise, resultCode);
183 FinishAsyncTrace(HITRACE_TAG_ABILITY_MANAGER, "StartFreeInstall", atoi(startTime.c_str()));
184 }
185 for (const napi_ref& callback : callbacks) {
186 CallCallback(callback, resultCode);
187 FinishAsyncTrace(HITRACE_TAG_ABILITY_MANAGER, "StartFreeInstall", atoi(startTime.c_str()));
188 }
189 }
190
CallCallback(napi_ref callback,int32_t resultCode)191 void JsFreeInstallObserver::CallCallback(napi_ref callback, int32_t resultCode)
192 {
193 TAG_LOGD(AAFwkTag::FREE_INSTALL, "call");
194 if (callback == nullptr) {
195 TAG_LOGE(AAFwkTag::FREE_INSTALL, "callback is nullptr.");
196 return;
197 }
198 napi_value value;
199 if (resultCode == ERR_OK) {
200 value = CreateJsUndefined(env_);
201 } else {
202 value = CreateJsError(env_, GetJsErrorCodeByNativeError(resultCode));
203 }
204 napi_value argv[] = { value };
205 napi_value func = nullptr;
206 napi_get_reference_value(env_, callback, &func);
207 napi_call_function(env_, CreateJsUndefined(env_), func, ArraySize(argv), argv, nullptr);
208 }
209
CallCallback(napi_ref callback,napi_value abilityResult)210 void JsFreeInstallObserver::CallCallback(napi_ref callback, napi_value abilityResult)
211 {
212 TAG_LOGD(AAFwkTag::FREE_INSTALL, "call");
213 if (callback == nullptr) {
214 TAG_LOGE(AAFwkTag::FREE_INSTALL, "callback is nullptr");
215 return;
216 }
217 napi_value argv[] = {
218 CreateJsError(env_, 0),
219 abilityResult,
220 };
221 napi_value func = nullptr;
222 napi_get_reference_value(env_, callback, &func);
223 napi_call_function(env_, CreateJsUndefined(env_), func, ArraySize(argv), argv, nullptr);
224 }
225
CallPromise(napi_deferred deferred,int32_t resultCode)226 void JsFreeInstallObserver::CallPromise(napi_deferred deferred, int32_t resultCode)
227 {
228 if (deferred == nullptr) {
229 TAG_LOGE(AAFwkTag::FREE_INSTALL, "deferred is nullptr");
230 return;
231 }
232 if (resultCode == ERR_OK) {
233 napi_value value = CreateJsUndefined(env_);
234 napi_resolve_deferred(env_, deferred, value);
235 } else {
236 napi_value error = CreateJsError(env_, GetJsErrorCodeByNativeError(resultCode));
237 napi_reject_deferred(env_, deferred, error);
238 }
239 }
240
CallPromise(napi_deferred deferred,napi_value abilityResult)241 void JsFreeInstallObserver::CallPromise(napi_deferred deferred, napi_value abilityResult)
242 {
243 if (deferred == nullptr) {
244 TAG_LOGE(AAFwkTag::FREE_INSTALL, "deferred is nullptr");
245 return;
246 }
247 napi_resolve_deferred(env_, deferred, abilityResult);
248 }
249
AddJsObserverObject(const std::string & bundleName,const std::string & abilityName,const std::string & startTime,napi_value jsObserverObject,napi_value * result,bool isAbilityResult)250 void JsFreeInstallObserver::AddJsObserverObject(const std::string &bundleName, const std::string &abilityName,
251 const std::string &startTime, napi_value jsObserverObject, napi_value* result, bool isAbilityResult)
252 {
253 TAG_LOGD(AAFwkTag::FREE_INSTALL, "call");
254 {
255 std::unique_lock<std::mutex> lock(jsObserverObjectListLock_);
256 for (auto it = jsObserverObjectList_.begin(); it != jsObserverObjectList_.end(); ++it) {
257 if (it->bundleName == bundleName && it->abilityName == abilityName &&
258 it->startTime == startTime) {
259 TAG_LOGW(AAFwkTag::FREE_INSTALL, "The jsObject has been added");
260 return;
261 }
262 }
263 }
264
265 StartAsyncTrace(HITRACE_TAG_ABILITY_MANAGER, "StartFreeInstall", atoi(startTime.c_str()));
266 JsFreeInstallObserverObject object;
267 object.bundleName = bundleName;
268 object.abilityName = abilityName;
269 object.startTime = startTime;
270 AddJsObserverCommon(object, jsObserverObject, result, isAbilityResult);
271 }
272
AddJsObserverObject(const std::string & startTime,const std::string & url,napi_value jsObserverObject,napi_value * result,bool isAbilityResult)273 void JsFreeInstallObserver::AddJsObserverObject(const std::string &startTime, const std::string &url,
274 napi_value jsObserverObject, napi_value* result, bool isAbilityResult)
275 {
276 TAG_LOGD(AAFwkTag::FREE_INSTALL, "call");
277 {
278 std::unique_lock<std::mutex> lock(jsObserverObjectListLock_);
279 for (auto it = jsObserverObjectList_.begin(); it != jsObserverObjectList_.end(); ++it) {
280 if (it->startTime == startTime && it->url == url) {
281 TAG_LOGW(AAFwkTag::FREE_INSTALL, "The jsObject has been added");
282 return;
283 }
284 }
285 }
286
287 StartAsyncTrace(HITRACE_TAG_ABILITY_MANAGER, "StartFreeInstall", atoi(startTime.c_str()));
288 JsFreeInstallObserverObject object;
289 object.startTime = startTime;
290 object.url = url;
291 AddJsObserverCommon(object, jsObserverObject, result, isAbilityResult);
292 }
293
AddJsObserverCommon(JsFreeInstallObserverObject & object,napi_value jsObserverObject,napi_value * result,bool isAbilityResult)294 void JsFreeInstallObserver::AddJsObserverCommon(JsFreeInstallObserverObject &object,
295 napi_value jsObserverObject, napi_value* result, bool isAbilityResult)
296 {
297 TAG_LOGD(AAFwkTag::FREE_INSTALL, "call");
298 object.isAbilityResult = isAbilityResult;
299 napi_valuetype type = napi_undefined;
300 napi_typeof(env_, jsObserverObject, &type);
301 if (jsObserverObject == nullptr || type != napi_function) {
302 napi_deferred deferred;
303 napi_create_promise(env_, &deferred, result);
304 object.deferred = deferred;
305 object.callback = nullptr;
306 } else {
307 napi_ref ref = nullptr;
308 napi_get_undefined(env_, result);
309 napi_create_reference(env_, jsObserverObject, 1, &ref);
310 object.deferred = nullptr;
311 object.callback = ref;
312 }
313 std::unique_lock<std::mutex> lock(jsObserverObjectListLock_);
314 jsObserverObjectList_.emplace_back(object);
315 }
316 } // namespace AbilityRuntime
317 } // namespace OHOS