diff options
5 files changed, 101 insertions, 32 deletions
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java index de52e65..fdb3d20 100644 --- a/core/java/android/content/ContentProviderNative.java +++ b/core/java/android/content/ContentProviderNative.java @@ -73,7 +73,10 @@ abstract public class ContentProviderNative extends Binder implements IContentPr case QUERY_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); + Uri url = Uri.CREATOR.createFromParcel(data); + + // String[] projection int num = data.readInt(); String[] projection = null; if (num > 0) { @@ -82,6 +85,8 @@ abstract public class ContentProviderNative extends Binder implements IContentPr projection[i] = data.readString(); } } + + // String selection, String[] selectionArgs... String selection = data.readString(); num = data.readInt(); String[] selectionArgs = null; @@ -91,19 +96,33 @@ abstract public class ContentProviderNative extends Binder implements IContentPr selectionArgs[i] = data.readString(); } } + String sortOrder = data.readString(); IContentObserver observer = IContentObserver.Stub. asInterface(data.readStrongBinder()); CursorWindow window = CursorWindow.CREATOR.createFromParcel(data); + // Flag for whether caller wants the number of + // rows in the cursor and the position of the + // "_id" column index (or -1 if non-existent) + // Only to be returned if binder != null. + boolean wantsCursorMetadata = data.readInt() != 0; + IBulkCursor bulkCursor = bulkQuery(url, projection, selection, selectionArgs, sortOrder, observer, window); reply.writeNoException(); if (bulkCursor != null) { reply.writeStrongBinder(bulkCursor.asBinder()); + + if (wantsCursorMetadata) { + reply.writeInt(bulkCursor.count()); + reply.writeInt(BulkCursorToCursorAdaptor.findRowIdColumnIndex( + bulkCursor.getColumnNames())); + } } else { reply.writeStrongBinder(null); } + return true; } @@ -266,9 +285,12 @@ final class ContentProviderProxy implements IContentProvider return mRemote; } - public IBulkCursor bulkQuery(Uri url, String[] projection, - String selection, String[] selectionArgs, String sortOrder, IContentObserver observer, - CursorWindow window) throws RemoteException { + // Like bulkQuery() but sets up provided 'adaptor' if not null. + private IBulkCursor bulkQueryInternal( + Uri url, String[] projection, + String selection, String[] selectionArgs, String sortOrder, + IContentObserver observer, CursorWindow window, + BulkCursorToCursorAdaptor adaptor) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); @@ -297,6 +319,12 @@ final class ContentProviderProxy implements IContentProvider data.writeStrongBinder(observer.asBinder()); window.writeToParcel(data, 0); + // Flag for whether or not we want the number of rows in the + // cursor and the position of the "_id" column index (or -1 if + // non-existent). Only to be returned if binder != null. + final boolean wantsCursorMetadata = (adaptor != null); + data.writeInt(wantsCursorMetadata ? 1 : 0); + mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0); DatabaseUtils.readExceptionFromParcel(reply); @@ -305,26 +333,43 @@ final class ContentProviderProxy implements IContentProvider IBinder bulkCursorBinder = reply.readStrongBinder(); if (bulkCursorBinder != null) { bulkCursor = BulkCursorNative.asInterface(bulkCursorBinder); + + if (wantsCursorMetadata) { + int rowCount = reply.readInt(); + int idColumnPosition = reply.readInt(); + if (bulkCursor != null) { + adaptor.set(bulkCursor, rowCount, idColumnPosition); + } + } } - + data.recycle(); reply.recycle(); - + return bulkCursor; } + public IBulkCursor bulkQuery(Uri url, String[] projection, + String selection, String[] selectionArgs, String sortOrder, IContentObserver observer, + CursorWindow window) throws RemoteException { + return bulkQueryInternal( + url, projection, selection, selectionArgs, sortOrder, + observer, window, + null /* BulkCursorToCursorAdaptor */); + } + public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, String sortOrder) throws RemoteException { //TODO make a pool of windows so we can reuse memory dealers CursorWindow window = new CursorWindow(false /* window will be used remotely */); BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor(); - IBulkCursor bulkCursor = bulkQuery(url, projection, selection, selectionArgs, sortOrder, - adaptor.getObserver(), window); - + IBulkCursor bulkCursor = bulkQueryInternal( + url, projection, selection, selectionArgs, sortOrder, + adaptor.getObserver(), window, + adaptor); if (bulkCursor == null) { return null; } - adaptor.set(bulkCursor); return adaptor; } diff --git a/core/java/android/database/BulkCursorToCursorAdaptor.java b/core/java/android/database/BulkCursorToCursorAdaptor.java index cf30dd9..1469ea2 100644 --- a/core/java/android/database/BulkCursorToCursorAdaptor.java +++ b/core/java/android/database/BulkCursorToCursorAdaptor.java @@ -43,25 +43,43 @@ public final class BulkCursorToCursorAdaptor extends AbstractWindowedCursor { try { mCount = mBulkCursor.count(); mWantsAllOnMoveCalls = mBulkCursor.getWantsAllOnMoveCalls(); - + // Search for the rowID column index and set it for our parent mColumns = mBulkCursor.getColumnNames(); - int length = mColumns.length; - for (int i = 0; i < length; i++) { - if (mColumns[i].equals("_id")) { - mRowIdColumnIndex = i; - break; - } - } + mRowIdColumnIndex = findRowIdColumnIndex(mColumns); } catch (RemoteException ex) { Log.e(TAG, "Setup failed because the remote process is dead"); } } /** + * Version of set() that does fewer Binder calls if the caller + * already knows BulkCursorToCursorAdaptor's properties. + */ + public void set(IBulkCursor bulkCursor, int count, int idIndex) { + mBulkCursor = bulkCursor; + mColumns = null; // lazily retrieved + mCount = count; + mRowIdColumnIndex = idIndex; + } + + /** + * Returns column index of "_id" column, or -1 if not found. + */ + public static int findRowIdColumnIndex(String[] columnNames) { + int length = columnNames.length; + for (int i = 0; i < length; i++) { + if (columnNames[i].equals("_id")) { + return i; + } + } + return -1; + } + + /** * Gets a SelfDataChangeOberserver that can be sent to a remote * process to receive change notifications over IPC. - * + * * @return A SelfContentObserver hooked up to this Cursor */ public synchronized IContentObserver getObserver() { @@ -190,6 +208,14 @@ public final class BulkCursorToCursorAdaptor extends AbstractWindowedCursor { @Override public String[] getColumnNames() { + if (mColumns == null) { + try { + mColumns = mBulkCursor.getColumnNames(); + } catch (RemoteException ex) { + Log.e(TAG, "Unable to fetch column names because the remote process is dead"); + return null; + } + } return mColumns; } @@ -255,4 +281,3 @@ public final class BulkCursorToCursorAdaptor extends AbstractWindowedCursor { } } } - diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java index 99db81b..c756825 100644 --- a/core/java/android/database/CursorWindow.java +++ b/core/java/android/database/CursorWindow.java @@ -44,7 +44,7 @@ public class CursorWindow extends SQLiteClosable implements Parcelable { /** * Returns the starting position of this window within the entire * Cursor's result set. - * + * * @return the starting position of this window within the entire * Cursor's result set. */ diff --git a/core/java/android/database/IBulkCursor.java b/core/java/android/database/IBulkCursor.java index 24354fd..46790a3 100644 --- a/core/java/android/database/IBulkCursor.java +++ b/core/java/android/database/IBulkCursor.java @@ -27,11 +27,10 @@ import java.util.Map; * This interface provides a low-level way to pass bulk cursor data across * both process and language boundries. Application code should use the Cursor * interface directly. - * + * * {@hide} */ -public interface IBulkCursor extends IInterface -{ +public interface IBulkCursor extends IInterface { /** * Returns a BulkCursorWindow, which either has a reference to a shared * memory segment with the rows, or an array of JSON strings. @@ -60,7 +59,7 @@ public interface IBulkCursor extends IInterface public boolean deleteRow(int position) throws RemoteException; public void deactivate() throws RemoteException; - + public void close() throws RemoteException; public int requery(IContentObserver observer, CursorWindow window) throws RemoteException; @@ -87,4 +86,3 @@ public interface IBulkCursor extends IInterface static final int RESPOND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 10; static final int CLOSE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 11; } - diff --git a/core/java/android/database/sqlite/SQLiteClosable.java b/core/java/android/database/sqlite/SQLiteClosable.java index e589f34..71fa2c2 100644 --- a/core/java/android/database/sqlite/SQLiteClosable.java +++ b/core/java/android/database/sqlite/SQLiteClosable.java @@ -19,14 +19,15 @@ package android.database.sqlite; import android.database.CursorWindow; /** - * An object create from a SQLiteDatabase that can be closed. + * An object created from a SQLiteDatabase that can be closed. */ -public abstract class SQLiteClosable { +public abstract class SQLiteClosable { private int mReferenceCount = 1; private Object mLock = new Object(); + protected abstract void onAllReferencesReleased(); - protected void onAllReferencesReleasedFromContainer(){} - + protected void onAllReferencesReleasedFromContainer() {} + public void acquireReference() { synchronized(mLock) { if (mReferenceCount <= 0) { @@ -36,7 +37,7 @@ public abstract class SQLiteClosable { mReferenceCount++; } } - + public void releaseReference() { synchronized(mLock) { mReferenceCount--; @@ -45,14 +46,14 @@ public abstract class SQLiteClosable { } } } - + public void releaseReferenceFromContainer() { synchronized(mLock) { mReferenceCount--; if (mReferenceCount == 0) { onAllReferencesReleasedFromContainer(); } - } + } } private String getObjInfo() { |