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