Home | History | Annotate | Download | only in jni
      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 <atomic>
     33 #include <iomanip>
     34 #include <string>
     35 
     36 #include <android-base/stringprintf.h>
     37 #include <android-base/unique_fd.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/JNIHelp.h>
     44 #include <nativehelper/ScopedUtfChars.h>
     45 #include "jni.h"
     46 #include <memtrack/memtrack.h>
     47 #include <memunreachable/memunreachable.h>
     48 #include "android_os_Debug.h"
     49 
     50 namespace android
     51 {
     52 
     53 static inline UniqueFile MakeUniqueFile(const char* path, const char* mode) {
     54     return UniqueFile(fopen(path, mode), safeFclose);
     55 }
     56 
     57 enum {
     58     HEAP_UNKNOWN,
     59     HEAP_DALVIK,
     60     HEAP_NATIVE,
     61 
     62     HEAP_DALVIK_OTHER,
     63     HEAP_STACK,
     64     HEAP_CURSOR,
     65     HEAP_ASHMEM,
     66     HEAP_GL_DEV,
     67     HEAP_UNKNOWN_DEV,
     68     HEAP_SO,
     69     HEAP_JAR,
     70     HEAP_APK,
     71     HEAP_TTF,
     72     HEAP_DEX,
     73     HEAP_OAT,
     74     HEAP_ART,
     75     HEAP_UNKNOWN_MAP,
     76     HEAP_GRAPHICS,
     77     HEAP_GL,
     78     HEAP_OTHER_MEMTRACK,
     79 
     80     // Dalvik extra sections (heap).
     81     HEAP_DALVIK_NORMAL,
     82     HEAP_DALVIK_LARGE,
     83     HEAP_DALVIK_ZYGOTE,
     84     HEAP_DALVIK_NON_MOVING,
     85 
     86     // Dalvik other extra sections.
     87     HEAP_DALVIK_OTHER_LINEARALLOC,
     88     HEAP_DALVIK_OTHER_ACCOUNTING,
     89     HEAP_DALVIK_OTHER_CODE_CACHE,
     90     HEAP_DALVIK_OTHER_COMPILER_METADATA,
     91     HEAP_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE,
     92 
     93     // Boot vdex / app dex / app vdex
     94     HEAP_DEX_BOOT_VDEX,
     95     HEAP_DEX_APP_DEX,
     96     HEAP_DEX_APP_VDEX,
     97 
     98     // App art, boot art.
     99     HEAP_ART_APP,
    100     HEAP_ART_BOOT,
    101 
    102     _NUM_HEAP,
    103     _NUM_EXCLUSIVE_HEAP = HEAP_OTHER_MEMTRACK+1,
    104     _NUM_CORE_HEAP = HEAP_NATIVE+1
    105 };
    106 
    107 struct stat_fields {
    108     jfieldID pss_field;
    109     jfieldID pssSwappable_field;
    110     jfieldID rss_field;
    111     jfieldID privateDirty_field;
    112     jfieldID sharedDirty_field;
    113     jfieldID privateClean_field;
    114     jfieldID sharedClean_field;
    115     jfieldID swappedOut_field;
    116     jfieldID swappedOutPss_field;
    117 };
    118 
    119 struct stat_field_names {
    120     const char* pss_name;
    121     const char* pssSwappable_name;
    122     const char* rss_name;
    123     const char* privateDirty_name;
    124     const char* sharedDirty_name;
    125     const char* privateClean_name;
    126     const char* sharedClean_name;
    127     const char* swappedOut_name;
    128     const char* swappedOutPss_name;
    129 };
    130 
    131 static stat_fields stat_fields[_NUM_CORE_HEAP];
    132 
    133 static stat_field_names stat_field_names[_NUM_CORE_HEAP] = {
    134     { "otherPss", "otherSwappablePss", "otherRss", "otherPrivateDirty", "otherSharedDirty",
    135         "otherPrivateClean", "otherSharedClean", "otherSwappedOut", "otherSwappedOutPss" },
    136     { "dalvikPss", "dalvikSwappablePss", "dalvikRss", "dalvikPrivateDirty", "dalvikSharedDirty",
    137         "dalvikPrivateClean", "dalvikSharedClean", "dalvikSwappedOut", "dalvikSwappedOutPss" },
    138     { "nativePss", "nativeSwappablePss", "nativeRss", "nativePrivateDirty", "nativeSharedDirty",
    139         "nativePrivateClean", "nativeSharedClean", "nativeSwappedOut", "nativeSwappedOutPss" }
    140 };
    141 
    142 jfieldID otherStats_field;
    143 jfieldID hasSwappedOutPss_field;
    144 
    145 struct stats_t {
    146     int pss;
    147     int swappablePss;
    148     int rss;
    149     int privateDirty;
    150     int sharedDirty;
    151     int privateClean;
    152     int sharedClean;
    153     int swappedOut;
    154     int swappedOutPss;
    155 };
    156 
    157 enum pss_rollup_support {
    158   PSS_ROLLUP_UNTRIED,
    159   PSS_ROLLUP_SUPPORTED,
    160   PSS_ROLLUP_UNSUPPORTED
    161 };
    162 
    163 static std::atomic<pss_rollup_support> g_pss_rollup_support;
    164 
    165 #define BINDER_STATS "/proc/binder/stats"
    166 
    167 static jlong android_os_Debug_getNativeHeapSize(JNIEnv *env, jobject clazz)
    168 {
    169     struct mallinfo info = mallinfo();
    170     return (jlong) info.usmblks;
    171 }
    172 
    173 static jlong android_os_Debug_getNativeHeapAllocatedSize(JNIEnv *env, jobject clazz)
    174 {
    175     struct mallinfo info = mallinfo();
    176     return (jlong) info.uordblks;
    177 }
    178 
    179 static jlong android_os_Debug_getNativeHeapFreeSize(JNIEnv *env, jobject clazz)
    180 {
    181     struct mallinfo info = mallinfo();
    182     return (jlong) info.fordblks;
    183 }
    184 
    185 // Container used to retrieve graphics memory pss
    186 struct graphics_memory_pss
    187 {
    188     int graphics;
    189     int gl;
    190     int other;
    191 };
    192 
    193 /*
    194  * Uses libmemtrack to retrieve graphics memory that the process is using.
    195  * Any graphics memory reported in /proc/pid/smaps is not included here.
    196  */
    197 static int read_memtrack_memory(struct memtrack_proc* p, int pid,
    198         struct graphics_memory_pss* graphics_mem)
    199 {
    200     int err = memtrack_proc_get(p, pid);
    201     if (err != 0) {
    202         ALOGW("failed to get memory consumption info: %d", err);
    203         return err;
    204     }
    205 
    206     ssize_t pss = memtrack_proc_graphics_pss(p);
    207     if (pss < 0) {
    208         ALOGW("failed to get graphics pss: %zd", pss);
    209         return pss;
    210     }
    211     graphics_mem->graphics = pss / 1024;
    212 
    213     pss = memtrack_proc_gl_pss(p);
    214     if (pss < 0) {
    215         ALOGW("failed to get gl pss: %zd", pss);
    216         return pss;
    217     }
    218     graphics_mem->gl = pss / 1024;
    219 
    220     pss = memtrack_proc_other_pss(p);
    221     if (pss < 0) {
    222         ALOGW("failed to get other pss: %zd", pss);
    223         return pss;
    224     }
    225     graphics_mem->other = pss / 1024;
    226 
    227     return 0;
    228 }
    229 
    230 /*
    231  * Retrieves the graphics memory that is unaccounted for in /proc/pid/smaps.
    232  */
    233 static int read_memtrack_memory(int pid, struct graphics_memory_pss* graphics_mem)
    234 {
    235     struct memtrack_proc* p = memtrack_proc_new();
    236     if (p == NULL) {
    237         ALOGW("failed to create memtrack_proc");
    238         return -1;
    239     }
    240 
    241     int err = read_memtrack_memory(p, pid, graphics_mem);
    242     memtrack_proc_destroy(p);
    243     return err;
    244 }
    245 
    246 static void read_mapinfo(FILE *fp, stats_t* stats, bool* foundSwapPss)
    247 {
    248     char line[1024];
    249     int len, nameLen;
    250     bool skip, done = false;
    251 
    252     unsigned pss = 0, swappable_pss = 0, rss = 0;
    253     float sharing_proportion = 0.0;
    254     unsigned shared_clean = 0, shared_dirty = 0;
    255     unsigned private_clean = 0, private_dirty = 0;
    256     unsigned swapped_out = 0, swapped_out_pss = 0;
    257     bool is_swappable = false;
    258     unsigned temp;
    259 
    260     uint64_t start;
    261     uint64_t end = 0;
    262     uint64_t prevEnd = 0;
    263     char* name;
    264     int name_pos;
    265 
    266     int whichHeap = HEAP_UNKNOWN;
    267     int subHeap = HEAP_UNKNOWN;
    268     int prevHeap = HEAP_UNKNOWN;
    269 
    270     *foundSwapPss = false;
    271 
    272     if(fgets(line, sizeof(line), fp) == 0) return;
    273 
    274     while (!done) {
    275         prevHeap = whichHeap;
    276         prevEnd = end;
    277         whichHeap = HEAP_UNKNOWN;
    278         subHeap = HEAP_UNKNOWN;
    279         skip = false;
    280         is_swappable = false;
    281 
    282         len = strlen(line);
    283         if (len < 1) return;
    284         line[--len] = 0;
    285 
    286         if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) {
    287             skip = true;
    288         } else {
    289             while (isspace(line[name_pos])) {
    290                 name_pos += 1;
    291             }
    292             name = line + name_pos;
    293             nameLen = strlen(name);
    294             // Trim the end of the line if it is " (deleted)".
    295             const char* deleted_str = " (deleted)";
    296             if (nameLen > (int)strlen(deleted_str) &&
    297                 strcmp(name+nameLen-strlen(deleted_str), deleted_str) == 0) {
    298                 nameLen -= strlen(deleted_str);
    299                 name[nameLen] = '\0';
    300             }
    301             if ((strstr(name, "[heap]") == name)) {
    302                 whichHeap = HEAP_NATIVE;
    303             } else if (strncmp(name, "[anon:libc_malloc]", 18) == 0) {
    304                 whichHeap = HEAP_NATIVE;
    305             } else if (strncmp(name, "[stack", 6) == 0) {
    306                 whichHeap = HEAP_STACK;
    307             } else if (nameLen > 3 && strcmp(name+nameLen-3, ".so") == 0) {
    308                 whichHeap = HEAP_SO;
    309                 is_swappable = true;
    310             } else if (nameLen > 4 && strcmp(name+nameLen-4, ".jar") == 0) {
    311                 whichHeap = HEAP_JAR;
    312                 is_swappable = true;
    313             } else if (nameLen > 4 && strcmp(name+nameLen-4, ".apk") == 0) {
    314                 whichHeap = HEAP_APK;
    315                 is_swappable = true;
    316             } else if (nameLen > 4 && strcmp(name+nameLen-4, ".ttf") == 0) {
    317                 whichHeap = HEAP_TTF;
    318                 is_swappable = true;
    319             } else if ((nameLen > 4 && strstr(name, ".dex") != NULL) ||
    320                        (nameLen > 5 && strcmp(name+nameLen-5, ".odex") == 0)) {
    321                 whichHeap = HEAP_DEX;
    322                 subHeap = HEAP_DEX_APP_DEX;
    323                 is_swappable = true;
    324             } else if (nameLen > 5 && strcmp(name+nameLen-5, ".vdex") == 0) {
    325                 whichHeap = HEAP_DEX;
    326                 // Handle system@framework@boot* and system/framework/boot*
    327                 if (strstr(name, "@boot") != NULL || strstr(name, "/boot") != NULL) {
    328                     subHeap = HEAP_DEX_BOOT_VDEX;
    329                 } else {
    330                     subHeap = HEAP_DEX_APP_VDEX;
    331                 }
    332                 is_swappable = true;
    333             } else if (nameLen > 4 && strcmp(name+nameLen-4, ".oat") == 0) {
    334                 whichHeap = HEAP_OAT;
    335                 is_swappable = true;
    336             } else if (nameLen > 4 && strcmp(name+nameLen-4, ".art") == 0) {
    337                 whichHeap = HEAP_ART;
    338                 // Handle system@framework@boot* and system/framework/boot*
    339                 if (strstr(name, "@boot") != NULL || strstr(name, "/boot") != NULL) {
    340                     subHeap = HEAP_ART_BOOT;
    341                 } else {
    342                     subHeap = HEAP_ART_APP;
    343                 }
    344                 is_swappable = true;
    345             } else if (strncmp(name, "/dev/", 5) == 0) {
    346                 if (strncmp(name, "/dev/kgsl-3d0", 13) == 0) {
    347                     whichHeap = HEAP_GL_DEV;
    348                 } else if (strncmp(name, "/dev/ashmem", 11) == 0) {
    349                     if (strncmp(name, "/dev/ashmem/dalvik-", 19) == 0) {
    350                         whichHeap = HEAP_DALVIK_OTHER;
    351                         if (strstr(name, "/dev/ashmem/dalvik-LinearAlloc") == name) {
    352                             subHeap = HEAP_DALVIK_OTHER_LINEARALLOC;
    353                         } else if ((strstr(name, "/dev/ashmem/dalvik-alloc space") == name) ||
    354                                    (strstr(name, "/dev/ashmem/dalvik-main space") == name)) {
    355                             // This is the regular Dalvik heap.
    356                             whichHeap = HEAP_DALVIK;
    357                             subHeap = HEAP_DALVIK_NORMAL;
    358                         } else if (strstr(name, "/dev/ashmem/dalvik-large object space") == name ||
    359                                    strstr(name, "/dev/ashmem/dalvik-free list large object space")
    360                                        == name) {
    361                             whichHeap = HEAP_DALVIK;
    362                             subHeap = HEAP_DALVIK_LARGE;
    363                         } else if (strstr(name, "/dev/ashmem/dalvik-non moving space") == name) {
    364                             whichHeap = HEAP_DALVIK;
    365                             subHeap = HEAP_DALVIK_NON_MOVING;
    366                         } else if (strstr(name, "/dev/ashmem/dalvik-zygote space") == name) {
    367                             whichHeap = HEAP_DALVIK;
    368                             subHeap = HEAP_DALVIK_ZYGOTE;
    369                         } else if (strstr(name, "/dev/ashmem/dalvik-indirect ref") == name) {
    370                             subHeap = HEAP_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE;
    371                         } else if (strstr(name, "/dev/ashmem/dalvik-jit-code-cache") == name ||
    372                                    strstr(name, "/dev/ashmem/dalvik-data-code-cache") == name) {
    373                             subHeap = HEAP_DALVIK_OTHER_CODE_CACHE;
    374                         } else if (strstr(name, "/dev/ashmem/dalvik-CompilerMetadata") == name) {
    375                             subHeap = HEAP_DALVIK_OTHER_COMPILER_METADATA;
    376                         } else {
    377                             subHeap = HEAP_DALVIK_OTHER_ACCOUNTING;  // Default to accounting.
    378                         }
    379                     } else if (strncmp(name, "/dev/ashmem/CursorWindow", 24) == 0) {
    380                         whichHeap = HEAP_CURSOR;
    381                     } else if (strncmp(name, "/dev/ashmem/libc malloc", 23) == 0) {
    382                         whichHeap = HEAP_NATIVE;
    383                     } else {
    384                         whichHeap = HEAP_ASHMEM;
    385                     }
    386                 } else {
    387                     whichHeap = HEAP_UNKNOWN_DEV;
    388                 }
    389             } else if (strncmp(name, "[anon:", 6) == 0) {
    390                 whichHeap = HEAP_UNKNOWN;
    391             } else if (nameLen > 0) {
    392                 whichHeap = HEAP_UNKNOWN_MAP;
    393             } else if (start == prevEnd && prevHeap == HEAP_SO) {
    394                 // bss section of a shared library.
    395                 whichHeap = HEAP_SO;
    396             }
    397         }
    398 
    399         //ALOGI("native=%d dalvik=%d sqlite=%d: %s\n", isNativeHeap, isDalvikHeap,
    400         //    isSqliteHeap, line);
    401 
    402         shared_clean = 0;
    403         shared_dirty = 0;
    404         private_clean = 0;
    405         private_dirty = 0;
    406         swapped_out = 0;
    407         swapped_out_pss = 0;
    408 
    409         while (true) {
    410             if (fgets(line, 1024, fp) == 0) {
    411                 done = true;
    412                 break;
    413             }
    414 
    415             if (line[0] == 'S' && sscanf(line, "Size: %d kB", &temp) == 1) {
    416                 /* size = temp; */
    417             } else if (line[0] == 'R' && sscanf(line, "Rss: %d kB", &temp) == 1) {
    418                 rss = temp;
    419             } else if (line[0] == 'P' && sscanf(line, "Pss: %d kB", &temp) == 1) {
    420                 pss = temp;
    421             } else if (line[0] == 'S' && sscanf(line, "Shared_Clean: %d kB", &temp) == 1) {
    422                 shared_clean = temp;
    423             } else if (line[0] == 'S' && sscanf(line, "Shared_Dirty: %d kB", &temp) == 1) {
    424                 shared_dirty = temp;
    425             } else if (line[0] == 'P' && sscanf(line, "Private_Clean: %d kB", &temp) == 1) {
    426                 private_clean = temp;
    427             } else if (line[0] == 'P' && sscanf(line, "Private_Dirty: %d kB", &temp) == 1) {
    428                 private_dirty = temp;
    429             } else if (line[0] == 'R' && sscanf(line, "Referenced: %d kB", &temp) == 1) {
    430                 /* referenced = temp; */
    431             } else if (line[0] == 'S' && sscanf(line, "Swap: %d kB", &temp) == 1) {
    432                 swapped_out = temp;
    433             } else if (line[0] == 'S' && sscanf(line, "SwapPss: %d kB", &temp) == 1) {
    434                 *foundSwapPss = true;
    435                 swapped_out_pss = temp;
    436             } else if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %*s %*x %*x:%*x %*d", &start, &end) == 2) {
    437                 // looks like a new mapping
    438                 // example: "10000000-10001000 ---p 10000000 00:00 0"
    439                 break;
    440             }
    441         }
    442 
    443         if (!skip) {
    444             if (is_swappable && (pss > 0)) {
    445                 sharing_proportion = 0.0;
    446                 if ((shared_clean > 0) || (shared_dirty > 0)) {
    447                     sharing_proportion = (pss - private_clean
    448                             - private_dirty)/(shared_clean+shared_dirty);
    449                 }
    450                 swappable_pss = (sharing_proportion*shared_clean) + private_clean;
    451             } else
    452                 swappable_pss = 0;
    453 
    454             stats[whichHeap].pss += pss;
    455             stats[whichHeap].swappablePss += swappable_pss;
    456             stats[whichHeap].rss += rss;
    457             stats[whichHeap].privateDirty += private_dirty;
    458             stats[whichHeap].sharedDirty += shared_dirty;
    459             stats[whichHeap].privateClean += private_clean;
    460             stats[whichHeap].sharedClean += shared_clean;
    461             stats[whichHeap].swappedOut += swapped_out;
    462             stats[whichHeap].swappedOutPss += swapped_out_pss;
    463             if (whichHeap == HEAP_DALVIK || whichHeap == HEAP_DALVIK_OTHER ||
    464                     whichHeap == HEAP_DEX || whichHeap == HEAP_ART) {
    465                 stats[subHeap].pss += pss;
    466                 stats[subHeap].swappablePss += swappable_pss;
    467                 stats[subHeap].rss += rss;
    468                 stats[subHeap].privateDirty += private_dirty;
    469                 stats[subHeap].sharedDirty += shared_dirty;
    470                 stats[subHeap].privateClean += private_clean;
    471                 stats[subHeap].sharedClean += shared_clean;
    472                 stats[subHeap].swappedOut += swapped_out;
    473                 stats[subHeap].swappedOutPss += swapped_out_pss;
    474             }
    475         }
    476     }
    477 }
    478 
    479 static void load_maps(int pid, stats_t* stats, bool* foundSwapPss)
    480 {
    481     *foundSwapPss = false;
    482 
    483     std::string smaps_path = base::StringPrintf("/proc/%d/smaps", pid);
    484     UniqueFile fp = MakeUniqueFile(smaps_path.c_str(), "re");
    485     if (fp == nullptr) return;
    486 
    487     read_mapinfo(fp.get(), stats, foundSwapPss);
    488 }
    489 
    490 static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
    491         jint pid, jobject object)
    492 {
    493     bool foundSwapPss;
    494     stats_t stats[_NUM_HEAP];
    495     memset(&stats, 0, sizeof(stats));
    496 
    497     load_maps(pid, stats, &foundSwapPss);
    498 
    499     struct graphics_memory_pss graphics_mem;
    500     if (read_memtrack_memory(pid, &graphics_mem) == 0) {
    501         stats[HEAP_GRAPHICS].pss = graphics_mem.graphics;
    502         stats[HEAP_GRAPHICS].privateDirty = graphics_mem.graphics;
    503         stats[HEAP_GRAPHICS].rss = graphics_mem.graphics;
    504         stats[HEAP_GL].pss = graphics_mem.gl;
    505         stats[HEAP_GL].privateDirty = graphics_mem.gl;
    506         stats[HEAP_GL].rss = graphics_mem.gl;
    507         stats[HEAP_OTHER_MEMTRACK].pss = graphics_mem.other;
    508         stats[HEAP_OTHER_MEMTRACK].privateDirty = graphics_mem.other;
    509         stats[HEAP_OTHER_MEMTRACK].rss = graphics_mem.other;
    510     }
    511 
    512     for (int i=_NUM_CORE_HEAP; i<_NUM_EXCLUSIVE_HEAP; i++) {
    513         stats[HEAP_UNKNOWN].pss += stats[i].pss;
    514         stats[HEAP_UNKNOWN].swappablePss += stats[i].swappablePss;
    515         stats[HEAP_UNKNOWN].rss += stats[i].rss;
    516         stats[HEAP_UNKNOWN].privateDirty += stats[i].privateDirty;
    517         stats[HEAP_UNKNOWN].sharedDirty += stats[i].sharedDirty;
    518         stats[HEAP_UNKNOWN].privateClean += stats[i].privateClean;
    519         stats[HEAP_UNKNOWN].sharedClean += stats[i].sharedClean;
    520         stats[HEAP_UNKNOWN].swappedOut += stats[i].swappedOut;
    521         stats[HEAP_UNKNOWN].swappedOutPss += stats[i].swappedOutPss;
    522     }
    523 
    524     for (int i=0; i<_NUM_CORE_HEAP; i++) {
    525         env->SetIntField(object, stat_fields[i].pss_field, stats[i].pss);
    526         env->SetIntField(object, stat_fields[i].pssSwappable_field, stats[i].swappablePss);
    527         env->SetIntField(object, stat_fields[i].rss_field, stats[i].rss);
    528         env->SetIntField(object, stat_fields[i].privateDirty_field, stats[i].privateDirty);
    529         env->SetIntField(object, stat_fields[i].sharedDirty_field, stats[i].sharedDirty);
    530         env->SetIntField(object, stat_fields[i].privateClean_field, stats[i].privateClean);
    531         env->SetIntField(object, stat_fields[i].sharedClean_field, stats[i].sharedClean);
    532         env->SetIntField(object, stat_fields[i].swappedOut_field, stats[i].swappedOut);
    533         env->SetIntField(object, stat_fields[i].swappedOutPss_field, stats[i].swappedOutPss);
    534     }
    535 
    536 
    537     env->SetBooleanField(object, hasSwappedOutPss_field, foundSwapPss);
    538     jintArray otherIntArray = (jintArray)env->GetObjectField(object, otherStats_field);
    539 
    540     jint* otherArray = (jint*)env->GetPrimitiveArrayCritical(otherIntArray, 0);
    541     if (otherArray == NULL) {
    542         return;
    543     }
    544 
    545     int j=0;
    546     for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
    547         otherArray[j++] = stats[i].pss;
    548         otherArray[j++] = stats[i].swappablePss;
    549         otherArray[j++] = stats[i].rss;
    550         otherArray[j++] = stats[i].privateDirty;
    551         otherArray[j++] = stats[i].sharedDirty;
    552         otherArray[j++] = stats[i].privateClean;
    553         otherArray[j++] = stats[i].sharedClean;
    554         otherArray[j++] = stats[i].swappedOut;
    555         otherArray[j++] = stats[i].swappedOutPss;
    556     }
    557 
    558     env->ReleasePrimitiveArrayCritical(otherIntArray, otherArray, 0);
    559 }
    560 
    561 static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject object)
    562 {
    563     android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object);
    564 }
    565 
    566 UniqueFile OpenSmapsOrRollup(int pid)
    567 {
    568     enum pss_rollup_support rollup_support =
    569             g_pss_rollup_support.load(std::memory_order_relaxed);
    570     if (rollup_support != PSS_ROLLUP_UNSUPPORTED) {
    571         std::string smaps_rollup_path =
    572                 base::StringPrintf("/proc/%d/smaps_rollup", pid);
    573         UniqueFile fp_rollup = MakeUniqueFile(smaps_rollup_path.c_str(), "re");
    574         if (fp_rollup == nullptr && errno != ENOENT) {
    575             return fp_rollup;  // Actual error, not just old kernel.
    576         }
    577         if (fp_rollup != nullptr) {
    578             if (rollup_support == PSS_ROLLUP_UNTRIED) {
    579                 ALOGI("using rollup pss collection");
    580                 g_pss_rollup_support.store(PSS_ROLLUP_SUPPORTED,
    581                                            std::memory_order_relaxed);
    582             }
    583             return fp_rollup;
    584         }
    585         g_pss_rollup_support.store(PSS_ROLLUP_UNSUPPORTED,
    586                                    std::memory_order_relaxed);
    587     }
    588 
    589     std::string smaps_path = base::StringPrintf("/proc/%d/smaps", pid);
    590     return MakeUniqueFile(smaps_path.c_str(), "re");
    591 }
    592 
    593 static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid,
    594         jlongArray outUssSwapPssRss, jlongArray outMemtrack)
    595 {
    596     char lineBuffer[1024];
    597     jlong pss = 0;
    598     jlong rss = 0;
    599     jlong swapPss = 0;
    600     jlong uss = 0;
    601     jlong memtrack = 0;
    602 
    603     struct graphics_memory_pss graphics_mem;
    604     if (read_memtrack_memory(pid, &graphics_mem) == 0) {
    605         pss = uss = memtrack = graphics_mem.graphics + graphics_mem.gl + graphics_mem.other;
    606     }
    607 
    608     {
    609         UniqueFile fp = OpenSmapsOrRollup(pid);
    610 
    611         if (fp != nullptr) {
    612             char* line;
    613 
    614             while (true) {
    615                 if (fgets(lineBuffer, sizeof (lineBuffer), fp.get()) == NULL) {
    616                     break;
    617                 }
    618                 line = lineBuffer;
    619 
    620                 switch (line[0]) {
    621                     case 'P':
    622                         if (strncmp(line, "Pss:", 4) == 0) {
    623                             char* c = line + 4;
    624                             while (*c != 0 && (*c < '0' || *c > '9')) {
    625                                 c++;
    626                             }
    627                             pss += atoi(c);
    628                         } else if (strncmp(line, "Private_Clean:", 14) == 0
    629                                     || strncmp(line, "Private_Dirty:", 14) == 0) {
    630                             char* c = line + 14;
    631                             while (*c != 0 && (*c < '0' || *c > '9')) {
    632                                 c++;
    633                             }
    634                             uss += atoi(c);
    635                         }
    636                         break;
    637                     case 'R':
    638                         if (strncmp(line, "Rss:", 4) == 0) {
    639                             char* c = line + 4;
    640                             while (*c != 0 && (*c < '0' || *c > '9')) {
    641                                 c++;
    642                             }
    643                             rss += atoi(c);
    644                         }
    645                         break;
    646                     case 'S':
    647                         if (strncmp(line, "SwapPss:", 8) == 0) {
    648                             char* c = line + 8;
    649                             jlong lSwapPss;
    650                             while (*c != 0 && (*c < '0' || *c > '9')) {
    651                                 c++;
    652                             }
    653                             lSwapPss = atoi(c);
    654                             swapPss += lSwapPss;
    655                             pss += lSwapPss; // Also in swap, those pages would be accounted as Pss without SWAP
    656                         }
    657                         break;
    658                 }
    659             }
    660         }
    661     }
    662 
    663     if (outUssSwapPssRss != NULL) {
    664         if (env->GetArrayLength(outUssSwapPssRss) >= 1) {
    665             jlong* outUssSwapPssRssArray = env->GetLongArrayElements(outUssSwapPssRss, 0);
    666             if (outUssSwapPssRssArray != NULL) {
    667                 outUssSwapPssRssArray[0] = uss;
    668                 if (env->GetArrayLength(outUssSwapPssRss) >= 2) {
    669                     outUssSwapPssRssArray[1] = swapPss;
    670                 }
    671                 if (env->GetArrayLength(outUssSwapPssRss) >= 3) {
    672                     outUssSwapPssRssArray[2] = rss;
    673                 }
    674             }
    675             env->ReleaseLongArrayElements(outUssSwapPssRss, outUssSwapPssRssArray, 0);
    676         }
    677     }
    678 
    679     if (outMemtrack != NULL) {
    680         if (env->GetArrayLength(outMemtrack) >= 1) {
    681             jlong* outMemtrackArray = env->GetLongArrayElements(outMemtrack, 0);
    682             if (outMemtrackArray != NULL) {
    683                 outMemtrackArray[0] = memtrack;
    684             }
    685             env->ReleaseLongArrayElements(outMemtrack, outMemtrackArray, 0);
    686         }
    687     }
    688 
    689     return pss;
    690 }
    691 
    692 static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz)
    693 {
    694     return android_os_Debug_getPssPid(env, clazz, getpid(), NULL, NULL);
    695 }
    696 
    697 static long get_allocated_vmalloc_memory() {
    698     char line[1024];
    699     // Ignored tags that don't actually consume memory (ie remappings)
    700     static const char* const ignored_tags[] = {
    701             "ioremap",
    702             "map_lowmem",
    703             "vm_map_ram",
    704             NULL
    705     };
    706     long size, vmalloc_allocated_size = 0;
    707 
    708     UniqueFile fp = MakeUniqueFile("/proc/vmallocinfo", "re");
    709     if (fp == nullptr) {
    710         return 0;
    711     }
    712 
    713     while (true) {
    714         if (fgets(line, 1024, fp.get()) == NULL) {
    715             break;
    716         }
    717         bool valid_line = true;
    718         int i = 0;
    719         while (ignored_tags[i]) {
    720             if (strstr(line, ignored_tags[i]) != NULL) {
    721                 valid_line = false;
    722                 break;
    723             }
    724             i++;
    725         }
    726         if (valid_line && (sscanf(line, "%*x-%*x %ld", &size) == 1)) {
    727             vmalloc_allocated_size += size;
    728         }
    729     }
    730     return vmalloc_allocated_size;
    731 }
    732 
    733 enum {
    734     MEMINFO_TOTAL,
    735     MEMINFO_FREE,
    736     MEMINFO_BUFFERS,
    737     MEMINFO_CACHED,
    738     MEMINFO_SHMEM,
    739     MEMINFO_SLAB,
    740     MEMINFO_SLAB_RECLAIMABLE,
    741     MEMINFO_SLAB_UNRECLAIMABLE,
    742     MEMINFO_SWAP_TOTAL,
    743     MEMINFO_SWAP_FREE,
    744     MEMINFO_ZRAM_TOTAL,
    745     MEMINFO_MAPPED,
    746     MEMINFO_VMALLOC_USED,
    747     MEMINFO_PAGE_TABLES,
    748     MEMINFO_KERNEL_STACK,
    749     MEMINFO_COUNT
    750 };
    751 
    752 static long long get_zram_mem_used()
    753 {
    754 #define ZRAM_SYSFS "/sys/block/zram0/"
    755     UniqueFile mm_stat_file = MakeUniqueFile(ZRAM_SYSFS "mm_stat", "re");
    756     if (mm_stat_file) {
    757         long long mem_used_total = 0;
    758 
    759         int matched = fscanf(mm_stat_file.get(), "%*d %*d %lld %*d %*d %*d %*d", &mem_used_total);
    760         if (matched != 1)
    761             ALOGW("failed to parse " ZRAM_SYSFS "mm_stat");
    762 
    763         return mem_used_total;
    764     }
    765 
    766     UniqueFile mem_used_total_file = MakeUniqueFile(ZRAM_SYSFS "mem_used_total", "re");
    767     if (mem_used_total_file) {
    768         long long mem_used_total = 0;
    769 
    770         int matched = fscanf(mem_used_total_file.get(), "%lld", &mem_used_total);
    771         if (matched != 1)
    772             ALOGW("failed to parse " ZRAM_SYSFS "mem_used_total");
    773 
    774         return mem_used_total;
    775     }
    776 
    777     return 0;
    778 }
    779 
    780 static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray out)
    781 {
    782     char buffer[4096];
    783     size_t numFound = 0;
    784 
    785     if (out == NULL) {
    786         jniThrowNullPointerException(env, "out == null");
    787         return;
    788     }
    789 
    790     int fd = open("/proc/meminfo", O_RDONLY | O_CLOEXEC);
    791 
    792     if (fd < 0) {
    793         ALOGW("Unable to open /proc/meminfo: %s\n", strerror(errno));
    794         return;
    795     }
    796 
    797     int len = read(fd, buffer, sizeof(buffer)-1);
    798     close(fd);
    799 
    800     if (len < 0) {
    801         ALOGW("Empty /proc/meminfo");
    802         return;
    803     }
    804     buffer[len] = 0;
    805 
    806     static const char* const tags[] = {
    807             "MemTotal:",
    808             "MemFree:",
    809             "Buffers:",
    810             "Cached:",
    811             "Shmem:",
    812             "Slab:",
    813             "SReclaimable:",
    814             "SUnreclaim:",
    815             "SwapTotal:",
    816             "SwapFree:",
    817             "ZRam:",
    818             "Mapped:",
    819             "VmallocUsed:",
    820             "PageTables:",
    821             "KernelStack:",
    822             NULL
    823     };
    824     static const int tagsLen[] = {
    825             9,
    826             8,
    827             8,
    828             7,
    829             6,
    830             5,
    831             13,
    832             11,
    833             10,
    834             9,
    835             5,
    836             7,
    837             12,
    838             11,
    839             12,
    840             0
    841     };
    842     long mem[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    843 
    844     char* p = buffer;
    845     while (*p && numFound < (sizeof(tagsLen) / sizeof(tagsLen[0]))) {
    846         int i = 0;
    847         while (tags[i]) {
    848             if (strncmp(p, tags[i], tagsLen[i]) == 0) {
    849                 p += tagsLen[i];
    850                 while (*p == ' ') p++;
    851                 char* num = p;
    852                 while (*p >= '0' && *p <= '9') p++;
    853                 if (*p != 0) {
    854                     *p = 0;
    855                     p++;
    856                 }
    857                 mem[i] = atoll(num);
    858                 numFound++;
    859                 break;
    860             }
    861             i++;
    862         }
    863         while (*p && *p != '\n') {
    864             p++;
    865         }
    866         if (*p) p++;
    867     }
    868 
    869     mem[MEMINFO_ZRAM_TOTAL] = get_zram_mem_used() / 1024;
    870     // Recompute Vmalloc Used since the value in meminfo
    871     // doesn't account for I/O remapping which doesn't use RAM.
    872     mem[MEMINFO_VMALLOC_USED] = get_allocated_vmalloc_memory() / 1024;
    873 
    874     int maxNum = env->GetArrayLength(out);
    875     if (maxNum > MEMINFO_COUNT) {
    876         maxNum = MEMINFO_COUNT;
    877     }
    878     jlong* outArray = env->GetLongArrayElements(out, 0);
    879     if (outArray != NULL) {
    880         for (int i=0; i<maxNum; i++) {
    881             outArray[i] = mem[i];
    882         }
    883     }
    884     env->ReleaseLongArrayElements(out, outArray, 0);
    885 }
    886 
    887 
    888 static jint read_binder_stat(const char* stat)
    889 {
    890     UniqueFile fp = MakeUniqueFile(BINDER_STATS, "re");
    891     if (fp == nullptr) {
    892         return -1;
    893     }
    894 
    895     char line[1024];
    896 
    897     char compare[128];
    898     int len = snprintf(compare, 128, "proc %d", getpid());
    899 
    900     // loop until we have the block that represents this process
    901     do {
    902         if (fgets(line, 1024, fp.get()) == 0) {
    903             return -1;
    904         }
    905     } while (strncmp(compare, line, len));
    906 
    907     // now that we have this process, read until we find the stat that we are looking for
    908     len = snprintf(compare, 128, "  %s: ", stat);
    909 
    910     do {
    911         if (fgets(line, 1024, fp.get()) == 0) {
    912             return -1;
    913         }
    914     } while (strncmp(compare, line, len));
    915 
    916     // we have the line, now increment the line ptr to the value
    917     char* ptr = line + len;
    918     jint result = atoi(ptr);
    919     return result;
    920 }
    921 
    922 static jint android_os_Debug_getBinderSentTransactions(JNIEnv *env, jobject clazz)
    923 {
    924     return read_binder_stat("bcTRANSACTION");
    925 }
    926 
    927 static jint android_os_getBinderReceivedTransactions(JNIEnv *env, jobject clazz)
    928 {
    929     return read_binder_stat("brTRANSACTION");
    930 }
    931 
    932 // these are implemented in android_util_Binder.cpp
    933 jint android_os_Debug_getLocalObjectCount(JNIEnv* env, jobject clazz);
    934 jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz);
    935 jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz);
    936 
    937 
    938 /* pulled out of bionic */
    939 extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
    940     size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
    941 extern "C" void free_malloc_leak_info(uint8_t* info);
    942 #define SIZE_FLAG_ZYGOTE_CHILD  (1<<31)
    943 
    944 static size_t gNumBacktraceElements;
    945 
    946 /*
    947  * This is a qsort() callback.
    948  *
    949  * See dumpNativeHeap() for comments about the data format and sort order.
    950  */
    951 static int compareHeapRecords(const void* vrec1, const void* vrec2)
    952 {
    953     const size_t* rec1 = (const size_t*) vrec1;
    954     const size_t* rec2 = (const size_t*) vrec2;
    955     size_t size1 = *rec1;
    956     size_t size2 = *rec2;
    957 
    958     if (size1 < size2) {
    959         return 1;
    960     } else if (size1 > size2) {
    961         return -1;
    962     }
    963 
    964     uintptr_t* bt1 = (uintptr_t*)(rec1 + 2);
    965     uintptr_t* bt2 = (uintptr_t*)(rec2 + 2);
    966     for (size_t idx = 0; idx < gNumBacktraceElements; idx++) {
    967         uintptr_t addr1 = bt1[idx];
    968         uintptr_t addr2 = bt2[idx];
    969         if (addr1 == addr2) {
    970             if (addr1 == 0)
    971                 break;
    972             continue;
    973         }
    974         if (addr1 < addr2) {
    975             return -1;
    976         } else if (addr1 > addr2) {
    977             return 1;
    978         }
    979     }
    980 
    981     return 0;
    982 }
    983 
    984 /*
    985  * The get_malloc_leak_info() call returns an array of structs that
    986  * look like this:
    987  *
    988  *   size_t size
    989  *   size_t allocations
    990  *   intptr_t backtrace[32]
    991  *
    992  * "size" is the size of the allocation, "backtrace" is a fixed-size
    993  * array of function pointers, and "allocations" is the number of
    994  * allocations with the exact same size and backtrace.
    995  *
    996  * The entries are sorted by descending total size (i.e. size*allocations)
    997  * then allocation count.  For best results with "diff" we'd like to sort
    998  * primarily by individual size then stack trace.  Since the entries are
    999  * fixed-size, and we're allowed (by the current implementation) to mangle
   1000  * them, we can do this in place.
   1001  */
   1002 static void dumpNativeHeap(FILE* fp)
   1003 {
   1004     uint8_t* info = NULL;
   1005     size_t overallSize, infoSize, totalMemory, backtraceSize;
   1006 
   1007     get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory,
   1008         &backtraceSize);
   1009     if (info == NULL) {
   1010         fprintf(fp, "Native heap dump not available. To enable, run these"
   1011                     " commands (requires root):\n");
   1012         fprintf(fp, "# adb shell stop\n");
   1013         fprintf(fp, "# adb shell setprop libc.debug.malloc.options "
   1014                     "backtrace\n");
   1015         fprintf(fp, "# adb shell start\n");
   1016         return;
   1017     }
   1018     assert(infoSize != 0);
   1019     assert(overallSize % infoSize == 0);
   1020 
   1021     fprintf(fp, "Android Native Heap Dump v1.0\n\n");
   1022 
   1023     size_t recordCount = overallSize / infoSize;
   1024     fprintf(fp, "Total memory: %zu\n", totalMemory);
   1025     fprintf(fp, "Allocation records: %zd\n", recordCount);
   1026     fprintf(fp, "Backtrace size: %zd\n", backtraceSize);
   1027     fprintf(fp, "\n");
   1028 
   1029     /* re-sort the entries */
   1030     gNumBacktraceElements = backtraceSize;
   1031     qsort(info, recordCount, infoSize, compareHeapRecords);
   1032 
   1033     /* dump the entries to the file */
   1034     const uint8_t* ptr = info;
   1035     for (size_t idx = 0; idx < recordCount; idx++) {
   1036         size_t size = *(size_t*) ptr;
   1037         size_t allocations = *(size_t*) (ptr + sizeof(size_t));
   1038         uintptr_t* backtrace = (uintptr_t*) (ptr + sizeof(size_t) * 2);
   1039 
   1040         fprintf(fp, "z %d  sz %8zu  num %4zu  bt",
   1041                 (size & SIZE_FLAG_ZYGOTE_CHILD) != 0,
   1042                 size & ~SIZE_FLAG_ZYGOTE_CHILD,
   1043                 allocations);
   1044         for (size_t bt = 0; bt < backtraceSize; bt++) {
   1045             if (backtrace[bt] == 0) {
   1046                 break;
   1047             } else {
   1048 #ifdef __LP64__
   1049                 fprintf(fp, " %016" PRIxPTR, backtrace[bt]);
   1050 #else
   1051                 fprintf(fp, " %08" PRIxPTR, backtrace[bt]);
   1052 #endif
   1053             }
   1054         }
   1055         fprintf(fp, "\n");
   1056 
   1057         ptr += infoSize;
   1058     }
   1059 
   1060     free_malloc_leak_info(info);
   1061 
   1062     fprintf(fp, "MAPS\n");
   1063     const char* maps = "/proc/self/maps";
   1064     UniqueFile in = MakeUniqueFile(maps, "re");
   1065     if (in == nullptr) {
   1066         fprintf(fp, "Could not open %s\n", maps);
   1067         return;
   1068     }
   1069     char buf[BUFSIZ];
   1070     while (size_t n = fread(buf, sizeof(char), BUFSIZ, in.get())) {
   1071         fwrite(buf, sizeof(char), n, fp);
   1072     }
   1073 
   1074     fprintf(fp, "END\n");
   1075 }
   1076 
   1077 static bool openFile(JNIEnv* env, jobject fileDescriptor, UniqueFile& fp)
   1078 {
   1079     if (fileDescriptor == NULL) {
   1080         jniThrowNullPointerException(env, "fd == null");
   1081         return false;
   1082     }
   1083     int origFd = jniGetFDFromFileDescriptor(env, fileDescriptor);
   1084     if (origFd < 0) {
   1085         jniThrowRuntimeException(env, "Invalid file descriptor");
   1086         return false;
   1087     }
   1088 
   1089     /* dup() the descriptor so we don't close the original with fclose() */
   1090     int fd = dup(origFd);
   1091     if (fd < 0) {
   1092         ALOGW("dup(%d) failed: %s\n", origFd, strerror(errno));
   1093         jniThrowRuntimeException(env, "dup() failed");
   1094         return false;
   1095     }
   1096 
   1097     fp.reset(fdopen(fd, "w"));
   1098     if (fp == nullptr) {
   1099         ALOGW("fdopen(%d) failed: %s\n", fd, strerror(errno));
   1100         close(fd);
   1101         jniThrowRuntimeException(env, "fdopen() failed");
   1102         return false;
   1103     }
   1104     return true;
   1105 }
   1106 
   1107 /*
   1108  * Dump the native heap, writing human-readable output to the specified
   1109  * file descriptor.
   1110  */
   1111 static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject,
   1112     jobject fileDescriptor)
   1113 {
   1114     UniqueFile fp(nullptr, safeFclose);
   1115     if (!openFile(env, fileDescriptor, fp)) {
   1116         return;
   1117     }
   1118 
   1119     ALOGD("Native heap dump starting...\n");
   1120     dumpNativeHeap(fp.get());
   1121     ALOGD("Native heap dump complete.\n");
   1122 }
   1123 
   1124 /*
   1125  * Dump the native malloc info, writing xml output to the specified
   1126  * file descriptor.
   1127  */
   1128 static void android_os_Debug_dumpNativeMallocInfo(JNIEnv* env, jobject,
   1129     jobject fileDescriptor)
   1130 {
   1131     UniqueFile fp(nullptr, safeFclose);
   1132     if (!openFile(env, fileDescriptor, fp)) {
   1133         return;
   1134     }
   1135 
   1136     malloc_info(0, fp.get());
   1137 }
   1138 
   1139 static bool dumpTraces(JNIEnv* env, jint pid, jstring fileName, jint timeoutSecs,
   1140                        DebuggerdDumpType dumpType) {
   1141     const ScopedUtfChars fileNameChars(env, fileName);
   1142     if (fileNameChars.c_str() == nullptr) {
   1143         return false;
   1144     }
   1145 
   1146     android::base::unique_fd fd(open(fileNameChars.c_str(),
   1147                                      O_CREAT | O_WRONLY | O_NOFOLLOW | O_CLOEXEC | O_APPEND,
   1148                                      0666));
   1149     if (fd < 0) {
   1150         fprintf(stderr, "Can't open %s: %s\n", fileNameChars.c_str(), strerror(errno));
   1151         return false;
   1152     }
   1153 
   1154     return (dump_backtrace_to_file_timeout(pid, dumpType, timeoutSecs, fd) == 0);
   1155 }
   1156 
   1157 static jboolean android_os_Debug_dumpJavaBacktraceToFileTimeout(JNIEnv* env, jobject clazz,
   1158         jint pid, jstring fileName, jint timeoutSecs) {
   1159     const bool ret =  dumpTraces(env, pid, fileName, timeoutSecs, kDebuggerdJavaBacktrace);
   1160     return ret ? JNI_TRUE : JNI_FALSE;
   1161 }
   1162 
   1163 static jboolean android_os_Debug_dumpNativeBacktraceToFileTimeout(JNIEnv* env, jobject clazz,
   1164         jint pid, jstring fileName, jint timeoutSecs) {
   1165     const bool ret = dumpTraces(env, pid, fileName, timeoutSecs, kDebuggerdNativeBacktrace);
   1166     return ret ? JNI_TRUE : JNI_FALSE;
   1167 }
   1168 
   1169 static jstring android_os_Debug_getUnreachableMemory(JNIEnv* env, jobject clazz,
   1170     jint limit, jboolean contents)
   1171 {
   1172     std::string s = GetUnreachableMemoryString(contents, limit);
   1173     return env->NewStringUTF(s.c_str());
   1174 }
   1175 
   1176 /*
   1177  * JNI registration.
   1178  */
   1179 
   1180 static const JNINativeMethod gMethods[] = {
   1181     { "getNativeHeapSize",      "()J",
   1182             (void*) android_os_Debug_getNativeHeapSize },
   1183     { "getNativeHeapAllocatedSize", "()J",
   1184             (void*) android_os_Debug_getNativeHeapAllocatedSize },
   1185     { "getNativeHeapFreeSize",  "()J",
   1186             (void*) android_os_Debug_getNativeHeapFreeSize },
   1187     { "getMemoryInfo",          "(Landroid/os/Debug$MemoryInfo;)V",
   1188             (void*) android_os_Debug_getDirtyPages },
   1189     { "getMemoryInfo",          "(ILandroid/os/Debug$MemoryInfo;)V",
   1190             (void*) android_os_Debug_getDirtyPagesPid },
   1191     { "getPss",                 "()J",
   1192             (void*) android_os_Debug_getPss },
   1193     { "getPss",                 "(I[J[J)J",
   1194             (void*) android_os_Debug_getPssPid },
   1195     { "getMemInfo",             "([J)V",
   1196             (void*) android_os_Debug_getMemInfo },
   1197     { "dumpNativeHeap",         "(Ljava/io/FileDescriptor;)V",
   1198             (void*) android_os_Debug_dumpNativeHeap },
   1199     { "dumpNativeMallocInfo",   "(Ljava/io/FileDescriptor;)V",
   1200             (void*) android_os_Debug_dumpNativeMallocInfo },
   1201     { "getBinderSentTransactions", "()I",
   1202             (void*) android_os_Debug_getBinderSentTransactions },
   1203     { "getBinderReceivedTransactions", "()I",
   1204             (void*) android_os_getBinderReceivedTransactions },
   1205     { "getBinderLocalObjectCount", "()I",
   1206             (void*)android_os_Debug_getLocalObjectCount },
   1207     { "getBinderProxyObjectCount", "()I",
   1208             (void*)android_os_Debug_getProxyObjectCount },
   1209     { "getBinderDeathObjectCount", "()I",
   1210             (void*)android_os_Debug_getDeathObjectCount },
   1211     { "dumpJavaBacktraceToFileTimeout", "(ILjava/lang/String;I)Z",
   1212             (void*)android_os_Debug_dumpJavaBacktraceToFileTimeout },
   1213     { "dumpNativeBacktraceToFileTimeout", "(ILjava/lang/String;I)Z",
   1214             (void*)android_os_Debug_dumpNativeBacktraceToFileTimeout },
   1215     { "getUnreachableMemory", "(IZ)Ljava/lang/String;",
   1216             (void*)android_os_Debug_getUnreachableMemory },
   1217 };
   1218 
   1219 int register_android_os_Debug(JNIEnv *env)
   1220 {
   1221     jclass clazz = env->FindClass("android/os/Debug$MemoryInfo");
   1222 
   1223     // Sanity check the number of other statistics expected in Java matches here.
   1224     jfieldID numOtherStats_field = env->GetStaticFieldID(clazz, "NUM_OTHER_STATS", "I");
   1225     jint numOtherStats = env->GetStaticIntField(clazz, numOtherStats_field);
   1226     jfieldID numDvkStats_field = env->GetStaticFieldID(clazz, "NUM_DVK_STATS", "I");
   1227     jint numDvkStats = env->GetStaticIntField(clazz, numDvkStats_field);
   1228     int expectedNumOtherStats = _NUM_HEAP - _NUM_CORE_HEAP;
   1229     if ((numOtherStats + numDvkStats) != expectedNumOtherStats) {
   1230         jniThrowExceptionFmt(env, "java/lang/RuntimeException",
   1231                              "android.os.Debug.Meminfo.NUM_OTHER_STATS+android.os.Debug.Meminfo.NUM_DVK_STATS=%d expected %d",
   1232                              numOtherStats+numDvkStats, expectedNumOtherStats);
   1233         return JNI_ERR;
   1234     }
   1235 
   1236     otherStats_field = env->GetFieldID(clazz, "otherStats", "[I");
   1237     hasSwappedOutPss_field = env->GetFieldID(clazz, "hasSwappedOutPss", "Z");
   1238 
   1239     for (int i=0; i<_NUM_CORE_HEAP; i++) {
   1240         stat_fields[i].pss_field =
   1241                 env->GetFieldID(clazz, stat_field_names[i].pss_name, "I");
   1242         stat_fields[i].pssSwappable_field =
   1243                 env->GetFieldID(clazz, stat_field_names[i].pssSwappable_name, "I");
   1244         stat_fields[i].rss_field =
   1245                 env->GetFieldID(clazz, stat_field_names[i].rss_name, "I");
   1246         stat_fields[i].privateDirty_field =
   1247                 env->GetFieldID(clazz, stat_field_names[i].privateDirty_name, "I");
   1248         stat_fields[i].sharedDirty_field =
   1249                 env->GetFieldID(clazz, stat_field_names[i].sharedDirty_name, "I");
   1250         stat_fields[i].privateClean_field =
   1251                 env->GetFieldID(clazz, stat_field_names[i].privateClean_name, "I");
   1252         stat_fields[i].sharedClean_field =
   1253                 env->GetFieldID(clazz, stat_field_names[i].sharedClean_name, "I");
   1254         stat_fields[i].swappedOut_field =
   1255                 env->GetFieldID(clazz, stat_field_names[i].swappedOut_name, "I");
   1256         stat_fields[i].swappedOutPss_field =
   1257                 env->GetFieldID(clazz, stat_field_names[i].swappedOutPss_name, "I");
   1258     }
   1259 
   1260     return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods));
   1261 }
   1262 
   1263 }; // namespace android
   1264