• 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 "want_agent.h"
20 #include "napi_base_context.h"
21 
22 #include "background_mode.h"
23 #include "background_task_mgr_helper.h"
24 #include "bgtaskmgr_inner_errors.h"
25 #include "continuous_task_log.h"
26 #include "continuous_task_param.h"
27 
28 namespace OHOS {
29 namespace BackgroundTaskMgr {
30 namespace {
31 static constexpr uint32_t MAX_START_BG_RUNNING_PARAMS = 4;
32 static constexpr uint32_t MAX_STOP_BG_RUNNING_PARAMS = 2;
33 static constexpr uint32_t CALLBACK_RESULT_PARAMS_NUM = 2;
34 static constexpr int32_t BG_MODE_ID_BEGIN = 1;
35 static constexpr int32_t BG_MODE_ID_END = 9;
36 }
37 
38 struct AsyncCallbackInfo {
39     napi_env env {nullptr};
40     napi_ref callback {nullptr};
41     napi_async_work asyncWork {nullptr};
42     napi_deferred deferred {nullptr};
43     std::shared_ptr<AbilityRuntime::AbilityContext> abilityContext {nullptr};
44     int32_t bgMode {0};
45     AbilityRuntime::WantAgent::WantAgent *wantAgent {nullptr};
46     int errCode {0};
47 };
48 
WrapVoidToJS(napi_env env)49 napi_value WrapVoidToJS(napi_env env)
50 {
51     napi_value result = nullptr;
52     NAPI_CALL(env, napi_get_null(env, &result));
53     return result;
54 }
55 
WrapUndefinedToJS(napi_env env)56 napi_value WrapUndefinedToJS(napi_env env)
57 {
58     napi_value result = nullptr;
59     NAPI_CALL(env, napi_get_undefined(env, &result));
60     return result;
61 }
62 
GetCallbackErrorValue(napi_env env,int errCode)63 napi_value GetCallbackErrorValue(napi_env env, int errCode)
64 {
65     napi_value jsObject = nullptr;
66     napi_value jsValue = nullptr;
67     NAPI_CALL(env, napi_create_int32(env, errCode, &jsValue));
68     NAPI_CALL(env, napi_create_object(env, &jsObject));
69     NAPI_CALL(env, napi_set_named_property(env, jsObject, "code", jsValue));
70     return jsObject;
71 }
72 
GetAbilityContext(const napi_env & env,const napi_value & value,std::shared_ptr<AbilityRuntime::AbilityContext> & abilityContext)73 napi_value GetAbilityContext(const napi_env &env, const napi_value &value,
74     std::shared_ptr<AbilityRuntime::AbilityContext> &abilityContext)
75 {
76     bool stageMode = false;
77     napi_status status = OHOS::AbilityRuntime::IsStageContext(env, value, stageMode);
78     BGTASK_LOGI("is stage mode: %{public}s", stageMode ? "true" : "false");
79 
80     if (status != napi_ok || !stageMode) {
81         BGTASK_LOGI("Getting context with FA model");
82         auto ability = OHOS::AbilityRuntime::GetCurrentAbility(env);
83         if (!ability) {
84             BGTASK_LOGE("Failed to get native ability instance");
85             return nullptr;
86         }
87         abilityContext = ability->GetAbilityContext();
88         if (!abilityContext) {
89             BGTASK_LOGE("get FA model ability context failed");
90             return nullptr;
91         }
92         return WrapVoidToJS(env);
93     } else {
94         BGTASK_LOGI("Getting context with stage model");
95         auto context = AbilityRuntime::GetStageModeContext(env, value);
96         if (!context) {
97             BGTASK_LOGE("get context failed");
98             return nullptr;
99         }
100         abilityContext = AbilityRuntime::Context::ConvertTo<AbilityRuntime::AbilityContext>(context);
101         if (!abilityContext) {
102             BGTASK_LOGE("get Stage model ability context failed");
103             return nullptr;
104         }
105         return WrapVoidToJS(env);
106     }
107 }
108 
StartBackgroundRunningExecuteCB(napi_env env,void * data)109 void StartBackgroundRunningExecuteCB(napi_env env, void *data)
110 {
111     BGTASK_LOGI("begin");
112     AsyncCallbackInfo *asyncCallbackInfo = (AsyncCallbackInfo *)data;
113     if (asyncCallbackInfo == nullptr) {
114         BGTASK_LOGE("asyncCallbackInfo is nullptr");
115         return;
116     }
117     if (asyncCallbackInfo->errCode != ERR_OK) {
118         BGTASK_LOGE("input params parse failed");
119         return;
120     }
121     if (asyncCallbackInfo->abilityContext == nullptr) {
122         asyncCallbackInfo->errCode = ERR_BGTASK_INVALID_PARAM;
123         BGTASK_LOGE("abilityContext is null");
124         return;
125     }
126     const std::shared_ptr<AppExecFwk::AbilityInfo> info = asyncCallbackInfo->abilityContext->GetAbilityInfo();
127     if (info == nullptr) {
128         BGTASK_LOGE("ability info is null");
129         asyncCallbackInfo->errCode = ERR_BGTASK_INVALID_PARAM;
130         return;
131     }
132 
133     if (asyncCallbackInfo->wantAgent == nullptr) {
134         BGTASK_LOGE("wantAgent param is nullptr");
135         asyncCallbackInfo->errCode = ERR_BGTASK_INVALID_PARAM;
136         return;
137     }
138 
139     sptr<IRemoteObject> token = asyncCallbackInfo->abilityContext->GetToken();
140     if (!token) {
141         BGTASK_LOGE("get ability token info failed");
142         asyncCallbackInfo->errCode = ERR_BGTASK_INVALID_PARAM;
143         return;
144     }
145 
146     if (asyncCallbackInfo->bgMode < BG_MODE_ID_BEGIN || asyncCallbackInfo->bgMode > BG_MODE_ID_END) {
147         BGTASK_LOGE("request background mode id: %{public}d out of range", asyncCallbackInfo->bgMode);
148         asyncCallbackInfo->errCode = ERR_BGTASK_INVALID_PARAM;
149         return;
150     }
151 
152     ContinuousTaskParam taskParam = ContinuousTaskParam(true, asyncCallbackInfo->bgMode,
153         std::make_shared<AbilityRuntime::WantAgent::WantAgent>(*asyncCallbackInfo->wantAgent), info->name, token);
154     asyncCallbackInfo->errCode = BackgroundTaskMgrHelper::RequestStartBackgroundRunning(taskParam);
155 
156     BGTASK_LOGI("end");
157 }
158 
CallbackCompletedCB(napi_env env,napi_status status,void * data)159 void CallbackCompletedCB(napi_env env, napi_status status, void *data)
160 {
161     BGTASK_LOGI("begin");
162     AsyncCallbackInfo *asyncCallbackInfo = static_cast<AsyncCallbackInfo *>(data);
163     napi_value callback = 0;
164     napi_value undefined = 0;
165     napi_value result[CALLBACK_RESULT_PARAMS_NUM] = {0};
166     napi_value callResult = 0;
167     napi_get_undefined(env, &undefined);
168     if (asyncCallbackInfo->errCode == ERR_OK) {
169         result[0] = WrapUndefinedToJS(env);
170         napi_create_int32(env, 0, &result[1]);
171     } else {
172         result[1] = WrapUndefinedToJS(env);
173         result[0] = GetCallbackErrorValue(env, asyncCallbackInfo->errCode);
174     }
175 
176     napi_get_reference_value(env, asyncCallbackInfo->callback, &callback);
177     napi_call_function(env, undefined, callback, CALLBACK_RESULT_PARAMS_NUM, result, &callResult);
178 
179     if (asyncCallbackInfo->callback != nullptr) {
180         napi_delete_reference(env, asyncCallbackInfo->callback);
181     }
182     napi_delete_async_work(env, asyncCallbackInfo->asyncWork);
183     delete asyncCallbackInfo;
184     asyncCallbackInfo = nullptr;
185     BGTASK_LOGI("end");
186 }
187 
PromiseCompletedCB(napi_env env,napi_status status,void * data)188 void PromiseCompletedCB(napi_env env, napi_status status, void *data)
189 {
190     BGTASK_LOGI("begin");
191     AsyncCallbackInfo *asyncCallbackInfo = static_cast<AsyncCallbackInfo *>(data);
192     napi_value result = 0;
193     if (asyncCallbackInfo->errCode == ERR_OK) {
194         napi_create_int32(env, 0, &result);
195         napi_resolve_deferred(env, asyncCallbackInfo->deferred, result);
196     } else {
197         result = GetCallbackErrorValue(env, asyncCallbackInfo->errCode);
198         napi_reject_deferred(env, asyncCallbackInfo->deferred, result);
199     }
200 
201     napi_delete_async_work(env, asyncCallbackInfo->asyncWork);
202     delete asyncCallbackInfo;
203     asyncCallbackInfo = nullptr;
204     BGTASK_LOGI("end");
205 }
206 
StartBackgroundRunningAsync(napi_env env,napi_value * argv,const size_t argCallback,AsyncCallbackInfo * asyncCallbackInfo)207 napi_value StartBackgroundRunningAsync(
208     napi_env env, napi_value *argv, const size_t argCallback, AsyncCallbackInfo *asyncCallbackInfo)
209 {
210     BGTASK_LOGI("begin");
211     if (argv == nullptr || asyncCallbackInfo == nullptr) {
212         BGTASK_LOGE("param is nullptr");
213         return nullptr;
214     }
215     napi_value resourceName = 0;
216     NAPI_CALL(env, napi_create_string_latin1(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
217 
218     napi_valuetype valuetype = napi_undefined;
219     NAPI_CALL(env, napi_typeof(env, argv[argCallback], &valuetype));
220     NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected.");
221     NAPI_CALL(env, napi_create_reference(env, argv[argCallback], 1, &asyncCallbackInfo->callback));
222 
223     NAPI_CALL(env, napi_create_async_work(env,
224         nullptr,
225         resourceName,
226         StartBackgroundRunningExecuteCB,
227         CallbackCompletedCB,
228         (void *)asyncCallbackInfo,
229         &asyncCallbackInfo->asyncWork));
230     NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork));
231 
232     BGTASK_LOGI("end");
233     return WrapVoidToJS(env);
234 }
235 
StartBackgroundRunningPromise(napi_env env,AsyncCallbackInfo * asyncCallbackInfo)236 napi_value StartBackgroundRunningPromise(napi_env env, AsyncCallbackInfo *asyncCallbackInfo)
237 {
238     BGTASK_LOGI("begin");
239     if (asyncCallbackInfo == nullptr) {
240         BGTASK_LOGE("param is nullptr");
241         return nullptr;
242     }
243     napi_value resourceName;
244     NAPI_CALL(env, napi_create_string_latin1(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
245     napi_deferred deferred;
246     napi_value promise = 0;
247     NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));
248     asyncCallbackInfo->deferred = deferred;
249 
250     NAPI_CALL(env, napi_create_async_work(env,
251         nullptr,
252         resourceName,
253         StartBackgroundRunningExecuteCB,
254         PromiseCompletedCB,
255         (void *)asyncCallbackInfo,
256         &asyncCallbackInfo->asyncWork));
257     NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork));
258     BGTASK_LOGI("end");
259     return promise;
260 }
261 
GetBackgroundMode(const napi_env & env,const napi_value & value,int32_t & bgMode)262 napi_value GetBackgroundMode(const napi_env &env, const napi_value &value, int32_t &bgMode)
263 {
264     BGTASK_LOGI("begin");
265 
266     napi_valuetype valuetype = napi_undefined;
267     NAPI_CALL(env, napi_typeof(env, value, &valuetype));
268     NAPI_ASSERT(env, valuetype == napi_number, "Wrong argument type. Number expected.");
269     napi_get_value_int32(env, value, &bgMode);
270 
271     BGTASK_LOGI("get bgmode info: %{public}d", bgMode);
272     return WrapVoidToJS(env);
273 }
274 
GetWantAgent(const napi_env & env,const napi_value & value,AbilityRuntime::WantAgent::WantAgent * & wantAgent)275 napi_value GetWantAgent(const napi_env &env, const napi_value &value, AbilityRuntime::WantAgent::WantAgent *&wantAgent)
276 {
277     BGTASK_LOGI("begin");
278     napi_valuetype valuetype = napi_undefined;
279     NAPI_CALL(env, napi_typeof(env, value, &valuetype));
280     NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type. Object expected.");
281     napi_unwrap(env, value, (void **)&wantAgent);
282 
283     BGTASK_LOGI("end");
284     return WrapVoidToJS(env);
285 }
286 
StartBackgroundRunning(napi_env env,napi_callback_info info)287 napi_value StartBackgroundRunning(napi_env env, napi_callback_info info)
288 {
289     BGTASK_LOGI("begin");
290     AsyncCallbackInfo *asyncCallbackInfo = new (std::nothrow) AsyncCallbackInfo {.env = env};
291     if (asyncCallbackInfo == nullptr) {
292         BGTASK_LOGE("asyncCallbackInfo == nullpter");
293         return WrapVoidToJS(env);
294     }
295 
296     size_t argc = MAX_START_BG_RUNNING_PARAMS;
297     napi_value argv[MAX_START_BG_RUNNING_PARAMS] = {nullptr};
298     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
299     if (argc > MAX_START_BG_RUNNING_PARAMS) {
300         BGTASK_LOGE("wrong param nums");
301         delete asyncCallbackInfo;
302         asyncCallbackInfo = nullptr;
303         return nullptr;
304     }
305 
306     // argv[0] : context : AbilityContext
307     if (GetAbilityContext(env, argv[0], asyncCallbackInfo->abilityContext) == nullptr) {
308         BGTASK_LOGE("Get ability context failed");
309         asyncCallbackInfo->errCode = ERR_BGTASK_INVALID_PARAM;
310     }
311 
312     // argv[1] : bgMode : BackgroundMode
313     if (GetBackgroundMode(env, argv[1], asyncCallbackInfo->bgMode) == nullptr) {
314         BGTASK_LOGE("input bgmode param not number");
315         asyncCallbackInfo->errCode = ERR_BGTASK_INVALID_PARAM;
316     }
317 
318     // argv[2] : wantAgent: WantAgent
319     if (GetWantAgent(env, argv[2], asyncCallbackInfo->wantAgent) == nullptr) {
320         BGTASK_LOGE("input wantAgent param is not object");
321         asyncCallbackInfo->errCode = ERR_BGTASK_INVALID_PARAM;
322     }
323 
324     napi_value ret = 0;
325 
326     if (argc == MAX_START_BG_RUNNING_PARAMS) {
327         ret = StartBackgroundRunningAsync(env, argv, MAX_START_BG_RUNNING_PARAMS - 1, asyncCallbackInfo);
328     } else {
329         ret = StartBackgroundRunningPromise(env, asyncCallbackInfo);
330     }
331 
332     if (ret == nullptr) {
333         BGTASK_LOGE("ret is nullpter");
334         if (asyncCallbackInfo != nullptr) {
335             delete asyncCallbackInfo;
336             asyncCallbackInfo = nullptr;
337         }
338         ret = WrapVoidToJS(env);
339     }
340     BGTASK_LOGI("end");
341     return ret;
342 }
343 
StopBackgroundRunningExecuteCB(napi_env env,void * data)344 void StopBackgroundRunningExecuteCB(napi_env env, void *data)
345 {
346     BGTASK_LOGI("begin");
347     AsyncCallbackInfo *asyncCallbackInfo = static_cast<AsyncCallbackInfo *>(data);
348     if (asyncCallbackInfo == nullptr) {
349         BGTASK_LOGE("asyncCallbackInfo is nullptr");
350         return;
351     }
352     if (asyncCallbackInfo->abilityContext == nullptr) {
353         asyncCallbackInfo->errCode = ERR_BGTASK_INVALID_PARAM;
354         BGTASK_LOGE("ability context is null");
355         return;
356     }
357     const std::shared_ptr<AppExecFwk::AbilityInfo> info = asyncCallbackInfo->abilityContext->GetAbilityInfo();
358     if (info == nullptr) {
359         BGTASK_LOGE("abilityInfo is null");
360         asyncCallbackInfo->errCode = ERR_BGTASK_INVALID_PARAM;
361         return;
362     }
363 
364     sptr<IRemoteObject> token = asyncCallbackInfo->abilityContext->GetToken();
365     if (!token) {
366         BGTASK_LOGE("get ability token info failed");
367         asyncCallbackInfo->errCode = ERR_BGTASK_INVALID_PARAM;
368         return;
369     }
370     asyncCallbackInfo->errCode = BackgroundTaskMgrHelper::RequestStopBackgroundRunning(info->name, token);
371 }
372 
StopBackgroundRunningAsync(napi_env env,napi_value * argv,const size_t argCallback,AsyncCallbackInfo * asyncCallbackInfo)373 napi_value StopBackgroundRunningAsync(napi_env env, napi_value *argv,
374     const size_t argCallback, AsyncCallbackInfo *asyncCallbackInfo)
375 {
376     BGTASK_LOGI("begin");
377     if (argv == nullptr || asyncCallbackInfo == nullptr) {
378         BGTASK_LOGE("param is nullptr");
379         return nullptr;
380     }
381     napi_value resourceName = 0;
382     NAPI_CALL(env, napi_create_string_latin1(env, __func__, NAPI_AUTO_LENGTH, &resourceName));
383 
384     napi_valuetype valuetype = napi_undefined;
385     NAPI_CALL(env, napi_typeof(env, argv[argCallback], &valuetype));
386     if (valuetype == napi_function) {
387         NAPI_CALL(env, napi_create_reference(env, argv[argCallback], 1, &asyncCallbackInfo->callback));
388     }
389 
390     NAPI_CALL(env, napi_create_async_work(env,
391         nullptr,
392         resourceName,
393         StopBackgroundRunningExecuteCB,
394         CallbackCompletedCB,
395         (void *)asyncCallbackInfo,
396         &asyncCallbackInfo->asyncWork));
397     NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork));
398     BGTASK_LOGI("end");
399     return WrapVoidToJS(env);
400 }
401 
StopBackgroundRunningPromise(napi_env env,AsyncCallbackInfo * asyncCallbackInfo)402 napi_value StopBackgroundRunningPromise(napi_env env, AsyncCallbackInfo *asyncCallbackInfo)
403 {
404     BGTASK_LOGI("begin");
405     if (asyncCallbackInfo == nullptr) {
406         BGTASK_LOGE("param is nullptr");
407         return nullptr;
408     }
409     napi_value resourceName = 0;
410     napi_create_string_latin1(env, __func__, NAPI_AUTO_LENGTH, &resourceName);
411     napi_deferred deferred;
412     napi_value promise = 0;
413     napi_create_promise(env, &deferred, &promise);
414 
415     asyncCallbackInfo->deferred = deferred;
416 
417     napi_create_async_work(
418         env,
419         nullptr,
420         resourceName,
421         StopBackgroundRunningExecuteCB,
422         PromiseCompletedCB,
423         (void *)asyncCallbackInfo,
424         &asyncCallbackInfo->asyncWork);
425     napi_queue_async_work(env, asyncCallbackInfo->asyncWork);
426     BGTASK_LOGI("end");
427     return promise;
428 }
429 
StopBackgroundRunning(napi_env env,napi_callback_info info)430 napi_value StopBackgroundRunning(napi_env env, napi_callback_info info)
431 {
432     BGTASK_LOGI("begin");
433     AsyncCallbackInfo *asyncCallbackInfo = new (std::nothrow) AsyncCallbackInfo {.env = env};
434     if (asyncCallbackInfo == nullptr) {
435         BGTASK_LOGE("asyncCallbackInfo is nullpter");
436         return WrapVoidToJS(env);
437     }
438 
439     size_t argc = MAX_STOP_BG_RUNNING_PARAMS;
440     napi_value argv[MAX_STOP_BG_RUNNING_PARAMS] = {nullptr};
441 
442     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
443     if (argc > MAX_STOP_BG_RUNNING_PARAMS) {
444         BGTASK_LOGE("wrong param nums");
445         delete asyncCallbackInfo;
446         asyncCallbackInfo = nullptr;
447         return nullptr;
448     }
449 
450     // argv[0] : context : AbilityContext
451     if (GetAbilityContext(env, argv[0], asyncCallbackInfo->abilityContext) == nullptr) {
452         BGTASK_LOGE("Get ability context failed");
453         asyncCallbackInfo->errCode = ERR_BGTASK_INVALID_PARAM;
454     }
455 
456     napi_value ret = 0;
457     if (argc == MAX_STOP_BG_RUNNING_PARAMS) {
458         ret = StopBackgroundRunningAsync(env, argv, MAX_STOP_BG_RUNNING_PARAMS - 1, asyncCallbackInfo);
459     } else {
460         ret = StopBackgroundRunningPromise(env, asyncCallbackInfo);
461     }
462 
463     if (ret == nullptr) {
464         BGTASK_LOGE("ret is nullpter");
465         if (asyncCallbackInfo != nullptr) {
466             delete asyncCallbackInfo;
467             asyncCallbackInfo = nullptr;
468         }
469         ret = WrapVoidToJS(env);
470     }
471     BGTASK_LOGI("end");
472     return ret;
473 }
474 } // namespace BackgroundTaskMgr
475 }