blob: bdef6816de714445b7e9da6338822af317e0170e [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"
Adam Lesinski5b4ef812013-09-23 10:06:09 -070023#include <memtrack/memtrack.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024
Ruben Brunk87eac992013-09-09 17:44:59 -070025#include <cutils/log.h>
Dianne Hackbornf72467a2012-06-08 17:23:59 -070026#include <fcntl.h>
Mark Salyzyn85394032014-04-16 10:28:37 -070027#include <inttypes.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
32#include <time.h>
33#include <sys/time.h>
Andy McFadden06a6b552010-07-13 16:28:09 -070034#include <errno.h>
35#include <assert.h>
Dianne Hackborn0e3328f2011-07-17 13:31:17 -070036#include <ctype.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037
38#ifdef HAVE_MALLOC_H
39#include <malloc.h>
40#endif
41
42namespace android
43{
44
Dianne Hackborn0e3328f2011-07-17 13:31:17 -070045enum {
46 HEAP_UNKNOWN,
47 HEAP_DALVIK,
48 HEAP_NATIVE,
Dianne Hackborn18429302014-11-03 13:58:11 -080049
Dianne Hackborn64770d12013-05-23 17:51:19 -070050 HEAP_DALVIK_OTHER,
Ian Rogers7c9f30b2013-02-27 10:57:13 -080051 HEAP_STACK,
Dianne Hackborn0e3328f2011-07-17 13:31:17 -070052 HEAP_CURSOR,
53 HEAP_ASHMEM,
Dianne Hackborn18429302014-11-03 13:58:11 -080054 HEAP_GL_DEV,
Dianne Hackborn0e3328f2011-07-17 13:31:17 -070055 HEAP_UNKNOWN_DEV,
56 HEAP_SO,
57 HEAP_JAR,
58 HEAP_APK,
59 HEAP_TTF,
60 HEAP_DEX,
Anwar Ghuloum8884ef42013-03-15 12:56:59 -070061 HEAP_OAT,
Anwar Ghuloum88887d02013-03-19 15:30:12 -070062 HEAP_ART,
Dianne Hackborn0e3328f2011-07-17 13:31:17 -070063 HEAP_UNKNOWN_MAP,
Adam Lesinski5b4ef812013-09-23 10:06:09 -070064 HEAP_GRAPHICS,
65 HEAP_GL,
66 HEAP_OTHER_MEMTRACK,
Dianne Hackborn64770d12013-05-23 17:51:19 -070067
Anwar Ghuloum3c615062013-05-13 14:18:02 -070068 HEAP_DALVIK_NORMAL,
69 HEAP_DALVIK_LARGE,
70 HEAP_DALVIK_LINEARALLOC,
71 HEAP_DALVIK_ACCOUNTING,
72 HEAP_DALVIK_CODE_CACHE,
Dianne Hackborn0e3328f2011-07-17 13:31:17 -070073
74 _NUM_HEAP,
Adam Lesinski5b4ef812013-09-23 10:06:09 -070075 _NUM_EXCLUSIVE_HEAP = HEAP_OTHER_MEMTRACK+1,
Dianne Hackborn0e3328f2011-07-17 13:31:17 -070076 _NUM_CORE_HEAP = HEAP_NATIVE+1
77};
78
79struct stat_fields {
80 jfieldID pss_field;
Anwar Ghuloum3c615062013-05-13 14:18:02 -070081 jfieldID pssSwappable_field;
Dianne Hackborn0e3328f2011-07-17 13:31:17 -070082 jfieldID privateDirty_field;
83 jfieldID sharedDirty_field;
Anwar Ghuloum3c615062013-05-13 14:18:02 -070084 jfieldID privateClean_field;
Anwar Ghuloum3a8ce1b2013-04-26 16:18:28 -070085 jfieldID sharedClean_field;
Dianne Hackborn8883ced2013-10-02 16:58:06 -070086 jfieldID swappedOut_field;
Dianne Hackborn0e3328f2011-07-17 13:31:17 -070087};
88
89struct stat_field_names {
90 const char* pss_name;
Anwar Ghuloum3c615062013-05-13 14:18:02 -070091 const char* pssSwappable_name;
Dianne Hackborn0e3328f2011-07-17 13:31:17 -070092 const char* privateDirty_name;
93 const char* sharedDirty_name;
Anwar Ghuloum3c615062013-05-13 14:18:02 -070094 const char* privateClean_name;
Anwar Ghuloum3a8ce1b2013-04-26 16:18:28 -070095 const char* sharedClean_name;
Dianne Hackborn8883ced2013-10-02 16:58:06 -070096 const char* swappedOut_name;
Dianne Hackborn0e3328f2011-07-17 13:31:17 -070097};
98
99static stat_fields stat_fields[_NUM_CORE_HEAP];
100
101static stat_field_names stat_field_names[_NUM_CORE_HEAP] = {
Dianne Hackborn8883ced2013-10-02 16:58:06 -0700102 { "otherPss", "otherSwappablePss", "otherPrivateDirty", "otherSharedDirty",
103 "otherPrivateClean", "otherSharedClean", "otherSwappedOut" },
104 { "dalvikPss", "dalvikSwappablePss", "dalvikPrivateDirty", "dalvikSharedDirty",
105 "dalvikPrivateClean", "dalvikSharedClean", "dalvikSwappedOut" },
106 { "nativePss", "nativeSwappablePss", "nativePrivateDirty", "nativeSharedDirty",
107 "nativePrivateClean", "nativeSharedClean", "nativeSwappedOut" }
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700108};
109
110jfieldID otherStats_field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700112static bool memtrackLoaded;
113
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114struct stats_t {
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700115 int pss;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700116 int swappablePss;
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700117 int privateDirty;
118 int sharedDirty;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700119 int privateClean;
Anwar Ghuloum3a8ce1b2013-04-26 16:18:28 -0700120 int sharedClean;
Dianne Hackborn8883ced2013-10-02 16:58:06 -0700121 int swappedOut;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122};
123
124#define BINDER_STATS "/proc/binder/stats"
125
126static jlong android_os_Debug_getNativeHeapSize(JNIEnv *env, jobject clazz)
127{
128#ifdef HAVE_MALLOC_H
129 struct mallinfo info = mallinfo();
130 return (jlong) info.usmblks;
131#else
132 return -1;
133#endif
134}
135
136static jlong android_os_Debug_getNativeHeapAllocatedSize(JNIEnv *env, jobject clazz)
137{
138#ifdef HAVE_MALLOC_H
139 struct mallinfo info = mallinfo();
140 return (jlong) info.uordblks;
141#else
142 return -1;
143#endif
144}
145
146static jlong android_os_Debug_getNativeHeapFreeSize(JNIEnv *env, jobject clazz)
147{
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800148#ifdef HAVE_MALLOC_H
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 struct mallinfo info = mallinfo();
150 return (jlong) info.fordblks;
151#else
152 return -1;
153#endif
154}
155
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700156// Container used to retrieve graphics memory pss
157struct graphics_memory_pss
Dianne Hackborn37c99432013-09-05 19:34:57 -0700158{
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700159 int graphics;
160 int gl;
161 int other;
162};
Dianne Hackborn37c99432013-09-05 19:34:57 -0700163
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700164/*
165 * Uses libmemtrack to retrieve graphics memory that the process is using.
166 * Any graphics memory reported in /proc/pid/smaps is not included here.
167 */
Dianne Hackborncb428552013-09-26 11:07:17 -0700168static int read_memtrack_memory(struct memtrack_proc* p, int pid,
169 struct graphics_memory_pss* graphics_mem)
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700170{
171 int err = memtrack_proc_get(p, pid);
172 if (err != 0) {
Dianne Hackborncb428552013-09-26 11:07:17 -0700173 ALOGW("failed to get memory consumption info: %d", err);
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700174 return err;
Dianne Hackborn37c99432013-09-05 19:34:57 -0700175 }
176
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700177 ssize_t pss = memtrack_proc_graphics_pss(p);
178 if (pss < 0) {
Colin Cross0c6bc732014-06-17 15:18:07 -0700179 ALOGW("failed to get graphics pss: %zd", pss);
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700180 return pss;
181 }
182 graphics_mem->graphics = pss / 1024;
Dianne Hackborn37c99432013-09-05 19:34:57 -0700183
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700184 pss = memtrack_proc_gl_pss(p);
185 if (pss < 0) {
Colin Cross0c6bc732014-06-17 15:18:07 -0700186 ALOGW("failed to get gl pss: %zd", pss);
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700187 return pss;
188 }
189 graphics_mem->gl = pss / 1024;
Dianne Hackborn37c99432013-09-05 19:34:57 -0700190
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700191 pss = memtrack_proc_other_pss(p);
192 if (pss < 0) {
Colin Cross0c6bc732014-06-17 15:18:07 -0700193 ALOGW("failed to get other pss: %zd", pss);
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700194 return pss;
195 }
196 graphics_mem->other = pss / 1024;
Dianne Hackborn37c99432013-09-05 19:34:57 -0700197
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700198 return 0;
199}
Dianne Hackborn37c99432013-09-05 19:34:57 -0700200
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700201/*
202 * Retrieves the graphics memory that is unaccounted for in /proc/pid/smaps.
203 */
204static int read_memtrack_memory(int pid, struct graphics_memory_pss* graphics_mem)
205{
206 if (!memtrackLoaded) {
207 return -1;
Dianne Hackborn37c99432013-09-05 19:34:57 -0700208 }
209
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700210 struct memtrack_proc* p = memtrack_proc_new();
211 if (p == NULL) {
Dianne Hackborncb428552013-09-26 11:07:17 -0700212 ALOGW("failed to create memtrack_proc");
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700213 return -1;
214 }
Dianne Hackborn37c99432013-09-05 19:34:57 -0700215
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700216 int err = read_memtrack_memory(p, pid, graphics_mem);
217 memtrack_proc_destroy(p);
218 return err;
Dianne Hackborn37c99432013-09-05 19:34:57 -0700219}
220
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221static void read_mapinfo(FILE *fp, stats_t* stats)
222{
223 char line[1024];
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700224 int len, nameLen;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225 bool skip, done = false;
226
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700227 unsigned size = 0, resident = 0, pss = 0, swappable_pss = 0;
228 float sharing_proportion = 0.0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 unsigned shared_clean = 0, shared_dirty = 0;
230 unsigned private_clean = 0, private_dirty = 0;
Dianne Hackborn8883ced2013-10-02 16:58:06 -0700231 unsigned swapped_out = 0;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700232 bool is_swappable = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 unsigned referenced = 0;
234 unsigned temp;
235
Colin Cross0c6bc732014-06-17 15:18:07 -0700236 uint64_t start;
237 uint64_t end = 0;
238 uint64_t prevEnd = 0;
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700239 char* name;
240 int name_pos;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700242 int whichHeap = HEAP_UNKNOWN;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700243 int subHeap = HEAP_UNKNOWN;
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700244 int prevHeap = HEAP_UNKNOWN;
245
246 if(fgets(line, sizeof(line), fp) == 0) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247
248 while (!done) {
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700249 prevHeap = whichHeap;
250 prevEnd = end;
251 whichHeap = HEAP_UNKNOWN;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700252 subHeap = HEAP_UNKNOWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 skip = false;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700254 is_swappable = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255
256 len = strlen(line);
257 if (len < 1) return;
258 line[--len] = 0;
259
Colin Cross0c6bc732014-06-17 15:18:07 -0700260 if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) {
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700261 skip = true;
262 } else {
263 while (isspace(line[name_pos])) {
264 name_pos += 1;
265 }
266 name = line + name_pos;
267 nameLen = strlen(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268
Dianne Hackborn64770d12013-05-23 17:51:19 -0700269 if ((strstr(name, "[heap]") == name)) {
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700270 whichHeap = HEAP_NATIVE;
Dianne Hackborn64770d12013-05-23 17:51:19 -0700271 } else if (strncmp(name, "/dev/ashmem", 11) == 0) {
272 if (strncmp(name, "/dev/ashmem/dalvik-", 19) == 0) {
273 whichHeap = HEAP_DALVIK_OTHER;
274 if (strstr(name, "/dev/ashmem/dalvik-LinearAlloc") == name) {
275 subHeap = HEAP_DALVIK_LINEARALLOC;
Mathieu Chartiereee97642014-09-23 17:24:30 -0700276 } else if ((strstr(name, "/dev/ashmem/dalvik-alloc space") == name) ||
277 (strstr(name, "/dev/ashmem/dalvik-main space") == name) ||
Mathieu Chartier7fc91762014-11-19 13:34:05 -0800278 (strstr(name, "/dev/ashmem/dalvik-zygote space") == name) ||
Mathieu Chartiereee97642014-09-23 17:24:30 -0700279 (strstr(name, "/dev/ashmem/dalvik-non moving space") == name)) {
280 // This is the regular Dalvik heap.
281 whichHeap = HEAP_DALVIK;
282 subHeap = HEAP_DALVIK_NORMAL;
283 } else if (strstr(name, "/dev/ashmem/dalvik-large object space") == name) {
Dianne Hackborn64770d12013-05-23 17:51:19 -0700284 whichHeap = HEAP_DALVIK;
285 subHeap = HEAP_DALVIK_LARGE;
286 } else if (strstr(name, "/dev/ashmem/dalvik-jit-code-cache") == name) {
287 subHeap = HEAP_DALVIK_CODE_CACHE;
288 } else {
Mathieu Chartiereee97642014-09-23 17:24:30 -0700289 subHeap = HEAP_DALVIK_ACCOUNTING; // Default to accounting.
Dianne Hackborn64770d12013-05-23 17:51:19 -0700290 }
291 } else if (strncmp(name, "/dev/ashmem/CursorWindow", 24) == 0) {
292 whichHeap = HEAP_CURSOR;
293 } else if (strncmp(name, "/dev/ashmem/libc malloc", 23) == 0) {
294 whichHeap = HEAP_NATIVE;
295 } else {
296 whichHeap = HEAP_ASHMEM;
297 }
Colin Crosscb4728f2013-08-09 13:23:46 -0700298 } else if (strncmp(name, "[anon:libc_malloc]", 18) == 0) {
299 whichHeap = HEAP_NATIVE;
Dianne Hackborn64770d12013-05-23 17:51:19 -0700300 } else if (strncmp(name, "[stack", 6) == 0) {
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800301 whichHeap = HEAP_STACK;
Dianne Hackborn64770d12013-05-23 17:51:19 -0700302 } else if (strncmp(name, "/dev/", 5) == 0) {
Dianne Hackborn18429302014-11-03 13:58:11 -0800303 if (strncmp(name, "/dev/kgsl-3d0", 13) == 0) {
304 whichHeap = HEAP_GL_DEV;
305 } else {
306 whichHeap = HEAP_UNKNOWN_DEV;
307 }
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700308 } else if (nameLen > 3 && strcmp(name+nameLen-3, ".so") == 0) {
309 whichHeap = HEAP_SO;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700310 is_swappable = true;
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700311 } else if (nameLen > 4 && strcmp(name+nameLen-4, ".jar") == 0) {
312 whichHeap = HEAP_JAR;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700313 is_swappable = true;
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700314 } else if (nameLen > 4 && strcmp(name+nameLen-4, ".apk") == 0) {
315 whichHeap = HEAP_APK;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700316 is_swappable = true;
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700317 } else if (nameLen > 4 && strcmp(name+nameLen-4, ".ttf") == 0) {
318 whichHeap = HEAP_TTF;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700319 is_swappable = true;
Ian Rogers9f8589c2013-02-22 20:35:06 -0800320 } else if ((nameLen > 4 && strcmp(name+nameLen-4, ".dex") == 0) ||
321 (nameLen > 5 && strcmp(name+nameLen-5, ".odex") == 0)) {
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700322 whichHeap = HEAP_DEX;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700323 is_swappable = true;
Anwar Ghuloum8884ef42013-03-15 12:56:59 -0700324 } else if (nameLen > 4 && strcmp(name+nameLen-4, ".oat") == 0) {
325 whichHeap = HEAP_OAT;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700326 is_swappable = true;
Anwar Ghuloum88887d02013-03-19 15:30:12 -0700327 } else if (nameLen > 4 && strcmp(name+nameLen-4, ".art") == 0) {
328 whichHeap = HEAP_ART;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700329 is_swappable = true;
Colin Crosscb4728f2013-08-09 13:23:46 -0700330 } else if (strncmp(name, "[anon:", 6) == 0) {
331 whichHeap = HEAP_UNKNOWN;
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700332 } else if (nameLen > 0) {
333 whichHeap = HEAP_UNKNOWN_MAP;
334 } else if (start == prevEnd && prevHeap == HEAP_SO) {
335 // bss section of a shared library.
336 whichHeap = HEAP_SO;
337 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338 }
339
Steve Block6215d3f2012-01-04 20:05:49 +0000340 //ALOGI("native=%d dalvik=%d sqlite=%d: %s\n", isNativeHeap, isDalvikHeap,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 // isSqliteHeap, line);
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800342
Dianne Hackborn8883ced2013-10-02 16:58:06 -0700343 shared_clean = 0;
344 shared_dirty = 0;
345 private_clean = 0;
346 private_dirty = 0;
347 swapped_out = 0;
348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 while (true) {
350 if (fgets(line, 1024, fp) == 0) {
351 done = true;
352 break;
353 }
354
Dianne Hackborn8883ced2013-10-02 16:58:06 -0700355 if (line[0] == 'S' && sscanf(line, "Size: %d kB", &temp) == 1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 size = temp;
Dianne Hackborn8883ced2013-10-02 16:58:06 -0700357 } else if (line[0] == 'R' && sscanf(line, "Rss: %d kB", &temp) == 1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 resident = temp;
Dianne Hackborn8883ced2013-10-02 16:58:06 -0700359 } else if (line[0] == 'P' && sscanf(line, "Pss: %d kB", &temp) == 1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 pss = temp;
Dianne Hackborn8883ced2013-10-02 16:58:06 -0700361 } else if (line[0] == 'S' && sscanf(line, "Shared_Clean: %d kB", &temp) == 1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 shared_clean = temp;
Dianne Hackborn8883ced2013-10-02 16:58:06 -0700363 } else if (line[0] == 'S' && sscanf(line, "Shared_Dirty: %d kB", &temp) == 1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 shared_dirty = temp;
Dianne Hackborn8883ced2013-10-02 16:58:06 -0700365 } else if (line[0] == 'P' && sscanf(line, "Private_Clean: %d kB", &temp) == 1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 private_clean = temp;
Dianne Hackborn8883ced2013-10-02 16:58:06 -0700367 } else if (line[0] == 'P' && sscanf(line, "Private_Dirty: %d kB", &temp) == 1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 private_dirty = temp;
Dianne Hackborn8883ced2013-10-02 16:58:06 -0700369 } else if (line[0] == 'R' && sscanf(line, "Referenced: %d kB", &temp) == 1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 referenced = temp;
Dianne Hackborn8883ced2013-10-02 16:58:06 -0700371 } else if (line[0] == 'S' && sscanf(line, "Swap: %d kB", &temp) == 1) {
372 swapped_out = temp;
Colin Cross0c6bc732014-06-17 15:18:07 -0700373 } else if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %*s %*x %*x:%*x %*d", &start, &end) == 2) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 // looks like a new mapping
Grace Klobabd511162009-07-08 23:32:25 -0700375 // example: "10000000-10001000 ---p 10000000 00:00 0"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 break;
377 }
378 }
379
380 if (!skip) {
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700381 if (is_swappable && (pss > 0)) {
382 sharing_proportion = 0.0;
383 if ((shared_clean > 0) || (shared_dirty > 0)) {
Dianne Hackborn8883ced2013-10-02 16:58:06 -0700384 sharing_proportion = (pss - private_clean
385 - private_dirty)/(shared_clean+shared_dirty);
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700386 }
387 swappable_pss = (sharing_proportion*shared_clean) + private_clean;
388 } else
389 swappable_pss = 0;
390
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700391 stats[whichHeap].pss += pss;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700392 stats[whichHeap].swappablePss += swappable_pss;
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700393 stats[whichHeap].privateDirty += private_dirty;
394 stats[whichHeap].sharedDirty += shared_dirty;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700395 stats[whichHeap].privateClean += private_clean;
Anwar Ghuloum3a8ce1b2013-04-26 16:18:28 -0700396 stats[whichHeap].sharedClean += shared_clean;
Dianne Hackborn8883ced2013-10-02 16:58:06 -0700397 stats[whichHeap].swappedOut += swapped_out;
Dianne Hackborn64770d12013-05-23 17:51:19 -0700398 if (whichHeap == HEAP_DALVIK || whichHeap == HEAP_DALVIK_OTHER) {
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700399 stats[subHeap].pss += pss;
400 stats[subHeap].swappablePss += swappable_pss;
401 stats[subHeap].privateDirty += private_dirty;
402 stats[subHeap].sharedDirty += shared_dirty;
403 stats[subHeap].privateClean += private_clean;
404 stats[subHeap].sharedClean += shared_clean;
Dianne Hackborn8883ced2013-10-02 16:58:06 -0700405 stats[subHeap].swappedOut += swapped_out;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700406 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 }
408 }
409}
410
411static void load_maps(int pid, stats_t* stats)
412{
413 char tmp[128];
414 FILE *fp;
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 sprintf(tmp, "/proc/%d/smaps", pid);
417 fp = fopen(tmp, "r");
418 if (fp == 0) return;
419
420 read_mapinfo(fp, stats);
421 fclose(fp);
422}
423
Dianne Hackborn3025ef32009-08-31 21:31:47 -0700424static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
425 jint pid, jobject object)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426{
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700427 stats_t stats[_NUM_HEAP];
428 memset(&stats, 0, sizeof(stats));
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800429
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700430 load_maps(pid, stats);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700432 struct graphics_memory_pss graphics_mem;
433 if (read_memtrack_memory(pid, &graphics_mem) == 0) {
434 stats[HEAP_GRAPHICS].pss = graphics_mem.graphics;
435 stats[HEAP_GRAPHICS].privateDirty = graphics_mem.graphics;
436 stats[HEAP_GL].pss = graphics_mem.gl;
437 stats[HEAP_GL].privateDirty = graphics_mem.gl;
438 stats[HEAP_OTHER_MEMTRACK].pss = graphics_mem.other;
439 stats[HEAP_OTHER_MEMTRACK].privateDirty = graphics_mem.other;
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700440 }
Dianne Hackborn37c99432013-09-05 19:34:57 -0700441
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700442 for (int i=_NUM_CORE_HEAP; i<_NUM_EXCLUSIVE_HEAP; i++) {
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700443 stats[HEAP_UNKNOWN].pss += stats[i].pss;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700444 stats[HEAP_UNKNOWN].swappablePss += stats[i].swappablePss;
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700445 stats[HEAP_UNKNOWN].privateDirty += stats[i].privateDirty;
446 stats[HEAP_UNKNOWN].sharedDirty += stats[i].sharedDirty;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700447 stats[HEAP_UNKNOWN].privateClean += stats[i].privateClean;
Anwar Ghuloum3a8ce1b2013-04-26 16:18:28 -0700448 stats[HEAP_UNKNOWN].sharedClean += stats[i].sharedClean;
Dianne Hackborn8883ced2013-10-02 16:58:06 -0700449 stats[HEAP_UNKNOWN].swappedOut += stats[i].swappedOut;
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700450 }
451
452 for (int i=0; i<_NUM_CORE_HEAP; i++) {
453 env->SetIntField(object, stat_fields[i].pss_field, stats[i].pss);
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700454 env->SetIntField(object, stat_fields[i].pssSwappable_field, stats[i].swappablePss);
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700455 env->SetIntField(object, stat_fields[i].privateDirty_field, stats[i].privateDirty);
456 env->SetIntField(object, stat_fields[i].sharedDirty_field, stats[i].sharedDirty);
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700457 env->SetIntField(object, stat_fields[i].privateClean_field, stats[i].privateClean);
Anwar Ghuloum3a8ce1b2013-04-26 16:18:28 -0700458 env->SetIntField(object, stat_fields[i].sharedClean_field, stats[i].sharedClean);
Dianne Hackborn8883ced2013-10-02 16:58:06 -0700459 env->SetIntField(object, stat_fields[i].swappedOut_field, stats[i].swappedOut);
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700460 }
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800461
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700462
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700463 jintArray otherIntArray = (jintArray)env->GetObjectField(object, otherStats_field);
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800464
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700465 jint* otherArray = (jint*)env->GetPrimitiveArrayCritical(otherIntArray, 0);
466 if (otherArray == NULL) {
467 return;
468 }
469
470 int j=0;
471 for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
472 otherArray[j++] = stats[i].pss;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700473 otherArray[j++] = stats[i].swappablePss;
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700474 otherArray[j++] = stats[i].privateDirty;
475 otherArray[j++] = stats[i].sharedDirty;
Anwar Ghuloum3c615062013-05-13 14:18:02 -0700476 otherArray[j++] = stats[i].privateClean;
Anwar Ghuloum3a8ce1b2013-04-26 16:18:28 -0700477 otherArray[j++] = stats[i].sharedClean;
Dianne Hackborn8883ced2013-10-02 16:58:06 -0700478 otherArray[j++] = stats[i].swappedOut;
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700479 }
480
481 env->ReleasePrimitiveArrayCritical(otherIntArray, otherArray, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800482}
483
Dianne Hackborn3025ef32009-08-31 21:31:47 -0700484static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject object)
485{
486 android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object);
487}
488
Dianne Hackborn1a4b5a42014-12-08 17:43:31 -0800489static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid, jlongArray outUss,
490 jlongArray outMemtrack)
Dianne Hackbornb437e092011-08-05 17:50:29 -0700491{
492 char line[1024];
493 jlong pss = 0;
Dianne Hackbornc8230512013-07-13 21:32:12 -0700494 jlong uss = 0;
Dianne Hackborn1a4b5a42014-12-08 17:43:31 -0800495 jlong memtrack = 0;
Dianne Hackbornb437e092011-08-05 17:50:29 -0700496 unsigned temp;
497
498 char tmp[128];
499 FILE *fp;
500
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700501 struct graphics_memory_pss graphics_mem;
502 if (read_memtrack_memory(pid, &graphics_mem) == 0) {
Dianne Hackborn1a4b5a42014-12-08 17:43:31 -0800503 pss = uss = memtrack = graphics_mem.graphics + graphics_mem.gl + graphics_mem.other;
Dianne Hackbornb437e092011-08-05 17:50:29 -0700504 }
505
Dianne Hackbornb437e092011-08-05 17:50:29 -0700506 sprintf(tmp, "/proc/%d/smaps", pid);
507 fp = fopen(tmp, "r");
Dianne Hackbornb437e092011-08-05 17:50:29 -0700508
Dianne Hackborn37c99432013-09-05 19:34:57 -0700509 if (fp != 0) {
510 while (true) {
511 if (fgets(line, 1024, fp) == NULL) {
512 break;
513 }
Dianne Hackbornb437e092011-08-05 17:50:29 -0700514
Dianne Hackborn37c99432013-09-05 19:34:57 -0700515 if (line[0] == 'P') {
516 if (strncmp(line, "Pss:", 4) == 0) {
517 char* c = line + 4;
518 while (*c != 0 && (*c < '0' || *c > '9')) {
519 c++;
520 }
521 pss += atoi(c);
522 } else if (strncmp(line, "Private_Clean:", 14)
523 || strncmp(line, "Private_Dirty:", 14)) {
524 char* c = line + 14;
525 while (*c != 0 && (*c < '0' || *c > '9')) {
526 c++;
527 }
528 uss += atoi(c);
Dianne Hackbornc8230512013-07-13 21:32:12 -0700529 }
Dianne Hackborncfc837f2013-06-27 18:32:07 -0700530 }
Dianne Hackbornb437e092011-08-05 17:50:29 -0700531 }
Dianne Hackbornb437e092011-08-05 17:50:29 -0700532
Dianne Hackborn37c99432013-09-05 19:34:57 -0700533 fclose(fp);
534 }
Dianne Hackbornb437e092011-08-05 17:50:29 -0700535
Dianne Hackbornc8230512013-07-13 21:32:12 -0700536 if (outUss != NULL) {
537 if (env->GetArrayLength(outUss) >= 1) {
538 jlong* outUssArray = env->GetLongArrayElements(outUss, 0);
539 if (outUssArray != NULL) {
540 outUssArray[0] = uss;
541 }
542 env->ReleaseLongArrayElements(outUss, outUssArray, 0);
543 }
544 }
Dianne Hackbornb437e092011-08-05 17:50:29 -0700545
Dianne Hackborn1a4b5a42014-12-08 17:43:31 -0800546 if (outMemtrack != NULL) {
547 if (env->GetArrayLength(outMemtrack) >= 1) {
548 jlong* outMemtrackArray = env->GetLongArrayElements(outMemtrack, 0);
549 if (outMemtrackArray != NULL) {
550 outMemtrackArray[0] = memtrack;
551 }
552 env->ReleaseLongArrayElements(outMemtrack, outMemtrackArray, 0);
553 }
554 }
555
Dianne Hackbornb437e092011-08-05 17:50:29 -0700556 return pss;
557}
558
559static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz)
560{
Dianne Hackborn1a4b5a42014-12-08 17:43:31 -0800561 return android_os_Debug_getPssPid(env, clazz, getpid(), NULL, NULL);
Dianne Hackbornb437e092011-08-05 17:50:29 -0700562}
563
Dianne Hackborncbd9a522013-09-24 23:10:14 -0700564enum {
565 MEMINFO_TOTAL,
566 MEMINFO_FREE,
567 MEMINFO_BUFFERS,
568 MEMINFO_CACHED,
569 MEMINFO_SHMEM,
570 MEMINFO_SLAB,
571 MEMINFO_SWAP_TOTAL,
572 MEMINFO_SWAP_FREE,
573 MEMINFO_ZRAM_TOTAL,
Dianne Hackbornb3af4ec2014-10-17 15:25:13 -0700574 MEMINFO_MAPPED,
575 MEMINFO_VMALLOC_USED,
576 MEMINFO_PAGE_TABLES,
577 MEMINFO_KERNEL_STACK,
Dianne Hackborncbd9a522013-09-24 23:10:14 -0700578 MEMINFO_COUNT
579};
580
Dianne Hackborn8e692572013-09-10 19:06:15 -0700581static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray out)
582{
583 char buffer[1024];
584 int numFound = 0;
585
586 if (out == NULL) {
587 jniThrowNullPointerException(env, "out == null");
588 return;
589 }
590
591 int fd = open("/proc/meminfo", O_RDONLY);
592
593 if (fd < 0) {
Dianne Hackborncbd9a522013-09-24 23:10:14 -0700594 ALOGW("Unable to open /proc/meminfo: %s\n", strerror(errno));
Dianne Hackborn8e692572013-09-10 19:06:15 -0700595 return;
596 }
597
Dianne Hackborncbd9a522013-09-24 23:10:14 -0700598 int len = read(fd, buffer, sizeof(buffer)-1);
Dianne Hackborn8e692572013-09-10 19:06:15 -0700599 close(fd);
600
601 if (len < 0) {
Dianne Hackborncbd9a522013-09-24 23:10:14 -0700602 ALOGW("Empty /proc/meminfo");
Dianne Hackborn8e692572013-09-10 19:06:15 -0700603 return;
604 }
605 buffer[len] = 0;
606
607 static const char* const tags[] = {
608 "MemTotal:",
609 "MemFree:",
610 "Buffers:",
611 "Cached:",
612 "Shmem:",
613 "Slab:",
Dianne Hackborncbd9a522013-09-24 23:10:14 -0700614 "SwapTotal:",
615 "SwapFree:",
Dianne Hackbornb3af4ec2014-10-17 15:25:13 -0700616 "ZRam:",
617 "Mapped:",
618 "VmallocUsed:",
619 "PageTables:",
620 "KernelStack:",
Dianne Hackborn8e692572013-09-10 19:06:15 -0700621 NULL
622 };
623 static const int tagsLen[] = {
624 9,
625 8,
626 8,
627 7,
628 6,
629 5,
Dianne Hackborncbd9a522013-09-24 23:10:14 -0700630 10,
631 9,
Dianne Hackbornb3af4ec2014-10-17 15:25:13 -0700632 5,
633 7,
634 12,
635 11,
636 12,
Dianne Hackborn8e692572013-09-10 19:06:15 -0700637 0
638 };
Dianne Hackbornb3af4ec2014-10-17 15:25:13 -0700639 long mem[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Dianne Hackborn8e692572013-09-10 19:06:15 -0700640
641 char* p = buffer;
Dianne Hackbornb3af4ec2014-10-17 15:25:13 -0700642 while (*p && numFound < 13) {
Dianne Hackborn8e692572013-09-10 19:06:15 -0700643 int i = 0;
644 while (tags[i]) {
645 if (strncmp(p, tags[i], tagsLen[i]) == 0) {
646 p += tagsLen[i];
647 while (*p == ' ') p++;
648 char* num = p;
649 while (*p >= '0' && *p <= '9') p++;
650 if (*p != 0) {
651 *p = 0;
652 p++;
653 }
654 mem[i] = atoll(num);
655 numFound++;
656 break;
657 }
658 i++;
659 }
660 while (*p && *p != '\n') {
661 p++;
662 }
663 if (*p) p++;
664 }
665
Dianne Hackborncbd9a522013-09-24 23:10:14 -0700666 fd = open("/sys/block/zram0/mem_used_total", O_RDONLY);
667 if (fd >= 0) {
668 len = read(fd, buffer, sizeof(buffer)-1);
669 close(fd);
670 if (len > 0) {
671 buffer[len] = 0;
Dianne Hackborncb428552013-09-26 11:07:17 -0700672 mem[MEMINFO_ZRAM_TOTAL] = atoll(buffer)/1024;
Dianne Hackborncbd9a522013-09-24 23:10:14 -0700673 }
674 }
675
Dianne Hackborn8e692572013-09-10 19:06:15 -0700676 int maxNum = env->GetArrayLength(out);
Dianne Hackborncbd9a522013-09-24 23:10:14 -0700677 if (maxNum > MEMINFO_COUNT) {
678 maxNum = MEMINFO_COUNT;
679 }
Dianne Hackborn8e692572013-09-10 19:06:15 -0700680 jlong* outArray = env->GetLongArrayElements(out, 0);
681 if (outArray != NULL) {
Dianne Hackborncb428552013-09-26 11:07:17 -0700682 for (int i=0; i<maxNum; i++) {
Dianne Hackborn8e692572013-09-10 19:06:15 -0700683 outArray[i] = mem[i];
684 }
685 }
686 env->ReleaseLongArrayElements(out, outArray, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687}
688
689static jint read_binder_stat(const char* stat)
690{
691 FILE* fp = fopen(BINDER_STATS, "r");
692 if (fp == NULL) {
693 return -1;
694 }
695
696 char line[1024];
697
698 char compare[128];
699 int len = snprintf(compare, 128, "proc %d", getpid());
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800700
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 // loop until we have the block that represents this process
702 do {
703 if (fgets(line, 1024, fp) == 0) {
Elliott Hughesc367d482013-10-29 13:12:55 -0700704 fclose(fp);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800705 return -1;
706 }
707 } while (strncmp(compare, line, len));
708
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800709 // 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 -0800710 len = snprintf(compare, 128, " %s: ", stat);
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800711
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712 do {
713 if (fgets(line, 1024, fp) == 0) {
Elliott Hughesc367d482013-10-29 13:12:55 -0700714 fclose(fp);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 return -1;
716 }
717 } while (strncmp(compare, line, len));
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719 // we have the line, now increment the line ptr to the value
720 char* ptr = line + len;
Elliott Hughesc367d482013-10-29 13:12:55 -0700721 jint result = atoi(ptr);
722 fclose(fp);
723 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724}
725
726static jint android_os_Debug_getBinderSentTransactions(JNIEnv *env, jobject clazz)
727{
728 return read_binder_stat("bcTRANSACTION");
729}
730
731static jint android_os_getBinderReceivedTransactions(JNIEnv *env, jobject clazz)
732{
733 return read_binder_stat("brTRANSACTION");
734}
735
736// these are implemented in android_util_Binder.cpp
737jint android_os_Debug_getLocalObjectCount(JNIEnv* env, jobject clazz);
738jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz);
739jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz);
740
Andy McFadden06a6b552010-07-13 16:28:09 -0700741
Andy McFadden06a6b552010-07-13 16:28:09 -0700742/* pulled out of bionic */
743extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
744 size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
745extern "C" void free_malloc_leak_info(uint8_t* info);
746#define SIZE_FLAG_ZYGOTE_CHILD (1<<31)
747#define BACKTRACE_SIZE 32
748
749/*
750 * This is a qsort() callback.
751 *
752 * See dumpNativeHeap() for comments about the data format and sort order.
753 */
754static int compareHeapRecords(const void* vrec1, const void* vrec2)
755{
756 const size_t* rec1 = (const size_t*) vrec1;
757 const size_t* rec2 = (const size_t*) vrec2;
758 size_t size1 = *rec1;
759 size_t size2 = *rec2;
760
761 if (size1 < size2) {
762 return 1;
763 } else if (size1 > size2) {
764 return -1;
765 }
766
767 intptr_t* bt1 = (intptr_t*)(rec1 + 2);
768 intptr_t* bt2 = (intptr_t*)(rec2 + 2);
769 for (size_t idx = 0; idx < BACKTRACE_SIZE; idx++) {
770 intptr_t addr1 = bt1[idx];
771 intptr_t addr2 = bt2[idx];
772 if (addr1 == addr2) {
773 if (addr1 == 0)
774 break;
775 continue;
776 }
777 if (addr1 < addr2) {
778 return -1;
779 } else if (addr1 > addr2) {
780 return 1;
781 }
782 }
783
784 return 0;
785}
786
787/*
788 * The get_malloc_leak_info() call returns an array of structs that
789 * look like this:
790 *
791 * size_t size
792 * size_t allocations
793 * intptr_t backtrace[32]
794 *
795 * "size" is the size of the allocation, "backtrace" is a fixed-size
796 * array of function pointers, and "allocations" is the number of
797 * allocations with the exact same size and backtrace.
798 *
799 * The entries are sorted by descending total size (i.e. size*allocations)
800 * then allocation count. For best results with "diff" we'd like to sort
801 * primarily by individual size then stack trace. Since the entries are
802 * fixed-size, and we're allowed (by the current implementation) to mangle
803 * them, we can do this in place.
804 */
805static void dumpNativeHeap(FILE* fp)
806{
807 uint8_t* info = NULL;
808 size_t overallSize, infoSize, totalMemory, backtraceSize;
809
810 get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory,
811 &backtraceSize);
812 if (info == NULL) {
813 fprintf(fp, "Native heap dump not available. To enable, run these"
814 " commands (requires root):\n");
815 fprintf(fp, "$ adb shell setprop libc.debug.malloc 1\n");
816 fprintf(fp, "$ adb shell stop\n");
817 fprintf(fp, "$ adb shell start\n");
818 return;
819 }
820 assert(infoSize != 0);
821 assert(overallSize % infoSize == 0);
822
823 fprintf(fp, "Android Native Heap Dump v1.0\n\n");
824
825 size_t recordCount = overallSize / infoSize;
826 fprintf(fp, "Total memory: %zu\n", totalMemory);
827 fprintf(fp, "Allocation records: %zd\n", recordCount);
828 if (backtraceSize != BACKTRACE_SIZE) {
Ashok Bhatf5df7002014-03-25 20:51:35 +0000829 fprintf(fp, "WARNING: mismatched backtrace sizes (%zu vs. %d)\n",
Andy McFadden06a6b552010-07-13 16:28:09 -0700830 backtraceSize, BACKTRACE_SIZE);
831 }
832 fprintf(fp, "\n");
833
834 /* re-sort the entries */
835 qsort(info, recordCount, infoSize, compareHeapRecords);
836
837 /* dump the entries to the file */
838 const uint8_t* ptr = info;
839 for (size_t idx = 0; idx < recordCount; idx++) {
840 size_t size = *(size_t*) ptr;
841 size_t allocations = *(size_t*) (ptr + sizeof(size_t));
842 intptr_t* backtrace = (intptr_t*) (ptr + sizeof(size_t) * 2);
843
844 fprintf(fp, "z %d sz %8zu num %4zu bt",
845 (size & SIZE_FLAG_ZYGOTE_CHILD) != 0,
846 size & ~SIZE_FLAG_ZYGOTE_CHILD,
847 allocations);
848 for (size_t bt = 0; bt < backtraceSize; bt++) {
849 if (backtrace[bt] == 0) {
850 break;
851 } else {
Ashok Bhatf5df7002014-03-25 20:51:35 +0000852#ifdef __LP64__
Mark Salyzyn85394032014-04-16 10:28:37 -0700853 fprintf(fp, " %016" PRIxPTR, backtrace[bt]);
Ashok Bhatf5df7002014-03-25 20:51:35 +0000854#else
Mark Salyzyn85394032014-04-16 10:28:37 -0700855 fprintf(fp, " %08" PRIxPTR, backtrace[bt]);
Ashok Bhatf5df7002014-03-25 20:51:35 +0000856#endif
Andy McFadden06a6b552010-07-13 16:28:09 -0700857 }
858 }
859 fprintf(fp, "\n");
860
861 ptr += infoSize;
862 }
863
Andy McFadden06a6b552010-07-13 16:28:09 -0700864 free_malloc_leak_info(info);
Brian Carlstrom393b84c12010-10-17 23:40:43 -0700865
866 fprintf(fp, "MAPS\n");
867 const char* maps = "/proc/self/maps";
868 FILE* in = fopen(maps, "r");
869 if (in == NULL) {
870 fprintf(fp, "Could not open %s\n", maps);
871 return;
872 }
873 char buf[BUFSIZ];
874 while (size_t n = fread(buf, sizeof(char), BUFSIZ, in)) {
875 fwrite(buf, sizeof(char), n, fp);
876 }
877 fclose(in);
878
879 fprintf(fp, "END\n");
Andy McFadden06a6b552010-07-13 16:28:09 -0700880}
Andy McFadden06a6b552010-07-13 16:28:09 -0700881
882/*
883 * Dump the native heap, writing human-readable output to the specified
884 * file descriptor.
885 */
886static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject clazz,
887 jobject fileDescriptor)
888{
889 if (fileDescriptor == NULL) {
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800890 jniThrowNullPointerException(env, "fd == null");
Andy McFadden06a6b552010-07-13 16:28:09 -0700891 return;
892 }
893 int origFd = jniGetFDFromFileDescriptor(env, fileDescriptor);
894 if (origFd < 0) {
895 jniThrowRuntimeException(env, "Invalid file descriptor");
896 return;
897 }
898
899 /* dup() the descriptor so we don't close the original with fclose() */
900 int fd = dup(origFd);
901 if (fd < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000902 ALOGW("dup(%d) failed: %s\n", origFd, strerror(errno));
Andy McFadden06a6b552010-07-13 16:28:09 -0700903 jniThrowRuntimeException(env, "dup() failed");
904 return;
905 }
906
907 FILE* fp = fdopen(fd, "w");
908 if (fp == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000909 ALOGW("fdopen(%d) failed: %s\n", fd, strerror(errno));
Andy McFadden06a6b552010-07-13 16:28:09 -0700910 close(fd);
911 jniThrowRuntimeException(env, "fdopen() failed");
912 return;
913 }
914
Steve Block5baa3a62011-12-20 16:23:08 +0000915 ALOGD("Native heap dump starting...\n");
Andy McFadden06a6b552010-07-13 16:28:09 -0700916 dumpNativeHeap(fp);
Steve Block5baa3a62011-12-20 16:23:08 +0000917 ALOGD("Native heap dump complete.\n");
Andy McFadden06a6b552010-07-13 16:28:09 -0700918
919 fclose(fp);
920}
921
922
Dianne Hackbornf72467a2012-06-08 17:23:59 -0700923static void android_os_Debug_dumpNativeBacktraceToFile(JNIEnv* env, jobject clazz,
924 jint pid, jstring fileName)
925{
926 if (fileName == NULL) {
Ian Rogers7c9f30b2013-02-27 10:57:13 -0800927 jniThrowNullPointerException(env, "file == null");
Dianne Hackbornf72467a2012-06-08 17:23:59 -0700928 return;
929 }
930 const jchar* str = env->GetStringCritical(fileName, 0);
931 String8 fileName8;
932 if (str) {
933 fileName8 = String8(str, env->GetStringLength(fileName));
934 env->ReleaseStringCritical(fileName, str);
935 }
936
937 int fd = open(fileName8.string(), O_CREAT | O_WRONLY | O_NOFOLLOW, 0666); /* -rw-rw-rw- */
938 if (fd < 0) {
939 fprintf(stderr, "Can't open %s: %s\n", fileName8.string(), strerror(errno));
940 return;
941 }
942
943 if (lseek(fd, 0, SEEK_END) < 0) {
944 fprintf(stderr, "lseek: %s\n", strerror(errno));
945 } else {
946 dump_backtrace_to_file(pid, fd);
947 }
948
949 close(fd);
950}
951
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952/*
953 * JNI registration.
954 */
955
956static JNINativeMethod gMethods[] = {
957 { "getNativeHeapSize", "()J",
958 (void*) android_os_Debug_getNativeHeapSize },
959 { "getNativeHeapAllocatedSize", "()J",
960 (void*) android_os_Debug_getNativeHeapAllocatedSize },
961 { "getNativeHeapFreeSize", "()J",
962 (void*) android_os_Debug_getNativeHeapFreeSize },
963 { "getMemoryInfo", "(Landroid/os/Debug$MemoryInfo;)V",
964 (void*) android_os_Debug_getDirtyPages },
Dianne Hackborn3025ef32009-08-31 21:31:47 -0700965 { "getMemoryInfo", "(ILandroid/os/Debug$MemoryInfo;)V",
966 (void*) android_os_Debug_getDirtyPagesPid },
Dianne Hackbornb437e092011-08-05 17:50:29 -0700967 { "getPss", "()J",
968 (void*) android_os_Debug_getPss },
Dianne Hackborn1a4b5a42014-12-08 17:43:31 -0800969 { "getPss", "(I[J[J)J",
Dianne Hackbornb437e092011-08-05 17:50:29 -0700970 (void*) android_os_Debug_getPssPid },
Dianne Hackborn8e692572013-09-10 19:06:15 -0700971 { "getMemInfo", "([J)V",
972 (void*) android_os_Debug_getMemInfo },
Andy McFadden06a6b552010-07-13 16:28:09 -0700973 { "dumpNativeHeap", "(Ljava/io/FileDescriptor;)V",
974 (void*) android_os_Debug_dumpNativeHeap },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975 { "getBinderSentTransactions", "()I",
976 (void*) android_os_Debug_getBinderSentTransactions },
977 { "getBinderReceivedTransactions", "()I",
978 (void*) android_os_getBinderReceivedTransactions },
979 { "getBinderLocalObjectCount", "()I",
980 (void*)android_os_Debug_getLocalObjectCount },
981 { "getBinderProxyObjectCount", "()I",
982 (void*)android_os_Debug_getProxyObjectCount },
983 { "getBinderDeathObjectCount", "()I",
984 (void*)android_os_Debug_getDeathObjectCount },
Dianne Hackbornf72467a2012-06-08 17:23:59 -0700985 { "dumpNativeBacktraceToFile", "(ILjava/lang/String;)V",
986 (void*)android_os_Debug_dumpNativeBacktraceToFile },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987};
988
989int register_android_os_Debug(JNIEnv *env)
990{
Adam Lesinski5b4ef812013-09-23 10:06:09 -0700991 int err = memtrack_init();
992 if (err != 0) {
993 memtrackLoaded = false;
994 ALOGE("failed to load memtrack module: %d", err);
995 } else {
996 memtrackLoaded = true;
997 }
998
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800999 jclass clazz = env->FindClass("android/os/Debug$MemoryInfo");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000
Ian Rogers7c9f30b2013-02-27 10:57:13 -08001001 // Sanity check the number of other statistics expected in Java matches here.
1002 jfieldID numOtherStats_field = env->GetStaticFieldID(clazz, "NUM_OTHER_STATS", "I");
1003 jint numOtherStats = env->GetStaticIntField(clazz, numOtherStats_field);
Anwar Ghuloum3c615062013-05-13 14:18:02 -07001004 jfieldID numDvkStats_field = env->GetStaticFieldID(clazz, "NUM_DVK_STATS", "I");
1005 jint numDvkStats = env->GetStaticIntField(clazz, numDvkStats_field);
Ian Rogers7c9f30b2013-02-27 10:57:13 -08001006 int expectedNumOtherStats = _NUM_HEAP - _NUM_CORE_HEAP;
Anwar Ghuloum3c615062013-05-13 14:18:02 -07001007 if ((numOtherStats + numDvkStats) != expectedNumOtherStats) {
Ian Rogers7c9f30b2013-02-27 10:57:13 -08001008 jniThrowExceptionFmt(env, "java/lang/RuntimeException",
Anwar Ghuloum3c615062013-05-13 14:18:02 -07001009 "android.os.Debug.Meminfo.NUM_OTHER_STATS+android.os.Debug.Meminfo.NUM_DVK_STATS=%d expected %d",
1010 numOtherStats+numDvkStats, expectedNumOtherStats);
Ian Rogers7c9f30b2013-02-27 10:57:13 -08001011 return JNI_ERR;
1012 }
1013
1014 otherStats_field = env->GetFieldID(clazz, "otherStats", "[I");
1015
Dianne Hackborn0e3328f2011-07-17 13:31:17 -07001016 for (int i=0; i<_NUM_CORE_HEAP; i++) {
1017 stat_fields[i].pss_field =
1018 env->GetFieldID(clazz, stat_field_names[i].pss_name, "I");
Anwar Ghuloum3c615062013-05-13 14:18:02 -07001019 stat_fields[i].pssSwappable_field =
1020 env->GetFieldID(clazz, stat_field_names[i].pssSwappable_name, "I");
Dianne Hackborn0e3328f2011-07-17 13:31:17 -07001021 stat_fields[i].privateDirty_field =
1022 env->GetFieldID(clazz, stat_field_names[i].privateDirty_name, "I");
1023 stat_fields[i].sharedDirty_field =
1024 env->GetFieldID(clazz, stat_field_names[i].sharedDirty_name, "I");
Anwar Ghuloum3c615062013-05-13 14:18:02 -07001025 stat_fields[i].privateClean_field =
1026 env->GetFieldID(clazz, stat_field_names[i].privateClean_name, "I");
Anwar Ghuloum3a8ce1b2013-04-26 16:18:28 -07001027 stat_fields[i].sharedClean_field =
1028 env->GetFieldID(clazz, stat_field_names[i].sharedClean_name, "I");
Dianne Hackborn8883ced2013-10-02 16:58:06 -07001029 stat_fields[i].swappedOut_field =
1030 env->GetFieldID(clazz, stat_field_names[i].swappedOut_name, "I");
Dianne Hackborn0e3328f2011-07-17 13:31:17 -07001031 }
1032
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods));
1034}
1035
Andy McFadden06a6b552010-07-13 16:28:09 -07001036}; // namespace android