From 0c3922bd41453bfef83ee036d13d595cda33f71d Mon Sep 17 00:00:00 2001 From: whezzz Date: Sat, 14 Feb 2026 13:51:12 +0800 Subject: [PATCH] Set JsEnvironmentCallback::OnConfigurationUpdated callback to barrier Signed-off-by: whezzz --- .../context/environment_callback.cpp | 23 ++- .../BUILD.gn | 56 ++++++ .../js_environment_callback_test.cpp | 167 ++++++++++++++++++ 3 files changed, 233 insertions(+), 13 deletions(-) create mode 100644 test/unittest/frameworks_kits_appkit_native_test/js_environment_callback_test.cpp diff --git a/frameworks/native/appkit/ability_runtime/context/environment_callback.cpp b/frameworks/native/appkit/ability_runtime/context/environment_callback.cpp index 002757253e..3307e95432 100755 --- a/frameworks/native/appkit/ability_runtime/context/environment_callback.cpp +++ b/frameworks/native/appkit/ability_runtime/context/environment_callback.cpp @@ -61,20 +61,17 @@ void JsEnvironmentCallback::CallConfigurationUpdatedInner(const std::string &met void JsEnvironmentCallback::OnConfigurationUpdated(const AppExecFwk::Configuration &config) { std::weak_ptr thisWeakPtr(shared_from_this()); - std::unique_ptr complete = std::make_unique( - [thisWeakPtr, config, callbacks = callbacks_, callbacksSync = callbacksSync_] - (napi_env env, NapiAsyncTask &task, int32_t status) { - std::shared_ptr jsEnvCallback = thisWeakPtr.lock(); - if (jsEnvCallback) { - jsEnvCallback->CallConfigurationUpdatedInner("onConfigurationUpdated", config, callbacks); - jsEnvCallback->CallConfigurationUpdatedInner("onConfigurationUpdated", config, callbacksSync); - } + auto callbacks = callbacks_; + auto callbacksSync = callbacksSync_; + // When vsync_first is enabled, events marked with napi_barrier_need are + // treated as barriers and will execute *before* the next vsync. + napi_send_event(env_, [thisWeakPtr, config, callbacks, callbacksSync]() { + std::shared_ptr jsEnvCallback = thisWeakPtr.lock(); + if (jsEnvCallback) { + jsEnvCallback->CallConfigurationUpdatedInner("onConfigurationUpdated", config, callbacks); + jsEnvCallback->CallConfigurationUpdatedInner("onConfigurationUpdated", config, callbacksSync); } - ); - napi_ref callback = nullptr; - std::unique_ptr execute = nullptr; - NapiAsyncTask::ScheduleLowQos("JsEnvironmentCallback::OnConfigurationUpdated", - env_, std::make_unique(callback, std::move(execute), std::move(complete))); + }, napi_eprio_low, "JsEnvironmentCallback::OnConfigurationUpdated", napi_barrier_need); } void JsEnvironmentCallback::CallMemoryLevelInner(const std::string &methodName, const int level, diff --git a/test/unittest/frameworks_kits_appkit_native_test/BUILD.gn b/test/unittest/frameworks_kits_appkit_native_test/BUILD.gn index 7aaaf067c0..07a246d15c 100644 --- a/test/unittest/frameworks_kits_appkit_native_test/BUILD.gn +++ b/test/unittest/frameworks_kits_appkit_native_test/BUILD.gn @@ -1270,6 +1270,61 @@ ohos_unittest("startup_manager_mock_test") { ] } +ohos_unittest("js_environment_callback_test") { + module_out_path = module_output_path + + include_dirs = [ + "${ability_runtime_services_path}/common/include", + "${ability_runtime_test_path}/mock/common/include", + ] + + sources = [ + "js_environment_callback_test.cpp", + ] + + configs = [ ":module_private_config" ] + + deps = [ + "${ability_runtime_innerkits_path}/ability_manager:ability_manager", + "${ability_runtime_innerkits_path}/app_manager:app_manager", + "${ability_runtime_innerkits_path}/deps_wrapper:ability_deps_wrapper", + "${ability_runtime_innerkits_path}/runtime:runtime", + "${ability_runtime_native_path}/ability/native:ability_thread", + "${ability_runtime_native_path}/ability/native:abilitykit_native", + "${ability_runtime_native_path}/ability/native:abilitykit_utils", + "${ability_runtime_native_path}/ability/native:configuration_helper", + "${ability_runtime_native_path}/ability/native:uiabilitykit_native", + "${ability_runtime_native_path}/appkit:app_context", + "${ability_runtime_native_path}/appkit:appkit_manager_helper", + "${ability_runtime_native_path}/appkit:appkit_native", + "${ability_runtime_path}/js_environment/frameworks/js_environment:js_environment", + ] + + external_deps = [ + "ability_base:base", + "ability_base:configuration", + "ability_base:extractortool", + "ability_base:want", + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "common_event_service:cesfwk_innerkits", + "eventhandler:libeventhandler", + "ffrt:libffrt", + "form_fwk:fmskit_native", + "googletest:gtest_main", + "hilog:libhilog", + "hitrace:hitrace_meter", + "init:libbegetutil", + "ipc:ipc_core", + "napi:ace_napi", + "resource_management:global_resmgr", + "resource_management:librawfile", + "samgr:samgr_proxy", + "runtime_core:ani", + ] +} + ############################################################################### group("unittest") { @@ -1297,6 +1352,7 @@ group("unittest") { ":extension_plugin_info_test", ":form_extension_context_test", ":idle_time_test", + ":js_environment_callback_test", ":native_lib_util_test", ":overlay_event_subscriber_test", ":startup_manager_mock_test", diff --git a/test/unittest/frameworks_kits_appkit_native_test/js_environment_callback_test.cpp b/test/unittest/frameworks_kits_appkit_native_test/js_environment_callback_test.cpp new file mode 100644 index 0000000000..bb3872bdfc --- /dev/null +++ b/test/unittest/frameworks_kits_appkit_native_test/js_environment_callback_test.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2026 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 + +#include "configuration.h" +#include "environment_callback.h" +#include "global_configuration_key.h" +#include "hilog_tag_wrapper.h" +#include "js_runtime.h" +#include "js_runtime_utils.h" +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "native_engine/native_engine.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AbilityRuntime; +using namespace AAFwk; + +namespace { +constexpr int32_t TEST_MEMORY_LEVEL = 1; +} + +class JsEnvironmentCallbackTest : public testing::Test { +public: + static void SetUpTestCase() {} + static void TearDownTestCase() {} + void SetUp() override; + void TearDown() override; + +protected: + std::unique_ptr jsRuntime_ = nullptr; + napi_env env_ = nullptr; + std::shared_ptr jsEnvCallback_ = nullptr; +}; + +void JsEnvironmentCallbackTest::SetUp() +{ + JsRuntime::Options options; + jsRuntime_ = JsRuntime::Create(options); + ASSERT_NE(jsRuntime_, nullptr); + env_ = jsRuntime_->GetNapiEnv(); + ASSERT_NE(env_, nullptr); + jsEnvCallback_ = std::make_shared(env_); + ASSERT_NE(jsEnvCallback_, nullptr); +} + +void JsEnvironmentCallbackTest::TearDown() +{ + jsEnvCallback_ = nullptr; + jsRuntime_.reset(); +} + +napi_value TestCallback(napi_env env, napi_callback_info info) +{ + return nullptr; +} + +/** + * @tc.name: JsEnvironmentCallback_OnConfigurationUpdated_001 + * @tc.desc: Test OnConfigurationUpdated with valid config and registered callback + * @tc.type: FUNC + */ +HWTEST_F(JsEnvironmentCallbackTest, JsEnvironmentCallback_OnConfigurationUpdated_001, Function | MediumTest | Level1) +{ + TAG_LOGI(AAFwkTag::APPKIT, "JsEnvironmentCallback_OnConfigurationUpdated_001 start"); + napi_value callback = nullptr; + napi_create_function(env_, "testCallback", NAPI_AUTO_LENGTH, TestCallback, nullptr, &callback); + ASSERT_NE(callback, nullptr); + + int32_t callbackId = jsEnvCallback_->Register(callback, false); + EXPECT_GE(callbackId, 0); + + AppExecFwk::Configuration config; + config.AddItem(0, GlobalConfigurationKey::SYSTEM_LANGUAGE, "zh-CN"); + jsEnvCallback_->OnConfigurationUpdated(config); + + EXPECT_FALSE(jsEnvCallback_->IsEmpty()); + TAG_LOGI(AAFwkTag::APPKIT, "JsEnvironmentCallback_OnConfigurationUpdated_001 end"); +} + +/** + * @tc.name: JsEnvironmentCallback_OnConfigurationUpdated_002 + * @tc.desc: Test OnConfigurationUpdated with sync callback + * @tc.type: FUNC + */ +HWTEST_F(JsEnvironmentCallbackTest, JsEnvironmentCallback_OnConfigurationUpdated_002, Function | MediumTest | Level1) +{ + TAG_LOGI(AAFwkTag::APPKIT, "JsEnvironmentCallback_OnConfigurationUpdated_002 start"); + napi_value callback = nullptr; + napi_create_function(env_, "testCallback", NAPI_AUTO_LENGTH, TestCallback, nullptr, &callback); + ASSERT_NE(callback, nullptr); + + int32_t callbackId = jsEnvCallback_->Register(callback, true); + EXPECT_GE(callbackId, 0); + + AppExecFwk::Configuration config; + config.AddItem(0, GlobalConfigurationKey::SYSTEM_LANGUAGE, "en-US"); + jsEnvCallback_->OnConfigurationUpdated(config); + + EXPECT_FALSE(jsEnvCallback_->IsEmpty()); + TAG_LOGI(AAFwkTag::APPKIT, "JsEnvironmentCallback_OnConfigurationUpdated_002 end"); +} + +/** + * @tc.name: JsEnvironmentCallback_OnConfigurationUpdated_003 + * @tc.desc: Test OnConfigurationUpdated with both sync and async callbacks + * @tc.type: FUNC + */ +HWTEST_F(JsEnvironmentCallbackTest, JsEnvironmentCallback_OnConfigurationUpdated_003, Function | MediumTest | Level1) +{ + TAG_LOGI(AAFwkTag::APPKIT, "JsEnvironmentCallback_OnConfigurationUpdated_003 start"); + napi_value callback = nullptr; + napi_create_function(env_, "testCallback", NAPI_AUTO_LENGTH, TestCallback, nullptr, &callback); + ASSERT_NE(callback, nullptr); + + int32_t asyncCallbackId = jsEnvCallback_->Register(callback, false); + EXPECT_GE(asyncCallbackId, 0); + + int32_t syncCallbackId = jsEnvCallback_->Register(callback, true); + EXPECT_GE(syncCallbackId, 0); + + AppExecFwk::Configuration config; + config.AddItem(0, "ohos.application.direction", "1"); + jsEnvCallback_->OnConfigurationUpdated(config); + + EXPECT_FALSE(jsEnvCallback_->IsEmpty()); + TAG_LOGI(AAFwkTag::APPKIT, "JsEnvironmentCallback_OnConfigurationUpdated_003 end"); +} + +/** + * @tc.name: JsEnvironmentCallback_OnConfigurationUpdated_004 + * @tc.desc: Test OnConfigurationUpdated when callback is destroyed (weak_ptr lock fails) + * @tc.type: FUNC + */ +HWTEST_F(JsEnvironmentCallbackTest, JsEnvironmentCallback_OnConfigurationUpdated_004, Function | MediumTest | Level1) +{ + TAG_LOGI(AAFwkTag::APPKIT, "JsEnvironmentCallback_OnConfigurationUpdated_004 start"); + auto testCallback = std::make_shared(env_); + ASSERT_NE(testCallback, nullptr); + + napi_value callback = nullptr; + napi_create_function(env_, "testCallback", NAPI_AUTO_LENGTH, TestCallback, nullptr, &callback); + ASSERT_NE(callback, nullptr); + + int32_t callbackId = testCallback->Register(callback, false); + EXPECT_GE(callbackId, 0); + + AppExecFwk::Configuration config; + testCallback->OnConfigurationUpdated(config); + + testCallback = nullptr; + TAG_LOGI(AAFwkTag::APPKIT, "JsEnvironmentCallback_OnConfigurationUpdated_004 end"); +} \ No newline at end of file