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

Commit 0cde89f5 authored by Jeff Brown's avatar Jeff Brown
Browse files

Use ashmem for CursorWindows.

Bug: 5332296

The memory dealer introduces additional delays for reclaiming
the memory owned by CursorWindows because the Binder object must
be finalized.  Using ashmem instead gives CursorWindow more
direct control over the lifetime of the shared memory region.

The provider now allocates the CursorWindows and returns them
to clients with a read-only protection bit set on the ashmem
region.

Improved the encapsulation of CursorWindow.  Callers shouldn't
need to care about details like how string fields are allocated.

Removed the compile-time configuration of string and numeric
storage modes to remove some dead weight.

Change-Id: I07c2bc2a9c573d7e435dcaecd269d25ea9807acd
parent 99f36683
Loading
Loading
Loading
Loading
+51 −59
Original line number Diff line number Diff line
@@ -108,21 +108,22 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                    String sortOrder = data.readString();
                    IContentObserver observer = IContentObserver.Stub.asInterface(
                            data.readStrongBinder());
                    CursorWindow window = CursorWindow.CREATOR.createFromParcel(data);

                    Cursor cursor = query(url, projection, selection, selectionArgs, sortOrder);
                    if (cursor != null) {
                        CursorToBulkCursorAdaptor adaptor = new CursorToBulkCursorAdaptor(
                                cursor, observer, getProviderName(), window);
                                cursor, observer, getProviderName());
                        final IBinder binder = adaptor.asBinder();
                        final int count = adaptor.count();
                        final int index = BulkCursorToCursorAdaptor.findRowIdColumnIndex(
                                adaptor.getColumnNames());
                        final boolean wantsAllOnMoveCalls = adaptor.getWantsAllOnMoveCalls();

                        reply.writeNoException();
                        reply.writeStrongBinder(binder);
                        reply.writeInt(count);
                        reply.writeInt(index);
                        reply.writeInt(wantsAllOnMoveCalls ? 1 : 0);
                    } else {
                        reply.writeNoException();
                        reply.writeStrongBinder(null);
@@ -324,8 +325,6 @@ final class ContentProviderProxy implements IContentProvider

    public Cursor query(Uri url, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) throws RemoteException {
        CursorWindow window = new CursorWindow(false /* window will be used remotely */);
        try {
        BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
@@ -353,7 +352,6 @@ final class ContentProviderProxy implements IContentProvider
            }
            data.writeString(sortOrder);
            data.writeStrongBinder(adaptor.getObserver().asBinder());
                window.writeToParcel(data, 0);

            mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);

@@ -363,7 +361,8 @@ final class ContentProviderProxy implements IContentProvider
            if (bulkCursor != null) {
                int rowCount = reply.readInt();
                int idColumnPosition = reply.readInt();
                    adaptor.initialize(bulkCursor, rowCount, idColumnPosition);
                boolean wantsAllOnMoveCalls = reply.readInt() != 0;
                adaptor.initialize(bulkCursor, rowCount, idColumnPosition, wantsAllOnMoveCalls);
            } else {
                adaptor.close();
                adaptor = null;
@@ -379,13 +378,6 @@ final class ContentProviderProxy implements IContentProvider
            data.recycle();
            reply.recycle();
        }
        } finally {
            // We close the window now because the cursor adaptor does not
            // take ownership of the window until the first call to onMove.
            // The adaptor will obtain a fresh reference to the window when
            // it is filled.
            window.close();
        }
    }

    public String getType(Uri url) throws RemoteException
