Merge "Added setIdleConnectionTimeout method" into oc-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
82f289a4b4
@@ -11956,6 +11956,7 @@ package android.database.sqlite {
|
||||
public static final class SQLiteDatabase.OpenParams {
|
||||
method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
|
||||
method public android.database.DatabaseErrorHandler getErrorHandler();
|
||||
method public long getIdleConnectionTimeout();
|
||||
method public int getLookasideSlotCount();
|
||||
method public int getLookasideSlotSize();
|
||||
method public int getOpenFlags();
|
||||
@@ -11969,6 +11970,7 @@ package android.database.sqlite {
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder removeOpenFlags(int);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setErrorHandler(android.database.DatabaseErrorHandler);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setIdleConnectionTimeout(long);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setLookasideConfig(int, int);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int);
|
||||
}
|
||||
@@ -12026,6 +12028,7 @@ package android.database.sqlite {
|
||||
method public void onDowngrade(android.database.sqlite.SQLiteDatabase, int, int);
|
||||
method public void onOpen(android.database.sqlite.SQLiteDatabase);
|
||||
method public abstract void onUpgrade(android.database.sqlite.SQLiteDatabase, int, int);
|
||||
method public void setIdleConnectionTimeout(long);
|
||||
method public void setLookasideConfig(int, int);
|
||||
method public void setWriteAheadLoggingEnabled(boolean);
|
||||
}
|
||||
|
||||
@@ -12752,6 +12752,7 @@ package android.database.sqlite {
|
||||
public static final class SQLiteDatabase.OpenParams {
|
||||
method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
|
||||
method public android.database.DatabaseErrorHandler getErrorHandler();
|
||||
method public long getIdleConnectionTimeout();
|
||||
method public int getLookasideSlotCount();
|
||||
method public int getLookasideSlotSize();
|
||||
method public int getOpenFlags();
|
||||
@@ -12765,6 +12766,7 @@ package android.database.sqlite {
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder removeOpenFlags(int);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setErrorHandler(android.database.DatabaseErrorHandler);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setIdleConnectionTimeout(long);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setLookasideConfig(int, int);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int);
|
||||
}
|
||||
@@ -12822,6 +12824,7 @@ package android.database.sqlite {
|
||||
method public void onDowngrade(android.database.sqlite.SQLiteDatabase, int, int);
|
||||
method public void onOpen(android.database.sqlite.SQLiteDatabase);
|
||||
method public abstract void onUpgrade(android.database.sqlite.SQLiteDatabase, int, int);
|
||||
method public void setIdleConnectionTimeout(long);
|
||||
method public void setLookasideConfig(int, int);
|
||||
method public void setWriteAheadLoggingEnabled(boolean);
|
||||
}
|
||||
|
||||
@@ -12000,6 +12000,7 @@ package android.database.sqlite {
|
||||
public static final class SQLiteDatabase.OpenParams {
|
||||
method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
|
||||
method public android.database.DatabaseErrorHandler getErrorHandler();
|
||||
method public long getIdleConnectionTimeout();
|
||||
method public int getLookasideSlotCount();
|
||||
method public int getLookasideSlotSize();
|
||||
method public int getOpenFlags();
|
||||
@@ -12013,6 +12014,7 @@ package android.database.sqlite {
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder removeOpenFlags(int);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setErrorHandler(android.database.DatabaseErrorHandler);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setIdleConnectionTimeout(long);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setLookasideConfig(int, int);
|
||||
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int);
|
||||
}
|
||||
@@ -12095,6 +12097,7 @@ package android.database.sqlite {
|
||||
method public void onDowngrade(android.database.sqlite.SQLiteDatabase, int, int);
|
||||
method public void onOpen(android.database.sqlite.SQLiteDatabase);
|
||||
method public abstract void onUpgrade(android.database.sqlite.SQLiteDatabase, int, int);
|
||||
method public void setIdleConnectionTimeout(long);
|
||||
method public void setLookasideConfig(int, int);
|
||||
method public void setWriteAheadLoggingEnabled(boolean);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package android.database.sqlite;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.database.sqlite.SQLiteDebug.DbStats;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.Handler;
|
||||
@@ -24,7 +23,6 @@ import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.OperationCanceledException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.Log;
|
||||
import android.util.PrefixPrinter;
|
||||
import android.util.Printer;
|
||||
@@ -84,15 +82,6 @@ public final class SQLiteConnectionPool implements Closeable {
|
||||
// and logging a message about the connection pool being busy.
|
||||
private static final long CONNECTION_POOL_BUSY_MILLIS = 30 * 1000; // 30 seconds
|
||||
|
||||
// TODO b/63398887 Move to SQLiteGlobal
|
||||
private static final long IDLE_CONNECTION_CLOSE_DELAY_MILLIS = SystemProperties
|
||||
.getInt("persist.debug.sqlite.idle_connection_close_delay", 30000);
|
||||
|
||||
// TODO b/63398887 STOPSHIP.
|
||||
// Temporarily enabled for testing across a broader set of dogfood devices.
|
||||
private static final boolean CLOSE_IDLE_CONNECTIONS = SystemProperties
|
||||
.getBoolean("persist.debug.sqlite.close_idle_connections", true);
|
||||
|
||||
private final CloseGuard mCloseGuard = CloseGuard.get();
|
||||
|
||||
private final Object mLock = new Object();
|
||||
@@ -167,16 +156,12 @@ public final class SQLiteConnectionPool implements Closeable {
|
||||
|
||||
private SQLiteConnectionPool(SQLiteDatabaseConfiguration configuration) {
|
||||
mConfiguration = new SQLiteDatabaseConfiguration(configuration);
|
||||
// Disable lookaside allocator on low-RAM devices
|
||||
if (ActivityManager.isLowRamDeviceStatic()) {
|
||||
mConfiguration.lookasideSlotCount = 0;
|
||||
mConfiguration.lookasideSlotSize = 0;
|
||||
}
|
||||
setMaxConnectionPoolSizeLocked();
|
||||
|
||||
// Do not close idle connections for in-memory databases
|
||||
if (CLOSE_IDLE_CONNECTIONS && !configuration.isInMemoryDb()) {
|
||||
setupIdleConnectionHandler(Looper.getMainLooper(), IDLE_CONNECTION_CLOSE_DELAY_MILLIS);
|
||||
// If timeout is set, setup idle connection handler
|
||||
// In case of MAX_VALUE - idle connections are never closed
|
||||
if (mConfiguration.idleConnectionTimeoutMs != Long.MAX_VALUE) {
|
||||
setupIdleConnectionHandler(Looper.getMainLooper(),
|
||||
mConfiguration.idleConnectionTimeoutMs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,6 +199,12 @@ public final class SQLiteConnectionPool implements Closeable {
|
||||
// This might throw if the database is corrupt.
|
||||
mAvailablePrimaryConnection = openConnectionLocked(mConfiguration,
|
||||
true /*primaryConnection*/); // might throw
|
||||
// Mark it released so it can be closed after idle timeout
|
||||
synchronized (mLock) {
|
||||
if (mIdleConnectionHandler != null) {
|
||||
mIdleConnectionHandler.connectionReleased(mAvailablePrimaryConnection);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the pool as being open for business.
|
||||
mIsOpen = true;
|
||||
@@ -1023,12 +1014,12 @@ public final class SQLiteConnectionPool implements Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the handler based on the provided looper and delay.
|
||||
* Set up the handler based on the provided looper and timeout.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public void setupIdleConnectionHandler(Looper looper, long delayMs) {
|
||||
public void setupIdleConnectionHandler(Looper looper, long timeoutMs) {
|
||||
synchronized (mLock) {
|
||||
mIdleConnectionHandler = new IdleConnectionHandler(looper, delayMs);
|
||||
mIdleConnectionHandler = new IdleConnectionHandler(looper, timeoutMs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1089,6 +1080,10 @@ public final class SQLiteConnectionPool implements Closeable {
|
||||
printer.println(" Lookaside config: sz=" + mConfiguration.lookasideSlotSize
|
||||
+ " cnt=" + mConfiguration.lookasideSlotCount);
|
||||
}
|
||||
if (mConfiguration.idleConnectionTimeoutMs != Long.MAX_VALUE) {
|
||||
printer.println(
|
||||
" Idle connection timeout: " + mConfiguration.idleConnectionTimeoutMs);
|
||||
}
|
||||
printer.println(" Available primary connection:");
|
||||
if (mAvailablePrimaryConnection != null) {
|
||||
mAvailablePrimaryConnection.dump(indentedPrinter, verbose);
|
||||
@@ -1155,11 +1150,11 @@ public final class SQLiteConnectionPool implements Closeable {
|
||||
}
|
||||
|
||||
private class IdleConnectionHandler extends Handler {
|
||||
private final long mDelay;
|
||||
private final long mTimeout;
|
||||
|
||||
IdleConnectionHandler(Looper looper, long delay) {
|
||||
IdleConnectionHandler(Looper looper, long timeout) {
|
||||
super(looper);
|
||||
mDelay = delay;
|
||||
mTimeout = timeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1172,14 +1167,14 @@ public final class SQLiteConnectionPool implements Closeable {
|
||||
if (closeAvailableConnectionLocked(msg.what)) {
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "Closed idle connection " + mConfiguration.label + " " + msg.what
|
||||
+ " after " + mDelay);
|
||||
+ " after " + mTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void connectionReleased(SQLiteConnection con) {
|
||||
sendEmptyMessageDelayed(con.getConnectionId(), mDelay);
|
||||
sendEmptyMessageDelayed(con.getConnectionId(), mTimeout);
|
||||
}
|
||||
|
||||
void connectionAcquired(SQLiteConnection con) {
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.DatabaseErrorHandler;
|
||||
@@ -30,6 +31,7 @@ import android.database.sqlite.SQLiteDebug.DbStats;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.Looper;
|
||||
import android.os.OperationCanceledException;
|
||||
import android.os.SystemProperties;
|
||||
import android.text.TextUtils;
|
||||
import android.util.EventLog;
|
||||
import android.util.Log;
|
||||
@@ -77,21 +79,21 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
|
||||
private static final int EVENT_DB_CORRUPT = 75004;
|
||||
|
||||
// TODO b/63398887 STOPSHIP.
|
||||
// Temporarily enabled for testing across a broader set of dogfood devices.
|
||||
private static final boolean DEBUG_CLOSE_IDLE_CONNECTIONS = SystemProperties
|
||||
.getBoolean("persist.debug.sqlite.close_idle_connections", true);
|
||||
|
||||
// Stores reference to all databases opened in the current process.
|
||||
// (The referent Object is not used at this time.)
|
||||
// INVARIANT: Guarded by sActiveDatabases.
|
||||
private static WeakHashMap<SQLiteDatabase, Object> sActiveDatabases =
|
||||
new WeakHashMap<SQLiteDatabase, Object>();
|
||||
private static WeakHashMap<SQLiteDatabase, Object> sActiveDatabases = new WeakHashMap<>();
|
||||
|
||||
// Thread-local for database sessions that belong to this database.
|
||||
// Each thread has its own database session.
|
||||
// INVARIANT: Immutable.
|
||||
private final ThreadLocal<SQLiteSession> mThreadSession = new ThreadLocal<SQLiteSession>() {
|
||||
@Override
|
||||
protected SQLiteSession initialValue() {
|
||||
return createSession();
|
||||
}
|
||||
};
|
||||
private final ThreadLocal<SQLiteSession> mThreadSession = ThreadLocal
|
||||
.withInitial(this::createSession);
|
||||
|
||||
// The optional factory to use when creating new Cursors. May be null.
|
||||
// INVARIANT: Immutable.
|
||||
@@ -261,12 +263,29 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
|
||||
private SQLiteDatabase(final String path, final int openFlags,
|
||||
CursorFactory cursorFactory, DatabaseErrorHandler errorHandler,
|
||||
int lookasideSlotSize, int lookasideSlotCount) {
|
||||
int lookasideSlotSize, int lookasideSlotCount, long idleConnectionTimeoutMs) {
|
||||
mCursorFactory = cursorFactory;
|
||||
mErrorHandler = errorHandler != null ? errorHandler : new DefaultDatabaseErrorHandler();
|
||||
mConfigurationLocked = new SQLiteDatabaseConfiguration(path, openFlags);
|
||||
mConfigurationLocked.lookasideSlotSize = lookasideSlotSize;
|
||||
mConfigurationLocked.lookasideSlotCount = lookasideSlotCount;
|
||||
// Disable lookaside allocator on low-RAM devices
|
||||
if (ActivityManager.isLowRamDeviceStatic()) {
|
||||
mConfigurationLocked.lookasideSlotCount = 0;
|
||||
mConfigurationLocked.lookasideSlotSize = 0;
|
||||
}
|
||||
long effectiveTimeoutMs = Long.MAX_VALUE;
|
||||
// Never close idle connections for in-memory databases
|
||||
if (!mConfigurationLocked.isInMemoryDb()) {
|
||||
// First, check app-specific value. Otherwise use defaults
|
||||
// -1 in idleConnectionTimeoutMs indicates unset value
|
||||
if (idleConnectionTimeoutMs >= 0) {
|
||||
effectiveTimeoutMs = idleConnectionTimeoutMs;
|
||||
} else if (DEBUG_CLOSE_IDLE_CONNECTIONS) {
|
||||
effectiveTimeoutMs = SQLiteGlobal.getIdleConnectionTimeout();
|
||||
}
|
||||
}
|
||||
mConfigurationLocked.idleConnectionTimeoutMs = effectiveTimeoutMs;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -694,7 +713,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
Preconditions.checkArgument(openParams != null, "OpenParams cannot be null");
|
||||
SQLiteDatabase db = new SQLiteDatabase(path, openParams.mOpenFlags,
|
||||
openParams.mCursorFactory, openParams.mErrorHandler,
|
||||
openParams.mLookasideSlotSize, openParams.mLookasideSlotCount);
|
||||
openParams.mLookasideSlotSize, openParams.mLookasideSlotCount,
|
||||
openParams.mIdleConnectionTimeout);
|
||||
db.open();
|
||||
return db;
|
||||
}
|
||||
@@ -720,7 +740,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
*/
|
||||
public static SQLiteDatabase openDatabase(@NonNull String path, @Nullable CursorFactory factory,
|
||||
@DatabaseOpenFlags int flags, @Nullable DatabaseErrorHandler errorHandler) {
|
||||
SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler, -1, -1);
|
||||
SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler, -1, -1, -1);
|
||||
db.open();
|
||||
return db;
|
||||
}
|
||||
@@ -2267,14 +2287,17 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
private final DatabaseErrorHandler mErrorHandler;
|
||||
private final int mLookasideSlotSize;
|
||||
private final int mLookasideSlotCount;
|
||||
private long mIdleConnectionTimeout;
|
||||
|
||||
private OpenParams(int openFlags, CursorFactory cursorFactory,
|
||||
DatabaseErrorHandler errorHandler, int lookasideSlotSize, int lookasideSlotCount) {
|
||||
DatabaseErrorHandler errorHandler, int lookasideSlotSize, int lookasideSlotCount,
|
||||
long idleConnectionTimeout) {
|
||||
mOpenFlags = openFlags;
|
||||
mCursorFactory = cursorFactory;
|
||||
mErrorHandler = errorHandler;
|
||||
mLookasideSlotSize = lookasideSlotSize;
|
||||
mLookasideSlotCount = lookasideSlotCount;
|
||||
mIdleConnectionTimeout = idleConnectionTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2329,6 +2352,17 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
return mErrorHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns maximum number of milliseconds that SQLite connection is allowed to be idle
|
||||
* before it is closed and removed from the pool.
|
||||
* <p>If the value isn't set, the timeout defaults to the system wide timeout
|
||||
*
|
||||
* @return timeout in milliseconds or -1 if the value wasn't set.
|
||||
*/
|
||||
public long getIdleConnectionTimeout() {
|
||||
return mIdleConnectionTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of builder {@link Builder#Builder(OpenParams) initialized} with
|
||||
* {@code this} parameters.
|
||||
@@ -2345,6 +2379,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
public static final class Builder {
|
||||
private int mLookasideSlotSize = -1;
|
||||
private int mLookasideSlotCount = -1;
|
||||
private long mIdleConnectionTimeout = -1;
|
||||
private int mOpenFlags;
|
||||
private CursorFactory mCursorFactory;
|
||||
private DatabaseErrorHandler mErrorHandler;
|
||||
@@ -2473,6 +2508,22 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of milliseconds that SQLite connection is allowed to be idle
|
||||
* before it is closed and removed from the pool.
|
||||
*
|
||||
* @param idleConnectionTimeoutMs timeout in milliseconds. Use {@link Long#MAX_VALUE}
|
||||
* to allow unlimited idle connections.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setIdleConnectionTimeout(
|
||||
@IntRange(from = 0) long idleConnectionTimeoutMs) {
|
||||
Preconditions.checkArgument(idleConnectionTimeoutMs >= 0,
|
||||
"idle connection timeout cannot be negative");
|
||||
mIdleConnectionTimeout = idleConnectionTimeoutMs;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of {@link OpenParams} with the options that were previously set
|
||||
* on this builder
|
||||
@@ -2480,7 +2531,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
@NonNull
|
||||
public OpenParams build() {
|
||||
return new OpenParams(mOpenFlags, mCursorFactory, mErrorHandler, mLookasideSlotSize,
|
||||
mLookasideSlotCount);
|
||||
mLookasideSlotCount, mIdleConnectionTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,14 +94,21 @@ public final class SQLiteDatabaseConfiguration {
|
||||
*
|
||||
* <p>If negative, the default lookaside configuration will be used
|
||||
*/
|
||||
public int lookasideSlotSize;
|
||||
public int lookasideSlotSize = -1;
|
||||
|
||||
/**
|
||||
* The total number of lookaside memory slots per database connection
|
||||
*
|
||||
* <p>If negative, the default lookaside configuration will be used
|
||||
*/
|
||||
public int lookasideSlotCount;
|
||||
public int lookasideSlotCount = -1;
|
||||
|
||||
/**
|
||||
* The number of milliseconds that SQLite connection is allowed to be idle before it
|
||||
* is closed and removed from the pool.
|
||||
* <p>By default, idle connections are not closed
|
||||
*/
|
||||
public long idleConnectionTimeoutMs = Long.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* Creates a database configuration with the required parameters for opening a
|
||||
@@ -122,8 +129,6 @@ public final class SQLiteDatabaseConfiguration {
|
||||
// Set default values for optional parameters.
|
||||
maxSqlCacheSize = 25;
|
||||
locale = Locale.getDefault();
|
||||
lookasideSlotSize = -1;
|
||||
lookasideSlotCount = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,6 +169,7 @@ public final class SQLiteDatabaseConfiguration {
|
||||
customFunctions.addAll(other.customFunctions);
|
||||
lookasideSlotSize = other.lookasideSlotSize;
|
||||
lookasideSlotCount = other.lookasideSlotCount;
|
||||
idleConnectionTimeoutMs = other.idleConnectionTimeoutMs;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -124,4 +124,15 @@ public final class SQLiteGlobal {
|
||||
com.android.internal.R.integer.db_connection_pool_size));
|
||||
return Math.max(2, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The default number of milliseconds that SQLite connection is allowed to be idle before it
|
||||
* is closed and removed from the pool.
|
||||
*/
|
||||
public static int getIdleConnectionTimeout() {
|
||||
return SystemProperties.getInt("debug.sqlite.idle_connection_timeout",
|
||||
Resources.getSystem().getInteger(
|
||||
com.android.internal.R.integer.db_default_idle_connection_timeout));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -194,6 +194,26 @@ public abstract class SQLiteOpenHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of milliseconds that SQLite connection is allowed to be idle
|
||||
* before it is closed and removed from the pool.
|
||||
*
|
||||
* <p>This method should be called from the constructor of the subclass,
|
||||
* before opening the database
|
||||
*
|
||||
* @param idleConnectionTimeoutMs timeout in milliseconds. Use {@link Long#MAX_VALUE} value
|
||||
* to allow unlimited idle connections.
|
||||
*/
|
||||
public void setIdleConnectionTimeout(@IntRange(from = 0) final long idleConnectionTimeoutMs) {
|
||||
synchronized (this) {
|
||||
if (mDatabase != null && mDatabase.isOpen()) {
|
||||
throw new IllegalStateException(
|
||||
"Connection timeout setting cannot be changed after opening the database");
|
||||
}
|
||||
mOpenParamsBuilder.setIdleConnectionTimeout(idleConnectionTimeoutMs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -1673,6 +1673,10 @@
|
||||
The size of the WAL file is also constrained by 'db_journal_size_limit'. -->
|
||||
<integer name="db_wal_autocheckpoint">100</integer>
|
||||
|
||||
<!-- The number of milliseconds that SQLite connection is allowed to be idle before it
|
||||
is closed and removed from the pool -->
|
||||
<integer name="db_default_idle_connection_timeout">30000</integer>
|
||||
|
||||
<!-- Max space (in MB) allocated to DownloadManager to store the downloaded
|
||||
files if they are to be stored in DownloadManager's data dir,
|
||||
which typically is /data/data/com.android.providers.downloads/files -->
|
||||
|
||||
@@ -428,6 +428,7 @@
|
||||
<java-symbol type="integer" name="db_connection_pool_size" />
|
||||
<java-symbol type="integer" name="db_journal_size_limit" />
|
||||
<java-symbol type="integer" name="db_wal_autocheckpoint" />
|
||||
<java-symbol type="integer" name="db_default_idle_connection_timeout" />
|
||||
<java-symbol type="integer" name="config_soundEffectVolumeDb" />
|
||||
<java-symbol type="integer" name="config_lockSoundVolumeDb" />
|
||||
<java-symbol type="integer" name="config_multiuserMaximumUsers" />
|
||||
|
||||
@@ -25,6 +25,8 @@ import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteDebug;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.os.Parcel;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.uiautomator.UiDevice;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.test.PerformanceTestCase;
|
||||
import android.test.suitebuilder.annotation.LargeTest;
|
||||
@@ -1185,4 +1187,38 @@ public class DatabaseGeneralTest extends AndroidTestCase implements PerformanceT
|
||||
fail("unexpected");
|
||||
}
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
public void testCloseIdleConnection() throws Exception {
|
||||
mDatabase.close();
|
||||
SQLiteDatabase.OpenParams params = new SQLiteDatabase.OpenParams.Builder()
|
||||
.setIdleConnectionTimeout(1000).build();
|
||||
mDatabase = SQLiteDatabase.openDatabase(mDatabaseFile.getPath(), params);
|
||||
// Wait a bit and check that connection is still open
|
||||
Thread.sleep(100);
|
||||
String output = executeShellCommand("dumpsys dbinfo " + getContext().getPackageName());
|
||||
assertTrue("Connection #0 should be open. Output: " + output,
|
||||
output.contains("Connection #0:"));
|
||||
|
||||
// Now cause idle timeout and check that connection is closed
|
||||
Thread.sleep(1000);
|
||||
output = executeShellCommand("dumpsys dbinfo " + getContext().getPackageName());
|
||||
assertFalse("Connection #0 should be closed. Output: " + output,
|
||||
output.contains("Connection #0:"));
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testSetIdleConnectionTimeoutValidation() throws Exception {
|
||||
try {
|
||||
new SQLiteDatabase.OpenParams.Builder().setIdleConnectionTimeout(-1).build();
|
||||
fail("Negative timeout should be rejected");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
private String executeShellCommand(String cmd) throws Exception {
|
||||
return UiDevice.getInstance(
|
||||
InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user