1 /*
2 * Copyright (c) 2023 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_media_control_extension_context.h"
17
18 #include <cstdint>
19
20 #include "event_handler.h"
21 #include "hilog_wrapper.h"
22 #include "js_extension_context.h"
23 #include "js_error_utils.h"
24 #include "js_data_struct_converter.h"
25 #include "js_runtime.h"
26 #include "js_runtime_utils.h"
27 #include "napi/native_api.h"
28 #include "napi_common_ability.h"
29 #include "napi_common_want.h"
30 #include "napi_common_util.h"
31 #include "napi_common_start_options.h"
32 #include "start_options.h"
33 #include "hitrace_meter.h"
34
35 namespace OHOS {
36 namespace AbilityRuntime {
37 namespace {
38 constexpr int32_t INDEX_ZERO = 0;
39 constexpr int32_t ERROR_CODE_ONE = 1;
40 constexpr size_t ARGC_ZERO = 0;
41 constexpr size_t ARGC_ONE = 1;
42 } // namespace
43
44 static std::shared_ptr<AppExecFwk::EventHandler> handler_ = nullptr;
45
Finalizer(NativeEngine * engine,void * data,void * hint)46 void JsMediaControlExtensionContext::Finalizer(NativeEngine* engine, void* data, void* hint)
47 {
48 HILOG_DEBUG("JsMediaControlExtensionContext Finalizer is called");
49 std::unique_ptr<JsMediaControlExtensionContext>(static_cast<JsMediaControlExtensionContext*>(data));
50 }
51
StartAbility(NativeEngine * engine,NativeCallbackInfo * info)52 NativeValue *JsMediaControlExtensionContext::StartAbility(NativeEngine* engine, NativeCallbackInfo* info)
53 {
54 JsMediaControlExtensionContext* me = CheckParamsAndGetThis<JsMediaControlExtensionContext>(engine, info);
55 return (me != nullptr) ? me->OnStartAbility(*engine, *info) : nullptr;
56 }
57
TerminateSelf(NativeEngine * engine,NativeCallbackInfo * info)58 NativeValue *JsMediaControlExtensionContext::TerminateSelf(NativeEngine* engine, NativeCallbackInfo* info)
59 {
60 JsMediaControlExtensionContext* me = CheckParamsAndGetThis<JsMediaControlExtensionContext>(engine, info);
61 return (me != nullptr) ? me->OnTerminateSelf(*engine, *info) : nullptr;
62 }
63
TerminateSelfWithResult(NativeEngine * engine,NativeCallbackInfo * info)64 NativeValue* JsMediaControlExtensionContext::TerminateSelfWithResult(NativeEngine* engine, NativeCallbackInfo* info)
65 {
66 JsMediaControlExtensionContext* me = CheckParamsAndGetThis<JsMediaControlExtensionContext>(engine, info);
67 return (me != nullptr) ? me->OnTerminateSelfWithResult(*engine, *info) : nullptr;
68 }
69
OnStartAbility(NativeEngine & engine,NativeCallbackInfo & info)70 NativeValue *JsMediaControlExtensionContext::OnStartAbility(NativeEngine& engine, NativeCallbackInfo& info)
71 {
72 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
73 HILOG_DEBUG("OnStartAbility is called");
74 if (info.argc < ARGC_ONE) {
75 HILOG_ERROR("Start ability failed, not enough params.");
76 ThrowTooFewParametersError(engine);
77 return engine.CreateUndefined();
78 }
79
80 size_t unwrapArgc = 0;
81 AAFwk::Want want;
82 AAFwk::StartOptions startOptions;
83 if (!CheckStartAbilityInputParam(engine, info, want, startOptions, unwrapArgc)) {
84 ThrowError(engine, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
85 return engine.CreateUndefined();
86 }
87
88 AsyncTask::CompleteCallback complete =
89 [weak = context_, want, startOptions, unwrapArgc](NativeEngine& engine, AsyncTask& task, int32_t status) {
90 HILOG_DEBUG("startAbility begin");
91 auto context = weak.lock();
92 if (!context) {
93 HILOG_ERROR("context is released");
94 task.Reject(engine, CreateJsError(engine, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
95 return;
96 }
97
98 ErrCode innerErrorCode = ERR_OK;
99 (unwrapArgc == 1) ? innerErrorCode = context->StartAbility(want) :
100 innerErrorCode = context->StartAbility(want, startOptions);
101 if (innerErrorCode == 0) {
102 task.Resolve(engine, engine.CreateUndefined());
103 } else {
104 task.Reject(engine, CreateJsErrorByNativeErr(engine, innerErrorCode));
105 }
106 };
107
108 NativeValue* lastParam = (info.argc == unwrapArgc) ? nullptr : info.argv[unwrapArgc];
109 NativeValue* result = nullptr;
110 AsyncTask::Schedule("JSMediaControlExtensionContext OnStartAbility",
111 engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
112 return result;
113 }
114
OnTerminateSelf(NativeEngine & engine,const NativeCallbackInfo & info)115 NativeValue *JsMediaControlExtensionContext::OnTerminateSelf(NativeEngine& engine, const NativeCallbackInfo& info)
116 {
117 HILOG_DEBUG("OnTerminateSelf is called");
118 AsyncTask::CompleteCallback complete =
119 [weak = context_](NativeEngine& engine, AsyncTask& task, int32_t status) {
120 auto context = weak.lock();
121 if (!context) {
122 HILOG_ERROR("context is released");
123 task.Reject(engine, CreateJsError(engine, ERROR_CODE_ONE, "Context is released"));
124 return;
125 }
126
127 ErrCode innerErrorCode = context->TerminateSelf();
128 if (innerErrorCode == 0) {
129 task.Resolve(engine, engine.CreateUndefined());
130 } else {
131 task.Reject(engine, CreateJsErrorByNativeErr(engine, innerErrorCode));
132 }
133 };
134
135 NativeValue* lastParam = (info.argc == ARGC_ZERO) ? nullptr : info.argv[INDEX_ZERO];
136 NativeValue* result = nullptr;
137 AsyncTask::Schedule("JSMediaControlExtensionContext OnTerminateSelf",
138 engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
139 return result;
140 }
141
OnTerminateSelfWithResult(NativeEngine & engine,const NativeCallbackInfo & info)142 NativeValue* JsMediaControlExtensionContext::OnTerminateSelfWithResult(NativeEngine& engine,
143 const NativeCallbackInfo& info)
144 {
145 HILOG_INFO("OnTerminateSelfWithResult is called");
146
147 if (info.argc == 0) {
148 HILOG_ERROR("Not enough params");
149 ThrowTooFewParametersError(engine);
150 return engine.CreateUndefined();
151 }
152
153 int resultCode = 0;
154 AAFwk::Want want;
155 if (!JsMediaControlExtensionContext::UnWrapAbilityResult(engine, info.argv[0], resultCode, want)) {
156 HILOG_ERROR("OnTerminateSelfWithResult Failed to parse ability result!");
157 ThrowError(engine, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
158 return engine.CreateUndefined();
159 }
160
161 AsyncTask::CompleteCallback complete =
162 [weak = context_, want, resultCode](NativeEngine& engine, AsyncTask& task, int32_t status) {
163 auto context = weak.lock();
164 if (!context) {
165 HILOG_WARN("context is released");
166 task.Reject(engine, CreateJsError(engine, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
167 return;
168 }
169
170 auto errorCode = context->TerminateSelf();
171 if (errorCode == 0) {
172 task.Resolve(engine, engine.CreateUndefined());
173 } else {
174 task.Reject(engine, CreateJsErrorByNativeErr(engine, errorCode));
175 }
176 };
177
178 NativeValue* lastParam = (info.argc > ARGC_ONE) ? info.argv[1] : nullptr;
179 NativeValue* result = nullptr;
180 AsyncTask::Schedule("JsMediaControlExtensionContext::OnTerminateSelfWithResult",
181 engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
182 HILOG_INFO("OnTerminateSelfWithResult is called end");
183 return result;
184 }
185
CreateJsMediaControlExtensionContext(NativeEngine & engine,std::shared_ptr<MediaControlExtensionContext> context)186 NativeValue *JsMediaControlExtensionContext::CreateJsMediaControlExtensionContext(NativeEngine& engine,
187 std::shared_ptr<MediaControlExtensionContext> context)
188 {
189 HILOG_DEBUG("CreateJsMediaControlExtensionContext begin");
190 std::shared_ptr<OHOS::AppExecFwk::AbilityInfo> abilityInfo = nullptr;
191 if (context) {
192 abilityInfo = context->GetAbilityInfo();
193 }
194 NativeValue* objValue = CreateJsExtensionContext(engine, context, abilityInfo);
195 NativeObject* object = ConvertNativeValueTo<NativeObject>(objValue);
196
197 std::unique_ptr<JsMediaControlExtensionContext> jsContext =
198 std::make_unique<JsMediaControlExtensionContext>(context);
199 object->SetNativePointer(jsContext.release(), Finalizer, nullptr);
200
201 // make handler
202 handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
203
204 const char *moduleName = "JsMediaControlExtensionContext";
205 BindNativeFunction(engine, *object, "startAbility", moduleName, StartAbility);
206 BindNativeFunction(engine, *object, "terminateSelf", moduleName, TerminateSelf);
207 BindNativeFunction(engine, *object, "terminateSelfWithResult", moduleName, TerminateSelfWithResult);
208
209 return objValue;
210 }
211
CheckStartAbilityInputParam(NativeEngine & engine,NativeCallbackInfo & info,AAFwk::Want & want,AAFwk::StartOptions & startOptions,size_t & unwrapArgc) const212 bool JsMediaControlExtensionContext::CheckStartAbilityInputParam(NativeEngine& engine, NativeCallbackInfo& info,
213 AAFwk::Want& want, AAFwk::StartOptions& startOptions, size_t& unwrapArgc) const
214 {
215 if (info.argc < ARGC_ONE) {
216 return false;
217 }
218 unwrapArgc = ARGC_ZERO;
219
220 // Check input want
221 if (!CheckWantParam(engine, info.argv[INDEX_ZERO], want)) {
222 return false;
223 }
224 ++unwrapArgc;
225 if (info.argc > ARGC_ONE && info.argv[1]->TypeOf() == NATIVE_OBJECT) {
226 AppExecFwk::UnwrapStartOptions(reinterpret_cast<napi_env>(&engine),
227 reinterpret_cast<napi_value>(info.argv[1]), startOptions);
228 unwrapArgc++;
229 }
230 return true;
231 }
232
CheckWantParam(NativeEngine & engine,NativeValue * value,AAFwk::Want & want) const233 bool JsMediaControlExtensionContext::CheckWantParam(NativeEngine& engine, NativeValue* value, AAFwk::Want& want) const
234 {
235 if (!OHOS::AppExecFwk::UnwrapWant(reinterpret_cast<napi_env>(&engine),
236 reinterpret_cast<napi_value>(value), want)) {
237 HILOG_ERROR("The input want is invalid.");
238 return false;
239 }
240 HILOG_DEBUG("UnwrapWant, BundleName: %{public}s, AbilityName: %{public}s.", want.GetBundle().c_str(),
241 want.GetElement().GetAbilityName().c_str());
242 return true;
243 }
244
UnWrapWant(NativeEngine & engine,NativeValue * argv,AAFwk::Want & want)245 bool JsMediaControlExtensionContext::UnWrapWant(NativeEngine& engine, NativeValue* argv, AAFwk::Want& want)
246 {
247 if (argv == nullptr) {
248 HILOG_WARN("UnWrapWant argv == nullptr!");
249 return false;
250 }
251 return AppExecFwk::UnwrapWant(reinterpret_cast<napi_env>(&engine), reinterpret_cast<napi_value>(argv), want);
252 }
253
UnWrapAbilityResult(NativeEngine & engine,NativeValue * argv,int & resultCode,AAFwk::Want & want)254 bool JsMediaControlExtensionContext::UnWrapAbilityResult(NativeEngine& engine, NativeValue* argv, int& resultCode,
255 AAFwk::Want& want)
256 {
257 if (argv == nullptr) {
258 HILOG_WARN("UnWrapAbilityResult argv == nullptr!");
259 return false;
260 }
261 if (argv->TypeOf() != NativeValueType::NATIVE_OBJECT) {
262 HILOG_WARN("UnWrapAbilityResult invalid type of abilityResult!");
263 return false;
264 }
265 NativeObject* jObj = ConvertNativeValueTo<NativeObject>(argv);
266 NativeValue* jResultCode = jObj->GetProperty("resultCode");
267 if (jResultCode == nullptr) {
268 HILOG_WARN("UnWrapAbilityResult jResultCode == nullptr!");
269 return false;
270 }
271 if (jResultCode->TypeOf() != NativeValueType::NATIVE_NUMBER) {
272 HILOG_WARN("UnWrapAbilityResult invalid type of resultCode!");
273 return false;
274 }
275 resultCode = int64_t(*ConvertNativeValueTo<NativeNumber>(jObj->GetProperty("resultCode")));
276 NativeValue* jWant = jObj->GetProperty("want");
277 if (jWant == nullptr) {
278 HILOG_WARN("UnWrapAbilityResult jWant == nullptr!");
279 return false;
280 }
281 if (jWant->TypeOf() != NativeValueType::NATIVE_OBJECT) {
282 HILOG_WARN("UnWrapAbilityResult invalid type of want!");
283 return false;
284 }
285 return JsMediaControlExtensionContext::UnWrapWant(engine, jWant, want);
286 }
287 } // namespace AbilityRuntime
288 } // namespace OHOS
289