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         NapiAsyncTask::CompleteCallback complete =
69             [weak = context_, want](napi_env env, NapiAsyncTask& task, int32_t status) {
70                 auto context = weak.lock();
71                 if (!context) {
72                     WS_HILOGE("context released");
73                     task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
74                     return;
75                 }
76                 auto innerErrorCode = context->StartServiceExtensionAbility(want);
77                 if (innerErrorCode == 0) {
78                     WS_HILOGI("OK");
79                     task.Resolve(env, CreateJsUndefined(env));
80                 } else {
81                     WS_HILOGE("failed");
82                     task.Reject(env, CreateJsErrorByNativeErr(env, innerErrorCode));
83                 }
84             };
85 
86         napi_value lastParam = (info.argc <= ARGC_ONE) ? nullptr : info.argv[ARGC_ONE];
87         napi_value result = nullptr;
88         NapiAsyncTask::ScheduleHighQos("JSWorkSchedulerExtensionContext::OnStartExtensionAbility",
89             env, CreateAsyncTaskWithLastParam(env, lastParam, nullptr, std::move(complete), &result));
90         return result;
91     }
92 
OnStopExtensionAbility(napi_env env,NapiCallbackInfo & info)93     napi_value OnStopExtensionAbility(napi_env env, NapiCallbackInfo& info)
94     {
95         WS_HILOGI("called");
96         if (info.argc < ARGC_ONE) {
97             WS_HILOGE("invalid argc");
98             ThrowTooFewParametersError(env);
99             return CreateJsUndefined(env);
100         }
101         AAFwk::Want want;
102         if (!AppExecFwk::UnwrapWant(env, info.argv[INDEX_ZERO], want)) {
103             ThrowInvalidParamError(env, "Parse param want failed, must be a Want.");
104             return CreateJsUndefined(env);
105         }
106         WS_HILOGI("%{public}s", want.ToString().c_str());
107         NapiAsyncTask::CompleteCallback complete =
108             [weak = context_, want](napi_env env, NapiAsyncTask& task, int32_t status) {
109                 auto context = weak.lock();
110                 if (!context) {
111                     WS_HILOGE("context released");
112                     task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
113                     return;
114                 }
115                 auto innerErrorCode = context->StopServiceExtensionAbility(want);
116                 if (innerErrorCode == 0) {
117                     task.Resolve(env, CreateJsUndefined(env));
118                 } else {
119                     task.Reject(env, CreateJsErrorByNativeErr(env, innerErrorCode));
120                 }
121             };
122 
123         napi_value lastParam = (info.argc <= ARGC_ONE) ? nullptr : info.argv[ARGC_ONE];
124         napi_value result = nullptr;
125         NapiAsyncTask::Schedule("JSWorkSchedulerExtensionContext::OnStopExtensionAbility",
126             env, CreateAsyncTaskWithLastParam(env, lastParam, nullptr, std::move(complete), &result));
127         return result;
128     }
129 
130 private:
131     std::weak_ptr<WorkSchedulerExtensionContext> context_;
132 };
133 } // namespace
134 
CreateJsWorkSchedulerExtensionContext(napi_env env,std::shared_ptr<WorkSchedulerExtensionContext> context)135 napi_value CreateJsWorkSchedulerExtensionContext(napi_env env,
136     std::shared_ptr<WorkSchedulerExtensionContext> context)
137 {
138     napi_value objValue = AbilityRuntime::CreateJsExtensionContext(env, context);
139 
140     std::unique_ptr<JsWorkSchedulerExtensionContext> jsContext =
141         std::make_unique<JsWorkSchedulerExtensionContext>(context);
142     napi_status status = napi_wrap(env, objValue, jsContext.release(), JsWorkSchedulerExtensionContext::Finalizer,
143         nullptr, nullptr);
144     if (status != napi_ok) {
145         WS_HILOGE("JsWorkSchedulerExtensionContext failed to wrap the object");
146         return nullptr;
147     }
148     const char *moduleName = "JsWorkSchedulerExtensionContext";
149     BindNativeFunction(env, objValue, "startServiceExtensionAbility", moduleName,
150         JsWorkSchedulerExtensionContext::StartServiceExtensionAbility);
151     BindNativeFunction(env, objValue, "stopServiceExtensionAbility", moduleName,
152         JsWorkSchedulerExtensionContext::StopServiceExtensionAbility);
153     return objValue;
154 }
155 } // namespace WorkScheduler
156 } // namespace OHOS