mirror of
https://github.com/openharmony/ability_ability_runtime.git
synced 2026-08-24 22:21:36 -04:00
!18898 merge feat/extension-timeout-monitor-for-test into master
feat: add dump interface for extension running timeout monitor Created-by: zhang_hao_zheng Commit-by: zhang_hao_zheng Merged-by: openharmony_ci Description: **IssueNo**: https://gitcode.com/openharmony/ability_ability_runtime/issues/14920 **Description**: **稳定性自检:** | 自检项 | 自检结果 | | ------------------------------------------------------------ | -------- | | 涉及跨进程调用的相关操作需要抛至主线程或加锁防止并发 | √ | | 成员变量进行赋值或创建需要排查并发 | √ | | 谨慎在lambda表达式中使用引用捕获 | √ | | 谨慎在未经拷贝的情况下使用外部传入的string、C字符串 | √ | | map\vector\list\set等stl模板类使用时需要排查并发 | √ | | 谨慎考虑加锁范围 | √ | | 在IPC通信中谨慎使用同步通信方式 | √ | | 禁止传递this指针至其他模块或线程(特别是eventhandler任务) | √ | | 禁止将外部传入的裸指针在内部直接构造智能指针 | √ | | 禁止多个独立创建的智能指针管理同一地址 | √ | | 禁止在析构函数中抛异步任务 | √ | | 禁止js对象在非js线程(例如在IPC线程)创建、使用或销毁 | √ | | 禁止在对外接口中未经判空直接使用外部传入的指针 | √ | | 禁止接口返回局部变量引用 | √ | | 禁止在信号函数中加锁 | √ | | 禁止在关键流程(SA启动、应用启动等主流程)执行耗时的操作 | √ | | 禁止将同一个cpp编译在不同的so中 | √ | **安全编码自检:** | 自检项 | 自检结果 | | -------------------------------------------------------------- | -------- | | 裸指针避免通过隐式转换构造为sptr | √ | | json对象在取值之前必须先判断类型,避免类型不匹配 | √ | | 序列化时必须对传入的数组大小进行校验,避免出现超大数组 | √ | | 避免使用未明确位宽的整型,选择使用int8_t、uint8_t等类型 | √ | | 外部传入的路径要做规范化校验,对路径中的.、..、../等特殊字符严格校验 | √ | | 指针变量、表示资源描述符的变量、bool变量必须赋初值 | √ | | readParcelable获取的对象使用前需要判空 | √ | | 分配和释放内存的函数需要成对出现 | √ | | 申请内存后异常退出前需要及时进行内存释放 | √ | | 内存申请前必须对内存大小进行合法性校验 | √ | | 内存分配后必须判断是否成功 | √ | | 禁止使用realloc、alloca函数 | √ | | 禁止打印文件路径、口令等敏感信息,如有需要,使用private修饰 | √ | | 禁止打印内存地址 | √ | | 整数之间运算时必须严格检查,确保不会出现溢出、反转、除0 | √ | | 禁止对有符号整数进行位操作符运算 | √ | | 禁止对指针进行逻辑或位运算 | √ | | 循环次数如果收外部数据控制,需要检验其合法性 | √ | | 禁止使用内存操作类危险函数,需要使用安全函数 | √ | | 谨慎使用不可重入函数 | √ | | 必须检查安全函数的返回值,并进行正确处理 | √ | | 禁止仅通过TokenType类型判断绕过权限校验 | √ | **TDD Result**: pass **XTS Result**: pass ### 是否已执行L0用例 - [ ] 已验证 - [ ] 不涉及。如不涉及,请写明理由 See merge request: openharmony/ability_ability_runtime!18898
This commit is contained in:
+10
-1
@@ -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}
|
||||
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}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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<std::string> 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);
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 <list>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#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<ExtensionRunningTimeoutMonitor> {
|
||||
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<ExtensionTimeoutEvent>::iterator &dupIter);
|
||||
void SubmitPeriodicTask();
|
||||
|
||||
std::mutex monitorMutex_;
|
||||
std::unordered_map<int32_t, ExtensionStartInfo> runningExtensions_;
|
||||
std::list<ExtensionTimeoutEvent> 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
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"ams_extension_config": []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<AAFwk::ExtensionRunningTimeoutMonitor>::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<AAFwk::ExtensionRunningTimeoutMonitor>::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());
|
||||
}
|
||||
|
||||
@@ -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<AbilityRuntime::ModularObjectExtensionEventMgr>();
|
||||
modularObjectExtensionEventMgr_->SubscribeSysEventReceiver();
|
||||
ReportDataPartitionUsageManager::SendReportDataPartitionUsageEvent();
|
||||
DelayedSingleton<AAFwk::ExtensionRunningTimeoutMonitor>::GetInstance()->StartMonitor();
|
||||
#ifdef RESOURCE_SCHEDULE_SERVICE_ENABLE
|
||||
ResourceSchedule::ResSchedClient::GetInstance().InitKillReasonListener();
|
||||
#endif
|
||||
|
||||
@@ -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<std::string>();
|
||||
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<int32_t>();
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -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<std::mutex> 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<AAFwk::ExtensionRunningTimeoutMonitor>::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<std::mutex> lock(mutex_);
|
||||
extensionRecords_.erase(extensionRecordId);
|
||||
terminateRecords_.erase(extensionRecordId);
|
||||
|
||||
// Notify running timeout monitor about extension termination
|
||||
auto monitor = DelayedSingleton<AAFwk::ExtensionRunningTimeoutMonitor>::GetInstance();
|
||||
if (monitor != nullptr) {
|
||||
monitor->OnExtensionTerminated(extensionRecordId);
|
||||
}
|
||||
}
|
||||
|
||||
void ExtensionRecordManager::AddExtensionRecordToTerminatedList(const int32_t extensionRecordId)
|
||||
|
||||
@@ -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 <chrono>
|
||||
#include <cinttypes>
|
||||
#include <functional>
|
||||
|
||||
#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<std::unique_ptr<char[]>> &buffers,
|
||||
std::vector<char*> &ptrs)
|
||||
{
|
||||
size_t len = str.size() + 1;
|
||||
auto buf = std::make_unique<char[]>(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<std::chrono::milliseconds>(now.time_since_epoch()).count();
|
||||
|
||||
ExtensionStartInfo info;
|
||||
info.extensionTypeName = extensionTypeName;
|
||||
info.bundleName = bundleName;
|
||||
info.abilityName = abilityName;
|
||||
info.startTimeMillis = startTimeMillis;
|
||||
|
||||
std::lock_guard<std::mutex> lock(monitorMutex_);
|
||||
runningExtensions_[extensionRecordId] = info;
|
||||
}
|
||||
|
||||
void ExtensionRunningTimeoutMonitor::OnExtensionTerminated(int32_t extensionRecordId)
|
||||
{
|
||||
TAG_LOGD(AAFwkTag::ABILITYMGR, "recordId: %{public}d", extensionRecordId);
|
||||
|
||||
ExtensionStartInfo startInfo;
|
||||
{
|
||||
std::lock_guard<std::mutex> 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<ExtensionConfig>::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<std::chrono::milliseconds>(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<std::mutex> 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<ExtensionRunningTimeoutMonitor>::GetInstance();
|
||||
monitor->CheckAliveExtensions();
|
||||
monitor->ReportTimeoutEvents();
|
||||
monitor->SubmitPeriodicTask();
|
||||
};
|
||||
taskHandler->SubmitTask(task, PERIODIC_TASK_NAME, REPORT_INTERVAL_MS);
|
||||
}
|
||||
|
||||
void ExtensionRunningTimeoutMonitor::ReportTimeoutEvents()
|
||||
{
|
||||
std::list<ExtensionTimeoutEvent> eventsToReport;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(monitorMutex_);
|
||||
if (cachedEvents_.empty()) {
|
||||
TAG_LOGD(AAFwkTag::ABILITYMGR, "no timeout events to report");
|
||||
return;
|
||||
}
|
||||
eventsToReport = cachedEvents_;
|
||||
cachedEvents_.clear();
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<char[]>> stringBuffers;
|
||||
std::vector<char*> extensionTypePtrs;
|
||||
std::vector<char*> bundleNamePtrs;
|
||||
std::vector<char*> abilityNamePtrs;
|
||||
std::vector<int64_t> runningDurations;
|
||||
std::vector<bool> stillAliveFlags;
|
||||
std::vector<int32_t> 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<int32_t, ExtensionStartInfo> aliveCopy;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(monitorMutex_);
|
||||
aliveCopy = runningExtensions_;
|
||||
}
|
||||
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
auto nowMillis = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
|
||||
|
||||
std::vector<ExtensionTimeoutEvent> pendingEvents;
|
||||
for (auto &[recordId, startInfo] : aliveCopy) {
|
||||
int32_t configuredTimeout = DelayedSingleton<ExtensionConfig>::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<std::mutex> lock(monitorMutex_);
|
||||
for (auto &event : pendingEvents) {
|
||||
AddOrUpdateTimeoutEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtensionRunningTimeoutMonitor::IsDuplicateEvent(const ExtensionTimeoutEvent &event,
|
||||
std::list<ExtensionTimeoutEvent>::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<ExtensionTimeoutEvent>::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<int32_t>(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
|
||||
@@ -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<int32_t> &value);
|
||||
void InsertParam(const char* name, std::vector<char*> &value);
|
||||
void InsertParam(const char* name, const std::vector<uint64_t> &value);
|
||||
void InsertParam(const char* name, const std::vector<bool> &value);
|
||||
void InsertParam(const char* name, const std::vector<int64_t> &value);
|
||||
int32_t Report(const char* domain, const char* event, HiSysEventEventType type);
|
||||
|
||||
private:
|
||||
void SetParamName(HiSysEventParam& param, const char* name);
|
||||
|
||||
std::vector<std::unique_ptr<char[]>> paramBuffers_;
|
||||
HiSysEventParam* params_;
|
||||
HiSysEventParam* params_ = nullptr;
|
||||
int32_t length_ = SYSTEM_PARAM_MAX_LEN;
|
||||
int32_t pos_ = 0;
|
||||
};
|
||||
|
||||
@@ -197,7 +197,7 @@ void HisyseventReport::InsertParam(const char* name, char* value)
|
||||
int32_t len = std::strlen(value) + 1;
|
||||
auto buffer = std::make_unique<char[]>(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<char*> &value)
|
||||
params_[pos_++] = param;
|
||||
}
|
||||
|
||||
void HisyseventReport::InsertParam(const char* name, const std::vector<bool> &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<bool*>(buf);
|
||||
for (size_t i = 0; i < value.size(); ++i) {
|
||||
boolBuf[i] = value[i];
|
||||
}
|
||||
param.v.array = static_cast<void*>(boolBuf);
|
||||
param.arraySize = value.size();
|
||||
paramBuffers_.emplace_back(buf);
|
||||
}
|
||||
}
|
||||
SetParamName(param, name);
|
||||
params_[pos_++] = param;
|
||||
}
|
||||
|
||||
void HisyseventReport::InsertParam(const char* name, const std::vector<int64_t> &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<void*>(const_cast<int64_t*>(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<char *>(value.c_str()));
|
||||
this->InsertParam(name, value.c_str());
|
||||
}
|
||||
|
||||
void HisyseventReport::InsertParam(const char* name, const char* value)
|
||||
{
|
||||
this->InsertParam(name, const_cast<char *>(value));
|
||||
if (!name || !value || length_ <= pos_) {
|
||||
TAG_LOGE(AAFwkTag::DEFAULT, "param is full");
|
||||
return;
|
||||
}
|
||||
int32_t len = static_cast<int32_t>(std::strlen(value)) + 1;
|
||||
auto buffer = std::make_unique<char[]>(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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
+610
-1
@@ -14,6 +14,8 @@
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
#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<AAFwk::ExtensionRunningTimeoutMonitor>::GetInstance();
|
||||
monitor->runningExtensions_.clear();
|
||||
monitor->cachedEvents_.clear();
|
||||
}
|
||||
|
||||
void ExtensionRunningTimeoutMonitorTest::TearDown()
|
||||
{
|
||||
auto monitor = DelayedSingleton<AAFwk::ExtensionRunningTimeoutMonitor>::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<AAFwk::ExtensionRunningTimeoutMonitor>::GetInstance();
|
||||
ASSERT_NE(monitor, nullptr);
|
||||
|
||||
monitor->OnExtensionStarted(100, "ServiceExtension", "com.test.bundle", "TestAbility");
|
||||
EXPECT_EQ(monitor->runningExtensions_.size(), static_cast<size_t>(1));
|
||||
EXPECT_EQ(monitor->runningExtensions_.count(100), static_cast<size_t>(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<int64_t>(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<AAFwk::ExtensionRunningTimeoutMonitor>::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<size_t>(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<AAFwk::ExtensionRunningTimeoutMonitor>::GetInstance();
|
||||
ASSERT_NE(monitor, nullptr);
|
||||
|
||||
monitor->OnExtensionStarted(100, "ServiceExtension", "com.test.old", "OldAbility");
|
||||
EXPECT_EQ(monitor->runningExtensions_.size(), static_cast<size_t>(1));
|
||||
|
||||
monitor->OnExtensionStarted(100, "UIExtension", "com.test.new", "NewAbility");
|
||||
EXPECT_EQ(monitor->runningExtensions_.size(), static_cast<size_t>(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<AAFwk::ExtensionRunningTimeoutMonitor>::GetInstance();
|
||||
ASSERT_NE(monitor, nullptr);
|
||||
|
||||
monitor->OnExtensionTerminated(9999);
|
||||
EXPECT_EQ(monitor->runningExtensions_.size(), static_cast<size_t>(0));
|
||||
EXPECT_EQ(monitor->cachedEvents_.size(), static_cast<size_t>(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<AAFwk::ExtensionRunningTimeoutMonitor>::GetInstance();
|
||||
ASSERT_NE(monitor, nullptr);
|
||||
|
||||
monitor->OnExtensionStarted(100, "ServiceExtension", "com.test.bundle", "TestAbility");
|
||||
EXPECT_EQ(monitor->runningExtensions_.size(), static_cast<size_t>(1));
|
||||
|
||||
// No timeout configured (default -1), so no event should be cached
|
||||
monitor->OnExtensionTerminated(100);
|
||||
EXPECT_EQ(monitor->runningExtensions_.size(), static_cast<size_t>(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<AAFwk::ExtensionRunningTimeoutMonitor>::GetInstance();
|
||||
ASSERT_NE(monitor, nullptr);
|
||||
|
||||
// Configure timeout for this extension type via ExtensionConfig
|
||||
auto config = DelayedSingleton<AAFwk::ExtensionConfig>::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<size_t>(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<size_t>(0));
|
||||
EXPECT_EQ(monitor->cachedEvents_.size(), static_cast<size_t>(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<int64_t>(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<AAFwk::ExtensionRunningTimeoutMonitor>::GetInstance();
|
||||
ASSERT_NE(monitor, nullptr);
|
||||
|
||||
// Configure long timeout
|
||||
auto config = DelayedSingleton<AAFwk::ExtensionConfig>::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<size_t>(0));
|
||||
EXPECT_EQ(monitor->cachedEvents_.size(), static_cast<size_t>(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<AAFwk::ExtensionRunningTimeoutMonitor>::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<size_t>(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<AAFwk::ExtensionRunningTimeoutMonitor>::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<size_t>(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<size_t>(1));
|
||||
EXPECT_EQ(monitor->cachedEvents_.front().cnt, 2);
|
||||
EXPECT_EQ(monitor->cachedEvents_.front().runningDuration, static_cast<int64_t>(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<AAFwk::ExtensionRunningTimeoutMonitor>::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<size_t>(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<size_t>(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<AAFwk::ExtensionRunningTimeoutMonitor>::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<AAFwk::ExtensionTimeoutEvent>::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<AAFwk::ExtensionRunningTimeoutMonitor>::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<AAFwk::ExtensionTimeoutEvent>::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<AAFwk::ExtensionRunningTimeoutMonitor>::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<size_t>(1));
|
||||
|
||||
monitor->ReportTimeoutEvents();
|
||||
EXPECT_EQ(monitor->cachedEvents_.size(), static_cast<size_t>(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<AAFwk::ExtensionRunningTimeoutMonitor>::GetInstance();
|
||||
ASSERT_NE(monitor, nullptr);
|
||||
|
||||
EXPECT_EQ(monitor->cachedEvents_.size(), static_cast<size_t>(0));
|
||||
monitor->ReportTimeoutEvents();
|
||||
EXPECT_EQ(monitor->cachedEvents_.size(), static_cast<size_t>(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<AAFwk::ExtensionRunningTimeoutMonitor>::GetInstance();
|
||||
ASSERT_NE(monitor, nullptr);
|
||||
|
||||
// Configure timeout
|
||||
auto config = DelayedSingleton<AAFwk::ExtensionConfig>::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<size_t>(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<int64_t>(1));
|
||||
|
||||
// Extension should still be in running list
|
||||
EXPECT_EQ(monitor->runningExtensions_.size(), static_cast<size_t>(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<AAFwk::ExtensionRunningTimeoutMonitor>::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<size_t>(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<AAFwk::ExtensionRunningTimeoutMonitor>::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<AAFwk::ExtensionRunningTimeoutMonitor>::GetInstance();
|
||||
ASSERT_NE(monitor, nullptr);
|
||||
|
||||
const int32_t threadCount = 10;
|
||||
std::vector<std::thread> 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<size_t>(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<size_t>(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<AAFwk::ExtensionConfig>::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<AAFwk::ExtensionConfig>::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
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user