Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c3849200 authored by Vasu Nori's avatar Vasu Nori
Browse files

add more debug info to SQL section in bugreport

after this CL, adb bugreport will the following info (under SQL section
of each app's meminfo dump)

 SQL
            heap:      344       memoryUsed:      344
pageCacheOverflo:       67  largestMemAlloc:       50

 DATABASES
  Pagesize   Dbsize  Lookaside  Dbname
      1024        7         24  googlesettings.db
      1024       26        110  talk.db
      1024       11          0    (attached) transient_talk_db
      1024       11         32  subscribedfeeds.db
      1024       20         27  gservices.db

Change-Id: Iabd13be9793d9794137c60a045b84fa632f13498
parent ae58f6d7
Loading
Loading
Loading
Loading
+27 −11
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDebug;
import android.database.sqlite.SQLiteDebug.DbStats;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.os.Bundle;
@@ -1441,6 +1442,7 @@ public final class ActivityThread {
        private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s";
        private static final String ONE_COUNT_COLUMN = "%17s %8d";
        private static final String TWO_COUNT_COLUMNS = "%17s %8d %17s %8d";
        private static final String DB_INFO_FORMAT = "  %8d %8d %10d  %s";

        // Formatting for checkin service - update version if row format changes
        private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 1;
@@ -1760,8 +1762,7 @@ public final class ActivityThread {
            int binderDeathObjectCount = Debug.getBinderDeathObjectCount();
            int openSslSocketCount = OpenSSLSocketImpl.getInstanceCount();
            long sqliteAllocated = SQLiteDebug.getHeapAllocatedSize() / 1024;
            SQLiteDebug.PagerStats stats = new SQLiteDebug.PagerStats();
            SQLiteDebug.getPagerStats(stats);
            SQLiteDebug.PagerStats stats = SQLiteDebug.getDatabaseInfo();

            // Check to see if we were called by checkin server. If so, print terse format.
            boolean doCheckinFormat = false;
@@ -1835,10 +1836,15 @@ public final class ActivityThread {

                // SQL
                pw.print(sqliteAllocated); pw.print(',');
                pw.print(stats.databaseBytes / 1024); pw.print(',');
                pw.print(stats.numPagers); pw.print(',');
                pw.print((stats.totalBytes - stats.referencedBytes) / 1024); pw.print(',');
                pw.print(stats.referencedBytes / 1024); pw.print('\n');
                pw.print(stats.memoryUsed / 1024); pw.print(',');
                pw.print(stats.pageCacheOverflo / 1024); pw.print(',');
                pw.print(stats.largestMemAlloc / 1024); pw.print(',');
                for (int i = 0; i < stats.dbStats.size(); i++) {
                    DbStats dbStats = stats.dbStats.get(i);
                    printRow(pw, DB_INFO_FORMAT, dbStats.pageSize, dbStats.dbSize,
                            dbStats.lookaside, dbStats.dbName);
                    pw.print(',');
                }

                return;
            }
@@ -1879,11 +1885,21 @@ public final class ActivityThread {
            // SQLite mem info
            pw.println(" ");
            pw.println(" SQL");
            printRow(pw, TWO_COUNT_COLUMNS, "heap:", sqliteAllocated, "dbFiles:",
                    stats.databaseBytes / 1024);
            printRow(pw, TWO_COUNT_COLUMNS, "numPagers:", stats.numPagers, "inactivePageKB:",
                    (stats.totalBytes - stats.referencedBytes) / 1024);
            printRow(pw, ONE_COUNT_COLUMN, "activePageKB:", stats.referencedBytes / 1024);
            printRow(pw, TWO_COUNT_COLUMNS, "heap:", sqliteAllocated, "memoryUsed:",
                    stats.memoryUsed / 1024);
            printRow(pw, TWO_COUNT_COLUMNS, "pageCacheOverflo:", stats.pageCacheOverflo / 1024,
                    "largestMemAlloc:", stats.largestMemAlloc / 1024);
            pw.println(" ");
            int N = stats.dbStats.size();
            if (N > 0) {
                pw.println(" DATABASES");
                printRow(pw, "  %8s %8s %10s  %s", "Pagesize", "Dbsize", "Lookaside", "Dbname");
                for (int i = 0; i < N; i++) {
                    DbStats dbStats = stats.dbStats.get(i);
                    printRow(pw, DB_INFO_FORMAT, dbStats.pageSize, dbStats.dbSize,
                            dbStats.lookaside, dbStats.dbName);
                }
            }

            // Asset details.
            String assetAlloc = AssetManager.getAssetAllocations();
+1 −2
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ public abstract class SQLiteClosable {
        synchronized(mLock) {
            if (mReferenceCount <= 0) {
                throw new IllegalStateException(
                        "attempt to acquire a reference on an already-closed " + getObjInfo());
                        "attempt to re-open an already-closed object: " + getObjInfo());
            }
            mReferenceCount++;
        }
@@ -59,7 +59,6 @@ public abstract class SQLiteClosable {
    private String getObjInfo() {
        StringBuilder buff = new StringBuilder();
        buff.append(this.getClass().getName());
        buff.append(" Obj");
        buff.append(" (");
        if (this instanceof SQLiteDatabase) {
            buff.append("database = ");
+100 −4
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.content.ContentValues;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.SQLException;
import android.database.sqlite.SQLiteDebug.DbStats;
import android.os.Debug;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -30,10 +31,14 @@ import android.text.TextUtils;
import android.util.Config;
import android.util.EventLog;
import android.util.Log;
import android.util.Pair;

import java.io.File;
import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
@@ -787,25 +792,27 @@ public class SQLiteDatabase extends SQLiteClosable {
     * @throws SQLiteException if the database cannot be opened
     */
    public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) {
        SQLiteDatabase db = null;
        SQLiteDatabase sqliteDatabase = null;
        try {
            // Open the database.
            SQLiteDatabase sqliteDatabase = new SQLiteDatabase(path, factory, flags);
            sqliteDatabase = new SQLiteDatabase(path, factory, flags);
            if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
                sqliteDatabase.enableSqlTracing(path);
            }
            if (SQLiteDebug.DEBUG_SQL_TIME) {
                sqliteDatabase.enableSqlProfiling(path);
            }
            return sqliteDatabase;
        } catch (SQLiteDatabaseCorruptException e) {
            // Try to recover from this, if we can.
            // TODO: should we do this for other open failures?
            Log.e(TAG, "Deleting and re-creating corrupt database " + path, e);
            EventLog.writeEvent(EVENT_DB_CORRUPT, path);
            new File(path).delete();
            return new SQLiteDatabase(path, factory, flags);
            sqliteDatabase = new SQLiteDatabase(path, factory, flags);
        }
        ActiveDatabases.getInstance().mActiveDatabases.add(
                new WeakReference<SQLiteDatabase>(sqliteDatabase));
        return sqliteDatabase;
    }

    /**
@@ -2040,6 +2047,88 @@ public class SQLiteDatabase extends SQLiteClosable {
        mMaxSqlCacheSize = cacheSize;
    }

    static class ActiveDatabases {
        private static final ActiveDatabases activeDatabases = new ActiveDatabases();
        private HashSet<WeakReference<SQLiteDatabase>> mActiveDatabases =
            new HashSet<WeakReference<SQLiteDatabase>>();
        private ActiveDatabases() {} // disable instantiation of this class
        static ActiveDatabases getInstance() {return activeDatabases;}
    }

    /* package */ static ArrayList<DbStats> getDbStats() {
        ArrayList<DbStats> dbStatsList = new ArrayList<DbStats>();
        for (WeakReference<SQLiteDatabase> w : ActiveDatabases.getInstance().mActiveDatabases) {
            SQLiteDatabase db = w.get();
            if (db == null || !db.isOpen()) {
                continue;
            }
            // get SQLITE_DBSTATUS_LOOKASIDE_USED for the db
            int lookasideUsed = db.native_getDbLookaside();

            // get the lastnode of the dbname
            String path = db.getPath();
            int indx = path.lastIndexOf("/");
            String lastnode = path.substring((indx != -1) ? ++indx : 0);

            // get list of attached dbs and for each db, get its size and pagesize
            ArrayList<Pair<String, String>> attachedDbs = getAttachedDbs(db);
            for (int i = 0; i < attachedDbs.size(); i++) {
                Pair<String, String> p = attachedDbs.get(i);
                long pageCount = getPragmaVal(db, p.first + ".page_count;");

                // first entry in the attached db list is always the main database
                // don't worry about prefixing the dbname with "main"
                String dbName;
                if (i == 0) {
                    dbName = lastnode;
                } else {
                    // lookaside is only relevant for the main db
                    lookasideUsed = 0;
                    dbName = "  (attached) " + p.first;
                    // if the attached db has a path, attach the lastnode from the path to above
                    if (p.second.trim().length() > 0) {
                        int idx = p.second.lastIndexOf("/");
                        dbName += " : " + p.second.substring((idx != -1) ? ++idx : 0);
                    }
                }
                dbStatsList.add(new DbStats(dbName, pageCount, db.getPageSize(), lookasideUsed));
            }
        }
        return dbStatsList;
    }

    /**
     * get the specified pragma value from sqlite for the specified database.
     * only handles pragma's that return int/long.
     * NO JAVA locks are held in this method.
     * TODO: use this to do all pragma's in this class
     */
    private static long getPragmaVal(SQLiteDatabase db, String pragma) {
        SQLiteStatement prog = null;
        try {
            prog = new SQLiteStatement(db, "PRAGMA " + pragma);
            long val = prog.simpleQueryForLong();
            return val;
        } finally {
            if (prog != null) prog.close();
        }
    }

    /**
     * returns list of full pathnames of all attached databases
     * including the main database
     * TODO: move this to {@link DatabaseUtils}
     */
    private static ArrayList<Pair<String, String>> getAttachedDbs(SQLiteDatabase dbObj) {
        ArrayList<Pair<String, String>> attachedDbs = new ArrayList<Pair<String, String>>();
        Cursor c = dbObj.rawQuery("pragma database_list;", null);
        while (c.moveToNext()) {
             attachedDbs.add(new Pair<String, String>(c.getString(1), c.getString(2)));
        }
        c.close();
        return attachedDbs;
    }

    /**
     * Native call to open the database.
     *
@@ -2093,4 +2182,11 @@ public class SQLiteDatabase extends SQLiteClosable {
     * @return the number of changes made in the last statement executed.
     */
    /* package */ native int lastChangeCount();

    /**
     * return the SQLITE_DBSTATUS_LOOKASIDE_USED documented here
     * http://www.sqlite.org/c3ref/c_dbstatus_lookaside_used.html
     * @return int value of SQLITE_DBSTATUS_LOOKASIDE_USED
     */
    private native int native_getDbLookaside();
}
+79 −4
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.database.sqlite;

import java.util.ArrayList;

import android.util.Log;

/**
@@ -68,14 +70,87 @@ public final class SQLiteDebug {
     * @see #getPagerStats(PagerStats)
     */
    public static class PagerStats {
        /** The total number of bytes in all pagers in the current process */
        /** The total number of bytes in all pagers in the current process
         * @deprecated not used any longer
         */
        @Deprecated
        public long totalBytes;
        /** The number of bytes in referenced pages in all pagers in the current process */
        /** The number of bytes in referenced pages in all pagers in the current process
         * @deprecated not used any longer
         * */
        @Deprecated
        public long referencedBytes;
        /** The number of bytes in all database files opened in the current process */
        /** The number of bytes in all database files opened in the current process
         * @deprecated not used any longer
         */
        @Deprecated
        public long databaseBytes;
        /** The number of pagers opened in the current process */
        /** The number of pagers opened in the current process
         * @deprecated not used any longer
         */
        @Deprecated
        public int numPagers;

        /** the current amount of memory checked out by sqlite using sqlite3_malloc().
         * documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
         */
        public int memoryUsed;

        /** the number of bytes of page cache allocation which could not be sattisfied by the
         * SQLITE_CONFIG_PAGECACHE buffer and where forced to overflow to sqlite3_malloc().
         * The returned value includes allocations that overflowed because they where too large
         * (they were larger than the "sz" parameter to SQLITE_CONFIG_PAGECACHE) and allocations
         * that overflowed because no space was left in the page cache.
         * documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
         */
        public int pageCacheOverflo;

        /** records the largest memory allocation request handed to sqlite3.
         * documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
         */
        public int largestMemAlloc;

        /** a list of {@link DbStats} - one for each main database opened by the applications
         * running on the android device
         */
        public ArrayList<DbStats> dbStats;
    }

    /**
     * contains statistics about a database
     * @author vnori@google.com (Your Name Here)
     *
     */
    public static class DbStats {
        /** name of the database */
        public String dbName;

        /** the page size for the database */
        public long pageSize;

        /** the database size */
        public long dbSize;

        /** documented here http://www.sqlite.org/c3ref/c_dbstatus_lookaside_used.html */
        public int lookaside;

        public DbStats(String dbName, long pageCount, long pageSize, int lookaside) {
            this.dbName = dbName;
            this.pageSize = pageSize;
            dbSize = (pageCount * pageSize) / 1024;
            this.lookaside = lookaside;
        }
    }

    /**
     * return all pager and database stats for the current process.
     * @return {@link PagerStats}
     */
    public static PagerStats getDatabaseInfo() {
        PagerStats stats = new PagerStats();
        getPagerStats(stats);
        stats.dbStats = SQLiteDatabase.getDbStats();
        return stats;
    }

    /**
+11 −0
Original line number Diff line number Diff line
@@ -306,6 +306,16 @@ static jint lastChangeCount(JNIEnv* env, jobject object)
    return sqlite3_changes(handle);
}

/* native int native_getDbLookaside(); */
static jint native_getDbLookaside(JNIEnv* env, jobject object)
{
    sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
    int pCur = -1;
    int unused;
    sqlite3_db_status(handle, SQLITE_DBSTATUS_LOOKASIDE_USED, &pCur, &unused, 0);
    return pCur;
}

/* set locale in the android_metadata table, install localized collators, and rebuild indexes */
static void native_setLocale(JNIEnv* env, jobject object, jstring localeString, jint flags)
{
@@ -442,6 +452,7 @@ static JNINativeMethod sMethods[] =
    {"lastInsertRow", "()J", (void *)lastInsertRow},
    {"lastChangeCount", "()I", (void *)lastChangeCount},
    {"native_setLocale", "(Ljava/lang/String;I)V", (void *)native_setLocale},
    {"native_getDbLookaside", "()I", (void *)native_getDbLookaside},
    {"releaseMemory", "()I", (void *)native_releaseMemory},
};

Loading