1 /*
2  * Copyright (C) 2023 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 "shell_catcher.h"
16 #include <regex>
17 #include <unistd.h>
18 #include <sys/wait.h>
19 #include "hiview_logger.h"
20 #include "common_utils.h"
21 #include "cpu_collector.h"
22 #include "log_catcher_utils.h"
23 #include "securec.h"
24 #include "time_util.h"
25 namespace OHOS {
26 namespace HiviewDFX {
27 DEFINE_LOG_LABEL(0xD002D01, "EventLogger-ShellCatcher");
ShellCatcher()28 ShellCatcher::ShellCatcher() : EventLogCatcher()
29 {
30     name_ = "ShellCatcher";
31 }
32 
Initialize(const std::string & cmd,int type,int catcherPid)33 bool ShellCatcher::Initialize(const std::string& cmd, int type, int catcherPid)
34 {
35     catcherCmd_ = cmd;
36     catcherType_ = CATCHER_TYPE(type);
37     pid_ = catcherPid;
38     description_ = "catcher cmd: " + catcherCmd_ + " ";
39     return true;
40 }
41 
SetEvent(std::shared_ptr<SysEvent> event)42 void ShellCatcher::SetEvent(std::shared_ptr<SysEvent> event)
43 {
44     event_ = event;
45 }
46 
47 
DoOtherChildProcesscatcher(int writeFd)48 int ShellCatcher::DoOtherChildProcesscatcher(int writeFd)
49 {
50     int ret = -1;
51     switch (catcherType_) {
52         case CATCHER_TAGHILOG:
53             ret = execl("/system/bin/hilog",
54                 "hilog",
55                 "-T",
56                 "PowerState,PowerSuspend,PowerInput,DisplayState,DfxFaultLogger",
57                 nullptr);
58             break;
59         default:
60             break;
61     }
62     return ret;
63 }
64 
DoChildProcesscatcher(int writeFd)65 int ShellCatcher::DoChildProcesscatcher(int writeFd)
66 {
67     int ret = -1;
68     switch (catcherType_) {
69         case CATCHER_INPUT_EVENT_HILOG:
70             ret = execl("/system/bin/hilog", "hilog", "-T", "InputKeyFlow", "-e",
71                 std::to_string(pid_).c_str(), "-x", nullptr);
72             break;
73         case CATCHER_INPUT_HILOG:
74             ret = execl("/system/bin/hilog", "hilog", "-T", "InputKeyFlow", "-x", nullptr);
75             break;
76         case CATCHER_EEC:
77             {
78                 std::string cmd = "-b EventExclusiveCommander getAllEventExclusiveCaller";
79                 ret = execl("/system/bin/hidumper", "hidumper", "-s", "4606", "-a", cmd.c_str(), nullptr);
80             }
81             break;
82         case CATCHER_GEC:
83             {
84                 std::string cmd = "-b SCBGestureManager getAllGestureEnableCaller";
85                 ret = execl("/system/bin/hidumper", "hidumper", "-s", "4606", "-a", cmd.c_str(), nullptr);
86             }
87             break;
88         case CATCHER_UI:
89             {
90                 std::string cmd = "-p 0";
91                 ret = execl("/system/bin/hidumper", "hidumper", "-s", "4606", "-a", cmd.c_str(), nullptr);
92             }
93             break;
94         default:
95             ret = DoOtherChildProcesscatcher(writeFd);
96             break;
97     }
98     return ret;
99 }
100 
CaDoInChildProcesscatcher(int writeFd)101 int ShellCatcher::CaDoInChildProcesscatcher(int writeFd)
102 {
103     int ret = -1;
104     switch (catcherType_) {
105         case CATCHER_HILOG:
106             ret = execl("/system/bin/hilog", "hilog", "-x", nullptr);
107             break;
108         case CATCHER_LIGHT_HILOG:
109             ret = execl("/system/bin/hilog", "hilog", "-z", "1000", "-P", std::to_string(pid_).c_str(),
110                 nullptr);
111             break;
112         case CATCHER_DAM:
113             ret = execl("/system/bin/hidumper", "hidumper", "-s", "1910", "-a", "DumpAppMap", nullptr);
114             break;
115         case CATCHER_SCBWMS:
116         case CATCHER_SCBWMSEVT:
117             {
118                 if (event_ == nullptr || focusWindowId_.empty()) {
119                     HIVIEW_LOGI("check param error %{public}d", focusWindowId_.empty());
120                     break;
121                 }
122                 std::string cmdSuffix = (catcherType_ == CATCHER_SCBWMS) ? " -simplify" : " -event";
123                 std::string cmd = "-w " + focusWindowId_ + cmdSuffix;
124                 ret = execl("/system/bin/hidumper", "hidumper", "-s", "WindowManagerService", "-a",
125                     cmd.c_str(), nullptr);
126             }
127             break;
128         case CATCHER_SNAPSHOT:
129             {
130                 std::string path = "/data/log/eventlog/snapshot_display_";
131                 path += TimeUtil::TimestampFormatToDate(TimeUtil::GetMilliseconds() / TimeUtil::SEC_TO_MILLISEC,
132                     "%Y%m%d%H%M%S");
133                 path += ".jpeg";
134                 ret = execl("/system/bin/snapshot_display", "snapshot_display", "-f", path.c_str(), nullptr);
135             }
136             break;
137         case CATCHER_SCBSESSION:
138         case CATCHER_SCBVIEWPARAM:
139             {
140                 std::string cmd = (catcherType_ == CATCHER_SCBSESSION) ? "-b SCBScenePanel getContainerSession" :
141                     "-b SCBScenePanel getViewParam";
142                 ret = execl("/system/bin/hidumper", "hidumper", "-s", "4606", "-a", cmd.c_str(), nullptr);
143             }
144             break;
145         default:
146             ret = DoChildProcesscatcher(writeFd);
147             break;
148     }
149     return ret;
150 }
151 
DoChildProcess(int writeFd)152 void ShellCatcher::DoChildProcess(int writeFd)
153 {
154     if (focusWindowId_.empty() && (catcherType_ == CATCHER_SCBWMS || catcherType_ == CATCHER_SCBWMSEVT)) {
155         GetFocusWindowId();
156     }
157     if (writeFd < 0 || dup2(writeFd, STDOUT_FILENO) == -1 ||
158         dup2(writeFd, STDIN_FILENO) == -1 || dup2(writeFd, STDERR_FILENO) == -1) {
159         HIVIEW_LOGE("dup2 writeFd fail");
160         _exit(-1);
161     }
162 
163     int ret = -1;
164     switch (catcherType_) {
165         case CATCHER_AMS:
166             ret = execl("/system/bin/hidumper", "hidumper", "-s", "AbilityManagerService", "-a", "-a", nullptr);
167             break;
168         case CATCHER_WMS:
169             ret = execl("/system/bin/hidumper", "hidumper", "-s", "WindowManagerService", "-a", "-a", nullptr);
170             break;
171         case CATCHER_CPU:
172             GetCpuCoreFreqInfo(writeFd);
173             ret = execl("/system/bin/hidumper", "hidumper", "--cpuusage", nullptr);
174             break;
175         case CATCHER_PMS:
176             ret = execl("/system/bin/hidumper", "hidumper", "-s", "PowerManagerService", "-a", "-s", nullptr);
177             break;
178         case CATCHER_DPMS:
179             ret = execl("/system/bin/hidumper", "hidumper", "-s", "DisplayPowerManagerService", nullptr);
180             break;
181         case CATCHER_RS:
182             ret = execl("/system/bin/hidumper", "hidumper", "-s", "RenderService", "-a", "allInfo", nullptr);
183             break;
184         case CATCHER_MMI:
185             ret = execl("/system/bin/hidumper", "hidumper", "-s", "MultimodalInput", "-a", "-w", nullptr);
186             break;
187         case CATCHER_DMS:
188             ret = execl("/system/bin/hidumper", "hidumper", "-s", "DisplayManagerService", "-a", "-a", nullptr);
189             break;
190         default:
191             ret = CaDoInChildProcesscatcher(writeFd);
192             break;
193     }
194     if (ret < 0) {
195         HIVIEW_LOGE("execl %{public}d, errno: %{public}d", ret, errno);
196         _exit(-1);
197     }
198 }
199 
GetFocusWindowId()200 std::string ShellCatcher::GetFocusWindowId()
201 {
202     if (focusWindowId_.empty()) {
203         ParseFocusWindowId();
204     }
205     return focusWindowId_;
206 }
207 
ParseFocusWindowId()208 void ShellCatcher::ParseFocusWindowId()
209 {
210     FILE *file = popen("/system/bin/hidumper -s WindowManagerService -a -a", "r");
211     if (file == nullptr) {
212         HIVIEW_LOGE("parse focus window id error");
213         return;
214     }
215     std::smatch result;
216     std::string line = "";
217     auto windowIdRegex = std::regex("Focus window: ([0-9]+)");
218     char *buffer = nullptr;
219     size_t length = 0;
220     while (getline(&buffer, &length, file) != -1) {
221         line = buffer;
222         if (regex_search(line, result, windowIdRegex)) {
223             focusWindowId_ = result[1];
224             break;
225         }
226     }
227     if (buffer != nullptr) {
228         free(buffer);
229         buffer = nullptr;
230     }
231     pclose(file);
232     file = nullptr;
233 }
234 
ReadShellToFile(int writeFd,const std::string & cmd)235 bool ShellCatcher::ReadShellToFile(int writeFd, const std::string& cmd)
236 {
237     int childPid = fork();
238     if (childPid < 0) {
239         HIVIEW_LOGE("fork fail");
240         return false;
241     } else if (childPid == 0) {
242         DoChildProcess(writeFd);
243     } else {
244         if (waitpid(childPid, nullptr, 0) != childPid) {
245             HIVIEW_LOGE("waitpid fail, pid: %{public}d, errno: %{public}d", childPid, errno);
246             return false;
247         }
248         HIVIEW_LOGI("waitpid %{public}d success", childPid);
249     }
250     return true;
251 }
252 
Catch(int fd,int jsonFd)253 int ShellCatcher::Catch(int fd, int jsonFd)
254 {
255     auto originSize = GetFdSize(fd);
256     if (catcherCmd_.empty()) {
257         HIVIEW_LOGE("catcherCmd empty");
258         return -1;
259     }
260 
261     ReadShellToFile(fd, catcherCmd_);
262     logSize_ = GetFdSize(fd) - originSize;
263     return logSize_;
264 }
265 
GetCpuCoreFreqInfo(int fd) const266 void ShellCatcher::GetCpuCoreFreqInfo(int fd) const
267 {
268     std::shared_ptr<UCollectUtil::CpuCollector> collector =
269         UCollectUtil::CpuCollector::Create();
270     CollectResult<SysCpuUsage> resultInfo = collector->CollectSysCpuUsage(true);
271     if (resultInfo.retCode != UCollect::UcError::SUCCESS) {
272         FileUtil::SaveStringToFd(fd, "\n Get each cpu info failed.\n");
273         return;
274     }
275 
276     const SysCpuUsage& sysCpuUsage = resultInfo.data;
277     std::string temp = "";
278     for (auto i = 0; i < sysCpuUsage.cpuInfos.size(); i++) {
279         temp = "\n" + sysCpuUsage.cpuInfos[i].cpuId +
280             ", userUsage=" + std::to_string(sysCpuUsage.cpuInfos[i].userUsage) + "\n";
281         FileUtil::SaveStringToFd(fd, temp);
282         temp = "";
283     }
284     CollectResult<std::vector<CpuFreq>> resultCpuFreq = collector->CollectCpuFrequency();
285     if (resultCpuFreq.retCode != UCollect::UcError::SUCCESS) {
286         FileUtil::SaveStringToFd(fd, "\n Get each cpu freq failed.\n");
287         return;
288     }
289 
290     const std::vector<CpuFreq>& cpuFreqs = resultCpuFreq.data;
291     for (auto i = 0; i < cpuFreqs.size(); i++) {
292         temp = "\ncpu" + std::to_string(cpuFreqs[i].cpuId) + ", cpuFreq=" + std::to_string(cpuFreqs[i].curFreq) +
293             ", minFreq=" + std::to_string(cpuFreqs[i].minFreq) + ", maxFreq=" + std::to_string(cpuFreqs[i].maxFreq) +
294             "\n";
295         FileUtil::SaveStringToFd(fd, temp);
296         temp = "";
297     }
298 }
299 } // namespace HiviewDFX
300 } // namespace OHOS
301