1 /*
2 * Copyright (C) 2023-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "process_status.h"
16
17 #include <unordered_map>
18
19 #include "common_utils.h"
20 #include "file_util.h"
21 #include "hiview_logger.h"
22 #include "time_util.h"
23 #include "unified_collection_data.h"
24
25 namespace OHOS {
26 namespace HiviewDFX {
27 namespace UCollectUtil {
28 DEFINE_LOG_TAG("ProcessStatus");
29 namespace {
30 constexpr uint64_t INVALID_LAST_FOREGROUND_TIME = 0;
31 }
32
GetProcessName(int32_t pid)33 std::string ProcessStatus::GetProcessName(int32_t pid)
34 {
35 std::unique_lock<std::mutex> lock(mutex_);
36 // the cleanup judgment is triggered each time
37 if (NeedClearProcessInfos()) {
38 ClearProcessInfos();
39 }
40
41 if (processInfos_.find(pid) != processInfos_.end() && !processInfos_[pid].name.empty()) {
42 return processInfos_[pid].name;
43 }
44 std::string procName = CommonUtils::GetProcFullNameByPid(pid);
45 if (UpdateProcessName(pid, procName)) {
46 return procName;
47 }
48 HIVIEW_LOGD("failed to get proc name from pid=%{public}d", pid);
49 return "";
50 }
51
NeedClearProcessInfos()52 bool ProcessStatus::NeedClearProcessInfos()
53 {
54 if (processInfos_.size() <= capacity_) {
55 return false;
56 }
57 static uint64_t lastClearTime = 0;
58 uint64_t now = TimeUtil::GetSteadyClockTimeMs();
59 uint64_t interval = now > lastClearTime ? (now - lastClearTime) : 0;
60 constexpr uint32_t clearInterval = 600 * 1000; // 10min
61 if (interval <= clearInterval) {
62 return false;
63 }
64 lastClearTime = now;
65 return true;
66 }
67
ClearProcessInfos()68 void ProcessStatus::ClearProcessInfos()
69 {
70 HIVIEW_LOGI("start to clear process cache, size=%{public}zu, capacity=%{public}u", processInfos_.size(), capacity_);
71 for (auto it = processInfos_.begin(); it != processInfos_.end();) {
72 if (!CommonUtils::IsPidExist(it->first) || CommonUtils::GetProcFullNameByPid(it->first) != it->second.name) {
73 it = processInfos_.erase(it);
74 continue;
75 }
76 it++;
77 }
78 constexpr uint32_t reservedNum = 100;
79 capacity_ = processInfos_.size() + reservedNum;
80 HIVIEW_LOGI("end to clear process cache, size=%{public}zu, capacity=%{public}u", processInfos_.size(), capacity_);
81 }
82
UpdateProcessName(int32_t pid,const std::string & procName)83 bool ProcessStatus::UpdateProcessName(int32_t pid, const std::string& procName)
84 {
85 if (procName.empty()) {
86 return false;
87 }
88
89 if (processInfos_.find(pid) != processInfos_.end()) {
90 processInfos_[pid].name = procName;
91 return true;
92 }
93 processInfos_[pid] = {
94 .name = procName,
95 .state = BACKGROUND,
96 .lastForegroundTime = INVALID_LAST_FOREGROUND_TIME,
97 };
98 return true;
99 }
100
GetProcessState(int32_t pid)101 ProcessState ProcessStatus::GetProcessState(int32_t pid)
102 {
103 std::unique_lock<std::mutex> lock(mutex_);
104 return (processInfos_.find(pid) != processInfos_.end())
105 ? processInfos_[pid].state
106 : BACKGROUND;
107 }
108
GetProcessLastForegroundTime(int32_t pid)109 uint64_t ProcessStatus::GetProcessLastForegroundTime(int32_t pid)
110 {
111 std::unique_lock<std::mutex> lock(mutex_);
112 return (processInfos_.find(pid) != processInfos_.end())
113 ? processInfos_[pid].lastForegroundTime
114 : INVALID_LAST_FOREGROUND_TIME;
115 }
116
NotifyProcessState(int32_t pid,ProcessState procState)117 void ProcessStatus::NotifyProcessState(int32_t pid, ProcessState procState)
118 {
119 std::unique_lock<std::mutex> lock(mutex_);
120 UpdateProcessState(pid, procState);
121 }
122
UpdateProcessState(int32_t pid,ProcessState procState)123 void ProcessStatus::UpdateProcessState(int32_t pid, ProcessState procState)
124 {
125 HIVIEW_LOGD("pid=%{public}d state=%{public}d", pid, procState);
126 switch (procState) {
127 case FOREGROUND:
128 UpdateProcessForegroundState(pid);
129 break;
130 case BACKGROUND:
131 UpdateProcessBackgroundState(pid);
132 break;
133 case CREATED:
134 ClearProcessInfo(pid);
135 break;
136 case DIED:
137 ClearProcessInfo(pid);
138 break;
139 default:
140 HIVIEW_LOGW("invalid process=%{public}d state=%{public}d", pid, procState);
141 }
142 }
143
UpdateProcessForegroundState(int32_t pid)144 void ProcessStatus::UpdateProcessForegroundState(int32_t pid)
145 {
146 HIVIEW_LOGI("pid=%{public}d state=FOREGROUND", pid);
147 uint64_t nowTime = TimeUtil::GetMilliseconds();
148 if (processInfos_.find(pid) != processInfos_.end()) {
149 processInfos_[pid].state = FOREGROUND;
150 processInfos_[pid].lastForegroundTime = nowTime;
151 return;
152 }
153 processInfos_[pid] = {
154 .name = CommonUtils::GetProcFullNameByPid(pid),
155 .state = FOREGROUND,
156 .lastForegroundTime = nowTime,
157 };
158 }
159
UpdateProcessBackgroundState(int32_t pid)160 void ProcessStatus::UpdateProcessBackgroundState(int32_t pid)
161 {
162 HIVIEW_LOGI("pid=%{public}d state=BACKGROUND", pid);
163 if (processInfos_.find(pid) != processInfos_.end()) {
164 // last foreground time needs to be updated when the foreground status is switched to the background
165 if (processInfos_[pid].state == FOREGROUND) {
166 processInfos_[pid].lastForegroundTime = TimeUtil::GetMilliseconds();
167 }
168 processInfos_[pid].state = BACKGROUND;
169 return;
170 }
171 processInfos_[pid] = {
172 .name = CommonUtils::GetProcFullNameByPid(pid),
173 .state = BACKGROUND,
174 .lastForegroundTime = INVALID_LAST_FOREGROUND_TIME,
175 };
176 }
177
ClearProcessInfo(int32_t pid)178 void ProcessStatus::ClearProcessInfo(int32_t pid)
179 {
180 if (processInfos_.find(pid) != processInfos_.end()) {
181 processInfos_.erase(pid);
182 HIVIEW_LOGD("end to clear process cache, pid=%{public}d", pid);
183 }
184 }
185 } // UCollectUtil
186 } // namespace HiviewDFX
187 } // namespace OHOS
188