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