1 /*
2  * Copyright (C) 2021-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 "event_log_task.h"
16 
17 #include <unistd.h>
18 #include <regex>
19 
20 #include "binder_catcher.h"
21 #include "common_utils.h"
22 #include "dmesg_catcher.h"
23 #include "ffrt_catcher.h"
24 #include "hiview_logger.h"
25 #include "memory_catcher.h"
26 #include "open_stacktrace_catcher.h"
27 #include "parameter_ex.h"
28 #include "peer_binder_catcher.h"
29 #include "securec.h"
30 #include "shell_catcher.h"
31 #include "string_util.h"
32 #include "trace_collector.h"
33 #include "time_util.h"
34 
35 namespace OHOS {
36 namespace HiviewDFX {
37 namespace {
38     static constexpr int BP_CMD_PERF_TYPE_INDEX = 2;
39     static constexpr int BP_CMD_LAYER_INDEX = 1;
40     static constexpr size_t BP_CMD_SZ = 3;
41     const char* SYSTEM_STACK[] = {
42         "foundation",
43         "render_service",
44     };
45     static constexpr int TRACE_OUT_OF_TIME = 30; // 30s
46     static constexpr int DELAY_OUT_OF_TIME = 15; // 15s
47     static constexpr int DEFAULT_LOG_SIZE = 1024 * 1024; // 1M
48     static constexpr uint64_t MILLISEC_TO_SEC = 1000;
49     static constexpr uint64_t DELAY_TIME = 2;
50 }
51 DEFINE_LOG_LABEL(0xD002D01, "EventLogger-EventLogTask");
EventLogTask(int fd, int jsonFd, std::shared_ptr<SysEvent> event)52 EventLogTask::EventLogTask(int fd, int jsonFd, std::shared_ptr<SysEvent> event)
53     : targetFd_(fd),
54       targetJsonFd_(jsonFd),
55       event_(event),
56       maxLogSize_(DEFAULT_LOG_SIZE),
57       taskLogSize_(0),
58       status_(Status::TASK_RUNNABLE)
59 {
60     int pid = event_->GetEventIntValue("PID");
61     pid_ = pid ? pid : event_->GetPid();
62     captureList_.insert(std::pair<std::string, capture>("s", [this] { this->AppStackCapture(); }));
63     captureList_.insert(std::pair<std::string, capture>("S", [this] { this->SystemStackCapture(); }));
64     captureList_.insert(std::pair<std::string, capture>("b", [this] { this->BinderLogCapture(); }));
65     captureList_.insert(std::pair<std::string, capture>("ffrt", [this] { this->FfrtCapture(); }));
66     captureList_.insert(std::pair<std::string, capture>("cmd:m", [this] { this->MemoryUsageCapture(); }));
67     captureList_.insert(std::pair<std::string, capture>("cmd:c", [this] { this->CpuUsageCapture(); }));
68     captureList_.insert(std::pair<std::string, capture>("cmd:w", [this] { this->WMSUsageCapture(); }));
69     captureList_.insert(std::pair<std::string, capture>("cmd:a", [this] { this->AMSUsageCapture(); }));
70     captureList_.insert(std::pair<std::string, capture>("cmd:p", [this] { this->PMSUsageCapture(); }));
71     captureList_.insert(std::pair<std::string, capture>("cmd:d", [this] { this->DPMSUsageCapture(); }));
72     captureList_.insert(std::pair<std::string, capture>("cmd:rs", [this] { this->RSUsageCapture(); }));
73     captureList_.insert(std::pair<std::string, capture>("cmd:mmi", [this] { this->MMIUsageCapture(); }));
74     captureList_.insert(std::pair<std::string, capture>("cmd:dms", [this] { this->DMSUsageCapture(); }));
75     captureList_.insert(std::pair<std::string, capture>("cmd:eec", [this] { this->EECStateCapture(); }));
76     captureList_.insert(std::pair<std::string, capture>("cmd:gec", [this] { this->GECStateCapture(); }));
77     captureList_.insert(std::pair<std::string, capture>("cmd:ui", [this] { this->UIStateCapture(); }));
78     captureList_.insert(std::pair<std::string, capture>("cmd:ss", [this] { this->Screenshot(); }));
79     captureList_.insert(std::pair<std::string, capture>("T", [this] { this->HilogCapture(); }));
80     captureList_.insert(std::pair<std::string, capture>("t", [this] { this->LightHilogCapture(); }));
81     captureList_.insert(std::pair<std::string, capture>("e", [this] { this->DmesgCapture(); }));
82     captureList_.insert(std::pair<std::string, capture>("k:SysRq",
83         [this] { this->SysrqCapture(false); }));
84     captureList_.insert(std::pair<std::string, capture>("k:SysRqFile",
85         [this] { this->SysrqCapture(true); }));
86     captureList_.insert(std::pair<std::string, capture>("tr", [this] { this->HitraceCapture(); }));
87     captureList_.insert(std::pair<std::string, capture>("cmd:scbCS",
88         [this] { this->SCBSessionCapture(); }));
89     captureList_.insert(std::pair<std::string, capture>("cmd:scbVP",
90         [this] { this->SCBViewParamCapture(); }));
91     captureList_.insert(std::pair<std::string, capture>("cmd:scbWMS",
92         [this] { this->SCBWMSCapture(); }));
93     captureList_.insert(std::pair<std::string, capture>("cmd:scbWMSEVT",
94         [this] { this->SCBWMSEVTCapture(); }));
95     captureList_.insert(std::pair<std::string, capture>("cmd:dam",
96         [this] { this->DumpAppMapCapture(); }));
97     captureList_.insert(std::pair<std::string, capture>("t:input",
98         [this] { this->InputHilogCapture(); }));
99 }
100 
AddLog(const std::string &cmd)101 void EventLogTask::AddLog(const std::string &cmd)
102 {
103     if (tasks_.size() == 0) {
104         status_ = Status::TASK_RUNNABLE;
105     }
106 
107     if (captureList_.find(cmd) != captureList_.end()) {
108         captureList_[cmd]();
109         return;
110     }
111     PeerBinderCapture(cmd);
112     catchedPids_.clear();
113 }
114 
SetFocusWindowId(const std::string& focusWindowId)115 void EventLogTask::SetFocusWindowId(const std::string& focusWindowId)
116 {
117     focusWindowId_ = focusWindowId;
118 }
119 
StartCompose()120 EventLogTask::Status EventLogTask::StartCompose()
121 {
122     // nothing to do, return success
123     if (status_ != Status::TASK_RUNNABLE) {
124         return status_;
125     }
126     status_ = Status::TASK_RUNNING;
127     // nothing to do, return success
128     if (tasks_.size() == 0) {
129         return Status::TASK_SUCCESS;
130     }
131 
132     auto dupedFd = dup(targetFd_);
133     int dupedJsonFd = -1;
134     if (targetJsonFd_ >= 0) {
135         dupedJsonFd = dup(targetJsonFd_);
136     }
137     uint32_t catcherIndex = 0;
138     for (auto& catcher : tasks_) {
139         catcherIndex++;
140         if (dupedFd < 0) {
141             status_ = Status::TASK_FAIL;
142             AddStopReason(targetFd_, catcher, "Fail to dup file descriptor, exit!");
143             return TASK_FAIL;
144         }
145 
146         AddSeparator(dupedFd, catcher);
147         int curLogSize = catcher->Catch(dupedFd, dupedJsonFd);
148         HIVIEW_LOGI("finish catcher: %{public}s, curLogSize: %{public}d", catcher->GetDescription().c_str(),
149             curLogSize);
150         if (ShouldStopLogTask(dupedFd, catcherIndex, curLogSize, catcher)) {
151             break;
152         }
153     }
154     close(dupedFd);
155     if (dupedJsonFd >= 0) {
156         close(dupedJsonFd);
157     }
158     if (status_ == Status::TASK_RUNNING) {
159         status_ = Status::TASK_SUCCESS;
160     }
161     return status_;
162 }
163 
ShouldStopLogTask(int fd, uint32_t curTaskIndex, int curLogSize, std::shared_ptr<EventLogCatcher> catcher)164 bool EventLogTask::ShouldStopLogTask(int fd, uint32_t curTaskIndex, int curLogSize,
165     std::shared_ptr<EventLogCatcher> catcher)
166 {
167     if (status_ == Status::TASK_TIMEOUT) {
168         HIVIEW_LOGE("Break Log task, parent has timeout.");
169         return true;
170     }
171 
172     bool encounterErr = (curLogSize < 0);
173     bool hasFinished = (curTaskIndex == tasks_.size());
174     if (!encounterErr) {
175         taskLogSize_ += static_cast<uint32_t>(curLogSize);
176     }
177 
178     if (taskLogSize_ > maxLogSize_ && !hasFinished) {
179         AddStopReason(fd, catcher, "Exceed max log size");
180         status_ = Status::TASK_EXCEED_SIZE;
181         return true;
182     }
183 
184     if (encounterErr) {
185         AddStopReason(fd, catcher, "Log catcher not successful");
186         HIVIEW_LOGE("catcher %{public}s, Log catcher not successful", catcher->GetDescription().c_str());
187     }
188     return false;
189 }
190 
AddStopReason(int fd, std::shared_ptr<EventLogCatcher> catcher, const std::string& reason)191 void EventLogTask::AddStopReason(int fd, std::shared_ptr<EventLogCatcher> catcher, const std::string& reason)
192 {
193     char buf[BUF_SIZE_512] = {0};
194     int ret = -1;
195     if (catcher != nullptr) {
196         catcher->Stop();
197         // sleep 1s for syncing log to the fd, then we could append failure reason ?
198         sleep(1);
199         std::string summary = catcher->GetDescription();
200         ret = snprintf_s(buf, BUF_SIZE_512, BUF_SIZE_512 - 1, "\nTask stopped when running catcher:%s, Reason:%s \n",
201                          summary.c_str(), reason.c_str());
202     } else {
203         ret = snprintf_s(buf, BUF_SIZE_512, BUF_SIZE_512 - 1, "\nTask stopped, Reason:%s \n", reason.c_str());
204     }
205 
206     if (ret > 0) {
207         write(fd, buf, strnlen(buf, BUF_SIZE_512));
208         fsync(fd);
209     }
210 }
211 
AddSeparator(int fd, std::shared_ptr<EventLogCatcher> catcher) const212 void EventLogTask::AddSeparator(int fd, std::shared_ptr<EventLogCatcher> catcher) const
213 {
214     char buf[BUF_SIZE_512] = {0};
215     std::string summary = catcher->GetDescription();
216     if (summary.empty()) {
217         HIVIEW_LOGE("summary.empty() catcher is %{public}s", catcher->GetName().c_str());
218         return;
219     }
220 
221     int ret = snprintf_s(buf, BUF_SIZE_512, BUF_SIZE_512 - 1, "\n%s\n", summary.c_str());
222     if (ret > 0) {
223         write(fd, buf, strnlen(buf, BUF_SIZE_512));
224         fsync(fd);
225     }
226 }
227 
RecordCatchedPids(const std::string& packageName)228 void EventLogTask::RecordCatchedPids(const std::string& packageName)
229 {
230     int pid = CommonUtils::GetPidByName(packageName);
231     if (pid > 0) {
232         catchedPids_.insert(pid);
233     }
234 }
235 
GetTaskStatus() const236 EventLogTask::Status EventLogTask::GetTaskStatus() const
237 {
238     return status_;
239 }
240 
GetLogSize() const241 long EventLogTask::GetLogSize() const
242 {
243     return taskLogSize_;
244 }
245 
AppStackCapture()246 void EventLogTask::AppStackCapture()
247 {
248     auto capture = std::make_shared<OpenStacktraceCatcher>();
249     capture->Initialize(event_->GetEventValue("PACKAGE_NAME"), pid_, 0);
250     tasks_.push_back(capture);
251 }
252 
SystemStackCapture()253 void EventLogTask::SystemStackCapture()
254 {
255     for (auto packageName : SYSTEM_STACK) {
256         auto capture = std::make_shared<OpenStacktraceCatcher>();
257         capture->Initialize(packageName, 0, 0);
258         RecordCatchedPids(packageName);
259         tasks_.push_back(capture);
260     }
261 }
262 
BinderLogCapture()263 void EventLogTask::BinderLogCapture()
264 {
265     auto capture = std::make_shared<BinderCatcher>();
266     capture->Initialize("", 0, 0);
267     tasks_.push_back(capture);
268 }
269 
FfrtCapture()270 void EventLogTask::FfrtCapture()
271 {
272     if (pid_ > 0) {
273         auto capture = std::make_shared<FfrtCatcher>();
274         capture->Initialize("", pid_, 0);
275         tasks_.push_back(capture);
276     }
277 }
278 
MemoryUsageCapture()279 void EventLogTask::MemoryUsageCapture()
280 {
281     auto capture = std::make_shared<MemoryCatcher>();
282     capture->Initialize("", 0, 0);
283     tasks_.push_back(capture);
284 }
285 
PeerBinderCapture(const std::string &cmd)286 bool EventLogTask::PeerBinderCapture(const std::string &cmd)
287 {
288     auto find = cmd.find("pb");
289     if (find == cmd.npos) {
290         return false;
291     }
292 
293     std::vector<std::string> cmdList;
294     StringUtil::SplitStr(cmd, ":", cmdList, true);
295     if (cmdList.size() != BP_CMD_SZ || cmdList.front() != "pb") {
296         return false;
297     }
298 
299     auto capture = std::make_shared<PeerBinderCatcher>();
300     capture->Initialize(cmdList[BP_CMD_PERF_TYPE_INDEX],
301         StringUtil::StrToInt(cmdList[BP_CMD_LAYER_INDEX]), pid_);
302     capture->Init(event_, "", catchedPids_);
303     tasks_.push_back(capture);
304     return true;
305 }
306 
CpuUsageCapture()307 void EventLogTask::CpuUsageCapture()
308 {
309     auto capture = std::make_shared<ShellCatcher>();
310     capture->Initialize("hidumper --cpuusage", ShellCatcher::CATCHER_CPU, pid_);
311     tasks_.push_back(capture);
312 }
313 
WMSUsageCapture()314 void EventLogTask::WMSUsageCapture()
315 {
316     auto capture = std::make_shared<ShellCatcher>();
317     capture->Initialize("hidumper -s WindowManagerService -a -a", ShellCatcher::CATCHER_WMS, pid_);
318     tasks_.push_back(capture);
319 }
320 
AMSUsageCapture()321 void EventLogTask::AMSUsageCapture()
322 {
323     auto capture = std::make_shared<ShellCatcher>();
324     capture->Initialize("hidumper -s AbilityManagerService -a -a", ShellCatcher::CATCHER_AMS, pid_);
325     tasks_.push_back(capture);
326 }
327 
PMSUsageCapture()328 void EventLogTask::PMSUsageCapture()
329 {
330     auto capture = std::make_shared<ShellCatcher>();
331     capture->Initialize("hidumper -s PowerManagerService -a -s", ShellCatcher::CATCHER_PMS, pid_);
332     tasks_.push_back(capture);
333 }
334 
DPMSUsageCapture()335 void EventLogTask::DPMSUsageCapture()
336 {
337     auto capture = std::make_shared<ShellCatcher>();
338     capture->Initialize("hidumper -s DisplayPowerManagerService", ShellCatcher::CATCHER_DPMS, pid_);
339     tasks_.push_back(capture);
340 }
341 
RSUsageCapture()342 void EventLogTask::RSUsageCapture()
343 {
344     auto capture = std::make_shared<ShellCatcher>();
345     capture->Initialize("hidumper -s RenderService -a allInfo", ShellCatcher::CATCHER_RS, pid_);
346     tasks_.push_back(capture);
347 }
348 
MMIUsageCapture()349 void EventLogTask::MMIUsageCapture()
350 {
351     auto capture = std::make_shared<ShellCatcher>();
352     capture->Initialize("hidumper -s MultimodalInput -a -w", ShellCatcher::CATCHER_MMI, pid_);
353     tasks_.push_back(capture);
354 }
355 
DMSUsageCapture()356 void EventLogTask::DMSUsageCapture()
357 {
358     auto capture = std::make_shared<ShellCatcher>();
359     capture->Initialize("hidumper -s DisplayManagerService -a -a", ShellCatcher::CATCHER_DMS, pid_);
360     tasks_.push_back(capture);
361 }
362 
EECStateCapture()363 void EventLogTask::EECStateCapture()
364 {
365     auto capture = std::make_shared<ShellCatcher>();
366     capture->Initialize("hidumper -s 4606 -a '-b EventExclusiveCommander getAllEventExclusiveCaller'",
367         ShellCatcher::CATCHER_EEC, pid_);
368     tasks_.push_back(capture);
369 }
370 
GECStateCapture()371 void EventLogTask::GECStateCapture()
372 {
373     auto capture = std::make_shared<ShellCatcher>();
374     capture->Initialize("hidumper -s 4606 -a '-b SCBGestureManager getAllGestureEnableCaller'",
375         ShellCatcher::CATCHER_GEC, pid_);
376     tasks_.push_back(capture);
377 }
378 
UIStateCapture()379 void EventLogTask::UIStateCapture()
380 {
381     auto capture = std::make_shared<ShellCatcher>();
382     capture->Initialize("hidumper -s 4606 -a '-p 0'", ShellCatcher::CATCHER_UI, pid_);
383     tasks_.push_back(capture);
384 }
385 
Screenshot()386 void EventLogTask::Screenshot()
387 {
388     auto capture = std::make_shared<ShellCatcher>();
389     capture->Initialize("snapshot_display -f x.jpeg", ShellCatcher::CATCHER_SNAPSHOT, pid_);
390     tasks_.push_back(capture);
391 }
392 
HilogCapture()393 void EventLogTask::HilogCapture()
394 {
395     auto capture = std::make_shared<ShellCatcher>();
396     capture->Initialize("hilog -x", ShellCatcher::CATCHER_HILOG, 0);
397     tasks_.push_back(capture);
398 }
399 
LightHilogCapture()400 void EventLogTask::LightHilogCapture()
401 {
402     auto capture = std::make_shared<ShellCatcher>();
403     capture->Initialize("hilog -z 1000 -P", ShellCatcher::CATCHER_LIGHT_HILOG, pid_);
404     tasks_.push_back(capture);
405 }
406 
DmesgCapture()407 void EventLogTask::DmesgCapture()
408 {
409     auto capture = std::make_shared<DmesgCatcher>();
410     capture->Initialize("", 0, 0);
411     capture->Init(event_);
412     tasks_.push_back(capture);
413 }
414 
SysrqCapture(bool isWriteNewFile)415 void EventLogTask::SysrqCapture(bool isWriteNewFile)
416 {
417     auto capture = std::make_shared<DmesgCatcher>();
418     capture->Initialize("", isWriteNewFile, 1);
419     capture->Init(event_);
420     tasks_.push_back(capture);
421 }
422 
HitraceCapture()423 void EventLogTask::HitraceCapture()
424 {
425     std::shared_ptr<UCollectUtil::TraceCollector> collector = UCollectUtil::TraceCollector::Create();
426     UCollect::TraceCaller caller = UCollect::TraceCaller::RELIABILITY;
427     std::regex reg("Fault time:(\\d{4}/\\d{2}/\\d{2}-\\d{2}:\\d{2}:\\d{2})");
428     std::string timeStamp = event_->GetEventValue("MSG");
429     std::smatch match;
430     timeStamp = std::regex_search(timeStamp, match, reg) ? match[1].str() : "";
431     uint64_t faultTime = timeStamp.empty() ? (event_->happenTime_) :
432         static_cast<uint64_t>(TimeUtil::StrToTimeStamp(timeStamp, "%Y/%m/%d-%H:%M:%S"));
433     faultTime += DELAY_TIME;
434     uint64_t currentTime = TimeUtil::GetMilliseconds() / MILLISEC_TO_SEC;
435     if (currentTime >= (TRACE_OUT_OF_TIME + faultTime)) {
436         faultTime = currentTime - DELAY_OUT_OF_TIME;
437     }
438     auto result = collector->DumpTraceWithDuration(caller, MAX_DUMP_TRACE_LIMIT, faultTime);
439     if (result.retCode != 0) {
440         HIVIEW_LOGE("get hitrace fail! error code : %{public}d", result.retCode);
441         return;
442     }
443 }
444 
SCBSessionCapture()445 void EventLogTask::SCBSessionCapture()
446 {
447     auto capture = std::make_shared<ShellCatcher>();
448     capture->Initialize("hidumper -s 4606 -a '-b SCBScenePanel getContainerSession'",
449         ShellCatcher::CATCHER_SCBSESSION, pid_);
450     tasks_.push_back(capture);
451 }
452 
SCBViewParamCapture()453 void EventLogTask::SCBViewParamCapture()
454 {
455     auto capture = std::make_shared<ShellCatcher>();
456     capture->Initialize("hidumper -s 4606 -a '-b SCBScenePanel getViewParam'",
457         ShellCatcher::CATCHER_SCBVIEWPARAM, pid_);
458     tasks_.push_back(capture);
459 }
460 
SCBWMSCapture()461 void EventLogTask::SCBWMSCapture()
462 {
463     auto capture = std::make_shared<ShellCatcher>();
464     capture->SetEvent(event_);
465     if (focusWindowId_.empty()) {
466         HIVIEW_LOGE("dump simplify get focus window error");
467         return;
468     }
469     std::string cmd = "hidumper -s WindowManagerService -a -w " + focusWindowId_ + " -simplify";
470     capture->Initialize(cmd, ShellCatcher::CATCHER_SCBWMS, pid_);
471     capture->SetFocusWindowId(focusWindowId_);
472     tasks_.push_back(capture);
473 }
474 
SCBWMSEVTCapture()475 void EventLogTask::SCBWMSEVTCapture()
476 {
477     auto capture = std::make_shared<ShellCatcher>();
478     capture->SetEvent(event_);
479     if (focusWindowId_.empty()) {
480         HIVIEW_LOGE("dump event get focus window error");
481         return;
482     }
483     std::string cmd = "hidumper -s WindowManagerService -a -w " + focusWindowId_ + " -event";
484     capture->Initialize(cmd, ShellCatcher::CATCHER_SCBWMSEVT, pid_);
485     capture->SetFocusWindowId(focusWindowId_);
486     tasks_.push_back(capture);
487 }
488 
DumpAppMapCapture()489 void EventLogTask::DumpAppMapCapture()
490 {
491     auto capture = std::make_shared<ShellCatcher>();
492     capture->Initialize("hidumper -s 1910 -a DumpAppMap", ShellCatcher::CATCHER_DAM, pid_);
493     tasks_.push_back(capture);
494 }
495 
InputHilogCapture()496 void EventLogTask::InputHilogCapture()
497 {
498     auto capture = std::make_shared<ShellCatcher>();
499     int32_t eventId = event_->GetEventIntValue("INPUT_ID");
500     if (eventId > 0) {
501         std::string cmd = "hilog -T InputKeyFlow -e " +
502             std::to_string(eventId) + " -x";
503         capture->Initialize(cmd, ShellCatcher::CATCHER_INPUT_EVENT_HILOG, eventId);
504     } else {
505         capture->Initialize("hilog -T InputKeyFlow -x", ShellCatcher::CATCHER_INPUT_HILOG,
506             pid_);
507     }
508     tasks_.push_back(capture);
509 }
510 } // namespace HiviewDFX
511 } // namespace OHOS
512