SQLiteConnectionPool.java revision e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fc
1e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown/*
2e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Copyright (C) 2011 The Android Open Source Project
3e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *
4e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
5e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * you may not use this file except in compliance with the License.
6e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * You may obtain a copy of the License at
7e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *
8e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
9e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *
10e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Unless required by applicable law or agreed to in writing, software
11e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
12e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * See the License for the specific language governing permissions and
14e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * limitations under the License.
15e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */
16e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
17e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownpackage android.database.sqlite;
18e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
19e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport dalvik.system.CloseGuard;
20e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
214c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brownimport android.content.CancellationSignal;
2275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brownimport android.content.OperationCanceledException;
23e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.database.sqlite.SQLiteDebug.DbStats;
24e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.os.SystemClock;
25e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.util.Log;
26e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.util.PrefixPrinter;
27e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.util.Printer;
28e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
29e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport java.io.Closeable;
30e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport java.util.ArrayList;
31e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport java.util.Map;
32e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport java.util.WeakHashMap;
33e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport java.util.concurrent.atomic.AtomicBoolean;
34e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport java.util.concurrent.locks.LockSupport;
35e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
36e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown/**
37e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Maintains a pool of active SQLite database connections.
38e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p>
39e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * At any given time, a connection is either owned by the pool, or it has been
40e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * acquired by a {@link SQLiteSession}.  When the {@link SQLiteSession} is
41e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * finished with the connection it is using, it must return the connection
42e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * back to the pool.
43e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p>
44e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * The pool holds strong references to the connections it owns.  However,
45e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * it only holds <em>weak references</em> to the connections that sessions
46e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * have acquired from it.  Using weak references in the latter case ensures
47e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * that the connection pool can detect when connections have been improperly
48e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * abandoned so that it can create new connections to replace them if needed.
49e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p>
50e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * The connection pool is thread-safe (but the connections themselves are not).
51e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p>
52e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *
53e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <h2>Exception safety</h2>
54e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p>
55e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * This code attempts to maintain the invariant that opened connections are
56e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * always owned.  Unfortunately that means it needs to handle exceptions
57e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * all over to ensure that broken connections get cleaned up.  Most
58e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * operations invokving SQLite can throw {@link SQLiteException} or other
59e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * runtime exceptions.  This is a bit of a pain to deal with because the compiler
60e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * cannot help us catch missing exception handling code.
61e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p>
62e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * The general rule for this file: If we are making calls out to
63e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * {@link SQLiteConnection} then we must be prepared to handle any
64e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * runtime exceptions it might throw at us.  Note that out-of-memory
65e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * is an {@link Error}, not a {@link RuntimeException}.  We don't trouble ourselves
66e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * handling out of memory because it is hard to do anything at all sensible then
67e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * and most likely the VM is about to crash.
68e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p>
69e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *
70e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @hide
71e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */
72e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownpublic final class SQLiteConnectionPool implements Closeable {
73e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private static final String TAG = "SQLiteConnectionPool";
74e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
75e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Amount of time to wait in milliseconds before unblocking acquireConnection
76e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // and logging a message about the connection pool being busy.
77e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private static final long CONNECTION_POOL_BUSY_MILLIS = 30 * 1000; // 30 seconds
78e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
79e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private final CloseGuard mCloseGuard = CloseGuard.get();
80e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
81e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private final Object mLock = new Object();
82e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private final AtomicBoolean mConnectionLeaked = new AtomicBoolean();
83e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private final SQLiteDatabaseConfiguration mConfiguration;
84e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private boolean mIsOpen;
85e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private int mNextConnectionId;
86e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
87e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private ConnectionWaiter mConnectionWaiterPool;
88e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private ConnectionWaiter mConnectionWaiterQueue;
89e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
90e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Strong references to all available connections.
91e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private final ArrayList<SQLiteConnection> mAvailableNonPrimaryConnections =
92e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            new ArrayList<SQLiteConnection>();
93e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private SQLiteConnection mAvailablePrimaryConnection;
94e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
95559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    // Describes what should happen to an acquired connection when it is returned to the pool.
96559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    enum AcquiredConnectionStatus {
97559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        // The connection should be returned to the pool as usual.
98559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        NORMAL,
99559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown
100559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        // The connection must be reconfigured before being returned.
101559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        RECONFIGURE,
102559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown
103559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        // The connection must be closed and discarded.
104559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        DISCARD,
105559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    }
106559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown
107e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Weak references to all acquired connections.  The associated value
108559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    // indicates whether the connection must be reconfigured before being
109559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    // returned to the available connection list or discarded.
110e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // For example, the prepared statement cache size may have changed and
111559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    // need to be updated in preparation for the next client.
112559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    private final WeakHashMap<SQLiteConnection, AcquiredConnectionStatus> mAcquiredConnections =
113559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            new WeakHashMap<SQLiteConnection, AcquiredConnectionStatus>();
114e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
115e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
116e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Connection flag: Read-only.
117e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * <p>
118e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * This flag indicates that the connection will only be used to
119e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * perform read-only operations.
120e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * </p>
121e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
122e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    public static final int CONNECTION_FLAG_READ_ONLY = 1 << 0;
123e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
124e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
125e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Connection flag: Primary connection affinity.
126e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * <p>
127e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * This flag indicates that the primary connection is required.
128e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * This flag helps support legacy applications that expect most data modifying
129e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * operations to be serialized by locking the primary database connection.
130e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Setting this flag essentially implements the old "db lock" concept by preventing
131e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * an operation from being performed until it can obtain exclusive access to
132e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * the primary connection.
133e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * </p>
134e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
135e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    public static final int CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY = 1 << 1;
136e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
137e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
138e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Connection flag: Connection is being used interactively.
139e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * <p>
140e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * This flag indicates that the connection is needed by the UI thread.
141e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * The connection pool can use this flag to elevate the priority
142e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * of the database connection request.
143e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * </p>
144e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
145e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    public static final int CONNECTION_FLAG_INTERACTIVE = 1 << 2;
146e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
147e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private SQLiteConnectionPool(SQLiteDatabaseConfiguration configuration) {
148e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        mConfiguration = new SQLiteDatabaseConfiguration(configuration);
149e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
150e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
151e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    @Override
152e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    protected void finalize() throws Throwable {
153e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        try {
154e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            dispose(true);
155e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } finally {
156e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            super.finalize();
157e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
158e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
159e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
160e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
161e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Opens a connection pool for the specified database.
162e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
163e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param configuration The database configuration.
164e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @return The connection pool.
165e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
166e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws SQLiteException if a database error occurs.
167e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
168e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    public static SQLiteConnectionPool open(SQLiteDatabaseConfiguration configuration) {
169e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (configuration == null) {
170e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw new IllegalArgumentException("configuration must not be null.");
171e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
172e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
173e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // Create the pool.
174e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        SQLiteConnectionPool pool = new SQLiteConnectionPool(configuration);
175e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        pool.open(); // might throw
176e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return pool;
177e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
178e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
179e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Might throw
180e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private void open() {
181e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // Open the primary connection.
182e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // This might throw if the database is corrupt.
183559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        mAvailablePrimaryConnection = openConnectionLocked(mConfiguration,
184e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                true /*primaryConnection*/); // might throw
185e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
186e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // Mark the pool as being open for business.
187e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        mIsOpen = true;
188e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        mCloseGuard.open("close");
189e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
190e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
191e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
192e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Closes the connection pool.
193e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * <p>
194e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * When the connection pool is closed, it will refuse all further requests
195e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * to acquire connections.  All connections that are currently available in
196e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * the pool are closed immediately.  Any connections that are still in use
197e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * will be closed as soon as they are returned to the pool.
198e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * </p>
199e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
200e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws IllegalStateException if the pool has been closed.
201e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
202e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    public void close() {
203e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        dispose(false);
204e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
205e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
206e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private void dispose(boolean finalized) {
207e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (mCloseGuard != null) {
208e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (finalized) {
209e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                mCloseGuard.warnIfOpen();
210e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
211e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            mCloseGuard.close();
212e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
213e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
214e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (!finalized) {
215e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // Close all connections.  We don't need (or want) to do this
216e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // when finalized because we don't know what state the connections
217e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // themselves will be in.  The finalizer is really just here for CloseGuard.
218e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // The connections will take care of themselves when their own finalizers run.
219e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            synchronized (mLock) {
220e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                throwIfClosedLocked();
221e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
222e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                mIsOpen = false;
223e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
224559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                closeAvailableConnectionsAndLogExceptionsLocked();
225e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
226e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                final int pendingCount = mAcquiredConnections.size();
227e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                if (pendingCount != 0) {
228e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    Log.i(TAG, "The connection pool for " + mConfiguration.label
229e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                            + " has been closed but there are still "
230e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                            + pendingCount + " connections in use.  They will be closed "
231e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                            + "as they are released back to the pool.");
232e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
233e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
234e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                wakeConnectionWaitersLocked();
235e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
236e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
237e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
238e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
239e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
240e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Reconfigures the database configuration of the connection pool and all of its
241e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * connections.
242e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * <p>
243e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Configuration changes are propagated down to connections immediately if
244e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * they are available or as soon as they are released.  This includes changes
245e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * that affect the size of the pool.
246e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * </p>
247e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
248e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param configuration The new configuration.
249e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
250e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws IllegalStateException if the pool has been closed.
251e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
252e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    public void reconfigure(SQLiteDatabaseConfiguration configuration) {
253e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (configuration == null) {
254e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw new IllegalArgumentException("configuration must not be null.");
255e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
256e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
257e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        synchronized (mLock) {
258e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throwIfClosedLocked();
259e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
260e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown            boolean restrictToOneConnection = false;
261e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown            if (mConfiguration.journalMode.equalsIgnoreCase("WAL")
262e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                    != configuration.journalMode.equalsIgnoreCase("WAL")) {
263e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                // WAL mode can only be changed if there are no acquired connections
264e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                // because we need to close all but the primary connection first.
265e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                if (!mAcquiredConnections.isEmpty()) {
266e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                    throw new IllegalStateException("Write Ahead Logging (WAL) mode cannot "
267e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                            + "be enabled or disabled while there are transactions in "
268e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                            + "progress.  Finish all transactions and release all active "
269e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                            + "database connections first.");
270e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                }
271e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown
272e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                // Close all non-primary connections.  This should happen immediately
273e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                // because none of them are in use.
274e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                closeAvailableNonPrimaryConnectionsAndLogExceptionsLocked();
275e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                assert mAvailableNonPrimaryConnections.isEmpty();
276e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown
277e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                restrictToOneConnection = true;
278e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown            }
279e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown
280559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            if (mConfiguration.openFlags != configuration.openFlags) {
281e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                // If we are changing open flags and WAL mode at the same time, then
282e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                // we have no choice but to close the primary connection beforehand
283e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                // because there can only be one connection open when we change WAL mode.
284e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                if (restrictToOneConnection) {
285e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                    closeAvailableConnectionsAndLogExceptionsLocked();
286e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown                }
287e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown
288559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                // Try to reopen the primary connection using the new open flags then
289559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                // close and discard all existing connections.
290559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                // This might throw if the database is corrupt or cannot be opened in
291559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                // the new mode in which case existing connections will remain untouched.
292559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                SQLiteConnection newPrimaryConnection = openConnectionLocked(configuration,
293559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                        true /*primaryConnection*/); // might throw
294e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
295559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                closeAvailableConnectionsAndLogExceptionsLocked();
296559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                discardAcquiredConnectionsLocked();
297e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
298559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                mAvailablePrimaryConnection = newPrimaryConnection;
299559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                mConfiguration.updateParametersFrom(configuration);
300559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            } else {
301559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                // Reconfigure the database connections in place.
302559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                mConfiguration.updateParametersFrom(configuration);
303559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown
304559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                closeExcessConnectionsAndLogExceptionsLocked();
305559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                reconfigureAllConnectionsLocked();
306559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            }
307e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
308e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            wakeConnectionWaitersLocked();
309e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
310e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
311e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
312e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
313e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Acquires a connection from the pool.
314e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * <p>
315e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * The caller must call {@link #releaseConnection} to release the connection
316e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * back to the pool when it is finished.  Failure to do so will result
317e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * in much unpleasantness.
318e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * </p>
319e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
320e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param sql If not null, try to find a connection that already has
321e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * the specified SQL statement in its prepared statement cache.
322e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param connectionFlags The connection request flags.
3234c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
324e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @return The connection that was acquired, never null.
325e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
326e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws IllegalStateException if the pool has been closed.
327e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws SQLiteException if a database error occurs.
32875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @throws OperationCanceledException if the operation was canceled.
329e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
33075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    public SQLiteConnection acquireConnection(String sql, int connectionFlags,
3314c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            CancellationSignal cancellationSignal) {
3324c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        return waitForConnection(sql, connectionFlags, cancellationSignal);
333e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
334e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
335e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
336e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Releases a connection back to the pool.
337e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * <p>
338e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * It is ok to call this method after the pool has closed, to release
339e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * connections that were still in use at the time of closure.
340e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * </p>
341e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
342e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param connection The connection to release.  Must not be null.
343e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
344e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws IllegalStateException if the connection was not acquired
345e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * from this pool or if it has already been released.
346e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
347e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    public void releaseConnection(SQLiteConnection connection) {
348e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        synchronized (mLock) {
349559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            AcquiredConnectionStatus status = mAcquiredConnections.remove(connection);
350559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            if (status == null) {
351e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                throw new IllegalStateException("Cannot perform this operation "
352e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        + "because the specified connection was not acquired "
353e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        + "from this pool or has already been released.");
354e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
355e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
356e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (!mIsOpen) {
357e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                closeConnectionAndLogExceptionsLocked(connection);
358e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } else if (connection.isPrimaryConnection()) {
359559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                if (recycleConnectionLocked(connection, status)) {
360559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                    assert mAvailablePrimaryConnection == null;
361e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    mAvailablePrimaryConnection = connection;
362e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
363e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                wakeConnectionWaitersLocked();
364e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } else if (mAvailableNonPrimaryConnections.size() >=
365e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    mConfiguration.maxConnectionPoolSize - 1) {
366e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                closeConnectionAndLogExceptionsLocked(connection);
367e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } else {
368559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                if (recycleConnectionLocked(connection, status)) {
369e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    mAvailableNonPrimaryConnections.add(connection);
370e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
371e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                wakeConnectionWaitersLocked();
372e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
373e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
374e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
375e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
376559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    // Can't throw.
377559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    private boolean recycleConnectionLocked(SQLiteConnection connection,
378559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            AcquiredConnectionStatus status) {
379559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        if (status == AcquiredConnectionStatus.RECONFIGURE) {
380559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            try {
381559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                connection.reconfigure(mConfiguration); // might throw
382559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            } catch (RuntimeException ex) {
383559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                Log.e(TAG, "Failed to reconfigure released connection, closing it: "
384559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                        + connection, ex);
385559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                status = AcquiredConnectionStatus.DISCARD;
386559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            }
387559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        }
388559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        if (status == AcquiredConnectionStatus.DISCARD) {
389559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            closeConnectionAndLogExceptionsLocked(connection);
390559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            return false;
391559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        }
392559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        return true;
393559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    }
394559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown
395e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
396e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Returns true if the session should yield the connection due to
397e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * contention over available database connections.
398e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
399e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param connection The connection owned by the session.
400e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param connectionFlags The connection request flags.
401e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @return True if the session should yield its connection.
402e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
403e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws IllegalStateException if the connection was not acquired
404e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * from this pool or if it has already been released.
405e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
406e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    public boolean shouldYieldConnection(SQLiteConnection connection, int connectionFlags) {
407e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        synchronized (mLock) {
408e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (!mAcquiredConnections.containsKey(connection)) {
409e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                throw new IllegalStateException("Cannot perform this operation "
410e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        + "because the specified connection was not acquired "
411e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        + "from this pool or has already been released.");
412e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
413e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
414e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (!mIsOpen) {
415e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                return false;
416e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
417e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
418e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            return isSessionBlockingImportantConnectionWaitersLocked(
419e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    connection.isPrimaryConnection(), connectionFlags);
420e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
421e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
422e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
423e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
424e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Collects statistics about database connection memory usage.
425e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
426e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param dbStatsList The list to populate.
427e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
428e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    public void collectDbStats(ArrayList<DbStats> dbStatsList) {
429e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        synchronized (mLock) {
430e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (mAvailablePrimaryConnection != null) {
431e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                mAvailablePrimaryConnection.collectDbStats(dbStatsList);
432e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
433e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
434e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            for (SQLiteConnection connection : mAvailableNonPrimaryConnections) {
435e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                connection.collectDbStats(dbStatsList);
436e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
437e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
438e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            for (SQLiteConnection connection : mAcquiredConnections.keySet()) {
439e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                connection.collectDbStatsUnsafe(dbStatsList);
440e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
441e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
442e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
443e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
444e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Might throw.
445559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    private SQLiteConnection openConnectionLocked(SQLiteDatabaseConfiguration configuration,
446559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            boolean primaryConnection) {
447e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        final int connectionId = mNextConnectionId++;
448559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        return SQLiteConnection.open(this, configuration,
449e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                connectionId, primaryConnection); // might throw
450e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
451e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
452e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    void onConnectionLeaked() {
453e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // This code is running inside of the SQLiteConnection finalizer.
454e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        //
455e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // We don't know whether it is just the connection that has been finalized (and leaked)
456e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // or whether the connection pool has also been or is about to be finalized.
457e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // Consequently, it would be a bad idea to try to grab any locks or to
458e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // do any significant work here.  So we do the simplest possible thing and
459e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // set a flag.  waitForConnection() periodically checks this flag (when it
460e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // times out) so that it can recover from leaked connections and wake
461e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // itself or other threads up if necessary.
462e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        //
463e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // You might still wonder why we don't try to do more to wake up the waiters
464e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // immediately.  First, as explained above, it would be hard to do safely
465e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // unless we started an extra Thread to function as a reference queue.  Second,
466e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // this is never supposed to happen in normal operation.  Third, there is no
467e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // guarantee that the GC will actually detect the leak in a timely manner so
468e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // it's not all that important that we recover from the leak in a timely manner
469e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // either.  Fourth, if a badly behaved application finds itself hung waiting for
470e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // several seconds while waiting for a leaked connection to be detected and recreated,
471e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // then perhaps its authors will have added incentive to fix the problem!
472e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
473e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        Log.w(TAG, "A SQLiteConnection object for database '"
474e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                + mConfiguration.label + "' was leaked!  Please fix your application "
475e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                + "to end transactions in progress properly and to close the database "
476e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                + "when it is no longer needed.");
477e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
478e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        mConnectionLeaked.set(true);
479e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
480e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
481e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Can't throw.
482559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    private void closeAvailableConnectionsAndLogExceptionsLocked() {
483e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown        closeAvailableNonPrimaryConnectionsAndLogExceptionsLocked();
484559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown
485559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        if (mAvailablePrimaryConnection != null) {
486559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            closeConnectionAndLogExceptionsLocked(mAvailablePrimaryConnection);
487559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            mAvailablePrimaryConnection = null;
488559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        }
489559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    }
490559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown
491559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    // Can't throw.
492e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown    private void closeAvailableNonPrimaryConnectionsAndLogExceptionsLocked() {
493e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown        final int count = mAvailableNonPrimaryConnections.size();
494e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown        for (int i = 0; i < count; i++) {
495e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown            closeConnectionAndLogExceptionsLocked(mAvailableNonPrimaryConnections.get(i));
496e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown        }
497e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown        mAvailableNonPrimaryConnections.clear();
498e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown    }
499e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown
500e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fcJeff Brown    // Can't throw.
501559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    private void closeExcessConnectionsAndLogExceptionsLocked() {
502559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        int availableCount = mAvailableNonPrimaryConnections.size();
503559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        while (availableCount-- > mConfiguration.maxConnectionPoolSize - 1) {
504559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            SQLiteConnection connection =
505559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                    mAvailableNonPrimaryConnections.remove(availableCount);
506559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            closeConnectionAndLogExceptionsLocked(connection);
507559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        }
508559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    }
509559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown
510559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    // Can't throw.
511e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private void closeConnectionAndLogExceptionsLocked(SQLiteConnection connection) {
512e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        try {
513e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            connection.close(); // might throw
514e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } catch (RuntimeException ex) {
515e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            Log.e(TAG, "Failed to close connection, its fate is now in the hands "
516e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    + "of the merciful GC: " + connection, ex);
517e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
518e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
519e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
520e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Can't throw.
521559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    private void discardAcquiredConnectionsLocked() {
522559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        markAcquiredConnectionsLocked(AcquiredConnectionStatus.DISCARD);
523559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    }
524559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown
525559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    // Can't throw.
526e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private void reconfigureAllConnectionsLocked() {
527e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (mAvailablePrimaryConnection != null) {
528e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            try {
529e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                mAvailablePrimaryConnection.reconfigure(mConfiguration); // might throw
530e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } catch (RuntimeException ex) {
531e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                Log.e(TAG, "Failed to reconfigure available primary connection, closing it: "
532e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        + mAvailablePrimaryConnection, ex);
533e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                closeConnectionAndLogExceptionsLocked(mAvailablePrimaryConnection);
534e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                mAvailablePrimaryConnection = null;
535e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
536e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
537e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
538e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        int count = mAvailableNonPrimaryConnections.size();
539e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        for (int i = 0; i < count; i++) {
540e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            final SQLiteConnection connection = mAvailableNonPrimaryConnections.get(i);
541e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            try {
542e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                connection.reconfigure(mConfiguration); // might throw
543e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } catch (RuntimeException ex) {
544e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                Log.e(TAG, "Failed to reconfigure available non-primary connection, closing it: "
545e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        + connection, ex);
546e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                closeConnectionAndLogExceptionsLocked(connection);
547e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                mAvailableNonPrimaryConnections.remove(i--);
548e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                count -= 1;
549e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
550e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
551e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
552559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        markAcquiredConnectionsLocked(AcquiredConnectionStatus.RECONFIGURE);
553559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    }
554559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown
555559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    // Can't throw.
556559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown    private void markAcquiredConnectionsLocked(AcquiredConnectionStatus status) {
557e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (!mAcquiredConnections.isEmpty()) {
558e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            ArrayList<SQLiteConnection> keysToUpdate = new ArrayList<SQLiteConnection>(
559e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    mAcquiredConnections.size());
560559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            for (Map.Entry<SQLiteConnection, AcquiredConnectionStatus> entry
561559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                    : mAcquiredConnections.entrySet()) {
562559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                AcquiredConnectionStatus oldStatus = entry.getValue();
563559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                if (status != oldStatus
564559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                        && oldStatus != AcquiredConnectionStatus.DISCARD) {
565e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    keysToUpdate.add(entry.getKey());
566e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
567e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
568e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            final int updateCount = keysToUpdate.size();
569e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            for (int i = 0; i < updateCount; i++) {
570559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                mAcquiredConnections.put(keysToUpdate.get(i), status);
571e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
572e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
573e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
574e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
575e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Might throw.
57675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    private SQLiteConnection waitForConnection(String sql, int connectionFlags,
5774c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            CancellationSignal cancellationSignal) {
578e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        final boolean wantPrimaryConnection =
579e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                (connectionFlags & CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY) != 0;
580e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
581e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        final ConnectionWaiter waiter;
582e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        synchronized (mLock) {
583e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throwIfClosedLocked();
584e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
58575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            // Abort if canceled.
5864c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            if (cancellationSignal != null) {
5874c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                cancellationSignal.throwIfCanceled();
58875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            }
58975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
590e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // Try to acquire a connection.
591e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            SQLiteConnection connection = null;
592e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (!wantPrimaryConnection) {
593e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                connection = tryAcquireNonPrimaryConnectionLocked(
594e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        sql, connectionFlags); // might throw
595e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
596e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (connection == null) {
597e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                connection = tryAcquirePrimaryConnectionLocked(connectionFlags); // might throw
598e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
599e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (connection != null) {
600e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                return connection;
601e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
602e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
603e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // No connections available.  Enqueue a waiter in priority order.
604e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            final int priority = getPriority(connectionFlags);
605e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            final long startTime = SystemClock.uptimeMillis();
606e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            waiter = obtainConnectionWaiterLocked(Thread.currentThread(), startTime,
607e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    priority, wantPrimaryConnection, sql, connectionFlags);
608e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            ConnectionWaiter predecessor = null;
609e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            ConnectionWaiter successor = mConnectionWaiterQueue;
610e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            while (successor != null) {
611e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                if (priority > successor.mPriority) {
612e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    waiter.mNext = successor;
613e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    break;
614e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
615e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                predecessor = successor;
616e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                successor = successor.mNext;
617e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
618e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (predecessor != null) {
619e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                predecessor.mNext = waiter;
620e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } else {
621e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                mConnectionWaiterQueue = waiter;
622e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
62375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
6244c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            if (cancellationSignal != null) {
62575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                final int nonce = waiter.mNonce;
6264c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                cancellationSignal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
62775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                    @Override
62875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                    public void onCancel() {
62975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                        synchronized (mLock) {
63075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                            cancelConnectionWaiterLocked(waiter, nonce);
63175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                        }
63275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                    }
63375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                });
63475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            }
635e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
636e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
637e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // Park the thread until a connection is assigned or the pool is closed.
638e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // Rethrow an exception from the wait, if we got one.
639e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        long busyTimeoutMillis = CONNECTION_POOL_BUSY_MILLIS;
640e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        long nextBusyTimeoutTime = waiter.mStartTime + busyTimeoutMillis;
641e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        for (;;) {
642e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // Detect and recover from connection leaks.
643e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (mConnectionLeaked.compareAndSet(true, false)) {
64475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                synchronized (mLock) {
64575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                    wakeConnectionWaitersLocked();
64675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                }
647e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
648e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
649e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // Wait to be unparked (may already have happened), a timeout, or interruption.
650e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            LockSupport.parkNanos(this, busyTimeoutMillis * 1000000L);
651e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
652e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // Clear the interrupted flag, just in case.
653e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            Thread.interrupted();
654e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
655e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // Check whether we are done waiting yet.
656e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            synchronized (mLock) {
657e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                throwIfClosedLocked();
658e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
65975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                final SQLiteConnection connection = waiter.mAssignedConnection;
66075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                final RuntimeException ex = waiter.mException;
66175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                if (connection != null || ex != null) {
6624c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                    if (cancellationSignal != null) {
6634c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                        cancellationSignal.setOnCancelListener(null);
66475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                    }
665e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    recycleConnectionWaiterLocked(waiter);
66675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                    if (connection != null) {
66775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                        return connection;
66875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                    }
669e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    throw ex; // rethrow!
670e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
671e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
672e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                final long now = SystemClock.uptimeMillis();
673e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                if (now < nextBusyTimeoutTime) {
674e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    busyTimeoutMillis = now - nextBusyTimeoutTime;
675e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                } else {
676e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    logConnectionPoolBusyLocked(now - waiter.mStartTime, connectionFlags);
677e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    busyTimeoutMillis = CONNECTION_POOL_BUSY_MILLIS;
678e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    nextBusyTimeoutTime = now + busyTimeoutMillis;
679e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
680e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
681e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
682e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
683e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
684e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Can't throw.
68575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    private void cancelConnectionWaiterLocked(ConnectionWaiter waiter, int nonce) {
68675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        if (waiter.mNonce != nonce) {
68775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            // Waiter already removed and recycled.
68875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            return;
68975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
69075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
69175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        if (waiter.mAssignedConnection != null || waiter.mException != null) {
69275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            // Waiter is done waiting but has not woken up yet.
69375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            return;
69475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
69575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
69675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        // Waiter must still be waiting.  Dequeue it.
69775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        ConnectionWaiter predecessor = null;
69875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        ConnectionWaiter current = mConnectionWaiterQueue;
69975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        while (current != waiter) {
70075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            assert current != null;
70175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            predecessor = current;
70275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            current = current.mNext;
70375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
70475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        if (predecessor != null) {
70575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            predecessor.mNext = waiter.mNext;
70675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        } else {
70775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            mConnectionWaiterQueue = waiter.mNext;
70875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
70975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
71075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        // Send the waiter an exception and unpark it.
71175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        waiter.mException = new OperationCanceledException();
71275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        LockSupport.unpark(waiter.mThread);
71375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
71475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        // Check whether removing this waiter will enable other waiters to make progress.
71575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        wakeConnectionWaitersLocked();
71675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
71775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
71875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    // Can't throw.
719e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private void logConnectionPoolBusyLocked(long waitMillis, int connectionFlags) {
720e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        final Thread thread = Thread.currentThread();
721e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        StringBuilder msg = new StringBuilder();
722e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        msg.append("The connection pool for database '").append(mConfiguration.label);
723e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        msg.append("' has been unable to grant a connection to thread ");
724e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        msg.append(thread.getId()).append(" (").append(thread.getName()).append(") ");
725e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        msg.append("with flags 0x").append(Integer.toHexString(connectionFlags));
726e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        msg.append(" for ").append(waitMillis * 0.001f).append(" seconds.\n");
727e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
728e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        ArrayList<String> requests = new ArrayList<String>();
729e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        int activeConnections = 0;
730e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        int idleConnections = 0;
731e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (!mAcquiredConnections.isEmpty()) {
732559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            for (SQLiteConnection connection : mAcquiredConnections.keySet()) {
733e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                String description = connection.describeCurrentOperationUnsafe();
734e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                if (description != null) {
735e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    requests.add(description);
736e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    activeConnections += 1;
737e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                } else {
738e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    idleConnections += 1;
739e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
740e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
741e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
742e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        int availableConnections = mAvailableNonPrimaryConnections.size();
743e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (mAvailablePrimaryConnection != null) {
744e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            availableConnections += 1;
745e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
746e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
747e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        msg.append("Connections: ").append(activeConnections).append(" active, ");
748e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        msg.append(idleConnections).append(" idle, ");
749e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        msg.append(availableConnections).append(" available.\n");
750e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
751e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (!requests.isEmpty()) {
752e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            msg.append("\nRequests in progress:\n");
753e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            for (String request : requests) {
754e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                msg.append("  ").append(request).append("\n");
755e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
756e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
757e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
758e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        Log.w(TAG, msg.toString());
759e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
760e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
761e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Can't throw.
762e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private void wakeConnectionWaitersLocked() {
763e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // Unpark all waiters that have requests that we can fulfill.
764e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // This method is designed to not throw runtime exceptions, although we might send
765e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // a waiter an exception for it to rethrow.
766e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        ConnectionWaiter predecessor = null;
767e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        ConnectionWaiter waiter = mConnectionWaiterQueue;
768e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        boolean primaryConnectionNotAvailable = false;
769e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        boolean nonPrimaryConnectionNotAvailable = false;
770e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        while (waiter != null) {
771e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            boolean unpark = false;
772e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (!mIsOpen) {
773e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                unpark = true;
774e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } else {
775e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                try {
776e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    SQLiteConnection connection = null;
777e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    if (!waiter.mWantPrimaryConnection && !nonPrimaryConnectionNotAvailable) {
778e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        connection = tryAcquireNonPrimaryConnectionLocked(
779e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                                waiter.mSql, waiter.mConnectionFlags); // might throw
780e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        if (connection == null) {
781e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                            nonPrimaryConnectionNotAvailable = true;
782e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        }
783e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    }
784e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    if (connection == null && !primaryConnectionNotAvailable) {
785e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        connection = tryAcquirePrimaryConnectionLocked(
786e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                                waiter.mConnectionFlags); // might throw
787e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        if (connection == null) {
788e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                            primaryConnectionNotAvailable = true;
789e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        }
790e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    }
791e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    if (connection != null) {
792e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        waiter.mAssignedConnection = connection;
793e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        unpark = true;
794e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    } else if (nonPrimaryConnectionNotAvailable && primaryConnectionNotAvailable) {
795e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        // There are no connections available and the pool is still open.
796e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        // We cannot fulfill any more connection requests, so stop here.
797e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        break;
798e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    }
799e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                } catch (RuntimeException ex) {
800e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    // Let the waiter handle the exception from acquiring a connection.
801e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    waiter.mException = ex;
802e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    unpark = true;
803e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
804e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
805e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
806e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            final ConnectionWaiter successor = waiter.mNext;
807e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (unpark) {
808e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                if (predecessor != null) {
809e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    predecessor.mNext = successor;
810e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                } else {
811e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    mConnectionWaiterQueue = successor;
812e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
813e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                waiter.mNext = null;
814e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
815e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                LockSupport.unpark(waiter.mThread);
816e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } else {
817e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                predecessor = waiter;
818e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
819e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            waiter = successor;
820e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
821e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
822e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
823e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Might throw.
824e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private SQLiteConnection tryAcquirePrimaryConnectionLocked(int connectionFlags) {
825e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // If the primary connection is available, acquire it now.
826e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        SQLiteConnection connection = mAvailablePrimaryConnection;
827e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (connection != null) {
828e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            mAvailablePrimaryConnection = null;
829e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            finishAcquireConnectionLocked(connection, connectionFlags); // might throw
830e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            return connection;
831e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
832e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
833e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // Make sure that the primary connection actually exists and has just been acquired.
834e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        for (SQLiteConnection acquiredConnection : mAcquiredConnections.keySet()) {
835e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (acquiredConnection.isPrimaryConnection()) {
836e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                return null;
837e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
838e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
839e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
840e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // Uhoh.  No primary connection!  Either this is the first time we asked
841e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // for it, or maybe it leaked?
842559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        connection = openConnectionLocked(mConfiguration,
843559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                true /*primaryConnection*/); // might throw
844e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        finishAcquireConnectionLocked(connection, connectionFlags); // might throw
845e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return connection;
846e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
847e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
848e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Might throw.
849e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private SQLiteConnection tryAcquireNonPrimaryConnectionLocked(
850e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            String sql, int connectionFlags) {
851e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // Try to acquire the next connection in the queue.
852e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        SQLiteConnection connection;
853e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        final int availableCount = mAvailableNonPrimaryConnections.size();
854e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (availableCount > 1 && sql != null) {
855e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // If we have a choice, then prefer a connection that has the
856e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // prepared statement in its cache.
857e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            for (int i = 0; i < availableCount; i++) {
858e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                connection = mAvailableNonPrimaryConnections.get(i);
859e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                if (connection.isPreparedStatementInCache(sql)) {
860e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    mAvailableNonPrimaryConnections.remove(i);
861e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    finishAcquireConnectionLocked(connection, connectionFlags); // might throw
862e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    return connection;
863e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
864e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
865e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
866e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (availableCount > 0) {
867e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // Otherwise, just grab the next one.
868e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            connection = mAvailableNonPrimaryConnections.remove(availableCount - 1);
869e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            finishAcquireConnectionLocked(connection, connectionFlags); // might throw
870e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            return connection;
871e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
872e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
873e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // Expand the pool if needed.
874e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        int openConnections = mAcquiredConnections.size();
875e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (mAvailablePrimaryConnection != null) {
876e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            openConnections += 1;
877e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
878e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (openConnections >= mConfiguration.maxConnectionPoolSize) {
879e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            return null;
880e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
881559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown        connection = openConnectionLocked(mConfiguration,
882559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                false /*primaryConnection*/); // might throw
883e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        finishAcquireConnectionLocked(connection, connectionFlags); // might throw
884e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return connection;
885e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
886e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
887e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Might throw.
888e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private void finishAcquireConnectionLocked(SQLiteConnection connection, int connectionFlags) {
889e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        try {
890e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            final boolean readOnly = (connectionFlags & CONNECTION_FLAG_READ_ONLY) != 0;
891e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            connection.setOnlyAllowReadOnlyOperations(readOnly);
892e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
893559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown            mAcquiredConnections.put(connection, AcquiredConnectionStatus.NORMAL);
894e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } catch (RuntimeException ex) {
895e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            Log.e(TAG, "Failed to prepare acquired connection for session, closing it: "
896e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    + connection +", connectionFlags=" + connectionFlags);
897e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            closeConnectionAndLogExceptionsLocked(connection);
898e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw ex; // rethrow!
899e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
900e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
901e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
902e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private boolean isSessionBlockingImportantConnectionWaitersLocked(
903e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            boolean holdingPrimaryConnection, int connectionFlags) {
904e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        ConnectionWaiter waiter = mConnectionWaiterQueue;
905e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (waiter != null) {
906e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            final int priority = getPriority(connectionFlags);
907e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            do {
908e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                // Only worry about blocked connections that have same or lower priority.
909e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                if (priority > waiter.mPriority) {
910e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    break;
911e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
912e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
913e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                // If we are holding the primary connection then we are blocking the waiter.
914e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                // Likewise, if we are holding a non-primary connection and the waiter
915e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                // would accept a non-primary connection, then we are blocking the waier.
916e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                if (holdingPrimaryConnection || !waiter.mWantPrimaryConnection) {
917e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    return true;
918e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
919e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
920e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                waiter = waiter.mNext;
921e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } while (waiter != null);
922e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
923e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return false;
924e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
925e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
926e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private static int getPriority(int connectionFlags) {
927e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return (connectionFlags & CONNECTION_FLAG_INTERACTIVE) != 0 ? 1 : 0;
928e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
929e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
930e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private void throwIfClosedLocked() {
931e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (!mIsOpen) {
932e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw new IllegalStateException("Cannot perform this operation "
933559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                    + "because the connection pool has been closed.");
934e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
935e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
936e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
937e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private ConnectionWaiter obtainConnectionWaiterLocked(Thread thread, long startTime,
938e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            int priority, boolean wantPrimaryConnection, String sql, int connectionFlags) {
939e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        ConnectionWaiter waiter = mConnectionWaiterPool;
940e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (waiter != null) {
941e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            mConnectionWaiterPool = waiter.mNext;
942e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            waiter.mNext = null;
943e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } else {
944e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            waiter = new ConnectionWaiter();
945e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
946e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        waiter.mThread = thread;
947e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        waiter.mStartTime = startTime;
948e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        waiter.mPriority = priority;
949e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        waiter.mWantPrimaryConnection = wantPrimaryConnection;
950e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        waiter.mSql = sql;
951e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        waiter.mConnectionFlags = connectionFlags;
952e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return waiter;
953e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
954e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
955e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private void recycleConnectionWaiterLocked(ConnectionWaiter waiter) {
956e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        waiter.mNext = mConnectionWaiterPool;
957e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        waiter.mThread = null;
958e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        waiter.mSql = null;
959e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        waiter.mAssignedConnection = null;
960e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        waiter.mException = null;
96175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        waiter.mNonce += 1;
962e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        mConnectionWaiterPool = waiter;
963e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
964e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
965e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
966e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Dumps debugging information about this connection pool.
967e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
968e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param printer The printer to receive the dump, not null.
969a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown     * @param verbose True to dump more verbose information.
970e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
971a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown    public void dump(Printer printer, boolean verbose) {
972e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        Printer indentedPrinter = PrefixPrinter.create(printer, "    ");
973e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        synchronized (mLock) {
974e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            printer.println("Connection pool for " + mConfiguration.path + ":");
975e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            printer.println("  Open: " + mIsOpen);
976e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            printer.println("  Max connections: " + mConfiguration.maxConnectionPoolSize);
977e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
978e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            printer.println("  Available primary connection:");
979e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (mAvailablePrimaryConnection != null) {
980a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown                mAvailablePrimaryConnection.dump(indentedPrinter, verbose);
981e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } else {
982e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                indentedPrinter.println("<none>");
983e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
984e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
985e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            printer.println("  Available non-primary connections:");
986e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (!mAvailableNonPrimaryConnections.isEmpty()) {
987e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                final int count = mAvailableNonPrimaryConnections.size();
988e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                for (int i = 0; i < count; i++) {
989a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown                    mAvailableNonPrimaryConnections.get(i).dump(indentedPrinter, verbose);
990e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
991e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } else {
992e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                indentedPrinter.println("<none>");
993e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
994e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
995e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            printer.println("  Acquired connections:");
996e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (!mAcquiredConnections.isEmpty()) {
997559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                for (Map.Entry<SQLiteConnection, AcquiredConnectionStatus> entry :
998e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        mAcquiredConnections.entrySet()) {
999e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    final SQLiteConnection connection = entry.getKey();
1000a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown                    connection.dumpUnsafe(indentedPrinter, verbose);
1001559d0645ac8f80491671fa5d3c63e8f296f2909eJeff Brown                    indentedPrinter.println("  Status: " + entry.getValue());
1002e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
1003e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } else {
1004e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                indentedPrinter.println("<none>");
1005e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
1006e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
1007e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            printer.println("  Connection waiters:");
1008e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (mConnectionWaiterQueue != null) {
1009e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                int i = 0;
1010e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                final long now = SystemClock.uptimeMillis();
1011e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                for (ConnectionWaiter waiter = mConnectionWaiterQueue; waiter != null;
1012e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        waiter = waiter.mNext, i++) {
1013e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    indentedPrinter.println(i + ": waited for "
1014e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                            + ((now - waiter.mStartTime) * 0.001f)
1015e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                            + " ms - thread=" + waiter.mThread
1016e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                            + ", priority=" + waiter.mPriority
1017e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                            + ", sql='" + waiter.mSql + "'");
1018e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
1019e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } else {
1020e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                indentedPrinter.println("<none>");
1021e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
1022e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
1023e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
1024e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
1025e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    @Override
1026e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    public String toString() {
1027e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return "SQLiteConnectionPool: " + mConfiguration.path;
1028e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
1029e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
1030e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private static final class ConnectionWaiter {
1031e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        public ConnectionWaiter mNext;
1032e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        public Thread mThread;
1033e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        public long mStartTime;
1034e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        public int mPriority;
1035e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        public boolean mWantPrimaryConnection;
1036e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        public String mSql;
1037e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        public int mConnectionFlags;
1038e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        public SQLiteConnection mAssignedConnection;
1039e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        public RuntimeException mException;
104075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        public int mNonce;
1041e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
1042e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
1043