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