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 #include "native_leak_state.h"
16
17 #include <fstream>
18 #include <iostream>
19 #include <map>
20 #include <memory>
21 #include <regex>
22 #include <string>
23
24 #include <faultlogger.h>
25 #include <fcntl.h>
26 #include <sys/types.h>
27 #include <sys/wait.h>
28 #include <unistd.h>
29
30 #include "app_event_handler.h"
31 #include "app_event_publisher_factory.h"
32 #include "event_publish.h"
33 #include "fault_common_base.h"
34 #include "fault_detector_base.h"
35 #include "fault_info_base.h"
36 #include "fault_state_base.h"
37 #include "ffrt.h"
38 #include "hisysevent.h"
39 #include "hiview_logger.h"
40 #include "mem_profiler_collector.h"
41 #include "native_leak_info.h"
42 #include "native_leak_util.h"
43 #include "plugin_factory.h"
44
45 namespace OHOS {
46 namespace HiviewDFX {
47 DEFINE_LOG_TAG("NativeLeakState");
48
49 using namespace std;
50 using std::chrono::microseconds;
51
52 namespace {
53 constexpr uint32_t SHORT_WEIGHT = 8; // the ostream placeholder for a word when write memory info to file
54 constexpr uint32_t LOG_WEIGHT = 16;
55 constexpr size_t BASE_MEMBER_CNT = 4;
56 constexpr mode_t DEFAULT_LOG_FILE_MODE = 0644;
57 constexpr mode_t HIPROFILER_LOG_FILE_MODE = 0664;
58 constexpr uint32_t ABANDON_PROPORTION = 5;
59 constexpr uint32_t MAX_RECORD_NUM = 30;
60 constexpr uint32_t JUDGE_RECORD_NUM = 8;
61 constexpr uint32_t US_PER_SECOND = 1000 * 1000;
62 constexpr uint32_t WAIT_TRACKER_SO_LOAD_TIME_OUT = 3;
63 constexpr uint32_t WAIT_NMD_INFO_DUMP = 5;
64 constexpr uint32_t PROFILER_DEBUG_TIME_OUT = 900;
65 constexpr uint32_t WAIT_TO_DUMP_PROFILER_MEM = PROFILER_DEBUG_TIME_OUT + 5;
66 constexpr uint32_t PROFILER_SAMPLE_INTERVAL = 256;
67 constexpr uint32_t KILLER_MEM_LIMIT = 8 * 1024 * 1024; // 8GB
68
69 constexpr uint32_t HARD_THRESHOLD = 4 * 1024 * 1024; // 4GB
70
71 enum {
72 SMAPS_INFO = 1,
73 };
74
75 map<uint32_t, string> extraInfo = {
76 { SMAPS_INFO, "SMAPS_INFO"},
77 };
78
79 enum SmapsRollupRecordItem {
80 PSS = 1,
81 PSS_SIZE,
82 };
83
84 struct TrackCmd {
85 uint32_t magic;
86 uint32_t id;
87 uint32_t type;
88 uint64_t timestamp;
89 enum MemCmd cmd;
90 };
91
92 struct DetailInfo {
93 uint32_t magic { 0 };
94 uint32_t id { 0 };
95 uint32_t type { 0 };
96 uint64_t size { 0 };
97 uint64_t timestamp;
98 char data[0];
99 };
100 }
101
StateProcess(shared_ptr<FaultInfoBase> & monitorInfo,FaultDetectorBase & detectorObj)102 ErrCode NativeLeakSampleState::StateProcess(shared_ptr<FaultInfoBase> &monitorInfo, FaultDetectorBase &detectorObj)
103 {
104 auto userMonitorInfo = static_pointer_cast<NativeLeakInfo>(monitorInfo);
105 HIVIEW_LOGI("NativeLeakSampleState::StateProcess pid: %{public}d", userMonitorInfo->GetPid());
106 CollectBaseInfo(userMonitorInfo);
107 return SUCCESSED;
108 }
ChangeNextState(shared_ptr<FaultInfoBase> & monitorInfo,FaultDetectorBase & detectorObj)109 ErrCode NativeLeakSampleState::ChangeNextState(shared_ptr<FaultInfoBase> &monitorInfo, FaultDetectorBase &detectorObj)
110 {
111 return SUCCESSED;
112 }
113
CollectBaseInfo(shared_ptr<NativeLeakInfo> & userMonitorInfo) const114 void NativeLeakSampleState::CollectBaseInfo(shared_ptr<NativeLeakInfo> &userMonitorInfo) const
115 {
116 CollectUserBaseInfo(userMonitorInfo);
117 RemoveData(userMonitorInfo);
118 }
119
CollectUserBaseInfo(shared_ptr<NativeLeakInfo> & userMonitorInfo) const120 bool NativeLeakSampleState::CollectUserBaseInfo(shared_ptr<NativeLeakInfo> &userMonitorInfo) const
121 {
122 HIVIEW_LOGI("NativeLeakSampleState::CollectUserBaseInfo pid: %{public}d", userMonitorInfo->GetPid());
123 userMonitorInfo->AddCpuTime(FaultDetectorUtil::GetRunningMonotonicTime());
124 userMonitorInfo->AddRealTime(FaultDetectorUtil::GetRealTime());
125 userMonitorInfo->AddMemory(FaultDetectorUtil::GetProcessRss(userMonitorInfo->GetPid()));
126 string smapsRollupPath = "/proc/" + to_string(userMonitorInfo->GetPid()) + "/smaps_rollup";
127 ifstream fin;
128 fin.open(smapsRollupPath.c_str());
129 if (!fin.is_open()) {
130 HIVIEW_LOGE("failed to open: %{public}s", smapsRollupPath.c_str());
131 return false;
132 }
133
134 string line;
135 uint64_t pssMemoryKb = 0;
136 while (getline(fin, line)) {
137 regex recordRegex("^(.+):\\s*(.+) kB$");
138 smatch matches;
139 if (!regex_match(line, matches, recordRegex)) {
140 continue;
141 }
142 if (matches[PSS].str() == "Pss" || matches[PSS].str() == "SwapPss") {
143 pssMemoryKb += stoull(matches[PSS_SIZE]);
144 }
145 }
146 userMonitorInfo->AddCpuTime(FaultDetectorUtil::GetRunningMonotonicTime());
147 userMonitorInfo->AddRealTime(FaultDetectorUtil::GetRealTime());
148 userMonitorInfo->AddMemory(pssMemoryKb);
149 HIVIEW_LOGI("process: %{public}s, pid: %{public}d, pss:%{public}u KB",
150 userMonitorInfo->GetProcessName().c_str(), userMonitorInfo->GetPid(), static_cast<uint32_t>(pssMemoryKb));
151 if (pssMemoryKb > (userMonitorInfo->GetTopMemory())) {
152 userMonitorInfo->SetTopMemory(pssMemoryKb);
153 }
154 return true;
155 }
156
RemoveData(shared_ptr<NativeLeakInfo> & userMonitorInfo) const157 void NativeLeakSampleState::RemoveData(shared_ptr<NativeLeakInfo> &userMonitorInfo) const
158 {
159 size_t cpuSize = userMonitorInfo->GetCpuTime().size();
160 if (cpuSize < MAX_RECORD_NUM) {
161 return;
162 }
163 HIVIEW_LOGI("NativeLeakSampleState::RemoveData pid: %{public}d", userMonitorInfo->GetPid());
164 userMonitorInfo->RemoveMemory(ABANDON_PROPORTION);
165 userMonitorInfo->RemoveTime(ABANDON_PROPORTION);
166 }
167
StateProcess(shared_ptr<FaultInfoBase> & monitorInfo,FaultDetectorBase & detectorObj)168 ErrCode NativeLeakJudgeState::StateProcess(shared_ptr<FaultInfoBase> &monitorInfo, FaultDetectorBase &detectorObj)
169 {
170 HIVIEW_LOGI("NativeLeakJudgeState::StateProcess pid: %{public}d", monitorInfo->GetPid());
171 auto userMonitorInfo = static_pointer_cast<NativeLeakInfo>(monitorInfo);
172 if (IsMemoryLeak(userMonitorInfo)) {
173 HIVIEW_LOGE("pid: %{public}d does memory leak", userMonitorInfo->GetPid());
174 userMonitorInfo->SetLeakGrade(JudgeMemoryLeakGrade(userMonitorInfo));
175 return SUCCESSED;
176 }
177 HIVIEW_LOGI("pid: %{public}d dont memory leak", userMonitorInfo->GetPid());
178 return FAILURE;
179 }
180
IsMemoryLeak(shared_ptr<NativeLeakInfo> & userMonitorInfo)181 bool NativeLeakJudgeState::IsMemoryLeak(shared_ptr<NativeLeakInfo> &userMonitorInfo)
182 {
183 uint64_t topMemory = userMonitorInfo->GetTopMemory();
184 auto pid = userMonitorInfo->GetPid();
185 if (topMemory >= HARD_THRESHOLD) {
186 return true;
187 }
188 uint32_t memorySize = userMonitorInfo->GetMemory().size();
189 if (memorySize < JUDGE_RECORD_NUM) {
190 HIVIEW_LOGE("pid: %{public}d memorySize:%{public}u", pid, memorySize);
191 return false;
192 }
193 uint64_t leakThreshold = userMonitorInfo->GetMemoryLimit();
194 for (size_t i = memorySize - JUDGE_RECORD_NUM; i < memorySize; ++i) {
195 if (userMonitorInfo->GetMemory().at(i) < leakThreshold) {
196 HIVIEW_LOGE("pid: %{public}d some memory record is few, no leak", pid);
197 return false;
198 }
199 }
200 HIVIEW_LOGI("pid: %{public}d memory always over limit, seems leak", userMonitorInfo->GetPid());
201 return true;
202 }
203
JudgeMemoryLeakGrade(shared_ptr<NativeLeakInfo> & userMonitorInfo)204 string NativeLeakJudgeState::JudgeMemoryLeakGrade(shared_ptr<NativeLeakInfo> &userMonitorInfo)
205 {
206 string leakGrade;
207 if (userMonitorInfo->GetMemoryLimit() > MEMORY_RATING_LINE) {
208 leakGrade = JudgeMemoryLeakGradeByRatio(userMonitorInfo);
209 } else {
210 leakGrade = JudgeSmallMemoryLeakGrade(userMonitorInfo);
211 }
212 HIVIEW_LOGI("pid: %{public}d leakGrade:%{public}s", userMonitorInfo->GetPid(), leakGrade.c_str());
213 return leakGrade;
214 }
215
JudgeSmallMemoryLeakGrade(shared_ptr<NativeLeakInfo> & userMonitorInfo)216 string NativeLeakJudgeState::JudgeSmallMemoryLeakGrade(shared_ptr<NativeLeakInfo> &userMonitorInfo)
217 {
218 uint64_t diff = userMonitorInfo->GetTopMemory() - userMonitorInfo->GetMemoryLimit();
219 if (diff <= MEMORY_WARNING_GRADE) {
220 return MEMORY_LEAK_INFO;
221 }
222 if (diff <= MEMORY_ERROR_GRADE) {
223 return MEMORY_LEAK_WARNING;
224 }
225 return MEMORY_LEAK_ERROR;
226 }
227
JudgeMemoryLeakGradeByRatio(shared_ptr<NativeLeakInfo> & userMonitorInfo)228 string NativeLeakJudgeState::JudgeMemoryLeakGradeByRatio(shared_ptr<NativeLeakInfo> &userMonitorInfo)
229 {
230 uint64_t memoryLimit = userMonitorInfo->GetMemoryLimit();
231 uint64_t diff = userMonitorInfo->GetTopMemory() - memoryLimit;
232 if (memoryLimit == 0) {
233 return MEMORY_LEAK_ERROR;
234 }
235 double diffRatio = diff * 1.0 / memoryLimit;
236 constexpr uint32_t oneHundred = 100;
237 diffRatio = floor(diffRatio * oneHundred) / oneHundred;
238 if (diffRatio <= MEMORY_WARNING_RATIO && diff < MEMORY_WARNING_RATIO_GRADE) {
239 return MEMORY_LEAK_INFO;
240 }
241 if (diffRatio <= MEMORY_ERROR_RATIO && diff < MEMORY_ERROR_RATIO_GRADE) {
242 return MEMORY_LEAK_WARNING;
243 }
244 return MEMORY_LEAK_ERROR;
245 }
246
JudgeOtherMemoryLeakGrade(shared_ptr<NativeLeakInfo> & userMonitorInfo)247 string NativeLeakJudgeState::JudgeOtherMemoryLeakGrade(shared_ptr<NativeLeakInfo> &userMonitorInfo)
248 {
249 return MEMORY_LEAK_WARNING;
250 }
251
ChangeNextState(shared_ptr<FaultInfoBase> & monitorInfo,FaultDetectorBase & detectorObj)252 ErrCode NativeLeakJudgeState::ChangeNextState(shared_ptr<FaultInfoBase> &monitorInfo, FaultDetectorBase &detectorObj)
253 {
254 return SUCCESSED;
255 }
256
NativeLeakDumpState()257 NativeLeakDumpState::NativeLeakDumpState()
258 #ifdef HAS_HIPROFILER
259 : memProfilerCollector_(UCollectUtil::MemProfilerCollector::Create())
260 #endif
261 {
262 }
263
StateProcess(shared_ptr<FaultInfoBase> & monitorInfo,FaultDetectorBase & detectorObj)264 ErrCode NativeLeakDumpState::StateProcess(shared_ptr<FaultInfoBase> &monitorInfo, FaultDetectorBase &detectorObj)
265 {
266 auto userMonitorInfo = static_pointer_cast<NativeLeakInfo>(monitorInfo);
267 HIVIEW_LOGI("NativeLeakDumpState::StateProcess pid: %{public}d", userMonitorInfo->GetPid());
268 GetMemoryLeakLog(userMonitorInfo, GENERAL_STATISTICS);
269 DumpExtraInfo(userMonitorInfo, SMAPS_INFO);
270 LaunchMemoryDebug(userMonitorInfo);
271 GetProfiler(userMonitorInfo);
272 if (ChangeNextState(monitorInfo, detectorObj)) {
273 HIVIEW_LOGE("ChangeNextState failed, pid: %{public}d", userMonitorInfo->GetPid());
274 return FAILURE;
275 }
276 HIVIEW_LOGI("ChangeNextState success, pid: %{public}d", userMonitorInfo->GetPid());
277 return SUCCESSED;
278 }
279
GetMemoryLeakLog(shared_ptr<NativeLeakInfo> & userMonitorInfo,uint32_t flag)280 void NativeLeakDumpState::GetMemoryLeakLog(shared_ptr<NativeLeakInfo> &userMonitorInfo, uint32_t flag)
281 {
282 string filePath = userMonitorInfo->GetSmapsPath();
283 HIVIEW_LOGE("filepath:%{public}s", filePath.c_str());
284 ofstream fout;
285 if (!userMonitorInfo->GetIsAppendSmapsFile()) {
286 fout.open(filePath, ios::out);
287 } else {
288 fout.open(filePath, ios::out | ios::app);
289 }
290 if (!fout.is_open()) {
291 HIVIEW_LOGE("failed to open file:%{public}s", filePath.c_str());
292 return;
293 }
294 if (flag & GENERAL_STATISTICS) {
295 DumpGeneralInfo(fout, userMonitorInfo);
296 userMonitorInfo->SetIsAppendSmapsFile(true);
297 }
298 if (flag & ACCURATE_STATISTICS) {
299 DumpDetailInfo(fout, userMonitorInfo);
300 }
301 if (flag & STACK_STATISTICS) {
302 DumpStackInfo(userMonitorInfo);
303 }
304 DumpUserMemInfo(userMonitorInfo);
305 }
306
DumpGeneralInfo(ofstream & fout,shared_ptr<NativeLeakInfo> & userMonitorInfo) const307 void NativeLeakDumpState::DumpGeneralInfo(ofstream &fout, shared_ptr<NativeLeakInfo> &userMonitorInfo) const
308 {
309 if (userMonitorInfo == nullptr) {
310 HIVIEW_LOGE("WRONG POINTER");
311 return;
312 }
313 fout << endl;
314 fout << "Generated by HivewDFX @OpenHarmony" << endl;
315 fout << "LOGGER_MEMCHECK_GERNAL_INFO" << endl;
316 fout << "\tpidNumber: " << userMonitorInfo->GetPid() << endl;
317 fout << "\tprocessName: " << userMonitorInfo->GetProcessName() << endl;
318 fout << "\tPidStartTime: " << userMonitorInfo->GetPidStartTime() << endl;
319 fout << "\tTopPssMemory: " << userMonitorInfo->GetTopMemory() << endl;
320 fout << endl;
321 string meminfoPath = FaultDetectorUtil::GetMemInfoPath();
322 ifstream fin(meminfoPath);
323 if (!fin.is_open()) {
324 HIVIEW_LOGE("failed to open file: %{public}s", meminfoPath.c_str());
325 return;
326 }
327 fout << "******************************" << endl;
328 fout << "LOGGER_MEMCHECK_MEMINFO" << endl;
329 fout << fin.rdbuf();
330 fout << endl;
331 HIVIEW_LOGI("write general statis itics finished");
332 }
333
DumpDetailInfo(ofstream & fout,shared_ptr<NativeLeakInfo> & userMonitorInfo)334 void NativeLeakDumpState::DumpDetailInfo(ofstream &fout, shared_ptr<NativeLeakInfo> &userMonitorInfo)
335 {
336 dumpStateMtx_.lock();
337 fout << endl;
338 fout << "******************************" << endl;
339 fout << "LOGGER_MEMCHECK_DETAIL_INFO" << endl;
340 auto fd = open(BBOX_PATH.c_str(), O_RDONLY);
341 if (fd < 0) {
342 dumpStateMtx_.unlock();
343 HIVIEW_LOGE("failed to open %{public}s, err: %{public}d", BBOX_PATH.c_str(), errno);
344 return;
345 }
346 uint64_t detailSize = sizeof(DetailInfo) + MEMCHECK_DETAILINFO_MAXSIZE;
347 auto detailInfo = static_cast<DetailInfo *>(calloc(1, detailSize));
348 if (detailInfo == nullptr) {
349 dumpStateMtx_.unlock();
350 HIVIEW_LOGE("failed to alloc memory!");
351 close(fd);
352 return;
353 }
354 detailInfo->magic = MEMCHECK_MAGIC;
355 detailInfo->id = userMonitorInfo->GetPid();
356 detailInfo->size = MEMCHECK_DETAILINFO_MAXSIZE;
357 detailInfo->type = MTYPE_USER_PSS;
358 detailInfo->timestamp = userMonitorInfo->GetPidStartTime();
359 int32_t ret = ioctl(fd, LOGGER_MEMCHECK_DETAIL_READ, detailInfo);
360 if (ret != 0) {
361 HIVIEW_LOGE("ioctl read detail statisitics failed, ret=%{public}d", ret);
362 }
363 fout << detailInfo->data << endl;
364 free(detailInfo);
365 HIVIEW_LOGI("process %{public}s write detail statisitics finished", userMonitorInfo->GetProcessName().c_str());
366 close(fd);
367 dumpStateMtx_.unlock();
368 }
369
DumpStackInfo(shared_ptr<NativeLeakInfo> & userMonitorInfo)370 void NativeLeakDumpState::DumpStackInfo(shared_ptr<NativeLeakInfo> &userMonitorInfo)
371 {
372 #ifdef HAS_HIPROFILER
373 HIVIEW_LOGW("HAS_HIPROFILER defined, is going to dump stack info.");
374 string logFilePath = userMonitorInfo->GetLogFilePath();
375 auto fd = open(logFilePath.c_str(), O_CREAT | O_RDWR, HIPROFILER_LOG_FILE_MODE);
376 if (fd < 0) {
377 HIVIEW_LOGE("failed to open %{public}s, err: %{public}d", logFilePath.c_str(), errno);
378 return;
379 }
380 int ret = memProfilerCollector_->Start(fd, UCollectUtil::ProfilerType::MEM_PROFILER_CALL_STACK,
381 userMonitorInfo->GetPid(), PROFILER_DEBUG_TIME_OUT, PROFILER_SAMPLE_INTERVAL);
382 if (ret < 0) {
383 close(fd);
384 HIVIEW_LOGE("dump process %{public}s mem profiler failed, ret is: %{public}d",
385 userMonitorInfo->GetProcessName().c_str(), ret);
386 return;
387 }
388 ffrt::this_task::sleep_for(microseconds(WAIT_TO_DUMP_PROFILER_MEM * US_PER_SECOND));
389 close(fd);
390 HIVIEW_LOGI("process %{public}s write stack statisitics finished", userMonitorInfo->GetProcessName().c_str());
391 #else
392 HIVIEW_LOGW("HAS_HIPROFILER not define, will not dump stack info.");
393 #endif
394 }
395
DumpUserMemInfo(shared_ptr<NativeLeakInfo> & userMonitorInfo)396 void NativeLeakDumpState::DumpUserMemInfo(shared_ptr<NativeLeakInfo> &userMonitorInfo)
397 {
398 dumpStateMtx_.lock();
399 string filePath = userMonitorInfo->GetSampleFilePath();
400 ofstream fout(filePath);
401 if (!fout.is_open()) {
402 HIVIEW_LOGE("failed to open file: %{public}s", filePath.c_str());
403 dumpStateMtx_.unlock();
404 return;
405 }
406 fout << "pid:\t" << userMonitorInfo->GetPid() << "\t" << endl;
407 fout << "processName:\t" << userMonitorInfo->GetProcessName() << endl;
408 fout << "threshold:\t" << userMonitorInfo->GetMemoryLimit() << "(KB)" << endl;
409 fout << "actualRss:\t" << userMonitorInfo->GetActualRssThreshold() << "(KB)" << endl;
410 fout << "TopPssMemory:\t" << userMonitorInfo->GetTopMemory() << "(KB)" << endl;
411 fout << left;
412 fout << endl;
413 fout << setw(LOG_WEIGHT) << "time(s)" << setw(LOG_WEIGHT) << "PssMemory(KB)";
414 fout << setw(LOG_WEIGHT) << "realtime" << endl;
415 size_t cpuSize = userMonitorInfo->GetCpuTime().size();
416 for (size_t i = 0; i < cpuSize; ++i) {
417 if (cpuSize != userMonitorInfo->GetMemory().size()) {
418 HIVIEW_LOGE("CPU SIZE NOT MATCH MEMORY SIZE");
419 dumpStateMtx_.unlock();
420 return;
421 }
422 fout << setw(LOG_WEIGHT) << userMonitorInfo->GetCpuTime().at(i);
423 fout << setw(LOG_WEIGHT) << userMonitorInfo->GetMemory().at(i);
424 fout << setw(LOG_WEIGHT) << userMonitorInfo->GetRealTime().at(i) << endl;
425 }
426 dumpStateMtx_.unlock();
427 }
428
DumpExtraInfo(shared_ptr<NativeLeakInfo> & userMonitorInfo,uint32_t type) const429 void NativeLeakDumpState::DumpExtraInfo(shared_ptr<NativeLeakInfo> &userMonitorInfo, uint32_t type) const
430 {
431 if (type & SMAPS_INFO) {
432 ForkProcessToDumpExtraInfo(userMonitorInfo->GetSmapsPath(), userMonitorInfo, SMAPS_INFO);
433 }
434 }
435
ForkProcessToDumpExtraInfo(const string & path,shared_ptr<NativeLeakInfo> & userMonitorInfo,uint32_t type) const436 bool NativeLeakDumpState::ForkProcessToDumpExtraInfo(
437 const string &path, shared_ptr<NativeLeakInfo> &userMonitorInfo, uint32_t type) const
438 {
439 int writeFd = 0;
440 if (type & SMAPS_INFO) {
441 writeFd = open(path.c_str(), O_CREAT | O_RDWR | O_APPEND, DEFAULT_LOG_FILE_MODE);
442 } else {
443 writeFd = open(path.c_str(), O_CREAT | O_RDWR, DEFAULT_LOG_FILE_MODE);
444 }
445 if (writeFd < 0) {
446 HIVIEW_LOGE("failed to open %{public}s, errno is: %{public}d", path.c_str(), errno);
447 return false;
448 }
449 int ret = dup2(writeFd, STDIN_FILENO) + dup2(writeFd, STDOUT_FILENO) + dup2(writeFd, STDERR_FILENO);
450 if (ret < 0) {
451 HIVIEW_LOGE("dup2 writeFd fail, error is %{public}d", errno);
452 close(writeFd);
453 return false;
454 }
455 if (!DumpUserMemInfoToSmapsFile(writeFd, userMonitorInfo)) {
456 HIVIEW_LOGE("dump user mem info to smaps failed, errno is %{public}d", errno);
457 }
458 string generalMessage = string("******************************\n")
459 + string("LOGGER_MEMCHECK_") + GetExtraInfo(type) + "\n"
460 + string("get info realtime:\t") + FaultDetectorUtil::GetRealTime() + "\n";
461 size_t generalMessageSize = generalMessage.size();
462 ssize_t watchdogWrite = write(writeFd, generalMessage.c_str(), generalMessageSize);
463 if (watchdogWrite < 0) {
464 HIVIEW_LOGE("write get extra info realtime failed, errno is %{public}d", errno);
465 }
466 pid_t childPid = fork();
467 if (childPid < 0) {
468 HIVIEW_LOGE("failed to fork process, errno is: %{public}d\n", errno);
469 close(writeFd);
470 return false;
471 }
472 if (childPid == 0) {
473 if (type & SMAPS_INFO) {
474 ExecuteChildProcessGetSmapsInfo(userMonitorInfo->GetPid());
475 }
476 } else {
477 if (waitpid(childPid, nullptr, 0) != childPid) {
478 HIVIEW_LOGE("waitpid fail, pid: %{public}d, error: %{public}d", childPid, errno);
479 close(writeFd);
480 return false;
481 }
482 HIVIEW_LOGI("waitpid %{public}d success", childPid);
483 }
484 close(writeFd);
485 return true;
486 }
487
DumpUserMemInfoToSmapsFile(int writeFd,shared_ptr<NativeLeakInfo> & userMonitorInfo) const488 bool NativeLeakDumpState::DumpUserMemInfoToSmapsFile(int writeFd, shared_ptr<NativeLeakInfo> &userMonitorInfo) const
489 {
490 string longWeight(LOG_WEIGHT, ' ');
491 string userMemMessage = "pid:\t" + to_string(userMonitorInfo->GetPid()) + "\n"
492 + "processName:\t" + userMonitorInfo->GetProcessName() + "\n"
493 + "threshold:\t" + to_string(userMonitorInfo->GetMemoryLimit()) + "\n"
494 + "TopPssMemory:\t" + to_string(userMonitorInfo->GetTopMemory()) + "\n"
495 + "\n";
496 userMemMessage += "time(s)" + longWeight + "PssMemory(KB)" + longWeight + "realtime\n";
497 size_t cpuSize = userMonitorInfo->GetCpuTime().size();
498 for (size_t i = 0; i < userMonitorInfo->GetCpuTime().size(); ++i) {
499 if (cpuSize != userMonitorInfo->GetMemory().size()) {
500 HIVIEW_LOGE("cpu size not match memory size");
501 return false;
502 }
503 userMemMessage += to_string(userMonitorInfo->GetCpuTime().at(i)) + longWeight
504 + to_string(userMonitorInfo->GetMemory().at(i)) + longWeight
505 + userMonitorInfo->GetRealTime().at(i) + "\n";
506 }
507 size_t userMemMessageSize = userMemMessage.size();
508 ssize_t watchdogWrite = write(writeFd, userMemMessage.c_str(), userMemMessageSize);
509 if (watchdogWrite < 0) {
510 HIVIEW_LOGE("write to smaps file failed, errno is %{public}d", errno);
511 return false;
512 }
513 return true;
514 }
515
GetExtraInfo(uint32_t type) const516 string NativeLeakDumpState::GetExtraInfo(uint32_t type) const
517 {
518 auto it = find_if(extraInfo.begin(), extraInfo.end(),
519 [&type](const pair<uint32_t, string>& item) {
520 return type & item.first;
521 });
522 if (it != extraInfo.end()) {
523 return it->second;
524 }
525 return "";
526 }
527
ExecuteChildProcessGetSmapsInfo(int pid) const528 void NativeLeakDumpState::ExecuteChildProcessGetSmapsInfo(int pid) const
529 {
530 int ret = execl("/system/bin/hidumper", "hidumper", "--mem-smaps", to_string(pid).c_str(), nullptr);
531 if (ret < 0) {
532 HIVIEW_LOGE("execl return %{public}d, type is SMAPS_INFO, errno: %{public}d", ret, errno);
533 _exit(-1);
534 }
535 _exit(0);
536 }
537
LaunchMemoryDebug(shared_ptr<NativeLeakInfo> & userMonitorInfo)538 void NativeLeakDumpState::LaunchMemoryDebug(shared_ptr<NativeLeakInfo> &userMonitorInfo)
539 {
540 if (userMonitorInfo->GetIsProcessDied()) {
541 HIVIEW_LOGE("process %{public}s has died, stop get native log.", userMonitorInfo->GetProcessName().c_str());
542 return;
543 }
544 userMonitorInfo->SetDebugStartTime(FaultDetectorUtil::GetRunningMonotonicTime());
545 if (!SuccessToSendCmd(userMonitorInfo, MEMCMD_ENABLE)) {
546 return;
547 }
548 // wait memleak_tracker so dlopen
549 ffrt::this_task::sleep_for(microseconds(WAIT_TRACKER_SO_LOAD_TIME_OUT * US_PER_SECOND));
550 GetMemoryLeakLog(userMonitorInfo, ACCURATE_STATISTICS);
551 if (!SuccessToSendCmd(userMonitorInfo, MEMCMD_CLEAR_LOG)) {
552 return;
553 }
554 }
555
GetProfiler(shared_ptr<NativeLeakInfo> & userMonitorInfo)556 void NativeLeakDumpState::GetProfiler(shared_ptr<NativeLeakInfo> &userMonitorInfo)
557 {
558 // musl hooking leak, hiprofiler is not allowed, wait for nmd info dump
559 ffrt::this_task::sleep_for(microseconds(WAIT_NMD_INFO_DUMP * US_PER_SECOND));
560 GetMemoryLeakLog(userMonitorInfo, STACK_STATISTICS);
561 }
562
SuccessToSendCmd(shared_ptr<NativeLeakInfo> & userMonitorInfo,MemCmd cmdType)563 bool NativeLeakDumpState::SuccessToSendCmd(shared_ptr<NativeLeakInfo> &userMonitorInfo, MemCmd cmdType)
564 {
565 if (SendCmd(userMonitorInfo, cmdType)) {
566 return false;
567 }
568 return true;
569 }
570
SendCmd(shared_ptr<NativeLeakInfo> & userMonitorInfo,MemCmd cmdType) const571 int32_t NativeLeakDumpState::SendCmd(shared_ptr<NativeLeakInfo> &userMonitorInfo, MemCmd cmdType) const
572 {
573 TrackCmd trackCmd;
574 trackCmd.magic = MEMCHECK_MAGIC;
575 trackCmd.cmd = cmdType;
576 trackCmd.id = userMonitorInfo->GetPid();
577 trackCmd.type = userMonitorInfo->GetJavaState() ? MTYPE_USER_PSS_JAVA : MTYPE_USER_PSS_NATIVE;
578 trackCmd.timestamp = userMonitorInfo->GetPidStartTime();
579 HIVIEW_LOGI("ID:%{public}d, type:%{public}u, cmd:%{public}d", trackCmd.id, trackCmd.type, cmdType);
580 int fd = open(BBOX_PATH.c_str(), O_RDONLY);
581 if (fd < 0) {
582 HIVIEW_LOGE("failed to open %{public}s", BBOX_PATH.c_str());
583 return FAILURE;
584 }
585 int32_t ret = ioctl(fd, LOGGER_MEMCHECK_COMMAND, &trackCmd);
586 if (ret != 0) {
587 HIVIEW_LOGE("send cmd error");
588 }
589 close(fd);
590 return ret;
591 }
592
ChangeNextState(shared_ptr<FaultInfoBase> & monitorInfo,FaultDetectorBase & detectorObj)593 ErrCode NativeLeakDumpState::ChangeNextState(shared_ptr<FaultInfoBase> &monitorInfo, FaultDetectorBase &detectorObj)
594 {
595 FaultStateType nextState = PROC_REPORT_STATE;
596 auto userMonitorInfo = static_pointer_cast<NativeLeakInfo>(monitorInfo);
597
598 int ret = detectorObj.ExeNextStateProcess(monitorInfo, nextState);
599 if (ret) {
600 HIVIEW_LOGE("dump finished, change to %{public}s state process failed, ret is %{public}d\n",
601 FaultStateName[monitorInfo->GetState()].c_str(), ret);
602 return FAILURE;
603 }
604 return SUCCESSED;
605 }
606
StateProcess(shared_ptr<FaultInfoBase> & monitorInfo,FaultDetectorBase & detectorObj)607 ErrCode NativeLeakReportState::StateProcess(shared_ptr<FaultInfoBase> &monitorInfo, FaultDetectorBase &detectorObj)
608 {
609 auto userMonitorInfo = static_pointer_cast<NativeLeakInfo>(monitorInfo);
610 PostEvent(monitorInfo);
611
612 if (ChangeNextState(monitorInfo, detectorObj)) {
613 return FAILURE;
614 }
615 return SUCCESSED;
616 }
617
setEventHandler(std::shared_ptr<AppEventHandler> handler)618 void NativeLeakReportState::setEventHandler(std::shared_ptr<AppEventHandler> handler)
619 {
620 HIVIEW_LOGI("NativeLeakReportState::setEventHandler");
621 this->appEventHandler_ = handler;
622 }
623
PostEvent(shared_ptr<FaultInfoBase> & monitorInfo)624 void NativeLeakReportState::PostEvent(shared_ptr<FaultInfoBase> &monitorInfo)
625 {
626 auto userMonitorInfo = static_pointer_cast<NativeLeakInfo>(monitorInfo);
627
628 if (appEventHandler_ == nullptr) {
629 HIVIEW_LOGE("appEventHandler_ is null, will not postEvent.");
630 return;
631 }
632
633 AppEventHandler::ResourceOverLimitInfo info;
634 info.pid = userMonitorInfo->GetPid();
635 info.uid = FaultDetectorUtil::GetProcessUid(info.pid);
636 info.bundleName = userMonitorInfo->GetProcessName();
637 info.bundleVersion = userMonitorInfo->GetHapVersion();
638 info.resourceType = "pss_memory";
639 info.pss = userMonitorInfo->GetTopMemory();
640 FaultDetectorUtil::GetStatm(info.pid, info.vss, info.rss);
641 FaultDetectorUtil::GetMeminfo(info.avaliableMem, info.freeMem, info.totalMem);
642
643 HIVIEW_LOGD("PostFaultEvent start");
644 appEventHandler_->PostEvent(info);
645 HIVIEW_LOGD("PostFaultEvent end");
646 }
647
ChangeNextState(shared_ptr<FaultInfoBase> & monitorInfo,FaultDetectorBase & detectorObj)648 ErrCode NativeLeakReportState::ChangeNextState(shared_ptr<FaultInfoBase> &monitorInfo, FaultDetectorBase &detectorObj)
649 {
650 FaultStateType nextState = PROC_FINISHED_STATE;
651 auto userMonitorInfo = static_pointer_cast<NativeLeakInfo>(monitorInfo);
652
653 int ret = detectorObj.ExeNextStateProcess(monitorInfo, nextState);
654 if (ret) {
655 HIVIEW_LOGE("report finished, Exe %{public}s state process failed, ret is %{public}d\n",
656 FaultStateName[nextState].c_str(), ret);
657 return FAILURE;
658 }
659 return SUCCESSED;
660 }
661
StateProcess(shared_ptr<FaultInfoBase> & monitorInfo,FaultDetectorBase & detectorObj)662 ErrCode NativeLeakRemovalState::StateProcess(shared_ptr<FaultInfoBase> &monitorInfo, FaultDetectorBase &detectorObj)
663 {
664 HIVIEW_LOGI("NativeLeakRemovalState StateProcess not define\n"); // wzy:kiding me? maybe can use interface
665 if (ChangeNextState(monitorInfo, detectorObj)) {
666 return FAILURE;
667 }
668 return SUCCESSED;
669 }
670
ChangeNextState(shared_ptr<FaultInfoBase> & monitorInfo,FaultDetectorBase & detectorObj)671 ErrCode NativeLeakRemovalState::ChangeNextState(shared_ptr<FaultInfoBase> &monitorInfo, FaultDetectorBase &detectorObj)
672 {
673 int ret = detectorObj.ExeNextStateProcess(monitorInfo, PROC_FINISHED_STATE);
674 if (ret) {
675 HIVIEW_LOGE("remove finished, Exe PROC_FINISHED_STATE state process failed, ret is %{public}d\n", ret);
676 return FAILURE;
677 }
678 return SUCCESSED;
679 }
680 } // namespace HiviewDFX
681 } // namespace OHOS
682