1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "android.os.Debug" 18 19 #include <assert.h> 20 #include <ctype.h> 21 #include <errno.h> 22 #include <fcntl.h> 23 #include <inttypes.h> 24 #include <malloc.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <sys/time.h> 29 #include <time.h> 30 #include <unistd.h> 31 32 #include <iomanip> 33 #include <string> 34 #include <vector> 35 36 #include <android-base/logging.h> 37 #include <bionic/malloc.h> 38 #include <debuggerd/client.h> 39 #include <log/log.h> 40 #include <utils/misc.h> 41 #include <utils/String8.h> 42 43 #include <nativehelper/JNIPlatformHelp.h> 44 #include <nativehelper/ScopedUtfChars.h> 45 #include "jni.h" 46 #include <dmabufinfo/dmabuf_sysfs_stats.h> 47 #include <dmabufinfo/dmabufinfo.h> 48 #include <meminfo/procmeminfo.h> 49 #include <meminfo/sysmeminfo.h> 50 #include <memtrack/memtrack.h> 51 #include <memunreachable/memunreachable.h> 52 #include <android-base/strings.h> 53 #include "android_os_Debug.h" 54 #include <vintf/VintfObject.h> 55 56 namespace android 57 { 58 59 enum { 60 HEAP_UNKNOWN, 61 HEAP_DALVIK, 62 HEAP_NATIVE, 63 64 HEAP_DALVIK_OTHER, 65 HEAP_STACK, 66 HEAP_CURSOR, 67 HEAP_ASHMEM, 68 HEAP_GL_DEV, 69 HEAP_UNKNOWN_DEV, 70 HEAP_SO, 71 HEAP_JAR, 72 HEAP_APK, 73 HEAP_TTF, 74 HEAP_DEX, 75 HEAP_OAT, 76 HEAP_ART, 77 HEAP_UNKNOWN_MAP, 78 HEAP_GRAPHICS, 79 HEAP_GL, 80 HEAP_OTHER_MEMTRACK, 81 82 // Dalvik extra sections (heap). 83 HEAP_DALVIK_NORMAL, 84 HEAP_DALVIK_LARGE, 85 HEAP_DALVIK_ZYGOTE, 86 HEAP_DALVIK_NON_MOVING, 87 88 // Dalvik other extra sections. 89 HEAP_DALVIK_OTHER_LINEARALLOC, 90 HEAP_DALVIK_OTHER_ACCOUNTING, 91 HEAP_DALVIK_OTHER_ZYGOTE_CODE_CACHE, 92 HEAP_DALVIK_OTHER_APP_CODE_CACHE, 93 HEAP_DALVIK_OTHER_COMPILER_METADATA, 94 HEAP_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE, 95 96 // Boot vdex / app dex / app vdex 97 HEAP_DEX_BOOT_VDEX, 98 HEAP_DEX_APP_DEX, 99 HEAP_DEX_APP_VDEX, 100 101 // App art, boot art. 102 HEAP_ART_APP, 103 HEAP_ART_BOOT, 104 105 _NUM_HEAP, 106 _NUM_EXCLUSIVE_HEAP = HEAP_OTHER_MEMTRACK+1, 107 _NUM_CORE_HEAP = HEAP_NATIVE+1 108 }; 109 110 struct stat_fields { 111 jfieldID pss_field; 112 jfieldID pssSwappable_field; 113 jfieldID rss_field; 114 jfieldID privateDirty_field; 115 jfieldID sharedDirty_field; 116 jfieldID privateClean_field; 117 jfieldID sharedClean_field; 118 jfieldID swappedOut_field; 119 jfieldID swappedOutPss_field; 120 }; 121 122 struct stat_field_names { 123 const char* pss_name; 124 const char* pssSwappable_name; 125 const char* rss_name; 126 const char* privateDirty_name; 127 const char* sharedDirty_name; 128 const char* privateClean_name; 129 const char* sharedClean_name; 130 const char* swappedOut_name; 131 const char* swappedOutPss_name; 132 }; 133 134 static stat_fields stat_fields[_NUM_CORE_HEAP]; 135 136 static stat_field_names stat_field_names[_NUM_CORE_HEAP] = { 137 { "otherPss", "otherSwappablePss", "otherRss", "otherPrivateDirty", "otherSharedDirty", 138 "otherPrivateClean", "otherSharedClean", "otherSwappedOut", "otherSwappedOutPss" }, 139 { "dalvikPss", "dalvikSwappablePss", "dalvikRss", "dalvikPrivateDirty", "dalvikSharedDirty", 140 "dalvikPrivateClean", "dalvikSharedClean", "dalvikSwappedOut", "dalvikSwappedOutPss" }, 141 { "nativePss", "nativeSwappablePss", "nativeRss", "nativePrivateDirty", "nativeSharedDirty", 142 "nativePrivateClean", "nativeSharedClean", "nativeSwappedOut", "nativeSwappedOutPss" } 143 }; 144 145 static jfieldID otherStats_field; 146 static jfieldID hasSwappedOutPss_field; 147 148 struct stats_t { 149 int pss; 150 int swappablePss; 151 int rss; 152 int privateDirty; 153 int sharedDirty; 154 int privateClean; 155 int sharedClean; 156 int swappedOut; 157 int swappedOutPss; 158 }; 159 160 #define BINDER_STATS "/proc/binder/stats" 161 162 static jlong android_os_Debug_getNativeHeapSize(JNIEnv *env, jobject clazz) 163 { 164 struct mallinfo info = mallinfo(); 165 return (jlong) info.usmblks; 166 } 167 168 static jlong android_os_Debug_getNativeHeapAllocatedSize(JNIEnv *env, jobject clazz) 169 { 170 struct mallinfo info = mallinfo(); 171 return (jlong) info.uordblks; 172 } 173 174 static jlong android_os_Debug_getNativeHeapFreeSize(JNIEnv *env, jobject clazz) 175 { 176 struct mallinfo info = mallinfo(); 177 return (jlong) info.fordblks; 178 } 179 180 // Container used to retrieve graphics memory pss 181 struct graphics_memory_pss 182 { 183 int graphics; 184 int gl; 185 int other; 186 }; 187 188 /* 189 * Uses libmemtrack to retrieve graphics memory that the process is using. 190 * Any graphics memory reported in /proc/pid/smaps is not included here. 191 */ 192 static int read_memtrack_memory(struct memtrack_proc* p, int pid, 193 struct graphics_memory_pss* graphics_mem) 194 { 195 int err = memtrack_proc_get(p, pid); 196 if (err != 0) { 197 // The memtrack HAL may not be available, do not log to avoid flooding 198 // logcat. 199 return err; 200 } 201 202 ssize_t pss = memtrack_proc_graphics_pss(p); 203 if (pss < 0) { 204 ALOGW("failed to get graphics pss: %zd", pss); 205 return pss; 206 } 207 graphics_mem->graphics = pss / 1024; 208 209 pss = memtrack_proc_gl_pss(p); 210 if (pss < 0) { 211 ALOGW("failed to get gl pss: %zd", pss); 212 return pss; 213 } 214 graphics_mem->gl = pss / 1024; 215 216 pss = memtrack_proc_other_pss(p); 217 if (pss < 0) { 218 ALOGW("failed to get other pss: %zd", pss); 219 return pss; 220 } 221 graphics_mem->other = pss / 1024; 222 223 return 0; 224 } 225 226 /* 227 * Retrieves the graphics memory that is unaccounted for in /proc/pid/smaps. 228 */ 229 static int read_memtrack_memory(int pid, struct graphics_memory_pss* graphics_mem) 230 { 231 struct memtrack_proc* p = memtrack_proc_new(); 232 if (p == NULL) { 233 ALOGW("failed to create memtrack_proc"); 234 return -1; 235 } 236 237 int err = read_memtrack_memory(p, pid, graphics_mem); 238 memtrack_proc_destroy(p); 239 return err; 240 } 241 242 static bool load_maps(int pid, stats_t* stats, bool* foundSwapPss) 243 { 244 *foundSwapPss = false; 245 uint64_t prev_end = 0; 246 int prev_heap = HEAP_UNKNOWN; 247 248 std::string smaps_path = base::StringPrintf("/proc/%d/smaps", pid); 249 auto vma_scan = [&](const meminfo::Vma& vma) { 250 int which_heap = HEAP_UNKNOWN; 251 int sub_heap = HEAP_UNKNOWN; 252 bool is_swappable = false; 253 std::string name; 254 if (base::EndsWith(vma.name, " (deleted)")) { 255 name = vma.name.substr(0, vma.name.size() - strlen(" (deleted)")); 256 } else { 257 name = vma.name; 258 } 259 260 uint32_t namesz = name.size(); 261 if (base::StartsWith(name, "[heap]")) { 262 which_heap = HEAP_NATIVE; 263 } else if (base::StartsWith(name, "[anon:libc_malloc]")) { 264 which_heap = HEAP_NATIVE; 265 } else if (base::StartsWith(name, "[anon:scudo:")) { 266 which_heap = HEAP_NATIVE; 267 } else if (base::StartsWith(name, "[anon:GWP-ASan")) { 268 which_heap = HEAP_NATIVE; 269 } else if (base::StartsWith(name, "[stack")) { 270 which_heap = HEAP_STACK; 271 } else if (base::StartsWith(name, "[anon:stack_and_tls:")) { 272 which_heap = HEAP_STACK; 273 } else if (base::EndsWith(name, ".so")) { 274 which_heap = HEAP_SO; 275 is_swappable = true; 276 } else if (base::EndsWith(name, ".jar")) { 277 which_heap = HEAP_JAR; 278 is_swappable = true; 279 } else if (base::EndsWith(name, ".apk")) { 280 which_heap = HEAP_APK; 281 is_swappable = true; 282 } else if (base::EndsWith(name, ".ttf")) { 283 which_heap = HEAP_TTF; 284 is_swappable = true; 285 } else if ((base::EndsWith(name, ".odex")) || 286 (namesz > 4 && strstr(name.c_str(), ".dex") != nullptr)) { 287 which_heap = HEAP_DEX; 288 sub_heap = HEAP_DEX_APP_DEX; 289 is_swappable = true; 290 } else if (base::EndsWith(name, ".vdex")) { 291 which_heap = HEAP_DEX; 292 // Handle system@framework@boot and system/framework/boot|apex 293 if ((strstr(name.c_str(), "@boot") != nullptr) || 294 (strstr(name.c_str(), "/boot") != nullptr) || 295 (strstr(name.c_str(), "/apex") != nullptr)) { 296 sub_heap = HEAP_DEX_BOOT_VDEX; 297 } else { 298 sub_heap = HEAP_DEX_APP_VDEX; 299 } 300 is_swappable = true; 301 } else if (base::EndsWith(name, ".oat")) { 302 which_heap = HEAP_OAT; 303 is_swappable = true; 304 } else if (base::EndsWith(name, ".art") || base::EndsWith(name, ".art]")) { 305 which_heap = HEAP_ART; 306 // Handle system@framework@boot* and system/framework/boot|apex* 307 if ((strstr(name.c_str(), "@boot") != nullptr) || 308 (strstr(name.c_str(), "/boot") != nullptr) || 309 (strstr(name.c_str(), "/apex") != nullptr)) { 310 sub_heap = HEAP_ART_BOOT; 311 } else { 312 sub_heap = HEAP_ART_APP; 313 } 314 is_swappable = true; 315 } else if (base::StartsWith(name, "/dev/")) { 316 which_heap = HEAP_UNKNOWN_DEV; 317 if (base::StartsWith(name, "/dev/kgsl-3d0")) { 318 which_heap = HEAP_GL_DEV; 319 } else if (base::StartsWith(name, "/dev/ashmem/CursorWindow")) { 320 which_heap = HEAP_CURSOR; 321 } else if (base::StartsWith(name, "/dev/ashmem/jit-zygote-cache")) { 322 which_heap = HEAP_DALVIK_OTHER; 323 sub_heap = HEAP_DALVIK_OTHER_ZYGOTE_CODE_CACHE; 324 } else if (base::StartsWith(name, "/dev/ashmem")) { 325 which_heap = HEAP_ASHMEM; 326 } 327 } else if (base::StartsWith(name, "/memfd:jit-cache")) { 328 which_heap = HEAP_DALVIK_OTHER; 329 sub_heap = HEAP_DALVIK_OTHER_APP_CODE_CACHE; 330 } else if (base::StartsWith(name, "/memfd:jit-zygote-cache")) { 331 which_heap = HEAP_DALVIK_OTHER; 332 sub_heap = HEAP_DALVIK_OTHER_ZYGOTE_CODE_CACHE; 333 } else if (base::StartsWith(name, "[anon:")) { 334 which_heap = HEAP_UNKNOWN; 335 if (base::StartsWith(name, "[anon:dalvik-")) { 336 which_heap = HEAP_DALVIK_OTHER; 337 if (base::StartsWith(name, "[anon:dalvik-LinearAlloc")) { 338 sub_heap = HEAP_DALVIK_OTHER_LINEARALLOC; 339 } else if (base::StartsWith(name, "[anon:dalvik-alloc space") || 340 base::StartsWith(name, "[anon:dalvik-main space")) { 341 // This is the regular Dalvik heap. 342 which_heap = HEAP_DALVIK; 343 sub_heap = HEAP_DALVIK_NORMAL; 344 } else if (base::StartsWith(name, 345 "[anon:dalvik-large object space") || 346 base::StartsWith( 347 name, "[anon:dalvik-free list large object space")) { 348 which_heap = HEAP_DALVIK; 349 sub_heap = HEAP_DALVIK_LARGE; 350 } else if (base::StartsWith(name, "[anon:dalvik-non moving space")) { 351 which_heap = HEAP_DALVIK; 352 sub_heap = HEAP_DALVIK_NON_MOVING; 353 } else if (base::StartsWith(name, "[anon:dalvik-zygote space")) { 354 which_heap = HEAP_DALVIK; 355 sub_heap = HEAP_DALVIK_ZYGOTE; 356 } else if (base::StartsWith(name, "[anon:dalvik-indirect ref")) { 357 sub_heap = HEAP_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE; 358 } else if (base::StartsWith(name, "[anon:dalvik-jit-code-cache") || 359 base::StartsWith(name, "[anon:dalvik-data-code-cache")) { 360 sub_heap = HEAP_DALVIK_OTHER_APP_CODE_CACHE; 361 } else if (base::StartsWith(name, "[anon:dalvik-CompilerMetadata")) { 362 sub_heap = HEAP_DALVIK_OTHER_COMPILER_METADATA; 363 } else { 364 sub_heap = HEAP_DALVIK_OTHER_ACCOUNTING; // Default to accounting. 365 } 366 } 367 } else if (namesz > 0) { 368 which_heap = HEAP_UNKNOWN_MAP; 369 } else if (vma.start == prev_end && prev_heap == HEAP_SO) { 370 // bss section of a shared library 371 which_heap = HEAP_SO; 372 } 373 374 prev_end = vma.end; 375 prev_heap = which_heap; 376 377 const meminfo::MemUsage& usage = vma.usage; 378 if (usage.swap_pss > 0 && *foundSwapPss != true) { 379 *foundSwapPss = true; 380 } 381 382 uint64_t swapable_pss = 0; 383 if (is_swappable && (usage.pss > 0)) { 384 float sharing_proportion = 0.0; 385 if ((usage.shared_clean > 0) || (usage.shared_dirty > 0)) { 386 sharing_proportion = (usage.pss - usage.uss) / (usage.shared_clean + usage.shared_dirty); 387 } 388 swapable_pss = (sharing_proportion * usage.shared_clean) + usage.private_clean; 389 } 390 391 stats[which_heap].pss += usage.pss; 392 stats[which_heap].swappablePss += swapable_pss; 393 stats[which_heap].rss += usage.rss; 394 stats[which_heap].privateDirty += usage.private_dirty; 395 stats[which_heap].sharedDirty += usage.shared_dirty; 396 stats[which_heap].privateClean += usage.private_clean; 397 stats[which_heap].sharedClean += usage.shared_clean; 398 stats[which_heap].swappedOut += usage.swap; 399 stats[which_heap].swappedOutPss += usage.swap_pss; 400 if (which_heap == HEAP_DALVIK || which_heap == HEAP_DALVIK_OTHER || 401 which_heap == HEAP_DEX || which_heap == HEAP_ART) { 402 stats[sub_heap].pss += usage.pss; 403 stats[sub_heap].swappablePss += swapable_pss; 404 stats[sub_heap].rss += usage.rss; 405 stats[sub_heap].privateDirty += usage.private_dirty; 406 stats[sub_heap].sharedDirty += usage.shared_dirty; 407 stats[sub_heap].privateClean += usage.private_clean; 408 stats[sub_heap].sharedClean += usage.shared_clean; 409 stats[sub_heap].swappedOut += usage.swap; 410 stats[sub_heap].swappedOutPss += usage.swap_pss; 411 } 412 }; 413 414 return meminfo::ForEachVmaFromFile(smaps_path, vma_scan); 415 } 416 417 static jboolean android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz, 418 jint pid, jobject object) 419 { 420 bool foundSwapPss; 421 stats_t stats[_NUM_HEAP]; 422 memset(&stats, 0, sizeof(stats)); 423 424 if (!load_maps(pid, stats, &foundSwapPss)) { 425 return JNI_FALSE; 426 } 427 428 struct graphics_memory_pss graphics_mem; 429 if (read_memtrack_memory(pid, &graphics_mem) == 0) { 430 stats[HEAP_GRAPHICS].pss = graphics_mem.graphics; 431 stats[HEAP_GRAPHICS].privateDirty = graphics_mem.graphics; 432 stats[HEAP_GRAPHICS].rss = graphics_mem.graphics; 433 stats[HEAP_GL].pss = graphics_mem.gl; 434 stats[HEAP_GL].privateDirty = graphics_mem.gl; 435 stats[HEAP_GL].rss = graphics_mem.gl; 436 stats[HEAP_OTHER_MEMTRACK].pss = graphics_mem.other; 437 stats[HEAP_OTHER_MEMTRACK].privateDirty = graphics_mem.other; 438 stats[HEAP_OTHER_MEMTRACK].rss = graphics_mem.other; 439 } 440 441 for (int i=_NUM_CORE_HEAP; i<_NUM_EXCLUSIVE_HEAP; i++) { 442 stats[HEAP_UNKNOWN].pss += stats[i].pss; 443 stats[HEAP_UNKNOWN].swappablePss += stats[i].swappablePss; 444 stats[HEAP_UNKNOWN].rss += stats[i].rss; 445 stats[HEAP_UNKNOWN].privateDirty += stats[i].privateDirty; 446 stats[HEAP_UNKNOWN].sharedDirty += stats[i].sharedDirty; 447 stats[HEAP_UNKNOWN].privateClean += stats[i].privateClean; 448 stats[HEAP_UNKNOWN].sharedClean += stats[i].sharedClean; 449 stats[HEAP_UNKNOWN].swappedOut += stats[i].swappedOut; 450 stats[HEAP_UNKNOWN].swappedOutPss += stats[i].swappedOutPss; 451 } 452 453 for (int i=0; i<_NUM_CORE_HEAP; i++) { 454 env->SetIntField(object, stat_fields[i].pss_field, stats[i].pss); 455 env->SetIntField(object, stat_fields[i].pssSwappable_field, stats[i].swappablePss); 456 env->SetIntField(object, stat_fields[i].rss_field, stats[i].rss); 457 env->SetIntField(object, stat_fields[i].privateDirty_field, stats[i].privateDirty); 458 env->SetIntField(object, stat_fields[i].sharedDirty_field, stats[i].sharedDirty); 459 env->SetIntField(object, stat_fields[i].privateClean_field, stats[i].privateClean); 460 env->SetIntField(object, stat_fields[i].sharedClean_field, stats[i].sharedClean); 461 env->SetIntField(object, stat_fields[i].swappedOut_field, stats[i].swappedOut); 462 env->SetIntField(object, stat_fields[i].swappedOutPss_field, stats[i].swappedOutPss); 463 } 464 465 466 env->SetBooleanField(object, hasSwappedOutPss_field, foundSwapPss); 467 jintArray otherIntArray = (jintArray)env->GetObjectField(object, otherStats_field); 468 469 jint* otherArray = (jint*)env->GetPrimitiveArrayCritical(otherIntArray, 0); 470 if (otherArray == NULL) { 471 return JNI_FALSE; 472 } 473 474 int j=0; 475 for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) { 476 otherArray[j++] = stats[i].pss; 477 otherArray[j++] = stats[i].swappablePss; 478 otherArray[j++] = stats[i].rss; 479 otherArray[j++] = stats[i].privateDirty; 480 otherArray[j++] = stats[i].sharedDirty; 481 otherArray[j++] = stats[i].privateClean; 482 otherArray[j++] = stats[i].sharedClean; 483 otherArray[j++] = stats[i].swappedOut; 484 otherArray[j++] = stats[i].swappedOutPss; 485 } 486 487 env->ReleasePrimitiveArrayCritical(otherIntArray, otherArray, 0); 488 return JNI_TRUE; 489 } 490 491 static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject object) 492 { 493 android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object); 494 } 495 496 static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid, 497 jlongArray outUssSwapPssRss, jlongArray outMemtrack) 498 { 499 jlong pss = 0; 500 jlong rss = 0; 501 jlong swapPss = 0; 502 jlong uss = 0; 503 jlong memtrack = 0; 504 505 struct graphics_memory_pss graphics_mem; 506 if (read_memtrack_memory(pid, &graphics_mem) == 0) { 507 pss = uss = rss = memtrack = graphics_mem.graphics + graphics_mem.gl + graphics_mem.other; 508 } 509 510 ::android::meminfo::ProcMemInfo proc_mem(pid); 511 ::android::meminfo::MemUsage stats; 512 if (proc_mem.SmapsOrRollup(&stats)) { 513 pss += stats.pss; 514 uss += stats.uss; 515 rss += stats.rss; 516 swapPss = stats.swap_pss; 517 pss += swapPss; // Also in swap, those pages would be accounted as Pss without SWAP 518 } else { 519 return 0; 520 } 521 522 if (outUssSwapPssRss != NULL) { 523 int outLen = env->GetArrayLength(outUssSwapPssRss); 524 if (outLen >= 1) { 525 jlong* outUssSwapPssRssArray = env->GetLongArrayElements(outUssSwapPssRss, 0); 526 if (outUssSwapPssRssArray != NULL) { 527 outUssSwapPssRssArray[0] = uss; 528 if (outLen >= 2) { 529 outUssSwapPssRssArray[1] = swapPss; 530 } 531 if (outLen >= 3) { 532 outUssSwapPssRssArray[2] = rss; 533 } 534 } 535 env->ReleaseLongArrayElements(outUssSwapPssRss, outUssSwapPssRssArray, 0); 536 } 537 } 538 539 if (outMemtrack != NULL) { 540 int outLen = env->GetArrayLength(outMemtrack); 541 if (outLen >= 1) { 542 jlong* outMemtrackArray = env->GetLongArrayElements(outMemtrack, 0); 543 if (outMemtrackArray != NULL) { 544 outMemtrackArray[0] = memtrack; 545 if (outLen >= 2) { 546 outMemtrackArray[1] = graphics_mem.graphics; 547 } 548 if (outLen >= 3) { 549 outMemtrackArray[2] = graphics_mem.gl; 550 } 551 if (outLen >= 4) { 552 outMemtrackArray[3] = graphics_mem.other; 553 } 554 } 555 env->ReleaseLongArrayElements(outMemtrack, outMemtrackArray, 0); 556 } 557 } 558 559 return pss; 560 } 561 562 static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz) 563 { 564 return android_os_Debug_getPssPid(env, clazz, getpid(), NULL, NULL); 565 } 566 567 // The 1:1 mapping of MEMINFO_* enums here must match with the constants from 568 // Debug.java. 569 enum { 570 MEMINFO_TOTAL, 571 MEMINFO_FREE, 572 MEMINFO_BUFFERS, 573 MEMINFO_CACHED, 574 MEMINFO_SHMEM, 575 MEMINFO_SLAB, 576 MEMINFO_SLAB_RECLAIMABLE, 577 MEMINFO_SLAB_UNRECLAIMABLE, 578 MEMINFO_SWAP_TOTAL, 579 MEMINFO_SWAP_FREE, 580 MEMINFO_ZRAM_TOTAL, 581 MEMINFO_MAPPED, 582 MEMINFO_VMALLOC_USED, 583 MEMINFO_PAGE_TABLES, 584 MEMINFO_KERNEL_STACK, 585 MEMINFO_KERNEL_RECLAIMABLE, 586 MEMINFO_ACTIVE, 587 MEMINFO_INACTIVE, 588 MEMINFO_UNEVICTABLE, 589 MEMINFO_COUNT 590 }; 591 592 static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray out) 593 { 594 if (out == NULL) { 595 jniThrowNullPointerException(env, "out == null"); 596 return; 597 } 598 599 int outLen = env->GetArrayLength(out); 600 if (outLen < MEMINFO_COUNT) { 601 jniThrowRuntimeException(env, "outLen < MEMINFO_COUNT"); 602 return; 603 } 604 605 // Read system memory info including ZRAM. The values are stored in the vector 606 // in the same order as MEMINFO_* enum 607 std::vector<std::string_view> tags( 608 ::android::meminfo::SysMemInfo::kDefaultSysMemInfoTags.begin(), 609 ::android::meminfo::SysMemInfo::kDefaultSysMemInfoTags.end()); 610 tags.insert(tags.begin() + MEMINFO_ZRAM_TOTAL, "Zram:"); 611 std::vector<uint64_t> mem(tags.size()); 612 ::android::meminfo::SysMemInfo smi; 613 if (!smi.ReadMemInfo(tags.size(), tags.data(), mem.data())) { 614 jniThrowRuntimeException(env, "SysMemInfo read failed"); 615 return; 616 } 617 618 jlong* outArray = env->GetLongArrayElements(out, 0); 619 if (outArray != NULL) { 620 outLen = MEMINFO_COUNT; 621 for (int i = 0; i < outLen; i++) { 622 if (i == MEMINFO_VMALLOC_USED && mem[i] == 0) { 623 outArray[i] = smi.ReadVmallocInfo() / 1024; 624 continue; 625 } 626 outArray[i] = mem[i]; 627 } 628 } 629 630 env->ReleaseLongArrayElements(out, outArray, 0); 631 } 632 633 static jint read_binder_stat(const char* stat) 634 { 635 UniqueFile fp = MakeUniqueFile(BINDER_STATS, "re"); 636 if (fp == nullptr) { 637 return -1; 638 } 639 640 char line[1024]; 641 642 char compare[128]; 643 int len = snprintf(compare, 128, "proc %d", getpid()); 644 645 // loop until we have the block that represents this process 646 do { 647 if (fgets(line, 1024, fp.get()) == 0) { 648 return -1; 649 } 650 } while (strncmp(compare, line, len)); 651 652 // now that we have this process, read until we find the stat that we are looking for 653 len = snprintf(compare, 128, " %s: ", stat); 654 655 do { 656 if (fgets(line, 1024, fp.get()) == 0) { 657 return -1; 658 } 659 } while (strncmp(compare, line, len)); 660 661 // we have the line, now increment the line ptr to the value 662 char* ptr = line + len; 663 jint result = atoi(ptr); 664 return result; 665 } 666 667 static jint android_os_Debug_getBinderSentTransactions(JNIEnv *env, jobject clazz) 668 { 669 return read_binder_stat("bcTRANSACTION"); 670 } 671 672 static jint android_os_getBinderReceivedTransactions(JNIEnv *env, jobject clazz) 673 { 674 return read_binder_stat("brTRANSACTION"); 675 } 676 677 // these are implemented in android_util_Binder.cpp 678 jint android_os_Debug_getLocalObjectCount(JNIEnv* env, jobject clazz); 679 jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz); 680 jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz); 681 682 static bool openFile(JNIEnv* env, jobject fileDescriptor, UniqueFile& fp) 683 { 684 if (fileDescriptor == NULL) { 685 jniThrowNullPointerException(env, "fd == null"); 686 return false; 687 } 688 int origFd = jniGetFDFromFileDescriptor(env, fileDescriptor); 689 if (origFd < 0) { 690 jniThrowRuntimeException(env, "Invalid file descriptor"); 691 return false; 692 } 693 694 /* dup() the descriptor so we don't close the original with fclose() */ 695 int fd = fcntl(origFd, F_DUPFD_CLOEXEC, 0); 696 if (fd < 0) { 697 ALOGW("dup(%d) failed: %s\n", origFd, strerror(errno)); 698 jniThrowRuntimeException(env, "dup() failed"); 699 return false; 700 } 701 702 fp.reset(fdopen(fd, "w")); 703 if (fp == nullptr) { 704 ALOGW("fdopen(%d) failed: %s\n", fd, strerror(errno)); 705 close(fd); 706 jniThrowRuntimeException(env, "fdopen() failed"); 707 return false; 708 } 709 return true; 710 } 711 712 /* 713 * Dump the native heap, writing human-readable output to the specified 714 * file descriptor. 715 */ 716 static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject, 717 jobject fileDescriptor) 718 { 719 UniqueFile fp(nullptr, safeFclose); 720 if (!openFile(env, fileDescriptor, fp)) { 721 return; 722 } 723 724 ALOGD("Native heap dump starting...\n"); 725 // Formatting of the native heap dump is handled by malloc debug itself. 726 // See https://android.googlesource.com/platform/bionic/+/master/libc/malloc_debug/README.md#backtrace-heap-dump-format 727 if (android_mallopt(M_WRITE_MALLOC_LEAK_INFO_TO_FILE, fp.get(), sizeof(FILE*))) { 728 ALOGD("Native heap dump complete.\n"); 729 } else { 730 PLOG(ERROR) << "Failed to write native heap dump to file"; 731 } 732 } 733 734 /* 735 * Dump the native malloc info, writing xml output to the specified 736 * file descriptor. 737 */ 738 static void android_os_Debug_dumpNativeMallocInfo(JNIEnv* env, jobject, 739 jobject fileDescriptor) 740 { 741 UniqueFile fp(nullptr, safeFclose); 742 if (!openFile(env, fileDescriptor, fp)) { 743 return; 744 } 745 746 malloc_info(0, fp.get()); 747 } 748 749 static bool dumpTraces(JNIEnv* env, jint pid, jstring fileName, jint timeoutSecs, 750 DebuggerdDumpType dumpType) { 751 const ScopedUtfChars fileNameChars(env, fileName); 752 if (fileNameChars.c_str() == nullptr) { 753 return false; 754 } 755 756 android::base::unique_fd fd(open(fileNameChars.c_str(), 757 O_CREAT | O_WRONLY | O_NOFOLLOW | O_CLOEXEC | O_APPEND, 758 0666)); 759 if (fd < 0) { 760 PLOG(ERROR) << "Can't open " << fileNameChars.c_str(); 761 return false; 762 } 763 764 int res = dump_backtrace_to_file_timeout(pid, dumpType, timeoutSecs, fd); 765 if (fdatasync(fd.get()) != 0) { 766 PLOG(ERROR) << "Failed flushing trace."; 767 } 768 return res == 0; 769 } 770 771 static jboolean android_os_Debug_dumpJavaBacktraceToFileTimeout(JNIEnv* env, jobject clazz, 772 jint pid, jstring fileName, jint timeoutSecs) { 773 const bool ret = dumpTraces(env, pid, fileName, timeoutSecs, kDebuggerdJavaBacktrace); 774 return ret ? JNI_TRUE : JNI_FALSE; 775 } 776 777 static jboolean android_os_Debug_dumpNativeBacktraceToFileTimeout(JNIEnv* env, jobject clazz, 778 jint pid, jstring fileName, jint timeoutSecs) { 779 const bool ret = dumpTraces(env, pid, fileName, timeoutSecs, kDebuggerdNativeBacktrace); 780 return ret ? JNI_TRUE : JNI_FALSE; 781 } 782 783 static jstring android_os_Debug_getUnreachableMemory(JNIEnv* env, jobject clazz, 784 jint limit, jboolean contents) 785 { 786 std::string s = GetUnreachableMemoryString(contents, limit); 787 return env->NewStringUTF(s.c_str()); 788 } 789 790 static jlong android_os_Debug_getFreeZramKb(JNIEnv* env, jobject clazz) { 791 792 jlong zramFreeKb = 0; 793 794 std::string status_path = android::base::StringPrintf("/proc/meminfo"); 795 UniqueFile file = MakeUniqueFile(status_path.c_str(), "re"); 796 797 char line[256]; 798 while (file != nullptr && fgets(line, sizeof(line), file.get())) { 799 jlong v; 800 if (sscanf(line, "SwapFree: %" SCNd64 " kB", &v) == 1) { 801 zramFreeKb = v; 802 break; 803 } 804 } 805 806 return zramFreeKb; 807 } 808 809 static jlong android_os_Debug_getIonHeapsSizeKb(JNIEnv* env, jobject clazz) { 810 jlong heapsSizeKb = -1; 811 uint64_t size; 812 813 if (meminfo::ReadIonHeapsSizeKb(&size)) { 814 heapsSizeKb = size; 815 } 816 817 return heapsSizeKb; 818 } 819 820 static jlong android_os_Debug_getDmabufTotalExportedKb(JNIEnv* env, jobject clazz) { 821 jlong dmabufTotalSizeKb = -1; 822 uint64_t size; 823 824 if (dmabufinfo::GetDmabufTotalExportedKb(&size)) { 825 dmabufTotalSizeKb = size; 826 } 827 return dmabufTotalSizeKb; 828 } 829 830 static jlong android_os_Debug_getDmabufHeapTotalExportedKb(JNIEnv* env, jobject clazz) { 831 jlong dmabufHeapTotalSizeKb = -1; 832 uint64_t size; 833 834 if (meminfo::ReadDmabufHeapTotalExportedKb(&size)) { 835 dmabufHeapTotalSizeKb = size; 836 } 837 return dmabufHeapTotalSizeKb; 838 } 839 840 static jlong android_os_Debug_getIonPoolsSizeKb(JNIEnv* env, jobject clazz) { 841 jlong poolsSizeKb = -1; 842 uint64_t size; 843 844 if (meminfo::ReadIonPoolsSizeKb(&size)) { 845 poolsSizeKb = size; 846 } 847 848 return poolsSizeKb; 849 } 850 851 static jlong android_os_Debug_getDmabufHeapPoolsSizeKb(JNIEnv* env, jobject clazz) { 852 jlong poolsSizeKb = -1; 853 uint64_t size; 854 855 if (meminfo::ReadDmabufHeapPoolsSizeKb(&size)) { 856 poolsSizeKb = size; 857 } 858 859 return poolsSizeKb; 860 } 861 862 static jlong android_os_Debug_getGpuPrivateMemoryKb(JNIEnv* env, jobject clazz) { 863 struct memtrack_proc* p = memtrack_proc_new(); 864 if (p == nullptr) { 865 LOG(ERROR) << "getGpuPrivateMemoryKb: Failed to create memtrack_proc"; 866 return -1; 867 } 868 869 // Memtrack hal defines PID 0 as global total for GPU-private (GL) memory. 870 if (memtrack_proc_get(p, 0) != 0) { 871 // The memtrack HAL may not be available, avoid flooding the log. 872 memtrack_proc_destroy(p); 873 return -1; 874 } 875 876 ssize_t gpuPrivateMem = memtrack_proc_gl_pss(p); 877 878 memtrack_proc_destroy(p); 879 return gpuPrivateMem / 1024; 880 } 881 882 static jlong android_os_Debug_getDmabufMappedSizeKb(JNIEnv* env, jobject clazz) { 883 jlong dmabufPss = 0; 884 std::vector<dmabufinfo::DmaBuffer> dmabufs; 885 886 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir("/proc"), closedir); 887 if (!dir) { 888 LOG(ERROR) << "Failed to open /proc directory"; 889 return false; 890 } 891 892 struct dirent* dent; 893 while ((dent = readdir(dir.get()))) { 894 if (dent->d_type != DT_DIR) continue; 895 896 int pid = atoi(dent->d_name); 897 if (pid == 0) { 898 continue; 899 } 900 901 if (!ReadDmaBufMapRefs(pid, &dmabufs)) { 902 LOG(ERROR) << "Failed to read maps for pid " << pid; 903 } 904 } 905 906 for (const dmabufinfo::DmaBuffer& buf : dmabufs) { 907 dmabufPss += buf.size() / 1024; 908 } 909 910 return dmabufPss; 911 } 912 913 static jlong android_os_Debug_getGpuTotalUsageKb(JNIEnv* env, jobject clazz) { 914 jlong sizeKb = -1; 915 uint64_t size; 916 917 if (meminfo::ReadGpuTotalUsageKb(&size)) { 918 sizeKb = size; 919 } 920 921 return sizeKb; 922 } 923 924 static jboolean android_os_Debug_isVmapStack(JNIEnv *env, jobject clazz) 925 { 926 static enum { 927 CONFIG_UNKNOWN, 928 CONFIG_SET, 929 CONFIG_UNSET, 930 } cfg_state = CONFIG_UNKNOWN; 931 932 if (cfg_state == CONFIG_UNKNOWN) { 933 auto runtime_info = vintf::VintfObject::GetInstance()->getRuntimeInfo( 934 vintf::RuntimeInfo::FetchFlag::CONFIG_GZ); 935 CHECK(runtime_info != nullptr) << "Kernel configs cannot be fetched. b/151092221"; 936 const std::map<std::string, std::string>& configs = runtime_info->kernelConfigs(); 937 std::map<std::string, std::string>::const_iterator it = configs.find("CONFIG_VMAP_STACK"); 938 cfg_state = (it != configs.end() && it->second == "y") ? CONFIG_SET : CONFIG_UNSET; 939 } 940 return cfg_state == CONFIG_SET; 941 } 942 943 /* 944 * JNI registration. 945 */ 946 947 static const JNINativeMethod gMethods[] = { 948 { "getNativeHeapSize", "()J", 949 (void*) android_os_Debug_getNativeHeapSize }, 950 { "getNativeHeapAllocatedSize", "()J", 951 (void*) android_os_Debug_getNativeHeapAllocatedSize }, 952 { "getNativeHeapFreeSize", "()J", 953 (void*) android_os_Debug_getNativeHeapFreeSize }, 954 { "getMemoryInfo", "(Landroid/os/Debug$MemoryInfo;)V", 955 (void*) android_os_Debug_getDirtyPages }, 956 { "getMemoryInfo", "(ILandroid/os/Debug$MemoryInfo;)Z", 957 (void*) android_os_Debug_getDirtyPagesPid }, 958 { "getPss", "()J", 959 (void*) android_os_Debug_getPss }, 960 { "getPss", "(I[J[J)J", 961 (void*) android_os_Debug_getPssPid }, 962 { "getMemInfo", "([J)V", 963 (void*) android_os_Debug_getMemInfo }, 964 { "dumpNativeHeap", "(Ljava/io/FileDescriptor;)V", 965 (void*) android_os_Debug_dumpNativeHeap }, 966 { "dumpNativeMallocInfo", "(Ljava/io/FileDescriptor;)V", 967 (void*) android_os_Debug_dumpNativeMallocInfo }, 968 { "getBinderSentTransactions", "()I", 969 (void*) android_os_Debug_getBinderSentTransactions }, 970 { "getBinderReceivedTransactions", "()I", 971 (void*) android_os_getBinderReceivedTransactions }, 972 { "getBinderLocalObjectCount", "()I", 973 (void*)android_os_Debug_getLocalObjectCount }, 974 { "getBinderProxyObjectCount", "()I", 975 (void*)android_os_Debug_getProxyObjectCount }, 976 { "getBinderDeathObjectCount", "()I", 977 (void*)android_os_Debug_getDeathObjectCount }, 978 { "dumpJavaBacktraceToFileTimeout", "(ILjava/lang/String;I)Z", 979 (void*)android_os_Debug_dumpJavaBacktraceToFileTimeout }, 980 { "dumpNativeBacktraceToFileTimeout", "(ILjava/lang/String;I)Z", 981 (void*)android_os_Debug_dumpNativeBacktraceToFileTimeout }, 982 { "getUnreachableMemory", "(IZ)Ljava/lang/String;", 983 (void*)android_os_Debug_getUnreachableMemory }, 984 { "getZramFreeKb", "()J", 985 (void*)android_os_Debug_getFreeZramKb }, 986 { "getIonHeapsSizeKb", "()J", 987 (void*)android_os_Debug_getIonHeapsSizeKb }, 988 { "getDmabufTotalExportedKb", "()J", 989 (void*)android_os_Debug_getDmabufTotalExportedKb }, 990 { "getGpuPrivateMemoryKb", "()J", 991 (void*)android_os_Debug_getGpuPrivateMemoryKb }, 992 { "getDmabufHeapTotalExportedKb", "()J", 993 (void*)android_os_Debug_getDmabufHeapTotalExportedKb }, 994 { "getIonPoolsSizeKb", "()J", 995 (void*)android_os_Debug_getIonPoolsSizeKb }, 996 { "getDmabufMappedSizeKb", "()J", 997 (void*)android_os_Debug_getDmabufMappedSizeKb }, 998 { "getDmabufHeapPoolsSizeKb", "()J", 999 (void*)android_os_Debug_getDmabufHeapPoolsSizeKb }, 1000 { "getGpuTotalUsageKb", "()J", 1001 (void*)android_os_Debug_getGpuTotalUsageKb }, 1002 { "isVmapStack", "()Z", 1003 (void*)android_os_Debug_isVmapStack }, 1004 }; 1005 1006 int register_android_os_Debug(JNIEnv *env) 1007 { 1008 jclass clazz = env->FindClass("android/os/Debug$MemoryInfo"); 1009 1010 // Check the number of other statistics expected in Java matches here. 1011 jfieldID numOtherStats_field = env->GetStaticFieldID(clazz, "NUM_OTHER_STATS", "I"); 1012 jint numOtherStats = env->GetStaticIntField(clazz, numOtherStats_field); 1013 jfieldID numDvkStats_field = env->GetStaticFieldID(clazz, "NUM_DVK_STATS", "I"); 1014 jint numDvkStats = env->GetStaticIntField(clazz, numDvkStats_field); 1015 int expectedNumOtherStats = _NUM_HEAP - _NUM_CORE_HEAP; 1016 if ((numOtherStats + numDvkStats) != expectedNumOtherStats) { 1017 jniThrowExceptionFmt(env, "java/lang/RuntimeException", 1018 "android.os.Debug.Meminfo.NUM_OTHER_STATS+android.os.Debug.Meminfo.NUM_DVK_STATS=%d expected %d", 1019 numOtherStats+numDvkStats, expectedNumOtherStats); 1020 return JNI_ERR; 1021 } 1022 1023 otherStats_field = env->GetFieldID(clazz, "otherStats", "[I"); 1024 hasSwappedOutPss_field = env->GetFieldID(clazz, "hasSwappedOutPss", "Z"); 1025 1026 for (int i=0; i<_NUM_CORE_HEAP; i++) { 1027 stat_fields[i].pss_field = 1028 env->GetFieldID(clazz, stat_field_names[i].pss_name, "I"); 1029 stat_fields[i].pssSwappable_field = 1030 env->GetFieldID(clazz, stat_field_names[i].pssSwappable_name, "I"); 1031 stat_fields[i].rss_field = 1032 env->GetFieldID(clazz, stat_field_names[i].rss_name, "I"); 1033 stat_fields[i].privateDirty_field = 1034 env->GetFieldID(clazz, stat_field_names[i].privateDirty_name, "I"); 1035 stat_fields[i].sharedDirty_field = 1036 env->GetFieldID(clazz, stat_field_names[i].sharedDirty_name, "I"); 1037 stat_fields[i].privateClean_field = 1038 env->GetFieldID(clazz, stat_field_names[i].privateClean_name, "I"); 1039 stat_fields[i].sharedClean_field = 1040 env->GetFieldID(clazz, stat_field_names[i].sharedClean_name, "I"); 1041 stat_fields[i].swappedOut_field = 1042 env->GetFieldID(clazz, stat_field_names[i].swappedOut_name, "I"); 1043 stat_fields[i].swappedOutPss_field = 1044 env->GetFieldID(clazz, stat_field_names[i].swappedOutPss_name, "I"); 1045 } 1046 1047 return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods)); 1048 } 1049 1050 }; // namespace android 1051