• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
32 namespace android
33 {
34 
35 static jfieldID dalvikPss_field;
36 static jfieldID dalvikPrivateDirty_field;
37 static jfieldID dalvikSharedDirty_field;
38 static jfieldID nativePss_field;
39 static jfieldID nativePrivateDirty_field;
40 static jfieldID nativeSharedDirty_field;
41 static jfieldID otherPss_field;
42 static jfieldID otherPrivateDirty_field;
43 static jfieldID otherSharedDirty_field;
44 
45 struct 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 
android_os_Debug_getNativeHeapSize(JNIEnv * env,jobject clazz)61 static 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 
android_os_Debug_getNativeHeapAllocatedSize(JNIEnv * env,jobject clazz)71 static 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 
android_os_Debug_getNativeHeapFreeSize(JNIEnv * env,jobject clazz)81 static 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 
read_mapinfo(FILE * fp,stats_t * stats)91 static 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 
load_maps(int pid,stats_t * stats)190 static 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 
android_os_Debug_getDirtyPagesPid(JNIEnv * env,jobject clazz,jint pid,jobject object)203 static 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 
android_os_Debug_getDirtyPages(JNIEnv * env,jobject clazz,jobject object)224 static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject object)
225 {
226     android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object);
227 }
228 
read_binder_stat(const char * stat)229 static 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 
android_os_Debug_getBinderSentTransactions(JNIEnv * env,jobject clazz)262 static jint android_os_Debug_getBinderSentTransactions(JNIEnv *env, jobject clazz)
263 {
264     return read_binder_stat("bcTRANSACTION");
265 }
266 
android_os_getBinderReceivedTransactions(JNIEnv * env,jobject clazz)267 static 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
273 jint android_os_Debug_getLocalObjectCount(JNIEnv* env, jobject clazz);
274 jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz);
275 jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz);
276 
277 /*
278  * JNI registration.
279  */
280 
281 static 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 
register_android_os_Debug(JNIEnv * env)304 int 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