Java Code Examples for android.os.CancellationSignal#throwIfCanceled()

The following examples show how to use android.os.CancellationSignal#throwIfCanceled() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: ContentProviderClient.java    From android_9.0.0_r45 with Apache License 2.0 6 votes vote down vote up
/** See {@link ContentProvider#refresh} */
public boolean refresh(Uri url, @Nullable Bundle args,
        @Nullable CancellationSignal cancellationSignal) throws RemoteException {
    Preconditions.checkNotNull(url, "url");

    beforeRemote();
    try {
        ICancellationSignal remoteCancellationSignal = null;
        if (cancellationSignal != null) {
            cancellationSignal.throwIfCanceled();
            remoteCancellationSignal = mContentProvider.createCancellationSignal();
            cancellationSignal.setRemote(remoteCancellationSignal);
        }
        return mContentProvider.refresh(mPackageName, url, args, remoteCancellationSignal);
    } catch (DeadObjectException e) {
        if (!mStable) {
            mContentResolver.unstableProviderDied(mContentProvider);
        }
        throw e;
    } finally {
        afterRemote();
    }
}
 
Example 2
Source File: SQLiteSession.java    From squidb with Apache License 2.0 6 votes vote down vote up
/**
 * Performs special reinterpretation of certain SQL statements such as "BEGIN",
 * "COMMIT" and "ROLLBACK" to ensure that transaction state invariants are
 * maintained.
 *
 * This function is mainly used to support legacy apps that perform their
 * own transactions by executing raw SQL rather than calling {@link #beginTransaction}
 * and the like.
 *
 * @param sql The SQL statement to execute.
 * @param bindArgs The arguments to bind, or null if none.
 * @param connectionFlags The connection flags to use if a connection must be
 * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
 * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
 * @return True if the statement was of a special form that was handled here,
 * false otherwise.
 *
 * @throws SQLiteException if an error occurs, such as a syntax error
 * or invalid number of bind arguments.
 * @throws OperationCanceledException if the operation was canceled.
 */
private boolean executeSpecial(String sql, Object[] bindArgs, int connectionFlags,
        CancellationSignal cancellationSignal) {
    if (cancellationSignal != null) {
        cancellationSignal.throwIfCanceled();
    }

    final int type = DatabaseUtils.getSqlStatementType(sql);
    switch (type) {
        case DatabaseUtils.STATEMENT_BEGIN:
            beginTransaction(TRANSACTION_MODE_EXCLUSIVE, null, connectionFlags,
                    cancellationSignal);
            return true;

        case DatabaseUtils.STATEMENT_COMMIT:
            setTransactionSuccessful();
            endTransaction(cancellationSignal);
            return true;

        case DatabaseUtils.STATEMENT_ABORT:
            endTransaction(cancellationSignal);
            return true;
    }
    return false;
}
 
Example 3
Source File: ContentProviderClient.java    From android_9.0.0_r45 with Apache License 2.0 6 votes vote down vote up
/** See {@link ContentProvider#openTypedAssetFile ContentProvider.openTypedAssetFile} */
public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri,
        @NonNull String mimeType, @Nullable Bundle opts, @Nullable CancellationSignal signal)
                throws RemoteException, FileNotFoundException {
    Preconditions.checkNotNull(uri, "uri");
    Preconditions.checkNotNull(mimeType, "mimeType");

    beforeRemote();
    try {
        ICancellationSignal remoteSignal = null;
        if (signal != null) {
            signal.throwIfCanceled();
            remoteSignal = mContentProvider.createCancellationSignal();
            signal.setRemote(remoteSignal);
        }
        return mContentProvider.openTypedAssetFile(
                mPackageName, uri, mimeType, opts, remoteSignal);
    } catch (DeadObjectException e) {
        if (!mStable) {
            mContentResolver.unstableProviderDied(mContentProvider);
        }
        throw e;
    } finally {
        afterRemote();
    }
}
 
Example 4
Source File: ContentProviderClient.java    From android_9.0.0_r45 with Apache License 2.0 6 votes vote down vote up
/**
 * See {@link ContentProvider#openAssetFile ContentProvider.openAssetFile}.
 * Note that this <em>does not</em>
 * take care of non-content: URIs such as file:.  It is strongly recommended
 * you use the {@link ContentResolver#openAssetFileDescriptor
 * ContentResolver.openAssetFileDescriptor} API instead.
 */
