• 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 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <cutils/mspace.h>
25 #include <utils/Log.h>
26 
27 #include <sqlite3.h>
28 
29 // From mem_mspace.c in libsqlite
30 extern "C" mspace sqlite3_get_mspace();
31 
32 // From sqlite.c, hacked in for Android
33 extern "C" void sqlite3_get_pager_stats(sqlite3_int64 * totalBytesOut,
34                                        sqlite3_int64 * referencedBytesOut,
35                                        sqlite3_int64 * dbBytesOut,
36                                        int * numPagersOut);
37 
38 namespace android {
39 
40 static jfieldID gTotalBytesField;
41 static jfieldID gReferencedBytesField;
42 static jfieldID gDbBytesField;
43 static jfieldID gNumPagersField;
44 
45 
46 #define USE_MSPACE 0
47 
getPagerStats(JNIEnv * env,jobject clazz,jobject statsObj)48 static void getPagerStats(JNIEnv *env, jobject clazz, jobject statsObj)
49 {
50     sqlite3_int64 totalBytes;
51     sqlite3_int64 referencedBytes;
52     sqlite3_int64 dbBytes;
53     int numPagers;
54 
55     sqlite3_get_pager_stats(&totalBytes, &referencedBytes, &dbBytes,
56             &numPagers);
57 
58     env->SetLongField(statsObj, gTotalBytesField, totalBytes);
59     env->SetLongField(statsObj, gReferencedBytesField, referencedBytes);
60     env->SetLongField(statsObj, gDbBytesField, dbBytes);
61     env->SetIntField(statsObj, gNumPagersField, numPagers);
62 }
63 
getHeapSize(JNIEnv * env,jobject clazz)64 static jlong getHeapSize(JNIEnv *env, jobject clazz)
65 {
66 #if !NO_MALLINFO
67     struct mallinfo info = mspace_mallinfo(sqlite3_get_mspace());
68     struct mallinfo info = dlmallinfo();
69     return (jlong) info.usmblks;
70 #elif USE_MSPACE
71     mspace space = sqlite3_get_mspace();
72     if (space != 0) {
73         return mspace_footprint(space);
74     } else {
75         return 0;
76     }
77 #else
78     return 0;
79 #endif
80 }
81 
getHeapAllocatedSize(JNIEnv * env,jobject clazz)82 static jlong getHeapAllocatedSize(JNIEnv *env, jobject clazz)
83 {
84 #if !NO_MALLINFO
85     struct mallinfo info = mspace_mallinfo(sqlite3_get_mspace());
86     return (jlong) info.uordblks;
87 #else
88     return sqlite3_memory_used();
89 #endif
90 }
91 
getHeapFreeSize(JNIEnv * env,jobject clazz)92 static jlong getHeapFreeSize(JNIEnv *env, jobject clazz)
93 {
94 #if !NO_MALLINFO
95     struct mallinfo info = mspace_mallinfo(sqlite3_get_mspace());
96     return (jlong) info.fordblks;
97 #else
98     return getHeapSize(env, clazz) - sqlite3_memory_used();
99 #endif
100 }
101 
read_mapinfo(FILE * fp,int * sharedPages,int * privatePages)102 static int read_mapinfo(FILE *fp,
103         int *sharedPages, int *privatePages)
104 {
105     char line[1024];
106     int len;
107     int skip;
108 
109     unsigned start = 0, size = 0, resident = 0;
110     unsigned shared_clean = 0, shared_dirty = 0;
111     unsigned private_clean = 0, private_dirty = 0;
112     unsigned referenced = 0;
113 
114     int isAnon = 0;
115     int isHeap = 0;
116 
117 again:
118     skip = 0;
119 
120     if(fgets(line, 1024, fp) == 0) return 0;
121 
122     len = strlen(line);
123     if (len < 1) return 0;
124     line[--len] = 0;
125 
126     /* ignore guard pages */
127     if (line[18] == '-') skip = 1;
128 
129     start = strtoul(line, 0, 16);
130 
131     if (len > 50 && !strncmp(line + 49, "/tmp/sqlite-heap", strlen("/tmp/sqlite-heap"))) {
132         isHeap = 1;
133     }
134 
135     if (fgets(line, 1024, fp) == 0) return 0;
136     if (sscanf(line, "Size: %d kB", &size) != 1) return 0;
137     if (fgets(line, 1024, fp) == 0) return 0;
138     if (sscanf(line, "Rss: %d kB", &resident) != 1) return 0;
139     if (fgets(line, 1024, fp) == 0) return 0;
140     if (sscanf(line, "Shared_Clean: %d kB", &shared_clean) != 1) return 0;
141     if (fgets(line, 1024, fp) == 0) return 0;
142     if (sscanf(line, "Shared_Dirty: %d kB", &shared_dirty) != 1) return 0;
143     if (fgets(line, 1024, fp) == 0) return 0;
144     if (sscanf(line, "Private_Clean: %d kB", &private_clean) != 1) return 0;
145     if (fgets(line, 1024, fp) == 0) return 0;
146     if (sscanf(line, "Private_Dirty: %d kB", &private_dirty) != 1) return 0;
147     if (fgets(line, 1024, fp) == 0) return 0;
148     if (sscanf(line, "Referenced: %d kB", &referenced) != 1) return 0;
149 
150     if (skip) {
151         goto again;
152     }
153 
154     if (isHeap) {
155         *sharedPages += shared_dirty;
156         *privatePages += private_dirty;
157     }
158     return 1;
159 }
160 
load_maps(int pid,int * sharedPages,int * privatePages)161 static void load_maps(int pid, int *sharedPages, int *privatePages)
162 {
163     char tmp[128];
164     FILE *fp;
165 
166     sprintf(tmp, "/proc/%d/smaps", pid);
167     fp = fopen(tmp, "r");
168     if (fp == 0) return;
169 
170     while (read_mapinfo(fp, sharedPages, privatePages) != 0) {
171         // Do nothing
172     }
173     fclose(fp);
174 }
175 
getHeapDirtyPages(JNIEnv * env,jobject clazz,jintArray pages)176 static void getHeapDirtyPages(JNIEnv *env, jobject clazz, jintArray pages)
177 {
178     int _pages[2];
179 
180     _pages[0] = 0;
181     _pages[1] = 0;
182 
183     load_maps(getpid(), &_pages[0], &_pages[1]);
184 
185     // Convert from kbytes to 4K pages
186     _pages[0] /= 4;
187     _pages[1] /= 4;
188 
189     env->SetIntArrayRegion(pages, 0, 2, _pages);
190 }
191 
192 /*
193  * JNI registration.
194  */
195 
196 static JNINativeMethod gMethods[] =
197 {
198     { "getPagerStats", "(Landroid/database/sqlite/SQLiteDebug$PagerStats;)V",
199             (void*) getPagerStats },
200     { "getHeapSize", "()J", (void*) getHeapSize },
201     { "getHeapAllocatedSize", "()J", (void*) getHeapAllocatedSize },
202     { "getHeapFreeSize", "()J", (void*) getHeapFreeSize },
203     { "getHeapDirtyPages", "([I)V", (void*) getHeapDirtyPages },
204 };
205 
register_android_database_SQLiteDebug(JNIEnv * env)206 int register_android_database_SQLiteDebug(JNIEnv *env)
207 {
208     jclass clazz;
209 
210     clazz = env->FindClass("android/database/sqlite/SQLiteDebug$PagerStats");
211     if (clazz == NULL) {
212         LOGE("Can't find android/database/sqlite/SQLiteDebug$PagerStats");
213         return -1;
214     }
215 
216     gTotalBytesField = env->GetFieldID(clazz, "totalBytes", "J");
217     if (gTotalBytesField == NULL) {
218         LOGE("Can't find totalBytes");
219         return -1;
220     }
221 
222     gReferencedBytesField = env->GetFieldID(clazz, "referencedBytes", "J");
223     if (gReferencedBytesField == NULL) {
224         LOGE("Can't find referencedBytes");
225         return -1;
226     }
227 
228     gDbBytesField = env->GetFieldID(clazz, "databaseBytes", "J");
229     if (gDbBytesField == NULL) {
230         LOGE("Can't find databaseBytes");
231         return -1;
232     }
233 
234     gNumPagersField = env->GetFieldID(clazz, "numPagers", "I");
235     if (gNumPagersField == NULL) {
236         LOGE("Can't find numPagers");
237         return -1;
238     }
239 
240     return jniRegisterNativeMethods(env, "android/database/sqlite/SQLiteDebug",
241             gMethods, NELEM(gMethods));
242 }
243 
244 } // namespace android
245