blob: 1e6d53af20b59ca241c6e1cef7f3daf98f9c0e79 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Andy McFadden06a6b552010-07-13 16:28:09 -070017#define LOG_TAG "android.os.Debug"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018#include "JNIHelp.h"
19#include "jni.h"
Dianne Hackbornf72467a2012-06-08 17:23:59 -070020#include <utils/String8.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021#include "utils/misc.h"
Dianne Hackbornf72467a2012-06-08 17:23:59 -070022#include "cutils/debugger.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023
Dianne Hackbornf72467a2012-06-08 17:23:59 -070024#include <fcntl.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29#include <time.h>
30#include <sys/time.h>
Andy McFadden06a6b552010-07-13 16:28:09 -070031#include <errno.h>
32#include <assert.h>
Dianne Hackborn0e3328f2011-07-17 13:31:17 -070033#include <ctype.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034
35#ifdef HAVE_MALLOC_H
36#include <malloc.h>
37#endif
38
39namespace android
40{
41
Dianne Hackborn0e3328f2011-07-17 13:31:17 -070042enum {
43 HEAP_UNKNOWN,
44 HEAP_DALVIK,
45 HEAP_NATIVE,
Ian Rogers7c9f30b2013-02-27 10:57:13 -080046 HEAP_STACK,
Dianne Hackborn0e3328f2011-07-17 13:31:17 -070047 HEAP_CURSOR,
48 HEAP_ASHMEM,
49 HEAP_UNKNOWN_DEV,
50 HEAP_SO,
51 HEAP_JAR,
52 HEAP_APK,
53 HEAP_TTF,
54 HEAP_DEX,
Anwar Ghuloum8884ef42013-03-15 12:56:59 -070055 HEAP_OAT,
Dianne Hackborn0e3328f2011-07-17 13:31:17 -070056 HEAP_UNKNOWN_MAP,
57
58 _NUM_HEAP,
59 _NUM_CORE_HEAP = HEAP_NATIVE+1
60};
61
62struct stat_fields {
63 jfieldID pss_field;
64 jfieldID privateDirty_field;
65 jfieldID sharedDirty_field;
66};
67
68struct stat_field_names {
69 const char* pss_name;
70 const char* privateDirty_name;
71 const char* sharedDirty_name;
72};
73
74static stat_fields stat_fields[_NUM_CORE_HEAP];
75
76static stat_field_names stat_field_names[_NUM_CORE_HEAP] = {
77 { "otherPss", "otherPrivateDirty", "otherSharedDirty" },
78 { "dalvikPss", "dalvikPrivateDirty", "dalvikSharedDirty" },
79 { "nativePss", "nativePrivateDirty", "nativeSharedDirty" }
80};
81
82jfieldID otherStats_field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083
84struct stats_t {
Dianne Hackborn0e3328f2011-07-17 13:31:17 -070085 int pss;
86 int privateDirty;
87 int sharedDirty;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088};
89
90#define BINDER_STATS "/proc/binder/stats"
91
92static jlong android_os_Debug_getNativeHeapSize(JNIEnv *env, jobject clazz)
93{
94#ifdef HAVE_MALLOC_H
95 struct mallinfo info = mallinfo();
96 return (jlong) info.usmblks;
97#else
98 return -1;
99#endif
100}
101
102static jlong android_os_Debug_getNativeHeapAllocatedSize(JNIEnv *env, jobject clazz)
103{
104#ifdef HAVE_MALLOC_H
105 struct mallinfo info = mallinfo();
106 return (jlong) info.uordblks;
107#else
108 return -1;
109#endif
110}
111
112static jlong android_os_Debug_getNativeHeapFreeSize(JNIEnv *env, jobject clazz)
113{
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800114#ifdef HAVE_MALLOC_H
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 struct mallinfo info = mallinfo();
116 return (jlong) info.fordblks;
117#else
118 return -1;
119#endif
120}
121
122static void read_mapinfo(FILE *fp, stats_t* stats)
123{
124 char line[1024];
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700125 int len, nameLen;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 bool skip, done = false;
127
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700128 unsigned size = 0, resident = 0, pss = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 unsigned shared_clean = 0, shared_dirty = 0;
130 unsigned private_clean = 0, private_dirty = 0;
131 unsigned referenced = 0;
132 unsigned temp;
133
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700134 unsigned long int start;
135 unsigned long int end = 0;
136 unsigned long int prevEnd = 0;
137 char* name;
138 int name_pos;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700140 int whichHeap = HEAP_UNKNOWN;
141 int prevHeap = HEAP_UNKNOWN;
142
143 if(fgets(line, sizeof(line), fp) == 0) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144
145 while (!done) {
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700146 prevHeap = whichHeap;
147 prevEnd = end;
148 whichHeap = HEAP_UNKNOWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 skip = false;
150
151 len = strlen(line);
152 if (len < 1) return;
153 line[--len] = 0;
154
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700155 if (sscanf(line, "%lx-%lx %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) {
156 skip = true;
157 } else {
158 while (isspace(line[name_pos])) {
159 name_pos += 1;
160 }
161 name = line + name_pos;
162 nameLen = strlen(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163
Ian Rogersafc10e12013-02-22 09:40:58 -0800164 if ((strstr(name, "[heap]") == name) ||
165 (strstr(name, "/dev/ashmem/libc malloc") == name)) {
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700166 whichHeap = HEAP_NATIVE;
167 } else if (strstr(name, "/dev/ashmem/dalvik-") == name) {
168 whichHeap = HEAP_DALVIK;
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800169 } else if (strstr(name, "[stack") == name) {
170 whichHeap = HEAP_STACK;
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700171 } else if (strstr(name, "/dev/ashmem/CursorWindow") == name) {
172 whichHeap = HEAP_CURSOR;
173 } else if (strstr(name, "/dev/ashmem/") == name) {
174 whichHeap = HEAP_ASHMEM;
175 } else if (strstr(name, "/dev/") == name) {
176 whichHeap = HEAP_UNKNOWN_DEV;
177 } else if (nameLen > 3 && strcmp(name+nameLen-3, ".so") == 0) {
178 whichHeap = HEAP_SO;
179 } else if (nameLen > 4 && strcmp(name+nameLen-4, ".jar") == 0) {
180 whichHeap = HEAP_JAR;
181 } else if (nameLen > 4 && strcmp(name+nameLen-4, ".apk") == 0) {
182 whichHeap = HEAP_APK;
183 } else if (nameLen > 4 && strcmp(name+nameLen-4, ".ttf") == 0) {
184 whichHeap = HEAP_TTF;
Ian Rogers9f8589c2013-02-22 20:35:06 -0800185 } else if ((nameLen > 4 && strcmp(name+nameLen-4, ".dex") == 0) ||
186 (nameLen > 5 && strcmp(name+nameLen-5, ".odex") == 0)) {
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700187 whichHeap = HEAP_DEX;
Anwar Ghuloum8884ef42013-03-15 12:56:59 -0700188 } else if (nameLen > 4 && strcmp(name+nameLen-4, ".oat") == 0) {
189 whichHeap = HEAP_OAT;
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700190 } else if (nameLen > 0) {
191 whichHeap = HEAP_UNKNOWN_MAP;
192 } else if (start == prevEnd && prevHeap == HEAP_SO) {
193 // bss section of a shared library.
194 whichHeap = HEAP_SO;
195 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 }
197
Steve Block6215d3f2012-01-04 20:05:49 +0000198 //ALOGI("native=%d dalvik=%d sqlite=%d: %s\n", isNativeHeap, isDalvikHeap,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 // isSqliteHeap, line);
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800200
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 while (true) {
202 if (fgets(line, 1024, fp) == 0) {
203 done = true;
204 break;
205 }
206
207 if (sscanf(line, "Size: %d kB", &temp) == 1) {
208 size = temp;
209 } else if (sscanf(line, "Rss: %d kB", &temp) == 1) {
210 resident = temp;
211 } else if (sscanf(line, "Pss: %d kB", &temp) == 1) {
212 pss = temp;
213 } else if (sscanf(line, "Shared_Clean: %d kB", &temp) == 1) {
214 shared_clean = temp;
215 } else if (sscanf(line, "Shared_Dirty: %d kB", &temp) == 1) {
216 shared_dirty = temp;
217 } else if (sscanf(line, "Private_Clean: %d kB", &temp) == 1) {
218 private_clean = temp;
219 } else if (sscanf(line, "Private_Dirty: %d kB", &temp) == 1) {
220 private_dirty = temp;
221 } else if (sscanf(line, "Referenced: %d kB", &temp) == 1) {
222 referenced = temp;
Grace Klobabd511162009-07-08 23:32:25 -0700223 } else if (strlen(line) > 30 && line[8] == '-' && line[17] == ' ') {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 // looks like a new mapping
Grace Klobabd511162009-07-08 23:32:25 -0700225 // example: "10000000-10001000 ---p 10000000 00:00 0"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 break;
227 }
228 }
229
230 if (!skip) {
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700231 stats[whichHeap].pss += pss;
232 stats[whichHeap].privateDirty += private_dirty;
233 stats[whichHeap].sharedDirty += shared_dirty;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 }
235 }
236}
237
238static void load_maps(int pid, stats_t* stats)
239{
240 char tmp[128];
241 FILE *fp;
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 sprintf(tmp, "/proc/%d/smaps", pid);
244 fp = fopen(tmp, "r");
245 if (fp == 0) return;
246
247 read_mapinfo(fp, stats);
248 fclose(fp);
249}
250
Dianne Hackborn3025ef32009-08-31 21:31:47 -0700251static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
252 jint pid, jobject object)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253{
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700254 stats_t stats[_NUM_HEAP];
255 memset(&stats, 0, sizeof(stats));
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800256
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700257 load_maps(pid, stats);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700259 for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
260 stats[HEAP_UNKNOWN].pss += stats[i].pss;
261 stats[HEAP_UNKNOWN].privateDirty += stats[i].privateDirty;
262 stats[HEAP_UNKNOWN].sharedDirty += stats[i].sharedDirty;
263 }
264
265 for (int i=0; i<_NUM_CORE_HEAP; i++) {
266 env->SetIntField(object, stat_fields[i].pss_field, stats[i].pss);
267 env->SetIntField(object, stat_fields[i].privateDirty_field, stats[i].privateDirty);
268 env->SetIntField(object, stat_fields[i].sharedDirty_field, stats[i].sharedDirty);
269 }
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800270
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700271 jintArray otherIntArray = (jintArray)env->GetObjectField(object, otherStats_field);
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800272
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700273 jint* otherArray = (jint*)env->GetPrimitiveArrayCritical(otherIntArray, 0);
274 if (otherArray == NULL) {
275 return;
276 }
277
278 int j=0;
279 for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
280 otherArray[j++] = stats[i].pss;
281 otherArray[j++] = stats[i].privateDirty;
282 otherArray[j++] = stats[i].sharedDirty;
283 }
284
285 env->ReleasePrimitiveArrayCritical(otherIntArray, otherArray, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286}
287
Dianne Hackborn3025ef32009-08-31 21:31:47 -0700288static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject object)
289{
290 android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object);
291}
292
Dianne Hackbornb437e092011-08-05 17:50:29 -0700293static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid)
294{
295 char line[1024];
296 jlong pss = 0;
297 unsigned temp;
298
299 char tmp[128];
300 FILE *fp;
301
302 sprintf(tmp, "/proc/%d/smaps", pid);
303 fp = fopen(tmp, "r");
304 if (fp == 0) return 0;
305
306 while (true) {
307 if (fgets(line, 1024, fp) == 0) {
308 break;
309 }
310
311 if (sscanf(line, "Pss: %d kB", &temp) == 1) {
312 pss += temp;
313 }
314 }
315
316 fclose(fp);
317
318 return pss;
319}
320
321static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz)
322{
323 return android_os_Debug_getPssPid(env, clazz, getpid());
324}
325
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326static jint read_binder_stat(const char* stat)
327{
328 FILE* fp = fopen(BINDER_STATS, "r");
329 if (fp == NULL) {
330 return -1;
331 }
332
333 char line[1024];
334
335 char compare[128];
336 int len = snprintf(compare, 128, "proc %d", getpid());
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800337
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338 // loop until we have the block that represents this process
339 do {
340 if (fgets(line, 1024, fp) == 0) {
341 return -1;
342 }
343 } while (strncmp(compare, line, len));
344
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800345 // now that we have this process, read until we find the stat that we are looking for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 len = snprintf(compare, 128, " %s: ", stat);
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 do {
349 if (fgets(line, 1024, fp) == 0) {
350 return -1;
351 }
352 } while (strncmp(compare, line, len));
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800353
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 // we have the line, now increment the line ptr to the value
355 char* ptr = line + len;
356 return atoi(ptr);
357}
358
359static jint android_os_Debug_getBinderSentTransactions(JNIEnv *env, jobject clazz)
360{
361 return read_binder_stat("bcTRANSACTION");
362}
363
364static jint android_os_getBinderReceivedTransactions(JNIEnv *env, jobject clazz)
365{
366 return read_binder_stat("brTRANSACTION");
367}
368
369// these are implemented in android_util_Binder.cpp
370jint android_os_Debug_getLocalObjectCount(JNIEnv* env, jobject clazz);
371jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz);
372jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz);
373
Andy McFadden06a6b552010-07-13 16:28:09 -0700374
Andy McFadden06a6b552010-07-13 16:28:09 -0700375/* pulled out of bionic */
376extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
377 size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
378extern "C" void free_malloc_leak_info(uint8_t* info);
379#define SIZE_FLAG_ZYGOTE_CHILD (1<<31)
380#define BACKTRACE_SIZE 32
381
382/*
383 * This is a qsort() callback.
384 *
385 * See dumpNativeHeap() for comments about the data format and sort order.
386 */
387static int compareHeapRecords(const void* vrec1, const void* vrec2)
388{
389 const size_t* rec1 = (const size_t*) vrec1;
390 const size_t* rec2 = (const size_t*) vrec2;
391 size_t size1 = *rec1;
392 size_t size2 = *rec2;
393
394 if (size1 < size2) {
395 return 1;
396 } else if (size1 > size2) {
397 return -1;
398 }
399
400 intptr_t* bt1 = (intptr_t*)(rec1 + 2);
401 intptr_t* bt2 = (intptr_t*)(rec2 + 2);
402 for (size_t idx = 0; idx < BACKTRACE_SIZE; idx++) {
403 intptr_t addr1 = bt1[idx];
404 intptr_t addr2 = bt2[idx];
405 if (addr1 == addr2) {
406 if (addr1 == 0)
407 break;
408 continue;
409 }
410 if (addr1 < addr2) {
411 return -1;
412 } else if (addr1 > addr2) {
413 return 1;
414 }
415 }
416
417 return 0;
418}
419
420/*
421 * The get_malloc_leak_info() call returns an array of structs that
422 * look like this:
423 *
424 * size_t size
425 * size_t allocations
426 * intptr_t backtrace[32]
427 *
428 * "size" is the size of the allocation, "backtrace" is a fixed-size
429 * array of function pointers, and "allocations" is the number of
430 * allocations with the exact same size and backtrace.
431 *
432 * The entries are sorted by descending total size (i.e. size*allocations)
433 * then allocation count. For best results with "diff" we'd like to sort
434 * primarily by individual size then stack trace. Since the entries are
435 * fixed-size, and we're allowed (by the current implementation) to mangle
436 * them, we can do this in place.
437 */
438static void dumpNativeHeap(FILE* fp)
439{
440 uint8_t* info = NULL;
441 size_t overallSize, infoSize, totalMemory, backtraceSize;
442
443 get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory,
444 &backtraceSize);
445 if (info == NULL) {
446 fprintf(fp, "Native heap dump not available. To enable, run these"
447 " commands (requires root):\n");
448 fprintf(fp, "$ adb shell setprop libc.debug.malloc 1\n");
449 fprintf(fp, "$ adb shell stop\n");
450 fprintf(fp, "$ adb shell start\n");
451 return;
452 }
453 assert(infoSize != 0);
454 assert(overallSize % infoSize == 0);
455
456 fprintf(fp, "Android Native Heap Dump v1.0\n\n");
457
458 size_t recordCount = overallSize / infoSize;
459 fprintf(fp, "Total memory: %zu\n", totalMemory);
460 fprintf(fp, "Allocation records: %zd\n", recordCount);
461 if (backtraceSize != BACKTRACE_SIZE) {
462 fprintf(fp, "WARNING: mismatched backtrace sizes (%d vs. %d)\n",
463 backtraceSize, BACKTRACE_SIZE);
464 }
465 fprintf(fp, "\n");
466
467 /* re-sort the entries */
468 qsort(info, recordCount, infoSize, compareHeapRecords);
469
470 /* dump the entries to the file */
471 const uint8_t* ptr = info;
472 for (size_t idx = 0; idx < recordCount; idx++) {
473 size_t size = *(size_t*) ptr;
474 size_t allocations = *(size_t*) (ptr + sizeof(size_t));
475 intptr_t* backtrace = (intptr_t*) (ptr + sizeof(size_t) * 2);
476
477 fprintf(fp, "z %d sz %8zu num %4zu bt",
478 (size & SIZE_FLAG_ZYGOTE_CHILD) != 0,
479 size & ~SIZE_FLAG_ZYGOTE_CHILD,
480 allocations);
481 for (size_t bt = 0; bt < backtraceSize; bt++) {
482 if (backtrace[bt] == 0) {
483 break;
484 } else {
485 fprintf(fp, " %08x", backtrace[bt]);
486 }
487 }
488 fprintf(fp, "\n");
489
490 ptr += infoSize;
491 }
492
Andy McFadden06a6b552010-07-13 16:28:09 -0700493 free_malloc_leak_info(info);
Brian Carlstrom393b84c12010-10-17 23:40:43 -0700494
495 fprintf(fp, "MAPS\n");
496 const char* maps = "/proc/self/maps";
497 FILE* in = fopen(maps, "r");
498 if (in == NULL) {
499 fprintf(fp, "Could not open %s\n", maps);
500 return;
501 }
502 char buf[BUFSIZ];
503 while (size_t n = fread(buf, sizeof(char), BUFSIZ, in)) {
504 fwrite(buf, sizeof(char), n, fp);
505 }
506 fclose(in);
507
508 fprintf(fp, "END\n");
Andy McFadden06a6b552010-07-13 16:28:09 -0700509}
Andy McFadden06a6b552010-07-13 16:28:09 -0700510
511/*
512 * Dump the native heap, writing human-readable output to the specified
513 * file descriptor.
514 */
515static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject clazz,
516 jobject fileDescriptor)
517{
518 if (fileDescriptor == NULL) {
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800519 jniThrowNullPointerException(env, "fd == null");
Andy McFadden06a6b552010-07-13 16:28:09 -0700520 return;
521 }
522 int origFd = jniGetFDFromFileDescriptor(env, fileDescriptor);
523 if (origFd < 0) {
524 jniThrowRuntimeException(env, "Invalid file descriptor");
525 return;
526 }
527
528 /* dup() the descriptor so we don't close the original with fclose() */
529 int fd = dup(origFd);
530 if (fd < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000531 ALOGW("dup(%d) failed: %s\n", origFd, strerror(errno));
Andy McFadden06a6b552010-07-13 16:28:09 -0700532 jniThrowRuntimeException(env, "dup() failed");
533 return;
534 }
535
536 FILE* fp = fdopen(fd, "w");
537 if (fp == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000538 ALOGW("fdopen(%d) failed: %s\n", fd, strerror(errno));
Andy McFadden06a6b552010-07-13 16:28:09 -0700539 close(fd);
540 jniThrowRuntimeException(env, "fdopen() failed");
541 return;
542 }
543
Steve Block5baa3a62011-12-20 16:23:08 +0000544 ALOGD("Native heap dump starting...\n");
Andy McFadden06a6b552010-07-13 16:28:09 -0700545 dumpNativeHeap(fp);
Steve Block5baa3a62011-12-20 16:23:08 +0000546 ALOGD("Native heap dump complete.\n");
Andy McFadden06a6b552010-07-13 16:28:09 -0700547
548 fclose(fp);
549}
550
551
Dianne Hackbornf72467a2012-06-08 17:23:59 -0700552static void android_os_Debug_dumpNativeBacktraceToFile(JNIEnv* env, jobject clazz,
553 jint pid, jstring fileName)
554{
555 if (fileName == NULL) {
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800556 jniThrowNullPointerException(env, "file == null");
Dianne Hackbornf72467a2012-06-08 17:23:59 -0700557 return;
558 }
559 const jchar* str = env->GetStringCritical(fileName, 0);
560 String8 fileName8;
561 if (str) {
562 fileName8 = String8(str, env->GetStringLength(fileName));
563 env->ReleaseStringCritical(fileName, str);
564 }
565
566 int fd = open(fileName8.string(), O_CREAT | O_WRONLY | O_NOFOLLOW, 0666); /* -rw-rw-rw- */
567 if (fd < 0) {
568 fprintf(stderr, "Can't open %s: %s\n", fileName8.string(), strerror(errno));
569 return;
570 }
571
572 if (lseek(fd, 0, SEEK_END) < 0) {
573 fprintf(stderr, "lseek: %s\n", strerror(errno));
574 } else {
575 dump_backtrace_to_file(pid, fd);
576 }
577
578 close(fd);
579}
580
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581/*
582 * JNI registration.
583 */
584
585static JNINativeMethod gMethods[] = {
586 { "getNativeHeapSize", "()J",
587 (void*) android_os_Debug_getNativeHeapSize },
588 { "getNativeHeapAllocatedSize", "()J",
589 (void*) android_os_Debug_getNativeHeapAllocatedSize },
590 { "getNativeHeapFreeSize", "()J",
591 (void*) android_os_Debug_getNativeHeapFreeSize },
592 { "getMemoryInfo", "(Landroid/os/Debug$MemoryInfo;)V",
593 (void*) android_os_Debug_getDirtyPages },
Dianne Hackborn3025ef32009-08-31 21:31:47 -0700594 { "getMemoryInfo", "(ILandroid/os/Debug$MemoryInfo;)V",
595 (void*) android_os_Debug_getDirtyPagesPid },
Dianne Hackbornb437e092011-08-05 17:50:29 -0700596 { "getPss", "()J",
597 (void*) android_os_Debug_getPss },
598 { "getPss", "(I)J",
599 (void*) android_os_Debug_getPssPid },
Andy McFadden06a6b552010-07-13 16:28:09 -0700600 { "dumpNativeHeap", "(Ljava/io/FileDescriptor;)V",
601 (void*) android_os_Debug_dumpNativeHeap },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 { "getBinderSentTransactions", "()I",
603 (void*) android_os_Debug_getBinderSentTransactions },
604 { "getBinderReceivedTransactions", "()I",
605 (void*) android_os_getBinderReceivedTransactions },
606 { "getBinderLocalObjectCount", "()I",
607 (void*)android_os_Debug_getLocalObjectCount },
608 { "getBinderProxyObjectCount", "()I",
609 (void*)android_os_Debug_getProxyObjectCount },
610 { "getBinderDeathObjectCount", "()I",
611 (void*)android_os_Debug_getDeathObjectCount },
Dianne Hackbornf72467a2012-06-08 17:23:59 -0700612 { "dumpNativeBacktraceToFile", "(ILjava/lang/String;)V",
613 (void*)android_os_Debug_dumpNativeBacktraceToFile },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614};
615
616int register_android_os_Debug(JNIEnv *env)
617{
618 jclass clazz = env->FindClass("android/os/Debug$MemoryInfo");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800620 // Sanity check the number of other statistics expected in Java matches here.
621 jfieldID numOtherStats_field = env->GetStaticFieldID(clazz, "NUM_OTHER_STATS", "I");
622 jint numOtherStats = env->GetStaticIntField(clazz, numOtherStats_field);
623 int expectedNumOtherStats = _NUM_HEAP - _NUM_CORE_HEAP;
624 if (numOtherStats != expectedNumOtherStats) {
625 jniThrowExceptionFmt(env, "java/lang/RuntimeException",
626 "android.os.Debug.Meminfo.NUM_OTHER_STATS=%d expected %d",
627 numOtherStats, expectedNumOtherStats);
628 return JNI_ERR;
629 }
630
631 otherStats_field = env->GetFieldID(clazz, "otherStats", "[I");
632
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700633 for (int i=0; i<_NUM_CORE_HEAP; i++) {
634 stat_fields[i].pss_field =
635 env->GetFieldID(clazz, stat_field_names[i].pss_name, "I");
636 stat_fields[i].privateDirty_field =
637 env->GetFieldID(clazz, stat_field_names[i].privateDirty_name, "I");
638 stat_fields[i].sharedDirty_field =
639 env->GetFieldID(clazz, stat_field_names[i].sharedDirty_name, "I");
640 }
641
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642 return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods));
643}
644
Andy McFadden06a6b552010-07-13 16:28:09 -0700645}; // namespace android