android_os_Debug.cpp revision 3c61506b7147e13b9d39fc07fb189504fcab4541
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#include "JNIHelp.h" 19#include "jni.h" 20#include <utils/String8.h> 21#include "utils/misc.h" 22#include "cutils/debugger.h" 23 24#include <fcntl.h> 25#include <stdio.h> 26#include <stdlib.h> 27#include <string.h> 28#include <unistd.h> 29#include <time.h> 30#include <sys/time.h> 31#include <errno.h> 32#include <assert.h> 33#include <ctype.h> 34 35#ifdef HAVE_MALLOC_H 36#include <malloc.h> 37#endif 38 39namespace android 40{ 41 42enum { 43 HEAP_UNKNOWN, 44 HEAP_DALVIK, 45 HEAP_NATIVE, 46 HEAP_STACK, 47 HEAP_CURSOR, 48 HEAP_ASHMEM, 49 HEAP_UNKNOWN_DEV, 50 HEAP_SO, 51 HEAP_JAR, 52 HEAP_APK, 53 HEAP_TTF, 54 HEAP_DEX, 55 HEAP_OAT, 56 HEAP_ART, 57 HEAP_UNKNOWN_MAP, 58 HEAP_DALVIK_NORMAL, 59 HEAP_DALVIK_LARGE, 60 HEAP_DALVIK_LINEARALLOC, 61 HEAP_DALVIK_ACCOUNTING, 62 HEAP_DALVIK_CODE_CACHE, 63 64 _NUM_HEAP, 65 _NUM_EXCLUSIVE_HEAP = HEAP_UNKNOWN_MAP+1, 66 _NUM_CORE_HEAP = HEAP_NATIVE+1 67}; 68 69struct stat_fields { 70 jfieldID pss_field; 71 jfieldID pssSwappable_field; 72 jfieldID privateDirty_field; 73 jfieldID sharedDirty_field; 74 jfieldID privateClean_field; 75 jfieldID sharedClean_field; 76}; 77 78struct stat_field_names { 79 const char* pss_name; 80 const char* pssSwappable_name; 81 const char* privateDirty_name; 82 const char* sharedDirty_name; 83 const char* privateClean_name; 84 const char* sharedClean_name; 85}; 86 87static stat_fields stat_fields[_NUM_CORE_HEAP]; 88 89static stat_field_names stat_field_names[_NUM_CORE_HEAP] = { 90 { "otherPss", "otherSwappablePss", "otherPrivateDirty", "otherSharedDirty", "otherPrivateClean", "otherSharedClean" }, 91 { "dalvikPss", "dalvikSwappablePss", "dalvikPrivateDirty", "dalvikSharedDirty", "dalvikPrivateClean", "dalvikSharedClean" }, 92 { "nativePss", "nativeSwappablePss", "nativePrivateDirty", "nativeSharedDirty", "nativePrivateClean", "nativeSharedClean" } 93}; 94 95jfieldID otherStats_field; 96 97struct stats_t { 98 int pss; 99 int swappablePss; 100 int privateDirty; 101 int sharedDirty; 102 int privateClean; 103 int sharedClean; 104}; 105 106#define BINDER_STATS "/proc/binder/stats" 107 108static jlong android_os_Debug_getNativeHeapSize(JNIEnv *env, jobject clazz) 109{ 110#ifdef HAVE_MALLOC_H 111 struct mallinfo info = mallinfo(); 112 return (jlong) info.usmblks; 113#else 114 return -1; 115#endif 116} 117 118static jlong android_os_Debug_getNativeHeapAllocatedSize(JNIEnv *env, jobject clazz) 119{ 120#ifdef HAVE_MALLOC_H 121 struct mallinfo info = mallinfo(); 122 return (jlong) info.uordblks; 123#else 124 return -1; 125#endif 126} 127 128static jlong android_os_Debug_getNativeHeapFreeSize(JNIEnv *env, jobject clazz) 129{ 130#ifdef HAVE_MALLOC_H 131 struct mallinfo info = mallinfo(); 132 return (jlong) info.fordblks; 133#else 134 return -1; 135#endif 136} 137 138static void read_mapinfo(FILE *fp, stats_t* stats) 139{ 140 char line[1024]; 141 int len, nameLen; 142 bool skip, done = false; 143 144 unsigned size = 0, resident = 0, pss = 0, swappable_pss = 0; 145 float sharing_proportion = 0.0; 146 unsigned shared_clean = 0, shared_dirty = 0; 147 unsigned private_clean = 0, private_dirty = 0; 148 bool is_swappable = false; 149 unsigned referenced = 0; 150 unsigned temp; 151 152 unsigned long int start; 153 unsigned long int end = 0; 154 unsigned long int prevEnd = 0; 155 char* name; 156 int name_pos; 157 158 int whichHeap = HEAP_UNKNOWN; 159 int subHeap = HEAP_UNKNOWN; 160 int prevHeap = HEAP_UNKNOWN; 161 162 if(fgets(line, sizeof(line), fp) == 0) return; 163 164 while (!done) { 165 prevHeap = whichHeap; 166 prevEnd = end; 167 whichHeap = HEAP_UNKNOWN; 168 subHeap = HEAP_UNKNOWN; 169 skip = false; 170 is_swappable = false; 171 172 len = strlen(line); 173 if (len < 1) return; 174 line[--len] = 0; 175 176 if (sscanf(line, "%lx-%lx %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) { 177 skip = true; 178 } else { 179 while (isspace(line[name_pos])) { 180 name_pos += 1; 181 } 182 name = line + name_pos; 183 nameLen = strlen(name); 184 185 if ((strstr(name, "[heap]") == name) || 186 (strstr(name, "/dev/ashmem/libc malloc") == name)) { 187 whichHeap = HEAP_NATIVE; 188 } else if (strstr(name, "/dev/ashmem/dalvik-") == name) { 189 whichHeap = HEAP_DALVIK; 190 if (strstr(name, "/dev/ashmem/dalvik-LinearAlloc") == name) { 191 subHeap = HEAP_DALVIK_LINEARALLOC; 192 } else if ((strstr(name, "/dev/ashmem/dalvik-mark") == name) || 193 (strstr(name, "/dev/ashmem/dalvik-allocspace alloc space live-bitmap") == name) || 194 (strstr(name, "/dev/ashmem/dalvik-allocspace alloc space mark-bitmap") == name) || 195 (strstr(name, "/dev/ashmem/dalvik-card table") == name) || 196 (strstr(name, "/dev/ashmem/dalvik-allocation stack") == name) || 197 (strstr(name, "/dev/ashmem/dalvik-live stack") == name) || 198 (strstr(name, "/dev/ashmem/dalvik-imagespace") == name) || 199 (strstr(name, "/dev/ashmem/dalvik-bitmap") == name) || 200 (strstr(name, "/dev/ashmem/dalvik-card-table") == name) || 201 (strstr(name, "/dev/ashmem/dalvik-mark-stack") == name) || 202 (strstr(name, "/dev/ashmem/dalvik-aux-structure") == name)) { 203 subHeap = HEAP_DALVIK_ACCOUNTING; 204 } else if (strstr(name, "/dev/ashmem/dalvik-large") == name) { 205 subHeap = HEAP_DALVIK_LARGE; 206 } else if (strstr(name, "/dev/ashmem/dalvik-jit-code-cache") == name) { 207 subHeap = HEAP_DALVIK_CODE_CACHE; 208 } else 209 subHeap = HEAP_DALVIK_NORMAL; 210 } else if (strstr(name, "[stack") == name) { 211 whichHeap = HEAP_STACK; 212 } else if (strstr(name, "/dev/ashmem/CursorWindow") == name) { 213 whichHeap = HEAP_CURSOR; 214 } else if (strstr(name, "/dev/ashmem/") == name) { 215 whichHeap = HEAP_ASHMEM; 216 } else if (strstr(name, "/dev/") == name) { 217 whichHeap = HEAP_UNKNOWN_DEV; 218 } else if (nameLen > 3 && strcmp(name+nameLen-3, ".so") == 0) { 219 whichHeap = HEAP_SO; 220 is_swappable = true; 221 } else if (nameLen > 4 && strcmp(name+nameLen-4, ".jar") == 0) { 222 whichHeap = HEAP_JAR; 223 is_swappable = true; 224 } else if (nameLen > 4 && strcmp(name+nameLen-4, ".apk") == 0) { 225 whichHeap = HEAP_APK; 226 is_swappable = true; 227 } else if (nameLen > 4 && strcmp(name+nameLen-4, ".ttf") == 0) { 228 whichHeap = HEAP_TTF; 229 is_swappable = true; 230 } else if ((nameLen > 4 && strcmp(name+nameLen-4, ".dex") == 0) || 231 (nameLen > 5 && strcmp(name+nameLen-5, ".odex") == 0)) { 232 whichHeap = HEAP_DEX; 233 is_swappable = true; 234 } else if (nameLen > 4 && strcmp(name+nameLen-4, ".oat") == 0) { 235 whichHeap = HEAP_OAT; 236 is_swappable = true; 237 } else if (nameLen > 4 && strcmp(name+nameLen-4, ".art") == 0) { 238 whichHeap = HEAP_ART; 239 is_swappable = true; 240 } else if (nameLen > 0) { 241 whichHeap = HEAP_UNKNOWN_MAP; 242 } else if (start == prevEnd && prevHeap == HEAP_SO) { 243 // bss section of a shared library. 244 whichHeap = HEAP_SO; 245 } 246 } 247 248 //ALOGI("native=%d dalvik=%d sqlite=%d: %s\n", isNativeHeap, isDalvikHeap, 249 // isSqliteHeap, line); 250 251 while (true) { 252 if (fgets(line, 1024, fp) == 0) { 253 done = true; 254 break; 255 } 256 257 if (sscanf(line, "Size: %d kB", &temp) == 1) { 258 size = temp; 259 } else if (sscanf(line, "Rss: %d kB", &temp) == 1) { 260 resident = temp; 261 } else if (sscanf(line, "Pss: %d kB", &temp) == 1) { 262 pss = temp; 263 } else if (sscanf(line, "Shared_Clean: %d kB", &temp) == 1) { 264 shared_clean = temp; 265 } else if (sscanf(line, "Shared_Dirty: %d kB", &temp) == 1) { 266 shared_dirty = temp; 267 } else if (sscanf(line, "Private_Clean: %d kB", &temp) == 1) { 268 private_clean = temp; 269 } else if (sscanf(line, "Private_Dirty: %d kB", &temp) == 1) { 270 private_dirty = temp; 271 } else if (sscanf(line, "Referenced: %d kB", &temp) == 1) { 272 referenced = temp; 273 } else if (strlen(line) > 30 && line[8] == '-' && line[17] == ' ') { 274 // looks like a new mapping 275 // example: "10000000-10001000 ---p 10000000 00:00 0" 276 break; 277 } 278 } 279 280 if (!skip) { 281 if (is_swappable && (pss > 0)) { 282 sharing_proportion = 0.0; 283 if ((shared_clean > 0) || (shared_dirty > 0)) { 284 sharing_proportion = (pss - private_clean - private_dirty)/(shared_clean+shared_dirty); 285 } 286 swappable_pss = (sharing_proportion*shared_clean) + private_clean; 287 } else 288 swappable_pss = 0; 289 290 stats[whichHeap].pss += pss; 291 stats[whichHeap].swappablePss += swappable_pss; 292 stats[whichHeap].privateDirty += private_dirty; 293 stats[whichHeap].sharedDirty += shared_dirty; 294 stats[whichHeap].privateClean += private_clean; 295 stats[whichHeap].sharedClean += shared_clean; 296 if (whichHeap == HEAP_DALVIK) { 297 stats[subHeap].pss += pss; 298 stats[subHeap].swappablePss += swappable_pss; 299 stats[subHeap].privateDirty += private_dirty; 300 stats[subHeap].sharedDirty += shared_dirty; 301 stats[subHeap].privateClean += private_clean; 302 stats[subHeap].sharedClean += shared_clean; 303 } 304 } 305 } 306} 307 308static void load_maps(int pid, stats_t* stats) 309{ 310 char tmp[128]; 311 FILE *fp; 312 313 sprintf(tmp, "/proc/%d/smaps", pid); 314 fp = fopen(tmp, "r"); 315 if (fp == 0) return; 316 317 read_mapinfo(fp, stats); 318 fclose(fp); 319} 320 321static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz, 322 jint pid, jobject object) 323{ 324 stats_t stats[_NUM_HEAP]; 325 memset(&stats, 0, sizeof(stats)); 326 327 328 load_maps(pid, stats); 329 330 for (int i=_NUM_CORE_HEAP; i<_NUM_EXCLUSIVE_HEAP; i++) { 331 stats[HEAP_UNKNOWN].pss += stats[i].pss; 332 stats[HEAP_UNKNOWN].swappablePss += stats[i].swappablePss; 333 stats[HEAP_UNKNOWN].privateDirty += stats[i].privateDirty; 334 stats[HEAP_UNKNOWN].sharedDirty += stats[i].sharedDirty; 335 stats[HEAP_UNKNOWN].privateClean += stats[i].privateClean; 336 stats[HEAP_UNKNOWN].sharedClean += stats[i].sharedClean; 337 } 338 339 for (int i=0; i<_NUM_CORE_HEAP; i++) { 340 env->SetIntField(object, stat_fields[i].pss_field, stats[i].pss); 341 env->SetIntField(object, stat_fields[i].pssSwappable_field, stats[i].swappablePss); 342 env->SetIntField(object, stat_fields[i].privateDirty_field, stats[i].privateDirty); 343 env->SetIntField(object, stat_fields[i].sharedDirty_field, stats[i].sharedDirty); 344 env->SetIntField(object, stat_fields[i].privateClean_field, stats[i].privateClean); 345 env->SetIntField(object, stat_fields[i].sharedClean_field, stats[i].sharedClean); 346 } 347 348 349 jintArray otherIntArray = (jintArray)env->GetObjectField(object, otherStats_field); 350 351 jint* otherArray = (jint*)env->GetPrimitiveArrayCritical(otherIntArray, 0); 352 if (otherArray == NULL) { 353 return; 354 } 355 356 int j=0; 357 for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) { 358 otherArray[j++] = stats[i].pss; 359 otherArray[j++] = stats[i].swappablePss; 360 otherArray[j++] = stats[i].privateDirty; 361 otherArray[j++] = stats[i].sharedDirty; 362 otherArray[j++] = stats[i].privateClean; 363 otherArray[j++] = stats[i].sharedClean; 364 } 365 366 env->ReleasePrimitiveArrayCritical(otherIntArray, otherArray, 0); 367} 368 369static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject object) 370{ 371 android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object); 372} 373 374static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid) 375{ 376 char line[1024]; 377 jlong pss = 0; 378 unsigned temp; 379 380 char tmp[128]; 381 FILE *fp; 382 383 sprintf(tmp, "/proc/%d/smaps", pid); 384 fp = fopen(tmp, "r"); 385 if (fp == 0) return 0; 386 387 while (true) { 388 if (fgets(line, 1024, fp) == 0) { 389 break; 390 } 391 392 if (sscanf(line, "Pss: %d kB", &temp) == 1) { 393 pss += temp; 394 } 395 } 396 397 fclose(fp); 398 399 return pss; 400} 401 402static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz) 403{ 404 return android_os_Debug_getPssPid(env, clazz, getpid()); 405} 406 407static jint read_binder_stat(const char* stat) 408{ 409 FILE* fp = fopen(BINDER_STATS, "r"); 410 if (fp == NULL) { 411 return -1; 412 } 413 414 char line[1024]; 415 416 char compare[128]; 417 int len = snprintf(compare, 128, "proc %d", getpid()); 418 419 // loop until we have the block that represents this process 420 do { 421 if (fgets(line, 1024, fp) == 0) { 422 return -1; 423 } 424 } while (strncmp(compare, line, len)); 425 426 // now that we have this process, read until we find the stat that we are looking for 427 len = snprintf(compare, 128, " %s: ", stat); 428 429 do { 430 if (fgets(line, 1024, fp) == 0) { 431 return -1; 432 } 433 } while (strncmp(compare, line, len)); 434 435 // we have the line, now increment the line ptr to the value 436 char* ptr = line + len; 437 return atoi(ptr); 438} 439 440static jint android_os_Debug_getBinderSentTransactions(JNIEnv *env, jobject clazz) 441{ 442 return read_binder_stat("bcTRANSACTION"); 443} 444 445static jint android_os_getBinderReceivedTransactions(JNIEnv *env, jobject clazz) 446{ 447 return read_binder_stat("brTRANSACTION"); 448} 449 450// these are implemented in android_util_Binder.cpp 451jint android_os_Debug_getLocalObjectCount(JNIEnv* env, jobject clazz); 452jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz); 453jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz); 454 455 456/* pulled out of bionic */ 457extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, 458 size_t* infoSize, size_t* totalMemory, size_t* backtraceSize); 459extern "C" void free_malloc_leak_info(uint8_t* info); 460#define SIZE_FLAG_ZYGOTE_CHILD (1<<31) 461#define BACKTRACE_SIZE 32 462 463/* 464 * This is a qsort() callback. 465 * 466 * See dumpNativeHeap() for comments about the data format and sort order. 467 */ 468static int compareHeapRecords(const void* vrec1, const void* vrec2) 469{ 470 const size_t* rec1 = (const size_t*) vrec1; 471 const size_t* rec2 = (const size_t*) vrec2; 472 size_t size1 = *rec1; 473 size_t size2 = *rec2; 474 475 if (size1 < size2) { 476 return 1; 477 } else if (size1 > size2) { 478 return -1; 479 } 480 481 intptr_t* bt1 = (intptr_t*)(rec1 + 2); 482 intptr_t* bt2 = (intptr_t*)(rec2 + 2); 483 for (size_t idx = 0; idx < BACKTRACE_SIZE; idx++) { 484 intptr_t addr1 = bt1[idx]; 485 intptr_t addr2 = bt2[idx]; 486 if (addr1 == addr2) { 487 if (addr1 == 0) 488 break; 489 continue; 490 } 491 if (addr1 < addr2) { 492 return -1; 493 } else if (addr1 > addr2) { 494 return 1; 495 } 496 } 497 498 return 0; 499} 500 501/* 502 * The get_malloc_leak_info() call returns an array of structs that 503 * look like this: 504 * 505 * size_t size 506 * size_t allocations 507 * intptr_t backtrace[32] 508 * 509 * "size" is the size of the allocation, "backtrace" is a fixed-size 510 * array of function pointers, and "allocations" is the number of 511 * allocations with the exact same size and backtrace. 512 * 513 * The entries are sorted by descending total size (i.e. size*allocations) 514 * then allocation count. For best results with "diff" we'd like to sort 515 * primarily by individual size then stack trace. Since the entries are 516 * fixed-size, and we're allowed (by the current implementation) to mangle 517 * them, we can do this in place. 518 */ 519static void dumpNativeHeap(FILE* fp) 520{ 521 uint8_t* info = NULL; 522 size_t overallSize, infoSize, totalMemory, backtraceSize; 523 524 get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, 525 &backtraceSize); 526 if (info == NULL) { 527 fprintf(fp, "Native heap dump not available. To enable, run these" 528 " commands (requires root):\n"); 529 fprintf(fp, "$ adb shell setprop libc.debug.malloc 1\n"); 530 fprintf(fp, "$ adb shell stop\n"); 531 fprintf(fp, "$ adb shell start\n"); 532 return; 533 } 534 assert(infoSize != 0); 535 assert(overallSize % infoSize == 0); 536 537 fprintf(fp, "Android Native Heap Dump v1.0\n\n"); 538 539 size_t recordCount = overallSize / infoSize; 540 fprintf(fp, "Total memory: %zu\n", totalMemory); 541 fprintf(fp, "Allocation records: %zd\n", recordCount); 542 if (backtraceSize != BACKTRACE_SIZE) { 543 fprintf(fp, "WARNING: mismatched backtrace sizes (%d vs. %d)\n", 544 backtraceSize, BACKTRACE_SIZE); 545 } 546 fprintf(fp, "\n"); 547 548 /* re-sort the entries */ 549 qsort(info, recordCount, infoSize, compareHeapRecords); 550 551 /* dump the entries to the file */ 552 const uint8_t* ptr = info; 553 for (size_t idx = 0; idx < recordCount; idx++) { 554 size_t size = *(size_t*) ptr; 555 size_t allocations = *(size_t*) (ptr + sizeof(size_t)); 556 intptr_t* backtrace = (intptr_t*) (ptr + sizeof(size_t) * 2); 557 558 fprintf(fp, "z %d sz %8zu num %4zu bt", 559 (size & SIZE_FLAG_ZYGOTE_CHILD) != 0, 560 size & ~SIZE_FLAG_ZYGOTE_CHILD, 561 allocations); 562 for (size_t bt = 0; bt < backtraceSize; bt++) { 563 if (backtrace[bt] == 0) { 564 break; 565 } else { 566 fprintf(fp, " %08x", backtrace[bt]); 567 } 568 } 569 fprintf(fp, "\n"); 570 571 ptr += infoSize; 572 } 573 574 free_malloc_leak_info(info); 575 576 fprintf(fp, "MAPS\n"); 577 const char* maps = "/proc/self/maps"; 578 FILE* in = fopen(maps, "r"); 579 if (in == NULL) { 580 fprintf(fp, "Could not open %s\n", maps); 581 return; 582 } 583 char buf[BUFSIZ]; 584 while (size_t n = fread(buf, sizeof(char), BUFSIZ, in)) { 585 fwrite(buf, sizeof(char), n, fp); 586 } 587 fclose(in); 588 589 fprintf(fp, "END\n"); 590} 591 592/* 593 * Dump the native heap, writing human-readable output to the specified 594 * file descriptor. 595 */ 596static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject clazz, 597 jobject fileDescriptor) 598{ 599 if (fileDescriptor == NULL) { 600 jniThrowNullPointerException(env, "fd == null"); 601 return; 602 } 603 int origFd = jniGetFDFromFileDescriptor(env, fileDescriptor); 604 if (origFd < 0) { 605 jniThrowRuntimeException(env, "Invalid file descriptor"); 606 return; 607 } 608 609 /* dup() the descriptor so we don't close the original with fclose() */ 610 int fd = dup(origFd); 611 if (fd < 0) { 612 ALOGW("dup(%d) failed: %s\n", origFd, strerror(errno)); 613 jniThrowRuntimeException(env, "dup() failed"); 614 return; 615 } 616 617 FILE* fp = fdopen(fd, "w"); 618 if (fp == NULL) { 619 ALOGW("fdopen(%d) failed: %s\n", fd, strerror(errno)); 620 close(fd); 621 jniThrowRuntimeException(env, "fdopen() failed"); 622 return; 623 } 624 625 ALOGD("Native heap dump starting...\n"); 626 dumpNativeHeap(fp); 627 ALOGD("Native heap dump complete.\n"); 628 629 fclose(fp); 630} 631 632 633static void android_os_Debug_dumpNativeBacktraceToFile(JNIEnv* env, jobject clazz, 634 jint pid, jstring fileName) 635{ 636 if (fileName == NULL) { 637 jniThrowNullPointerException(env, "file == null"); 638 return; 639 } 640 const jchar* str = env->GetStringCritical(fileName, 0); 641 String8 fileName8; 642 if (str) { 643 fileName8 = String8(str, env->GetStringLength(fileName)); 644 env->ReleaseStringCritical(fileName, str); 645 } 646 647 int fd = open(fileName8.string(), O_CREAT | O_WRONLY | O_NOFOLLOW, 0666); /* -rw-rw-rw- */ 648 if (fd < 0) { 649 fprintf(stderr, "Can't open %s: %s\n", fileName8.string(), strerror(errno)); 650 return; 651 } 652 653 if (lseek(fd, 0, SEEK_END) < 0) { 654 fprintf(stderr, "lseek: %s\n", strerror(errno)); 655 } else { 656 dump_backtrace_to_file(pid, fd); 657 } 658 659 close(fd); 660} 661 662/* 663 * JNI registration. 664 */ 665 666static JNINativeMethod gMethods[] = { 667 { "getNativeHeapSize", "()J", 668 (void*) android_os_Debug_getNativeHeapSize }, 669 { "getNativeHeapAllocatedSize", "()J", 670 (void*) android_os_Debug_getNativeHeapAllocatedSize }, 671 { "getNativeHeapFreeSize", "()J", 672 (void*) android_os_Debug_getNativeHeapFreeSize }, 673 { "getMemoryInfo", "(Landroid/os/Debug$MemoryInfo;)V", 674 (void*) android_os_Debug_getDirtyPages }, 675 { "getMemoryInfo", "(ILandroid/os/Debug$MemoryInfo;)V", 676 (void*) android_os_Debug_getDirtyPagesPid }, 677 { "getPss", "()J", 678 (void*) android_os_Debug_getPss }, 679 { "getPss", "(I)J", 680 (void*) android_os_Debug_getPssPid }, 681 { "dumpNativeHeap", "(Ljava/io/FileDescriptor;)V", 682 (void*) android_os_Debug_dumpNativeHeap }, 683 { "getBinderSentTransactions", "()I", 684 (void*) android_os_Debug_getBinderSentTransactions }, 685 { "getBinderReceivedTransactions", "()I", 686 (void*) android_os_getBinderReceivedTransactions }, 687 { "getBinderLocalObjectCount", "()I", 688 (void*)android_os_Debug_getLocalObjectCount }, 689 { "getBinderProxyObjectCount", "()I", 690 (void*)android_os_Debug_getProxyObjectCount }, 691 { "getBinderDeathObjectCount", "()I", 692 (void*)android_os_Debug_getDeathObjectCount }, 693 { "dumpNativeBacktraceToFile", "(ILjava/lang/String;)V", 694 (void*)android_os_Debug_dumpNativeBacktraceToFile }, 695}; 696 697int register_android_os_Debug(JNIEnv *env) 698{ 699 jclass clazz = env->FindClass("android/os/Debug$MemoryInfo"); 700 701 // Sanity check the number of other statistics expected in Java matches here. 702 jfieldID numOtherStats_field = env->GetStaticFieldID(clazz, "NUM_OTHER_STATS", "I"); 703 jint numOtherStats = env->GetStaticIntField(clazz, numOtherStats_field); 704 jfieldID numDvkStats_field = env->GetStaticFieldID(clazz, "NUM_DVK_STATS", "I"); 705 jint numDvkStats = env->GetStaticIntField(clazz, numDvkStats_field); 706 int expectedNumOtherStats = _NUM_HEAP - _NUM_CORE_HEAP; 707 if ((numOtherStats + numDvkStats) != expectedNumOtherStats) { 708 jniThrowExceptionFmt(env, "java/lang/RuntimeException", 709 "android.os.Debug.Meminfo.NUM_OTHER_STATS+android.os.Debug.Meminfo.NUM_DVK_STATS=%d expected %d", 710 numOtherStats+numDvkStats, expectedNumOtherStats); 711 return JNI_ERR; 712 } 713 714 otherStats_field = env->GetFieldID(clazz, "otherStats", "[I"); 715 716 for (int i=0; i<_NUM_CORE_HEAP; i++) { 717 stat_fields[i].pss_field = 718 env->GetFieldID(clazz, stat_field_names[i].pss_name, "I"); 719 stat_fields[i].pssSwappable_field = 720 env->GetFieldID(clazz, stat_field_names[i].pssSwappable_name, "I"); 721 stat_fields[i].privateDirty_field = 722 env->GetFieldID(clazz, stat_field_names[i].privateDirty_name, "I"); 723 stat_fields[i].sharedDirty_field = 724 env->GetFieldID(clazz, stat_field_names[i].sharedDirty_name, "I"); 725 stat_fields[i].privateClean_field = 726 env->GetFieldID(clazz, stat_field_names[i].privateClean_name, "I"); 727 stat_fields[i].sharedClean_field = 728 env->GetFieldID(clazz, stat_field_names[i].sharedClean_name, "I"); 729 } 730 731 return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods)); 732} 733 734}; // namespace android 735