1 /*
2 * Copyright (c) 2022 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 "bg_continuous_task_napi_module.h"
17
18 #include "ability.h"
19 #include "bundle_mgr_interface.h"
20 #include "hitrace_meter.h"
21 #include "iservice_registry.h"
22 #include "napi_base_context.h"
23 #include "system_ability_definition.h"
24 #include "want_agent.h"
25 #ifdef SUPPORT_JSSTACK
26 #include "xpower_event_js.h"
27 #endif
28
29 #include "background_mode.h"
30 #include "background_task_mgr_helper.h"
31 #include "bgtaskmgr_inner_errors.h"
32 #include "common.h"
33 #include "continuous_task_log.h"
34 #include "continuous_task_param.h"
35 #include "js_backgroundtask_subscriber.h"
36 #include "js_runtime_utils.h"
37
38 namespace OHOS {
39 namespace BackgroundTaskMgr {
40 namespace {
41 static constexpr uint32_t MAX_START_BG_RUNNING_PARAMS = 4;
42 static constexpr uint32_t MAX_STOP_BG_RUNNING_PARAMS = 2;
43 static constexpr uint32_t MAX_UPDATE_BG_RUNNING_PARAMS = 2;
44 static constexpr uint32_t CALLBACK_RESULT_PARAMS_NUM = 2;
45 static constexpr uint32_t BG_MODE_ID_BEGIN = 1;
46 static constexpr uint32_t BG_MODE_ID_END = 9;
47 static constexpr int32_t SYSTEM_LIVE_CONTENT_TYPE = 8;
48 static constexpr int32_t SLOT_TYPE = 4;
49 static constexpr uint32_t ARGC_ONE = 1;
50 static constexpr uint32_t ARGC_TWO = 2;
51 static constexpr uint32_t INDEX_ZERO = 0;
52 static constexpr uint32_t INDEX_ONE = 1;
53 static std::shared_ptr<JsBackgroundTaskSubscriber> backgroundTaskSubscriber_ = nullptr;
54 static std::vector<std::string> g_backgroundModes = {
55 "dataTransfer",
56 "audioPlayback",
57 "audioRecording",
58 "location",
59 "bluetoothInteraction",
60 "multiDeviceConnection",
61 "wifiInteraction",
62 "voip",
63 "taskKeeping"
64 };
65 }
66
67 struct AsyncCallbackInfo : public AsyncWorkData {
AsyncCallbackInfoOHOS::BackgroundTaskMgr::AsyncCallbackInfo68 explicit AsyncCallbackInfo(napi_env env) : AsyncWorkData(env) {}
69 std::shared_ptr<AbilityRuntime::AbilityContext> abilityContext {nullptr};
70 uint32_t bgMode {0};
71 std::shared_ptr<AbilityRuntime::WantAgent::WantAgent> wantAgent {nullptr};
72 std::vector<uint32_t> bgModes {};
73 bool isBatchApi {false};
74 int32_t notificationId {-1}; // out
75 int32_t continuousTaskId {-1}; // out
76 };
77
WrapVoidToJS(napi_env env)78 napi_value WrapVoidToJS(napi_env env)
79 {
80 napi_value result = nullptr;
81 NAPI_CALL(env, napi_get_null(env, &result));
82 return result;
83 }
84
WrapUndefinedToJS(napi_env env)85 napi_value WrapUndefinedToJS(napi_env env)
86 {
87 napi_value result = nullptr;
88 NAPI_CALL(env, napi_get_undefined(env, &result));
89 return result;
90 }
91
GetCallbackErrorValue(napi_env env,int32_t errCode)92 napi_value GetCallbackErrorValue(napi_env env, int32_t errCode)
93 {
94 napi_value jsObject = nullptr;
95 napi_value jsValue = nullptr;
96 NAPI_CALL(env, napi_create_int32(env, errCode, &jsValue));
97 NAPI_CALL(env, napi_create_object(env, &jsObject));
98 NAPI_CALL(env, napi_set_named_property(env, jsObject, "code", jsValue));
99 return jsObject;
100 }
101
GetAbilityContext(const napi_env & env,const napi_value & value,std::shared_ptr<AbilityRuntime::AbilityContext> & abilityContext)102 napi_value GetAbilityContext(const napi_env &env, const napi_value &value,
103 std::shared_ptr<AbilityRuntime::AbilityContext> &abilityContext)
104 {
105 bool stageMode = false;
106 napi_status status = OHOS::AbilityRuntime::IsStageContext(env, value, stageMode);
107 BGTASK_LOGD("is stage mode: %{public}s", stageMode ? "true" : "false");
108
109 if (status != napi_ok || !stageMode) {
110 BGTASK_LOGI("Getting context with FA model");
111 auto ability = OHOS::AbilityRuntime::GetCurrentAbility(env);
112 if (!ability) {
113 BGTASK_LOGE("Failed to get native ability instance");
114 return nullptr;
115 }
116 abilityContext = ability->GetAbilityContext();
117 if (!abilityContext) {
118 BGTASK_LOGE("get FA model ability context failed");
119 return nullptr;
120 }
121 return WrapVoidToJS(env);
122 } else {
123 BGTASK_LOGD("Getting context with stage model");
124 auto context = AbilityRuntime::GetStageModeContext(env, value);
125 if (!context) {
126 BGTASK_LOGE("get context failed");
127 return nullptr;
128 }
129 abilityContext = AbilityRuntime::Context::ConvertTo<AbilityRuntime::AbilityContext>(context);
130 if (!abilityContext) {
131 BGTASK_LOGE("get Stage model ability context failed");
132 return nullptr;
133 }
134 return WrapVoidToJS(env);
135 }
136 }
137
CheckBackgroundMode(napi_env env,AsyncCallbackInfo * asyncCallbackInfo,bool isThrow)138 bool CheckBackgroundMode(napi_env env, AsyncCallbackInfo *asyncCallbackInfo, bool isThrow)
139 {
140 if (!asyncCallbackInfo->isBatchApi) {
141 if (asyncCallbackInfo->bgMode < BG_MODE_ID_BEGIN || asyncCallbackInfo->bgMode > BG_MODE_ID_END) {
142 BGTASK_LOGE("request background mode id: %{public}u out of range", asyncCallbackInfo->bgMode);
143 Common::HandleParamErr(env, ERR_BGMODE_RANGE_ERR, isThrow);
144 asyncCallbackInfo->errCode = ERR_BGMODE_RANGE_ERR;
145 return false;
146 }
147 } else {
148 for (unsigned int i = 0; i < asyncCallbackInfo->bgModes.size(); i++) {
149 if (asyncCallbackInfo->bgModes[i] < BG_MODE_ID_BEGIN || asyncCallbackInfo->bgModes[i] > BG_MODE_ID_END) {
150 BGTASK_LOGE("request background mode id: %{public}u out of range", asyncCallbackInfo->bgModes[i]);
151 Common::HandleParamErr(env, ERR_BGMODE_RANGE_ERR, isThrow);
152 asyncCallbackInfo->errCode = ERR_BGMODE_RANGE_ERR;
153 return false;
154 }
155 }
156 }
157 return true;
158 }
159
StartBackgroundRunningCheckParam(napi_env env,AsyncCallbackInfo * asyncCallbackInfo,bool isThrow)160 bool StartBackgroundRunningCheckParam(napi_env env, AsyncCallbackInfo *asyncCallbackInfo, bool isThrow)
161 {
162 if (asyncCallbackInfo == nullptr) {
163 BGTASK_LOGE("asyncCallbackInfo is nullptr");
164 return false;
165 }
166 if (asyncCallbackInfo->errCode != ERR_OK) {
167 BGTASK_LOGE("input params parse failed");
168 return false;
169 }
170 if (asyncCallbackInfo->abilityContext == nullptr) {
171 asyncCallbackInfo->errCode = ERR_CONTEXT_NULL_OR_TYPE_ERR;
172 Common::HandleParamErr(env, ERR_CONTEXT_NULL_OR_TYPE_ERR, isThrow);
173 BGTASK_LOGE("abilityContext is null");
174 return false;
175 }
176 const std::shared_ptr<AppExecFwk::AbilityInfo> info = asyncCallbackInfo->abilityContext->GetAbilityInfo();
177 if (info == nullptr) {
178 BGTASK_LOGE("ability info is null");
179 Common::HandleParamErr(env, ERR_ABILITY_INFO_EMPTY, isThrow);
180 asyncCallbackInfo->errCode = ERR_ABILITY_INFO_EMPTY;
181 return false;
182 }
183 if (asyncCallbackInfo->wantAgent == nullptr) {
184 BGTASK_LOGE("wantAgent param is nullptr");
185 Common::HandleParamErr(env, ERR_WANTAGENT_NULL_OR_TYPE_ERR, isThrow);
186 asyncCallbackInfo->errCode = ERR_WANTAGENT_NULL_OR_TYPE_ERR;
187 return false;
188 }
189 sptr<IRemoteObject> token = asyncCallbackInfo->abilityContext->GetToken();
190 if (!token) {
191 BGTASK_LOGE("get ability token info failed");
192 Common::HandleParamErr(env, ERR_GET_TOKEN_ERR, isThrow);
193 asyncCallbackInfo->errCode = ERR_GET_TOKEN_ERR;
194 return false;
195 }
196 if (!CheckBackgroundMode(env, asyncCallbackInfo, isThrow)) {
197 BGTASK_LOGE("check background mode failed.");
198 return false;
199 }
200 return true;
201 }
202
UpdateBackgroundRunningExecuteCB(napi_env env,void * data)203 void UpdateBackgroundRunningExecuteCB(napi_env env, void *data)
204 {
205 HitraceScoped traceScoped(HITRACE_TAG_OHOS,
206 "BackgroundTaskManager::ContinuousTask::Napi::UpdateBackgroundRunningExecuteCB");
207 AsyncCallbackInfo *asyncCallbackInfo = static_cast<AsyncCallbackInfo *>(data);
208 if (asyncCallbackInfo == nullptr || asyncCallbackInfo->errCode != ERR_OK) {
209 BGTASK_LOGE("input params error");
210 return;
211 }
212 const std::shared_ptr<AppExecFwk::AbilityInfo> info = asyncCallbackInfo->abilityContext->GetAbilityInfo();
213 ContinuousTaskParam taskParam = ContinuousTaskParam(true, asyncCallbackInfo->bgMode, nullptr, info->name,
214 asyncCallbackInfo->abilityContext->GetToken(), "", true, asyncCallbackInfo->bgModes,
215 asyncCallbackInfo->abilityContext->GetAbilityRecordId());
216 BGTASK_LOGI("RequestUpdateBackgroundRunning isBatch: %{public}d, bgModeSize: %{public}u",
217 taskParam.isBatchApi_, static_cast<uint32_t>(taskParam.bgModeIds_.size()));
218 asyncCallbackInfo->errCode = BackgroundTaskMgrHelper::RequestUpdateBackgroundRunning(taskParam);
219 asyncCallbackInfo->notificationId = taskParam.notificationId_;
220 asyncCallbackInfo->continuousTaskId = taskParam.continuousTaskId_;
221 BGTASK_LOGI("notification %{public}d, continuousTaskId %{public}d", taskParam.notificationId_,
222 taskParam.continuousTaskId_);
223 }
224
StartBackgroundRunningExecuteCB(napi_env env,void * data)225 void StartBackgroundRunningExecuteCB(napi_env env, void *data)
226 {
227 HitraceScoped traceScoped(HITRACE_TAG_OHOS,
228 "BackgroundTaskManager::ContinuousTask::Napi::StartBackgroundRunningExecuteCB");
229 AsyncCallbackInfo *asyncCallbackInfo = static_cast<AsyncCallbackInfo *>(data);
230 if (asyncCallbackInfo == nullptr || asyncCallbackInfo->errCode != ERR_OK) {
231 BGTASK_LOGE("input params error");
232 return;
233 }
234 const std::shared_ptr<AppExecFwk::AbilityInfo> info = asyncCallbackInfo->abilityContext->GetAbilityInfo();
235 ContinuousTaskParam taskParam = ContinuousTaskParam(true, asyncCallbackInfo->bgMode, asyncCallbackInfo->wantAgent,
236 info->name, asyncCallbackInfo->abilityContext->GetToken(), "",
237 asyncCallbackInfo->isBatchApi, asyncCallbackInfo->bgModes,
238 asyncCallbackInfo->abilityContext->GetAbilityRecordId());
239 BGTASK_LOGI("RequestStartBackgroundRunning isBatch: %{public}d, bgModeSize: %{public}u",
240 taskParam.isBatchApi_, static_cast<uint32_t>(taskParam.bgModeIds_.size()));
241 asyncCallbackInfo->errCode = BackgroundTaskMgrHelper::RequestStartBackgroundRunning(taskParam);
242 asyncCallbackInfo->notificationId = taskParam.notificationId_;
243 asyncCallbackInfo->continuousTaskId = taskParam.continuousTaskId_;
244 BGTASK_LOGI("notification %{public}d, continuousTaskId %{public}d", taskParam.notificationId_,
245 taskParam.continuousTaskId_);
246 }
247
CallbackCompletedCB(napi_env env,napi_status status,void * data)248 void CallbackCompletedCB(napi_env env, napi_status status, void *data)
249 {
250 HitraceScoped traceScoped(HITRACE_TAG_OHOS,
251 "BackgroundTaskManager::ContinuousTask::Napi::CallbackCompletedCB");
252 AsyncCallbackInfo *asyncCallbackInfo = static_cast<AsyncCallbackInfo *>(data);
253 std::unique_ptr<AsyncCallbackInfo> callbackPtr {asyncCallbackInfo};
254 napi_value callback {nullptr};
255 napi_value undefined {nullptr};
256 napi_value result[CALLBACK_RESULT_PARAMS_NUM] = {nullptr};
257 napi_value callResult = {nullptr};
258 NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined));
259 if (asyncCallbackInfo->errCode == ERR_OK) {
260 result[0] = WrapUndefinedToJS(env);
261 napi_create_int32(env, 0, &result[1]);
262 } else {
263 result[1] = WrapUndefinedToJS(env);
264 std::string errMsg = Common::FindErrMsg(env, asyncCallbackInfo->errCode);
265 int32_t errCodeInfo = Common::FindErrCode(env, asyncCallbackInfo->errCode);
266 result[0] = Common::GetCallbackErrorValue(env, errCodeInfo, errMsg);
267 }
268
269 NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncCallbackInfo->callback, &callback));
270 NAPI_CALL_RETURN_VOID(env,
271 napi_call_function(env, undefined, callback, CALLBACK_RESULT_PARAMS_NUM, result, &callResult));
272 }
273
PromiseCompletedCB(napi_env env,napi_status status,void * data)274 void PromiseCompletedCB(napi_env env, napi_status status, void *data)
275 {
276 HitraceScoped traceScoped(HITRACE_TAG_OHOS,
277 "BackgroundTaskManager::ContinuousTask::Napi::PromiseCompletedCB");
278 AsyncCallbackInfo *asyncCallbackInfo = static_cast<AsyncCallbackInfo *>(data);
279 std::unique_ptr<AsyncCallbackInfo> callbackPtr {asyncCallbackInfo};
280 napi_value result {nullptr};
281 if (asyncCallbackInfo->errCode == ERR_OK) {
282 if (asyncCallbackInfo->bgModes.size() > 0) {
283 napi_value slotType = nullptr;
284 napi_value contentType = nullptr;
285 napi_value notificationId = nullptr;
286 napi_value continuousTaskId = nullptr;
287 napi_create_object(env, &result);
288 napi_create_int32(env, SLOT_TYPE, &slotType);
289 napi_create_int32(env, SYSTEM_LIVE_CONTENT_TYPE, &contentType);
290 napi_create_int32(env, asyncCallbackInfo->notificationId, ¬ificationId);
291 napi_create_int32(env, asyncCallbackInfo->continuousTaskId, &continuousTaskId);
292 napi_set_named_property(env, result, "slotType", slotType);
293 napi_set_named_property(env, result, "contentType", contentType);
294 napi_set_named_property(env, result, "notificationId", notificationId);
295 napi_set_named_property(env, result, "continuousTaskId", continuousTaskId);
296 } else {
297 napi_create_int32(env, 0, &result);
298 }
299 NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, asyncCallbackInfo->deferred, result));
300 } else {
301 std::string errMsg = Common::FindErrMsg(env, asyncCallbackInfo->errCode);
302 int32_t errCodeInfo = Common::FindErrCode(env, asyncCallbackInfo->errCode);
303 result = Common::GetCallbackErrorValue(env, errCodeInfo, errMsg);
304 NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, asyncCallbackInfo->deferred, result));
305 }
306 }
307
ReportXPowerJsStackSysEventByType(napi_env env,const std::string & taskType)308 void ReportXPowerJsStackSysEventByType(napi_env env, const std::string &taskType)
309 {
310 #ifdef SUPPORT_JSSTACK
311 HiviewDFX::ReportXPowerJsStackSysEvent(env, taskType);
312 #endif
313 }
314
StartBackgroundRunningAsync(napi_env env,napi_value * argv,const uint32_t argCallback,AsyncCallbackInfo * asyncCallbackInfo,bool isThrow)315 napi_value StartBackgroundRunningAsync(napi_env env, napi_value *argv,
316 const uint32_t argCallback, AsyncCallbackInfo *asyncCallbackInfo, bool isThrow)
317 {
318 if (argv == nullptr || asyncCallbackInfo == nullptr) {
319 BGTASK_LOGE("param is nullptr");
320 return nullptr;
321 }
322 if (isThrow && asyncCallbackInfo->errCode != ERR_OK) {
323 return nullptr;
324 }
325 napi_value resourceName {nullptr};
326 NAPI_CALL(env, napi_create_string_latin1(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
327
328 napi_valuetype valuetype = napi_undefined;
329 NAPI_CALL(env, napi_typeof(env, argv[argCallback], &valuetype));
330 if (valuetype != napi_function) {
331 Common::HandleParamErr(env, ERR_CALLBACK_NULL_OR_TYPE_ERR, isThrow);
332 BGTASK_LOGE("valuetype is no napi_function.");
333 return nullptr;
334 }
335 NAPI_CALL(env, napi_create_reference(env, argv[argCallback], 1, &asyncCallbackInfo->callback));
336 if (!StartBackgroundRunningCheckParam(env, asyncCallbackInfo, isThrow) && isThrow) {
337 BGTASK_LOGE("start bgytask check param fail.");
338 return nullptr;
339 }
340
341 NAPI_CALL(env, napi_create_async_work(env,
342 nullptr,
343 resourceName,
344 StartBackgroundRunningExecuteCB,
345 CallbackCompletedCB,
346 static_cast<void *>(asyncCallbackInfo),
347 &asyncCallbackInfo->asyncWork));
348 NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork));
349
350 return WrapVoidToJS(env);
351 }
352
UpdateBackgroundRunningPromise(napi_env env,AsyncCallbackInfo * asyncCallbackInfo,bool isThrow)353 napi_value UpdateBackgroundRunningPromise(napi_env env, AsyncCallbackInfo *asyncCallbackInfo, bool isThrow)
354 {
355 if (asyncCallbackInfo == nullptr) {
356 BGTASK_LOGE("param is nullptr");
357 return nullptr;
358 }
359 if (!CheckBackgroundMode(env, asyncCallbackInfo, isThrow)) {
360 return nullptr;
361 }
362 napi_value resourceName;
363 NAPI_CALL(env, napi_create_string_latin1(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
364 napi_deferred deferred;
365 napi_value promise {nullptr};
366 NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));
367 asyncCallbackInfo->deferred = deferred;
368 NAPI_CALL(env, napi_create_async_work(env,
369 nullptr,
370 resourceName,
371 UpdateBackgroundRunningExecuteCB,
372 PromiseCompletedCB,
373 static_cast<void *>(asyncCallbackInfo),
374 &asyncCallbackInfo->asyncWork));
375 NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork));
376 return promise;
377 }
378
StartBackgroundRunningPromise(napi_env env,AsyncCallbackInfo * asyncCallbackInfo,bool isThrow)379 napi_value StartBackgroundRunningPromise(napi_env env, AsyncCallbackInfo *asyncCallbackInfo, bool isThrow)
380 {
381 if (asyncCallbackInfo == nullptr) {
382 BGTASK_LOGE("param is nullptr");
383 return nullptr;
384 }
385 napi_value resourceName;
386 NAPI_CALL(env, napi_create_string_latin1(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
387 napi_deferred deferred;
388 napi_value promise {nullptr};
389 NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));
390 asyncCallbackInfo->deferred = deferred;
391 if (!StartBackgroundRunningCheckParam(env, asyncCallbackInfo, isThrow) && isThrow) {
392 BGTASK_LOGE("start bgytask check param fail.");
393 return nullptr;
394 }
395 NAPI_CALL(env, napi_create_async_work(env,
396 nullptr,
397 resourceName,
398 StartBackgroundRunningExecuteCB,
399 PromiseCompletedCB,
400 static_cast<void *>(asyncCallbackInfo),
401 &asyncCallbackInfo->asyncWork));
402 NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork));
403 return promise;
404 }
405
CheckTypeForNapiValue(napi_env env,napi_value param,napi_valuetype expectType)406 bool CheckTypeForNapiValue(napi_env env, napi_value param, napi_valuetype expectType)
407 {
408 napi_valuetype valueType = napi_undefined;
409 if (napi_typeof(env, param, &valueType) != napi_ok) {
410 return false;
411 }
412 return valueType == expectType;
413 }
414
GetMode(const napi_env & env,const napi_value & value,AsyncCallbackInfo * asyncCallbackInfo)415 napi_value GetMode(const napi_env &env, const napi_value &value, AsyncCallbackInfo *asyncCallbackInfo)
416 {
417 napi_valuetype valuetype = napi_undefined;
418 NAPI_CALL(env, napi_typeof(env, value, &valuetype));
419 if (valuetype != napi_number) {
420 Common::HandleParamErr(env, ERR_BGMODE_NULL_OR_TYPE_ERR, true);
421 return nullptr;
422 }
423 napi_get_value_uint32(env, value, &asyncCallbackInfo->bgMode);
424 asyncCallbackInfo->isBatchApi = false;
425 BGTASK_LOGI("get bgmode info: %{public}u", asyncCallbackInfo->bgMode);
426 return WrapVoidToJS(env);
427 }
428
GetModes(const napi_env & env,const napi_value & value,AsyncCallbackInfo * asyncCallbackInfo)429 napi_value GetModes(const napi_env &env, const napi_value &value, AsyncCallbackInfo *asyncCallbackInfo)
430 {
431 uint32_t arrayLen = 0;
432 napi_get_array_length(env, value, &arrayLen);
433 BGTASK_LOGI("get bgModes arraylen: %{public}u", arrayLen);
434 if (arrayLen == 0) {
435 BGTASK_LOGE("get bgModes arraylen is 0");
436 Common::HandleParamErr(env, ERR_BGMODE_NULL_OR_TYPE_ERR, true);
437 return nullptr;
438 }
439 asyncCallbackInfo->isBatchApi = true;
440 for (uint32_t i = 0; i < arrayLen; i++) {
441 napi_value mode = nullptr;
442 napi_get_element(env, value, i, &mode);
443 std::string result;
444 if (Common::GetStringValue(env, mode, result) == nullptr) {
445 BGTASK_LOGE("GetStringValue failed.");
446 Common::HandleParamErr(env, ERR_BGMODE_NULL_OR_TYPE_ERR, true);
447 return nullptr;
448 }
449 BGTASK_LOGI("GetBackgroundMode %{public}s.", result.c_str());
450 auto it = std::find(g_backgroundModes.begin(), g_backgroundModes.end(), result);
451 if (it != g_backgroundModes.end()) {
452 auto index = std::distance(g_backgroundModes.begin(), it);
453 auto modeIter = std::find(asyncCallbackInfo->bgModes.begin(), asyncCallbackInfo->bgModes.end(), index + 1);
454 if (modeIter == asyncCallbackInfo->bgModes.end()) {
455 asyncCallbackInfo->bgModes.push_back(index + 1);
456 }
457 } else {
458 BGTASK_LOGE("mode string is invalid");
459 Common::HandleParamErr(env, ERR_BGMODE_NULL_OR_TYPE_ERR, true);
460 return nullptr;
461 }
462 }
463 return WrapVoidToJS(env);
464 }
465
GetBackgroundMode(const napi_env & env,const napi_value & value,AsyncCallbackInfo * asyncCallbackInfo)466 napi_value GetBackgroundMode(const napi_env &env, const napi_value &value, AsyncCallbackInfo *asyncCallbackInfo)
467 {
468 bool isArray = false;
469 if (napi_is_array(env, value, &isArray) != napi_ok || isArray == false) {
470 return GetMode(env, value, asyncCallbackInfo);
471 } else {
472 return GetModes(env, value, asyncCallbackInfo);
473 }
474 }
475
GetWantAgent(const napi_env & env,const napi_value & value,std::shared_ptr<AbilityRuntime::WantAgent::WantAgent> & wantAgent)476 napi_value GetWantAgent(const napi_env &env, const napi_value &value,
477 std::shared_ptr<AbilityRuntime::WantAgent::WantAgent> &wantAgent)
478 {
479 napi_valuetype valuetype = napi_undefined;
480 AbilityRuntime::WantAgent::WantAgent *wantAgentPtr = nullptr;
481 NAPI_CALL(env, napi_typeof(env, value, &valuetype));
482 if (valuetype != napi_object) {
483 Common::HandleParamErr(env, ERR_WANTAGENT_NULL_OR_TYPE_ERR, true);
484 return nullptr;
485 }
486 napi_unwrap(env, value, (void **)&wantAgentPtr);
487 if (wantAgentPtr == nullptr) {
488 return nullptr;
489 }
490 wantAgent = std::make_shared<AbilityRuntime::WantAgent::WantAgent>(*wantAgentPtr);
491
492 return WrapVoidToJS(env);
493 }
494
StartBackgroundRunningCheckParamBeforeSubmit(napi_env env,napi_value * argv,size_t len,bool isThrow,AsyncCallbackInfo * asyncCallbackInfo)495 bool StartBackgroundRunningCheckParamBeforeSubmit(napi_env env, napi_value *argv, size_t len, bool isThrow,
496 AsyncCallbackInfo *asyncCallbackInfo)
497 {
498 // argv[0] : context : AbilityContext
499 if (GetAbilityContext(env, argv[0], asyncCallbackInfo->abilityContext) == nullptr) {
500 BGTASK_LOGE("Get ability context failed");
501 Common::HandleParamErr(env, ERR_CONTEXT_NULL_OR_TYPE_ERR, isThrow);
502 asyncCallbackInfo->errCode = ERR_CONTEXT_NULL_OR_TYPE_ERR;
503 return false;
504 }
505
506 // argv[1] : bgMode : BackgroundMode
507 if (GetBackgroundMode(env, argv[1], asyncCallbackInfo) == nullptr) {
508 BGTASK_LOGE("input bgmode param not number");
509 Common::HandleParamErr(env, ERR_BGMODE_NULL_OR_TYPE_ERR, isThrow);
510 asyncCallbackInfo->errCode = ERR_BGMODE_NULL_OR_TYPE_ERR;
511 return false;
512 }
513
514 // argv[2] : wantAgent: WantAgent
515 if (GetWantAgent(env, argv[2], asyncCallbackInfo->wantAgent) == nullptr) {
516 BGTASK_LOGE("input wantAgent param is not object");
517 Common::HandleParamErr(env, ERR_WANTAGENT_NULL_OR_TYPE_ERR, isThrow);
518 asyncCallbackInfo->errCode = ERR_WANTAGENT_NULL_OR_TYPE_ERR;
519 return false;
520 }
521 return true;
522 }
523
524
UpdateBackgroundRunning(napi_env env,napi_callback_info info,bool isThrow)525 napi_value UpdateBackgroundRunning(napi_env env, napi_callback_info info, bool isThrow)
526 {
527 HitraceScoped traceScoped(HITRACE_TAG_OHOS,
528 "BackgroundTaskManager::ContinuousTask::Napi::UpdateBackgroundRunning");
529 ReportXPowerJsStackSysEventByType(env, "CONTINUOUS_TASK_UPDATE");
530 AsyncCallbackInfo *asyncCallbackInfo = new (std::nothrow) AsyncCallbackInfo(env);
531 if (asyncCallbackInfo == nullptr) {
532 BGTASK_LOGE("asyncCallbackInfo == nullpter");
533 return WrapVoidToJS(env);
534 }
535 std::unique_ptr<AsyncCallbackInfo> callbackPtr {asyncCallbackInfo};
536
537 size_t argc = MAX_UPDATE_BG_RUNNING_PARAMS;
538 napi_value argv[MAX_UPDATE_BG_RUNNING_PARAMS] = {nullptr};
539 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
540 if (argc != MAX_UPDATE_BG_RUNNING_PARAMS) {
541 BGTASK_LOGE("wrong param nums");
542 Common::HandleParamErr(env, ERR_PARAM_NUMBER_ERR, isThrow);
543 return WrapVoidToJS(env);
544 }
545
546 // argv[0] : context : AbilityContext
547 if (GetAbilityContext(env, argv[0], asyncCallbackInfo->abilityContext) == nullptr) {
548 BGTASK_LOGE("Get ability context failed");
549 Common::HandleParamErr(env, ERR_CONTEXT_NULL_OR_TYPE_ERR, isThrow);
550 asyncCallbackInfo->errCode = ERR_CONTEXT_NULL_OR_TYPE_ERR;
551 return WrapVoidToJS(env);
552 }
553
554 // argv[1] : bgMode : BackgroundMode
555 if (GetBackgroundMode(env, argv[1], asyncCallbackInfo) == nullptr) {
556 BGTASK_LOGE("input bgmode param not number");
557 Common::HandleParamErr(env, ERR_BGMODE_NULL_OR_TYPE_ERR, isThrow);
558 asyncCallbackInfo->errCode = ERR_BGMODE_NULL_OR_TYPE_ERR;
559 return WrapVoidToJS(env);
560 }
561
562 napi_value ret {nullptr};
563 ret = UpdateBackgroundRunningPromise(env, asyncCallbackInfo, isThrow);
564 callbackPtr.release();
565 if (ret == nullptr) {
566 BGTASK_LOGE("ret is nullpter");
567 if (asyncCallbackInfo != nullptr) {
568 delete asyncCallbackInfo;
569 asyncCallbackInfo = nullptr;
570 }
571 ret = WrapVoidToJS(env);
572 }
573 return ret;
574 }
575
StartBackgroundRunning(napi_env env,napi_callback_info info,bool isThrow)576 napi_value StartBackgroundRunning(napi_env env, napi_callback_info info, bool isThrow)
577 {
578 HitraceScoped traceScoped(HITRACE_TAG_OHOS,
579 "BackgroundTaskManager::ContinuousTask::Napi::StartBackgroundRunning");
580 ReportXPowerJsStackSysEventByType(env, "CONTINUOUS_TASK_APPLY");
581 AsyncCallbackInfo *asyncCallbackInfo = new (std::nothrow) AsyncCallbackInfo(env);
582 if (asyncCallbackInfo == nullptr) {
583 BGTASK_LOGE("asyncCallbackInfo == nullpter");
584 return WrapVoidToJS(env);
585 }
586 std::unique_ptr<AsyncCallbackInfo> callbackPtr {asyncCallbackInfo};
587
588 size_t argc = MAX_START_BG_RUNNING_PARAMS;
589 napi_value argv[MAX_START_BG_RUNNING_PARAMS] = {nullptr};
590 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
591 if (argc > MAX_START_BG_RUNNING_PARAMS) {
592 BGTASK_LOGE("wrong param nums");
593 Common::HandleParamErr(env, ERR_PARAM_NUMBER_ERR, isThrow);
594 return WrapVoidToJS(env);
595 }
596
597 if (!StartBackgroundRunningCheckParamBeforeSubmit(env, argv, MAX_START_BG_RUNNING_PARAMS, isThrow,
598 asyncCallbackInfo)) {
599 BGTASK_LOGE("failed to check parameters before start bgtask running.");
600 return WrapVoidToJS(env);
601 }
602
603 napi_value ret {nullptr};
604
605 if (argc == MAX_START_BG_RUNNING_PARAMS) {
606 ret = StartBackgroundRunningAsync(env, argv, MAX_START_BG_RUNNING_PARAMS - 1, asyncCallbackInfo, isThrow);
607 } else {
608 ret = StartBackgroundRunningPromise(env, asyncCallbackInfo, isThrow);
609 }
610 callbackPtr.release();
611 if (ret == nullptr) {
612 BGTASK_LOGE("ret is nullpter");
613 if (asyncCallbackInfo != nullptr) {
614 delete asyncCallbackInfo;
615 asyncCallbackInfo = nullptr;
616 }
617 ret = WrapVoidToJS(env);
618 }
619 return ret;
620 }
621
StopBackgroundRunningCheckParam(napi_env env,AsyncCallbackInfo * asyncCallbackInfo,bool isThrow)622 bool StopBackgroundRunningCheckParam(napi_env env, AsyncCallbackInfo *asyncCallbackInfo, bool isThrow)
623 {
624 if (asyncCallbackInfo == nullptr) {
625 BGTASK_LOGE("asyncCallbackInfo is nullptr");
626 return false;
627 }
628 if (asyncCallbackInfo->abilityContext == nullptr) {
629 BGTASK_LOGE("ability context is null");
630 Common::HandleParamErr(env, ERR_CONTEXT_NULL_OR_TYPE_ERR, isThrow);
631 asyncCallbackInfo->errCode = ERR_CONTEXT_NULL_OR_TYPE_ERR;
632 return false;
633 }
634 const std::shared_ptr<AppExecFwk::AbilityInfo> info = asyncCallbackInfo->abilityContext->GetAbilityInfo();
635 if (info == nullptr) {
636 BGTASK_LOGE("abilityInfo is null");
637 Common::HandleParamErr(env, ERR_ABILITY_INFO_EMPTY, isThrow);
638 asyncCallbackInfo->errCode = ERR_ABILITY_INFO_EMPTY;
639 return false;
640 }
641
642 sptr<IRemoteObject> token = asyncCallbackInfo->abilityContext->GetToken();
643 if (!token) {
644 BGTASK_LOGE("get ability token info failed");
645 Common::HandleParamErr(env, ERR_GET_TOKEN_ERR, isThrow);
646 asyncCallbackInfo->errCode = ERR_GET_TOKEN_ERR;
647 return false;
648 }
649 return true;
650 }
651
StopBackgroundRunningExecuteCB(napi_env env,void * data)652 void StopBackgroundRunningExecuteCB(napi_env env, void *data)
653 {
654 HitraceScoped traceScoped(HITRACE_TAG_OHOS,
655 "BackgroundTaskManager::ContinuousTask::Napi::StopBackgroundRunningExecuteCB");
656 AsyncCallbackInfo *asyncCallbackInfo = static_cast<AsyncCallbackInfo *>(data);
657 if (asyncCallbackInfo == nullptr || asyncCallbackInfo->errCode != ERR_OK) {
658 BGTASK_LOGE("input param error");
659 return;
660 }
661 const std::shared_ptr<AppExecFwk::AbilityInfo> info = asyncCallbackInfo->abilityContext->GetAbilityInfo();
662 sptr<IRemoteObject> token = asyncCallbackInfo->abilityContext->GetToken();
663 int32_t abilityId = asyncCallbackInfo->abilityContext->GetAbilityRecordId();
664 asyncCallbackInfo->errCode = BackgroundTaskMgrHelper::RequestStopBackgroundRunning(info->name, token, abilityId);
665 }
666
StopBackgroundRunningAsync(napi_env env,napi_value * argv,const uint32_t argCallback,AsyncCallbackInfo * asyncCallbackInfo,bool isThrow)667 napi_value StopBackgroundRunningAsync(napi_env env, napi_value *argv,
668 const uint32_t argCallback, AsyncCallbackInfo *asyncCallbackInfo, bool isThrow)
669 {
670 if (argv == nullptr || asyncCallbackInfo == nullptr) {
671 BGTASK_LOGE("param is nullptr");
672 return nullptr;
673 }
674 if (isThrow && asyncCallbackInfo->errCode != ERR_OK) {
675 return nullptr;
676 }
677 napi_value resourceName {nullptr};
678 NAPI_CALL(env, napi_create_string_latin1(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
679
680 napi_valuetype valuetype = napi_undefined;
681 NAPI_CALL(env, napi_typeof(env, argv[argCallback], &valuetype));
682 if (valuetype == napi_function) {
683 NAPI_CALL(env, napi_create_reference(env, argv[argCallback], 1, &asyncCallbackInfo->callback));
684 }
685 if (!StopBackgroundRunningCheckParam(env, asyncCallbackInfo, isThrow) && isThrow) {
686 return nullptr;
687 }
688
689 NAPI_CALL(env, napi_create_async_work(env,
690 nullptr,
691 resourceName,
692 StopBackgroundRunningExecuteCB,
693 CallbackCompletedCB,
694 static_cast<void *>(asyncCallbackInfo),
695 &asyncCallbackInfo->asyncWork));
696 NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork));
697 return WrapVoidToJS(env);
698 }
699
StopBackgroundRunningPromise(napi_env env,AsyncCallbackInfo * asyncCallbackInfo,bool isThrow)700 napi_value StopBackgroundRunningPromise(napi_env env, AsyncCallbackInfo *asyncCallbackInfo, bool isThrow)
701 {
702 if (asyncCallbackInfo == nullptr) {
703 BGTASK_LOGE("param is nullptr");
704 return nullptr;
705 }
706 napi_value resourceName {nullptr};
707 napi_create_string_latin1(env, __func__, NAPI_AUTO_LENGTH, &resourceName);
708 napi_deferred deferred;
709 napi_value promise {nullptr};
710 napi_create_promise(env, &deferred, &promise);
711
712 asyncCallbackInfo->deferred = deferred;
713 if (!StopBackgroundRunningCheckParam(env, asyncCallbackInfo, isThrow) && isThrow) {
714 return nullptr;
715 }
716
717 napi_create_async_work(
718 env,
719 nullptr,
720 resourceName,
721 StopBackgroundRunningExecuteCB,
722 PromiseCompletedCB,
723 static_cast<void *>(asyncCallbackInfo),
724 &asyncCallbackInfo->asyncWork);
725 napi_queue_async_work(env, asyncCallbackInfo->asyncWork);
726 return promise;
727 }
728
StopBackgroundRunning(napi_env env,napi_callback_info info,bool isThrow)729 napi_value StopBackgroundRunning(napi_env env, napi_callback_info info, bool isThrow)
730 {
731 HitraceScoped traceScoped(HITRACE_TAG_OHOS,
732 "BackgroundTaskManager::ContinuousTask::Napi::StopBackgroundRunning");
733 ReportXPowerJsStackSysEventByType(env, "CONTINUOUS_TASK_CANCEL");
734 AsyncCallbackInfo *asyncCallbackInfo = new (std::nothrow) AsyncCallbackInfo(env);
735 if (asyncCallbackInfo == nullptr) {
736 BGTASK_LOGE("asyncCallbackInfo is nullpter");
737 return WrapVoidToJS(env);
738 }
739 std::unique_ptr<AsyncCallbackInfo> callbackPtr {asyncCallbackInfo};
740
741 size_t argc = MAX_STOP_BG_RUNNING_PARAMS;
742 napi_value argv[MAX_STOP_BG_RUNNING_PARAMS] = {nullptr};
743
744 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
745 if (argc > MAX_STOP_BG_RUNNING_PARAMS) {
746 BGTASK_LOGE("wrong param nums");
747 Common::HandleParamErr(env, ERR_PARAM_NUMBER_ERR, isThrow);
748 return nullptr;
749 }
750
751 // argv[0] : context : AbilityContext
752 if (GetAbilityContext(env, argv[0], asyncCallbackInfo->abilityContext) == nullptr) {
753 BGTASK_LOGE("Get ability context failed");
754 Common::HandleParamErr(env, ERR_CONTEXT_NULL_OR_TYPE_ERR, isThrow);
755 asyncCallbackInfo->errCode = ERR_CONTEXT_NULL_OR_TYPE_ERR;
756 return nullptr;
757 }
758
759 napi_value ret {nullptr};
760 if (argc == MAX_STOP_BG_RUNNING_PARAMS) {
761 ret = StopBackgroundRunningAsync(env, argv, MAX_STOP_BG_RUNNING_PARAMS - 1, asyncCallbackInfo, isThrow);
762 } else {
763 ret = StopBackgroundRunningPromise(env, asyncCallbackInfo, isThrow);
764 }
765 callbackPtr.release();
766 if (ret == nullptr) {
767 BGTASK_LOGE("ret is nullpter");
768 if (asyncCallbackInfo != nullptr) {
769 delete asyncCallbackInfo;
770 asyncCallbackInfo = nullptr;
771 }
772 ret = WrapVoidToJS(env);
773 }
774 return ret;
775 }
776
777
CheckOnParam(napi_env env,uint32_t argc,napi_value argv[],int size)778 bool CheckOnParam(napi_env env, uint32_t argc, napi_value argv[], int size)
779 {
780 if (argc < ARGC_TWO) {
781 BGTASK_LOGE("wrong param nums");
782 return false;
783 }
784 // argv[0] : type
785 std::string type;
786 if (!AbilityRuntime::ConvertFromJsValue(env, argv[INDEX_ZERO], type)) {
787 BGTASK_LOGE("type must be string");
788 return false;
789 }
790 if (type != "continuousTaskCancel") {
791 BGTASK_LOGE("type must be continuousTaskCancel");
792 return false;
793 }
794 // arg[1] : callback
795 if (!CheckTypeForNapiValue(env, argv[INDEX_ONE], napi_function)) {
796 return false;
797 }
798 return true;
799 }
800
OnOnContinuousTaskCancel(napi_env env,napi_callback_info info)801 napi_value OnOnContinuousTaskCancel(napi_env env, napi_callback_info info)
802 {
803 size_t argc = ARGC_TWO;
804 napi_value argv[ARGC_TWO] = {nullptr};
805 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
806 if (!CheckOnParam(env, argc, argv, ARGC_TWO)) {
807 Common::HandleParamErr(env, ERR_BGTASK_INVALID_PARAM, true);
808 return WrapUndefinedToJS(env);
809 }
810
811 if (backgroundTaskSubscriber_ == nullptr) {
812 backgroundTaskSubscriber_ = std::make_shared<JsBackgroundTaskSubscriber>(env);
813 if (backgroundTaskSubscriber_ == nullptr) {
814 BGTASK_LOGE("ret is nullptr");
815 Common::HandleErrCode(env, ERR_BGTASK_SERVICE_INNER_ERROR, true);
816 return WrapUndefinedToJS(env);
817 }
818 }
819 if (backgroundTaskSubscriber_->IsEmpty()) {
820 ErrCode errCode = BackgroundTaskMgrHelper::SubscribeBackgroundTask(*backgroundTaskSubscriber_);
821 if (errCode != ERR_OK) {
822 BGTASK_LOGE("SubscribeBackgroundTask failed.");
823 Common::HandleErrCode(env, errCode, true);
824 return WrapUndefinedToJS(env);
825 }
826 }
827 backgroundTaskSubscriber_->AddJsObserverObject(argv[INDEX_ONE]);
828 backgroundTaskSubscriber_->SubscriberBgtaskSaStatusChange();
829 return WrapUndefinedToJS(env);
830 }
831
CheckOffParam(napi_env env,uint32_t argc,napi_value argv[],int size)832 bool CheckOffParam(napi_env env, uint32_t argc, napi_value argv[], int size)
833 {
834 if (argc < ARGC_ONE) {
835 BGTASK_LOGE("wrong param nums < 1");
836 return false;
837 }
838
839 // argv[0] : type
840 std::string type;
841 if (!AbilityRuntime::ConvertFromJsValue(env, argv[INDEX_ZERO], type)) {
842 BGTASK_LOGE("type must be string");
843 return false;
844 }
845 if (type != "continuousTaskCancel") {
846 BGTASK_LOGE("type must be continuousTaskCancel");
847 return false;
848 }
849 // arg[1] : callback
850 if (argc == ARGC_TWO) {
851 if (!CheckTypeForNapiValue(env, argv[INDEX_ONE], napi_function)) {
852 return false;
853 }
854 }
855 return true;
856 }
857
OffOnContinuousTaskCancel(napi_env env,napi_callback_info info)858 napi_value OffOnContinuousTaskCancel(napi_env env, napi_callback_info info)
859 {
860 size_t argc = ARGC_TWO;
861 napi_value argv[ARGC_TWO] = {nullptr};
862 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
863 if (!CheckOffParam(env, argc, argv, ARGC_TWO)) {
864 Common::HandleParamErr(env, ERR_BGTASK_INVALID_PARAM, true);
865 return WrapUndefinedToJS(env);
866 }
867 if (!backgroundTaskSubscriber_) {
868 BGTASK_LOGD("backgroundTaskSubscriber_ is null, return");
869 return WrapUndefinedToJS(env);
870 }
871 if (argc == ARGC_ONE) {
872 backgroundTaskSubscriber_->RemoveAllJsObserverObjects();
873 } else if (argc == ARGC_TWO) {
874 backgroundTaskSubscriber_->RemoveJsObserverObject(argv[INDEX_ONE]);
875 }
876
877 if (backgroundTaskSubscriber_->IsEmpty()) {
878 ErrCode errCode = BackgroundTaskMgrHelper::UnsubscribeBackgroundTask(*backgroundTaskSubscriber_);
879 if (errCode != ERR_OK) {
880 BGTASK_LOGE("UnsubscribeBackgroundTask failed.");
881 Common::HandleErrCode(env, errCode, true);
882 return WrapUndefinedToJS(env);
883 }
884 backgroundTaskSubscriber_->UnSubscriberBgtaskSaStatusChange();
885 backgroundTaskSubscriber_ = nullptr;
886 }
887 return WrapUndefinedToJS(env);
888 }
889
StartBackgroundRunning(napi_env env,napi_callback_info info)890 napi_value StartBackgroundRunning(napi_env env, napi_callback_info info)
891 {
892 return StartBackgroundRunning(env, info, false);
893 }
894
StopBackgroundRunning(napi_env env,napi_callback_info info)895 napi_value StopBackgroundRunning(napi_env env, napi_callback_info info)
896 {
897 return StopBackgroundRunning(env, info, false);
898 }
899
StartBackgroundRunningThrow(napi_env env,napi_callback_info info)900 napi_value StartBackgroundRunningThrow(napi_env env, napi_callback_info info)
901 {
902 return StartBackgroundRunning(env, info, true);
903 }
904
UpdateBackgroundRunningThrow(napi_env env,napi_callback_info info)905 napi_value UpdateBackgroundRunningThrow(napi_env env, napi_callback_info info)
906 {
907 return UpdateBackgroundRunning(env, info, true);
908 }
909
StopBackgroundRunningThrow(napi_env env,napi_callback_info info)910 napi_value StopBackgroundRunningThrow(napi_env env, napi_callback_info info)
911 {
912 return StopBackgroundRunning(env, info, true);
913 }
914 } // namespace BackgroundTaskMgr
915 } // namespace OHOS