Loading core/java/android/content/CancellationSignal.java +61 −22 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ public final class CancellationSignal { private boolean mIsCanceled; private OnCancelListener mOnCancelListener; private ICancellationSignal mRemote; private boolean mCancelInProgress; /** * Creates a cancellation signal, initially not canceled. Loading Loading @@ -59,18 +60,32 @@ public final class CancellationSignal { * If the operation has not yet started, then it will be canceled as soon as it does. */ public void cancel() { final OnCancelListener listener; final ICancellationSignal remote; synchronized (this) { if (!mIsCanceled) { if (mIsCanceled) { return; } mIsCanceled = true; if (mOnCancelListener != null) { mOnCancelListener.onCancel(); mCancelInProgress = true; listener = mOnCancelListener; remote = mRemote; } try { if (listener != null) { listener.onCancel(); } if (mRemote != null) { if (remote != null) { try { mRemote.cancel(); remote.cancel(); } catch (RemoteException ex) { } } } finally { synchronized (this) { mCancelInProgress = false; notifyAll(); } } } Loading @@ -86,39 +101,63 @@ public final class CancellationSignal { * If {@link CancellationSignal#cancel} has already been called, then the provided * listener is invoked immediately. * * The listener is called while holding the cancellation signal's lock which is * also held while registering or unregistering the listener. Because of the lock, * it is not possible for the listener to run after it has been unregistered. * This design choice makes it easier for clients of {@link CancellationSignal} to * prevent race conditions related to listener registration and unregistration. * This method is guaranteed that the listener will not be called after it * has been removed. * * @param listener The cancellation listener, or null to remove the current listener. */ public void setOnCancelListener(OnCancelListener listener) { synchronized (this) { waitForCancelFinishedLocked(); if (mOnCancelListener == listener) { return; } mOnCancelListener = listener; if (mIsCanceled && listener != null) { listener.onCancel(); if (!mIsCanceled || listener == null) { return; } } listener.onCancel(); } /** * Sets the remote transport. * * If {@link CancellationSignal#cancel} has already been called, then the provided * remote transport is canceled immediately. * * This method is guaranteed that the remote transport will not be called after it * has been removed. * * @param remote The remote transport, or null to remove. * * @hide */ public void setRemote(ICancellationSignal remote) { synchronized (this) { waitForCancelFinishedLocked(); if (mRemote == remote) { return; } mRemote = remote; if (mIsCanceled && remote != null) { if (!mIsCanceled || remote == null) { return; } } try { remote.cancel(); } catch (RemoteException ex) { } } private void waitForCancelFinishedLocked() { while (mCancelInProgress) { try { wait(); } catch (InterruptedException ex) { } } } Loading core/java/android/database/sqlite/SQLiteConnectionPool.java +55 −52 Original line number Diff line number Diff line Loading @@ -594,6 +594,7 @@ public final class SQLiteConnectionPool implements Closeable { (connectionFlags & CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY) != 0; final ConnectionWaiter waiter; final int nonce; synchronized (mLock) { throwIfClosedLocked(); Loading Loading @@ -636,19 +637,23 @@ public final class SQLiteConnectionPool implements Closeable { mConnectionWaiterQueue = waiter; } nonce = waiter.mNonce; } // Set up the cancellation listener. if (cancellationSignal != null) { final int nonce = waiter.mNonce; cancellationSignal.setOnCancelListener(new CancellationSignal.OnCancelListener() { @Override public void onCancel() { synchronized (mLock) { cancelConnectionWaiterLocked(waiter, nonce); if (waiter.mNonce == nonce) { cancelConnectionWaiterLocked(waiter); } } }); } }); } try { // Park the thread until a connection is assigned or the pool is closed. // Rethrow an exception from the wait, if we got one. long busyTimeoutMillis = CONNECTION_POOL_BUSY_MILLIS; Loading @@ -674,9 +679,6 @@ public final class SQLiteConnectionPool implements Closeable { final SQLiteConnection connection = waiter.mAssignedConnection; final RuntimeException ex = waiter.mException; if (connection != null || ex != null) { if (cancellationSignal != null) { cancellationSignal.setOnCancelListener(null); } recycleConnectionWaiterLocked(waiter); if (connection != null) { return connection; Loading @@ -694,15 +696,16 @@ public final class SQLiteConnectionPool implements Closeable { } } } } finally { // Remove the cancellation listener. if (cancellationSignal != null) { cancellationSignal.setOnCancelListener(null); } } // Can't throw. private void cancelConnectionWaiterLocked(ConnectionWaiter waiter, int nonce) { if (waiter.mNonce != nonce) { // Waiter already removed and recycled. return; } // Can't throw. private void cancelConnectionWaiterLocked(ConnectionWaiter waiter) { if (waiter.mAssignedConnection != null || waiter.mException != null) { // Waiter is done waiting but has not woken up yet. return; Loading Loading
core/java/android/content/CancellationSignal.java +61 −22 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ public final class CancellationSignal { private boolean mIsCanceled; private OnCancelListener mOnCancelListener; private ICancellationSignal mRemote; private boolean mCancelInProgress; /** * Creates a cancellation signal, initially not canceled. Loading Loading @@ -59,18 +60,32 @@ public final class CancellationSignal { * If the operation has not yet started, then it will be canceled as soon as it does. */ public void cancel() { final OnCancelListener listener; final ICancellationSignal remote; synchronized (this) { if (!mIsCanceled) { if (mIsCanceled) { return; } mIsCanceled = true; if (mOnCancelListener != null) { mOnCancelListener.onCancel(); mCancelInProgress = true; listener = mOnCancelListener; remote = mRemote; } try { if (listener != null) { listener.onCancel(); } if (mRemote != null) { if (remote != null) { try { mRemote.cancel(); remote.cancel(); } catch (RemoteException ex) { } } } finally { synchronized (this) { mCancelInProgress = false; notifyAll(); } } } Loading @@ -86,39 +101,63 @@ public final class CancellationSignal { * If {@link CancellationSignal#cancel} has already been called, then the provided * listener is invoked immediately. * * The listener is called while holding the cancellation signal's lock which is * also held while registering or unregistering the listener. Because of the lock, * it is not possible for the listener to run after it has been unregistered. * This design choice makes it easier for clients of {@link CancellationSignal} to * prevent race conditions related to listener registration and unregistration. * This method is guaranteed that the listener will not be called after it * has been removed. * * @param listener The cancellation listener, or null to remove the current listener. */ public void setOnCancelListener(OnCancelListener listener) { synchronized (this) { waitForCancelFinishedLocked(); if (mOnCancelListener == listener) { return; } mOnCancelListener = listener; if (mIsCanceled && listener != null) { listener.onCancel(); if (!mIsCanceled || listener == null) { return; } } listener.onCancel(); } /** * Sets the remote transport. * * If {@link CancellationSignal#cancel} has already been called, then the provided * remote transport is canceled immediately. * * This method is guaranteed that the remote transport will not be called after it * has been removed. * * @param remote The remote transport, or null to remove. * * @hide */ public void setRemote(ICancellationSignal remote) { synchronized (this) { waitForCancelFinishedLocked(); if (mRemote == remote) { return; } mRemote = remote; if (mIsCanceled && remote != null) { if (!mIsCanceled || remote == null) { return; } } try { remote.cancel(); } catch (RemoteException ex) { } } private void waitForCancelFinishedLocked() { while (mCancelInProgress) { try { wait(); } catch (InterruptedException ex) { } } } Loading
core/java/android/database/sqlite/SQLiteConnectionPool.java +55 −52 Original line number Diff line number Diff line Loading @@ -594,6 +594,7 @@ public final class SQLiteConnectionPool implements Closeable { (connectionFlags & CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY) != 0; final ConnectionWaiter waiter; final int nonce; synchronized (mLock) { throwIfClosedLocked(); Loading Loading @@ -636,19 +637,23 @@ public final class SQLiteConnectionPool implements Closeable { mConnectionWaiterQueue = waiter; } nonce = waiter.mNonce; } // Set up the cancellation listener. if (cancellationSignal != null) { final int nonce = waiter.mNonce; cancellationSignal.setOnCancelListener(new CancellationSignal.OnCancelListener() { @Override public void onCancel() { synchronized (mLock) { cancelConnectionWaiterLocked(waiter, nonce); if (waiter.mNonce == nonce) { cancelConnectionWaiterLocked(waiter); } } }); } }); } try { // Park the thread until a connection is assigned or the pool is closed. // Rethrow an exception from the wait, if we got one. long busyTimeoutMillis = CONNECTION_POOL_BUSY_MILLIS; Loading @@ -674,9 +679,6 @@ public final class SQLiteConnectionPool implements Closeable { final SQLiteConnection connection = waiter.mAssignedConnection; final RuntimeException ex = waiter.mException; if (connection != null || ex != null) { if (cancellationSignal != null) { cancellationSignal.setOnCancelListener(null); } recycleConnectionWaiterLocked(waiter); if (connection != null) { return connection; Loading @@ -694,15 +696,16 @@ public final class SQLiteConnectionPool implements Closeable { } } } } finally { // Remove the cancellation listener. if (cancellationSignal != null) { cancellationSignal.setOnCancelListener(null); } } // Can't throw. private void cancelConnectionWaiterLocked(ConnectionWaiter waiter, int nonce) { if (waiter.mNonce != nonce) { // Waiter already removed and recycled. return; } // Can't throw. private void cancelConnectionWaiterLocked(ConnectionWaiter waiter) { if (waiter.mAssignedConnection != null || waiter.mException != null) { // Waiter is done waiting but has not woken up yet. return; Loading