1 /* 2 * Copyright (c) 2021 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 #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 struct MemUsageInfo { 34 uint64_t vss; 35 uint64_t rss; 36 uint64_t pss; 37 uint64_t uss; 38 39 uint64_t swap; 40 uint64_t swapPss; 41 42 uint64_t privateClean; 43 uint64_t privateDirty; 44 uint64_t sharedClean; 45 uint64_t sharedDirty; 46 }; 47 48 class StatsInfo { 49 public: 50 int pss_; 51 int swappablePss_; 52 int rss_; 53 int privateDirty_; 54 int sharedDirty_; 55 int privateClean_; 56 int sharedClean_; 57 int swappedOut_; 58 int swappedOutPss_; 59 StatsInfo()60 StatsInfo() 61 : pss_(0), 62 swappablePss_(0), 63 rss_(0), 64 privateDirty_(0), 65 sharedDirty_(0), 66 privateClean_(0), 67 sharedClean_(0), 68 swappedOut_(0), 69 swappedOutPss_(0) 70 { 71 } 72 StatsInfo(uint64_t swapablePss,const MemUsageInfo & usage)73 StatsInfo(uint64_t swapablePss, const MemUsageInfo& usage) 74 : pss_(usage.pss), 75 swappablePss_(swapablePss), 76 rss_(usage.rss), 77 privateDirty_(usage.privateDirty), 78 sharedDirty_(usage.sharedDirty), 79 privateClean_(usage.privateClean), 80 sharedClean_(usage.sharedClean), 81 swappedOut_(usage.swap), 82 swappedOutPss_(usage.swapPss) 83 { 84 } ~StatsInfo()85 ~StatsInfo() {} 86 87 void operator+=(const StatsInfo &S) 88 { 89 pss_ += S.pss_; 90 swappablePss_ += S.swappablePss_; 91 rss_ += S.rss_; 92 privateDirty_ += S.privateDirty_; 93 sharedDirty_ += S.sharedDirty_; 94 privateClean_ += S.privateClean_; 95 sharedClean_ += S.sharedClean_; 96 swappedOut_ += S.swappedOut_; 97 swappedOutPss_ += S.swappedOutPss_; 98 } 99 }; 100 101 enum NumType { 102 FIFTH_FIELD = 5, 103 HEX_BASE = 16, 104 DEC_BASE = 10, 105 }; 106 107 struct MapPiecesInfo { 108 uint64_t startAddr; 109 uint64_t endAddr; 110 111 std::string name; 112 }; 113 114 struct SmapsHeadInfo { 115 std::string startAddrStr; 116 std::string endAddrStr; 117 std::string permission; 118 std::string path; 119 int64_t iNode = -1; 120 }; 121 122 enum VmemifoType { 123 VMHEAP_NULL = -2, 124 VMHEAP_NEEDFIX = -1, 125 VMHEAP_UNKNOWN, 126 VMHEAP_SENSITIVE_VM, 127 VMHEAP_NATIVE, 128 129 VMHEAP_SENSITIVE_VM_OTHER, 130 VMHEAP_STACK, 131 VMHEAP_CURSOR, 132 VMHEAP_ASHMEM, 133 VMHEAP_GL_DEV, 134 VMHEAP_UNKNOWN_DEV, 135 VMHEAP_SO, 136 VMHEAP_JAR, 137 VMHEAP_TTF, 138 VMHEAP_SENSITIVE_JVBIN, 139 VMHEAP_OAT, 140 VMHEAP_HRT, 141 VMHEAP_UNKNOWN_MAP, 142 VMHEAP_GRAPHICS, 143 VMHEAP_GL, 144 VMHEAP_OTHER_MEMTRACK, 145 146 // extra sections (heap). 147 VMHEAP_SENSITIVE_VM_NORMAL, 148 VMHEAP_SENSITIVE_VM_LARGE, 149 VMHEAP_SENSITIVE_VM_ZYGOTE, 150 VMHEAP_SENSITIVE_VM_NON_MOVING, 151 152 // other extra sections. 153 VMHEAP_SENSITIVE_VM_OTHER_LINEARALLOC, 154 VMHEAP_SENSITIVE_VM_OTHER_ACCOUNTING, 155 VMHEAP_SENSITIVE_VM_OTHER_ZYGOTE_CODE_CACHE, 156 VMHEAP_SENSITIVE_VM_OTHER_APP_CODE_CACHE, 157 VMHEAP_SENSITIVE_VM_OTHER_COMPILER_METADATA, 158 VMHEAP_SENSITIVE_VM_OTHER_INDIRECT_REFERENCE_TABLE, 159 160 VMHEAP_SENSITIVE_JVBIN_BOOT_VDEX, 161 VMHEAP_SENSITIVE_JVBIN_APP_SENSITIVE_JVBIN, 162 VMHEAP_SENSITIVE_JVBIN_APP_VDEX, 163 164 // App hrt, boot hrt. 165 VMHEAP_HRT_APP, 166 VMHEAP_HRT_BOOT, 167 168 VMHEAP_NUM_HEAP, 169 VMHEAP_NUM_EXCLUSIVE_HEAP = VMHEAP_OTHER_MEMTRACK + 1, 170 VMHEAP_NUM_CORE_HEAP = VMHEAP_NATIVE + 1 171 }; 172 173 enum OpsType { 174 OPS_START = 1, 175 OPS_END, 176 }; 177 178 struct VmeminfoAreaMapping { 179 int ops; 180 const char* heapstr; 181 int heapid[2]; 182 }; 183 184 constexpr VmeminfoAreaMapping g_vmaMemHeap[] = { 185 {OpsType::OPS_START, "[heap]", {VmemifoType::VMHEAP_NATIVE, VmemifoType::VMHEAP_NULL}}, 186 {OpsType::OPS_START, "[stack", {VmemifoType::VMHEAP_STACK, VmemifoType::VMHEAP_NULL}}, 187 }; 188 189 // [anon: 190 constexpr VmeminfoAreaMapping g_vmaMemAnon[] = { 191 {OpsType::OPS_START, "[anon:libc_malloc]", {VmemifoType::VMHEAP_NATIVE, VmemifoType::VMHEAP_NULL}}, 192 {OpsType::OPS_START, "[anon:native_heap:", {VmemifoType::VMHEAP_NATIVE, VmemifoType::VMHEAP_NULL}}, 193 {OpsType::OPS_START, "[anon:scudo:", {VmemifoType::VMHEAP_NATIVE, VmemifoType::VMHEAP_NULL}}, 194 {OpsType::OPS_START, "[anon:GWP-ASan", {VmemifoType::VMHEAP_NATIVE, VmemifoType::VMHEAP_NULL}}, 195 {OpsType::OPS_START, "[anon:stack_and_tls:", {VmemifoType::VMHEAP_STACK, VmemifoType::VMHEAP_NULL}}, 196 {OpsType::OPS_START, 197 "[anon:sensitive_vm-LinearAlloc", 198 {VmemifoType::VMHEAP_SENSITIVE_VM_OTHER, VmemifoType::VMHEAP_SENSITIVE_VM_OTHER_LINEARALLOC}}, 199 {OpsType::OPS_START, 200 "[anon:sensitive_vm-alloc space", {VmemifoType::VMHEAP_SENSITIVE_VM, VmemifoType::VMHEAP_SENSITIVE_VM_NORMAL}}, 201 {OpsType::OPS_START, 202 "[anon:sensitive_vm-main space", {VmemifoType::VMHEAP_SENSITIVE_VM, VmemifoType::VMHEAP_SENSITIVE_VM_NORMAL}}, 203 {OpsType::OPS_START, 204 "[anon:sensitive_vm-large object space", 205 {VmemifoType::VMHEAP_SENSITIVE_VM, VmemifoType::VMHEAP_SENSITIVE_VM_LARGE}}, 206 {OpsType::OPS_START, 207 "[anon:sensitive_vm-free list large object space", 208 {VmemifoType::VMHEAP_SENSITIVE_VM, VmemifoType::VMHEAP_SENSITIVE_VM_LARGE}}, 209 {OpsType::OPS_START, 210 "[anon:sensitive_vm-non moving space", 211 {VmemifoType::VMHEAP_SENSITIVE_VM, VmemifoType::VMHEAP_SENSITIVE_VM_NON_MOVING}}, 212 {OpsType::OPS_START, 213 "[anon:sensitive_vm-zygote space", {VmemifoType::VMHEAP_SENSITIVE_VM, VmemifoType::VMHEAP_SENSITIVE_VM_ZYGOTE}}, 214 {OpsType::OPS_START, 215 "[anon:sensitive_vm-indirect ref", 216 {VmemifoType::VMHEAP_SENSITIVE_VM_OTHER, VmemifoType::VMHEAP_SENSITIVE_VM_OTHER_INDIRECT_REFERENCE_TABLE}}, 217 {OpsType::OPS_START, 218 "[anon:sensitive_vm-jit-code-cache", 219 {VmemifoType::VMHEAP_SENSITIVE_VM_OTHER, VmemifoType::VMHEAP_SENSITIVE_VM_OTHER_APP_CODE_CACHE}}, 220 {OpsType::OPS_START, 221 "[anon:sensitive_vm-data-code-cache", 222 {VmemifoType::VMHEAP_SENSITIVE_VM_OTHER, VmemifoType::VMHEAP_SENSITIVE_VM_OTHER_APP_CODE_CACHE}}, 223 {OpsType::OPS_START, 224 "[anon:sensitive_vm-CompilerMetadata", 225 {VmemifoType::VMHEAP_SENSITIVE_VM_OTHER, VmemifoType::VMHEAP_SENSITIVE_VM_OTHER_COMPILER_METADATA}}, 226 {OpsType::OPS_START, 227 "[anon:sensitive_vm-", 228 {VmemifoType::VMHEAP_SENSITIVE_VM_OTHER, VmemifoType::VMHEAP_SENSITIVE_VM_OTHER_ACCOUNTING}}, 229 {OpsType::OPS_START, "[anon:", {VmemifoType::VMHEAP_UNKNOWN, VmemifoType::VMHEAP_NULL}}, 230 }; 231 232 constexpr VmeminfoAreaMapping g_vmaMemFd[] = { 233 {OpsType::OPS_START, 234 "/memfd:jit-cache", 235 {VmemifoType::VMHEAP_SENSITIVE_VM_OTHER, VmemifoType::VMHEAP_SENSITIVE_VM_OTHER_APP_CODE_CACHE}}, 236 {OpsType::OPS_START, 237 "/memfd:jit-zygote-cache", 238 {VmemifoType::VMHEAP_SENSITIVE_VM_OTHER, VmemifoType::VMHEAP_SENSITIVE_VM_OTHER_ZYGOTE_CODE_CACHE}}, 239 }; 240 // dev 241 constexpr VmeminfoAreaMapping g_vmaMemDev[] = { 242 {OpsType::OPS_START, "/dev/kgsl-3d0", {VmemifoType::VMHEAP_GL_DEV, VmemifoType::VMHEAP_NULL}}, 243 {OpsType::OPS_START, "/dev/ashmem/CursorWindow", {VmemifoType::VMHEAP_CURSOR, VmemifoType::VMHEAP_NULL}}, 244 {OpsType::OPS_START, 245 "/dev/ashmem/jit-zygote-cache", 246 {VmemifoType::VMHEAP_SENSITIVE_VM_OTHER, VmemifoType::VMHEAP_SENSITIVE_VM_OTHER_ZYGOTE_CODE_CACHE}}, 247 {OpsType::OPS_START, "/dev/ashmem", {VmemifoType::VMHEAP_ASHMEM, VmemifoType::VMHEAP_NULL}}, 248 {OpsType::OPS_START, "/dev/", {VmemifoType::VMHEAP_UNKNOWN_DEV, VmemifoType::VMHEAP_NULL}}, 249 }; 250 251 constexpr VmeminfoAreaMapping g_vmaMemSuffix[] = { 252 {OpsType::OPS_END, ".so", {VmemifoType::VMHEAP_SO, VmemifoType::VMHEAP_NULL}}, 253 {OpsType::OPS_END, ".so.1", {VmemifoType::VMHEAP_SO, VmemifoType::VMHEAP_NULL}}, 254 {OpsType::OPS_END, ".jar", {VmemifoType::VMHEAP_JAR, VmemifoType::VMHEAP_NULL}}, 255 {OpsType::OPS_END, ".ttf", {VmemifoType::VMHEAP_TTF, VmemifoType::VMHEAP_NULL}}, 256 {OpsType::OPS_END, ".oat", {VmemifoType::VMHEAP_OAT, VmemifoType::VMHEAP_NULL}}, 257 258 {OpsType::OPS_END, 259 ".odex", {VmemifoType::VMHEAP_SENSITIVE_JVBIN, VmemifoType::VMHEAP_SENSITIVE_JVBIN_APP_SENSITIVE_JVBIN}}, 260 261 {OpsType::OPS_END, ".vdex", {VmemifoType::VMHEAP_SENSITIVE_JVBIN, VmemifoType::VMHEAP_NEEDFIX}}, 262 {OpsType::OPS_END, ".hrt", {VmemifoType::VMHEAP_HRT, VmemifoType::VMHEAP_NEEDFIX}}, 263 {OpsType::OPS_END, ".hrt]", {VmemifoType::VMHEAP_HRT, VmemifoType::VMHEAP_NEEDFIX}}, 264 }; 265 266 class SmapsStats { 267 public: SmapsStats()268 SmapsStats() {} SmapsStats(const std::string path)269 SmapsStats(const std::string path) : testpath_(path){}; ~SmapsStats()270 ~SmapsStats() {} 271 272 using MatchFunc = std::function<bool(const std::string& name, const char* str)>; 273 274 bool ParseMaps(int pid, ProcessMemoryInfo& processinfo, bool isReportApp, bool isReportSmaps); 275 int GetProcessJavaHeap(); 276 int GetProcessNativeHeap(); 277 int GetProcessCode(); 278 int GetProcessStack(); 279 int GetProcessGraphics(); 280 int GetProcessPrivateOther(); 281 int GetProcessSystem(); 282 private: 283 std::array<StatsInfo, VMHEAP_NUM_HEAP> stats_; 284 bool lastline_ = false; 285 std::string testpath_; 286 287 int GetTotalPrivateClean(); 288 int GetTotalPrivateDirty(); 289 int GetPrivate(int type); 290 int GetTotalPss(); 291 int GetTotalSwappedOutPss(); 292 void ReviseStatsData(); 293 294 bool ReadVmemareasFile(const std::string& path, ProcessMemoryInfo& processinfo, bool isReportApp, 295 bool isReportSmaps); 296 bool ParseMapHead(std::string& line, MapPiecesInfo& head, SmapsHeadInfo& smapsHeadInfo); 297 bool SetMapAddrInfo(std::string& line, MapPiecesInfo& head); 298 bool GetMemUsageField(std::string& line, MemUsageInfo& memusage); 299 void CollectVmemAreasData(const MapPiecesInfo& mempic, 300 const MemUsageInfo& memusage, 301 uint64_t& prevEnd, 302 int& prevHeap); 303 bool GetVmaIndex(std::string name, uint32_t namesz, int32_t heapIndex[2], bool& swappable); 304 uint64_t GetSwapablepssValue(const MemUsageInfo& memusage, bool swappable); 305 void SetVmemAreasData(int index, uint64_t swapablePss, const MemUsageInfo& usage); 306 void HeapIndexFix(std::string name, const char* key, int32_t heapIndex[2]); 307 bool GetVMAStuId(int ops, 308 std::string name, 309 const VmeminfoAreaMapping vma[], 310 int count, 311 int32_t heapIndex[2], 312 bool& swappable); 313 std::string ParseCategory(const SmapsHeadInfo& smapsHeadInfo); 314 bool GetCategoryFromMap(const std::string &name, std::string &group, 315 const std::map<std::string, std::string> &map, MatchFunc func); 316 const std::map<std::string, std::string> beginMap_ = { 317 {"[heap]", "native heap"}, {"[stack]", "stack"}, {"[anon:stack", "stack"}, 318 {"[anon:native_heap:", "native heap"}, {"[anon:ArkTS Heap]", "ark ts heap"}, 319 {"[anon:guard", "guard"}, {"/dev", "dev"}, {"[anon:signal_stack", "stack"}, 320 {"/dmabuf", "dmabuf"}, {"/data/storage", ".hap"}, {"[anon:libc_malloc", "native heap"}, 321 {"[anon:scudo", "native heap"}, {"[anon:GWP-ASan", "native heap"}, 322 }; 323 const std::map<std::string, std::string> endMap_ = { 324 {".so", ".so"}, {".so.1", ".so"}, {".ttf", ".ttf"}, 325 {".db", ".db"}, {".db-shm", ".db"}, 326 }; 327 const std::string FILE_PAGE_TAG = "FilePage other"; 328 const std::string ANON_PAGE_TAG = "AnonPage other"; 329 }; 330 331 #endif