1 /*
2 * Copyright (c) 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
16 #include "watchdog_task.h"
17
18 #include <fstream>
19 #include <unistd.h>
20
21 #include "backtrace_local.h"
22 #include "hisysevent.h"
23 #include "mmi_log.h"
24 #include "parameter.h"
25
26 namespace OHOS {
27 namespace MMI {
28 namespace {
29 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, MMI_LOG_DOMAIN, "WatchdogTask" };
30 const std::string THREAD_NAME = "mmi_service";
31 } // namespace
32
WatchdogTask()33 WatchdogTask::WatchdogTask() {}
34
~WatchdogTask()35 WatchdogTask::~WatchdogTask() {}
36
GetFirstLine(const std::string & path)37 std::string WatchdogTask::GetFirstLine(const std::string& path)
38 {
39 char checkPath[PATH_MAX] = { 0 };
40 if (realpath(path.c_str(), checkPath) == nullptr) {
41 MMI_HILOGE("canonicalize failed. path is %{public}s", path.c_str());
42 return "";
43 }
44 std::ifstream inFile(checkPath);
45 if (!inFile.is_open()) {
46 MMI_HILOGE("inFile.is_open() false");
47 return "";
48 }
49 std::string firstLine;
50 getline(inFile, firstLine);
51 inFile.close();
52 return firstLine;
53 }
54
GetProcessNameFromProcCmdline(int32_t pid)55 std::string WatchdogTask::GetProcessNameFromProcCmdline(int32_t pid)
56 {
57 std::string procCmdlinePath = "/proc/" + std::to_string(pid) + "/cmdline";
58 std::string procCmdlineContent = GetFirstLine(procCmdlinePath);
59 if (procCmdlineContent.empty()) {
60 return "";
61 }
62 size_t procNameStartPos = 0;
63 size_t procNameEndPos = procCmdlineContent.size();
64 for (size_t i = 0; i < procCmdlineContent.size(); i++) {
65 if (procCmdlineContent[i] == '/') {
66 procNameStartPos = i + 1;
67 } else if (procCmdlineContent[i] == '\0') {
68 procNameEndPos = i;
69 break;
70 }
71 }
72 return procCmdlineContent.substr(procNameStartPos, procNameEndPos - procNameStartPos);
73 }
74
IsNumberic(const std::string & str)75 bool WatchdogTask::IsNumberic(const std::string &str)
76 {
77 return !str.empty() && std::all_of(str.begin(), str.end(), ::isdigit);
78 }
79
IsProcessDebug(int32_t pid)80 bool WatchdogTask::IsProcessDebug(int32_t pid)
81 {
82 const int32_t buffSize = 128;
83 char param[buffSize] = { 0 };
84 std::string filter = "hiviewdfx.freeze.filter." + GetProcessNameFromProcCmdline(pid);
85 GetParameter(filter.c_str(), "", param, buffSize - 1);
86 if (!IsNumberic(param)) {
87 MMI_HILOGE("Parameter:%{public}s is error", param);
88 return false;
89 }
90 int32_t debugPid = atoi(param);
91 if (debugPid == pid) {
92 return true;
93 }
94 return false;
95 }
96
GetBlockDescription(uint64_t interval)97 std::string WatchdogTask::GetBlockDescription(uint64_t interval)
98 {
99 std::string desc = "Watchdog: thread(";
100 desc += THREAD_NAME;
101 desc += ") blocked " + std::to_string(interval) + "s";
102 return desc;
103 }
104
GetSelfProcName()105 std::string WatchdogTask::GetSelfProcName()
106 {
107 constexpr uint16_t READ_SIZE = 128;
108 std::ifstream fin;
109 fin.open("/proc/self/comm", std::ifstream::in);
110 if (!fin.is_open()) {
111 MMI_HILOGE("fin.is_open() false");
112 return "";
113 }
114 char readStr[READ_SIZE] = {'\0'};
115 fin.getline(readStr, READ_SIZE - 1);
116 fin.close();
117
118 std::string ret = std::string(readStr);
119 ret.erase(std::remove_if(ret.begin(), ret.end(), [](unsigned char c) {
120 if (c >= '0' && c <= '9') {
121 return false;
122 }
123 if (c >= 'a' && c <= 'z') {
124 return false;
125 }
126 if (c >= 'A' && c <= 'Z') {
127 return false;
128 }
129 if (c == '.' || c == '-' || c == '_') {
130 return false;
131 }
132 return true;}), ret.end());
133 return ret;
134 }
135
SendEvent(const std::string & msg,const std::string & eventName)136 void WatchdogTask::SendEvent(const std::string &msg, const std::string &eventName)
137 {
138 int32_t pid = getpid();
139 if (IsProcessDebug(pid)) {
140 MMI_HILOGI("heap dump for %{public}d, don't report", pid);
141 return;
142 }
143 uint32_t gid = getgid();
144 uint32_t uid = getuid();
145 time_t curTime = time(nullptr);
146 std::string sendMsg = std::string((ctime(&curTime) == nullptr) ? "" : ctime(&curTime)) +
147 "\n" + msg + "\n";
148 HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::FRAMEWORK, eventName,
149 OHOS::HiviewDFX::HiSysEvent::EventType::FAULT,
150 "PID", pid,
151 "TGID", gid,
152 "UID", uid,
153 "MODULE_NAME", THREAD_NAME,
154 "PROCESS_NAME", GetSelfProcName(),
155 "MSG", sendMsg,
156 "STACK", OHOS::HiviewDFX::GetProcessStacktrace());
157 MMI_HILOGI("send event [FRAMEWORK,%{public}s], msg=%{public}s", eventName.c_str(), msg.c_str());
158 }
159 } // namespace MMI
160 } // namespace OHOS
161