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