blob: d9908ce86c04dab4213ce81f8cb2f6804b9ccf36 [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"
20#include "utils/misc.h"
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26#include <time.h>
27#include <sys/time.h>
Andy McFadden06a6b552010-07-13 16:28:09 -070028#include <errno.h>
29#include <assert.h>
Dianne Hackborn0e3328f2011-07-17 13:31:17 -070030#include <ctype.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031
32#ifdef HAVE_MALLOC_H
33#include <malloc.h>
34#endif
35
36namespace android
37{
38
Dianne Hackborn0e3328f2011-07-17 13:31:17 -070039enum {
40 HEAP_UNKNOWN,
41 HEAP_DALVIK,
42 HEAP_NATIVE,
43 HEAP_CURSOR,
44 HEAP_ASHMEM,
45 HEAP_UNKNOWN_DEV,
46 HEAP_SO,
47 HEAP_JAR,
48 HEAP_APK,
49 HEAP_TTF,
50 HEAP_DEX,
51 HEAP_UNKNOWN_MAP,
52
53 _NUM_HEAP,
54 _NUM_CORE_HEAP = HEAP_NATIVE+1
55};
56
57struct stat_fields {
58 jfieldID pss_field;
59 jfieldID privateDirty_field;
60 jfieldID sharedDirty_field;
61};
62
63struct stat_field_names {
64 const char* pss_name;
65 const char* privateDirty_name;
66 const char* sharedDirty_name;
67};
68
69static stat_fields stat_fields[_NUM_CORE_HEAP];
70
71static stat_field_names stat_field_names[_NUM_CORE_HEAP] = {
72 { "otherPss", "otherPrivateDirty", "otherSharedDirty" },
73 { "dalvikPss", "dalvikPrivateDirty", "dalvikSharedDirty" },
74 { "nativePss", "nativePrivateDirty", "nativeSharedDirty" }
75};
76
77jfieldID otherStats_field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078
79struct stats_t {
Dianne Hackborn0e3328f2011-07-17 13:31:17 -070080 int pss;
81 int privateDirty;
82 int sharedDirty;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083};
84
85#define BINDER_STATS "/proc/binder/stats"
86
87static jlong android_os_Debug_getNativeHeapSize(JNIEnv *env, jobject clazz)
88{
89#ifdef HAVE_MALLOC_H
90 struct mallinfo info = mallinfo();
91 return (jlong) info.usmblks;
92#else
93 return -1;
94#endif
95}
96
97static jlong android_os_Debug_getNativeHeapAllocatedSize(JNIEnv *env, jobject clazz)
98{
99#ifdef HAVE_MALLOC_H
100 struct mallinfo info = mallinfo();
101 return (jlong) info.uordblks;
102#else
103 return -1;
104#endif
105}
106
107static jlong android_os_Debug_getNativeHeapFreeSize(JNIEnv *env, jobject clazz)
108{
109#ifdef HAVE_MALLOC_H
110 struct mallinfo info = mallinfo();
111 return (jlong) info.fordblks;
112#else
113 return -1;
114#endif
115}
116
117static void read_mapinfo(FILE *fp, stats_t* stats)
118{
119 char line[1024];
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700120 int len, nameLen;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 bool skip, done = false;
122
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700123 unsigned size = 0, resident = 0, pss = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 unsigned shared_clean = 0, shared_dirty = 0;
125 unsigned private_clean = 0, private_dirty = 0;
126 unsigned referenced = 0;
127 unsigned temp;
128
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700129 unsigned long int start;
130 unsigned long int end = 0;
131 unsigned long int prevEnd = 0;
132 char* name;
133 int name_pos;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700135 int whichHeap = HEAP_UNKNOWN;
136 int prevHeap = HEAP_UNKNOWN;
137
138 if(fgets(line, sizeof(line), fp) == 0) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139
140 while (!done) {
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700141 prevHeap = whichHeap;
142 prevEnd = end;
143 whichHeap = HEAP_UNKNOWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 skip = false;
145
146 len = strlen(line);
147 if (len < 1) return;
148 line[--len] = 0;
149
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700150 if (sscanf(line, "%lx-%lx %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) {
151 skip = true;
152 } else {
153 while (isspace(line[name_pos])) {
154 name_pos += 1;
155 }
156 name = line + name_pos;
157 nameLen = strlen(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700159 if (strstr(name, "[heap]") == name) {
160 whichHeap = HEAP_NATIVE;
161 } else if (strstr(name, "/dev/ashmem/dalvik-") == name) {
162 whichHeap = HEAP_DALVIK;
163 } else if (strstr(name, "/dev/ashmem/CursorWindow") == name) {
164 whichHeap = HEAP_CURSOR;
165 } else if (strstr(name, "/dev/ashmem/") == name) {
166 whichHeap = HEAP_ASHMEM;
167 } else if (strstr(name, "/dev/") == name) {
168 whichHeap = HEAP_UNKNOWN_DEV;
169 } else if (nameLen > 3 && strcmp(name+nameLen-3, ".so") == 0) {
170 whichHeap = HEAP_SO;
171 } else if (nameLen > 4 && strcmp(name+nameLen-4, ".jar") == 0) {
172 whichHeap = HEAP_JAR;
173 } else if (nameLen > 4 && strcmp(name+nameLen-4, ".apk") == 0) {
174 whichHeap = HEAP_APK;
175 } else if (nameLen > 4 && strcmp(name+nameLen-4, ".ttf") == 0) {
176 whichHeap = HEAP_TTF;
177 } else if (nameLen > 4 && strcmp(name+nameLen-4, ".dex") == 0) {
178 whichHeap = HEAP_DEX;
179 } else if (nameLen > 0) {
180 whichHeap = HEAP_UNKNOWN_MAP;
181 } else if (start == prevEnd && prevHeap == HEAP_SO) {
182 // bss section of a shared library.
183 whichHeap = HEAP_SO;
184 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 }
186
Steve Block6215d3f2012-01-04 20:05:49 +0000187 //ALOGI("native=%d dalvik=%d sqlite=%d: %s\n", isNativeHeap, isDalvikHeap,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 // isSqliteHeap, line);
189
190 while (true) {
191 if (fgets(line, 1024, fp) == 0) {
192 done = true;
193 break;
194 }
195
196 if (sscanf(line, "Size: %d kB", &temp) == 1) {
197 size = temp;
198 } else if (sscanf(line, "Rss: %d kB", &temp) == 1) {
199 resident = temp;
200 } else if (sscanf(line, "Pss: %d kB", &temp) == 1) {
201 pss = temp;
202 } else if (sscanf(line, "Shared_Clean: %d kB", &temp) == 1) {
203 shared_clean = temp;
204 } else if (sscanf(line, "Shared_Dirty: %d kB", &temp) == 1) {
205 shared_dirty = temp;
206 } else if (sscanf(line, "Private_Clean: %d kB", &temp) == 1) {
207 private_clean = temp;
208 } else if (sscanf(line, "Private_Dirty: %d kB", &temp) == 1) {
209 private_dirty = temp;
210 } else if (sscanf(line, "Referenced: %d kB", &temp) == 1) {
211 referenced = temp;
Grace Klobabd511162009-07-08 23:32:25 -0700212 } else if (strlen(line) > 30 && line[8] == '-' && line[17] == ' ') {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 // looks like a new mapping
Grace Klobabd511162009-07-08 23:32:25 -0700214 // example: "10000000-10001000 ---p 10000000 00:00 0"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 break;
216 }
217 }
218
219 if (!skip) {
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700220 stats[whichHeap].pss += pss;
221 stats[whichHeap].privateDirty += private_dirty;
222 stats[whichHeap].sharedDirty += shared_dirty;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 }
224 }
225}
226
227static void load_maps(int pid, stats_t* stats)
228{
229 char tmp[128];
230 FILE *fp;
231
232 sprintf(tmp, "/proc/%d/smaps", pid);
233 fp = fopen(tmp, "r");
234 if (fp == 0) return;
235
236 read_mapinfo(fp, stats);
237 fclose(fp);
238}
239
Dianne Hackborn3025ef32009-08-31 21:31:47 -0700240static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
241 jint pid, jobject object)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242{
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700243 stats_t stats[_NUM_HEAP];
244 memset(&stats, 0, sizeof(stats));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700246 load_maps(pid, stats);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700248 for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
249 stats[HEAP_UNKNOWN].pss += stats[i].pss;
250 stats[HEAP_UNKNOWN].privateDirty += stats[i].privateDirty;
251 stats[HEAP_UNKNOWN].sharedDirty += stats[i].sharedDirty;
252 }
253
254 for (int i=0; i<_NUM_CORE_HEAP; i++) {
255 env->SetIntField(object, stat_fields[i].pss_field, stats[i].pss);
256 env->SetIntField(object, stat_fields[i].privateDirty_field, stats[i].privateDirty);
257 env->SetIntField(object, stat_fields[i].sharedDirty_field, stats[i].sharedDirty);
258 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700260 jintArray otherIntArray = (jintArray)env->GetObjectField(object, otherStats_field);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700262 jint* otherArray = (jint*)env->GetPrimitiveArrayCritical(otherIntArray, 0);
263 if (otherArray == NULL) {
264 return;
265 }
266
267 int j=0;
268 for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
269 otherArray[j++] = stats[i].pss;
270 otherArray[j++] = stats[i].privateDirty;
271 otherArray[j++] = stats[i].sharedDirty;
272 }
273
274 env->ReleasePrimitiveArrayCritical(otherIntArray, otherArray, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275}
276
Dianne Hackborn3025ef32009-08-31 21:31:47 -0700277static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject object)
278{
279 android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object);
280}
281
Dianne Hackbornb437e092011-08-05 17:50:29 -0700282static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid)
283{
284 char line[1024];
285 jlong pss = 0;
286 unsigned temp;
287
288 char tmp[128];
289 FILE *fp;
290
291 sprintf(tmp, "/proc/%d/smaps", pid);
292 fp = fopen(tmp, "r");
293 if (fp == 0) return 0;
294
295 while (true) {
296 if (fgets(line, 1024, fp) == 0) {
297 break;
298 }
299
300 if (sscanf(line, "Pss: %d kB", &temp) == 1) {
301 pss += temp;
302 }
303 }
304
305 fclose(fp);
306
307 return pss;
308}
309
310static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz)
311{
312 return android_os_Debug_getPssPid(env, clazz, getpid());
313}
314
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315static jint read_binder_stat(const char* stat)
316{
317 FILE* fp = fopen(BINDER_STATS, "r");
318 if (fp == NULL) {
319 return -1;
320 }
321
322 char line[1024];
323
324 char compare[128];
325 int len = snprintf(compare, 128, "proc %d", getpid());
326
327 // loop until we have the block that represents this process
328 do {
329 if (fgets(line, 1024, fp) == 0) {
330 return -1;
331 }
332 } while (strncmp(compare, line, len));
333
334 // now that we have this process, read until we find the stat that we are looking for
335 len = snprintf(compare, 128, " %s: ", stat);
336
337 do {
338 if (fgets(line, 1024, fp) == 0) {
339 return -1;
340 }
341 } while (strncmp(compare, line, len));
342
343 // we have the line, now increment the line ptr to the value
344 char* ptr = line + len;
345 return atoi(ptr);
346}
347
348static jint android_os_Debug_getBinderSentTransactions(JNIEnv *env, jobject clazz)
349{
350 return read_binder_stat("bcTRANSACTION");
351}
352
353static jint android_os_getBinderReceivedTransactions(JNIEnv *env, jobject clazz)
354{
355 return read_binder_stat("brTRANSACTION");
356}
357
358// these are implemented in android_util_Binder.cpp
359jint android_os_Debug_getLocalObjectCount(JNIEnv* env, jobject clazz);
360jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz);
361jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz);
362
Andy McFadden06a6b552010-07-13 16:28:09 -0700363
Andy McFadden06a6b552010-07-13 16:28:09 -0700364/* pulled out of bionic */
365extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
366 size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
367extern "C" void free_malloc_leak_info(uint8_t* info);
368#define SIZE_FLAG_ZYGOTE_CHILD (1<<31)
369#define BACKTRACE_SIZE 32
370
371/*
372 * This is a qsort() callback.
373 *
374 * See dumpNativeHeap() for comments about the data format and sort order.
375 */
376static int compareHeapRecords(const void* vrec1, const void* vrec2)
377{
378 const size_t* rec1 = (const size_t*) vrec1;
379 const size_t* rec2 = (const size_t*) vrec2;
380 size_t size1 = *rec1;
381 size_t size2 = *rec2;
382
383 if (size1 < size2) {
384 return 1;
385 } else if (size1 > size2) {
386 return -1;
387 }
388
389 intptr_t* bt1 = (intptr_t*)(rec1 + 2);
390 intptr_t* bt2 = (intptr_t*)(rec2 + 2);
391 for (size_t idx = 0; idx < BACKTRACE_SIZE; idx++) {
392 intptr_t addr1 = bt1[idx];
393 intptr_t addr2 = bt2[idx];
394 if (addr1 == addr2) {
395 if (addr1 == 0)
396 break;
397 continue;
398 }
399 if (addr1 < addr2) {
400 return -1;
401 } else if (addr1 > addr2) {
402 return 1;
403 }
404 }
405
406 return 0;
407}
408
409/*
410 * The get_malloc_leak_info() call returns an array of structs that
411 * look like this:
412 *
413 * size_t size
414 * size_t allocations
415 * intptr_t backtrace[32]
416 *
417 * "size" is the size of the allocation, "backtrace" is a fixed-size
418 * array of function pointers, and "allocations" is the number of
419 * allocations with the exact same size and backtrace.
420 *
421 * The entries are sorted by descending total size (i.e. size*allocations)
422 * then allocation count. For best results with "diff" we'd like to sort
423 * primarily by individual size then stack trace. Since the entries are
424 * fixed-size, and we're allowed (by the current implementation) to mangle
425 * them, we can do this in place.
426 */
427static void dumpNativeHeap(FILE* fp)
428{
429 uint8_t* info = NULL;
430 size_t overallSize, infoSize, totalMemory, backtraceSize;
431
432 get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory,
433 &backtraceSize);
434 if (info == NULL) {
435 fprintf(fp, "Native heap dump not available. To enable, run these"
436 " commands (requires root):\n");
437 fprintf(fp, "$ adb shell setprop libc.debug.malloc 1\n");
438 fprintf(fp, "$ adb shell stop\n");
439 fprintf(fp, "$ adb shell start\n");
440 return;
441 }
442 assert(infoSize != 0);
443 assert(overallSize % infoSize == 0);
444
445 fprintf(fp, "Android Native Heap Dump v1.0\n\n");
446
447 size_t recordCount = overallSize / infoSize;
448 fprintf(fp, "Total memory: %zu\n", totalMemory);
449 fprintf(fp, "Allocation records: %zd\n", recordCount);
450 if (backtraceSize != BACKTRACE_SIZE) {
451 fprintf(fp, "WARNING: mismatched backtrace sizes (%d vs. %d)\n",
452 backtraceSize, BACKTRACE_SIZE);
453 }
454 fprintf(fp, "\n");
455
456 /* re-sort the entries */
457 qsort(info, recordCount, infoSize, compareHeapRecords);
458
459 /* dump the entries to the file */
460 const uint8_t* ptr = info;
461 for (size_t idx = 0; idx < recordCount; idx++) {
462 size_t size = *(size_t*) ptr;
463 size_t allocations = *(size_t*) (ptr + sizeof(size_t));
464 intptr_t* backtrace = (intptr_t*) (ptr + sizeof(size_t) * 2);
465
466 fprintf(fp, "z %d sz %8zu num %4zu bt",
467 (size & SIZE_FLAG_ZYGOTE_CHILD) != 0,
468 size & ~SIZE_FLAG_ZYGOTE_CHILD,
469 allocations);
470 for (size_t bt = 0; bt < backtraceSize; bt++) {
471 if (backtrace[bt] == 0) {
472 break;
473 } else {
474 fprintf(fp, " %08x", backtrace[bt]);
475 }
476 }
477 fprintf(fp, "\n");
478
479 ptr += infoSize;
480 }
481
Andy McFadden06a6b552010-07-13 16:28:09 -0700482 free_malloc_leak_info(info);
Brian Carlstrom393b84c12010-10-17 23:40:43 -0700483
484 fprintf(fp, "MAPS\n");
485 const char* maps = "/proc/self/maps";
486 FILE* in = fopen(maps, "r");
487 if (in == NULL) {
488 fprintf(fp, "Could not open %s\n", maps);
489 return;
490 }
491 char buf[BUFSIZ];
492 while (size_t n = fread(buf, sizeof(char), BUFSIZ, in)) {
493 fwrite(buf, sizeof(char), n, fp);
494 }
495 fclose(in);
496
497 fprintf(fp, "END\n");
Andy McFadden06a6b552010-07-13 16:28:09 -0700498}
Andy McFadden06a6b552010-07-13 16:28:09 -0700499
500/*
501 * Dump the native heap, writing human-readable output to the specified
502 * file descriptor.
503 */
504static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject clazz,
505 jobject fileDescriptor)
506{
507 if (fileDescriptor == NULL) {
508 jniThrowNullPointerException(env, NULL);
509 return;
510 }
511 int origFd = jniGetFDFromFileDescriptor(env, fileDescriptor);
512 if (origFd < 0) {
513 jniThrowRuntimeException(env, "Invalid file descriptor");
514 return;
515 }
516
517 /* dup() the descriptor so we don't close the original with fclose() */
518 int fd = dup(origFd);
519 if (fd < 0) {
520 LOGW("dup(%d) failed: %s\n", origFd, strerror(errno));
521 jniThrowRuntimeException(env, "dup() failed");
522 return;
523 }
524
525 FILE* fp = fdopen(fd, "w");
526 if (fp == NULL) {
527 LOGW("fdopen(%d) failed: %s\n", fd, strerror(errno));
528 close(fd);
529 jniThrowRuntimeException(env, "fdopen() failed");
530 return;
531 }
532
Steve Block5baa3a62011-12-20 16:23:08 +0000533 ALOGD("Native heap dump starting...\n");
Andy McFadden06a6b552010-07-13 16:28:09 -0700534 dumpNativeHeap(fp);
Steve Block5baa3a62011-12-20 16:23:08 +0000535 ALOGD("Native heap dump complete.\n");
Andy McFadden06a6b552010-07-13 16:28:09 -0700536
537 fclose(fp);
538}
539
540
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541/*
542 * JNI registration.
543 */
544
545static JNINativeMethod gMethods[] = {
546 { "getNativeHeapSize", "()J",
547 (void*) android_os_Debug_getNativeHeapSize },
548 { "getNativeHeapAllocatedSize", "()J",
549 (void*) android_os_Debug_getNativeHeapAllocatedSize },
550 { "getNativeHeapFreeSize", "()J",
551 (void*) android_os_Debug_getNativeHeapFreeSize },
552 { "getMemoryInfo", "(Landroid/os/Debug$MemoryInfo;)V",
553 (void*) android_os_Debug_getDirtyPages },
Dianne Hackborn3025ef32009-08-31 21:31:47 -0700554 { "getMemoryInfo", "(ILandroid/os/Debug$MemoryInfo;)V",
555 (void*) android_os_Debug_getDirtyPagesPid },
Dianne Hackbornb437e092011-08-05 17:50:29 -0700556 { "getPss", "()J",
557 (void*) android_os_Debug_getPss },
558 { "getPss", "(I)J",
559 (void*) android_os_Debug_getPssPid },
Andy McFadden06a6b552010-07-13 16:28:09 -0700560 { "dumpNativeHeap", "(Ljava/io/FileDescriptor;)V",
561 (void*) android_os_Debug_dumpNativeHeap },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 { "getBinderSentTransactions", "()I",
563 (void*) android_os_Debug_getBinderSentTransactions },
564 { "getBinderReceivedTransactions", "()I",
565 (void*) android_os_getBinderReceivedTransactions },
566 { "getBinderLocalObjectCount", "()I",
567 (void*)android_os_Debug_getLocalObjectCount },
568 { "getBinderProxyObjectCount", "()I",
569 (void*)android_os_Debug_getProxyObjectCount },
570 { "getBinderDeathObjectCount", "()I",
571 (void*)android_os_Debug_getDeathObjectCount },
572};
573
574int register_android_os_Debug(JNIEnv *env)
575{
576 jclass clazz = env->FindClass("android/os/Debug$MemoryInfo");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577
Dianne Hackborn0e3328f2011-07-17 13:31:17 -0700578 for (int i=0; i<_NUM_CORE_HEAP; i++) {
579 stat_fields[i].pss_field =
580 env->GetFieldID(clazz, stat_field_names[i].pss_name, "I");
581 stat_fields[i].privateDirty_field =
582 env->GetFieldID(clazz, stat_field_names[i].privateDirty_name, "I");
583 stat_fields[i].sharedDirty_field =
584 env->GetFieldID(clazz, stat_field_names[i].sharedDirty_name, "I");
585 }
586
587 otherStats_field = env->GetFieldID(clazz, "otherStats", "[I");
588
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589 return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods));
590}
591
Andy McFadden06a6b552010-07-13 16:28:09 -0700592}; // namespace android