public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri url, @NonNull String mode,
        @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
    Preconditions.checkNotNull(url, "url");
    Preconditions.checkNotNull(mode, "mode");

    beforeRemote();
    try {
        ICancellationSignal remoteSignal = null;
        if (signal != null) {
            signal.throwIfCanceled();
            remoteSignal = mContentProvider.createCancellationSignal();
            signal.setRemote(remoteSignal);
        }
        return mContentProvider.openAssetFile(mPackageName, url, mode, remoteSignal);
    } catch (DeadObjectException e) {
        if (!mStable) {
            mContentResolver.unstableProviderDied(mContentProvider);
        }
        throw e;
    } finally {
        afterRemote();
    }
}
 
Example 5
Source File: ContentProviderClient.java    From android_9.0.0_r45 with Apache License 2.0 6 votes vote down vote up
/**
 * See {@link ContentProvider#openFile ContentProvider.openFile}.  Note that
 * this <em>does not</em>
 * take care of non-content: URIs such as file:.  It is strongly recommended
 * you use the {@link ContentResolver#openFileDescriptor
 * ContentResolver.openFileDescriptor} API instead.
 */
public @Nullable ParcelFileDescriptor openFile(@NonNull Uri url, @NonNull String mode,
        @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
    Preconditions.checkNotNull(url, "url");
    Preconditions.checkNotNull(mode, "mode");

    beforeRemote();
    try {
        ICancellationSignal remoteSignal = null;
        if (signal != null) {
            signal.throwIfCanceled();
            remoteSignal = mContentProvider.createCancellationSignal();
            signal.setRemote(remoteSignal);
        }
        return mContentProvider.openFile(mPackageName, url, mode, remoteSignal, null);
    } catch (DeadObjectException e) {
        if (!mStable) {
            mContentResolver.unstableProviderDied(mContentProvider);
        }
        throw e;
    } finally {
        afterRemote();
    }
}
 
Example 6
Source File: ContentResolver.java    From AndroidComponentPlugin with Apache License 2.0 6 votes vote down vote up
/**
 * This allows clients to request an explicit refresh of content identified by {@code uri}.
 * <p>
 * Client code should only invoke this method when there is a strong indication (such as a user
 * initiated pull to refresh gesture) that the content is stale.
 * <p>
 *
 * @param url The Uri identifying the data to refresh.
 * @param args Additional options from the client. The definitions of these are specific to the
 *            content provider being called.
 * @param cancellationSignal A signal to cancel the operation in progress, or {@code null} if
 *            none. For example, if you called refresh on a particular uri, you should call
 *            {@link CancellationSignal#throwIfCanceled()} to check whether the client has
 *            canceled the refresh request.
 * @return true if the provider actually tried refreshing.
 */
public final boolean refresh(@NonNull Uri url, @Nullable Bundle args,
        @Nullable CancellationSignal cancellationSignal) {
    Preconditions.checkNotNull(url, "url");
    IContentProvider provider = acquireProvider(url);
    if (provider == null) {
        return false;
    }

    try {
        ICancellationSignal remoteCancellationSignal = null;
        if (cancellationSignal != null) {
            cancellationSignal.throwIfCanceled();
            remoteCancellationSignal = provider.createCancellationSignal();
            cancellationSignal.setRemote(remoteCancellationSignal);
        }
        return provider.refresh(mPackageName, url, args, remoteCancellationSignal);
    } catch (RemoteException e) {
        // Arbitrary and not worth documenting, as Activity
        // Manager will kill this process shortly anyway.
        return false;
    } finally {
        releaseProvider(provider);
    }
}
 
Example 7
Source File: ContentResolver.java    From android_9.0.0_r45 with Apache License 2.0 6 votes vote down vote up
/**
 * This allows clients to request an explicit refresh of content identified by {@code uri}.
 * <p>
 * Client code should only invoke this method when there is a strong indication (such as a user
 * initiated pull to refresh gesture) that the content is stale.
 * <p>
 *
 * @param url The Uri identifying the data to refresh.
 * @param args Additional options from the client. The definitions of these are specific to the
 *            content provider being called.
 * @param cancellationSignal A signal to cancel the operation in progress, or {@code null} if
 *            none. For example, if you called refresh on a particular uri, you should call
 *            {@link CancellationSignal#throwIfCanceled()} to check whether the client has
 *            canceled the refresh request.
 * @return true if the provider actually tried refreshing.
 */
