• 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 "js_work_scheduler_extension_context.h"
17 
18 #include "js_extension_context.h"
19 #include "js_runtime.h"
20 #include "js_runtime_utils.h"
21 #include "js_error_utils.h"
22 #include "napi/native_api.h"
23 #include "napi_common_want.h"
24 #include "napi_common_util.h"
25 
26 namespace OHOS {
27 namespace WorkScheduler {
28 namespace {
29 using namespace OHOS::AbilityRuntime;
30 constexpr size_t ARGC_ONE = 1;
31 constexpr size_t INDEX_ZERO = 0;
32 class JsWorkSchedulerExtensionContext final {
33 public:
JsWorkSchedulerExtensionContext(const std::shared_ptr<WorkSchedulerExtensionContext> & context)34     explicit JsWorkSchedulerExtensionContext(const std::shared_ptr<WorkSchedulerExtensionContext>& context)
35         : context_(context) {}
36     ~JsWorkSchedulerExtensionContext() = default;
37 
Finalizer(napi_env env,void * data,void * hint)38     static void Finalizer(napi_env env, void* data, void* hint)
39     {
40         std::unique_ptr<JsWorkSchedulerExtensionContext>(
41             static_cast<JsWorkSchedulerExtensionContext*>(data));
42     }
43 
StartServiceExtensionAbility(napi_env env,napi_callback_info info)44     static napi_value StartServiceExtensionAbility(napi_env env, napi_callback_info info)
45     {
46         GET_NAPI_INFO_AND_CALL(env, info, JsWorkSchedulerExtensionContext, OnStartExtensionAbility);
47     }
48 
StopServiceExtensionAbility(napi_env env,napi_callback_info info)49     static napi_value StopServiceExtensionAbility(napi_env env, napi_callback_info info)
50     {
51         GET_NAPI_INFO_AND_CALL(env, info, JsWorkSchedulerExtensionContext, OnStopExtensionAbility);
52     }
53 
OnStartExtensionAbility(napi_env env,NapiCallbackInfo & info)54     napi_value OnStartExtensionAbility(napi_env env, NapiCallbackInfo& info)
55     {
56         WS_HILOGI("called");
57         if (info.argc < ARGC_ONE) {
58             WS_HILOGE("invalid argc");
59             ThrowTooFewParametersError(env);
60             return CreateJsUndefined(env);
61         }
62         AAFwk::Want want;
63         if (!AppExecFwk::UnwrapWant(env, info.argv[INDEX_ZERO], want)) {
64             ThrowInvalidParamError(env, "Parse param want failed, must be a Want.");
65             return CreateJsUndefined(env);
66         }
67         WS_HILOGI("%{public}s", want.ToString().c_str());
68         napi_value lastParam = (info.argc <= ARGC_ONE) ? nullptr : info.argv[ARGC_ONE];
69         napi_value result = nullptr;
70         std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
71         auto asyncTask = [weak = context_, want, env, task = napiAsyncTask.get()]() {
72             auto context = weak.lock();
73             if (!context) {
74                 WS_HILOGE("context released");
75                 task->Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
76                 return;
77             }
78             auto innerErrorCode = context->StartServiceExtensionAbility(want);
79             if (innerErrorCode == 0) {
80                 WS_HILOGI("OK");
81                 task->Resolve(env, CreateJsUndefined(env));
82             } else {
83                 WS_HILOGE("failed");
84                 task->Reject(env, CreateJsErrorByNativeErr(env, innerErrorCode));
85             }
86         };
87         if (napi_status::napi_ok != napi_send_event(env, asyncTask, napi_eprio_immediate)) {
88             napiAsyncTask->Reject(env, CreateJsErrorByNativeErr(
89                 env, static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INNER), "send event failed"));
90         } else {
91             napiAsyncTask.release();
92         }
93         return result;
94     }
95 
OnStopExtensionAbility(napi_env env,NapiCallbackInfo & info)96     napi_value OnStopExtensionAbility(napi_env env, NapiCallbackInfo& info)
97     {
98         WS_HILOGI("called");
99         if (info.argc < ARGC_ONE) {
100             WS_HILOGE("invalid argc");
101             ThrowTooFewParametersError(env);
102             return CreateJsUndefined(env);
103         }
104         AAFwk::Want want;
105         if (!AppExecFwk::UnwrapWant(env, info.argv[INDEX_ZERO], want)) {
106             ThrowInvalidParamError(env, "Parse param want failed, must be a Want.");
107             return CreateJsUndefined(env);
108         }
109         WS_HILOGI("%{public}s", want.ToString().c_str());
110         napi_value lastParam = (info.argc <= ARGC_ONE) ? nullptr : info.argv[ARGC_ONE];
111         napi_value result = nullptr;
112         std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
113         auto asyncTask = [weak = context_, want, env, task = napiAsyncTask.get()]() {
114             auto context = weak.lock();
115             if (!context) {
116                 WS_HILOGE("context released");
117                 task->Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
118                 return;
119             }
120             auto innerErrorCode = context->StopServiceExtensionAbility(want);
121             if (innerErrorCode == 0) {
122                 task->Resolve(env, CreateJsUndefined(env));
123             } else {
124                 task->Reject(env, CreateJsErrorByNativeErr(env, innerErrorCode));
125             }
126         };
127         if (napi_status::napi_ok != napi_send_event(env, asyncTask, napi_eprio_immediate)) {
128             napiAsyncTask->Reject(env, CreateJsErrorByNativeErr(
129                 env, static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INNER), "send event failed"));
130         } else {
131             napiAsyncTask.release();
132         }
133         return result;
134     }
135 
136 private:
137     std::weak_ptr<WorkSchedulerExtensionContext> context_;
138 };
139 } // namespace
140 
CreateJsWorkSchedulerExtensionContext(napi_env env,std::shared_ptr<WorkSchedulerExtensionContext> context)141 napi_value CreateJsWorkSchedulerExtensionContext(napi_env env,
142     std::shared_ptr<WorkSchedulerExtensionContext> context)
143 {
144     napi_value objValue = AbilityRuntime::CreateJsExtensionContext(env, context);
145 
146     std::unique_ptr<JsWorkSchedulerExtensionContext> jsContext =
147         std::make_unique<JsWorkSchedulerExtensionContext>(context);
148     napi_status status = napi_wrap(env, objValue, jsContext.release(), JsWorkSchedulerExtensionContext::Finalizer,
149         nullptr, nullptr);
150     if (status != napi_ok) {
151         WS_HILOGE("JsWorkSchedulerExtensionContext failed to wrap the object");
152         return nullptr;
153     }
154     const char *moduleName = "JsWorkSchedulerExtensionContext";
155     BindNativeFunction(env, objValue, "startServiceExtensionAbility", moduleName,
156         JsWorkSchedulerExtensionContext::StartServiceExtensionAbility);
157     BindNativeFunction(env, objValue, "stopServiceExtensionAbility", moduleName,
158         JsWorkSchedulerExtensionContext::StopServiceExtensionAbility);
159     return objValue;
160 }
161 } // namespace WorkScheduler
162 } // namespace OHOS