From 059fef744b14382d5d84fb1a468c75265841589e Mon Sep 17 00:00:00 2001 From: lidongrui Date: Thu, 25 Dec 2025 17:45:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BE=9BUIAbility=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E5=BC=80=E5=A7=8B=E5=90=AF=E5=8A=A8=E6=97=B6=E9=97=B4=E7=9A=84?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=20new=20Signed-off-by:=20lidongrui=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I7f6f1363b0ccd137fa952fea938af148ffc603da --- .../src/ets_data_struct_converter.cpp | 11 ++ .../ets/@ohos.app.ability.AbilityConstant.ets | 4 + .../runtime/js_data_struct_converter.cpp | 2 + .../ability_manager/include/launch_param.h | 4 +- .../abilitymgr/include/utils/ability_util.h | 9 + services/abilitymgr/src/ability_record.cpp | 2 + services/abilitymgr/src/launch_param.cpp | 15 +- test/unittest/launch_param_test/Build.gn | 65 +++++++ .../launch_param_test/launch_param_test.cpp | 167 ++++++++++++++++++ 9 files changed, 276 insertions(+), 3 deletions(-) create mode 100644 test/unittest/launch_param_test/Build.gn create mode 100644 test/unittest/launch_param_test/launch_param_test.cpp diff --git a/frameworks/ets/ani/ani_common/src/ets_data_struct_converter.cpp b/frameworks/ets/ani/ani_common/src/ets_data_struct_converter.cpp index fd52ed2ea3..7f8b74356a 100644 --- a/frameworks/ets/ani/ani_common/src/ets_data_struct_converter.cpp +++ b/frameworks/ets/ani/ani_common/src/ets_data_struct_converter.cpp @@ -15,6 +15,7 @@ #include "ets_data_struct_converter.h" +#include "ani_common_util.h" #include "ani_enum_convert.h" #include "hilog_tag_wrapper.h" #include "running_process_info.h" @@ -142,6 +143,16 @@ bool WrapLaunchParamInner(ani_env *env, const AAFwk::LaunchParam &launchParam, a TAG_LOGE(AAFwkTag::ETSRUNTIME, "Failed to set lastExitDetailInfo"); return false; } + if ((status = env->Object_SetPropertyByName_Ref(object, "launchUptime", + AppExecFwk::CreateLong(env, launchParam.launchUptime))) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Failed to set launchUptime"); + return false; + } + if ((status = env->Object_SetPropertyByName_Ref(object, "launchUTCTime", + AppExecFwk::CreateLong(env, launchParam.launchUTCTime))) != ANI_OK) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Failed to set launchUTCTime"); + return false; + } return true; } } // namespace diff --git a/frameworks/ets/ets/@ohos.app.ability.AbilityConstant.ets b/frameworks/ets/ets/@ohos.app.ability.AbilityConstant.ets index 7e3c3cd58d..7e26194f88 100644 --- a/frameworks/ets/ets/@ohos.app.ability.AbilityConstant.ets +++ b/frameworks/ets/ets/@ohos.app.ability.AbilityConstant.ets @@ -25,6 +25,8 @@ namespace AbilityConstant { lastExitReason: LastExitReason; lastExitMessage: string; lastExitDetailInfo?: LastExitDetailInfo; + launchUptime?: long; + launchUTCTime?: long; } export interface LastExitDetailInfo { @@ -126,6 +128,8 @@ class LaunchParamImpl implements AbilityConstant.LaunchParam { lastExitReason: AbilityConstant.LastExitReason = AbilityConstant.LastExitReason.UNKNOWN; lastExitMessage: string = ''; lastExitDetailInfo?: AbilityConstant.LastExitDetailInfo = undefined; + launchUptime?: long = 0; + launchUTCTime?: long = 0; } class LastExitDetailInfoImpl implements AbilityConstant.LastExitDetailInfo { diff --git a/frameworks/native/runtime/js_data_struct_converter.cpp b/frameworks/native/runtime/js_data_struct_converter.cpp index 4b15f0300e..c3eb844c31 100644 --- a/frameworks/native/runtime/js_data_struct_converter.cpp +++ b/frameworks/native/runtime/js_data_struct_converter.cpp @@ -103,6 +103,8 @@ napi_value CreateJsLaunchParam(napi_env env, const AAFwk::LaunchParam& launchPar napi_set_named_property(env, object, "lastExitMessage", CreateJsValue(env, launchParam.lastExitMessage)); napi_set_named_property(env, object, "lastExitDetailInfo", CreateLastExitDetailInfo( env, launchParam.lastExitDetailInfo)); + napi_set_named_property(env, object, "launchUptime", CreateJsValue(env, launchParam.launchUptime)); + napi_set_named_property(env, object, "launchUTCTime", CreateJsValue(env, launchParam.launchUTCTime)); return object; } diff --git a/interfaces/inner_api/ability_manager/include/launch_param.h b/interfaces/inner_api/ability_manager/include/launch_param.h index 35245f54cc..0e00315b59 100644 --- a/interfaces/inner_api/ability_manager/include/launch_param.h +++ b/interfaces/inner_api/ability_manager/include/launch_param.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2023 Huawei Device Co., Ltd. + * Copyright (c) 2021-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 @@ -81,6 +81,8 @@ struct LaunchParam : public Parcelable { std::string launchReasonMessage = ""; std::string lastExitMessage = ""; LastExitDetailInfo lastExitDetailInfo; + int64_t launchUptime = 0; + int64_t launchUTCTime = 0; bool ReadFromParcel(Parcel &parcel); virtual bool Marshalling(Parcel &parcel) const override; diff --git a/services/abilitymgr/include/utils/ability_util.h b/services/abilitymgr/include/utils/ability_util.h index 8281a83829..720f3ba972 100644 --- a/services/abilitymgr/include/utils/ability_util.h +++ b/services/abilitymgr/include/utils/ability_util.h @@ -169,6 +169,15 @@ static constexpr int64_t MICROSECONDS = 1000000; // MICROSECONDS mean 10^6 mi return (int64_t)(t.tv_sec); } +[[maybe_unused]] static int64_t UTCTimeMillis() +{ + struct timespec t; + t.tv_sec = 0; + t.tv_nsec = 0; + clock_gettime(CLOCK_REALTIME, &t); + return static_cast(t.tv_sec * 1000LL + t.tv_nsec / 1000000LL); +} + [[maybe_unused]] static bool IsStartFreeInstall(const Want &want) { auto flags = want.GetFlags(); diff --git a/services/abilitymgr/src/ability_record.cpp b/services/abilitymgr/src/ability_record.cpp index 8c41051e83..7a721becc8 100644 --- a/services/abilitymgr/src/ability_record.cpp +++ b/services/abilitymgr/src/ability_record.cpp @@ -279,6 +279,8 @@ int AbilityRecord::LoadAbility(bool isShellCall, bool isStartupHide, pid_t calli HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__); TAG_LOGI(AAFwkTag::ABILITYMGR, "LoadLifecycle: abilityName:%{public}s", abilityInfo_.name.c_str()); startTime_ = AbilityUtil::SystemTimeMillis(); + lifeCycleStateInfo_.launchParam.launchUptime = startTime_; + lifeCycleStateInfo_.launchParam.launchUTCTime = AbilityUtil::UTCTimeMillis(); CHECK_POINTER_AND_RETURN(token_, ERR_INVALID_VALUE); // only for UIAbility if (!IsDebug() && abilityInfo_.type != AppExecFwk::AbilityType::DATA) { diff --git a/services/abilitymgr/src/launch_param.cpp b/services/abilitymgr/src/launch_param.cpp index faa2059b8e..396c1ff0ed 100644 --- a/services/abilitymgr/src/launch_param.cpp +++ b/services/abilitymgr/src/launch_param.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024 Huawei Device Co., Ltd. + * Copyright (c) 2021-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 @@ -42,7 +42,8 @@ bool LaunchParam::ReadFromParcel(Parcel &parcel) return false; } lastExitDetailInfo = *detailInfo; - + launchUptime = parcel.ReadInt64(); + launchUTCTime = parcel.ReadInt64(); return true; } @@ -83,6 +84,16 @@ bool LaunchParam::Marshalling(Parcel &parcel) const TAG_LOGE(AAFwkTag::ABILITYMGR, "write lastExitDetailInfo failed"); return false; } + // write launchUptime + if (!parcel.WriteInt64(launchUptime)) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "write launchUptime failed"); + return false; + } + // write launchUTCTime + if (!parcel.WriteInt64(launchUTCTime)) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "write launchUTCTime failed"); + return false; + } return true; } } // namespace AAFwk diff --git a/test/unittest/launch_param_test/Build.gn b/test/unittest/launch_param_test/Build.gn new file mode 100644 index 0000000000..f6c535585a --- /dev/null +++ b/test/unittest/launch_param_test/Build.gn @@ -0,0 +1,65 @@ +# Copyright (c) 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. + +import("//build/test.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +module_output_path = "ability_runtime/ability_runtime/abilitymgr" + +ohos_unittest("launch_param_test") { + module_out_path = module_output_path + + include_dirs = [ + "${ability_runtime_services_path}/abilitymgr/include", + "${ability_runtime_innerkits_path}/ability_manager/include", + ] + + sources = [ + "${ability_runtime_services_path}/abilitymgr/src/last_exit_detail_info.cpp", + "${ability_runtime_services_path}/abilitymgr/src/launch_param.cpp", + "launch_param_test.cpp", + ] + + configs = [ "${ability_runtime_services_path}/abilitymgr:abilityms_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_services_path}/abilitymgr:abilityms", + "${ability_runtime_services_path}/common:perm_verification", + "${ability_runtime_test_path}/mock/services_abilitymgr_test/libs/aakit:aakit_mock", + ] + + external_deps = [ + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "common_event_service:cesfwk_innerkits", + "eventhandler:libeventhandler", + "ffrt:libffrt", + "googletest:gmock_main", + "googletest:gtest_main", + "hilog:libhilog", + "hisysevent:libhisysevent", + "init:libbegetutil", + "ipc:ipc_core", + "safwk:api_cache_manager", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":launch_param_test" ] +} diff --git a/test/unittest/launch_param_test/launch_param_test.cpp b/test/unittest/launch_param_test/launch_param_test.cpp new file mode 100644 index 0000000000..a58b2a952f --- /dev/null +++ b/test/unittest/launch_param_test/launch_param_test.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (c) 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 +#include "gmock/gmock.h" + +#define private public +#define protected public +#include "launch_param.h" +#undef private +#undef protected + +using namespace testing; +using namespace testing::ext; + +namespace OHOS { +namespace AAFwk { +class LaunchParamTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void LaunchParamTest::SetUpTestCase() +{ +} + +void LaunchParamTest::TearDownTestCase() +{ +} + +void LaunchParamTest::SetUp() +{ +} + +void LaunchParamTest::TearDown() +{ +} + +/** + * @tc.number: LaunchParamTest_Marshalling_001 + * @tc.desc: Test LaunchParam Marshalling with valid data + * @tc.type: FUNC + */ +HWTEST_F(LaunchParamTest, LaunchParamTest_Marshalling_001, TestSize.Level1) +{ + Parcel parcel; + LaunchParam launchParam; + launchParam.launchReason = LaunchReason::LAUNCHREASON_START_ABILITY; + launchParam.lastExitReason = LastExitReason::LASTEXITREASON_NORMAL; + launchParam.launchReasonMessage = "Test launch reason"; + launchParam.lastExitMessage = "Test exit message"; + launchParam.lastExitDetailInfo.pid = 5523; + launchParam.lastExitDetailInfo.uid = 520; + launchParam.lastExitDetailInfo.exitSubReason = 1; + launchParam.lastExitDetailInfo.rss = 0; + launchParam.lastExitDetailInfo.pss = 0; + launchParam.lastExitDetailInfo.processState = 1; + launchParam.lastExitDetailInfo.timestamp = 0; + launchParam.lastExitDetailInfo.processName = "launch_process"; + launchParam.lastExitDetailInfo.exitMsg = "exit message"; + launchParam.launchUptime = 0; + launchParam.launchUTCTime = 0; + EXPECT_TRUE(launchParam.Marshalling(parcel)); +} + +/** + * @tc.number: LaunchParam_Unmarshalling_001 + * @tc.desc: Test Unmarshalling with valid data + * @tc.type: FUNC + */ +HWTEST_F(LaunchParamTest, LaunchParam_Unmarshalling_001, TestSize.Level1) +{ + Parcel parcel; + LaunchParam launchParam; + launchParam.launchReason = LaunchReason::LAUNCHREASON_CALL; + launchParam.lastExitReason = LastExitReason::LASTEXITREASON_CPP_CRASH; + launchParam.launchReasonMessage = "call reason"; + launchParam.lastExitMessage = "crash message"; + launchParam.lastExitDetailInfo.pid = 5523; + launchParam.lastExitDetailInfo.uid = 520; + launchParam.lastExitDetailInfo.processName = "crash_process"; + launchParam.lastExitDetailInfo.exitMsg = "cpp crash"; + launchParam.launchUptime = 0; + launchParam.launchUTCTime = 0; + + EXPECT_TRUE(launchParam.Marshalling(parcel)); + + LaunchParam* result = LaunchParam::Unmarshalling(parcel); + ASSERT_NE(result, nullptr); + EXPECT_EQ(result->launchReason, LaunchReason::LAUNCHREASON_CALL); + EXPECT_EQ(result->lastExitReason, LastExitReason::LASTEXITREASON_CPP_CRASH); + EXPECT_EQ(result->launchReasonMessage, "call reason"); + EXPECT_EQ(result->lastExitMessage, "crash message"); + EXPECT_EQ(result->lastExitDetailInfo.pid, 5523); + EXPECT_EQ(result->lastExitDetailInfo.uid, 520); + EXPECT_EQ(result->lastExitDetailInfo.processName, "crash_process"); + EXPECT_EQ(result->lastExitDetailInfo.exitMsg, "cpp crash"); + EXPECT_EQ(result->launchUptime, 0); + EXPECT_EQ(result->launchUTCTime, 0); + delete result; +} + +/** + * @tc.number: LaunchParam_Marshalling_Unmarshalling_002 + * @tc.desc: Test complete marshalling and unmarshalling cycle + * @tc.type: FUNC + */ +HWTEST_F(LaunchParamTest, LaunchParam_Marshalling_Unmarshalling_002, TestSize.Level1) +{ + Parcel parcel; + LaunchParam original; + original.launchReason = LaunchReason::LAUNCHREASON_APP_RECOVERY; + original.lastExitReason = LastExitReason::LASTEXITREASON_JS_ERROR; + original.launchReasonMessage = "recovery message"; + original.lastExitMessage = "js error details"; + original.lastExitDetailInfo.pid = 520; + original.lastExitDetailInfo.uid = 5201314; + original.lastExitDetailInfo.exitSubReason = 1; + original.lastExitDetailInfo.rss = 666; + original.lastExitDetailInfo.pss = 888; + original.lastExitDetailInfo.processState = 1; + original.lastExitDetailInfo.timestamp = 0; + original.lastExitDetailInfo.processName = "recovery_process"; + original.lastExitDetailInfo.exitMsg = "js error occurred"; + original.launchUptime = 0; + original.launchUTCTime = 0; + + EXPECT_TRUE(original.Marshalling(parcel)); + + LaunchParam* result = LaunchParam::Unmarshalling(parcel); + ASSERT_NE(result, nullptr); + EXPECT_EQ(result->launchReason, original.launchReason); + EXPECT_EQ(result->lastExitReason, original.lastExitReason); + EXPECT_EQ(result->launchReasonMessage, original.launchReasonMessage); + EXPECT_EQ(result->lastExitMessage, original.lastExitMessage); + EXPECT_EQ(result->lastExitDetailInfo.pid, original.lastExitDetailInfo.pid); + EXPECT_EQ(result->lastExitDetailInfo.uid, original.lastExitDetailInfo.uid); + EXPECT_EQ(result->lastExitDetailInfo.exitSubReason, original.lastExitDetailInfo.exitSubReason); + EXPECT_EQ(result->lastExitDetailInfo.rss, original.lastExitDetailInfo.rss); + EXPECT_EQ(result->lastExitDetailInfo.pss, original.lastExitDetailInfo.pss); + EXPECT_EQ(result->lastExitDetailInfo.processState, original.lastExitDetailInfo.processState); + EXPECT_EQ(result->lastExitDetailInfo.timestamp, original.lastExitDetailInfo.timestamp); + EXPECT_EQ(result->lastExitDetailInfo.processName, original.lastExitDetailInfo.processName); + EXPECT_EQ(result->lastExitDetailInfo.exitMsg, original.lastExitDetailInfo.exitMsg); + EXPECT_EQ(result->launchUptime, original.launchUptime); + EXPECT_EQ(result->launchUTCTime, original.launchUTCTime); + + delete result; +} + +} // namespace AAFwk +} // namespace OHOS \ No newline at end of file