diff options
author | Jeff Brown <jeffbrown@google.com> | 2012-01-20 12:34:34 -0800 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2012-01-20 13:08:03 -0800 |
commit | 4b57553e693c9705e8363d3e0e9d881261b3e6fa (patch) | |
tree | b6468f5b5a28610452b1748c421f4766e07f3182 /core | |
parent | 8592baa347f5874b4f36713b6ca2edcedbb3f071 (diff) | |
download | frameworks_base-4b57553e693c9705e8363d3e0e9d881261b3e6fa.zip frameworks_base-4b57553e693c9705e8363d3e0e9d881261b3e6fa.tar.gz frameworks_base-4b57553e693c9705e8363d3e0e9d881261b3e6fa.tar.bz2 |
Initialize SQLite as part of the android runtime.
This ensures that the SQLite library is always correctly configured
and initialized before other framework or application code has
a chance to use it. This is important because initialization has
to happen at most once so we need to get it right and prevent races.
This change makes it possible to omit the SQLite auto-initialization
workaround from the SQLite library, potentially saving a few cycles
here and there.
Change-Id: Ifbed8685ee44aa1e9c0b391e233b0257fa738e4f
Diffstat (limited to 'core')
-rw-r--r-- | core/java/android/database/sqlite/SQLiteConnection.java | 2 | ||||
-rw-r--r-- | core/java/android/database/sqlite/SQLiteDebug.java | 1 | ||||
-rw-r--r-- | core/java/android/database/sqlite/SQLiteGlobal.java | 42 | ||||
-rw-r--r-- | core/jni/android_database_SQLiteGlobal.cpp | 27 | ||||
-rw-r--r-- | core/jni/android_util_Log.cpp | 39 | ||||
-rw-r--r-- | core/jni/android_util_Log.h | 30 |
6 files changed, 83 insertions, 58 deletions
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java index 2ea936e..72f62fd 100644 --- a/core/java/android/database/sqlite/SQLiteConnection.java +++ b/core/java/android/database/sqlite/SQLiteConnection.java @@ -194,8 +194,6 @@ public final class SQLiteConnection { } private void open() { - SQLiteGlobal.initializeOnce(); - mConnectionPtr = nativeOpen(mConfiguration.path, mConfiguration.openFlags, mConfiguration.label, SQLiteDebug.DEBUG_SQL_STATEMENTS, SQLiteDebug.DEBUG_SQL_TIME); diff --git a/core/java/android/database/sqlite/SQLiteDebug.java b/core/java/android/database/sqlite/SQLiteDebug.java index 95350ba..204483d 100644 --- a/core/java/android/database/sqlite/SQLiteDebug.java +++ b/core/java/android/database/sqlite/SQLiteDebug.java @@ -138,7 +138,6 @@ public final class SQLiteDebug { */ public static PagerStats getDatabaseInfo() { PagerStats stats = new PagerStats(); - SQLiteGlobal.initializeOnce(); nativeGetPagerStats(stats); stats.dbStats = SQLiteDatabase.getDbStats(); return stats; diff --git a/core/java/android/database/sqlite/SQLiteGlobal.java b/core/java/android/database/sqlite/SQLiteGlobal.java index 5e129be..dbefd63 100644 --- a/core/java/android/database/sqlite/SQLiteGlobal.java +++ b/core/java/android/database/sqlite/SQLiteGlobal.java @@ -22,57 +22,35 @@ import android.os.StatFs; * Provides access to SQLite functions that affect all database connection, * such as memory management. * + * The native code associated with SQLiteGlobal is also sets global configuration options + * using sqlite3_config() then calls sqlite3_initialize() to ensure that the SQLite + * library is properly initialized exactly once before any other framework or application + * code has a chance to run. + * + * Verbose SQLite logging is enabled if the "log.tag.SQLiteLog" property is set to "V". + * (per {@link SQLiteDebug#DEBUG_SQL_LOG}). + * * @hide */ public final class SQLiteGlobal { private static final String TAG = "SQLiteGlobal"; private static final Object sLock = new Object(); - private static boolean sInitialized; - private static int sSoftHeapLimit; private static int sDefaultPageSize; - private static native void nativeConfig(boolean verboseLog, int softHeapLimit); - private static native int nativeReleaseMemory(int bytesToFree); + private static native int nativeReleaseMemory(); private SQLiteGlobal() { } /** - * Initializes global SQLite settings the first time it is called. - * Should be called before opening the first (or any) database. - * Does nothing on repeated subsequent calls. - */ - public static void initializeOnce() { - synchronized (sLock) { - if (!sInitialized) { - sInitialized = true; - - // Limit to 8MB for now. This is 4 times the maximum cursor window - // size, as has been used by the original code in SQLiteDatabase for - // a long time. - // TODO: We really do need to test whether this helps or hurts us. - sSoftHeapLimit = 8 * 1024 * 1024; - - // Configure SQLite. - nativeConfig(SQLiteDebug.DEBUG_SQL_LOG, sSoftHeapLimit); - } - } - } - - /** * Attempts to release memory by pruning the SQLite page cache and other * internal data structures. * * @return The number of bytes that were freed. */ public static int releaseMemory() { - synchronized (sLock) { - if (!sInitialized) { - return 0; - } - return nativeReleaseMemory(sSoftHeapLimit); - } + return nativeReleaseMemory(); } /** diff --git a/core/jni/android_database_SQLiteGlobal.cpp b/core/jni/android_database_SQLiteGlobal.cpp index 82cae5a..9301183 100644 --- a/core/jni/android_database_SQLiteGlobal.cpp +++ b/core/jni/android_database_SQLiteGlobal.cpp @@ -24,9 +24,16 @@ #include <sqlite3_android.h> #include "android_database_SQLiteCommon.h" +#include "android_util_Log.h" namespace android { +// Limit heap to 8MB for now. This is 4 times the maximum cursor window +// size, as has been used by the original code in SQLiteDatabase for +// a long time. +static const int SOFT_HEAP_LIMIT = 8 * 1024 * 1024; + + // Called each time a message is logged. static void sqliteLogCallback(void* data, int iErrCode, const char* zMsg) { bool verboseLog = !!data; @@ -40,37 +47,41 @@ static void sqliteLogCallback(void* data, int iErrCode, const char* zMsg) { } // Sets the global SQLite configuration. -// This must be called before any other SQLite functions are called. */ -static void nativeConfig(JNIEnv* env, jclass clazz, jboolean verboseLog, jint softHeapLimit) { +// This must be called before any other SQLite functions are called. +static void sqliteInitialize() { // Enable multi-threaded mode. In this mode, SQLite is safe to use by multiple // threads as long as no two threads use the same database connection at the same // time (which we guarantee in the SQLite database wrappers). sqlite3_config(SQLITE_CONFIG_MULTITHREAD); // Redirect SQLite log messages to the Android log. + bool verboseLog = android_util_Log_isVerboseLogEnabled(SQLITE_LOG_TAG); sqlite3_config(SQLITE_CONFIG_LOG, &sqliteLogCallback, verboseLog ? (void*)1 : NULL); // The soft heap limit prevents the page cache allocations from growing // beyond the given limit, no matter what the max page cache sizes are // set to. The limit does not, as of 3.5.0, affect any other allocations. - sqlite3_soft_heap_limit(softHeapLimit); + sqlite3_soft_heap_limit(SOFT_HEAP_LIMIT); + + // Initialize SQLite. + sqlite3_initialize(); } -static jint nativeReleaseMemory(JNIEnv* env, jclass clazz, jint bytesToFree) { - return sqlite3_release_memory(bytesToFree); +static jint nativeReleaseMemory(JNIEnv* env, jclass clazz) { + return sqlite3_release_memory(SOFT_HEAP_LIMIT); } static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ - { "nativeConfig", "(ZI)V", - (void*)nativeConfig }, - { "nativeReleaseMemory", "(I)I", + { "nativeReleaseMemory", "()I", (void*)nativeReleaseMemory }, }; int register_android_database_SQLiteGlobal(JNIEnv *env) { + sqliteInitialize(); + return AndroidRuntime::registerNativeMethods(env, "android/database/sqlite/SQLiteGlobal", sMethods, NELEM(sMethods)); } diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp index a57aad7..2895171 100644 --- a/core/jni/android_util_Log.cpp +++ b/core/jni/android_util_Log.cpp @@ -27,6 +27,7 @@ #include "JNIHelp.h" #include "utils/misc.h" #include "android_runtime/AndroidRuntime.h" +#include "android_util_Log.h" #define MIN(a,b) ((a<b)?a:b) @@ -56,40 +57,48 @@ static int toLevel(const char* value) return levels.info; } -static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level) -{ - int len; - char key[PROPERTY_KEY_MAX]; +static jboolean isLoggable(const char* tag, jint level) { + String8 key; + key.append(LOG_NAMESPACE); + key.append(tag); + char buf[PROPERTY_VALUE_MAX]; + if (property_get(key.string(), buf, "") <= 0) { + return false; + } + int logLevel = toLevel(buf); + return logLevel >= 0 && level >= logLevel; +} + +static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level) +{ if (tag == NULL) { return false; } - jboolean result = false; - const char* chars = env->GetStringUTFChars(tag, NULL); + if (!chars) { + return false; + } + jboolean result = false; if ((strlen(chars)+sizeof(LOG_NAMESPACE)) > PROPERTY_KEY_MAX) { char buf2[200]; snprintf(buf2, sizeof(buf2), "Log tag \"%s\" exceeds limit of %d characters\n", chars, PROPERTY_KEY_MAX - sizeof(LOG_NAMESPACE)); - // release the chars! - env->ReleaseStringUTFChars(tag, chars); - jniThrowException(env, "java/lang/IllegalArgumentException", buf2); - return false; } else { - strncpy(key, LOG_NAMESPACE, sizeof(LOG_NAMESPACE)-1); - strcpy(key + sizeof(LOG_NAMESPACE) - 1, chars); + result = isLoggable(chars, level); } env->ReleaseStringUTFChars(tag, chars); + return result; +} - len = property_get(key, buf, ""); - int logLevel = toLevel(buf); - return (logLevel >= 0 && level >= logLevel) ? true : false; +bool android_util_Log_isVerboseLogEnabled(const char* tag) { + return isLoggable(tag, levels.verbose); } /* diff --git a/core/jni/android_util_Log.h b/core/jni/android_util_Log.h new file mode 100644 index 0000000..4804a85 --- /dev/null +++ b/core/jni/android_util_Log.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ANDROID_UTIL_LOG_H +#define _ANDROID_UTIL_LOG_H + +#include <jni.h> +#include <JNIHelp.h> + + +namespace android { + +bool android_util_Log_isVerboseLogEnabled(const char* tag); + +} + +#endif // _ANDROID_UTIL_LOG_H |