android_os_Debug.cpp revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
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 int read_mapinfo(FILE *fp, stats_t* stats) 92{ 93 char line[1024]; 94 int len; 95 int skip; 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 102 int isNativeHeap; 103 int isDalvikHeap; 104 int isSqliteHeap; 105 106again: 107 isNativeHeap = 0; 108 isDalvikHeap = 0; 109 isSqliteHeap = 0; 110 skip = 0; 111 112 if(fgets(line, 1024, fp) == 0) return 0; 113 114 len = strlen(line); 115 if (len < 1) return 0; 116 line[--len] = 0; 117 118 /* ignore guard pages */ 119 if (line[18] == '-') skip = 1; 120 121 start = strtoul(line, 0, 16); 122 123 if (len >= 50) { 124 if (!strcmp(line + 49, "[heap]")) { 125 isNativeHeap = 1; 126 } else if (!strncmp(line + 49, "/dalvik-LinearAlloc", strlen("/dalvik-LinearAlloc"))) { 127 isDalvikHeap = 1; 128 } else if (!strncmp(line + 49, "/mspace/dalvik-heap", strlen("/mspace/dalvik-heap"))) { 129 isDalvikHeap = 1; 130 } else if (!strncmp(line + 49, "/dalvik-heap-bitmap/", strlen("/dalvik-heap-bitmap/"))) { 131 isDalvikHeap = 1; 132 } else if (!strncmp(line + 49, "/tmp/sqlite-heap", strlen("/tmp/sqlite-heap"))) { 133 isSqliteHeap = 1; 134 } 135 } 136 137 // TODO: This needs to be fixed to be less fragile. If the order of this file changes or a new 138 // line is add, this method will return without filling out any of the information. 139 140 if (fgets(line, 1024, fp) == 0) return 0; 141 if (sscanf(line, "Size: %d kB", &size) != 1) return 0; 142 if (fgets(line, 1024, fp) == 0) return 0; 143 if (sscanf(line, "Rss: %d kB", &resident) != 1) return 0; 144 if (fgets(line, 1024, fp) == 0) return 0; 145 if (sscanf(line, "Pss: %d kB", &pss) != 1) return 0; 146 if (fgets(line, 1024, fp) == 0) return 0; 147 if (sscanf(line, "Shared_Clean: %d kB", &shared_clean) != 1) return 0; 148 if (fgets(line, 1024, fp) == 0) return 0; 149 if (sscanf(line, "Shared_Dirty: %d kB", &shared_dirty) != 1) return 0; 150 if (fgets(line, 1024, fp) == 0) return 0; 151 if (sscanf(line, "Private_Clean: %d kB", &private_clean) != 1) return 0; 152 if (fgets(line, 1024, fp) == 0) return 0; 153 if (sscanf(line, "Private_Dirty: %d kB", &private_dirty) != 1) return 0; 154 if (fgets(line, 1024, fp) == 0) return 0; 155 if (sscanf(line, "Referenced: %d kB", &referenced) != 1) return 0; 156 157 if (skip) { 158 goto again; 159 } 160 161 if (isNativeHeap) { 162 stats->nativePss += pss; 163 stats->nativePrivateDirty += private_dirty; 164 stats->nativeSharedDirty += shared_dirty; 165 } else if (isDalvikHeap) { 166 stats->dalvikPss += pss; 167 stats->dalvikPrivateDirty += private_dirty; 168 stats->dalvikSharedDirty += shared_dirty; 169 } else if (isSqliteHeap) { 170 // ignore 171 } else { 172 stats->otherPss += pss; 173 stats->otherPrivateDirty += shared_dirty; 174 stats->otherSharedDirty += private_dirty; 175 } 176 177 return 1; 178} 179 180static void load_maps(int pid, stats_t* stats) 181{ 182 char tmp[128]; 183 FILE *fp; 184 185 sprintf(tmp, "/proc/%d/smaps", pid); 186 fp = fopen(tmp, "r"); 187 if (fp == 0) return; 188 189 while (read_mapinfo(fp, stats) != 0) { 190 // Do nothing 191 } 192 fclose(fp); 193} 194 195static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject object) 196{ 197 stats_t stats; 198 memset(&stats, 0, sizeof(stats_t)); 199 200 load_maps(getpid(), &stats); 201 202 env->SetIntField(object, dalvikPss_field, stats.dalvikPss); 203 env->SetIntField(object, dalvikPrivateDirty_field, stats.dalvikPrivateDirty); 204 env->SetIntField(object, dalvikSharedDirty_field, stats.dalvikSharedDirty); 205 206 env->SetIntField(object, nativePss_field, stats.nativePss); 207 env->SetIntField(object, nativePrivateDirty_field, stats.nativePrivateDirty); 208 env->SetIntField(object, nativeSharedDirty_field, stats.nativeSharedDirty); 209 210 env->SetIntField(object, otherPss_field, stats.otherPss); 211 env->SetIntField(object, otherPrivateDirty_field, stats.otherPrivateDirty); 212 env->SetIntField(object, otherSharedDirty_field, stats.otherSharedDirty); 213} 214 215static jint read_binder_stat(const char* stat) 216{ 217 FILE* fp = fopen(BINDER_STATS, "r"); 218 if (fp == NULL) { 219 return -1; 220 } 221 222 char line[1024]; 223 224 char compare[128]; 225 int len = snprintf(compare, 128, "proc %d", getpid()); 226 227 // loop until we have the block that represents this process 228 do { 229 if (fgets(line, 1024, fp) == 0) { 230 return -1; 231 } 232 } while (strncmp(compare, line, len)); 233 234 // now that we have this process, read until we find the stat that we are looking for 235 len = snprintf(compare, 128, " %s: ", stat); 236 237 do { 238 if (fgets(line, 1024, fp) == 0) { 239 return -1; 240 } 241 } while (strncmp(compare, line, len)); 242 243 // we have the line, now increment the line ptr to the value 244 char* ptr = line + len; 245 return atoi(ptr); 246} 247 248static jint android_os_Debug_getBinderSentTransactions(JNIEnv *env, jobject clazz) 249{ 250 return read_binder_stat("bcTRANSACTION"); 251} 252 253static jint android_os_getBinderReceivedTransactions(JNIEnv *env, jobject clazz) 254{ 255 return read_binder_stat("brTRANSACTION"); 256} 257 258// these are implemented in android_util_Binder.cpp 259jint android_os_Debug_getLocalObjectCount(JNIEnv* env, jobject clazz); 260jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz); 261jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz); 262 263/* 264 * JNI registration. 265 */ 266 267static JNINativeMethod gMethods[] = { 268 { "getNativeHeapSize", "()J", 269 (void*) android_os_Debug_getNativeHeapSize }, 270 { "getNativeHeapAllocatedSize", "()J", 271 (void*) android_os_Debug_getNativeHeapAllocatedSize }, 272 { "getNativeHeapFreeSize", "()J", 273 (void*) android_os_Debug_getNativeHeapFreeSize }, 274 { "getMemoryInfo", "(Landroid/os/Debug$MemoryInfo;)V", 275 (void*) android_os_Debug_getDirtyPages }, 276 { "getBinderSentTransactions", "()I", 277 (void*) android_os_Debug_getBinderSentTransactions }, 278 { "getBinderReceivedTransactions", "()I", 279 (void*) android_os_getBinderReceivedTransactions }, 280 { "getBinderLocalObjectCount", "()I", 281 (void*)android_os_Debug_getLocalObjectCount }, 282 { "getBinderProxyObjectCount", "()I", 283 (void*)android_os_Debug_getProxyObjectCount }, 284 { "getBinderDeathObjectCount", "()I", 285 (void*)android_os_Debug_getDeathObjectCount }, 286}; 287 288int register_android_os_Debug(JNIEnv *env) 289{ 290 jclass clazz = env->FindClass("android/os/Debug$MemoryInfo"); 291 292 dalvikPss_field = env->GetFieldID(clazz, "dalvikPss", "I"); 293 dalvikPrivateDirty_field = env->GetFieldID(clazz, "dalvikPrivateDirty", "I"); 294 dalvikSharedDirty_field = env->GetFieldID(clazz, "dalvikSharedDirty", "I"); 295 296 nativePss_field = env->GetFieldID(clazz, "nativePss", "I"); 297 nativePrivateDirty_field = env->GetFieldID(clazz, "nativePrivateDirty", "I"); 298 nativeSharedDirty_field = env->GetFieldID(clazz, "nativeSharedDirty", "I"); 299 300 otherPss_field = env->GetFieldID(clazz, "otherPss", "I"); 301 otherPrivateDirty_field = env->GetFieldID(clazz, "otherPrivateDirty", "I"); 302 otherSharedDirty_field = env->GetFieldID(clazz, "otherSharedDirty", "I"); 303 304 return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods)); 305} 306 307}; 308