diff options
Diffstat (limited to 'core/java')
7 files changed, 177 insertions, 87 deletions
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 7043a73..d758eca 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -766,17 +766,18 @@ class ContextImpl extends Context { @Override public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) { - File f = validateFilePath(name, true); - SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f, factory); - setFilePermissionsFromMode(f.getPath(), mode, 0); - return db; + return openOrCreateDatabase(name, mode, factory, null); } @Override public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory, DatabaseErrorHandler errorHandler) { File f = validateFilePath(name, true); - SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f.getPath(), factory, errorHandler); + int flags = SQLiteDatabase.CREATE_IF_NECESSARY; + if ((mode & MODE_ENABLE_WRITE_AHEAD_LOGGING) != 0) { + flags |= SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING; + } + SQLiteDatabase db = SQLiteDatabase.openDatabase(f.getPath(), factory, flags, errorHandler); setFilePermissionsFromMode(f.getPath(), mode, 0); return db; } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 741a6e9..2902504 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -99,6 +99,16 @@ public abstract class Context { public static final int MODE_MULTI_PROCESS = 0x0004; /** + * Database open flag: when set, the database is opened with write-ahead + * logging enabled by default. + * + * @see #openOrCreateDatabase(String, int, CursorFactory) + * @see #openOrCreateDatabase(String, int, CursorFactory, DatabaseErrorHandler) + * @see SQLiteDatabase#enableWriteAheadLogging + */ + public static final int MODE_ENABLE_WRITE_AHEAD_LOGGING = 0x0008; + + /** * Flag for {@link #bindService}: automatically create the service as long * as the binding exists. Note that while this will create the service, * its {@link android.app.Service#onStartCommand} @@ -691,6 +701,7 @@ public abstract class Context { * @param mode Operating mode. Use 0 or {@link #MODE_PRIVATE} for the * default operation, {@link #MODE_WORLD_READABLE} * and {@link #MODE_WORLD_WRITEABLE} to control permissions. + * Use {@link #MODE_ENABLE_WRITE_AHEAD_LOGGING} to enable write-ahead logging by default. * @param factory An optional factory class that is called to instantiate a * cursor when query is called. * @@ -700,6 +711,7 @@ public abstract class Context { * @see #MODE_PRIVATE * @see #MODE_WORLD_READABLE * @see #MODE_WORLD_WRITEABLE + * @see #MODE_ENABLE_WRITE_AHEAD_LOGGING * @see #deleteDatabase */ public abstract SQLiteDatabase openOrCreateDatabase(String name, @@ -716,6 +728,7 @@ public abstract class Context { * @param mode Operating mode. Use 0 or {@link #MODE_PRIVATE} for the * default operation, {@link #MODE_WORLD_READABLE} * and {@link #MODE_WORLD_WRITEABLE} to control permissions. + * Use {@link #MODE_ENABLE_WRITE_AHEAD_LOGGING} to enable write-ahead logging by default. * @param factory An optional factory class that is called to instantiate a * cursor when query is called. * @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database @@ -726,6 +739,7 @@ public abstract class Context { * @see #MODE_PRIVATE * @see #MODE_WORLD_READABLE * @see #MODE_WORLD_WRITEABLE + * @see #MODE_ENABLE_WRITE_AHEAD_LOGGING * @see #deleteDatabase */ public abstract SQLiteDatabase openOrCreateDatabase(String name, diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java index bf10bcb..e999316 100644 --- a/core/java/android/database/sqlite/SQLiteConnection.java +++ b/core/java/android/database/sqlite/SQLiteConnection.java @@ -269,7 +269,7 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen private void setWalModeFromConfiguration() { if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) { - if (mConfiguration.walEnabled) { + if ((mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0) { setJournalMode("WAL"); setSyncMode(SQLiteGlobal.getWALSyncMode()); } else { @@ -389,7 +389,8 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen } // Remember what changed. - boolean walModeChanged = configuration.walEnabled != mConfiguration.walEnabled; + boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags) + & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0; boolean localeChanged = !configuration.locale.equals(mConfiguration.locale); // Update configuration parameters. diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java index 27c9ee5..0538ce4 100644 --- a/core/java/android/database/sqlite/SQLiteConnectionPool.java +++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java @@ -81,6 +81,7 @@ public final class SQLiteConnectionPool implements Closeable { private final Object mLock = new Object(); private final AtomicBoolean mConnectionLeaked = new AtomicBoolean(); private final SQLiteDatabaseConfiguration mConfiguration; + private int mMaxConnectionPoolSize; private boolean mIsOpen; private int mNextConnectionId; @@ -146,6 +147,7 @@ public final class SQLiteConnectionPool implements Closeable { private SQLiteConnectionPool(SQLiteDatabaseConfiguration configuration) { mConfiguration = new SQLiteDatabaseConfiguration(configuration); + setMaxConnectionPoolSizeLocked(); } @Override @@ -257,8 +259,9 @@ public final class SQLiteConnectionPool implements Closeable { synchronized (mLock) { throwIfClosedLocked(); - boolean restrictToOneConnection = false; - if (mConfiguration.walEnabled != configuration.walEnabled) { + boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags) + & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0; + if (walModeChanged) { // WAL mode can only be changed if there are no acquired connections // because we need to close all but the primary connection first. if (!mAcquiredConnections.isEmpty()) { @@ -272,15 +275,13 @@ public final class SQLiteConnectionPool implements Closeable { // because none of them are in use. closeAvailableNonPrimaryConnectionsAndLogExceptionsLocked(); assert mAvailableNonPrimaryConnections.isEmpty(); - - restrictToOneConnection = true; } if (mConfiguration.openFlags != configuration.openFlags) { // If we are changing open flags and WAL mode at the same time, then // we have no choice but to close the primary connection beforehand // because there can only be one connection open when we change WAL mode. - if (restrictToOneConnection) { + if (walModeChanged) { closeAvailableConnectionsAndLogExceptionsLocked(); } @@ -296,9 +297,11 @@ public final class SQLiteConnectionPool implements Closeable { mAvailablePrimaryConnection = newPrimaryConnection; mConfiguration.updateParametersFrom(configuration); + setMaxConnectionPoolSizeLocked(); } else { // Reconfigure the database connections in place. mConfiguration.updateParametersFrom(configuration); + setMaxConnectionPoolSizeLocked(); closeExcessConnectionsAndLogExceptionsLocked(); reconfigureAllConnectionsLocked(); @@ -360,8 +363,7 @@ public final class SQLiteConnectionPool implements Closeable { mAvailablePrimaryConnection = connection; } wakeConnectionWaitersLocked(); - } else if (mAvailableNonPrimaryConnections.size() >= - mConfiguration.maxConnectionPoolSize - 1) { + } else if (mAvailableNonPrimaryConnections.size() >= mMaxConnectionPoolSize - 1) { closeConnectionAndLogExceptionsLocked(connection); } else { if (recycleConnectionLocked(connection, status)) { @@ -499,7 +501,7 @@ public final class SQLiteConnectionPool implements Closeable { // Can't throw. private void closeExcessConnectionsAndLogExceptionsLocked() { int availableCount = mAvailableNonPrimaryConnections.size(); - while (availableCount-- > mConfiguration.maxConnectionPoolSize - 1) { + while (availableCount-- > mMaxConnectionPoolSize - 1) { SQLiteConnection connection = mAvailableNonPrimaryConnections.remove(availableCount); closeConnectionAndLogExceptionsLocked(connection); @@ -874,7 +876,7 @@ public final class SQLiteConnectionPool implements Closeable { if (mAvailablePrimaryConnection != null) { openConnections += 1; } - if (openConnections >= mConfiguration.maxConnectionPoolSize) { + if (openConnections >= mMaxConnectionPoolSize) { return null; } connection = openConnectionLocked(mConfiguration, @@ -926,6 +928,18 @@ public final class SQLiteConnectionPool implements Closeable { return (connectionFlags & CONNECTION_FLAG_INTERACTIVE) != 0 ? 1 : 0; } + private void setMaxConnectionPoolSizeLocked() { + if ((mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0) { + mMaxConnectionPoolSize = SQLiteGlobal.getWALConnectionPoolSize(); + } else { + // TODO: We don't actually need to restrict the connection pool size to 1 + // for non-WAL databases. There might be reasons to use connection pooling + // with other journal modes. For now, enabling connection pooling and + // using WAL are the same thing in the API. + mMaxConnectionPoolSize = 1; + } + } + private void throwIfClosedLocked() { if (!mIsOpen) { throw new IllegalStateException("Cannot perform this operation " @@ -972,7 +986,7 @@ public final class SQLiteConnectionPool implements Closeable { synchronized (mLock) { printer.println("Connection pool for " + mConfiguration.path + ":"); printer.println(" Open: " + mIsOpen); - printer.println(" Max connections: " + mConfiguration.maxConnectionPoolSize); + printer.println(" Max connections: " + mMaxConnectionPoolSize); printer.println(" Available primary connection:"); if (mAvailablePrimaryConnection != null) { diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index 0ecce4d..049a615 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -232,6 +232,18 @@ public final class SQLiteDatabase extends SQLiteClosable { public static final int CREATE_IF_NECESSARY = 0x10000000; // update native code if changing /** + * Open flag: Flag for {@link #openDatabase} to open the database file with + * write-ahead logging enabled by default. Using this flag is more efficient + * than calling {@link #enableWriteAheadLogging}. + * + * Write-ahead logging cannot be used with read-only databases so the value of + * this flag is ignored if the database is opened read-only. + * + * @see #enableWriteAheadLogging + */ + public static final int ENABLE_WRITE_AHEAD_LOGGING = 0x20000000; + + /** * Absolute max value that can be set by {@link #setMaxSqlCacheSize(int)}. * * Each prepared-statement is between 1K - 6K, depending on the complexity of the @@ -654,7 +666,7 @@ public final class SQLiteDatabase extends SQLiteClosable { * @throws SQLiteException if the database cannot be opened */ public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) { - return openDatabase(path, factory, flags, new DefaultDatabaseErrorHandler()); + return openDatabase(path, factory, flags, null); } /** @@ -694,7 +706,7 @@ public final class SQLiteDatabase extends SQLiteClosable { * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY). */ public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory) { - return openDatabase(path, factory, CREATE_IF_NECESSARY); + return openDatabase(path, factory, CREATE_IF_NECESSARY, null); } /** @@ -1781,56 +1793,84 @@ public final class SQLiteDatabase extends SQLiteClosable { } /** - * This method enables parallel execution of queries from multiple threads on the same database. - * It does this by opening multiple handles to the database and using a different - * database handle for each query. - * <p> - * If a transaction is in progress on one connection handle and say, a table is updated in the - * transaction, then query on the same table on another connection handle will block for the - * transaction to complete. But this method enables such queries to execute by having them - * return old version of the data from the table. Most often it is the data that existed in the - * table prior to the above transaction updates on that table. + * This method enables parallel execution of queries from multiple threads on the + * same database. It does this by opening multiple connections to the database + * and using a different database connection for each query. The database + * journal mode is also changed to enable writes to proceed concurrently with reads. * <p> - * Maximum number of simultaneous handles used to execute queries in parallel is + * When write-ahead logging is not enabled (the default), it is not possible for + * reads and writes to occur on the database at the same time. Before modifying the + * database, the writer implicitly acquires an exclusive lock on the database which + * prevents readers from accessing the database until the write is completed. + * </p><p> + * In contrast, when write-ahead logging is enabled (by calling this method), write + * operations occur in a separate log file which allows reads to proceed concurrently. + * While a write is in progress, readers on other threads will perceive the state + * of the database as it was before the write began. When the write completes, readers + * on other threads will then perceive the new state of the database. + * </p><p> + * It is a good idea to enable write-ahead logging whenever a database will be + * concurrently accessed and modified by multiple threads at the same time. + * However, write-ahead logging uses significantly more memory than ordinary + * journaling because there are multiple connections to the same database. + * So if a database will only be used by a single thread, or if optimizing + * concurrency is not very important, then write-ahead logging should be disabled. + * </p><p> + * After calling this method, execution of queries in parallel is enabled as long as + * the database remains open. To disable execution of queries in parallel, either + * call {@link #disableWriteAheadLogging} or close the database and reopen it. + * </p><p> + * The maximum number of connections used to execute queries in parallel is * dependent upon the device memory and possibly other properties. - * <p> - * After calling this method, execution of queries in parallel is enabled as long as this - * database handle is open. To disable execution of queries in parallel, database should - * be closed and reopened. - * <p> + * </p><p> * If a query is part of a transaction, then it is executed on the same database handle the * transaction was begun. - * <p> - * If the database has any attached databases, then execution of queries in paralel is NOT - * possible. In such cases, a message is printed to logcat and false is returned. - * <p> - * This feature is not available for :memory: databases. In such cases, - * a message is printed to logcat and false is returned. - * <p> - * A typical way to use this method is the following: - * <pre> - * SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory, - * CREATE_IF_NECESSARY, myDatabaseErrorHandler); - * db.enableWriteAheadLogging(); - * </pre> - * <p> + * </p><p> * Writers should use {@link #beginTransactionNonExclusive()} or * {@link #beginTransactionWithListenerNonExclusive(SQLiteTransactionListener)} - * to start a trsnsaction. - * Non-exclusive mode allows database file to be in readable by threads executing queries. + * to start a transaction. Non-exclusive mode allows database file to be in readable + * by other threads executing queries. + * </p><p> + * If the database has any attached databases, then execution of queries in parallel is NOT + * possible. Likewise, write-ahead logging is not supported for read-only databases + * or memory databases. In such cases, {@link #enableWriteAheadLogging} returns false. + * </p><p> + * The best way to enable write-ahead logging is to pass the + * {@link #ENABLE_WRITE_AHEAD_LOGGING} flag to {@link #openDatabase}. This is + * more efficient than calling {@link #enableWriteAheadLogging}. + * <code><pre> + * SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory, + * SQLiteDatabase.CREATE_IF_NECESSARY | SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING, + * myDatabaseErrorHandler); + * db.enableWriteAheadLogging(); + * </pre></code> + * </p><p> + * Another way to enable write-ahead logging is to call {@link #enableWriteAheadLogging} + * after opening the database. + * <code><pre> + * SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory, + * SQLiteDatabase.CREATE_IF_NECESSARY, myDatabaseErrorHandler); + * db.enableWriteAheadLogging(); + * </pre></code> + * </p><p> + * See also <a href="http://sqlite.org/wal.html">SQLite Write-Ahead Logging</a> for + * more details about how write-ahead logging works. * </p> * - * @return true if write-ahead-logging is set. false otherwise + * @return True if write-ahead logging is enabled. * * @throws IllegalStateException if there are transactions in progress at the * time this method is called. WAL mode can only be changed when there are no * transactions in progress. + * + * @see #ENABLE_WRITE_AHEAD_LOGGING + * @see #disableWriteAheadLogging */ public boolean enableWriteAheadLogging() { synchronized (mLock) { throwIfNotOpenLocked(); - if (mConfigurationLocked.walEnabled) { + if ((mConfigurationLocked.openFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0) { return true; } @@ -1855,14 +1895,11 @@ public final class SQLiteDatabase extends SQLiteClosable { return false; } - final int oldMaxConnectionPoolSize = mConfigurationLocked.maxConnectionPoolSize; - mConfigurationLocked.maxConnectionPoolSize = SQLiteGlobal.getWALConnectionPoolSize(); - mConfigurationLocked.walEnabled = true; + mConfigurationLocked.openFlags |= ENABLE_WRITE_AHEAD_LOGGING; try { mConnectionPoolLocked.reconfigure(mConfigurationLocked); } catch (RuntimeException ex) { - mConfigurationLocked.maxConnectionPoolSize = oldMaxConnectionPoolSize; - mConfigurationLocked.walEnabled = false; + mConfigurationLocked.openFlags &= ~ENABLE_WRITE_AHEAD_LOGGING; throw ex; } } @@ -1875,29 +1912,44 @@ public final class SQLiteDatabase extends SQLiteClosable { * @throws IllegalStateException if there are transactions in progress at the * time this method is called. WAL mode can only be changed when there are no * transactions in progress. + * + * @see #enableWriteAheadLogging */ public void disableWriteAheadLogging() { synchronized (mLock) { throwIfNotOpenLocked(); - if (!mConfigurationLocked.walEnabled) { + if ((mConfigurationLocked.openFlags & ENABLE_WRITE_AHEAD_LOGGING) == 0) { return; } - final int oldMaxConnectionPoolSize = mConfigurationLocked.maxConnectionPoolSize; - mConfigurationLocked.maxConnectionPoolSize = 1; - mConfigurationLocked.walEnabled = false; + mConfigurationLocked.openFlags &= ~ENABLE_WRITE_AHEAD_LOGGING; try { mConnectionPoolLocked.reconfigure(mConfigurationLocked); } catch (RuntimeException ex) { - mConfigurationLocked.maxConnectionPoolSize = oldMaxConnectionPoolSize; - mConfigurationLocked.walEnabled = true; + mConfigurationLocked.openFlags |= ENABLE_WRITE_AHEAD_LOGGING; throw ex; } } } /** + * Returns true if write-ahead logging has been enabled for this database. + * + * @return True if write-ahead logging has been enabled for this database. + * + * @see #enableWriteAheadLogging + * @see #ENABLE_WRITE_AHEAD_LOGGING + */ + public boolean isWriteAheadLoggingEnabled() { + synchronized (mLock) { + throwIfNotOpenLocked(); + + return (mConfigurationLocked.openFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0; + } + } + + /** * Collect statistics about all open databases in the current process. * Used by bug report. */ diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java index e06a5ee..123c2c6 100644 --- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java +++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java @@ -62,14 +62,6 @@ public final class SQLiteDatabaseConfiguration { public int openFlags; /** - * The maximum number of connections to retain in the connection pool. - * Must be at least 1. - * - * Default is 1. - */ - public int maxConnectionPoolSize; - - /** * The maximum size of the prepared statement cache for each database connection. * Must be non-negative. * @@ -85,13 +77,6 @@ public final class SQLiteDatabaseConfiguration { public Locale locale; /** - * True if WAL mode is enabled. - * - * Default is false. - */ - public boolean walEnabled; - - /** * The custom functions to register. */ public final ArrayList<SQLiteCustomFunction> customFunctions = @@ -114,7 +99,6 @@ public final class SQLiteDatabaseConfiguration { this.openFlags = openFlags; // Set default values for optional parameters. - maxConnectionPoolSize = 1; maxSqlCacheSize = 25; locale = Locale.getDefault(); } @@ -150,10 +134,8 @@ public final class SQLiteDatabaseConfiguration { } openFlags = other.openFlags; - maxConnectionPoolSize = other.maxConnectionPoolSize; maxSqlCacheSize = other.maxSqlCacheSize; locale = other.locale; - walEnabled = other.walEnabled; customFunctions.clear(); customFunctions.addAll(other.customFunctions); } diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java index ffa4663..fe37b8f 100644 --- a/core/java/android/database/sqlite/SQLiteOpenHelper.java +++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java @@ -58,6 +58,7 @@ public abstract class SQLiteOpenHelper { private SQLiteDatabase mDatabase; private boolean mIsInitializing; + private boolean mEnableWriteAheadLogging; private final DatabaseErrorHandler mErrorHandler; /** @@ -74,7 +75,7 @@ public abstract class SQLiteOpenHelper { * newer, {@link #onDowngrade} will be used to downgrade the database */ public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) { - this(context, name, factory, version, new DefaultDatabaseErrorHandler()); + this(context, name, factory, version, null); } /** @@ -92,14 +93,11 @@ public abstract class SQLiteOpenHelper { * {@link #onUpgrade} will be used to upgrade the database; if the database is * newer, {@link #onDowngrade} will be used to downgrade the database * @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database - * corruption. + * corruption, or null to use the default error handler. */ public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version, DatabaseErrorHandler errorHandler) { if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version); - if (errorHandler == null) { - throw new IllegalArgumentException("DatabaseErrorHandler param value can't be null."); - } mContext = context; mName = name; @@ -117,6 +115,32 @@ public abstract class SQLiteOpenHelper { } /** + * Enables or disables the use of write-ahead logging for the database. + * + * Write-ahead logging cannot be used with read-only databases so the value of + * this flag is ignored if the database is opened read-only. + * + * @param enabled True if write-ahead logging should be enabled, false if it + * should be disabled. + * + * @see SQLiteDatabase#enableWriteAheadLogging() + */ + public void setWriteAheadLoggingEnabled(boolean enabled) { + synchronized (this) { + if (mEnableWriteAheadLogging != enabled) { + if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) { + if (enabled) { + mDatabase.enableWriteAheadLogging(); + } else { + mDatabase.disableWriteAheadLogging(); + } + } + mEnableWriteAheadLogging = enabled; + } + } + } + + /** * Create and/or open a database that will be used for reading and writing. * The first time this is called, the database will be opened and * {@link #onCreate}, {@link #onUpgrade} and/or {@link #onOpen} will be @@ -197,7 +221,9 @@ public abstract class SQLiteOpenHelper { db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY, mErrorHandler); } else { - db = mContext.openOrCreateDatabase(mName, 0, mFactory, mErrorHandler); + db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ? + Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0, + mFactory, mErrorHandler); } } catch (SQLiteException ex) { if (writable) { |