• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
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 #ifndef SMAPS_STATS_H
17 #define SMAPS_STATS_H
18 
19 #include <array>
20 #include <cinttypes>
21 #include <cstdio>
22 #include <fstream>
23 #include <inttypes.h>
24 #include <iostream>
25 #include <map>
26 #include <memory>
27 #include <string>
28 #include <sys/mman.h>
29 
30 #include "logging.h"
31 #include "memory_plugin_result.pb.h"
32 
33 constexpr int PERCENT = 100;
34 
35 struct MemUsageInfo {
36     uint64_t vss;
37     uint64_t rss;
38     uint64_t pss;
39     uint64_t uss;
40 
41     uint64_t swap;
42     uint64_t swapPss;
43 
44     uint64_t privateClean;
45     uint64_t privateDirty;
46     uint64_t sharedClean;
47     uint64_t sharedDirty;
48 };
49 
50 class StatsInfo {
51 public:
52     int pss_;
53     int swappablePss_;
54     int rss_;
55     int privateDirty_;
56     int sharedDirty_;
57     int privateClean_;
58     int sharedClean_;
59     int swappedOut_;
60     int swappedOutPss_;
61 
StatsInfo()62     StatsInfo()
63         : pss_(0),
64         swappablePss_(0),
65         rss_(0),
66         privateDirty_(0),
67         sharedDirty_(0),
68         privateClean_(0),
69         sharedClean_(0),
70         swappedOut_(0),
71         swappedOutPss_(0)
72     {
73     }
74 
StatsInfo(uint64_t swapablePss,const MemUsageInfo & usage)75     StatsInfo(uint64_t swapablePss, const MemUsageInfo& usage)
76         : pss_(usage.pss),
77         swappablePss_(swapablePss),
78         rss_(usage.rss),
79         privateDirty_(usage.privateDirty),
80         sharedDirty_(usage.sharedDirty),
81         privateClean_(usage.privateClean),
82         sharedClean_(usage.sharedClean),
83         swappedOut_(usage.swap),
84         swappedOutPss_(usage.swapPss)
85     {
86     }
~StatsInfo()87     ~StatsInfo() {}
88 
89     void operator+=(const StatsInfo &S)
90     {
91         pss_ += S.pss_;
92         swappablePss_ += S.swappablePss_;
93         rss_ += S.rss_;
94         privateDirty_ += S.privateDirty_;
95         sharedDirty_ += S.sharedDirty_;
96         privateClean_ += S.privateClean_;
97         sharedClean_ += S.sharedClean_;
98         swappedOut_ += S.swappedOut_;
99         swappedOutPss_ += S.swappedOutPss_;
100     }
101 };
102 
103 enum NumType {
104     FIFTH_FIELD = 5,
105     HEX_BASE = 16,
106     DEC_BASE = 10,
107 };
108 
109 struct MapPiecesInfo {
110     uint64_t startAddr;
111     uint64_t endAddr;
112 
113     std::string name;
114 };
115 
116 struct SmapsHeadInfo {
117     std::string startAddrStr;
118     std::string endAddrStr;
119     std::string permission;
120     std::string path;
121     int64_t iNode = -1;
122 };
123 
124 enum VmemifoType {
125     VMHEAP_NULL = -2,
126     VMHEAP_NEEDFIX = -1,
127     VMHEAP_UNKNOWN,
128     VMHEAP_SENSITIVE_VM,
129     VMHEAP_NATIVE,
130 
131     VMHEAP_SENSITIVE_VM_OTHER,
132     VMHEAP_STACK,
133     VMHEAP_CURSOR,
134     VMHEAP_ASHMEM,
135     VMHEAP_GL_DEV,
136     VMHEAP_UNKNOWN_DEV,
137     VMHEAP_SO,
138     VMHEAP_JAR,
139     VMHEAP_TTF,
140     VMHEAP_SENSITIVE_JVBIN,
141     VMHEAP_OAT,
142     VMHEAP_HRT,
143     VMHEAP_UNKNOWN_MAP,
144     VMHEAP_GRAPHICS,
145     VMHEAP_GL,
146     VMHEAP_OTHER_MEMTRACK,
147 
148     // extra sections (heap).
149     VMHEAP_SENSITIVE_VM_NORMAL,
150     VMHEAP_SENSITIVE_VM_LARGE,
151     VMHEAP_SENSITIVE_VM_ZYGOTE,
152     VMHEAP_SENSITIVE_VM_NON_MOVING,
153 
154     // other extra sections.
155     VMHEAP_SENSITIVE_VM_OTHER_LINEARALLOC,
156     VMHEAP_SENSITIVE_VM_OTHER_ACCOUNTING,
157     VMHEAP_SENSITIVE_VM_OTHER_ZYGOTE_CODE_CACHE,
158     VMHEAP_SENSITIVE_VM_OTHER_APP_CODE_CACHE,
159     VMHEAP_SENSITIVE_VM_OTHER_COMPILER_METADATA,
160     VMHEAP_SENSITIVE_VM_OTHER_INDIRECT_REFERENCE_TABLE,
161 
162     VMHEAP_SENSITIVE_JVBIN_BOOT_VDEX,
163     VMHEAP_SENSITIVE_JVBIN_APP_SENSITIVE_JVBIN,
164     VMHEAP_SENSITIVE_JVBIN_APP_VDEX,
165 
166     // App hrt, boot hrt.
167     VMHEAP_HRT_APP,
168     VMHEAP_HRT_BOOT,
169 
170     VMHEAP_NUM_HEAP,
171     VMHEAP_NUM_EXCLUSIVE_HEAP = VMHEAP_OTHER_MEMTRACK + 1,
172     VMHEAP_NUM_CORE_HEAP = VMHEAP_NATIVE + 1
173 };
174 
175 enum OpsType {
176     OPS_START = 1,
177     OPS_END,
178 };
179 
180 struct VmeminfoAreaMapping {
181     int ops;
182     const char* heapstr;
183     int heapid[2];
184 };
185 
186 constexpr VmeminfoAreaMapping g_vmaMemHeap[] = {
187     {OpsType::OPS_START, "[heap]", {VmemifoType::VMHEAP_NATIVE, VmemifoType::VMHEAP_NULL}},
188     {OpsType::OPS_START, "[stack", {VmemifoType::VMHEAP_STACK, VmemifoType::VMHEAP_NULL}},
189 };
190 
191 // [anon:
192 constexpr VmeminfoAreaMapping g_vmaMemAnon[] = {
193     {OpsType::OPS_START, "[anon:libc_malloc]", {VmemifoType::VMHEAP_NATIVE, VmemifoType::VMHEAP_NULL}},
194     {OpsType::OPS_START, "[anon:native_heap:", {VmemifoType::VMHEAP_NATIVE, VmemifoType::VMHEAP_NULL}},
195     {OpsType::OPS_START, "[anon:scudo:", {VmemifoType::VMHEAP_NATIVE, VmemifoType::VMHEAP_NULL}},
196     {OpsType::OPS_START, "[anon:GWP-ASan", {VmemifoType::VMHEAP_NATIVE, VmemifoType::VMHEAP_NULL}},
197     {OpsType::OPS_START, "[anon:stack_and_tls:", {VmemifoType::VMHEAP_STACK, VmemifoType::VMHEAP_NULL}},
198     {OpsType::OPS_START,
199      "[anon:sensitive_vm-LinearAlloc",
200      {VmemifoType::VMHEAP_SENSITIVE_VM_OTHER, VmemifoType::VMHEAP_SENSITIVE_VM_OTHER_LINEARALLOC}},
201     {OpsType::OPS_START,
202      "[anon:sensitive_vm-alloc space", {VmemifoType::VMHEAP_SENSITIVE_VM, VmemifoType::VMHEAP_SENSITIVE_VM_NORMAL}},
203     {OpsType::OPS_START,
204      "[anon:sensitive_vm-main space", {VmemifoType::VMHEAP_SENSITIVE_VM, VmemifoType::VMHEAP_SENSITIVE_VM_NORMAL}},
205     {OpsType::OPS_START,
206      "[anon:sensitive_vm-large object space",
207      {VmemifoType::VMHEAP_SENSITIVE_VM, VmemifoType::VMHEAP_SENSITIVE_VM_LARGE}},
208     {OpsType::OPS_START,
209      "[anon:sensitive_vm-free list large object space",
210      {VmemifoType::VMHEAP_SENSITIVE_VM, VmemifoType::VMHEAP_SENSITIVE_VM_LARGE}},
211     {OpsType::OPS_START,
212      "[anon:sensitive_vm-non moving space",
213      {VmemifoType::VMHEAP_SENSITIVE_VM, VmemifoType::VMHEAP_SENSITIVE_VM_NON_MOVING}},
214     {OpsType::OPS_START,
215      "[anon:sensitive_vm-zygote space", {VmemifoType::VMHEAP_SENSITIVE_VM, VmemifoType::VMHEAP_SENSITIVE_VM_ZYGOTE}},
216     {OpsType::OPS_START,
217      "[anon:sensitive_vm-indirect ref",
218      {VmemifoType::VMHEAP_SENSITIVE_VM_OTHER, VmemifoType::VMHEAP_SENSITIVE_VM_OTHER_INDIRECT_REFERENCE_TABLE}},
219     {OpsType::OPS_START,
220      "[anon:sensitive_vm-jit-code-cache",
221      {VmemifoType::VMHEAP_SENSITIVE_VM_OTHER, VmemifoType::VMHEAP_SENSITIVE_VM_OTHER_APP_CODE_CACHE}},
222     {OpsType::OPS_START,
223      "[anon:sensitive_vm-data-code-cache",
224      {VmemifoType::VMHEAP_SENSITIVE_VM_OTHER, VmemifoType::VMHEAP_SENSITIVE_VM_OTHER_APP_CODE_CACHE}},
225     {OpsType::OPS_START,
226      "[anon:sensitive_vm-CompilerMetadata",
227      {VmemifoType::VMHEAP_SENSITIVE_VM_OTHER, VmemifoType::VMHEAP_SENSITIVE_VM_OTHER_COMPILER_METADATA}},
228     {OpsType::OPS_START,
229      "[anon:sensitive_vm-",
230      {VmemifoType::VMHEAP_SENSITIVE_VM_OTHER, VmemifoType::VMHEAP_SENSITIVE_VM_OTHER_ACCOUNTING}},
231     {OpsType::OPS_START, "[anon:", {VmemifoType::VMHEAP_UNKNOWN, VmemifoType::VMHEAP_NULL}},
232 };
233 
234 constexpr VmeminfoAreaMapping g_vmaMemFd[] = {
235     {OpsType::OPS_START,
236      "/memfd:jit-cache",
237      {VmemifoType::VMHEAP_SENSITIVE_VM_OTHER, VmemifoType::VMHEAP_SENSITIVE_VM_OTHER_APP_CODE_CACHE}},
238     {OpsType::OPS_START,
239      "/memfd:jit-zygote-cache",
240      {VmemifoType::VMHEAP_SENSITIVE_VM_OTHER, VmemifoType::VMHEAP_SENSITIVE_VM_OTHER_ZYGOTE_CODE_CACHE}},
241 };
242 // dev
243 constexpr VmeminfoAreaMapping g_vmaMemDev[] = {
244     {OpsType::OPS_START, "/dev/kgsl-3d0", {VmemifoType::VMHEAP_GL_DEV, VmemifoType::VMHEAP_NULL}},
245     {OpsType::OPS_START, "/dev/ashmem/CursorWindow", {VmemifoType::VMHEAP_CURSOR, VmemifoType::VMHEAP_NULL}},
246     {OpsType::OPS_START,
247      "/dev/ashmem/jit-zygote-cache",
248      {VmemifoType::VMHEAP_SENSITIVE_VM_OTHER, VmemifoType::VMHEAP_SENSITIVE_VM_OTHER_ZYGOTE_CODE_CACHE}},
249     {OpsType::OPS_START, "/dev/ashmem", {VmemifoType::VMHEAP_ASHMEM, VmemifoType::VMHEAP_NULL}},
250     {OpsType::OPS_START, "/dev/", {VmemifoType::VMHEAP_UNKNOWN_DEV, VmemifoType::VMHEAP_NULL}},
251 };
252 
253 constexpr VmeminfoAreaMapping g_vmaMemSuffix[] = {
254     {OpsType::OPS_END, ".so", {VmemifoType::VMHEAP_SO, VmemifoType::VMHEAP_NULL}},
255     {OpsType::OPS_END, ".so.1", {VmemifoType::VMHEAP_SO, VmemifoType::VMHEAP_NULL}},
256     {OpsType::OPS_END, ".jar", {VmemifoType::VMHEAP_JAR, VmemifoType::VMHEAP_NULL}},
257     {OpsType::OPS_END, ".ttf", {VmemifoType::VMHEAP_TTF, VmemifoType::VMHEAP_NULL}},
258     {OpsType::OPS_END, ".oat", {VmemifoType::VMHEAP_OAT, VmemifoType::VMHEAP_NULL}},
259 
260     {OpsType::OPS_END,
261      ".odex", {VmemifoType::VMHEAP_SENSITIVE_JVBIN, VmemifoType::VMHEAP_SENSITIVE_JVBIN_APP_SENSITIVE_JVBIN}},
262 
263     {OpsType::OPS_END, ".vdex", {VmemifoType::VMHEAP_SENSITIVE_JVBIN, VmemifoType::VMHEAP_NEEDFIX}},
264     {OpsType::OPS_END, ".hrt", {VmemifoType::VMHEAP_HRT, VmemifoType::VMHEAP_NEEDFIX}},
265     {OpsType::OPS_END, ".hrt]", {VmemifoType::VMHEAP_HRT, VmemifoType::VMHEAP_NEEDFIX}},
266 };
267 
268 class SmapsStats {
269 public:
SmapsStats()270     SmapsStats() {}
SmapsStats(const std::string path)271     SmapsStats(const std::string path) : testpath_(path){};
~SmapsStats()272     ~SmapsStats() {}
273 
274     template <typename T, typename S>
ParseMaps(int pid,T & processMemoryInfo,S smapsInfo,bool isReportApp,bool isReportSmaps)275     bool ParseMaps(int pid, T& processMemoryInfo, S smapsInfo, bool isReportApp, bool isReportSmaps)
276     {
277         std::string smaps_path = std::string("/proc/") + std::to_string(pid) + std::string("/smaps");
278         if (testpath_.size() > 0) {
279             smaps_path = testpath_ + std::to_string(pid) + std::string("/smaps");
280         }
281         ReadVmemareasFile(smaps_path, processMemoryInfo, smapsInfo, isReportApp, isReportSmaps);
282         if (isReportApp) {
283             ReviseStatsData();
284         }
285         return true;
286     }
287 
288     using MatchFunc = std::function<bool(const std::string& name, const char* str)>;
289 
290     int GetProcessJavaHeap();
291     int GetProcessNativeHeap();
292     int GetProcessCode();
293     int GetProcessStack();
294     int GetProcessGraphics();
295     int GetProcessPrivateOther();
296     int GetProcessSystem();
297 private:
298     std::array<StatsInfo, VMHEAP_NUM_HEAP> stats_;
299     bool lastline_ = false;
300     std::string testpath_;
301 
302     int GetTotalPrivateClean();
303     int GetTotalPrivateDirty();
304     int GetPrivate(int type);
305     int GetTotalPss();
306     int GetTotalSwappedOutPss();
307     void ReviseStatsData();
308 
309     template <typename T, typename S>
ReadVmemareasFile(const std::string & path,T & processMemoryInfo,S smapsInfo,bool isReportApp,bool isReportSmaps)310     bool ReadVmemareasFile(const std::string& path, T& processMemoryInfo, S smapsInfo,
311                            bool isReportApp, bool isReportSmaps)
312     {
313         bool findMapHead = false;
314         MapPiecesInfo mappic = {0};
315         MemUsageInfo memusage = {0};
316         SmapsHeadInfo smapsHeadInfo = {};
317         uint64_t prevEnd = 0;
318         int prevHeap = 0;
319         std::ifstream input(path, std::ios::in);
320         CHECK_TRUE(!input.fail(), false, "%s:open %s failed, errno = %d", __func__, path.c_str(), errno);
321         do {
322             if (!input.good()) {
323                 return false;
324             }
325             std::string line;
326             getline(input, line);
327             line += '\n';
328             if (!findMapHead) {
329                 // 00400000-00409000 r-xp 00000000 fc:00 426998  /usr/lib/gvfs/gvfsd-http
330                 ParseMapHead(line, mappic, smapsHeadInfo);
331                 findMapHead = true;
332                 if (isReportSmaps) {
333                     smapsInfo = processMemoryInfo.add_smapinfo();
334                     smapsInfo->set_start_addr(smapsHeadInfo.startAddrStr);
335                     smapsInfo->set_end_addr(smapsHeadInfo.endAddrStr);
336                     smapsInfo->set_permission(smapsHeadInfo.permission);
337                     smapsInfo->set_path(smapsHeadInfo.path);
338                     smapsInfo->set_category(ParseCategory(smapsHeadInfo));
339                 }
340                 continue;
341             }
342             if (findMapHead && GetMemUsageField(line, memusage)) {
343                 if (!lastline_) {
344                     continue;
345                 }
346                 if (isReportSmaps) {
347                     if (smapsInfo == nullptr) {
348                         smapsInfo = processMemoryInfo.add_smapinfo();
349                     }
350                     smapsInfo->set_size(memusage.vss);
351                     smapsInfo->set_rss(memusage.rss);
352                     smapsInfo->set_pss(memusage.pss);
353                     smapsInfo->set_dirty(memusage.privateDirty + memusage.sharedDirty);
354                     smapsInfo->set_swapper(memusage.swap + memusage.swapPss);
355                     smapsInfo->set_reside(static_cast<double>(memusage.rss) / memusage.vss * PERCENT);
356                     smapsInfo->set_private_clean(memusage.privateClean);
357                     smapsInfo->set_private_dirty(memusage.privateDirty);
358                     smapsInfo->set_shared_clean(memusage.sharedClean);
359                     smapsInfo->set_shared_dirty(memusage.sharedDirty);
360                     smapsInfo->set_swap(memusage.swap);
361                     smapsInfo->set_swap_pss(memusage.swapPss);
362                 }
363             }
364 
365             if (isReportApp) {
366                 CollectVmemAreasData(mappic, memusage, prevEnd, prevHeap);
367             }
368             findMapHead = false;
369             lastline_ = false;
370         } while (!input.eof());
371         input.close();
372 
373         return true;
374     }
375 
376     bool ParseMapHead(std::string& line, MapPiecesInfo& head, SmapsHeadInfo& smapsHeadInfo);
377     bool SetMapAddrInfo(std::string& line, MapPiecesInfo& head);
378     bool GetMemUsageField(std::string& line, MemUsageInfo& memusage);
379     void CollectVmemAreasData(const MapPiecesInfo& mempic,
380                               const MemUsageInfo& memusage,
381                               uint64_t& prevEnd,
382                               int& prevHeap);
383     bool GetVmaIndex(std::string name, uint32_t namesz, int32_t heapIndex[2], bool& swappable);
384     uint64_t GetSwapablepssValue(const MemUsageInfo& memusage, bool swappable);
385     void SetVmemAreasData(int index, uint64_t swapablePss, const MemUsageInfo& usage);
386     void HeapIndexFix(std::string name, const char* key, int32_t heapIndex[2]);
387     bool GetVMAStuId(int ops,
388                      std::string name,
389                      const VmeminfoAreaMapping vma[],
390                      int count,
391                      int32_t heapIndex[2],
392                      bool& swappable);
393     std::string ParseCategory(const SmapsHeadInfo& smapsHeadInfo);
394     bool GetCategoryFromMap(const std::string &name, std::string &group,
395                             const std::map<std::string, std::string> &map, MatchFunc func);
396     const std::map<std::string, std::string> beginMap_ = {
397         {"[heap]", "native heap"}, {"[stack]", "stack"}, {"[anon:stack", "stack"},
398         {"[anon:native_heap:", "native heap"}, {"[anon:ArkTS Heap", "ark ts heap"},
399         {"[anon:guard", "guard"}, {"/dev", "dev"}, {"[anon:signal_stack", "stack"},
400         {"/dmabuf", "dmabuf"}, {"/data/storage", ".hap"}, {"[anon:libc_malloc", "native heap"},
401         {"[anon:scudo", "native heap"}, {"[anon:GWP-ASan", "native heap"},
402     };
403     const std::map<std::string, std::string> endMap_ = {
404         {".so", ".so"}, {".so.1", ".so"}, {".ttf", ".ttf"},
405         {".db", ".db"}, {".db-shm", ".db"},
406     };
407     const std::string FILE_PAGE_TAG = "FilePage other";
408     const std::string ANON_PAGE_TAG = "AnonPage other";
409 };
410 
411 #endif