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