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