diff --git a/OAT.xml b/OAT.xml index 8dca4dd1122389f3e550789ae95b3c5155cb40ee..4c5f051eabe86bbeaed58f72de142bdfb37be482 100644 --- a/OAT.xml +++ b/OAT.xml @@ -62,6 +62,7 @@ Note:If the text contains special characters, please escape them according to th + @@ -71,6 +72,7 @@ Note:If the text contains special characters, please escape them according to th + diff --git a/framework/native/unified_collection/process/include/process_status.h b/framework/native/unified_collection/process/include/process_status.h index f0a95f81d53cadd57edbf8d4f58cb1cc51e8898b..af3ad60f39fd2e3e6cc2b4eed66b1ab176fab6e5 100644 --- a/framework/native/unified_collection/process/include/process_status.h +++ b/framework/native/unified_collection/process/include/process_status.h @@ -23,18 +23,37 @@ namespace OHOS { namespace HiviewDFX { namespace UCollectUtil { +enum ProcessState { + INVALID = -1, + BACKGROUND = 0, + FOREGROUND, +}; + +struct ProcessInfo { + std::string name; + ProcessState state; + uint64_t lastForegroundTime; +}; + class ProcessStatus : public OHOS::DelayedRefSingleton { public: std::string GetProcessName(int32_t pid); + ProcessState GetProcessState(int32_t pid); + uint64_t GetProcessLastForegroundTime(int32_t pid); + void NotifyProcessState(int32_t pid, ProcessState procState); private: - bool NeedClearProcessNames(); - void ClearProcessNames(); + bool UpdateProcessName(int32_t pid, const std::string& procName); + void UpdateProcessState(int32_t pid, ProcessState procState); + void UpdateProcessForegroundState(int32_t pid); + void UpdateProcessBackgroundState(int32_t pid); + bool NeedClearProcessInfos(); + void ClearProcessInfos(); private: std::mutex mutex_; - /* map */ - std::unordered_map processNames_; + /* map */ + std::unordered_map processInfos_; }; } // namespace UCollectUtil } // namespace HiviewDFX diff --git a/framework/native/unified_collection/process/process_status.cpp b/framework/native/unified_collection/process/process_status.cpp index b9140b784e906aca1211a80eb155e520462cdd4e..a18a9b14ae59d68292fb6c278ee05b7fb4265b3f 100644 --- a/framework/native/unified_collection/process/process_status.cpp +++ b/framework/native/unified_collection/process/process_status.cpp @@ -14,14 +14,19 @@ */ #include "process_status.h" +#include + #include "file_util.h" #include "logger.h" +#include "time_util.h" namespace OHOS { namespace HiviewDFX { namespace UCollectUtil { DEFINE_LOG_TAG("UCollectUtil-ProcessStatus"); namespace { +constexpr uint64_t INVALID_LAST_FOREGROUND_TIME = 0; + bool IsValidProcessId(int32_t pid) { std::string procDir = "/proc/" + std::to_string(pid); @@ -78,44 +83,129 @@ std::string ProcessStatus::GetProcessName(int32_t pid) { std::unique_lock lock(mutex_); // the cleanup judgment is triggered each time - if (NeedClearProcessNames()) { - ClearProcessNames(); + if (NeedClearProcessInfos()) { + ClearProcessInfos(); } - if (processNames_.find(pid) != processNames_.end()) { - return processNames_[pid]; + if (processInfos_.find(pid) != processInfos_.end() && !processInfos_[pid].name.empty()) { + return processInfos_[pid].name; } std::string procName = GetProcessNameFromProcCmdline(pid); - if (!procName.empty()) { - processNames_[pid] = procName; + if (UpdateProcessName(pid, procName)) { return procName; } procName = GetProcessNameFromProcStat(pid); - if (!procName.empty()) { - processNames_[pid] = procName; + if (UpdateProcessName(pid, procName)) { return procName; } HIVIEW_LOGW("failed to get proc name from pid=%{public}d", pid); return ""; } -bool ProcessStatus::NeedClearProcessNames() +bool ProcessStatus::NeedClearProcessInfos() { constexpr size_t maxSizeOfProcessNames = 1000; - return processNames_.size() > maxSizeOfProcessNames; + return processInfos_.size() > maxSizeOfProcessNames; } -void ProcessStatus::ClearProcessNames() +void ProcessStatus::ClearProcessInfos() { - HIVIEW_LOGI("start to clear process name, size=%{public}zu", processNames_.size()); - for (auto it = processNames_.begin(); it != processNames_.end();) { + HIVIEW_LOGI("start to clear process cache, size=%{public}zu", processInfos_.size()); + for (auto it = processInfos_.begin(); it != processInfos_.end();) { if (!IsValidProcessId(it->first)) { - processNames_.erase(it++); + processInfos_.erase(it++); } else { it++; } } - HIVIEW_LOGI("end to clear process name, size=%{public}zu", processNames_.size()); + HIVIEW_LOGI("end to clear process cache, size=%{public}zu", processInfos_.size()); +} + +bool ProcessStatus::UpdateProcessName(int32_t pid, const std::string& procName) +{ + if (procName.empty()) { + return false; + } + + if (processInfos_.find(pid) != processInfos_.end()) { + processInfos_[pid].name = procName; + return true; + } + processInfos_[pid] = { + .name = procName, + .state = BACKGROUND, + .lastForegroundTime = INVALID_LAST_FOREGROUND_TIME, + }; + return true; +} + +ProcessState ProcessStatus::GetProcessState(int32_t pid) +{ + std::unique_lock lock(mutex_); + return (processInfos_.find(pid) != processInfos_.end()) + ? processInfos_[pid].state + : BACKGROUND; +} + +uint64_t ProcessStatus::GetProcessLastForegroundTime(int32_t pid) +{ + std::unique_lock lock(mutex_); + return (processInfos_.find(pid) != processInfos_.end()) + ? processInfos_[pid].lastForegroundTime + : INVALID_LAST_FOREGROUND_TIME; +} + +void ProcessStatus::NotifyProcessState(int32_t pid, ProcessState procState) +{ + std::unique_lock lock(mutex_); + UpdateProcessState(pid, procState); +} + +void ProcessStatus::UpdateProcessState(int32_t pid, ProcessState procState) +{ + HIVIEW_LOGI("update process=%{public}d state=%{public}d", pid, procState); + switch (procState) { + case FOREGROUND: + UpdateProcessForegroundState(pid); + break; + case BACKGROUND: + UpdateProcessBackgroundState(pid); + break; + default: + HIVIEW_LOGW("invalid process=%{public}d state=%{public}d", pid, procState); + } +} + +void ProcessStatus::UpdateProcessForegroundState(int32_t pid) +{ + uint64_t nowTime = TimeUtil::GetMilliseconds(); + if (processInfos_.find(pid) != processInfos_.end()) { + processInfos_[pid].state = FOREGROUND; + processInfos_[pid].lastForegroundTime = nowTime; + return; + } + processInfos_[pid] = { + .name = "", + .state = FOREGROUND, + .lastForegroundTime = nowTime, + }; +} + +void ProcessStatus::UpdateProcessBackgroundState(int32_t pid) +{ + if (processInfos_.find(pid) != processInfos_.end()) { + // last foreground time needs to be updated when the foreground status is switched to the background + if (processInfos_[pid].state == FOREGROUND) { + processInfos_[pid].lastForegroundTime = TimeUtil::GetMilliseconds(); + } + processInfos_[pid].state = BACKGROUND; + return; + } + processInfos_[pid] = { + .name = "", + .state = BACKGROUND, + .lastForegroundTime = INVALID_LAST_FOREGROUND_TIME, + }; } } // UCollectUtil } // namespace HiviewDFX diff --git a/plugins/unified_collector/BUILD.gn b/plugins/unified_collector/BUILD.gn index f5e149fefa06e04af2d006e7bd5aca772d20c3bb..970f28c51b424fc17a5d5e24e451ed849c0d8b52 100644 --- a/plugins/unified_collector/BUILD.gn +++ b/plugins/unified_collector/BUILD.gn @@ -19,6 +19,7 @@ config("unified_collector_config") { "include", "storage/include", "task/include", + "$hiview_framework/native/unified_collection/process/include", ] } @@ -34,6 +35,7 @@ ohos_source_set("unified_collector") { deps = [ "$hiview_base:hiviewbase", "$hiview_interfaces/inner_api/unified_collection/utility:libucollection_utility", + "config:UnifiedCollector_event", ] external_deps = [ diff --git a/plugins/unified_collector/config/BUILD.gn b/plugins/unified_collector/config/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..5248d6f5dcd58538a3534bf8dbe5dcabe5c31efb --- /dev/null +++ b/plugins/unified_collector/config/BUILD.gn @@ -0,0 +1,20 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import("//build/ohos.gni") + +ohos_prebuilt_etc("UnifiedCollector_event") { + source = "UnifiedCollector" + relative_install_dir = "hiview/listener_rule" + part_name = "hiview" + subsystem_name = "hiviewdfx" +} diff --git a/plugins/unified_collector/config/UnifiedCollector b/plugins/unified_collector/config/UnifiedCollector new file mode 100644 index 0000000000000000000000000000000000000000..4efb8a0e0d3df6e8f654e95794c8cfce2b003e8a --- /dev/null +++ b/plugins/unified_collector/config/UnifiedCollector @@ -0,0 +1,8 @@ +{ + "domains": [ + { + "domain": "AAFWK", + "include": ["APP_FOREGROUND", "APP_BACKGROUND"] + } + ] +} \ No newline at end of file diff --git a/plugins/unified_collector/include/unified_collector.h b/plugins/unified_collector/include/unified_collector.h index 96af9232ae3cb675e9450da92de64021938594ee..b0db43048242febe010f8bcee70fa2e8bdf1b5c2 100644 --- a/plugins/unified_collector/include/unified_collector.h +++ b/plugins/unified_collector/include/unified_collector.h @@ -26,6 +26,7 @@ class UnifiedCollector : public Plugin { public: void OnLoad() override; void OnUnload() override; + void OnEventListeningCallback(const Event& event) override; private: void Init(); diff --git a/plugins/unified_collector/storage/cpu_storage.cpp b/plugins/unified_collector/storage/cpu_storage.cpp index 94e00d1e20e782df1f779861d09edc9e394e70a8..c7b0053adac0c5a45858c22a61b600cf6fc0373e 100644 --- a/plugins/unified_collector/storage/cpu_storage.cpp +++ b/plugins/unified_collector/storage/cpu_storage.cpp @@ -20,6 +20,7 @@ #include "file_util.h" #include "hisysevent.h" #include "logger.h" +#include "process_status.h" #include "rdb_helper.h" #include "sql_util.h" #include "string_util.h" @@ -28,6 +29,7 @@ namespace OHOS { namespace HiviewDFX { DEFINE_LOG_TAG("HiView-CpuStorage"); +using namespace OHOS::HiviewDFX::UCollectUtil; namespace { constexpr int32_t DB_VERSION = 1; const std::string TABLE_NAME = "unified_collection_cpu"; @@ -35,6 +37,7 @@ const std::string COLUMN_START_TIME = "start_time"; const std::string COLUMN_END_TIME = "end_time"; const std::string COLUMN_PID = "pid"; const std::string COLUMN_PROC_NAME = "proc_name"; +const std::string COLUMN_PROC_STATE = "proc_state"; const std::string COLUMN_CPU_LOAD = "cpu_load"; const std::string COLUMN_CPU_USAGE = "cpu_usage"; constexpr uint32_t MAX_NUM_OF_DB_FILES = 7; // save files for one week @@ -99,6 +102,24 @@ double TruncateDecimalWithNBitPrecision(double decimal, uint32_t precision = DEF auto truncateCoefficient = std::pow(10, precision); return std::floor(decimal * truncateCoefficient) / truncateCoefficient; } + +bool IsForegroundStateInCollectionPeriod(const ProcessCpuStatInfo& cpuCollectionInfo) +{ + int32_t pid = cpuCollectionInfo.pid; + ProcessState procState = ProcessStatus::GetInstance().GetProcessState(pid); + if (procState == FOREGROUND) { + return true; + } + uint64_t procForegroundTime = ProcessStatus::GetInstance().GetProcessLastForegroundTime(pid); + return (procForegroundTime >= cpuCollectionInfo.startTime && procForegroundTime < cpuCollectionInfo.endTime); +} + +int32_t GetProcessStateInCollectionPeriod(const ProcessCpuStatInfo& cpuCollectionInfo) +{ + return IsForegroundStateInCollectionPeriod(cpuCollectionInfo) + ? static_cast(FOREGROUND) + : static_cast(ProcessStatus::GetInstance().GetProcessState(cpuCollectionInfo.pid)); +} } class CpuDbStoreCallback : public NativeRdb::RdbOpenCallback { @@ -181,6 +202,7 @@ void CpuStorage::InsertTable(const ProcessCpuStatInfo& cpuCollectionInfo) bucket.PutLong(COLUMN_START_TIME, static_cast(cpuCollectionInfo.startTime)); bucket.PutLong(COLUMN_END_TIME, static_cast(cpuCollectionInfo.endTime)); bucket.PutInt(COLUMN_PID, cpuCollectionInfo.pid); + bucket.PutInt(COLUMN_PROC_STATE, GetProcessStateInCollectionPeriod(cpuCollectionInfo)); bucket.PutString(COLUMN_PROC_NAME, cpuCollectionInfo.procName); bucket.PutDouble(COLUMN_CPU_LOAD, TruncateDecimalWithNBitPrecision(cpuCollectionInfo.cpuLoad)); bucket.PutDouble(COLUMN_CPU_USAGE, TruncateDecimalWithNBitPrecision(cpuCollectionInfo.cpuUsage)); @@ -195,16 +217,17 @@ int32_t CpuStorage::CreateTable() /** * table: unified_collection_cpu * - * |-----|------------|----------|-----|-----------|----------|-----------| - * | id | start_time | end_time | pid | proc_name | cpu_load | cpu_usage | - * |-----|------------|----------|-----|-----------|----------|-----------| - * | INT | INT64 | INT64 | INT | VARCHAR | DOUBLE | DOUBLE | - * |-----|------------|----------|-----|-----------|----------|-----------| + * |-----|------------|----------|-----|------------|-----------|----------|-----------| + * | id | start_time | end_time | pid | proc_state | proc_name | cpu_load | cpu_usage | + * |-----|------------|----------|-----|------------|-----------|----------|-----------| + * | INT | INT64 | INT64 | INT | INT | VARCHAR | DOUBLE | DOUBLE | + * |-----|------------|----------|-----|------------|-----------|----------|-----------| */ const std::vector> fields = { {COLUMN_START_TIME, SqlUtil::COLUMN_TYPE_INT}, {COLUMN_END_TIME, SqlUtil::COLUMN_TYPE_INT}, {COLUMN_PID, SqlUtil::COLUMN_TYPE_INT}, + {COLUMN_PROC_STATE, SqlUtil::COLUMN_TYPE_INT}, {COLUMN_PROC_NAME, SqlUtil::COLUMN_TYPE_STR}, {COLUMN_CPU_LOAD, SqlUtil::COLUMN_TYPE_DOU}, {COLUMN_CPU_USAGE, SqlUtil::COLUMN_TYPE_DOU}, diff --git a/plugins/unified_collector/unified_collector.cpp b/plugins/unified_collector/unified_collector.cpp index a0cab73fb6a49069b44ebccb1e28861b0b202f2d..4551737c5ad64033d1828b18aa5de9583186f987 100644 --- a/plugins/unified_collector/unified_collector.cpp +++ b/plugins/unified_collector/unified_collector.cpp @@ -17,11 +17,30 @@ #include "file_util.h" #include "logger.h" #include "plugin_factory.h" +#include "process_status.h" +#include "sys_event.h" namespace OHOS { namespace HiviewDFX { REGISTER(UnifiedCollector); DEFINE_LOG_TAG("HiView-UnifiedCollector"); +using namespace OHOS::HiviewDFX::UCollectUtil; +namespace { +const std::unordered_map APP_STATES = { + {"APP_FOREGROUND", FOREGROUND}, + {"APP_BACKGROUND", BACKGROUND}, +}; + +ProcessState GetProcessStateByEvent(const SysEvent& sysEvent) +{ + std::string eventName = sysEvent.GetEventName(); + if (APP_STATES.find(eventName) != APP_STATES.end()) { + return APP_STATES.at(eventName); + } + HIVIEW_LOGW("invalid event name=%{public}s", eventName.c_str()); + return INVALID; +} +} void UnifiedCollector::OnLoad() { @@ -34,6 +53,22 @@ void UnifiedCollector::OnUnload() HIVIEW_LOGI("start to unload UnifiedCollector plugin"); } +void UnifiedCollector::OnEventListeningCallback(const Event& event) +{ + SysEvent& sysEvent = static_cast(const_cast(event)); + int32_t procId = sysEvent.GetEventIntValue("APP_PID"); + if (procId <= 0) { + HIVIEW_LOGW("invalid process id=%{public}d", procId); + return; + } + ProcessState procState = GetProcessStateByEvent(sysEvent); + if (procState == INVALID) { + HIVIEW_LOGW("invalid process state=%{public}d", procState); + return; + } + ProcessStatus::GetInstance().NotifyProcessState(procId, procState); +} + void UnifiedCollector::Init() { if (GetHiviewContext() == nullptr) {