• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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