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