diff --git a/hisysevent.yaml b/hisysevent.yaml index d470abb457..3f9debb713 100644 --- a/hisysevent.yaml +++ b/hisysevent.yaml @@ -511,4 +511,13 @@ USER_DATA_SIZE: PARTITION_NAME: {type: STRING, desc: name of partition} REMAIN_PARTITION_SIZE: {type: UINT64, desc: Remaining size of the partition} FILE_OR_FOLDER_PATH: {type: STRING, arrsize: 100, desc: File or folder path} - FILE_OR_FOLDER_SIZE: {type: UINT64, arrsize: 100, desc: File or folder size} \ No newline at end of file + FILE_OR_FOLDER_SIZE: {type: UINT64, arrsize: 100, desc: File or folder size} + +EXTENSION_RUNNING_TIMEOUT: + __BASE: {type: STATISTIC, level: CRITICAL, desc: extension ability running timeout} + EXTENSION_TYPE: {type: STRING, arrsize: 5, desc: extension type name list} + BUNDLE_NAME: {type: STRING, arrsize: 5, desc: bundle name list} + ABILITY_NAME: {type: STRING, arrsize: 5, desc: ability name list} + RUNNING_DURATION: {type: INT64, arrsize: 5, desc: running duration list in seconds} + STILL_ALIVE: {type: BOOL, arrsize: 5, desc: still alive flag list} + CNT: {type: INT32, arrsize: 5, desc: occurrence count list} diff --git a/services/abilitymgr/abilitymgr.gni b/services/abilitymgr/abilitymgr.gni index ea03342605..cc1e278a1a 100644 --- a/services/abilitymgr/abilitymgr.gni +++ b/services/abilitymgr/abilitymgr.gni @@ -48,6 +48,7 @@ abilityms_files = [ "src/extension_running_info.cpp", "src/extension_record/base_extension_record.cpp", "src/extension_record/extension_record_manager.cpp", + "src/extension_running_timeout_monitor.cpp", "src/extension_record/extension_record.cpp", "src/extension_record/extension_record_factory.cpp", "src/foreground_app_connection_manager/foreground_app_connection_manager.cpp", diff --git a/services/abilitymgr/include/extension_config.h b/services/abilitymgr/include/extension_config.h index ce038447af..c2e3c1b679 100644 --- a/services/abilitymgr/include/extension_config.h +++ b/services/abilitymgr/include/extension_config.h @@ -29,6 +29,7 @@ namespace OHOS { namespace AAFwk { constexpr static int32_t DEFAULT_EXTENSION_AUTO_DISCONNECT_TIME = -1; +constexpr static int32_t DEFAULT_EXTENSION_RUNNING_TIMEOUT_TIME = -1; constexpr static bool EXTENSION_NETWORK_ENABLE_FLAG_DEFAULT = true; constexpr static bool EXTENSION_SA_ENABLE_FLAG_DEFAULT = true; constexpr static bool EXTENSION_THIRD_PARTY_APP_ENABLE_FLAG_DEFAULT = true; @@ -55,6 +56,7 @@ struct ExtensionConfigItem { bool thirdPartyAppEnableFlag = EXTENSION_THIRD_PARTY_APP_ENABLE_FLAG_DEFAULT; bool serviceEnableFlag = EXTENSION_START_SERVICE_ENABLE_FLAG_DEFAULT; int32_t extensionAutoDisconnectTime = DEFAULT_EXTENSION_AUTO_DISCONNECT_TIME; + int32_t extensionRunningTimeoutTime = DEFAULT_EXTENSION_RUNNING_TIMEOUT_TIME; std::unordered_set serviceBlockedList; ScreenUnlockAccessItem screenUnlockAccess; AbilityAccessItem abilityAccess; @@ -67,6 +69,7 @@ public: virtual ~ExtensionConfig() = default; void LoadExtensionConfiguration(); int32_t GetExtensionAutoDisconnectTime(const std::string &extensionTypeName); + int32_t GetExtensionRunningTimeoutTime(const std::string &extensionTypeName); bool IsExtensionStartThirdPartyAppEnable(const std::string &extensionTypeName); bool IsExtensionStartServiceEnable(const std::string &extensionTypeName, const std::string &targetUri); bool HasAbilityAccess(const std::string &extensionTypeName); @@ -88,6 +91,7 @@ private: std::string GetExtensionConfigPath() const; void LoadExtensionAutoDisconnectTime(const nlohmann::json &object, const std::string &extensionTypeName); + void LoadExtensionRunningTimeoutTime(const nlohmann::json &object, const std::string &extensionTypeName); void LoadExtensionThirdPartyAppBlockedList(const nlohmann::json &object, std::string extensionTypeName); void LoadExtensionServiceBlockedList(const nlohmann::json &object, std::string extensionTypeNameobject); void LoadExtensionNetworkEnable(const nlohmann::json &object, const std::string &extensionTypeName); diff --git a/services/abilitymgr/include/extension_record/extension_record_manager.h b/services/abilitymgr/include/extension_record/extension_record_manager.h index 2dbb5acff8..159e16e64c 100644 --- a/services/abilitymgr/include/extension_record/extension_record_manager.h +++ b/services/abilitymgr/include/extension_record/extension_record_manager.h @@ -25,6 +25,7 @@ #include "base_extension_record.h" #include "extension_record.h" +#include "extension_running_timeout_monitor.h" #include "preload_ui_extension_execute_callback_interface.h" #include "ui_extension/ui_extension_host_info.h" #include "ui_extension/ui_extension_session_info.h" diff --git a/services/abilitymgr/include/extension_running_timeout_monitor.h b/services/abilitymgr/include/extension_running_timeout_monitor.h new file mode 100644 index 0000000000..60a0875b22 --- /dev/null +++ b/services/abilitymgr/include/extension_running_timeout_monitor.h @@ -0,0 +1,98 @@ +/* + * 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. + */ + +#ifndef OHOS_ABILITY_RUNTIME_EXTENSION_RUNNING_TIMEOUT_MONITOR_H +#define OHOS_ABILITY_RUNTIME_EXTENSION_RUNNING_TIMEOUT_MONITOR_H + +#include +#include +#include +#include + +#include "singleton.h" + +namespace OHOS { +namespace AAFwk { + +struct ExtensionTimeoutEvent { + std::string extensionTypeName; + std::string bundleName; + std::string abilityName; + int64_t runningDuration = 0; // seconds + bool stillAlive = false; + int32_t cnt = 1; +}; + +class ExtensionRunningTimeoutMonitor : public DelayedSingleton { + DECLARE_DELAYED_SINGLETON(ExtensionRunningTimeoutMonitor) +public: + /** + * @brief Called when an extension ability starts. Records start time. + */ + void OnExtensionStarted(int32_t extensionRecordId, const std::string &extensionTypeName, + const std::string &bundleName, const std::string &abilityName); + + /** + * @brief Called when an extension ability ends. Checks if it exceeded configured timeout. + */ + void OnExtensionTerminated(int32_t extensionRecordId); + + /** + * @brief Start the periodic report and check timer. Called during service init. + */ + void StartMonitor(); + + /** + * @brief Stop the periodic report and check timer. + */ + void StopMonitor(); + + /** + * @brief Report cached timeout events via HiSysEvent and clear cache. + */ + void ReportTimeoutEvents(); + + /** + * @brief Proactively check all currently alive extensions for timeout violations. + * Adds detected violations to the cached events list. + */ + void CheckAliveExtensions(); + +private: + struct ExtensionStartInfo { + std::string extensionTypeName; + std::string bundleName; + std::string abilityName; + int64_t startTimeMillis = 0; + }; + + void AddOrUpdateTimeoutEvent(const ExtensionTimeoutEvent &event); + bool IsDuplicateEvent(const ExtensionTimeoutEvent &event, + std::list::iterator &dupIter); + void SubmitPeriodicTask(); + + std::mutex monitorMutex_; + std::unordered_map runningExtensions_; + std::list cachedEvents_; + + static constexpr int32_t HISEVENT_PARAM_COUNT = 7; + static constexpr int32_t MAX_CACHED_EVENTS = 5; + static constexpr int64_t REPORT_INTERVAL_MS = 2 * 60 * 60 * 1000; // 2 hours + static constexpr const char *PERIODIC_TASK_NAME = "ExtensionTimeoutPeriodicTask"; +}; + +} // namespace AAFwk +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_EXTENSION_RUNNING_TIMEOUT_MONITOR_H diff --git a/services/abilitymgr/resource/ams_extension_config.json b/services/abilitymgr/resource/ams_extension_config.json index 6b881c5a0c..4b57e04b16 100644 --- a/services/abilitymgr/resource/ams_extension_config.json +++ b/services/abilitymgr/resource/ams_extension_config.json @@ -1,3 +1,3 @@ { "ams_extension_config": [] -} \ No newline at end of file +} diff --git a/services/abilitymgr/src/ability_connect_manager.cpp b/services/abilitymgr/src/ability_connect_manager.cpp index fcd2c7319b..d82333aa5e 100644 --- a/services/abilitymgr/src/ability_connect_manager.cpp +++ b/services/abilitymgr/src/ability_connect_manager.cpp @@ -29,6 +29,7 @@ #include "cache_extension_utils.h" #include "datetime_ex.h" #include "extension_ability_info.h" +#include "extension_running_timeout_monitor.h" #include "foreground_app_connection_manager.h" #include "global_constant.h" #include "hitrace_meter.h" @@ -283,6 +284,14 @@ int AbilityConnectManager::StopServiceAbilityLocked(const AbilityRequest &abilit void AbilityConnectManager::RemoveServiceFromMapSafe(const std::string &serviceKey) { std::lock_guard lock(serviceMapMutex_); + auto it = serviceMap_.find(serviceKey); + if (it != serviceMap_.end() && it->second != nullptr) { + auto recordId = it->second->GetRecordId(); + auto monitor = DelayedSingleton::GetInstance(); + if (monitor != nullptr) { + monitor->OnExtensionTerminated(recordId); + } + } serviceMap_.erase(serviceKey); TAG_LOGD(AAFwkTag::EXT, "ServiceMap remove, size:%{public}zu", serviceMap_.size()); } @@ -3246,6 +3255,17 @@ void AbilityConnectManager::GetOrCreateServiceRecord(const AbilityRequest &abili SetServiceAfterNewCreate(abilityRequest, *targetService); AddToServiceMap(serviceKey, targetService); isLoadedAbility = false; + + // Notify running timeout monitor about service extension start + auto &newAbilityInfo = abilityRequest.abilityInfo; + auto recordId = targetService->GetRecordId(); + auto monitor = DelayedSingleton::GetInstance(); + if (monitor != nullptr) { + monitor->OnExtensionStarted(recordId, + newAbilityInfo.extensionTypeName, + newAbilityInfo.bundleName, + newAbilityInfo.name); + } } TAG_LOGD(AAFwkTag::EXT, "service map add, serviceKey: %{public}s", serviceKey.c_str()); } diff --git a/services/abilitymgr/src/ability_manager_service.cpp b/services/abilitymgr/src/ability_manager_service.cpp index 4f95edefdf..252408c8d1 100644 --- a/services/abilitymgr/src/ability_manager_service.cpp +++ b/services/abilitymgr/src/ability_manager_service.cpp @@ -54,6 +54,7 @@ #include "hidden_start_observer_manager.h" #include "hitrace_meter.h" #include "hisysevent_report.h" +#include "extension_running_timeout_monitor.h" #include "insight_intent_execute_manager.h" #include "insight_intent_db_cache.h" #include "insight_intent_utils.h" @@ -469,6 +470,7 @@ bool AbilityManagerService::Init() modularObjectExtensionEventMgr_ = std::make_shared(); modularObjectExtensionEventMgr_->SubscribeSysEventReceiver(); ReportDataPartitionUsageManager::SendReportDataPartitionUsageEvent(); + DelayedSingleton::GetInstance()->StartMonitor(); #ifdef RESOURCE_SCHEDULE_SERVICE_ENABLE ResourceSchedule::ResSchedClient::GetInstance().InitKillReasonListener(); #endif diff --git a/services/abilitymgr/src/extension_config.cpp b/services/abilitymgr/src/extension_config.cpp index c88662809a..1484d3f5b4 100644 --- a/services/abilitymgr/src/extension_config.cpp +++ b/services/abilitymgr/src/extension_config.cpp @@ -30,6 +30,7 @@ constexpr const char* EXTENSION_CONFIG_FILE_PATH = "/etc/ams_extension_config.js constexpr const char* EXTENSION_CONFIG_NAME = "ams_extension_config"; constexpr const char* EXTENSION_TYPE_NAME = "extension_type_name"; constexpr const char* EXTENSION_AUTO_DISCONNECT_TIME = "auto_disconnect_time"; +constexpr const char* EXTENSION_RUNNING_TIMEOUT_TIME = "running_timeout_time"; // old access flag, deprecated constexpr const char* EXTENSION_THIRD_PARTY_APP_BLOCKED_FLAG_NAME = "third_party_app_blocked_flag"; @@ -128,6 +129,7 @@ void ExtensionConfig::LoadExtensionConfig(const nlohmann::json &object) std::lock_guard lock(configMapMutex_); std::string extensionTypeName = jsonObject.at(EXTENSION_TYPE_NAME).get(); LoadExtensionAutoDisconnectTime(jsonObject, extensionTypeName); + LoadExtensionRunningTimeoutTime(jsonObject, extensionTypeName); bool hasAbilityAccess = LoadExtensionAbilityAccess(jsonObject, extensionTypeName); if (!hasAbilityAccess) { LoadExtensionThirdPartyAppBlockedList(jsonObject, extensionTypeName); @@ -151,6 +153,30 @@ void ExtensionConfig::LoadExtensionAutoDisconnectTime(const nlohmann::json &obje configMap_[extensionTypeName].extensionAutoDisconnectTime = extensionAutoDisconnectTime; } +void ExtensionConfig::LoadExtensionRunningTimeoutTime(const nlohmann::json &object, + const std::string &extensionTypeName) +{ + if (!object.contains(EXTENSION_RUNNING_TIMEOUT_TIME) || + !object.at(EXTENSION_RUNNING_TIMEOUT_TIME).is_number()) { + TAG_LOGD(AAFwkTag::ABILITYMGR, "running timeout time config not set for %{public}s", + extensionTypeName.c_str()); + return; + } + int32_t extensionRunningTimeoutTime = object.at(EXTENSION_RUNNING_TIMEOUT_TIME).get(); + configMap_[extensionTypeName].extensionRunningTimeoutTime = extensionRunningTimeoutTime; + TAG_LOGI(AAFwkTag::ABILITYMGR, "extension %{public}s running timeout time: %{public}d ms", + extensionTypeName.c_str(), extensionRunningTimeoutTime); +} + +int32_t ExtensionConfig::GetExtensionRunningTimeoutTime(const std::string &extensionTypeName) +{ + std::lock_guard lock(configMapMutex_); + if (configMap_.find(extensionTypeName) != configMap_.end()) { + return configMap_[extensionTypeName].extensionRunningTimeoutTime; + } + return DEFAULT_EXTENSION_RUNNING_TIMEOUT_TIME; +} + void ExtensionConfig::LoadExtensionThirdPartyAppBlockedList(const nlohmann::json &object, std::string extensionTypeName) { diff --git a/services/abilitymgr/src/extension_record/extension_record_manager.cpp b/services/abilitymgr/src/extension_record/extension_record_manager.cpp index 506941d91d..c5702be530 100644 --- a/services/abilitymgr/src/extension_record/extension_record_manager.cpp +++ b/services/abilitymgr/src/extension_record/extension_record_manager.cpp @@ -17,6 +17,7 @@ #include "ability_util.h" #include "app_utils.h" +#include "extension_running_timeout_monitor.h" #include "preload_ui_extension_execute_callback_proxy.h" #include "preload_ui_extension_host_client.h" #include "ui_extension_record.h" @@ -89,6 +90,18 @@ void ExtensionRecordManager::AddExtensionRecord(const int32_t extensionRecordId, TAG_LOGD(AAFwkTag::ABILITYMGR, "extensionRecordId %{public}d.", extensionRecordId); std::lock_guard lock(mutex_); extensionRecords_.emplace(extensionRecordId, record); + + // Notify running timeout monitor about extension start + if (record != nullptr && record->abilityRecord_ != nullptr) { + auto &abilityInfo = record->abilityRecord_->GetAbilityInfo(); + auto monitor = DelayedSingleton::GetInstance(); + if (monitor != nullptr) { + monitor->OnExtensionStarted(extensionRecordId, + abilityInfo.extensionTypeName, + abilityInfo.bundleName, + abilityInfo.name); + } + } } void ExtensionRecordManager::RemoveExtensionRecord(const int32_t extensionRecordId) @@ -97,6 +110,12 @@ void ExtensionRecordManager::RemoveExtensionRecord(const int32_t extensionRecord std::lock_guard lock(mutex_); extensionRecords_.erase(extensionRecordId); terminateRecords_.erase(extensionRecordId); + + // Notify running timeout monitor about extension termination + auto monitor = DelayedSingleton::GetInstance(); + if (monitor != nullptr) { + monitor->OnExtensionTerminated(extensionRecordId); + } } void ExtensionRecordManager::AddExtensionRecordToTerminatedList(const int32_t extensionRecordId) diff --git a/services/abilitymgr/src/extension_running_timeout_monitor.cpp b/services/abilitymgr/src/extension_running_timeout_monitor.cpp new file mode 100644 index 0000000000..e7259fb3c0 --- /dev/null +++ b/services/abilitymgr/src/extension_running_timeout_monitor.cpp @@ -0,0 +1,311 @@ +/* + * 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 "extension_running_timeout_monitor.h" + +#include +#include +#include + +#include "extension_config.h" +#include "securec.h" +#include "hisysevent_report.h" +#include "hilog_tag_wrapper.h" +#include "task_handler_wrap.h" + +namespace OHOS { +namespace AAFwk { +namespace { +constexpr const char *DOMAIN = "AAFWK"; +constexpr const char *EVENT_NAME = "EXTENSION_RUNNING_TIMEOUT"; +constexpr const char *EXTENSION_TYPE_KEY = "EXTENSION_TYPE"; +constexpr const char *BUNDLE_NAME_KEY = "BUNDLE_NAME"; +constexpr const char *ABILITY_NAME_KEY = "ABILITY_NAME"; +constexpr const char *RUNNING_DURATION_KEY = "RUNNING_DURATION"; +constexpr const char *STILL_ALIVE_KEY = "STILL_ALIVE"; +constexpr const char *CNT_KEY = "CNT"; + +bool CopyStringParam(const std::string &str, std::vector> &buffers, + std::vector &ptrs) +{ + size_t len = str.size() + 1; + auto buf = std::make_unique(len); + if (strcpy_s(buf.get(), len, str.c_str()) != EOK) { + return false; + } + ptrs.push_back(buf.get()); + buffers.push_back(std::move(buf)); + return true; +} +} + +ExtensionRunningTimeoutMonitor::ExtensionRunningTimeoutMonitor() {} + +ExtensionRunningTimeoutMonitor::~ExtensionRunningTimeoutMonitor() {} + +void ExtensionRunningTimeoutMonitor::OnExtensionStarted(int32_t extensionRecordId, + const std::string &extensionTypeName, + const std::string &bundleName, const std::string &abilityName) +{ + TAG_LOGD(AAFwkTag::ABILITYMGR, + "recordId: %{public}d, type: %{public}s, bundle: %{public}s, ability: %{public}s", + extensionRecordId, extensionTypeName.c_str(), bundleName.c_str(), abilityName.c_str()); + + auto now = std::chrono::steady_clock::now(); + auto startTimeMillis = + std::chrono::duration_cast(now.time_since_epoch()).count(); + + ExtensionStartInfo info; + info.extensionTypeName = extensionTypeName; + info.bundleName = bundleName; + info.abilityName = abilityName; + info.startTimeMillis = startTimeMillis; + + std::lock_guard lock(monitorMutex_); + runningExtensions_[extensionRecordId] = info; +} + +void ExtensionRunningTimeoutMonitor::OnExtensionTerminated(int32_t extensionRecordId) +{ + TAG_LOGD(AAFwkTag::ABILITYMGR, "recordId: %{public}d", extensionRecordId); + + ExtensionStartInfo startInfo; + { + std::lock_guard lock(monitorMutex_); + auto it = runningExtensions_.find(extensionRecordId); + if (it == runningExtensions_.end()) { + TAG_LOGD(AAFwkTag::ABILITYMGR, "recordId %{public}d not found in running list", + extensionRecordId); + return; + } + startInfo = it->second; + runningExtensions_.erase(it); + } + + // Get configured timeout for this extension type + int32_t configuredTimeout = DelayedSingleton::GetInstance()-> + GetExtensionRunningTimeoutTime(startInfo.extensionTypeName); + if (configuredTimeout <= 0) { + TAG_LOGD(AAFwkTag::ABILITYMGR, "no timeout configured for type %{public}s, skip", + startInfo.extensionTypeName.c_str()); + return; + } + + auto now = std::chrono::steady_clock::now(); + auto nowMillis = std::chrono::duration_cast(now.time_since_epoch()).count(); + int64_t runningDurationMs = nowMillis - startInfo.startTimeMillis; + int64_t runningDurationSec = runningDurationMs / 1000; + + // runningDuration <= configuredTimeout means within limit, do not track + if (runningDurationSec <= configuredTimeout) { + TAG_LOGD(AAFwkTag::ABILITYMGR, + "extension %{public}s/%{public}s within timeout, duration: %{public}" PRId64 "s, limit: %{public}ds", + startInfo.bundleName.c_str(), startInfo.abilityName.c_str(), + runningDurationSec, configuredTimeout); + return; + } + + TAG_LOGI(AAFwkTag::ABILITYMGR, + "extension %{public}s/%{public}s exceeded timeout, duration: %{public}" PRId64 "s, limit: %{public}ds", + startInfo.bundleName.c_str(), startInfo.abilityName.c_str(), + runningDurationSec, configuredTimeout); + + ExtensionTimeoutEvent event; + event.extensionTypeName = startInfo.extensionTypeName; + event.bundleName = startInfo.bundleName; + event.abilityName = startInfo.abilityName; + event.runningDuration = runningDurationSec; + event.stillAlive = false; + event.cnt = 1; + + std::lock_guard lock(monitorMutex_); + AddOrUpdateTimeoutEvent(event); +} + +void ExtensionRunningTimeoutMonitor::StartMonitor() +{ + TAG_LOGI(AAFwkTag::ABILITYMGR, "start extension running timeout monitor"); + SubmitPeriodicTask(); +} + +void ExtensionRunningTimeoutMonitor::StopMonitor() +{ + TAG_LOGI(AAFwkTag::ABILITYMGR, "stop extension running timeout monitor"); + auto taskHandler = TaskHandlerWrap::GetFfrtHandler(); + if (taskHandler != nullptr) { + taskHandler->CancelTask(PERIODIC_TASK_NAME); + } +} + +void ExtensionRunningTimeoutMonitor::SubmitPeriodicTask() +{ + auto taskHandler = TaskHandlerWrap::GetFfrtHandler(); + if (taskHandler == nullptr) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "failed to get ffrt handler"); + return; + } + + auto task = []() { + TAG_LOGI(AAFwkTag::ABILITYMGR, "extension timeout periodic task triggered"); + auto monitor = DelayedSingleton::GetInstance(); + monitor->CheckAliveExtensions(); + monitor->ReportTimeoutEvents(); + monitor->SubmitPeriodicTask(); + }; + taskHandler->SubmitTask(task, PERIODIC_TASK_NAME, REPORT_INTERVAL_MS); +} + +void ExtensionRunningTimeoutMonitor::ReportTimeoutEvents() +{ + std::list eventsToReport; + { + std::lock_guard lock(monitorMutex_); + if (cachedEvents_.empty()) { + TAG_LOGD(AAFwkTag::ABILITYMGR, "no timeout events to report"); + return; + } + eventsToReport = cachedEvents_; + cachedEvents_.clear(); + } + + std::vector> stringBuffers; + std::vector extensionTypePtrs; + std::vector bundleNamePtrs; + std::vector abilityNamePtrs; + std::vector runningDurations; + std::vector stillAliveFlags; + std::vector cnts; + + for (const auto &event : eventsToReport) { + if (!CopyStringParam(event.extensionTypeName, stringBuffers, extensionTypePtrs) || + !CopyStringParam(event.bundleName, stringBuffers, bundleNamePtrs) || + !CopyStringParam(event.abilityName, stringBuffers, abilityNamePtrs)) { + TAG_LOGE(AAFwkTag::ABILITYMGR, "strcpy_s failed for event string"); + continue; + } + runningDurations.push_back(event.runningDuration); + stillAliveFlags.push_back(event.stillAlive); + cnts.push_back(event.cnt); + } + + if (extensionTypePtrs.empty()) { + TAG_LOGW(AAFwkTag::ABILITYMGR, "no valid events to report after buffer preparation"); + return; + } + + HisyseventReport report(HISEVENT_PARAM_COUNT); + report.InsertParam(EXTENSION_TYPE_KEY, extensionTypePtrs); + report.InsertParam(BUNDLE_NAME_KEY, bundleNamePtrs); + report.InsertParam(ABILITY_NAME_KEY, abilityNamePtrs); + report.InsertParam(RUNNING_DURATION_KEY, runningDurations); + report.InsertParam(STILL_ALIVE_KEY, stillAliveFlags); + report.InsertParam(CNT_KEY, cnts); + int32_t ret = report.Report(DOMAIN, EVENT_NAME, HISYSEVENT_STATISTIC); + TAG_LOGI(AAFwkTag::ABILITYMGR, "reported %{public}zu timeout events, ret: %{public}d", + eventsToReport.size(), ret); +} + +void ExtensionRunningTimeoutMonitor::CheckAliveExtensions() +{ + TAG_LOGI(AAFwkTag::ABILITYMGR, "check alive extensions for timeout violations"); + + // Copy the running extensions map to avoid holding mutex during slow checks + std::unordered_map aliveCopy; + { + std::lock_guard lock(monitorMutex_); + aliveCopy = runningExtensions_; + } + + auto now = std::chrono::steady_clock::now(); + auto nowMillis = std::chrono::duration_cast(now.time_since_epoch()).count(); + + std::vector pendingEvents; + for (auto &[recordId, startInfo] : aliveCopy) { + int32_t configuredTimeout = DelayedSingleton::GetInstance()-> + GetExtensionRunningTimeoutTime(startInfo.extensionTypeName); + if (configuredTimeout <= 0) { + continue; + } + + int64_t runningDurationMs = nowMillis - startInfo.startTimeMillis; + int64_t runningDurationSec = runningDurationMs / 1000; + if (runningDurationSec <= configuredTimeout) { + continue; + } + + TAG_LOGI(AAFwkTag::ABILITYMGR, + "alive extension %{public}s/%{public}s exceeded timeout, duration: %{public}" PRId64 "s", + startInfo.bundleName.c_str(), startInfo.abilityName.c_str(), runningDurationSec); + + ExtensionTimeoutEvent event; + event.extensionTypeName = startInfo.extensionTypeName; + event.bundleName = startInfo.bundleName; + event.abilityName = startInfo.abilityName; + event.runningDuration = runningDurationSec; + event.stillAlive = true; + event.cnt = 1; + pendingEvents.push_back(event); + } + + if (!pendingEvents.empty()) { + std::lock_guard lock(monitorMutex_); + for (auto &event : pendingEvents) { + AddOrUpdateTimeoutEvent(event); + } + } +} + +bool ExtensionRunningTimeoutMonitor::IsDuplicateEvent(const ExtensionTimeoutEvent &event, + std::list::iterator &dupIter) +{ + for (auto it = cachedEvents_.begin(); it != cachedEvents_.end(); ++it) { + if (it->extensionTypeName == event.extensionTypeName && + it->bundleName == event.bundleName && + it->abilityName == event.abilityName) { + dupIter = it; + return true; + } + } + return false; +} + +void ExtensionRunningTimeoutMonitor::AddOrUpdateTimeoutEvent(const ExtensionTimeoutEvent &event) +{ + std::list::iterator dupIter; + if (IsDuplicateEvent(event, dupIter)) { + dupIter->cnt++; + dupIter->runningDuration = event.runningDuration; + dupIter->stillAlive = event.stillAlive; + TAG_LOGD(AAFwkTag::ABILITYMGR, + "updated existing timeout event for %{public}s/%{public}s, cnt: %{public}d", + event.bundleName.c_str(), event.abilityName.c_str(), dupIter->cnt); + return; + } + + if (static_cast(cachedEvents_.size()) >= MAX_CACHED_EVENTS) { + TAG_LOGW(AAFwkTag::ABILITYMGR, + "cache full (%{public}d), discarding event for %{public}s/%{public}s", + MAX_CACHED_EVENTS, event.bundleName.c_str(), event.abilityName.c_str()); + return; + } + + cachedEvents_.push_back(event); + TAG_LOGD(AAFwkTag::ABILITYMGR, + "added new timeout event for %{public}s/%{public}s, cache size: %{public}zu", + event.bundleName.c_str(), event.abilityName.c_str(), cachedEvents_.size()); +} + +} // namespace AAFwk +} // namespace OHOS diff --git a/services/common/include/hisysevent_report.h b/services/common/include/hisysevent_report.h index 364270a0a7..ee64c7bc3e 100644 --- a/services/common/include/hisysevent_report.h +++ b/services/common/include/hisysevent_report.h @@ -33,6 +33,9 @@ public: return; } this->params_ = new (std::nothrow) HiSysEventParam[SYSTEM_PARAM_MAX_LEN]; + if (this->params_ == nullptr) { + length_ = 0; + } } ~HisyseventReport() { @@ -56,13 +59,15 @@ public: void InsertParam(const char* name, const std::vector &value); void InsertParam(const char* name, std::vector &value); void InsertParam(const char* name, const std::vector &value); + void InsertParam(const char* name, const std::vector &value); + void InsertParam(const char* name, const std::vector &value); int32_t Report(const char* domain, const char* event, HiSysEventEventType type); private: void SetParamName(HiSysEventParam& param, const char* name); std::vector> paramBuffers_; - HiSysEventParam* params_; + HiSysEventParam* params_ = nullptr; int32_t length_ = SYSTEM_PARAM_MAX_LEN; int32_t pos_ = 0; }; diff --git a/services/common/src/hisysevent_report.cpp b/services/common/src/hisysevent_report.cpp index 2f2ede484c..87cf67c8e4 100644 --- a/services/common/src/hisysevent_report.cpp +++ b/services/common/src/hisysevent_report.cpp @@ -197,7 +197,7 @@ void HisyseventReport::InsertParam(const char* name, char* value) int32_t len = std::strlen(value) + 1; auto buffer = std::make_unique(len); int32_t ret = strcpy_s(buffer.get(), len, value); - if (ret != 0) { + if (ret != EOK) { TAG_LOGE(AAFwkTag::DEFAULT, "InsertParam err %{public}d", ret); return; } @@ -273,20 +273,89 @@ void HisyseventReport::InsertParam(const char* name, std::vector &value) params_[pos_++] = param; } +void HisyseventReport::InsertParam(const char* name, const std::vector &value) +{ + if (length_ <= pos_) { + TAG_LOGE(AAFwkTag::DEFAULT, "param is full"); + return; + } + HiSysEventParam param = { + .t = HISYSEVENT_BOOL_ARRAY, + .v = { .array = nullptr}, + .arraySize = 0, + }; + + if (!value.empty()) { + size_t bufSize = value.size() * sizeof(bool); + auto *buf = new (std::nothrow) char[bufSize](); + if (buf != nullptr) { + auto *boolBuf = reinterpret_cast(buf); + for (size_t i = 0; i < value.size(); ++i) { + boolBuf[i] = value[i]; + } + param.v.array = static_cast(boolBuf); + param.arraySize = value.size(); + paramBuffers_.emplace_back(buf); + } + } + SetParamName(param, name); + params_[pos_++] = param; +} + +void HisyseventReport::InsertParam(const char* name, const std::vector &value) +{ + if (length_ <= pos_) { + TAG_LOGE(AAFwkTag::DEFAULT, "param is full"); + return; + } + HiSysEventParam param = { + .t = HISYSEVENT_INT64_ARRAY, + .v = { .array = nullptr}, + .arraySize = 0, + }; + + if (!value.empty()) { + param.v.array = static_cast(const_cast(value.data())); + param.arraySize = value.size(); + } + SetParamName(param, name); + params_[pos_++] = param; +} + void HisyseventReport::InsertParam(const char* name, std::string value) { - this->InsertParam(name, const_cast(value.c_str())); + this->InsertParam(name, value.c_str()); } void HisyseventReport::InsertParam(const char* name, const char* value) { - this->InsertParam(name, const_cast(value)); + if (!name || !value || length_ <= pos_) { + TAG_LOGE(AAFwkTag::DEFAULT, "param is full"); + return; + } + int32_t len = static_cast(std::strlen(value)) + 1; + auto buffer = std::make_unique(len); + int32_t ret = strcpy_s(buffer.get(), len, value); + if (ret != EOK) { + TAG_LOGE(AAFwkTag::DEFAULT, "InsertParam err %{public}d", ret); + return; + } + + HiSysEventParam param = { + .t = HISYSEVENT_STRING, + .v = { .s = buffer.get()}, + .arraySize = 0, + }; + SetParamName(param, name); + params_[pos_++] = param; + + paramBuffers_.emplace_back(std::move(buffer)); } void HisyseventReport::SetParamName(HiSysEventParam& param, const char* name) { int32_t ret = strcpy_s(param.name, sizeof(param.name), name); - if (ret != 0) { + if (ret != EOK) { TAG_LOGE(AAFwkTag::DEFAULT, "SetParamName err %{public}d", ret); } } diff --git a/test/fuzztest/extensionrecordmanager_fuzzer/BUILD.gn b/test/fuzztest/extensionrecordmanager_fuzzer/BUILD.gn index 224f8443cd..c92262fdc9 100644 --- a/test/fuzztest/extensionrecordmanager_fuzzer/BUILD.gn +++ b/test/fuzztest/extensionrecordmanager_fuzzer/BUILD.gn @@ -50,6 +50,8 @@ ohos_fuzztest("ExtensionRecordManagerFuzzTest") { "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_factory.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_manager.cpp", + "${ability_runtime_services_path}/abilitymgr/src/extension_running_timeout_monitor.cpp", + "${ability_runtime_services_path}/abilitymgr/src/extension_config.cpp", "${ability_runtime_services_path}/abilitymgr/src/ui_extension/preload_uiext_state_observer.cpp", "${ability_runtime_services_path}/abilitymgr/src/ui_extension_record/ui_extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/ui_extension_record/ui_extension_record_factory.cpp", diff --git a/test/fuzztest/extensionrecordmanagera_fuzzer/BUILD.gn b/test/fuzztest/extensionrecordmanagera_fuzzer/BUILD.gn index aef76513e9..6767a8e04b 100755 --- a/test/fuzztest/extensionrecordmanagera_fuzzer/BUILD.gn +++ b/test/fuzztest/extensionrecordmanagera_fuzzer/BUILD.gn @@ -48,6 +48,8 @@ ohos_fuzztest("ExtensionRecordManageraFuzzTest") { "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_factory.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_manager.cpp", + "${ability_runtime_services_path}/abilitymgr/src/extension_running_timeout_monitor.cpp", + "${ability_runtime_services_path}/abilitymgr/src/extension_config.cpp", "${ability_runtime_services_path}/abilitymgr/src/ui_extension/preload_uiext_state_observer.cpp", "${ability_runtime_services_path}/abilitymgr/src/ui_extension_record/ui_extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/ui_extension_record/ui_extension_record_factory.cpp", diff --git a/test/fuzztest/extensionrecordmanagerb_fuzzer/BUILD.gn b/test/fuzztest/extensionrecordmanagerb_fuzzer/BUILD.gn index dd07f6a46b..0e7ff32d5d 100755 --- a/test/fuzztest/extensionrecordmanagerb_fuzzer/BUILD.gn +++ b/test/fuzztest/extensionrecordmanagerb_fuzzer/BUILD.gn @@ -51,6 +51,8 @@ ohos_fuzztest("ExtensionRecordManagerbFuzzTest") { "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_factory.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_manager.cpp", + "${ability_runtime_services_path}/abilitymgr/src/extension_running_timeout_monitor.cpp", + "${ability_runtime_services_path}/abilitymgr/src/extension_config.cpp", "${ability_runtime_services_path}/abilitymgr/src/ui_extension/preload_uiext_state_observer.cpp", "${ability_runtime_services_path}/abilitymgr/src/ui_extension_record/ui_extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/ui_extension_record/ui_extension_record_factory.cpp", diff --git a/test/fuzztest/extensionrecordmanagerc_fuzzer/BUILD.gn b/test/fuzztest/extensionrecordmanagerc_fuzzer/BUILD.gn index 69cb4e7bb4..5208f43cc3 100755 --- a/test/fuzztest/extensionrecordmanagerc_fuzzer/BUILD.gn +++ b/test/fuzztest/extensionrecordmanagerc_fuzzer/BUILD.gn @@ -51,6 +51,8 @@ ohos_fuzztest("ExtensionRecordManagercFuzzTest") { "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_factory.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_manager.cpp", + "${ability_runtime_services_path}/abilitymgr/src/extension_running_timeout_monitor.cpp", + "${ability_runtime_services_path}/abilitymgr/src/extension_config.cpp", "${ability_runtime_services_path}/abilitymgr/src/ui_extension/preload_uiext_state_observer.cpp", "${ability_runtime_services_path}/abilitymgr/src/ui_extension_record/ui_extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/ui_extension_record/ui_extension_record_factory.cpp", diff --git a/test/unittest/ability_manager_service_first_test/abilitymgr.gni b/test/unittest/ability_manager_service_first_test/abilitymgr.gni index 80e0ccce35..3f1eac4a08 100644 --- a/test/unittest/ability_manager_service_first_test/abilitymgr.gni +++ b/test/unittest/ability_manager_service_first_test/abilitymgr.gni @@ -43,6 +43,7 @@ abilityms_files = [ "${ability_runtime_services_path}/abilitymgr/src/extension_running_info.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/base_extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_manager.cpp", + "${ability_runtime_services_path}/abilitymgr/src/extension_running_timeout_monitor.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_factory.cpp", "${ability_runtime_services_path}/abilitymgr/src/foreground_app_connection_manager/foreground_app_connection_manager.cpp", diff --git a/test/unittest/ability_manager_service_fourteenth_test/BUILD.gn b/test/unittest/ability_manager_service_fourteenth_test/BUILD.gn index d39bc6cd3f..6c53d0f4a6 100644 --- a/test/unittest/ability_manager_service_fourteenth_test/BUILD.gn +++ b/test/unittest/ability_manager_service_fourteenth_test/BUILD.gn @@ -123,6 +123,7 @@ ohos_unittest("ability_manager_service_fourteenth_test") { "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_factory.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_manager.cpp", + "${ability_runtime_services_path}/abilitymgr/src/extension_running_timeout_monitor.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_running_info.cpp", "${ability_runtime_services_path}/abilitymgr/src/foreground_app_connection_manager/foreground_app_connection_manager.cpp", "${ability_runtime_services_path}/abilitymgr/src/free_install_observer_manager.cpp", diff --git a/test/unittest/ability_manager_service_second_test/BUILD.gn b/test/unittest/ability_manager_service_second_test/BUILD.gn index f08f0ecba8..2d4d3e3cd8 100644 --- a/test/unittest/ability_manager_service_second_test/BUILD.gn +++ b/test/unittest/ability_manager_service_second_test/BUILD.gn @@ -125,6 +125,7 @@ ohos_unittest("ability_manager_service_second_test") { "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_factory.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_manager.cpp", + "${ability_runtime_services_path}/abilitymgr/src/extension_running_timeout_monitor.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_running_info.cpp", "${ability_runtime_services_path}/abilitymgr/src/foreground_app_connection_manager/foreground_app_connection_manager.cpp", "${ability_runtime_services_path}/abilitymgr/src/free_install_observer_manager.cpp", diff --git a/test/unittest/ability_manager_service_sixth_test/abilitymgr.gni b/test/unittest/ability_manager_service_sixth_test/abilitymgr.gni index e92187c195..03f03051b6 100644 --- a/test/unittest/ability_manager_service_sixth_test/abilitymgr.gni +++ b/test/unittest/ability_manager_service_sixth_test/abilitymgr.gni @@ -43,6 +43,7 @@ abilityms_files = [ "${ability_runtime_services_path}/abilitymgr/src/extension_running_info.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/base_extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_manager.cpp", + "${ability_runtime_services_path}/abilitymgr/src/extension_running_timeout_monitor.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_factory.cpp", "${ability_runtime_services_path}/abilitymgr/src/foreground_app_connection_manager/foreground_app_connection_manager.cpp", diff --git a/test/unittest/ability_manager_service_third_test/abilitymgr.gni b/test/unittest/ability_manager_service_third_test/abilitymgr.gni index 9501d951b7..079d73c163 100644 --- a/test/unittest/ability_manager_service_third_test/abilitymgr.gni +++ b/test/unittest/ability_manager_service_third_test/abilitymgr.gni @@ -43,6 +43,7 @@ abilityms_files = [ "${ability_runtime_services_path}/abilitymgr/src/extension_running_info.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/base_extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_manager.cpp", + "${ability_runtime_services_path}/abilitymgr/src/extension_running_timeout_monitor.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_factory.cpp", "${ability_runtime_services_path}/abilitymgr/src/foreground_app_connection_manager/foreground_app_connection_manager.cpp", diff --git a/test/unittest/ability_manager_service_thirteenth_test/BUILD.gn b/test/unittest/ability_manager_service_thirteenth_test/BUILD.gn index 772b5d5df1..21962b6a4a 100644 --- a/test/unittest/ability_manager_service_thirteenth_test/BUILD.gn +++ b/test/unittest/ability_manager_service_thirteenth_test/BUILD.gn @@ -123,6 +123,7 @@ ohos_unittest("ability_manager_service_thirteenth_test") { "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_factory.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_manager.cpp", + "${ability_runtime_services_path}/abilitymgr/src/extension_running_timeout_monitor.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_running_info.cpp", "${ability_runtime_services_path}/abilitymgr/src/foreground_app_connection_manager/foreground_app_connection_manager.cpp", "${ability_runtime_services_path}/abilitymgr/src/free_install_observer_manager.cpp", diff --git a/test/unittest/ui_extension/extension_record_manager_second_test/BUILD.gn b/test/unittest/ui_extension/extension_record_manager_second_test/BUILD.gn index 9a6a5d5ccb..b24a9b0eea 100644 --- a/test/unittest/ui_extension/extension_record_manager_second_test/BUILD.gn +++ b/test/unittest/ui_extension/extension_record_manager_second_test/BUILD.gn @@ -48,6 +48,12 @@ ohos_unittest("extension_record_manager_second_test") { "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_factory.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_manager.cpp", + "${ability_runtime_services_path}/abilitymgr/src/extension_running_timeout_monitor.cpp", + "${ability_runtime_services_path}/abilitymgr/src/extension_config.cpp", + "${ability_runtime_services_path}/common/src/ffrt_task_handler_wrap.cpp", + "${ability_runtime_services_path}/common/src/hisysevent_report.cpp", + "${ability_runtime_services_path}/common/src/queue_task_handler_wrap.cpp", + "${ability_runtime_services_path}/common/src/task_handler_wrap.cpp", "${ability_runtime_services_path}/abilitymgr/src/ui_extension/preload_uiext_state_observer.cpp", "${ability_runtime_services_path}/abilitymgr/src/ui_extension_record/ui_extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/ui_extension_record/ui_extension_record_factory.cpp", @@ -73,6 +79,7 @@ ohos_unittest("extension_record_manager_second_test") { "${ability_runtime_path}/utils/global/common:runtime_utils", "${ability_runtime_path}/utils/server/startup:startup_util", "${ability_runtime_services_path}/abilitymgr:abilityms", + "${ability_runtime_services_path}/common:task_handler_wrap", ] external_deps = [ diff --git a/test/unittest/ui_extension/extension_record_manager_second_test/extension_record_manager_second_test.cpp b/test/unittest/ui_extension/extension_record_manager_second_test/extension_record_manager_second_test.cpp index 2a3ce4bf59..ca9d0009b0 100644 --- a/test/unittest/ui_extension/extension_record_manager_second_test/extension_record_manager_second_test.cpp +++ b/test/unittest/ui_extension/extension_record_manager_second_test/extension_record_manager_second_test.cpp @@ -14,6 +14,8 @@ */ #include +#include +#include #include "hilog_tag_wrapper.h" #include "ability_manager_client.h" @@ -21,8 +23,10 @@ #define private public #define protected public #define inline -#include "extension_record.h" +#include "extension_record.h" #include "extension_record_manager.h" +#include "extension_running_timeout_monitor.h" +#include "extension_config.h" #define inline #undef protected #undef private @@ -1092,5 +1096,610 @@ HWTEST_F(ExtensionRecordManagerSecondTest, TerminateTimeout_0100, TestSize.Level TAG_LOGI(AAFwkTag::TEST, "end."); } +// ========== ExtensionRunningTimeoutMonitor TDD Tests ========== + +class ExtensionRunningTimeoutMonitorTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; +}; + +void ExtensionRunningTimeoutMonitorTest::SetUpTestCase() +{} + +void ExtensionRunningTimeoutMonitorTest::TearDownTestCase() +{} + +void ExtensionRunningTimeoutMonitorTest::SetUp() +{ + auto monitor = DelayedSingleton::GetInstance(); + monitor->runningExtensions_.clear(); + monitor->cachedEvents_.clear(); +} + +void ExtensionRunningTimeoutMonitorTest::TearDown() +{ + auto monitor = DelayedSingleton::GetInstance(); + monitor->StopMonitor(); + monitor->runningExtensions_.clear(); + monitor->cachedEvents_.clear(); +} + +/** + * @tc.name: OnExtensionStarted_0100 + * @tc.desc: Test OnExtensionStarted records extension info correctly. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, OnExtensionStarted_0100, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto monitor = DelayedSingleton::GetInstance(); + ASSERT_NE(monitor, nullptr); + + monitor->OnExtensionStarted(100, "ServiceExtension", "com.test.bundle", "TestAbility"); + EXPECT_EQ(monitor->runningExtensions_.size(), static_cast(1)); + EXPECT_EQ(monitor->runningExtensions_.count(100), static_cast(1)); + EXPECT_EQ(monitor->runningExtensions_[100].extensionTypeName, "ServiceExtension"); + EXPECT_EQ(monitor->runningExtensions_[100].bundleName, "com.test.bundle"); + EXPECT_EQ(monitor->runningExtensions_[100].abilityName, "TestAbility"); + EXPECT_GT(monitor->runningExtensions_[100].startTimeMillis, static_cast(0)); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + +/** + * @tc.name: OnExtensionStarted_0200 + * @tc.desc: Test OnExtensionStarted with multiple extensions. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, OnExtensionStarted_0200, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto monitor = DelayedSingleton::GetInstance(); + ASSERT_NE(monitor, nullptr); + + monitor->OnExtensionStarted(1, "ServiceExtension", "com.test.a", "AbilityA"); + monitor->OnExtensionStarted(2, "UIExtension", "com.test.b", "AbilityB"); + monitor->OnExtensionStarted(3, "DataShareExtension", "com.test.c", "AbilityC"); + + EXPECT_EQ(monitor->runningExtensions_.size(), static_cast(3)); + EXPECT_EQ(monitor->runningExtensions_[1].extensionTypeName, "ServiceExtension"); + EXPECT_EQ(monitor->runningExtensions_[2].extensionTypeName, "UIExtension"); + EXPECT_EQ(monitor->runningExtensions_[3].extensionTypeName, "DataShareExtension"); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + +/** + * @tc.name: OnExtensionStarted_0300 + * @tc.desc: Test OnExtensionStarted with same recordId overwrites previous entry. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, OnExtensionStarted_0300, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto monitor = DelayedSingleton::GetInstance(); + ASSERT_NE(monitor, nullptr); + + monitor->OnExtensionStarted(100, "ServiceExtension", "com.test.old", "OldAbility"); + EXPECT_EQ(monitor->runningExtensions_.size(), static_cast(1)); + + monitor->OnExtensionStarted(100, "UIExtension", "com.test.new", "NewAbility"); + EXPECT_EQ(monitor->runningExtensions_.size(), static_cast(1)); + EXPECT_EQ(monitor->runningExtensions_[100].extensionTypeName, "UIExtension"); + EXPECT_EQ(monitor->runningExtensions_[100].bundleName, "com.test.new"); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + +/** + * @tc.name: OnExtensionTerminated_0100 + * @tc.desc: Test OnExtensionTerminated with unknown recordId does nothing. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, OnExtensionTerminated_0100, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto monitor = DelayedSingleton::GetInstance(); + ASSERT_NE(monitor, nullptr); + + monitor->OnExtensionTerminated(9999); + EXPECT_EQ(monitor->runningExtensions_.size(), static_cast(0)); + EXPECT_EQ(monitor->cachedEvents_.size(), static_cast(0)); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + +/** + * @tc.name: OnExtensionTerminated_0200 + * @tc.desc: Test OnExtensionTerminated removes extension from running list. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, OnExtensionTerminated_0200, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto monitor = DelayedSingleton::GetInstance(); + ASSERT_NE(monitor, nullptr); + + monitor->OnExtensionStarted(100, "ServiceExtension", "com.test.bundle", "TestAbility"); + EXPECT_EQ(monitor->runningExtensions_.size(), static_cast(1)); + + // No timeout configured (default -1), so no event should be cached + monitor->OnExtensionTerminated(100); + EXPECT_EQ(monitor->runningExtensions_.size(), static_cast(0)); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + +/** + * @tc.name: OnExtensionTerminated_0300 + * @tc.desc: Test OnExtensionTerminated detects timeout and caches event. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, OnExtensionTerminated_0300, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto monitor = DelayedSingleton::GetInstance(); + ASSERT_NE(monitor, nullptr); + + // Configure timeout for this extension type via ExtensionConfig + auto config = DelayedSingleton::GetInstance(); + ASSERT_NE(config, nullptr); + AAFwk::ExtensionConfigItem item; + item.extensionRunningTimeoutTime = 1; // 1 second + config->configMap_["TestTimeoutExtension"] = item; + + monitor->OnExtensionStarted(200, "TestTimeoutExtension", "com.test.timeout", "TimeoutAbility"); + EXPECT_EQ(monitor->runningExtensions_.size(), static_cast(1)); + + // Wait for timeout to be exceeded + std::this_thread::sleep_for(std::chrono::seconds(2)); + + monitor->OnExtensionTerminated(200); + EXPECT_EQ(monitor->runningExtensions_.size(), static_cast(0)); + EXPECT_EQ(monitor->cachedEvents_.size(), static_cast(1)); + + auto &event = monitor->cachedEvents_.front(); + EXPECT_EQ(event.extensionTypeName, "TestTimeoutExtension"); + EXPECT_EQ(event.bundleName, "com.test.timeout"); + EXPECT_EQ(event.abilityName, "TimeoutAbility"); + EXPECT_GE(event.runningDuration, static_cast(1)); + EXPECT_EQ(event.stillAlive, false); + EXPECT_EQ(event.cnt, 1); + + // Clean up config + config->configMap_.erase("TestTimeoutExtension"); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + +/** + * @tc.name: OnExtensionTerminated_0400 + * @tc.desc: Test OnExtensionTerminated within timeout does not cache event. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, OnExtensionTerminated_0400, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto monitor = DelayedSingleton::GetInstance(); + ASSERT_NE(monitor, nullptr); + + // Configure long timeout + auto config = DelayedSingleton::GetInstance(); + AAFwk::ExtensionConfigItem item; + item.extensionRunningTimeoutTime = 3600; // 1 hour + config->configMap_["TestLongTimeout"] = item; + + monitor->OnExtensionStarted(300, "TestLongTimeout", "com.test.quick", "QuickAbility"); + + // Terminate immediately, well within 1 hour timeout + monitor->OnExtensionTerminated(300); + EXPECT_EQ(monitor->runningExtensions_.size(), static_cast(0)); + EXPECT_EQ(monitor->cachedEvents_.size(), static_cast(0)); + + config->configMap_.erase("TestLongTimeout"); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + +/** + * @tc.name: AddOrUpdateTimeoutEvent_0100 + * @tc.desc: Test AddOrUpdateTimeoutEvent adds new event when no duplicate. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, AddOrUpdateTimeoutEvent_0100, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto monitor = DelayedSingleton::GetInstance(); + ASSERT_NE(monitor, nullptr); + + AAFwk::ExtensionTimeoutEvent event; + event.extensionTypeName = "ServiceExtension"; + event.bundleName = "com.test.bundle"; + event.abilityName = "Ability1"; + event.runningDuration = 100; + event.stillAlive = false; + event.cnt = 1; + + monitor->AddOrUpdateTimeoutEvent(event); + EXPECT_EQ(monitor->cachedEvents_.size(), static_cast(1)); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + +/** + * @tc.name: AddOrUpdateTimeoutEvent_0200 + * @tc.desc: Test AddOrUpdateTimeoutEvent increments cnt for duplicate event. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, AddOrUpdateTimeoutEvent_0200, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto monitor = DelayedSingleton::GetInstance(); + ASSERT_NE(monitor, nullptr); + + AAFwk::ExtensionTimeoutEvent event1; + event1.extensionTypeName = "ServiceExtension"; + event1.bundleName = "com.test.dup"; + event1.abilityName = "DupAbility"; + event1.runningDuration = 10; + event1.stillAlive = true; + event1.cnt = 1; + + monitor->AddOrUpdateTimeoutEvent(event1); + EXPECT_EQ(monitor->cachedEvents_.size(), static_cast(1)); + EXPECT_EQ(monitor->cachedEvents_.front().cnt, 1); + + // Same extension detected again + AAFwk::ExtensionTimeoutEvent event2; + event2.extensionTypeName = "ServiceExtension"; + event2.bundleName = "com.test.dup"; + event2.abilityName = "DupAbility"; + event2.runningDuration = 20; + event2.stillAlive = false; + event2.cnt = 1; + + monitor->AddOrUpdateTimeoutEvent(event2); + EXPECT_EQ(monitor->cachedEvents_.size(), static_cast(1)); + EXPECT_EQ(monitor->cachedEvents_.front().cnt, 2); + EXPECT_EQ(monitor->cachedEvents_.front().runningDuration, static_cast(20)); + EXPECT_EQ(monitor->cachedEvents_.front().stillAlive, false); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + +/** + * @tc.name: AddOrUpdateTimeoutEvent_0300 + * @tc.desc: Test AddOrUpdateTimeoutEvent discards event when cache is full. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, AddOrUpdateTimeoutEvent_0300, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto monitor = DelayedSingleton::GetInstance(); + ASSERT_NE(monitor, nullptr); + + // Fill cache to MAX_CACHED_EVENTS (5) + for (int32_t i = 0; i < monitor->MAX_CACHED_EVENTS; i++) { + AAFwk::ExtensionTimeoutEvent event; + event.extensionTypeName = "ServiceExtension"; + event.bundleName = "com.test.bundle" + std::to_string(i); + event.abilityName = "Ability" + std::to_string(i); + event.runningDuration = i + 1; + event.cnt = 1; + monitor->AddOrUpdateTimeoutEvent(event); + } + EXPECT_EQ(monitor->cachedEvents_.size(), static_cast(monitor->MAX_CACHED_EVENTS)); + + // 6th different event should be discarded + AAFwk::ExtensionTimeoutEvent overflowEvent; + overflowEvent.extensionTypeName = "ServiceExtension"; + overflowEvent.bundleName = "com.test.overflow"; + overflowEvent.abilityName = "OverflowAbility"; + overflowEvent.runningDuration = 999; + overflowEvent.cnt = 1; + monitor->AddOrUpdateTimeoutEvent(overflowEvent); + + EXPECT_EQ(monitor->cachedEvents_.size(), static_cast(monitor->MAX_CACHED_EVENTS)); + + // Verify overflow event is not in cache + bool found = false; + for (const auto &e : monitor->cachedEvents_) { + if (e.bundleName == "com.test.overflow") { + found = true; + break; + } + } + EXPECT_FALSE(found); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + +/** + * @tc.name: IsDuplicateEvent_0100 + * @tc.desc: Test IsDuplicateEvent returns true for matching events. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, IsDuplicateEvent_0100, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto monitor = DelayedSingleton::GetInstance(); + ASSERT_NE(monitor, nullptr); + + AAFwk::ExtensionTimeoutEvent event; + event.extensionTypeName = "ServiceExtension"; + event.bundleName = "com.test.dup"; + event.abilityName = "TestAbility"; + monitor->cachedEvents_.push_back(event); + + AAFwk::ExtensionTimeoutEvent candidate; + candidate.extensionTypeName = "ServiceExtension"; + candidate.bundleName = "com.test.dup"; + candidate.abilityName = "TestAbility"; + + std::list::iterator dupIter; + EXPECT_TRUE(monitor->IsDuplicateEvent(candidate, dupIter)); + EXPECT_EQ(dupIter->bundleName, "com.test.dup"); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + +/** + * @tc.name: IsDuplicateEvent_0200 + * @tc.desc: Test IsDuplicateEvent returns false for non-matching events. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, IsDuplicateEvent_0200, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto monitor = DelayedSingleton::GetInstance(); + ASSERT_NE(monitor, nullptr); + + AAFwk::ExtensionTimeoutEvent event; + event.extensionTypeName = "ServiceExtension"; + event.bundleName = "com.test.exist"; + event.abilityName = "ExistAbility"; + monitor->cachedEvents_.push_back(event); + + AAFwk::ExtensionTimeoutEvent candidate; + candidate.extensionTypeName = "UIExtension"; + candidate.bundleName = "com.test.exist"; + candidate.abilityName = "ExistAbility"; + + std::list::iterator dupIter; + EXPECT_FALSE(monitor->IsDuplicateEvent(candidate, dupIter)); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + +/** + * @tc.name: ReportTimeoutEvents_0100 + * @tc.desc: Test ReportTimeoutEvents clears cache after reporting. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, ReportTimeoutEvents_0100, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto monitor = DelayedSingleton::GetInstance(); + ASSERT_NE(monitor, nullptr); + + AAFwk::ExtensionTimeoutEvent event; + event.extensionTypeName = "ServiceExtension"; + event.bundleName = "com.test.report"; + event.abilityName = "ReportAbility"; + event.runningDuration = 100; + event.stillAlive = false; + event.cnt = 1; + monitor->cachedEvents_.push_back(event); + EXPECT_EQ(monitor->cachedEvents_.size(), static_cast(1)); + + monitor->ReportTimeoutEvents(); + EXPECT_EQ(monitor->cachedEvents_.size(), static_cast(0)); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + +/** + * @tc.name: ReportTimeoutEvents_0200 + * @tc.desc: Test ReportTimeoutEvents with empty cache does nothing. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, ReportTimeoutEvents_0200, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto monitor = DelayedSingleton::GetInstance(); + ASSERT_NE(monitor, nullptr); + + EXPECT_EQ(monitor->cachedEvents_.size(), static_cast(0)); + monitor->ReportTimeoutEvents(); + EXPECT_EQ(monitor->cachedEvents_.size(), static_cast(0)); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + +/** + * @tc.name: CheckAliveExtensions_0100 + * @tc.desc: Test CheckAliveExtensions detects running extension exceeding timeout. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, CheckAliveExtensions_0100, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto monitor = DelayedSingleton::GetInstance(); + ASSERT_NE(monitor, nullptr); + + // Configure timeout + auto config = DelayedSingleton::GetInstance(); + AAFwk::ExtensionConfigItem item; + item.extensionRunningTimeoutTime = 1; // 1 second + config->configMap_["AliveTestExtension"] = item; + + monitor->OnExtensionStarted(400, "AliveTestExtension", "com.test.alive", "AliveAbility"); + + // Wait for timeout + std::this_thread::sleep_for(std::chrono::seconds(2)); + + monitor->CheckAliveExtensions(); + + EXPECT_EQ(monitor->cachedEvents_.size(), static_cast(1)); + auto &event = monitor->cachedEvents_.front(); + EXPECT_EQ(event.bundleName, "com.test.alive"); + EXPECT_EQ(event.abilityName, "AliveAbility"); + EXPECT_EQ(event.stillAlive, true); // detected via alive check + EXPECT_GE(event.runningDuration, static_cast(1)); + + // Extension should still be in running list + EXPECT_EQ(monitor->runningExtensions_.size(), static_cast(1)); + + config->configMap_.erase("AliveTestExtension"); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + +/** + * @tc.name: CheckAliveExtensions_0200 + * @tc.desc: Test CheckAliveExtensions skips extensions with no timeout config. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, CheckAliveExtensions_0200, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto monitor = DelayedSingleton::GetInstance(); + ASSERT_NE(monitor, nullptr); + + // No config for "UnconfiguredExtension", default timeout is -1 + monitor->OnExtensionStarted(500, "UnconfiguredExtension", "com.test.noconfig", "NoConfigAbility"); + + std::this_thread::sleep_for(std::chrono::seconds(2)); + + monitor->CheckAliveExtensions(); + + // Should not create any events since timeout is -1 (disabled) + EXPECT_EQ(monitor->cachedEvents_.size(), static_cast(0)); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + +/** + * @tc.name: StartStopMonitor_0100 + * @tc.desc: Test StartMonitor and StopMonitor do not crash. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, StartStopMonitor_0100, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto monitor = DelayedSingleton::GetInstance(); + ASSERT_NE(monitor, nullptr); + + monitor->StartMonitor(); + monitor->StopMonitor(); + + // Double stop should not crash + monitor->StopMonitor(); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + +/** + * @tc.name: ConcurrentAccess_0100 + * @tc.desc: Test concurrent OnExtensionStarted and OnExtensionTerminated do not crash. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, ConcurrentAccess_0100, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto monitor = DelayedSingleton::GetInstance(); + ASSERT_NE(monitor, nullptr); + + const int32_t threadCount = 10; + std::vector threads; + + for (int32_t i = 0; i < threadCount; i++) { + threads.emplace_back([monitor, i]() { + monitor->OnExtensionStarted(i, "ServiceExtension", + "com.test.concurrent", "Ability" + std::to_string(i)); + }); + } + for (auto &t : threads) { + t.join(); + } + EXPECT_EQ(monitor->runningExtensions_.size(), static_cast(threadCount)); + + threads.clear(); + for (int32_t i = 0; i < threadCount; i++) { + threads.emplace_back([monitor, i]() { + monitor->OnExtensionTerminated(i); + }); + } + for (auto &t : threads) { + t.join(); + } + EXPECT_EQ(monitor->runningExtensions_.size(), static_cast(0)); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + +/** + * @tc.name: ExtensionConfigGetRunningTimeoutTime_0100 + * @tc.desc: Test ExtensionConfig GetExtensionRunningTimeoutTime returns default when not configured. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, ExtensionConfigGetRunningTimeoutTime_0100, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto config = DelayedSingleton::GetInstance(); + ASSERT_NE(config, nullptr); + + int32_t timeout = config->GetExtensionRunningTimeoutTime("NonExistentType"); + EXPECT_EQ(timeout, AAFwk::DEFAULT_EXTENSION_RUNNING_TIMEOUT_TIME); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + +/** + * @tc.name: ExtensionConfigGetRunningTimeoutTime_0200 + * @tc.desc: Test ExtensionConfig GetExtensionRunningTimeoutTime returns configured value. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(ExtensionRunningTimeoutMonitorTest, ExtensionConfigGetRunningTimeoutTime_0200, TestSize.Level1) +{ + TAG_LOGI(AAFwkTag::TEST, "begin."); + auto config = DelayedSingleton::GetInstance(); + ASSERT_NE(config, nullptr); + + AAFwk::ExtensionConfigItem item; + item.extensionRunningTimeoutTime = 5000; + config->configMap_["ConfiguredType"] = item; + + int32_t timeout = config->GetExtensionRunningTimeoutTime("ConfiguredType"); + EXPECT_EQ(timeout, 5000); + + config->configMap_.erase("ConfiguredType"); + + TAG_LOGI(AAFwkTag::TEST, "end."); +} + } // namespace AbilityRuntime } // namespace OHOS diff --git a/test/unittest/ui_extension/extension_record_manager_test/BUILD.gn b/test/unittest/ui_extension/extension_record_manager_test/BUILD.gn index 305f1689d8..ff172ab2b6 100755 --- a/test/unittest/ui_extension/extension_record_manager_test/BUILD.gn +++ b/test/unittest/ui_extension/extension_record_manager_test/BUILD.gn @@ -45,6 +45,8 @@ ohos_unittest("extension_record_manager_test") { "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_factory.cpp", "${ability_runtime_services_path}/abilitymgr/src/extension_record/extension_record_manager.cpp", + "${ability_runtime_services_path}/abilitymgr/src/extension_running_timeout_monitor.cpp", + "${ability_runtime_services_path}/abilitymgr/src/extension_config.cpp", "${ability_runtime_services_path}/abilitymgr/src/ui_extension/preload_uiext_state_observer.cpp", "${ability_runtime_services_path}/abilitymgr/src/ui_extension_record/ui_extension_record.cpp", "${ability_runtime_services_path}/abilitymgr/src/ui_extension_record/ui_extension_record_factory.cpp",