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, &notificationId);
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