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