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
35namespace OHOS {
36namespace HiviewDFX {
37namespace {
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}
51DEFINE_LOG_LABEL(0xD002D01, "EventLogger-EventLogTask");
52EventLogTask::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
101void 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
115void EventLogTask::SetFocusWindowId(const std::string& focusWindowId)
116{
117    focusWindowId_ = focusWindowId;
118}
119
120EventLogTask::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
164bool 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
191void 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
212void 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
228void EventLogTask::RecordCatchedPids(const std::string& packageName)
229{
230    int pid = CommonUtils::GetPidByName(packageName);
231    if (pid > 0) {
232        catchedPids_.insert(pid);
233    }
234}
235
236EventLogTask::Status EventLogTask::GetTaskStatus() const
237{
238    return status_;
239}
240
241long EventLogTask::GetLogSize() const
242{
243    return taskLogSize_;
244}
245
246void 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
253void 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
263void EventLogTask::BinderLogCapture()
264{
265    auto capture = std::make_shared<BinderCatcher>();
266    capture->Initialize("", 0, 0);
267    tasks_.push_back(capture);
268}
269
270void 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
279void EventLogTask::MemoryUsageCapture()
280{
281    auto capture = std::make_shared<MemoryCatcher>();
282    capture->Initialize("", 0, 0);
283    tasks_.push_back(capture);
284}
285
286bool 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
307void 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
314void 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
321void 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
328void 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
335void 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
342void 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
349void 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
356void 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
363void 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
371void 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
379void 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
386void 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
393void 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
400void 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
407void 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
415void 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
423void 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
445void 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
453void 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
461void 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
475void 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
489void 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
496void 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