fix compiled statement bugs, synchronization bugs

1. when LRU cache wants to remove the eldest entry, it may be finalizing
a statement that is still in use
2. a couple of synchronization issues.
3. a bit code refactoring in SQLiteCompiledSql
4. remove a bunch of unsed debug code from SQLiteDatabase

Change-Id: I45454dc2dbadd7d8842ba77dd2b0e9ff138ec6f4
diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java
index 0b5a4df..588384b 100644
--- a/core/java/android/database/sqlite/SQLiteCompiledSql.java
+++ b/core/java/android/database/sqlite/SQLiteCompiledSql.java
@@ -31,12 +31,12 @@
     private static final String TAG = "SQLiteCompiledSql";
 
     /** The database this program is compiled against. */
-    /* package */ SQLiteDatabase mDatabase;
+    /* package */ final SQLiteDatabase mDatabase;
 
     /**
      * Native linkage, do not modify. This comes from the database.
      */
-    /* package */ int nHandle = 0;
+    /* package */ final int nHandle;
 
     /**
      * Native linkage, do not modify. When non-0 this holds a reference to a valid
@@ -54,38 +54,13 @@
     private boolean mInUse = false;
 
     /* package */ SQLiteCompiledSql(SQLiteDatabase db, String sql) {
-        if (!db.isOpen()) {
-            throw new IllegalStateException("database " + db.getPath() + " already closed");
-        }
+        db.verifyDbIsOpen();
+        db.verifyLockOwner();
         mDatabase = db;
         mSqlStmt = sql;
         mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
-        this.nHandle = db.mNativeHandle;
-        compile(sql, true);
-    }
-
-    /**
-     * Compiles the given SQL into a SQLite byte code program using sqlite3_prepare_v2(). If
-     * this method has been called previously without a call to close and forCompilation is set
-     * to false the previous compilation will be used. Setting forceCompilation to true will
-     * always re-compile the program and should be done if you pass differing SQL strings to this
-     * method.
-     *
-     * <P>Note: this method acquires the database lock.</P>
-     *
-     * @param sql the SQL string to compile
-     * @param forceCompilation forces the SQL to be recompiled in the event that there is an
-     *  existing compiled SQL program already around
-     */
-    private void compile(String sql, boolean forceCompilation) {
-        mDatabase.verifyLockOwner();
-        // Only compile if we don't have a valid statement already or the caller has
-        // explicitly requested a recompile.
-        if (forceCompilation) {
-            // Note that the native_compile() takes care of destroying any previously
-            // existing programs before it compiles.
-            native_compile(sql);
-        }
+        nHandle = db.mNativeHandle;
+        native_compile(sql);
     }
 
     /* package */ void releaseSqlStatement() {
@@ -102,7 +77,7 @@
      */
     /* package */ synchronized boolean acquire() {
         if (mInUse) {
-            // someone already has acquired it.
+            // it is already in use.
             return false;
         }
         mInUse = true;
@@ -117,6 +92,13 @@
         return mInUse;
     }
 
+    /* package */ synchronized void releaseIfNotInUse() {
+        // if it is not in use, release its memory from the database
+        if (!isInUse()) {
+            releaseSqlStatement();
+        }
+    }
+
     /**
      * Make sure that the native resource is cleaned up.
      */
@@ -125,10 +107,15 @@
         try {
             if (nStatement == 0) return;
             // finalizer should NEVER get called
-            int len = mSqlStmt.length();
-            Log.w(TAG, "Releasing statement in a finalizer. Please ensure " +
-                    "that you explicitly call close() on your cursor: " +
-                    mSqlStmt.substring(0, (len > 100) ? 100 : len), mStackTrace);
+            // but if the database itself is not closed and is GC'ed, then
+            // all sub-objects attached to the database could end up getting GC'ed too.
+            // in that case, don't print any warning.
+            if (!mInUse) {
+                int len = mSqlStmt.length();
+                Log.w(TAG, "Releasing statement in a finalizer. Please ensure " +
+                        "that you explicitly call close() on your cursor: " +
+                        mSqlStmt.substring(0, (len > 100) ? 100 : len), mStackTrace);
+            }
             releaseSqlStatement();
         } finally {
             super.finalize();
@@ -140,6 +127,8 @@
             StringBuilder buff = new StringBuilder();
             buff.append(" nStatement=");
             buff.append(nStatement);
+            buff.append(", mInUse=");
+            buff.append(mInUse);
             buff.append(", db=");
             buff.append(mDatabase.getPath());
             buff.append(", db_connectionNum=");