Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c21b5a01 authored by Jeff Brown's avatar Jeff Brown
Browse files

Fix cursor window leak when query execution fails.

Ensure that the Cursor object is closed if a query on a
content provider fails due to an error or is canceled during
execution.  There are several places in the code where
similar problems can occur.

To further reduce the likelihood of leaks, close the cursor
window immediately when a query fails.

Bug: 7278577
Change-Id: I8c686c259de80a162b9086628a817d57f09fdd13
parent f6f00b14
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -78,7 +78,7 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
                    // So we treat this case as an unhandled exception.
                    throw ex;
                }
                if (DEBUG) Slog.v(TAG, this + "  <<< doInBackground (was canceled)");
                if (DEBUG) Slog.v(TAG, this + "  <<< doInBackground (was canceled)", ex);
                return null;
            }
        }
+15 −7
Original line number Diff line number Diff line
@@ -113,13 +113,21 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                    Cursor cursor = query(url, projection, selection, selectionArgs, sortOrder,
                            cancellationSignal);
                    if (cursor != null) {
                        try {
                            CursorToBulkCursorAdaptor adaptor = new CursorToBulkCursorAdaptor(
                                    cursor, observer, getProviderName());
                            BulkCursorDescriptor d = adaptor.getBulkCursorDescriptor();
                            cursor = null;

                            reply.writeNoException();
                            reply.writeInt(1);
                            d.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                        } finally {
                            // Close cursor if an exception was thrown while constructing the adaptor.
                            if (cursor != null) {
                                cursor.close();
                            }
                        }
                    } else {
                        reply.writeNoException();
                        reply.writeInt(0);
+9 −3
Original line number Diff line number Diff line
@@ -381,6 +381,7 @@ public abstract class ContentResolver {
            return null;
        }
        IContentProvider stableProvider = null;
        Cursor qCursor = null;
        try {
            long startTime = SystemClock.uptimeMillis();

@@ -390,7 +391,6 @@ public abstract class ContentResolver {
                remoteCancellationSignal = unstableProvider.createCancellationSignal();
                cancellationSignal.setRemote(remoteCancellationSignal);
            }
            Cursor qCursor;
            try {
                qCursor = unstableProvider.query(uri, projection,
                        selection, selectionArgs, sortOrder, remoteCancellationSignal);
@@ -409,20 +409,26 @@ public abstract class ContentResolver {
            if (qCursor == null) {
                return null;
            }
            // force query execution

            // Force query execution.  Might fail and throw a runtime exception here.
            qCursor.getCount();
            long durationMillis = SystemClock.uptimeMillis() - startTime;
            maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);
            // Wrap the cursor object into CursorWrapperInner object

            // Wrap the cursor object into CursorWrapperInner object.
            CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
                    stableProvider != null ? stableProvider : acquireProvider(uri));
            stableProvider = null;
            qCursor = null;
            return wrapper;
        } catch (RemoteException e) {
            // Arbitrary and not worth documenting, as Activity
            // Manager will kill this process shortly anyway.
            return null;
        } finally {
            if (qCursor != null) {
                qCursor.close();
            }
            if (unstableProvider != null) {
                releaseUnstableProvider(unstableProvider);
            }
+8 −3
Original line number Diff line number Diff line
@@ -65,9 +65,14 @@ public class CursorLoader extends AsyncTaskLoader<Cursor> {
            Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
                    mSelectionArgs, mSortOrder, mCancellationSignal);
            if (cursor != null) {
                // Ensure the cursor window is filled
                try {
                    // Ensure the cursor window is filled.
                    cursor.getCount();
                    registerContentObserver(cursor, mObserver);
                } catch (RuntimeException ex) {
                    cursor.close();
                    throw ex;
                }
            }
            return cursor;
        } finally {
+5 −0
Original line number Diff line number Diff line
@@ -132,6 +132,11 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative
        }
    }

    /**
     * Returns an object that contains sufficient metadata to reconstruct
     * the cursor remotely.  May throw if an error occurs when executing the query
     * and obtaining the row count.
     */
    public BulkCursorDescriptor getBulkCursorDescriptor() {
        synchronized (mLock) {
            throwIfCursorIsClosed();
Loading