* Copyright (c) 2023-2025 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 "ohos_js_environment_impl.h"
#include "console.h"
#include "hilog_tag_wrapper.h"
#include "js_utils.h"
#include "js_worker.h"
#include "ohos_loop_handler.h"
#include "sys_timer.h"
#include "worker_info.h"
#include "parameters.h"
namespace OHOS {
namespace AbilityRuntime {
namespace {
std::shared_ptr<AppExecFwk::EventHandler> g_eventHandler = nullptr;
}
void OHOSJsEnvironmentImpl::PostTaskToHandler(const uv_task_info_t* taskInfo)
{
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
if (!taskInfo || !taskInfo->func || !taskInfo->work) {
TAG_LOGE(AAFwkTag::JSRUNTIME, "Invalid parameters");
return;
}
auto task = [func = taskInfo->func, work = taskInfo->work, status = taskInfo->status]() {
TAG_LOGD(AAFwkTag::JSRUNTIME, "Do uv work");
func(work, status);
TAG_LOGD(AAFwkTag::JSRUNTIME, "Do uv work end");
};
AppExecFwk::EventQueue::Priority prio = AppExecFwk::EventQueue::Priority::IMMEDIATE;
switch (taskInfo->prio) {
case uv_qos_t::uv_qos_user_interactive:
prio = AppExecFwk::EventQueue::Priority::VIP;
break;
case uv_qos_t::uv_qos_user_initiated:
prio = AppExecFwk::EventQueue::Priority::IMMEDIATE;
break;
case uv_qos_t::uv_qos_utility:
prio = AppExecFwk::EventQueue::Priority::LOW;
break;
case uv_qos_t::uv_qos_background:
prio = AppExecFwk::EventQueue::Priority::IDLE;
break;
default:
prio = AppExecFwk::EventQueue::Priority::HIGH;
break;
}
if (g_eventHandler == nullptr) {
TAG_LOGE(AAFwkTag::JSRUNTIME, "Invalid parameters");
return;
}
if (taskInfo->location == UV_POST_TASK_TO_HEAD) {
g_eventHandler->PostTaskAtFront(task, taskInfo->name ? taskInfo->name : "uv_loop_task", prio);
} else {
g_eventHandler->PostTask(task, taskInfo->name ? taskInfo->name : "uv_io_cb", 0, prio);
}
}
int OHOSJsEnvironmentImpl::CheckPendingHigherEvent(int priority)
{
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
if (g_eventHandler == nullptr) {
TAG_LOGE(AAFwkTag::JSRUNTIME, "g_eventHandler is null");
return -1;
}
return g_eventHandler->HasPendingHigherEvent(priority) ? 0 : -1;
}
OHOSJsEnvironmentImpl::OHOSJsEnvironmentImpl()
{
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
}
OHOSJsEnvironmentImpl::OHOSJsEnvironmentImpl(const std::shared_ptr<AppExecFwk::EventRunner>& eventRunner)
{
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
if (eventRunner != nullptr) {
TAG_LOGD(AAFwkTag::JSRUNTIME, "Create event handler");
eventHandler_ = std::make_shared<AppExecFwk::EventHandler>(eventRunner);
if (eventRunner.get() == AppExecFwk::EventRunner::GetMainEventRunner().get()) {
g_eventHandler = std::make_shared<AppExecFwk::EventHandler>(eventRunner);
}
}
}
OHOSJsEnvironmentImpl::~OHOSJsEnvironmentImpl()
{
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
}
void OHOSJsEnvironmentImpl::PostTask(const std::function<void()>& task, const std::string& name, int64_t delayTime)
{
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
if (eventHandler_ == nullptr) {
TAG_LOGE(AAFwkTag::JSRUNTIME, "null eventHandler_");
return;
}
eventHandler_->PostTask(task, name, delayTime);
}
void OHOSJsEnvironmentImpl::PostSyncTask(const std::function<void()>& task, const std::string& name)
{
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
if (eventHandler_ != nullptr) {
eventHandler_->PostSyncTask(task, name);
}
}
void OHOSJsEnvironmentImpl::RemoveTask(const std::string& name)
{
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
if (eventHandler_ != nullptr) {
eventHandler_->RemoveTask(name);
}
}
void OHOSJsEnvironmentImpl::InitTimerModule(NativeEngine* engine)
{
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
CHECK_POINTER(engine);
auto ret = JsSysModule::Timer::RegisterTime(reinterpret_cast<napi_env>(engine));
if (!ret) {
TAG_LOGE(AAFwkTag::JSRUNTIME, "Register timer failed");
}
}
void OHOSJsEnvironmentImpl::InitConsoleModule(NativeEngine* engine)
{
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
JsSysModule::Console::InitConsoleModule(reinterpret_cast<napi_env>(engine));
}
bool OHOSJsEnvironmentImpl::InitLoop(NativeEngine* engine, bool isStage)
{
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
CHECK_POINTER_AND_RETURN(engine, false);
auto uvLoop = engine->GetUVLoop();
auto fd = uvLoop != nullptr ? uv_backend_fd(uvLoop) : -1;
if (fd < 0) {
TAG_LOGE(AAFwkTag::JSRUNTIME, "get fd failed");
return false;
}
uv_run(uvLoop, UV_RUN_NOWAIT);
if (eventHandler_ != nullptr) {
uint32_t events = AppExecFwk::FILE_DESCRIPTOR_INPUT_EVENT | AppExecFwk::FILE_DESCRIPTOR_OUTPUT_EVENT;
eventHandler_->AddFileDescriptorListener(fd, events, std::make_shared<OHOSLoopHandler>(uvLoop), "uvLoopTask");
TAG_LOGD(AAFwkTag::JSRUNTIME, "uv_register_task_to_event, isStage: %{public}d", isStage);
if (isStage && (eventHandler_->GetEventRunner()).get() == AppExecFwk::EventRunner::GetMainEventRunner().get()) {
static const bool canInterrupt = system::GetBoolParameter("persist.sys.uv_can_interrupt", true);
TAG_LOGD(AAFwkTag::JSRUNTIME, "uv_register_task_to_event with canInterrupt: %{public}d", canInterrupt);
uv_register_task_to_event(uvLoop, PostTaskToHandler, canInterrupt ? CheckPendingHigherEvent : nullptr);
uv_async_send(&uvLoop->wq_async);
}
}
return true;
}
void OHOSJsEnvironmentImpl::DeInitLoop(NativeEngine* engine)
{
CHECK_POINTER(engine);
auto uvLoop = engine->GetUVLoop();
auto fd = uvLoop != nullptr ? uv_backend_fd(uvLoop) : -1;
if (fd >= 0 && eventHandler_ != nullptr) {
eventHandler_->RemoveFileDescriptorListener(fd);
}
uv_unregister_task_to_event(uvLoop);
RemoveTask(TIMER_TASK);
}
void OHOSJsEnvironmentImpl::InitWorkerModule(NativeEngine* engine, std::shared_ptr<JsEnv::WorkerInfo> workerInfo)
{
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
CHECK_POINTER(engine);
CHECK_POINTER(workerInfo);
engine->SetInitWorkerFunc(InitWorkerFunc);
engine->SetOffWorkerFunc(OffWorkerFunc);
engine->SetReleaseWorkerSafeMemFunc(ReleaseWorkerSafeMemFunc);
engine->SetGetAssetFunc(AssetHelper(workerInfo));
engine->SetApiVersion(static_cast<int32_t>(workerInfo->apiTargetVersion.GetOriginPointer()));
engine->SetGetContainerScopeIdFunc(GetContainerId);
engine->SetInitContainerScopeFunc(UpdateContainerScope);
engine->SetFinishContainerScopeFunc(RestoreContainerScope);
}
void OHOSJsEnvironmentImpl::InitSyscapModule()
{
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
}
}
}