public final boolean refresh(@NonNull Uri url, @Nullable Bundle args,
        @Nullable CancellationSignal cancellationSignal) {
    Preconditions.checkNotNull(url, "url");
    IContentProvider provider = acquireProvider(url);
    if (provider == null) {
        return false;
    }

    try {
        ICancellationSignal remoteCancellationSignal = null;
        if (cancellationSignal != null) {
            cancellationSignal.throwIfCanceled();
            remoteCancellationSignal = provider.createCancellationSignal();
            cancellationSignal.setRemote(remoteCancellationSignal);
        }
        return provider.refresh(mPackageName, url, args, remoteCancellationSignal);
    } catch (RemoteException e) {
        // Arbitrary and not worth documenting, as Activity
        // Manager will kill this process shortly anyway.
        return false;
    } finally {
        releaseProvider(provider);
    }
}
 
Example 8
Source File: SQLiteSession.java    From android_9.0.0_r45 with Apache License 2.0 6 votes vote down vote up
/**
 * Performs special reinterpretation of certain SQL statements such as "BEGIN",
 * "COMMIT" and "ROLLBACK" to ensure that transaction state invariants are
 * maintained.
 *
 * This function is mainly used to support legacy apps that perform their
 * own transactions by executing raw SQL rather than calling {@link #beginTransaction}
 * and the like.
 *
 * @param sql The SQL statement to execute.
 * @param bindArgs The arguments to bind, or null if none.
 * @param connectionFlags The connection flags to use if a connection must be
 * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
 * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
 * @return True if the statement was of a special form that was handled here,
 * false otherwise.
 *
 * @throws SQLiteException if an error occurs, such as a syntax error
 * or invalid number of bind arguments.
 * @throws OperationCanceledException if the operation was canceled.
 */
private boolean executeSpecial(String sql, Object[] bindArgs, int connectionFlags,
        CancellationSignal cancellationSignal) {
    if (cancellationSignal != null) {
        cancellationSignal.throwIfCanceled();
    }

    final int type = DatabaseUtils.getSqlStatementType(sql);
    switch (type) {
        case DatabaseUtils.STATEMENT_BEGIN:
            beginTransaction(TRANSACTION_MODE_EXCLUSIVE, null, connectionFlags,
                    cancellationSignal);
            return true;

        case DatabaseUtils.STATEMENT_COMMIT:
            setTransactionSuccessful();
            endTransaction(cancellationSignal);
            return true;

        case DatabaseUtils.STATEMENT_ABORT:
            endTransaction(cancellationSignal);
            return true;
    }
    return false;
}
 
Example 9
Source File: ContentProviderClient.java    From android_9.0.0_r45 with Apache License 2.0 5 votes vote down vote up
/** See {@link ContentProvider#query ContentProvider.query} */
public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
        Bundle queryArgs, @Nullable CancellationSignal cancellationSignal)
                throws RemoteException {
    Preconditions.checkNotNull(uri, "url");

    beforeRemote();
    try {
        ICancellationSignal remoteCancellationSignal = null;
        if (cancellationSignal != null) {
            cancellationSignal.throwIfCanceled();
            remoteCancellationSignal = mContentProvider.createCancellationSignal();
            cancellationSignal.setRemote(remoteCancellationSignal);
        }
        final Cursor cursor = mContentProvider.query(
                mPackageName, uri, projection, queryArgs, remoteCancellationSignal);
        if (cursor == null) {
            return null;
        }
        return new CursorWrapperInner(cursor);
    } catch (DeadObjectException e) {
        if (!mStable) {
            mContentResolver.unstableProviderDied(mContentProvider);
        }
        throw e;
    } finally {
        afterRemote();
    }
}
 
