/* * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "js_media_control_extension_context.h" #include #include "event_handler.h" #include "hilog_wrapper.h" #include "js_extension_context.h" #include "js_error_utils.h" #include "js_data_struct_converter.h" #include "js_runtime.h" #include "js_runtime_utils.h" #include "napi/native_api.h" #include "napi_common_ability.h" #include "napi_common_want.h" #include "napi_common_util.h" #include "napi_common_start_options.h" #include "start_options.h" #include "hitrace_meter.h" namespace OHOS { namespace AbilityRuntime { namespace { constexpr int32_t INDEX_ZERO = 0; constexpr int32_t ERROR_CODE_ONE = 1; constexpr size_t ARGC_ZERO = 0; constexpr size_t ARGC_ONE = 1; } // namespace static std::shared_ptr handler_ = nullptr; void JsMediaControlExtensionContext::Finalizer(NativeEngine* engine, void* data, void* hint) { HILOG_DEBUG("JsMediaControlExtensionContext Finalizer is called"); std::unique_ptr(static_cast(data)); } NativeValue *JsMediaControlExtensionContext::StartAbility(NativeEngine* engine, NativeCallbackInfo* info) { JsMediaControlExtensionContext* me = CheckParamsAndGetThis(engine, info); return (me != nullptr) ? me->OnStartAbility(*engine, *info) : nullptr; } NativeValue *JsMediaControlExtensionContext::TerminateSelf(NativeEngine* engine, NativeCallbackInfo* info) { JsMediaControlExtensionContext* me = CheckParamsAndGetThis(engine, info); return (me != nullptr) ? me->OnTerminateSelf(*engine, *info) : nullptr; } NativeValue* JsMediaControlExtensionContext::TerminateSelfWithResult(NativeEngine* engine, NativeCallbackInfo* info) { JsMediaControlExtensionContext* me = CheckParamsAndGetThis(engine, info); return (me != nullptr) ? me->OnTerminateSelfWithResult(*engine, *info) : nullptr; } NativeValue *JsMediaControlExtensionContext::OnStartAbility(NativeEngine& engine, NativeCallbackInfo& info) { HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); HILOG_DEBUG("OnStartAbility is called"); if (info.argc < ARGC_ONE) { HILOG_ERROR("Start ability failed, not enough params."); ThrowTooFewParametersError(engine); return engine.CreateUndefined(); } size_t unwrapArgc = 0; AAFwk::Want want; AAFwk::StartOptions startOptions; if (!CheckStartAbilityInputParam(engine, info, want, startOptions, unwrapArgc)) { ThrowError(engine, AbilityErrorCode::ERROR_CODE_INVALID_PARAM); return engine.CreateUndefined(); } AsyncTask::CompleteCallback complete = [weak = context_, want, startOptions, unwrapArgc](NativeEngine& engine, AsyncTask& task, int32_t status) { HILOG_DEBUG("startAbility begin"); auto context = weak.lock(); if (!context) { HILOG_ERROR("context is released"); task.Reject(engine, CreateJsError(engine, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)); return; } ErrCode innerErrorCode = ERR_OK; (unwrapArgc == 1) ? innerErrorCode = context->StartAbility(want) : innerErrorCode = context->StartAbility(want, startOptions); if (innerErrorCode == 0) { task.Resolve(engine, engine.CreateUndefined()); } else { task.Reject(engine, CreateJsErrorByNativeErr(engine, innerErrorCode)); } }; NativeValue* lastParam = (info.argc == unwrapArgc) ? nullptr : info.argv[unwrapArgc]; NativeValue* result = nullptr; AsyncTask::Schedule("JSMediaControlExtensionContext OnStartAbility", engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result)); return result; } NativeValue *JsMediaControlExtensionContext::OnTerminateSelf(NativeEngine& engine, const NativeCallbackInfo& info) { HILOG_DEBUG("OnTerminateSelf is called"); AsyncTask::CompleteCallback complete = [weak = context_](NativeEngine& engine, AsyncTask& task, int32_t status) { auto context = weak.lock(); if (!context) { HILOG_ERROR("context is released"); task.Reject(engine, CreateJsError(engine, ERROR_CODE_ONE, "Context is released")); return; } ErrCode innerErrorCode = context->TerminateSelf(); if (innerErrorCode == 0) { task.Resolve(engine, engine.CreateUndefined()); } else { task.Reject(engine, CreateJsErrorByNativeErr(engine, innerErrorCode)); } }; NativeValue* lastParam = (info.argc == ARGC_ZERO) ? nullptr : info.argv[INDEX_ZERO]; NativeValue* result = nullptr; AsyncTask::Schedule("JSMediaControlExtensionContext OnTerminateSelf", engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result)); return result; } NativeValue* JsMediaControlExtensionContext::OnTerminateSelfWithResult(NativeEngine& engine, const NativeCallbackInfo& info) { HILOG_INFO("OnTerminateSelfWithResult is called"); if (info.argc == 0) { HILOG_ERROR("Not enough params"); ThrowTooFewParametersError(engine); return engine.CreateUndefined(); } int resultCode = 0; AAFwk::Want want; if (!JsMediaControlExtensionContext::UnWrapAbilityResult(engine, info.argv[0], resultCode, want)) { HILOG_ERROR("OnTerminateSelfWithResult Failed to parse ability result!"); ThrowError(engine, AbilityErrorCode::ERROR_CODE_INVALID_PARAM); return engine.CreateUndefined(); } AsyncTask::CompleteCallback complete = [weak = context_, want, resultCode](NativeEngine& engine, AsyncTask& task, int32_t status) { auto context = weak.lock(); if (!context) { HILOG_WARN("context is released"); task.Reject(engine, CreateJsError(engine, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)); return; } auto errorCode = context->TerminateSelf(); if (errorCode == 0) { task.Resolve(engine, engine.CreateUndefined()); } else { task.Reject(engine, CreateJsErrorByNativeErr(engine, errorCode)); } }; NativeValue* lastParam = (info.argc > ARGC_ONE) ? info.argv[1] : nullptr; NativeValue* result = nullptr; AsyncTask::Schedule("JsMediaControlExtensionContext::OnTerminateSelfWithResult", engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result)); HILOG_INFO("OnTerminateSelfWithResult is called end"); return result; } NativeValue *JsMediaControlExtensionContext::CreateJsMediaControlExtensionContext(NativeEngine& engine, std::shared_ptr context) { HILOG_DEBUG("CreateJsMediaControlExtensionContext begin"); std::shared_ptr abilityInfo = nullptr; if (context) { abilityInfo = context->GetAbilityInfo(); } NativeValue* objValue = CreateJsExtensionContext(engine, context, abilityInfo); NativeObject* object = ConvertNativeValueTo(objValue); std::unique_ptr jsContext = std::make_unique(context); object->SetNativePointer(jsContext.release(), Finalizer, nullptr); // make handler handler_ = std::make_shared(AppExecFwk::EventRunner::GetMainEventRunner()); const char *moduleName = "JsMediaControlExtensionContext"; BindNativeFunction(engine, *object, "startAbility", moduleName, StartAbility); BindNativeFunction(engine, *object, "terminateSelf", moduleName, TerminateSelf); BindNativeFunction(engine, *object, "terminateSelfWithResult", moduleName, TerminateSelfWithResult); return objValue; } bool JsMediaControlExtensionContext::CheckStartAbilityInputParam(NativeEngine& engine, NativeCallbackInfo& info, AAFwk::Want& want, AAFwk::StartOptions& startOptions, size_t& unwrapArgc) const { if (info.argc < ARGC_ONE) { return false; } unwrapArgc = ARGC_ZERO; // Check input want if (!CheckWantParam(engine, info.argv[INDEX_ZERO], want)) { return false; } ++unwrapArgc; if (info.argc > ARGC_ONE && info.argv[1]->TypeOf() == NATIVE_OBJECT) { AppExecFwk::UnwrapStartOptions(reinterpret_cast(&engine), reinterpret_cast(info.argv[1]), startOptions); unwrapArgc++; } return true; } bool JsMediaControlExtensionContext::CheckWantParam(NativeEngine& engine, NativeValue* value, AAFwk::Want& want) const { if (!OHOS::AppExecFwk::UnwrapWant(reinterpret_cast(&engine), reinterpret_cast(value), want)) { HILOG_ERROR("The input want is invalid."); return false; } HILOG_DEBUG("UnwrapWant, BundleName: %{public}s, AbilityName: %{public}s.", want.GetBundle().c_str(), want.GetElement().GetAbilityName().c_str()); return true; } bool JsMediaControlExtensionContext::UnWrapWant(NativeEngine& engine, NativeValue* argv, AAFwk::Want& want) { if (argv == nullptr) { HILOG_WARN("UnWrapWant argv == nullptr!"); return false; } return AppExecFwk::UnwrapWant(reinterpret_cast(&engine), reinterpret_cast(argv), want); } bool JsMediaControlExtensionContext::UnWrapAbilityResult(NativeEngine& engine, NativeValue* argv, int& resultCode, AAFwk::Want& want) { if (argv == nullptr) { HILOG_WARN("UnWrapAbilityResult argv == nullptr!"); return false; } if (argv->TypeOf() != NativeValueType::NATIVE_OBJECT) { HILOG_WARN("UnWrapAbilityResult invalid type of abilityResult!"); return false; } NativeObject* jObj = ConvertNativeValueTo(argv); NativeValue* jResultCode = jObj->GetProperty("resultCode"); if (jResultCode == nullptr) { HILOG_WARN("UnWrapAbilityResult jResultCode == nullptr!"); return false; } if (jResultCode->TypeOf() != NativeValueType::NATIVE_NUMBER) { HILOG_WARN("UnWrapAbilityResult invalid type of resultCode!"); return false; } resultCode = int64_t(*ConvertNativeValueTo(jObj->GetProperty("resultCode"))); NativeValue* jWant = jObj->GetProperty("want"); if (jWant == nullptr) { HILOG_WARN("UnWrapAbilityResult jWant == nullptr!"); return false; } if (jWant->TypeOf() != NativeValueType::NATIVE_OBJECT) { HILOG_WARN("UnWrapAbilityResult invalid type of want!"); return false; } return JsMediaControlExtensionContext::UnWrapWant(engine, jWant, want); } } // namespace AbilityRuntime } // namespace OHOS