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