Example 10
Source File: SQLiteSession.java    From android_9.0.0_r45 with Apache License 2.0 5 votes vote down vote up
private boolean yieldTransactionUnchecked(long sleepAfterYieldDelayMillis,
        CancellationSignal cancellationSignal) {
    if (cancellationSignal != null) {
        cancellationSignal.throwIfCanceled();
    }

    if (!mConnectionPool.shouldYieldConnection(mConnection, mConnectionFlags)) {
        return false;
    }

    final int transactionMode = mTransactionStack.mMode;
    final SQLiteTransactionListener listener = mTransactionStack.mListener;
    final int connectionFlags = mConnectionFlags;
    endTransactionUnchecked(cancellationSignal, true); // might throw

    if (sleepAfterYieldDelayMillis > 0) {
        try {
            Thread.sleep(sleepAfterYieldDelayMillis);
        } catch (InterruptedException ex) {
            // we have been interrupted, that's all we need to do
        }
    }

    beginTransactionUnchecked(transactionMode, listener, connectionFlags,
            cancellationSignal); // might throw
    return true;
}
 
Example 11
Source File: SQLiteConnection.java    From squidb with Apache License 2.0 5 votes vote down vote up
private void attachCancellationSignal(CancellationSignal cancellationSignal) {
    if (cancellationSignal != null) {
        cancellationSignal.throwIfCanceled();

        mCancellationSignalAttachCount += 1;
        if (mCancellationSignalAttachCount == 1) {
            // Reset cancellation flag before executing the statement.
            nativeResetCancel(mConnectionPtr, true /*cancelable*/);

            // After this point, onCancel() may be called concurrently.
            cancellationSignal.setOnCancelListener(this);
        }
    }
}
 
Example 12
Source File: SQLiteSession.java    From squidb with Apache License 2.0 5 votes vote down vote up
private boolean yieldTransactionUnchecked(long sleepAfterYieldDelayMillis,
        CancellationSignal cancellationSignal) {
    if (cancellationSignal != null) {
        cancellationSignal.throwIfCanceled();
    }

    if (!mConnectionPool.shouldYieldConnection(mConnection, mConnectionFlags)) {
        return false;
    }

    final int transactionMode = mTransactionStack.mMode;
    final SQLiteTransactionListener listener = mTransactionStack.mListener;
    final int connectionFlags = mConnectionFlags;
    endTransactionUnchecked(cancellationSignal, true); // might throw

    if (sleepAfterYieldDelayMillis > 0) {
        try {
            Thread.sleep(sleepAfterYieldDelayMillis);
        } catch (InterruptedException ex) {
            // we have been interrupted, that's all we need to do
        }
    }

    beginTransactionUnchecked(transactionMode, listener, connectionFlags,
            cancellationSignal); // might throw
    return true;
}
 
Example 13
Source File: SQLiteConnection.java    From android_9.0.0_r45 with Apache License 2.0 5 votes vote down vote up
private void attachCancellationSignal(CancellationSignal cancellationSignal) {
    if (cancellationSignal != null) {
        cancellationSignal.throwIfCanceled();

        mCancellationSignalAttachCount += 1;
        if (mCancellationSignalAttachCount == 1) {
            // Reset cancellation flag before executing the statement.
            nativeResetCancel(mConnectionPtr, true /*cancelable*/);

            // After this point, onCancel() may be called concurrently.
            cancellationSignal.setOnCancelListener(this);
        }
    }
}
 
Example 14
Source File: SQLiteSession.java    From android_9.0.0_r45 with Apache License 2.0 4 votes vote down vote up
/**
 * Prepares a statement for execution but does not bind its parameters or execute it.
 * <p>
 * This method can be used to check for syntax errors during compilation
 * prior to execution of the statement.  If the {@code outStatementInfo} argument
 * is not null, the provided {@link SQLiteStatementInfo} object is populated
 * with information about the statement.
 * </p><p>
 * A prepared statement makes no reference to the arguments that may eventually
 * be bound to it, consequently it it possible to cache certain prepared statements
 * such as SELECT or INSERT/UPDATE statements.  If the statement is cacheable,
 * then it will be stored in the cache for later and reused if possible.
 * </p>
 *
 * @param sql The SQL statement to prepare.
 * @param connectionFlags The connection flags to use if a connection must be
 * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
 * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
 * @param outStatementInfo The {@link SQLiteStatementInfo} object to populate
 * with information about the statement, or null if none.
 *
 * @throws SQLiteException if an error occurs, such as a syntax error.
 * @throws OperationCanceledException if the operation was canceled.
 */
