• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "log_catcher_utils.h"
16 
17 #include <cstdio>
18 #include <fcntl.h>
19 #include <map>
20 #include <memory>
21 #include <sstream>
22 #include <sys/wait.h>
23 
24 #include "common_utils.h"
25 #include "dfx_dump_catcher.h"
26 #include "dfx_json_formatter.h"
27 #include "file_util.h"
28 #include "hiview_logger.h"
29 #include "iservice_registry.h"
30 #include "string_util.h"
31 #include "time_util.h"
32 
33 #ifdef HITRACE_CATCHER_ENABLE
34 #include <shared_mutex>
35 #include "trace_collector.h"
36 #endif
37 
38 namespace OHOS {
39 namespace HiviewDFX {
40 namespace LogCatcherUtils {
41 static std::map<int, std::shared_ptr<std::pair<bool, std::string>>> dumpMap;
42 static std::mutex dumpMutex;
43 static std::condition_variable getSync;
44 constexpr int DUMP_KERNEL_STACK_SUCCESS = 1;
45 constexpr int DUMP_STACK_FAILED = -1;
46 constexpr int MAX_RETRY_COUNT = 20;
47 constexpr int WAIT_CHILD_PROCESS_INTERVAL = 5 * 1000;
48 constexpr mode_t DEFAULT_LOG_FILE_MODE = 0644;
49 
50 #ifdef HITRACE_CATCHER_ENABLE
51 constexpr uint32_t MAX_DUMP_TRACE_LIMIT = 15;
52 constexpr const char* FAULT_FREEZE_TYPE = "32";
53 static std::shared_mutex grayscaleMutex_;
54 static std::string telemetryId_;
55 static std::string traceAppFilter_;
56 #endif
57 
58 DEFINE_LOG_LABEL(0xD002D01, "EventLogger-LogCatcherUtils");
59 
GetDump(int pid,std::string & msg)60 bool GetDump(int pid, std::string& msg)
61 {
62     std::unique_lock lock(dumpMutex);
63     auto it = dumpMap.find(pid);
64     if (it == dumpMap.end()) {
65         dumpMap[pid] = std::make_shared<std::pair<bool, std::string>>(std::pair<bool, std::string>(false, ""));
66         return false;
67     }
68     std::shared_ptr<std::pair<bool, std::string>> tmp = it->second;
69     if (!tmp->first) {
70         getSync.wait_for(lock, std::chrono::seconds(10), // 10: dump stack timeout
71             [pid]() -> bool { return (dumpMap.find(pid) == dumpMap.end()); });
72         if (!tmp->first) {
73             return false;
74         }
75     }
76     msg = tmp->second;
77     return true;
78 }
79 
FinshDump(int pid,const std::string & msg)80 void FinshDump(int pid, const std::string& msg)
81 {
82     std::lock_guard lock(dumpMutex);
83     auto it = dumpMap.find(pid);
84     if (it == dumpMap.end()) {
85         return;
86     }
87     std::shared_ptr<std::pair<bool, std::string>> tmp = it->second;
88     tmp->first = true;
89     tmp->second = msg;
90     dumpMap.erase(pid);
91     getSync.notify_all();
92 }
93 
WriteKernelStackToFd(int originFd,const std::string & msg,int pid)94 int WriteKernelStackToFd(int originFd, const std::string& msg, int pid)
95 {
96     std::string logPath = "/data/log/eventlog/";
97     std::vector<std::string> files;
98     FileUtil::GetDirFiles(logPath, files, false);
99     std::string filterName = "-KernelStack-" + std::to_string(originFd) + ".log";
100     std::string targetPath;
101     for (auto& fileName : files) {
102         if (fileName.find(filterName) != std::string::npos) {
103             targetPath = fileName;
104             break;
105         }
106     }
107     FILE* fp = nullptr;
108     std::string realPath;
109     if (FileUtil::PathToRealPath(targetPath, realPath)) {
110         fp = fopen(realPath.c_str(), "a");
111     } else {
112         std::string procName = CommonUtils::GetProcFullNameByPid(pid);
113         if (procName.empty()) {
114             return -1;
115         }
116         StringUtil::FormatProcessName(procName);
117         auto logTime = TimeUtil::GetMilliseconds() / TimeUtil::SEC_TO_MILLISEC;
118         std::string formatTime = TimeUtil::TimestampFormatToDate(logTime, "%Y%m%d%H%M%S");
119         std::string logName = procName + "-" + std::to_string(pid) + "-" + formatTime + filterName;
120         realPath = logPath + logName;
121         chmod(realPath.c_str(), DEFAULT_LOG_FILE_MODE);
122         fp = fopen(realPath.c_str(), "w+");
123     }
124     if (fp != nullptr) {
125         int fd = fileno(fp);
126         FileUtil::SaveStringToFd(fd, msg);
127         (void)fclose(fp);
128         fp = nullptr;
129         return 0;
130     }
131     return -1;
132 }
133 
DumpStacktrace(int fd,int pid,std::string & terminalBinderStack,int terminalBinderPid,int terminalBinderTid)134 int DumpStacktrace(int fd, int pid, std::string& terminalBinderStack, int terminalBinderPid, int terminalBinderTid)
135 {
136     if (fd < 0) {
137         return -1;
138     }
139     std::string msg;
140     if (!GetDump(pid, msg)) {
141         DfxDumpCatcher dumplog;
142         std::string ret;
143         std::pair<int, std::string> dumpResult = dumplog.DumpCatchWithTimeout(pid, ret);
144         if (dumpResult.first == DUMP_STACK_FAILED) {
145             msg = "Failed to dump stacktrace for " + std::to_string(pid) + "\n" + dumpResult.second + ret;
146         } else if (dumpResult.first == DUMP_KERNEL_STACK_SUCCESS) {
147             std::string failInfo = "Failed to dump normal stacktrace for " + std::to_string(pid) + "\n" +
148                 dumpResult.second;
149             msg = failInfo + (DfxJsonFormatter::FormatKernelStack(ret, msg, false) ? msg :
150                 "Failed to format kernel stack for " + std::to_string(pid) + "\n");
151             WriteKernelStackToFd(fd, ret, pid);
152         } else {
153             msg = ret;
154         }
155         FinshDump(pid, "\n-repeat-\n" + msg);
156     }
157 
158     if (msg == "") {
159         msg = "dumpCatch return empty stack!!!!";
160     }
161     if (terminalBinderPid > 0 && pid == terminalBinderPid) {
162         terminalBinderTid  = (terminalBinderTid > 0) ? terminalBinderTid : terminalBinderPid;
163         GetThreadStack(msg, terminalBinderStack, terminalBinderTid);
164     }
165 
166     FileUtil::SaveStringToFd(fd, msg);
167     return 0;
168 }
169 
GetThreadStack(const std::string & processStack,std::string & stack,int tid)170 void GetThreadStack(const std::string& processStack, std::string& stack, int tid)
171 {
172     if (tid <= 0) {
173         return;
174     }
175 
176     std::istringstream issStack(processStack);
177     if (issStack.fail()) {
178         return;
179     }
180     std::string regTidString = "^Tid:" + std::to_string(tid) + ", Name:(.{0,32})$";
181     std::regex regTid(regTidString);
182     std::regex regStack(R"(^#\d{2,3} (pc|at) .{0,1024}$)");
183     std::regex regSkip(R"(^ThreadInfo:.*$)");
184     std::string line;
185     while (std::getline(issStack, line)) {
186         if (!issStack.good()) {
187             break;
188         }
189 
190         if (!std::regex_match(line, regTid)) {
191             continue;
192         }
193 
194         while (std::getline(issStack, line)) {
195             if (std::regex_match(line, regSkip)) {
196                 continue;
197             } else if (!std::regex_match(line, regStack)) {
198                 break;
199             }
200             stack.append(line + "\n");
201             if (!issStack.good()) {
202                 break;
203             }
204         };
205         break;
206     }
207 }
208 
DumpStackFfrt(int fd,const std::string & pid)209 int DumpStackFfrt(int fd, const std::string& pid)
210 {
211     sptr<ISystemAbilityManager> sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
212     if (!sam) {
213         return 0;
214     }
215 
216     std::list<SystemProcessInfo> systemProcessInfos;
217     sam->GetRunningSystemProcess(systemProcessInfos);
218     std::string serviceName = std::any_of(systemProcessInfos.begin(), systemProcessInfos.end(),
219         [pid](auto& systemProcessInfo) { return pid == std::to_string(systemProcessInfo.pid); }) ?
220         "SystemAbilityManager" : "ApplicationManagerService";
221     int count = WAIT_CHILD_PROCESS_COUNT;
222 
223     ReadShellToFile(fd, serviceName, "--ffrt " + pid, count);
224     return 0;
225 }
226 
ReadShellToFile(int fd,const std::string & serviceName,const std::string & cmd,int & count)227 void ReadShellToFile(int fd, const std::string& serviceName, const std::string& cmd, int& count)
228 {
229     int childPid = fork();
230     if (childPid < 0) {
231         return;
232     }
233     if (childPid == 0) {
234         if (fd < 0 || dup2(fd, STDOUT_FILENO) == -1 || dup2(fd, STDIN_FILENO) == -1 || dup2(fd, STDERR_FILENO) == -1) {
235             _exit(-1);
236         }
237         int ret = execl("/system/bin/hidumper", "hidumper", "-s", serviceName.c_str(), "-a", cmd.c_str(), nullptr);
238         if (ret < 0) {
239             _exit(-1);
240         }
241     } else {
242         int ret = waitpid(childPid, nullptr, WNOHANG);
243         while (count > 0 && (ret == 0)) {
244             usleep(WAIT_CHILD_PROCESS_INTERVAL);
245             count--;
246             ret = waitpid(childPid, nullptr, WNOHANG);
247         }
248 
249         if (ret == childPid || ret < 0) {
250             return;
251         }
252 
253         kill(childPid, SIGKILL);
254         int retryCount = MAX_RETRY_COUNT;
255         while (retryCount > 0 && waitpid(childPid, nullptr, WNOHANG) == 0) {
256             usleep(WAIT_CHILD_PROCESS_INTERVAL);
257             retryCount--;
258         }
259     }
260 }
261 
262 #ifdef HITRACE_CATCHER_ENABLE
HandleTelemetryMsg(std::map<std::string,std::string> & valuePairs)263 void HandleTelemetryMsg(std::map<std::string, std::string>& valuePairs)
264 {
265     std::string telemetryId = valuePairs["telemetryId"];
266     if (telemetryId.empty() || valuePairs["fault"] != FAULT_FREEZE_TYPE) {
267         HIVIEW_LOGE("telemetryId is empty or fault type is not freeze");
268         return;
269     }
270 
271     std::string telemetryStatus = valuePairs["telemetryStatus"];
272     std::unique_lock<std::shared_mutex> lock(grayscaleMutex_);
273     if (telemetryStatus == "off") {
274         telemetryId_ = "";
275         traceAppFilter_ = "";
276     } else if (telemetryStatus == "on") {
277         telemetryId_  = telemetryId;
278         traceAppFilter_ = valuePairs["traceAppFilter"];
279     }
280 
281     HIVIEW_LOGW("telemetryId_:%{public}s, traceAppFilter_:%{public}s, after received telemetryStatus:%{public}s",
282         telemetryId_.c_str(), traceAppFilter_.c_str(), telemetryStatus.c_str());
283 }
284 
FreezeFilterTraceOn(const std::string & bundleName)285 void FreezeFilterTraceOn(const std::string& bundleName)
286 {
287     {
288         std::shared_lock<std::shared_mutex> lock(grayscaleMutex_);
289         if (telemetryId_.empty() || (!traceAppFilter_.empty() &&
290             bundleName.find(traceAppFilter_) == std::string::npos)) {
291             return;
292         }
293     }
294 
295     std::shared_ptr<UCollectUtil::TraceCollector> collector = UCollectUtil::TraceCollector::Create();
296     if (!collector) {
297         return;
298     }
299     UCollect::TeleModule caller = UCollect::TeleModule::RELIABILITY;
300     auto result = collector->FilterTraceOn(caller, MAX_DUMP_TRACE_LIMIT * TimeUtil::SEC_TO_MILLISEC);
301     HIVIEW_LOGW("FreezeFilterTraceOn, telemetryId_:%{public}s, traceAppFilter_:%{public}s, retCode:%{public}d",
302         telemetryId_.c_str(), traceAppFilter_.c_str(), result.retCode);
303 }
304 
FreezeDumpTrace(uint64_t hitraceTime,bool grayscale,const std::string & bundleName)305 std::pair<std::string, std::vector<std::string>> FreezeDumpTrace(uint64_t hitraceTime, bool grayscale,
306     const std::string& bundleName)
307 {
308     std::pair<std::string, std::vector<std::string>> result;
309     std::shared_ptr<UCollectUtil::TraceCollector> collector = UCollectUtil::TraceCollector::Create();
310     if (!collector) {
311         return result;
312     }
313 
314     UCollect::TraceCaller traceCaller = UCollect::TraceCaller::RELIABILITY;
315     uint64_t startTime = TimeUtil::GetMilliseconds();
316     CollectResult<std::vector<std::string>> collectResult =
317         collector->DumpTraceWithDuration(traceCaller, MAX_DUMP_TRACE_LIMIT, hitraceTime);
318     uint64_t endTime = TimeUtil::GetMilliseconds();
319     HIVIEW_LOGW("get hitrace with duration, hitraceTime:%{public}" PRIu64 ", startTime:%{public}" PRIu64
320         ", endTime:%{public}" PRIu64 ", retCode:%{public}d", hitraceTime, startTime, endTime, collectResult.retCode);
321     if (collectResult.retCode == UCollect::UcError::SUCCESS) {
322         result.second = collectResult.data;
323         return result;
324     }
325 
326     if (!grayscale) {
327         return result;
328     } else {
329         std::shared_lock<std::shared_mutex> lock(grayscaleMutex_);
330         if (telemetryId_.empty() || (!traceAppFilter_.empty() &&
331             bundleName.find(traceAppFilter_) == std::string::npos)) {
332             return result;
333         }
334         result.first = telemetryId_;
335     }
336 
337     UCollect::TeleModule teleModule = UCollect::TeleModule::RELIABILITY;
338     startTime = TimeUtil::GetMilliseconds();
339     collectResult = collector->DumpTraceWithFilter(teleModule, MAX_DUMP_TRACE_LIMIT, hitraceTime);
340     endTime = TimeUtil::GetMilliseconds();
341     HIVIEW_LOGW("get hitrace with filter, hitraceTime:%{public}" PRIu64 ", startTime:%{public}" PRIu64
342         ", endTime:%{public}" PRIu64 ", retCode:%{public}d", hitraceTime, startTime, endTime, collectResult.retCode);
343     if (collectResult.retCode == UCollect::UcError::SUCCESS) {
344         result.second = collectResult.data;
345     }
346     return result;
347 }
GetTelemetryInfo()348 std::pair<std::string, std::string> GetTelemetryInfo()
349 {
350     std::shared_lock<std::shared_mutex> lock(grayscaleMutex_);
351     std::pair<std::string, std::string> info = {telemetryId_, traceAppFilter_};
352     return info;
353 }
354 #endif
355 }
356 } // namespace HiviewDFX
357 } // namespace OHOS
358