• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 "dmesg_catcher.h"
16 
17 #include <string>
18 #include <sys/klog.h>
19 #include <fcntl.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 
23 #ifdef KERNELSTACK_CATCHER_ENABLE
24 #include "dfx_kernel_stack.h"
25 #endif
26 
27 #include "hiview_logger.h"
28 #include "log_catcher_utils.h"
29 #include "common_utils.h"
30 #include "ffrt.h"
31 #include "file_util.h"
32 #include "time_util.h"
33 #include "securec.h"
34 
35 namespace OHOS {
36 namespace HiviewDFX {
37 #ifdef DMESG_CATCHER_ENABLE
38 using namespace std::chrono_literals;
39 DEFINE_LOG_LABEL(0xD002D01, "EventLogger-DmesgCatcher");
40 namespace {
41     constexpr int SYSLOG_ACTION_READ_ALL = 3;
42     constexpr int SYSLOG_ACTION_SIZE_BUFFER = 10;
43     constexpr mode_t DEFAULT_LOG_FILE_MODE = 0644;
44     static constexpr const char* const FULL_DIR = "/data/log/eventlog/";
45     static constexpr int DECIMEL = 10;
46     static constexpr int DIR_BUFFER = 256;
47 }
DmesgCatcher()48 DmesgCatcher::DmesgCatcher() : EventLogCatcher()
49 {
50     event_ = nullptr;
51     name_ = "DmesgCatcher";
52 }
53 
Initialize(const std::string & packageNam __UNUSED,int writeNewFile __UNUSED,int writeType)54 bool DmesgCatcher::Initialize(const std::string& packageNam  __UNUSED,
55     int writeNewFile __UNUSED, int writeType)
56 {
57     writeNewFile_ = writeNewFile;
58     writeType_ = writeType;
59     return true;
60 }
61 
Init(std::shared_ptr<SysEvent> event)62 bool DmesgCatcher::Init(std::shared_ptr<SysEvent> event)
63 {
64     event_ = event;
65     return true;
66 }
67 
DumpToFile(int fd,const std::string & dataStr)68 bool DmesgCatcher::DumpToFile(int fd, const std::string& dataStr)
69 {
70     bool res = false;
71     size_t lineStart = 0;
72     size_t lineEnd = dataStr.size();
73     if (writeType_ == SYS_RQ) {
74         size_t sysRqStart = dataStr.find("sysrq start:");
75         if (sysRqStart == std::string::npos) {
76             return false;
77         }
78         size_t sysRqEnd = dataStr.find("sysrq end:", sysRqStart);
79         if (sysRqEnd == std::string::npos) {
80             return false;
81         }
82         lineStart = dataStr.rfind('\n', sysRqStart);
83         lineStart = (lineStart == std::string::npos) ? 0 : lineStart + 1;
84         lineEnd = dataStr.find('\n', sysRqEnd);
85         lineEnd = (lineEnd == std::string::npos) ? dataStr.length() : lineEnd;
86         res =  FileUtil::SaveStringToFd(fd, dataStr.substr(lineStart, lineEnd - lineStart + 1));
87     } else if (writeType_ == HUNG_TASK) {
88         std::string hungtaskStr;
89         while (lineStart < lineEnd) {
90             size_t seekPos = dataStr.find("hguard-worker", lineStart);
91             if (seekPos == std::string::npos) {
92                 seekPos = dataStr.find("sys-lmk-debug-t", lineStart);
93             }
94             if (seekPos == std::string::npos) {
95                 break;
96             }
97             lineStart = dataStr.rfind("\n", seekPos);
98             lineStart = (lineStart == std::string::npos) ? 0 : lineStart + 1;
99             lineEnd = dataStr.find("\n", seekPos);
100             lineEnd = (lineEnd == std::string::npos) ? dataStr.size() : lineEnd;
101 
102             hungtaskStr.append(dataStr, lineStart, lineEnd - lineStart + 1);
103             lineStart = lineEnd + 1;
104         }
105         res = FileUtil::SaveStringToFd(fd, hungtaskStr);
106     }
107     return res;
108 }
109 
DumpDmesgLog(int fd)110 bool DmesgCatcher::DumpDmesgLog(int fd)
111 {
112     if (fd < 0) {
113         return false;
114     }
115     int size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, 0, 0);
116     if (size <= 0) {
117         return false;
118     }
119     char *data = (char *)malloc(size + 1);
120     if (data == nullptr) {
121         return false;
122     }
123 
124     memset_s(data, size + 1, 0, size + 1);
125     int readSize = klogctl(SYSLOG_ACTION_READ_ALL, data, size);
126     if (readSize < 0) {
127         free(data);
128         return false;
129     }
130     std::string dataStr = std::string(data, size);
131     free(data);
132     bool res = (writeType_ == DMESG) ? FileUtil::SaveStringToFd(fd, dataStr) : DumpToFile(fd, dataStr);
133     return res;
134 }
135 
WriteSysrqTrigger()136 bool DmesgCatcher::WriteSysrqTrigger()
137 {
138     static std::atomic<bool> isWriting(false);
139     bool expected = false;
140     if (!isWriting.compare_exchange_strong(expected, true)) {
141         HIVIEW_LOGE("other is writing sysrq trigger!");
142         ffrt::this_task::sleep_for(1s);
143         return true;
144     }
145 
146     FILE* file = fopen("/proc/sysrq-trigger", "w");
147     if (file == nullptr) {
148         isWriting.store(false);
149         HIVIEW_LOGE("Can't read sysrq,errno: %{public}d", errno);
150         return false;
151     }
152 
153     fwrite("w", 1, 1, file);
154     fflush(file);
155 
156     fwrite("l", 1, 1, file);
157     ffrt::this_task::sleep_for(1s);
158     fclose(file);
159     isWriting.store(false);
160     return true;
161 }
162 
Catch(int fd,int jsonFd)163 int DmesgCatcher::Catch(int fd, int jsonFd)
164 {
165     if (writeType_ && !WriteSysrqTrigger()) {
166         return 0;
167     }
168     description_ = (writeType_ == SYS_RQ) ? "\nSysrqCatcher -- \n" :
169         (writeType_ == HUNG_TASK) ? "\nHungTaskCatcher -- \n" : "\nDmesgCatcher -- \n";;
170     auto originSize = GetFdSize(fd);
171     FileUtil::SaveStringToFd(fd, description_);
172     DumpDmesgLog(fd);
173     logSize_ = GetFdSize(fd) - originSize;
174     return logSize_;
175 }
176 #ifdef KERNELSTACK_CATCHER_ENABLE
GetTidsByPid(int pid,std::vector<pid_t> & tids)177 void DmesgCatcher::GetTidsByPid(int pid, std::vector<pid_t>& tids)
178 {
179     char taskDir[DIR_BUFFER];
180     if (pid < 0 || sprintf_s(taskDir, sizeof(taskDir), "/proc/%d/task", pid) < 0) {
181         HIVIEW_LOGW("get tids failed, pid: %{public}d", pid);
182         return;
183     }
184 
185     DIR* dir = opendir(taskDir);
186     if (dir != nullptr) {
187         struct dirent* dent;
188         while ((dent = readdir(dir)) != nullptr) {
189             char* endptr;
190             unsigned long tid = strtoul(dent->d_name, &endptr, DECIMEL);
191             if (tid == ULONG_MAX || *endptr) {
192                 continue;
193             }
194             tids.push_back(tid);
195         }
196         closedir(dir);
197     }
198 }
199 
DumpKernelStacktrace(int fd,int pid)200 int DmesgCatcher::DumpKernelStacktrace(int fd, int pid)
201 {
202     if (fd < 0 || pid < 0) {
203         return -1;
204     }
205     std::string msg = "";
206     std::vector<pid_t> tids;
207     GetTidsByPid(pid, tids);
208     for (auto tid : tids) {
209         std::string temp = "";
210         if (DfxGetKernelStack(tid, temp) != 0) {
211             msg = "Failed to format kernel stack for " + std::to_string(tid) + temp + "\n";
212             continue;
213         }
214         msg += temp + "\n";
215     }
216     if (msg == "") {
217         msg = "dumpCatch return empty stack!!!!";
218     }
219     FileUtil::SaveStringToFd(fd, msg);
220     return 0;
221 }
222 #endif
223 
WriteNewFile(int pid)224 void DmesgCatcher::WriteNewFile(int pid)
225 {
226     if (writeType_ && !WriteSysrqTrigger()) {
227         return;
228     }
229     std::string fileType = (writeType_ == SYS_RQ) ? "sysrq" : "hungtask";
230     std::string fileTime = (writeType_ == SYS_RQ) ?  event_->GetEventValue("SYSRQ_TIME") :
231         event_->GetEventValue("HUNGTASK_TIME");
232     std::string fileName = fileType + "-" + fileTime + ".log";
233     std::string fullPath = std::string(FULL_DIR) + fileName;
234     HIVIEW_LOGI("write file %{public}s start", fileName.c_str());
235     if (FileUtil::FileExists(fullPath)) {
236         HIVIEW_LOGW("filename: %{public}s is existed, direct use.", fileName.c_str());
237         return;
238     }
239     FILE* fp = fopen(fullPath.c_str(), "w");
240     chmod(fullPath.c_str(), DEFAULT_LOG_FILE_MODE);
241     if (fp == nullptr) {
242         HIVIEW_LOGI("Fail to create %{public}s, errno: %{public}d.", fileName.c_str(), errno);
243         return;
244     }
245     auto fd = fileno(fp);
246     DumpDmesgLog(fd);
247 #ifdef KERNELSTACK_CATCHER_ENABLE
248     if (writeType_ == SYS_RQ) {
249         DumpKernelStacktrace(fd, pid);
250     }
251 #endif // KERNELSTACK_CATCHER_ENABLE
252     if (fclose(fp)) {
253         HIVIEW_LOGE("fclose is failed");
254     }
255     fp = nullptr;
256     HIVIEW_LOGI("write file %{public}s end", fileName.c_str());
257 }
258 #endif // DMESG_CATCHER_ENABLE
259 } // namespace HiviewDFX
260 } // namespace OHOS
261