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