public void prepare(String sql, int connectionFlags, CancellationSignal cancellationSignal,
        SQLiteStatementInfo outStatementInfo) {
    if (sql == null) {
        throw new IllegalArgumentException("sql must not be null.");
    }

    if (cancellationSignal != null) {
        cancellationSignal.throwIfCanceled();
    }

    acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
    try {
        mConnection.prepare(sql, outStatementInfo); // might throw
    } finally {
        releaseConnection(); // might throw
    }
}
 
Example 15
Source File: SQLiteSession.java    From android_9.0.0_r45 with Apache License 2.0 4 votes vote down vote up
private void endTransactionUnchecked(CancellationSignal cancellationSignal, boolean yielding) {
    if (cancellationSignal != null) {
        cancellationSignal.throwIfCanceled();
    }

    final Transaction top = mTransactionStack;
    boolean successful = (top.mMarkedSuccessful || yielding) && !top.mChildFailed;

    RuntimeException listenerException = null;
    final SQLiteTransactionListener listener = top.mListener;
    if (listener != null) {
        try {
            if (successful) {
                listener.onCommit(); // might throw
            } else {
                listener.onRollback(); // might throw
            }
        } catch (RuntimeException ex) {
            listenerException = ex;
            successful = false;
        }
    }

    mTransactionStack = top.mParent;
    recycleTransaction(top);

    if (mTransactionStack != null) {
        if (!successful) {
            mTransactionStack.mChildFailed = true;
        }
    } else {
        try {
            if (successful) {
                mConnection.execute("COMMIT;", null, cancellationSignal); // might throw
            } else {
                mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
            }
        } finally {
            releaseConnection(); // might throw
        }
    }

    if (listenerException != null) {
        throw listenerException;
    }
}
 
Example 16
Source File: SQLiteSession.java    From android_9.0.0_r45 with Apache License 2.0 4 votes vote down vote up
private void beginTransactionUnchecked(int transactionMode,
        SQLiteTransactionListener transactionListener, int connectionFlags,
        CancellationSignal cancellationSignal) {
    if (cancellationSignal != null) {
        cancellationSignal.throwIfCanceled();
    }

    if (mTransactionStack == null) {
        acquireConnection(null, connectionFlags, cancellationSignal); // might throw
    }
    try {
        // Set up the transaction such that we can back out safely
        // in case we fail part way.
        if (mTransactionStack == null) {
            // Execute SQL might throw a runtime exception.
            switch (transactionMode) {
                case TRANSACTION_MODE_IMMEDIATE:
                    mConnection.execute("BEGIN IMMEDIATE;", null,
                            cancellationSignal); // might throw
                    break;
                case TRANSACTION_MODE_EXCLUSIVE:
                    mConnection.execute("BEGIN EXCLUSIVE;", null,
                            cancellationSignal); // might throw
                    break;
                default:
                    mConnection.execute("BEGIN;", null, cancellationSignal); // might throw
                    break;
            }
        }

        // Listener might throw a runtime exception.
        if (transactionListener != null) {
            try {
                transactionListener.onBegin(); // might throw
            } catch (RuntimeException ex) {
                if (mTransactionStack == null) {
                    mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
                }
                throw ex;
            }
        }

        // Bookkeeping can't throw, except an OOM, which is just too bad...
        Transaction transaction = obtainTransaction(transactionMode, transactionListener);
        transaction.mParent = mTransactionStack;
        mTransactionStack = transaction;
    } finally {
        if (mTransactionStack == null) {
            releaseConnection(); // might throw
        }
    }
}
 