+4 −2
Original line number Diff line number Diff line
@@ -189,12 +189,14 @@ public abstract class AbstractWindowedCursor extends AbstractCursor {
    /**
     * If there is a window, clear it.
     * Otherwise, creates a local window.
     *
     * @param name The window name.
     * @hide
     */
    protected void clearOrCreateLocalWindow() {
    protected void clearOrCreateLocalWindow(String name) {
        if (mWindow == null) {
            // If there isn't a window set already it will only be accessed locally
            mWindow = new CursorWindow(true /* the window is local only */);
            mWindow = new CursorWindow(name, true /* the window is local only */);
        } else {
            mWindow.clear();
        }
+3 −5
Original line number Diff line number Diff line
@@ -110,8 +110,7 @@ public abstract class BulkCursorNative extends Binder implements IBulkCursor
                    data.enforceInterface(IBulkCursor.descriptor);
                    IContentObserver observer =
                            IContentObserver.Stub.asInterface(data.readStrongBinder());
                    CursorWindow window = CursorWindow.CREATOR.createFromParcel(data);
                    int count = requery(observer, window);
                    int count = requery(observer);
                    reply.writeNoException();
                    reply.writeInt(count);
                    reply.writeBundle(getExtras());
@@ -294,13 +293,12 @@ final class BulkCursorProxy implements IBulkCursor {
        }
    }
    
    public int requery(IContentObserver observer, CursorWindow window) throws RemoteException {
    public int requery(IContentObserver observer) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        try {
            data.writeInterfaceToken(IBulkCursor.descriptor);
            data.writeStrongInterface(observer);
            window.writeToParcel(data, 0);

            boolean result = mRemote.transact(REQUERY_TRANSACTION, data, reply, 0);
            DatabaseUtils.readExceptionFromParcel(reply);
+21 −28
Original line number Diff line number Diff line
@@ -38,11 +38,13 @@ public final class BulkCursorToCursorAdaptor extends AbstractWindowedCursor {
     * Initializes the adaptor.
     * Must be called before first use.
     */
    public void initialize(IBulkCursor bulkCursor, int count, int idIndex) {
    public void initialize(IBulkCursor bulkCursor, int count, int idIndex,
            boolean wantsAllOnMoveCalls) {
        mBulkCursor = bulkCursor;
        mColumns = null;  // lazily retrieved
        mCount = count;
        mRowIdColumnIndex = idIndex;
        mWantsAllOnMoveCalls = wantsAllOnMoveCalls;
    }

    /**
@@ -86,16 +88,13 @@ public final class BulkCursorToCursorAdaptor extends AbstractWindowedCursor {

        try {
            // Make sure we have the proper window
            if (mWindow != null) {
                if (newPosition < mWindow.getStartPosition() ||
                        newPosition >= (mWindow.getStartPosition() + mWindow.getNumRows())) {
            if (mWindow == null
                    || newPosition < mWindow.getStartPosition()
                    || newPosition >= mWindow.getStartPosition() + mWindow.getNumRows()) {
                setWindow(mBulkCursor.getWindow(newPosition));
            } else if (mWantsAllOnMoveCalls) {
                mBulkCursor.onMove(newPosition);
            }
            } else {
                setWindow(mBulkCursor.getWindow(newPosition));
            }
        } catch (RemoteException ex) {
            // We tried to get a window and failed
            Log.e(TAG, "Unable to get window because the remote process is dead");
@@ -145,9 +144,7 @@ public final class BulkCursorToCursorAdaptor extends AbstractWindowedCursor {
        throwIfCursorIsClosed();

        try {
            CursorWindow newWindow = new CursorWindow(false /* create a remote window */);
            try {
                mCount = mBulkCursor.requery(getObserver(), newWindow);
            mCount = mBulkCursor.requery(getObserver());
            if (mCount != -1) {
                mPos = -1;
                closeWindow();
@@ -161,10 +158,6 @@ public final class BulkCursorToCursorAdaptor extends AbstractWindowedCursor {
                deactivate();
                return false;
            }
            } finally {
                // Don't take ownership of the window until the next call to onMove.
                newWindow.close();
            }
        } catch (Exception ex) {
            Log.e(TAG, "Unable to requery because the remote process exception " + ex.getMessage());
            deactivate();
+39 −46
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative
     * for managing the lifetime of their window.
     */
    private CursorWindow mWindowForNonWindowedCursor;
    private boolean mWindowForNonWindowedCursorWasFilled;

    private static final class ContentObserverProxy extends ContentObserver {
        protected IContentObserver mRemote;
@@ -87,26 +88,11 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative
        }
    }

    public CursorToBulkCursorAdaptor(Cursor cursor, IContentObserver observer, String providerName,
            CursorWindow window) {
    public CursorToBulkCursorAdaptor(Cursor cursor, IContentObserver observer,
            String providerName) {
        try {
            mCursor = (CrossProcessCursor) cursor;
            if (mCursor instanceof AbstractWindowedCursor) {
                AbstractWindowedCursor windowedCursor = (AbstractWindowedCursor) cursor;
                if (windowedCursor.hasWindow()) {
                    if (Log.isLoggable(TAG, Log.VERBOSE) || false) {
                        Log.v(TAG, "Cross process cursor has a local window before setWindow in "
                                + providerName, new RuntimeException());
                    }
                }
                windowedCursor.setWindow(window); // cursor takes ownership of window
            } else {
                mWindowForNonWindowedCursor = window; // we own the window
                mCursor.fillWindow(0, window);
            }
        } catch (ClassCastException e) {
            // TODO Implement this case.
            window.close();
            throw new UnsupportedOperationException(
                    "Only CrossProcessCursor cursors are supported across process for now", e);
        }
@@ -117,17 +103,22 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative
        }
    }

    private void closeCursorAndWindowLocked() {
    private void closeWindowForNonWindowedCursorLocked() {
        if (mWindowForNonWindowedCursor != null) {
            mWindowForNonWindowedCursor.close();
            mWindowForNonWindowedCursor = null;
            mWindowForNonWindowedCursorWasFilled = false;
        }
    }

    private void disposeLocked() {
        if (mCursor != null) {
            unregisterObserverProxyLocked();
            mCursor.close();
            mCursor = null;
        }

        if (mWindowForNonWindowedCursor != null) {
            mWindowForNonWindowedCursor.close();
            mWindowForNonWindowedCursor = null;
        }
        closeWindowForNonWindowedCursorLocked();
    }

    private void throwIfCursorIsClosed() {
@@ -139,7 +130,7 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative
    @Override
    public void binderDied() {
        synchronized (mLock) {
            closeCursorAndWindowLocked();
            disposeLocked();
        }
    }

@@ -148,17 +139,30 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative
        synchronized (mLock) {
            throwIfCursorIsClosed();

            mCursor.moveToPosition(startPos);

            final CursorWindow window;
            CursorWindow window;
            if (mCursor instanceof AbstractWindowedCursor) {
                window = ((AbstractWindowedCursor)mCursor).getWindow();
                AbstractWindowedCursor windowedCursor = (AbstractWindowedCursor)mCursor;
                window = windowedCursor.getWindow();
                if (window == null) {
                    window = new CursorWindow(mProviderName, false /*localOnly*/);
                    windowedCursor.setWindow(window);
                }

                mCursor.moveToPosition(startPos);
            } else {
                window = mWindowForNonWindowedCursor;
                if (window != null
                        && (startPos < window.getStartPosition() ||
                                startPos >= (window.getStartPosition() + window.getNumRows()))) {
                if (window == null) {
                    window = new CursorWindow(mProviderName, false /*localOnly*/);
                    mWindowForNonWindowedCursor = window;
                }

                mCursor.moveToPosition(startPos);

                if (!mWindowForNonWindowedCursorWasFilled
                        || startPos < window.getStartPosition()
                        || startPos >= window.getStartPosition() + window.getNumRows()) {
                    mCursor.fillWindow(startPos, window);
                    mWindowForNonWindowedCursorWasFilled = true;
                }
            }

@@ -206,29 +210,24 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative
                unregisterObserverProxyLocked();
                mCursor.deactivate();
            }

            closeWindowForNonWindowedCursorLocked();
        }
    }

    @Override
    public void close() {
        synchronized (mLock) {
            closeCursorAndWindowLocked();
            disposeLocked();
        }
    }

    @Override
    public int requery(IContentObserver observer, CursorWindow window) {
    public int requery(IContentObserver observer) {
        synchronized (mLock) {
            throwIfCursorIsClosed();

            if (mCursor instanceof AbstractWindowedCursor) {
                ((AbstractWindowedCursor) mCursor).setWindow(window);
            } else {
                if (mWindowForNonWindowedCursor != null) {
                    mWindowForNonWindowedCursor.close();
                }
                mWindowForNonWindowedCursor = window;
            }
            closeWindowForNonWindowedCursorLocked();

            try {
                if (!mCursor.requery()) {
@@ -241,12 +240,6 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative
                throw leakProgram;
            }

            if (!(mCursor instanceof AbstractWindowedCursor)) {
                if (window != null) {
                    mCursor.fillWindow(0, window);
                }
            }

            unregisterObserverProxyLocked();
            createAndRegisterObserverProxyLocked(observer);
            return mCursor.getCount();
Loading