1 /*
2  * Copyright (C) 2021-2022 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 
16 #include "executor/memory/parse/parse_smaps_info.h"
17 #include <fstream>
18 #include "executor/memory/memory_util.h"
19 #include "hilog_wrapper.h"
20 #include "util/string_utils.h"
21 #include "util/file_utils.h"
22 
23 using namespace std;
24 namespace OHOS {
25 namespace HiviewDFX {
26 constexpr int DATAS_MIN_LEN = 2;
ParseSmapsInfo()27 ParseSmapsInfo::ParseSmapsInfo()
28 {
29 }
30 
~ParseSmapsInfo()31 ParseSmapsInfo::~ParseSmapsInfo()
32 {
33 }
34 
GetHasPidValue(const string & str,string & type,uint64_t & value)35 bool ParseSmapsInfo::GetHasPidValue(const string &str, string &type, uint64_t &value)
36 {
37     bool success = false;
38     if (StringUtils::GetInstance().IsBegin(str, "R")) {
39         success = MemoryUtil::GetInstance().GetTypeAndValue(str, type, value);
40         if (success) {
41             if (type == "Rss") {
42                 return true;
43             }
44         }
45         return false;
46     } else if (StringUtils::GetInstance().IsBegin(str, "P")) {
47         success = MemoryUtil::GetInstance().GetTypeAndValue(str, type, value);
48         if (success) {
49             if (type == "Pss" || type == "Private_Clean" || type == "Private_Dirty") {
50                 return true;
51             }
52         }
53         return false;
54     } else if (StringUtils::GetInstance().IsBegin(str, "S")) {
55         success = MemoryUtil::GetInstance().GetTypeAndValue(str, type, value);
56         if (success) {
57             if (type == "Shared_Clean" || type == "Shared_Dirty" || type == "Swap" || type == "SwapPss" ||
58                 type == "Size") {
59                 return true;
60             }
61         }
62         return false;
63     }
64     return false;
65 }
66 
GetNoPidValue(const string & str,string & type,uint64_t & value)67 bool ParseSmapsInfo::GetNoPidValue(const string &str, string &type, uint64_t &value)
68 {
69     if (StringUtils::GetInstance().IsBegin(str, "Pss") || StringUtils::GetInstance().IsBegin(str, "SwapPss")) {
70         return MemoryUtil::GetInstance().GetTypeAndValue(str, type, value);
71     }
72     return false;
73 }
74 
GetValue(const MemoryFilter::MemoryType & memType,const string & str,string & type,uint64_t & value)75 bool ParseSmapsInfo::GetValue(const MemoryFilter::MemoryType &memType, const string &str, string &type, uint64_t &value)
76 {
77     if (memType == MemoryFilter::MemoryType::APPOINT_PID) {
78         return GetHasPidValue(str, type, value);
79     } else {
80         return GetNoPidValue(str, type, value);
81     }
82 }
83 
GetSmapsValue(const MemoryFilter::MemoryType & memType,const string & str,string & type,uint64_t & value)84 bool ParseSmapsInfo::GetSmapsValue(const MemoryFilter::MemoryType &memType, const string &str, string &type,
85     uint64_t &value)
86 {
87     if (memType == MemoryFilter::MemoryType::APPOINT_PID) {
88         return GetHasPidValue(str, type, value);
89     }
90     return false;
91 }
92 
93 /**
94  * @description: Parse smaps file
95  * @param {MemoryType} &memType-APPOINT_PID-Specify the PID,NOT_SPECIFIED_PID-No PID is specified
96  * @param {int} &pid-Pid
97  * @param {GroupMap} &result-The result of parsing
98  * @return bool-true:parse success,false-parse fail
99  */
GetInfo(const MemoryFilter::MemoryType & memType,const int & pid,GroupMap & nativeMap,GroupMap & result)100 bool ParseSmapsInfo::GetInfo(const MemoryFilter::MemoryType &memType, const int &pid,
101                              GroupMap &nativeMap, GroupMap &result)
102 {
103     DUMPER_HILOGD(MODULE_SERVICE, "ParseSmapsInfo: GetInfo pid:(%{public}d) begin.\n", pid);
104     string path = "/proc/" + to_string(pid) + "/smaps";
105     bool ret = FileUtils::GetInstance().LoadStringFromProcCb(path, false, true, [&](const string& line) -> void {
106         string name;
107         uint64_t iNode = 0;
108         if (StringUtils::GetInstance().IsEnd(line, "B")) {
109             string type;
110             uint64_t value = 0;
111             if (GetValue(memType, line, type, value)) {
112                 MemoryUtil::GetInstance().CalcGroup(memGroup_, type, value, result);
113                 MemoryUtil::GetInstance().CalcGroup(nativeMemGroup_, type, value, nativeMap);
114             }
115         } else if (MemoryUtil::GetInstance().IsNameLine(line, name, iNode)) {
116             MemoryFilter::GetInstance().ParseMemoryGroup(name, memGroup_, iNode);
117             MemoryFilter::GetInstance().ParseNativeHeapMemoryGroup(name, nativeMemGroup_, iNode);
118         }
119     });
120     DUMPER_HILOGD(MODULE_SERVICE, "ParseSmapsInfo: GetInfo pid:(%{public}d) end,success!\n", pid);
121     return ret;
122 }
123 
SetMapByNameLine(const string & group,const string & content)124 void ParseSmapsInfo::SetMapByNameLine(const string &group, const string &content)
125 {
126     memMap_.insert(pair<string, string>("Name", group));
127     vector<string> datas;
128     StringUtils::GetInstance().StringSplit(content, " ", datas);
129     vector<string> startAndEnd;
130     if (datas.size() < DATAS_MIN_LEN) {
131         DUMPER_HILOGE(MODULE_COMMON, "datas are invalid, content: %{public}s", content.c_str());
132         return;
133     }
134     StringUtils::GetInstance().StringSplit(datas.at(0), "-", startAndEnd);
135     string startVal = startAndEnd.front();
136     string endVal = startAndEnd.back();
137     memMap_.insert(pair<string, string>("Start", startVal));
138     memMap_.insert(pair<string, string>("End", endVal));
139     memMap_.insert(pair<string, string>("Perm", datas.at(1)));
140 }
141 
SetLineToResult(GroupMap & result,const std::string & line)142 void ParseSmapsInfo::SetLineToResult(GroupMap &result, const std::string &line)
143 {
144     vector<string> datas;
145     StringUtils::GetInstance().StringSplit(line, " ", datas);
146     if (datas.size() < DATAS_MIN_LEN) {
147         DUMPER_HILOGE(MODULE_COMMON, "datas are invalid, line: %{public}s", line.c_str());
148         return;
149     }
150     result[memGroup_].insert(pair<string, uint64_t>("Perm", MemoryUtil::GetInstance().PermToInt(datas.at(1))));
151     result[memGroup_].insert(pair<string, uint64_t>("Counts", 1));
152     result[memGroup_].insert(pair<string, uint64_t>("Name", 0));
153 }
154 
ShowSmapsData(const MemoryFilter::MemoryType & memType,const int & pid,GroupMap & result,bool isShowSmapsInfo,vector<map<string,string>> & vectMap)155 bool ParseSmapsInfo::ShowSmapsData(const MemoryFilter::MemoryType &memType, const int &pid, GroupMap &result,
156     bool isShowSmapsInfo, vector<map<string, string>> &vectMap)
157 {
158     string path = "/proc/" + to_string(pid) + "/smaps";
159     bool ret = FileUtils::GetInstance().LoadStringFromProcCb(path, false, true, [&](const string& line) -> void {
160         string name;
161         uint64_t iNode = 0;
162         if (StringUtils::GetInstance().IsEnd(line, "B")) {
163             string type;
164             uint64_t value = 0;
165             if (GetSmapsValue(memType, line, type, value)) {
166                 MemoryUtil::GetInstance().CalcGroup(memGroup_, type, value, result);
167                 memMap_.insert(pair<string, string>(type, to_string(value)));
168             }
169         } else if (MemoryUtil::GetInstance().IsNameLine(line, name, iNode)) {
170             memGroup_ = name;
171             if (!memMap_.empty()) {
172                 vectMap.push_back(memMap_);
173                 memMap_.clear();
174             }
175             if (result.find(memGroup_) != result.end()) {
176                 result[memGroup_]["Counts"]++;
177             } else {
178                 SetLineToResult(result, line);
179             }
180             if (isShowSmapsInfo) {
181                 SetMapByNameLine(memGroup_, line);
182             }
183         }
184     });
185     if (!memMap_.empty()) {
186         vectMap.push_back(memMap_);
187         memMap_.clear();
188     }
189     return ret;
190 }
191 } // namespace HiviewDFX
192 } // namespace OHOS
193