• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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