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 "common_utils.h"
18 #include "file_util.h"
19 #include "hiview_logger.h"
20 #include "time_util.h"
21 #include "unified_collection_data.h"
22
23 namespace OHOS {
24 namespace HiviewDFX {
25 namespace UCollectUtil {
26 DEFINE_LOG_TAG("ProcessStatus");
27 namespace {
28 constexpr uint64_t INVALID_LAST_FOREGROUND_TIME = 0;
29 }
30
GetProcessName(int32_t pid)31 std::string ProcessStatus::GetProcessName(int32_t pid)
32 {
33 std::unique_lock<std::mutex> lock(mutex_);
34 // the cleanup judgment is triggered each time
35 if (NeedClearProcessInfos()) {
36 ClearProcessInfos();
37 }
38
39 if (processInfos_.find(pid) != processInfos_.end() && !processInfos_[pid].name.empty()) {
40 return processInfos_[pid].name;
41 }
42 std::string procName = CommonUtils::GetProcFullNameByPid(pid);
43 if (UpdateProcessName(pid, procName)) {
44 return procName;
45 }
46 HIVIEW_LOGD("failed to get proc name from pid=%{public}d", pid);
47 return "";
48 }
49
NeedClearProcessInfos()50 bool ProcessStatus::NeedClearProcessInfos()
51 {
52 if (processInfos_.size() <= capacity_) {
53 return false;
54 }
55 static uint64_t lastClearTime = 0;
56 uint64_t now = TimeUtil::GetSteadyClockTimeMs();
57 uint64_t interval = now > lastClearTime ? (now - lastClearTime) : 0;
58 constexpr uint32_t clearInterval = 600 * 1000; // 10min
59 if (interval <= clearInterval) {
60 return false;
61 }
62 lastClearTime = now;
63 return true;
64 }
65
ClearProcessInfos()66 void ProcessStatus::ClearProcessInfos()
67 {
68 HIVIEW_LOGI("start to clear process cache, size=%{public}zu, capacity=%{public}u", processInfos_.size(), capacity_);
69 for (auto it = processInfos_.begin(); it != processInfos_.end();) {
70 if (!CommonUtils::IsPidExist(it->first) || CommonUtils::GetProcFullNameByPid(it->first) != it->second.name) {
71 it = processInfos_.erase(it);
72 continue;
73 }
74 it++;
75 }
76 constexpr uint32_t reservedNum = 100;
77 capacity_ = processInfos_.size() + reservedNum;
78 HIVIEW_LOGI("end to clear process cache, size=%{public}zu, capacity=%{public}u", processInfos_.size(), capacity_);
79 }
80
UpdateProcessName(int32_t pid,const std::string & procName)81 bool ProcessStatus::UpdateProcessName(int32_t pid, const std::string& procName)
82 {
83 if (procName.empty()) {
84 return false;
85 }
86
87 if (processInfos_.find(pid) != processInfos_.end()) {
88 processInfos_[pid].name = procName;
89 return true;
90 }
91 processInfos_[pid] = {
92 .name = procName,
93 .state = BACKGROUND,
94 .lastForegroundTime = INVALID_LAST_FOREGROUND_TIME,
95 };
96 return true;
97 }
98
GetProcessState(int32_t pid)99 ProcessState ProcessStatus::GetProcessState(int32_t pid)
100 {
101 std::unique_lock<std::mutex> lock(mutex_);
102 return (processInfos_.find(pid) != processInfos_.end())
103 ? processInfos_[pid].state
104 : BACKGROUND;
105 }
106
GetProcessLastForegroundTime(int32_t pid)107 uint64_t ProcessStatus::GetProcessLastForegroundTime(int32_t pid)
108 {
109 std::unique_lock<std::mutex> lock(mutex_);
110 return (processInfos_.find(pid) != processInfos_.end())
111 ? processInfos_[pid].lastForegroundTime
112 : INVALID_LAST_FOREGROUND_TIME;
113 }
114
NotifyProcessState(int32_t pid,ProcessState procState)115 void ProcessStatus::NotifyProcessState(int32_t pid, ProcessState procState)
116 {
117 std::unique_lock<std::mutex> lock(mutex_);
118 UpdateProcessState(pid, procState);
119 }
120
UpdateProcessState(int32_t pid,ProcessState procState)121 void ProcessStatus::UpdateProcessState(int32_t pid, ProcessState procState)
122 {
123 HIVIEW_LOGD("pid=%{public}d state=%{public}d", pid, procState);
124 switch (procState) {
125 case FOREGROUND:
126 UpdateProcessForegroundState(pid);
127 break;
128 case BACKGROUND:
129 UpdateProcessBackgroundState(pid);
130 break;
131 case CREATED:
132 ClearProcessInfo(pid);
133 break;
134 case DIED:
135 ClearProcessInfo(pid);
136 break;
137 default:
138 HIVIEW_LOGW("invalid process=%{public}d state=%{public}d", pid, procState);
139 }
140 }
141
UpdateProcessForegroundState(int32_t pid)142 void ProcessStatus::UpdateProcessForegroundState(int32_t pid)
143 {
144 HIVIEW_LOGI("pid=%{public}d state=FOREGROUND", pid);
145 uint64_t nowTime = TimeUtil::GetMilliseconds();
146 if (processInfos_.find(pid) != processInfos_.end()) {
147 processInfos_[pid].state = FOREGROUND;
148 processInfos_[pid].lastForegroundTime = nowTime;
149 return;
150 }
151 processInfos_[pid] = {
152 .name = CommonUtils::GetProcFullNameByPid(pid),
153 .state = FOREGROUND,
154 .lastForegroundTime = nowTime,
155 };
156 }
157
UpdateProcessBackgroundState(int32_t pid)158 void ProcessStatus::UpdateProcessBackgroundState(int32_t pid)
159 {
160 HIVIEW_LOGI("pid=%{public}d state=BACKGROUND", pid);
161 if (processInfos_.find(pid) != processInfos_.end()) {
162 // last foreground time needs to be updated when the foreground status is switched to the background
163 if (processInfos_[pid].state == FOREGROUND) {
164 processInfos_[pid].lastForegroundTime = TimeUtil::GetMilliseconds();
165 }
166 processInfos_[pid].state = BACKGROUND;
167 return;
168 }
169 processInfos_[pid] = {
170 .name = CommonUtils::GetProcFullNameByPid(pid),
171 .state = BACKGROUND,
172 .lastForegroundTime = INVALID_LAST_FOREGROUND_TIME,
173 };
174 }
175
ClearProcessInfo(int32_t pid)176 void ProcessStatus::ClearProcessInfo(int32_t pid)
177 {
178 if (processInfos_.find(pid) != processInfos_.end()) {
179 processInfos_.erase(pid);
180 HIVIEW_LOGD("end to clear process cache, pid=%{public}d", pid);
181 }
182 }
183 } // UCollectUtil
184 } // namespace HiviewDFX
185 } // namespace OHOS
186