android_os_Debug.cpp revision 3025ef332c29e255388f74b2afefe05f64bce07c
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#include "JNIHelp.h"
18#include "jni.h"
19#include "utils/misc.h"
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <unistd.h>
25#include <time.h>
26#include <sys/time.h>
27
28#ifdef HAVE_MALLOC_H
29#include <malloc.h>
30#endif
31
32namespace android
33{
34
35static jfieldID dalvikPss_field;
36static jfieldID dalvikPrivateDirty_field;
37static jfieldID dalvikSharedDirty_field;
38static jfieldID nativePss_field;
39static jfieldID nativePrivateDirty_field;
40static jfieldID nativeSharedDirty_field;
41static jfieldID otherPss_field;
42static jfieldID otherPrivateDirty_field;
43static jfieldID otherSharedDirty_field;
44
45struct stats_t {
46    int dalvikPss;
47    int dalvikPrivateDirty;
48    int dalvikSharedDirty;
49
50    int nativePss;
51    int nativePrivateDirty;
52    int nativeSharedDirty;
53
54    int otherPss;
55    int otherPrivateDirty;
56    int otherSharedDirty;
57};
58
59#define BINDER_STATS "/proc/binder/stats"
60
61static jlong android_os_Debug_getNativeHeapSize(JNIEnv *env, jobject clazz)
62{
63#ifdef HAVE_MALLOC_H
64    struct mallinfo info = mallinfo();
65    return (jlong) info.usmblks;
66#else
67    return -1;
68#endif
69}
70
71static jlong android_os_Debug_getNativeHeapAllocatedSize(JNIEnv *env, jobject clazz)
72{
73#ifdef HAVE_MALLOC_H
74    struct mallinfo info = mallinfo();
75    return (jlong) info.uordblks;
76#else
77    return -1;
78#endif
79}
80
81static jlong android_os_Debug_getNativeHeapFreeSize(JNIEnv *env, jobject clazz)
82{
83#ifdef HAVE_MALLOC_H
84    struct mallinfo info = mallinfo();
85    return (jlong) info.fordblks;
86#else
87    return -1;
88#endif
89}
90
91static void read_mapinfo(FILE *fp, stats_t* stats)
92{
93    char line[1024];
94    int len;
95    bool skip, done = false;
96
97    unsigned start = 0, size = 0, resident = 0, pss = 0;
98    unsigned shared_clean = 0, shared_dirty = 0;
99    unsigned private_clean = 0, private_dirty = 0;
100    unsigned referenced = 0;
101    unsigned temp;
102
103    int isNativeHeap;
104    int isDalvikHeap;
105    int isSqliteHeap;
106
107    if(fgets(line, 1024, fp) == 0) return;
108
109    while (!done) {
110        isNativeHeap = 0;
111        isDalvikHeap = 0;
112        isSqliteHeap = 0;
113        skip = false;
114
115        len = strlen(line);
116        if (len < 1) return;
117        line[--len] = 0;
118
119        /* ignore guard pages */
120        if (len > 18 && line[17] == '-') skip = true;
121
122        start = strtoul(line, 0, 16);
123
124        if (strstr(line, "[heap]")) {
125            isNativeHeap = 1;
126        } else if (strstr(line, "/dalvik-LinearAlloc")) {
127            isDalvikHeap = 1;
128        } else if (strstr(line, "/mspace/dalvik-heap")) {
129            isDalvikHeap = 1;
130        } else if (strstr(line, "/dalvik-heap-bitmap/")) {
131            isDalvikHeap = 1;
132        } else if (strstr(line, "/data/dalvik-cache/")) {
133            isDalvikHeap = 1;
134        } else if (strstr(line, "/tmp/sqlite-heap")) {
135            isSqliteHeap = 1;
136        }
137
138        //LOGI("native=%d dalvik=%d sqlite=%d: %s\n", isNativeHeap, isDalvikHeap,
139        //    isSqliteHeap, line);
140
141        while (true) {
142            if (fgets(line, 1024, fp) == 0) {
143                done = true;
144                break;
145            }
146
147            if (sscanf(line, "Size: %d kB", &temp) == 1) {
148                size = temp;
149            } else if (sscanf(line, "Rss: %d kB", &temp) == 1) {
150                resident = temp;
151            } else if (sscanf(line, "Pss: %d kB", &temp) == 1) {
152                pss = temp;
153            } else if (sscanf(line, "Shared_Clean: %d kB", &temp) == 1) {
154                shared_clean = temp;
155            } else if (sscanf(line, "Shared_Dirty: %d kB", &temp) == 1) {
156                shared_dirty = temp;
157            } else if (sscanf(line, "Private_Clean: %d kB", &temp) == 1) {
158                private_clean = temp;
159            } else if (sscanf(line, "Private_Dirty: %d kB", &temp) == 1) {
160                private_dirty = temp;
161            } else if (sscanf(line, "Referenced: %d kB", &temp) == 1) {
162                referenced = temp;
163            } else if (strlen(line) > 30 && line[8] == '-' && line[17] == ' ') {
164                // looks like a new mapping
165                // example: "10000000-10001000 ---p 10000000 00:00 0"
166                break;
167            }
168        }
169
170        if (!skip) {
171            if (isNativeHeap) {
172                stats->nativePss += pss;
173                stats->nativePrivateDirty += private_dirty;
174                stats->nativeSharedDirty += shared_dirty;
175            } else if (isDalvikHeap) {
176                stats->dalvikPss += pss;
177                stats->dalvikPrivateDirty += private_dirty;
178                stats->dalvikSharedDirty += shared_dirty;
179            } else if ( isSqliteHeap) {
180                // ignore
181            } else {
182                stats->otherPss += pss;
183                stats->otherPrivateDirty += private_dirty;
184                stats->otherSharedDirty += shared_dirty;
185            }
186        }
187    }
188}
189
190static void load_maps(int pid, stats_t* stats)
191{
192    char tmp[128];
193    FILE *fp;
194
195    sprintf(tmp, "/proc/%d/smaps", pid);
196    fp = fopen(tmp, "r");
197    if (fp == 0) return;
198
199    read_mapinfo(fp, stats);
200    fclose(fp);
201}
202
203static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
204        jint pid, jobject object)
205{
206    stats_t stats;
207    memset(&stats, 0, sizeof(stats_t));
208
209    load_maps(pid, &stats);
210
211    env->SetIntField(object, dalvikPss_field, stats.dalvikPss);
212    env->SetIntField(object, dalvikPrivateDirty_field, stats.dalvikPrivateDirty);
213    env->SetIntField(object, dalvikSharedDirty_field, stats.dalvikSharedDirty);
214
215    env->SetIntField(object, nativePss_field, stats.nativePss);
216    env->SetIntField(object, nativePrivateDirty_field, stats.nativePrivateDirty);
217    env->SetIntField(object, nativeSharedDirty_field, stats.nativeSharedDirty);
218
219    env->SetIntField(object, otherPss_field, stats.otherPss);
220    env->SetIntField(object, otherPrivateDirty_field, stats.otherPrivateDirty);
221    env->SetIntField(object, otherSharedDirty_field, stats.otherSharedDirty);
222}
223
224static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject object)
225{
226    android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object);
227}
228
229static jint read_binder_stat(const char* stat)
230{
231    FILE* fp = fopen(BINDER_STATS, "r");
232    if (fp == NULL) {
233        return -1;
234    }
235
236    char line[1024];
237
238    char compare[128];
239    int len = snprintf(compare, 128, "proc %d", getpid());
240
241    // loop until we have the block that represents this process
242    do {
243        if (fgets(line, 1024, fp) == 0) {
244            return -1;
245        }
246    } while (strncmp(compare, line, len));
247
248    // now that we have this process, read until we find the stat that we are looking for
249    len = snprintf(compare, 128, "  %s: ", stat);
250
251    do {
252        if (fgets(line, 1024, fp) == 0) {
253            return -1;
254        }
255    } while (strncmp(compare, line, len));
256
257    // we have the line, now increment the line ptr to the value
258    char* ptr = line + len;
259    return atoi(ptr);
260}
261
262static jint android_os_Debug_getBinderSentTransactions(JNIEnv *env, jobject clazz)
263{
264    return read_binder_stat("bcTRANSACTION");
265}
266
267static jint android_os_getBinderReceivedTransactions(JNIEnv *env, jobject clazz)
268{
269    return read_binder_stat("brTRANSACTION");
270}
271
272// these are implemented in android_util_Binder.cpp
273jint android_os_Debug_getLocalObjectCount(JNIEnv* env, jobject clazz);
274jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz);
275jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz);
276
277/*
278 * JNI registration.
279 */
280
281static JNINativeMethod gMethods[] = {
282    { "getNativeHeapSize",      "()J",
283            (void*) android_os_Debug_getNativeHeapSize },
284    { "getNativeHeapAllocatedSize", "()J",
285            (void*) android_os_Debug_getNativeHeapAllocatedSize },
286    { "getNativeHeapFreeSize",  "()J",
287            (void*) android_os_Debug_getNativeHeapFreeSize },
288    { "getMemoryInfo",          "(Landroid/os/Debug$MemoryInfo;)V",
289            (void*) android_os_Debug_getDirtyPages },
290    { "getMemoryInfo",          "(ILandroid/os/Debug$MemoryInfo;)V",
291            (void*) android_os_Debug_getDirtyPagesPid },
292    { "getBinderSentTransactions", "()I",
293            (void*) android_os_Debug_getBinderSentTransactions },
294    { "getBinderReceivedTransactions", "()I",
295            (void*) android_os_getBinderReceivedTransactions },
296    { "getBinderLocalObjectCount", "()I",
297            (void*)android_os_Debug_getLocalObjectCount },
298    { "getBinderProxyObjectCount", "()I",
299            (void*)android_os_Debug_getProxyObjectCount },
300    { "getBinderDeathObjectCount", "()I",
301            (void*)android_os_Debug_getDeathObjectCount },
302};
303
304int register_android_os_Debug(JNIEnv *env)
305{
306    jclass clazz = env->FindClass("android/os/Debug$MemoryInfo");
307
308    dalvikPss_field = env->GetFieldID(clazz, "dalvikPss", "I");
309    dalvikPrivateDirty_field = env->GetFieldID(clazz, "dalvikPrivateDirty", "I");
310    dalvikSharedDirty_field = env->GetFieldID(clazz, "dalvikSharedDirty", "I");
311
312    nativePss_field = env->GetFieldID(clazz, "nativePss", "I");
313    nativePrivateDirty_field = env->GetFieldID(clazz, "nativePrivateDirty", "I");
314    nativeSharedDirty_field = env->GetFieldID(clazz, "nativeSharedDirty", "I");
315
316    otherPss_field = env->GetFieldID(clazz, "otherPss", "I");
317    otherPrivateDirty_field = env->GetFieldID(clazz, "otherPrivateDirty", "I");
318    otherSharedDirty_field = env->GetFieldID(clazz, "otherSharedDirty", "I");
319
320    return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods));
321}
322
323};
324