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 "js_backgroundtask_subscriber.h"
17 #include "continuous_task_log.h"
18 #include "js_runtime_utils.h"
19 #include "iservice_registry.h"
20 #include "system_ability_definition.h"
21
22 namespace OHOS {
23 namespace BackgroundTaskMgr {
24 using namespace OHOS::AbilityRuntime;
25
JsBackgroudTaskSystemAbilityStatusChange(std::shared_ptr<JsBackgroundTaskSubscriber> subscriber)26 JsBackgroundTaskSubscriber::JsBackgroudTaskSystemAbilityStatusChange::JsBackgroudTaskSystemAbilityStatusChange(
27 std::shared_ptr<JsBackgroundTaskSubscriber> subscriber) : subscriber_(subscriber)
28 {
29 BGTASK_LOGD("JsBackgroudTaskSystemAbilityStatusChange constructor");
30 }
31
~JsBackgroudTaskSystemAbilityStatusChange()32 JsBackgroundTaskSubscriber::JsBackgroudTaskSystemAbilityStatusChange::~JsBackgroudTaskSystemAbilityStatusChange()
33 {
34 BGTASK_LOGD("~JsBackgroudTaskSystemAbilityStatusChange");
35 }
36
OnAddSystemAbility(int32_t systemAbilityId,const std::string & deviceId)37 void JsBackgroundTaskSubscriber::JsBackgroudTaskSystemAbilityStatusChange::OnAddSystemAbility(
38 int32_t systemAbilityId, const std::string& deviceId)
39 {
40 BGTASK_LOGI("JsBackgroudTaskSystemAbilityStatusChange::OnAddSystemAbility");
41 if (systemAbilityId != BACKGROUND_TASK_MANAGER_SERVICE_ID) {
42 return;
43 }
44 auto subscriber = subscriber_.lock();
45 if (subscriber == nullptr) {
46 return;
47 }
48 if (!subscriber->needRestoreSubscribeStatus_) {
49 return;
50 }
51 ErrCode errCode = BackgroundTaskMgrHelper::SubscribeBackgroundTask(*subscriber);
52 if (errCode) {
53 BGTASK_LOGE("restore SubscribeBackgroundTask error");
54 } else {
55 BGTASK_LOGI("restore SubscribeBackgroundTask ok");
56 }
57 subscriber->needRestoreSubscribeStatus_ = false;
58 }
59
OnRemoveSystemAbility(int32_t systemAbilityId,const std::string & deviceId)60 void JsBackgroundTaskSubscriber::JsBackgroudTaskSystemAbilityStatusChange::OnRemoveSystemAbility(
61 int32_t systemAbilityId, const std::string& deviceId)
62 {
63 if (systemAbilityId != BACKGROUND_TASK_MANAGER_SERVICE_ID) {
64 return;
65 }
66 BGTASK_LOGI("JsBackgroudTaskSystemAbilityStatusChange::OnRemoveSystemAbility");
67 auto subscriber = subscriber_.lock();
68 if (subscriber == nullptr) {
69 return;
70 }
71 if (!subscriber->IsEmpty()) {
72 subscriber->needRestoreSubscribeStatus_ = true;
73 BGTASK_LOGI("subscriber is not empty, need to restore");
74 } else {
75 BGTASK_LOGI("subscriber is empty, no need to restore");
76 }
77 }
78
JsBackgroundTaskSubscriber(napi_env env)79 JsBackgroundTaskSubscriber::JsBackgroundTaskSubscriber(napi_env env) : env_(env)
80 {
81 BGTASK_LOGD("JsBackgroundTaskSubscriber constructor");
82 }
83
~JsBackgroundTaskSubscriber()84 JsBackgroundTaskSubscriber::~JsBackgroundTaskSubscriber()
85 {
86 BGTASK_LOGD("~JsBackgroundTaskSubscriber");
87 }
88
SubscriberBgtaskSaStatusChange()89 void JsBackgroundTaskSubscriber::SubscriberBgtaskSaStatusChange()
90 {
91 if (jsSaListner_ != nullptr) {
92 return;
93 }
94 sptr<ISystemAbilityManager> systemManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
95 if (!systemManager) {
96 BGTASK_LOGI("ResSchedClient::Fail to get sa mgr client.");
97 return;
98 }
99 jsSaListner_ = new (std::nothrow) JsBackgroudTaskSystemAbilityStatusChange(shared_from_this());
100 if (jsSaListner_ == nullptr) {
101 BGTASK_LOGI("jsSaListner_ null");
102 return;
103 }
104 int32_t ret = systemManager->SubscribeSystemAbility(BACKGROUND_TASK_MANAGER_SERVICE_ID, jsSaListner_);
105 if (ret != ERR_OK) {
106 BGTASK_LOGI("sBackgroundTaskSubscriber::InitSaStatusListener error");
107 jsSaListner_ = nullptr;
108 }
109 BGTASK_LOGI("JsBackgroundTaskSubscriber::InitSaStatusListener ok");
110 }
111
UnSubscriberBgtaskSaStatusChange()112 void JsBackgroundTaskSubscriber::UnSubscriberBgtaskSaStatusChange()
113 {
114 if (jsSaListner_ == nullptr) {
115 return;
116 }
117 sptr<ISystemAbilityManager> systemManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
118 if (!systemManager) {
119 BGTASK_LOGE("GetSystemAbilityManager error");
120 return;
121 }
122 int32_t ret = systemManager->UnSubscribeSystemAbility(BACKGROUND_TASK_MANAGER_SERVICE_ID, jsSaListner_);
123 if (ret != ERR_OK) {
124 BGTASK_LOGE("UnSubscribeSystemAbility error");
125 } else {
126 BGTASK_LOGI("UnSubscribeSystemAbility ok");
127 }
128 jsSaListner_ = nullptr;
129 }
130
OnContinuousTaskStop(const std::shared_ptr<ContinuousTaskCallbackInfo> & continuousTaskCallbackInfo)131 void JsBackgroundTaskSubscriber::OnContinuousTaskStop(
132 const std::shared_ptr<ContinuousTaskCallbackInfo> &continuousTaskCallbackInfo)
133 {
134 BGTASK_LOGI("OnContinuousTaskStop abilityname %{public}s continuousTaskId %{public}d cancelReason %{public}d",
135 continuousTaskCallbackInfo->GetAbilityName().c_str(),
136 continuousTaskCallbackInfo->GetContinuousTaskId(),
137 continuousTaskCallbackInfo->GetCancelReason());
138 std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback>(
139 [self = weak_from_this(), continuousTaskCallbackInfo](napi_env env, NapiAsyncTask &task, int32_t status) {
140 auto jsObserver = self.lock();
141 if (jsObserver == nullptr) {
142 BGTASK_LOGE("null observer");
143 return;
144 }
145 BGTASK_LOGI("OnContinuousTaskStop js thread %{public}s",
146 continuousTaskCallbackInfo->GetAbilityName().c_str());
147 jsObserver->HandleOnContinuousTaskStop(continuousTaskCallbackInfo);
148 });
149 napi_ref callback = nullptr;
150 NapiAsyncTask::Schedule("JsBackgroundTaskSubscriber::OnContinuousTaskStop", env_,
151 std::make_unique<NapiAsyncTask>(callback, nullptr, std::move(complete)));
152 }
153
HandleOnContinuousTaskStop(const std::shared_ptr<ContinuousTaskCallbackInfo> & continuousTaskCallbackInfo)154 void JsBackgroundTaskSubscriber::HandleOnContinuousTaskStop(
155 const std::shared_ptr<ContinuousTaskCallbackInfo> &continuousTaskCallbackInfo)
156 {
157 BGTASK_LOGI("HandleOnContinuousTaskStop called");
158 std::lock_guard<std::mutex> lock(jsObserverObjectSetLock_);
159 auto iter = jsObserverObjectMap_.find("continuousTaskCancel");
160 if (iter == jsObserverObjectMap_.end()) {
161 BGTASK_LOGW("null callback Type");
162 return;
163 }
164 std::set<std::shared_ptr<NativeReference>> jsObserverObjectSet_ = iter->second;
165 for (auto &item : jsObserverObjectSet_) {
166 napi_value jsCallbackObj = item->GetNapiValue();
167 napi_value jsContinuousTaskCancelInfo = nullptr;
168
169 napi_create_object(env_, &jsContinuousTaskCancelInfo);
170
171 napi_value value = nullptr;
172 napi_create_int32(env_, continuousTaskCallbackInfo->GetCancelReason(), &value);
173 napi_set_named_property(env_, jsContinuousTaskCancelInfo, "reason", value);
174
175 napi_create_int32(env_, continuousTaskCallbackInfo->GetContinuousTaskId(), &value);
176 napi_set_named_property(env_, jsContinuousTaskCancelInfo, "id", value);
177
178 napi_value argv[1] = { jsContinuousTaskCancelInfo };
179 napi_value callResult = nullptr;
180 napi_value undefined = nullptr;
181 napi_get_undefined(env_, &undefined);
182 napi_status status = napi_call_function(env_, undefined, jsCallbackObj, 1, argv, &callResult);
183 if (status != napi_ok) {
184 BGTASK_LOGE("call js func failed %{public}d.", status);
185 }
186 }
187 }
188
OnContinuousTaskSuspend(const std::shared_ptr<ContinuousTaskCallbackInfo> & continuousTaskCallbackInfo)189 void JsBackgroundTaskSubscriber::OnContinuousTaskSuspend(
190 const std::shared_ptr<ContinuousTaskCallbackInfo> &continuousTaskCallbackInfo)
191 {
192 BGTASK_LOGI("OnContinuousTaskSuspend abilityname: %{public}s, continuousTaskId: %{public}d,"
193 "suspendReason: %{public}d, suspendState: %{public}d", continuousTaskCallbackInfo->GetAbilityName().c_str(),
194 continuousTaskCallbackInfo->GetContinuousTaskId(), continuousTaskCallbackInfo->GetSuspendReason(),
195 continuousTaskCallbackInfo->GetSuspendState());
196 std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback>(
197 [self = weak_from_this(), continuousTaskCallbackInfo](napi_env env, NapiAsyncTask &task, int32_t status) {
198 auto jsObserver = self.lock();
199 if (jsObserver == nullptr) {
200 BGTASK_LOGE("null observer");
201 return;
202 }
203 BGTASK_LOGD("OnContinuousTaskSuspend js thread %{public}s",
204 continuousTaskCallbackInfo->GetAbilityName().c_str());
205 jsObserver->HandleOnContinuousTaskSuspend(continuousTaskCallbackInfo);
206 });
207 napi_ref callback = nullptr;
208 NapiAsyncTask::Schedule("JsBackgroundTaskSubscriber::OnContinuousTaskSuspend", env_,
209 std::make_unique<NapiAsyncTask>(callback, nullptr, std::move(complete)));
210 }
211
HandleOnContinuousTaskSuspend(const std::shared_ptr<ContinuousTaskCallbackInfo> & continuousTaskCallbackInfo)212 void JsBackgroundTaskSubscriber::HandleOnContinuousTaskSuspend(
213 const std::shared_ptr<ContinuousTaskCallbackInfo> &continuousTaskCallbackInfo)
214 {
215 BGTASK_LOGI("HandleOnContinuousTaskSuspend called");
216 std::lock_guard<std::mutex> lock(jsObserverObjectSetLock_);
217 auto iter = jsObserverObjectMap_.find("continuousTaskSuspend");
218 if (iter == jsObserverObjectMap_.end()) {
219 BGTASK_LOGW("null callback Type: continuousTaskSuspend");
220 return;
221 }
222 std::set<std::shared_ptr<NativeReference>> jsObserverObjectSet_ = iter->second;
223 for (auto &item : jsObserverObjectSet_) {
224 napi_value jsCallbackObj = item->GetNapiValue();
225 napi_value jsContinuousTaskSuspendInfo = nullptr;
226
227 napi_create_object(env_, &jsContinuousTaskSuspendInfo);
228
229 // set continuousTaskId
230 napi_value continuousTaskId = nullptr;
231 napi_create_int32(env_, continuousTaskCallbackInfo->GetContinuousTaskId(), &continuousTaskId);
232 napi_set_named_property(env_, jsContinuousTaskSuspendInfo, "continuousTaskId", continuousTaskId);
233
234 // set suspendState
235 napi_value suspendState = nullptr;
236 napi_get_boolean(env_, continuousTaskCallbackInfo->GetSuspendState(), &suspendState);
237 napi_set_named_property(env_, jsContinuousTaskSuspendInfo, "suspendState", suspendState);
238
239 // set suspendReason
240 napi_value suspendReason = nullptr;
241 napi_create_int32(env_, continuousTaskCallbackInfo->GetSuspendReason(), &suspendReason);
242 napi_set_named_property(env_, jsContinuousTaskSuspendInfo, "suspendReason", suspendReason);
243
244 napi_value argv[1] = { jsContinuousTaskSuspendInfo };
245 napi_value callResult = nullptr;
246 napi_value undefined = nullptr;
247 napi_get_undefined(env_, &undefined);
248 napi_status status = napi_call_function(env_, undefined, jsCallbackObj, 1, argv, &callResult);
249 if (status != napi_ok) {
250 BGTASK_LOGE("call js func failed %{public}d.", status);
251 }
252 }
253 }
254
OnContinuousTaskActive(const std::shared_ptr<ContinuousTaskCallbackInfo> & continuousTaskCallbackInfo)255 void JsBackgroundTaskSubscriber::OnContinuousTaskActive(
256 const std::shared_ptr<ContinuousTaskCallbackInfo> &continuousTaskCallbackInfo)
257 {
258 BGTASK_LOGI("OnContinuousTaskActive abilityname: %{public}s, continuousTaskId: %{public}d",
259 continuousTaskCallbackInfo->GetAbilityName().c_str(), continuousTaskCallbackInfo->GetContinuousTaskId());
260 std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback>(
261 [self = weak_from_this(), continuousTaskCallbackInfo](napi_env env, NapiAsyncTask &task, int32_t status) {
262 auto jsObserver = self.lock();
263 if (jsObserver == nullptr) {
264 BGTASK_LOGE("null observer");
265 return;
266 }
267 BGTASK_LOGI("OnContinuousTaskActive js thread %{public}s",
268 continuousTaskCallbackInfo->GetAbilityName().c_str());
269 jsObserver->HandleOnContinuousTaskActive(continuousTaskCallbackInfo);
270 });
271 napi_ref callback = nullptr;
272 NapiAsyncTask::Schedule("JsBackgroundTaskSubscriber::OnContinuousTaskActive", env_,
273 std::make_unique<NapiAsyncTask>(callback, nullptr, std::move(complete)));
274 }
275
HandleOnContinuousTaskActive(const std::shared_ptr<ContinuousTaskCallbackInfo> & continuousTaskCallbackInfo)276 void JsBackgroundTaskSubscriber::HandleOnContinuousTaskActive(
277 const std::shared_ptr<ContinuousTaskCallbackInfo> &continuousTaskCallbackInfo)
278 {
279 BGTASK_LOGI("HandleOnContinuousTaskActive called");
280 std::lock_guard<std::mutex> lock(jsObserverObjectSetLock_);
281 auto iter = jsObserverObjectMap_.find("continuousTaskActive");
282 if (iter == jsObserverObjectMap_.end()) {
283 BGTASK_LOGW("null callback Type: continuousTaskActive");
284 return;
285 }
286 std::set<std::shared_ptr<NativeReference>> jsObserverObjectSet_ = iter->second;
287 for (auto &item : jsObserverObjectSet_) {
288 napi_value jsCallbackObj = item->GetNapiValue();
289 napi_value jsContinuousTaskActiveInfo = nullptr;
290
291 napi_create_object(env_, &jsContinuousTaskActiveInfo);
292
293 // set continuousTaskId
294 napi_value continuousTaskId = nullptr;
295 napi_create_int32(env_, continuousTaskCallbackInfo->GetContinuousTaskId(), &continuousTaskId);
296 napi_set_named_property(env_, jsContinuousTaskActiveInfo, "id", continuousTaskId);
297
298 napi_value argv[1] = { jsContinuousTaskActiveInfo };
299 napi_value callResult = nullptr;
300 napi_value undefined = nullptr;
301 napi_get_undefined(env_, &undefined);
302 napi_status status = napi_call_function(env_, undefined, jsCallbackObj, 1, argv, &callResult);
303 if (status != napi_ok) {
304 BGTASK_LOGE("call js func failed %{public}d.", status);
305 }
306 }
307 }
308
AddJsObserverObject(const std::string cbType,const napi_value & jsObserverObject)309 void JsBackgroundTaskSubscriber::AddJsObserverObject(const std::string cbType, const napi_value &jsObserverObject)
310 {
311 if (jsObserverObject == nullptr) {
312 BGTASK_LOGI("null observer");
313 return;
314 }
315
316 if (GetObserverObject(cbType, jsObserverObject) == nullptr) {
317 std::lock_guard<std::mutex> lock(jsObserverObjectSetLock_);
318 napi_ref ref = nullptr;
319 napi_create_reference(env_, jsObserverObject, 1, &ref);
320 jsObserverObjectMap_[cbType].emplace(
321 std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference *>(ref)));
322 BGTASK_LOGI("add observer, type: %{public}s, size: %{public}d", cbType.c_str(),
323 static_cast<int32_t>(jsObserverObjectMap_[cbType].size()));
324 } else {
325 BGTASK_LOGI("observer exist");
326 }
327 }
328
GetObserverObject(const std::string cbType,const napi_value & jsObserverObject)329 std::shared_ptr<NativeReference> JsBackgroundTaskSubscriber::GetObserverObject(
330 const std::string cbType, const napi_value &jsObserverObject)
331 {
332 if (jsObserverObject == nullptr) {
333 BGTASK_LOGI("null observer");
334 return nullptr;
335 }
336
337 std::lock_guard<std::mutex> lock(jsObserverObjectSetLock_);
338 auto iter = jsObserverObjectMap_.find(cbType);
339 if (iter == jsObserverObjectMap_.end()) {
340 BGTASK_LOGW("null callback Type: %{public}s", cbType.c_str());
341 return nullptr;
342 }
343 std::set<std::shared_ptr<NativeReference>> jsObserverObjectSet_ = iter->second;
344 for (auto &observer : jsObserverObjectSet_) {
345 if (observer == nullptr) {
346 BGTASK_LOGI("null observer");
347 continue;
348 }
349
350 napi_value value = observer->GetNapiValue();
351 if (value == nullptr) {
352 BGTASK_LOGI("null value");
353 continue;
354 }
355
356 bool isEqual = false;
357 napi_strict_equals(env_, value, jsObserverObject, &isEqual);
358 if (isEqual) {
359 return observer;
360 }
361 }
362 return nullptr;
363 }
364
IsEmpty()365 bool JsBackgroundTaskSubscriber::IsEmpty()
366 {
367 std::lock_guard<std::mutex> lock(jsObserverObjectSetLock_);
368 return jsObserverObjectMap_.empty();
369 }
370
IsTypeEmpty(const std::string & cbType)371 bool JsBackgroundTaskSubscriber::IsTypeEmpty(const std::string &cbType)
372 {
373 std::lock_guard<std::mutex> lock(jsObserverObjectSetLock_);
374 auto iter = jsObserverObjectMap_.find(cbType);
375 return iter == jsObserverObjectMap_.end();
376 }
377
RemoveJsObserverObjects(const std::string cbType)378 void JsBackgroundTaskSubscriber::RemoveJsObserverObjects(const std::string cbType)
379 {
380 std::lock_guard<std::mutex> lock(jsObserverObjectSetLock_);
381 auto iter = jsObserverObjectMap_.find(cbType);
382 if (iter != jsObserverObjectMap_.end()) {
383 jsObserverObjectMap_.erase(cbType);
384 }
385 }
386
RemoveJsObserverObject(const std::string cbType,const napi_value & jsObserverObject)387 void JsBackgroundTaskSubscriber::RemoveJsObserverObject(const std::string cbType, const napi_value &jsObserverObject)
388 {
389 if (jsObserverObject == nullptr) {
390 BGTASK_LOGI("null observer");
391 return;
392 }
393
394 auto observer = GetObserverObject(cbType, jsObserverObject);
395 if (observer != nullptr) {
396 jsObserverObjectMap_[cbType].erase(observer);
397 }
398 }
399
SetFlag(uint32_t flag,bool isSubscriber)400 void JsBackgroundTaskSubscriber::SetFlag(uint32_t flag, bool isSubscriber)
401 {
402 std::lock_guard<std::mutex> lock(flagLock_);
403 if (isSubscriber) {
404 flag_ |= flag;
405 } else {
406 flag_ &= ~flag;
407 }
408 }
409
GetFlag(int32_t & flag)410 void JsBackgroundTaskSubscriber::GetFlag(int32_t &flag)
411 {
412 std::lock_guard<std::mutex> lock(flagLock_);
413 flag = static_cast<int32_t>(flag_);
414 }
415 } // BackgroundTaskMgr
416 } // OHOS