• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &notificationId);
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