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
17package android.database.sqlite;
18
19import java.util.ArrayList;
20
21import android.os.Build;
22import android.os.SystemProperties;
23import android.util.Log;
24import android.util.Printer;
25
26/**
27 * Provides debugging info about all SQLite databases running in the current process.
28 *
29 * {@hide}
30 */
31public final class SQLiteDebug {
32    private static native void nativeGetPagerStats(PagerStats stats);
33
34    /**
35     * Controls the printing of informational SQL log messages.
36     *
37     * Enable using "adb shell setprop log.tag.SQLiteLog VERBOSE".
38     */
39    public static final boolean DEBUG_SQL_LOG =
40            Log.isLoggable("SQLiteLog", Log.VERBOSE);
41
42    /**
43     * Controls the printing of SQL statements as they are executed.
44     *
45     * Enable using "adb shell setprop log.tag.SQLiteStatements VERBOSE".
46     */
47    public static final boolean DEBUG_SQL_STATEMENTS =
48            Log.isLoggable("SQLiteStatements", Log.VERBOSE);
49
50    /**
51     * Controls the printing of wall-clock time taken to execute SQL statements
52     * as they are executed.
53     *
54     * Enable using "adb shell setprop log.tag.SQLiteTime VERBOSE".
55     */
56    public static final boolean DEBUG_SQL_TIME =
57            Log.isLoggable("SQLiteTime", Log.VERBOSE);
58
59    /**
60     * True to enable database performance testing instrumentation.
61     * @hide
62     */
63    public static final boolean DEBUG_LOG_SLOW_QUERIES = Build.IS_DEBUGGABLE;
64
65    private SQLiteDebug() {
66    }
67
68    /**
69     * Determines whether a query should be logged.
70     *
71     * Reads the "db.log.slow_query_threshold" system property, which can be changed
72     * by the user at any time.  If the value is zero, then all queries will
73     * be considered slow.  If the value does not exist or is negative, then no queries will
74     * be considered slow.
75     *
76     * This value can be changed dynamically while the system is running.
77     * For example, "adb shell setprop db.log.slow_query_threshold 200" will
78     * log all queries that take 200ms or longer to run.
79     * @hide
80     */
81    public static final boolean shouldLogSlowQuery(long elapsedTimeMillis) {
82        int slowQueryMillis = SystemProperties.getInt("db.log.slow_query_threshold", -1);
83        return slowQueryMillis >= 0 && elapsedTimeMillis >= slowQueryMillis;
84    }
85
86    /**
87     * Contains statistics about the active pagers in the current process.
88     *
89     * @see #nativeGetPagerStats(PagerStats)
90     */
91    public static class PagerStats {
92        /** the current amount of memory checked out by sqlite using sqlite3_malloc().
93         * documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
94         */
95        public int memoryUsed;
96
97        /** the number of bytes of page cache allocation which could not be sattisfied by the
98         * SQLITE_CONFIG_PAGECACHE buffer and where forced to overflow to sqlite3_malloc().
99         * The returned value includes allocations that overflowed because they where too large
100         * (they were larger than the "sz" parameter to SQLITE_CONFIG_PAGECACHE) and allocations
101         * that overflowed because no space was left in the page cache.
102         * documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
103         */
104        public int pageCacheOverflow;
105
106        /** records the largest memory allocation request handed to sqlite3.
107         * documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
108         */
109        public int largestMemAlloc;
110
111        /** a list of {@link DbStats} - one for each main database opened by the applications
112         * running on the android device
113         */
114        public ArrayList<DbStats> dbStats;
115    }
116
117    /**
118     * contains statistics about a database
119     */
120    public static class DbStats {
121        /** name of the database */
122        public String dbName;
123
124        /** the page size for the database */
125        public long pageSize;
126
127        /** the database size */
128        public long dbSize;
129
130        /** documented here http://www.sqlite.org/c3ref/c_dbstatus_lookaside_used.html */
131        public int lookaside;
132
133        /** statement cache stats: hits/misses/cachesize */
134        public String cache;
135
136        public DbStats(String dbName, long pageCount, long pageSize, int lookaside,
137            int hits, int misses, int cachesize) {
138            this.dbName = dbName;
139            this.pageSize = pageSize / 1024;
140            dbSize = (pageCount * pageSize) / 1024;
141            this.lookaside = lookaside;
142            this.cache = hits + "/" + misses + "/" + cachesize;
143        }
144    }
145
146    /**
147     * return all pager and database stats for the current process.
148     * @return {@link PagerStats}
149     */
150    public static PagerStats getDatabaseInfo() {
151        PagerStats stats = new PagerStats();
152        nativeGetPagerStats(stats);
153        stats.dbStats = SQLiteDatabase.getDbStats();
154        return stats;
155    }
156
157    /**
158     * Dumps detailed information about all databases used by the process.
159     * @param printer The printer for dumping database state.
160     * @param args Command-line arguments supplied to dumpsys dbinfo
161     */
162    public static void dump(Printer printer, String[] args) {
163        boolean verbose = false;
164        for (String arg : args) {
165            if (arg.equals("-v")) {
166                verbose = true;
167            }
168        }
169
170        SQLiteDatabase.dumpAll(printer, verbose);
171    }
172}
173