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