Example 17
Source File: SQLiteSession.java    From squidb with Apache License 2.0 4 votes vote down vote up
private void beginTransactionUnchecked(int transactionMode,
        SQLiteTransactionListener transactionListener, int connectionFlags,
        CancellationSignal cancellationSignal) {
    if (cancellationSignal != null) {
        cancellationSignal.throwIfCanceled();
    }

    if (mTransactionStack == null) {
        acquireConnection(null, connectionFlags, cancellationSignal); // might throw
    }
    try {
        // Set up the transaction such that we can back out safely
        // in case we fail part way.
        if (mTransactionStack == null) {
            // Execute SQL might throw a runtime exception.
            switch (transactionMode) {
                case TRANSACTION_MODE_IMMEDIATE:
                    mConnection.execute("BEGIN IMMEDIATE;", null,
                            cancellationSignal); // might throw
                    break;
                case TRANSACTION_MODE_EXCLUSIVE:
                    mConnection.execute("BEGIN EXCLUSIVE;", null,
                            cancellationSignal); // might throw
                    break;
                default:
                    mConnection.execute("BEGIN;", null, cancellationSignal); // might throw
                    break;
            }
        }

        // Listener might throw a runtime exception.
        if (transactionListener != null) {
            try {
                transactionListener.onBegin(); // might throw
            } catch (RuntimeException ex) {
                if (mTransactionStack == null) {
                    mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
                }
                throw ex;
            }
        }

        // Bookkeeping can't throw, except an OOM, which is just too bad...
        Transaction transaction = obtainTransaction(transactionMode, transactionListener);
        transaction.mParent = mTransactionStack;
        mTransactionStack = transaction;
    } finally {
        if (mTransactionStack == null) {
            releaseConnection(); // might throw
        }
    }
}
 
Example 18
Source File: SQLiteSession.java    From squidb with Apache License 2.0 4 votes vote down vote up
private void endTransactionUnchecked(CancellationSignal cancellationSignal, boolean yielding) {
    if (cancellationSignal != null) {
        cancellationSignal.throwIfCanceled();
    }

    final Transaction top = mTransactionStack;
    boolean successful = (top.mMarkedSuccessful || yielding) && !top.mChildFailed;

    RuntimeException listenerException = null;
    final SQLiteTransactionListener listener = top.mListener;
    if (listener != null) {
        try {
            if (successful) {
                listener.onCommit(); // might throw
            } else {
                listener.onRollback(); // might throw
            }
        } catch (RuntimeException ex) {
            listenerException = ex;
            successful = false;
        }
    }

    mTransactionStack = top.mParent;
    recycleTransaction(top);

    if (mTransactionStack != null) {
        if (!successful) {
            mTransactionStack.mChildFailed = true;
        }
    } else {
        try {
            if (successful) {
                mConnection.execute("COMMIT;", null, cancellationSignal); // might throw
            } else {
                mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
            }
        } finally {
            releaseConnection(); // might throw
        }
    }

    if (listenerException != null) {
        throw listenerException;
    }
}
 
Example 19
Source File: SQLiteSession.java    From squidb with Apache License 2.0 4 votes vote down vote up
/**
 * Prepares a statement for execution but does not bind its parameters or execute it.
 * <p>
 * This method can be used to check for syntax errors during compilation
 * prior to execution of the statement.  If the {@code outStatementInfo} argument
 * is not null, the provided {@link SQLiteStatementInfo} object is populated
 * with information about the statement.
 * </p><p>
 * A prepared statement makes no reference to the arguments that may eventually
 * be bound to it, consequently it it possible to cache certain prepared statements
 * such as SELECT or INSERT/UPDATE statements.  If the statement is cacheable,
 * then it will be stored in the cache for later and reused if possible.
 * </p>
 *
 * @param sql The SQL statement to prepare.
 * @param connectionFlags The connection flags to use if a connection must be
 * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
 * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
 * @param outStatementInfo The {@link SQLiteStatementInfo} object to populate
 * with information about the statement, or null if none.
 *
 * @throws SQLiteException if an error occurs, such as a syntax error.
 * @throws OperationCanceledException if the operation was canceled.
 */
public void prepare(String sql, int connectionFlags, CancellationSignal cancellationSignal,
        SQLiteStatementInfo outStatementInfo) {
    if (sql == null) {
        throw new IllegalArgumentException("sql must not be null.");
    }

    if (cancellationSignal != null) {
        cancellationSignal.throwIfCanceled();
    }

    acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
    try {
        mConnection.prepare(sql, outStatementInfo); // might throw
    } finally {
        releaseConnection(); // might throw
    }
}