am 241fe477: am 58bf986c: Merge "Use ashmem for CursorWindows. Bug: 5332296" into ics-mr0

* commit '241fe477edba539bcc58df4410c307d9540a4233':
  Use ashmem for CursorWindows. Bug: 5332296
This commit is contained in:
Jeff Brown
2011-10-12 12:37:46 -07:00
committed by Android Git Automerger
13 changed files with 696 additions and 818 deletions

View File

@@ -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,67 +325,58 @@ 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 */);
BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeInterfaceToken(IContentProvider.descriptor);
url.writeToParcel(data, 0);
int length = 0;
if (projection != null) {
length = projection.length;
}
data.writeInt(length);
for (int i = 0; i < length; i++) {
data.writeString(projection[i]);
}
data.writeString(selection);
if (selectionArgs != null) {
length = selectionArgs.length;
} else {
length = 0;
}
data.writeInt(length);
for (int i = 0; i < length; i++) {
data.writeString(selectionArgs[i]);
}
data.writeString(sortOrder);
data.writeStrongBinder(adaptor.getObserver().asBinder());
window.writeToParcel(data, 0);
mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
IBulkCursor bulkCursor = BulkCursorNative.asInterface(reply.readStrongBinder());
if (bulkCursor != null) {
int rowCount = reply.readInt();
int idColumnPosition = reply.readInt();
adaptor.initialize(bulkCursor, rowCount, idColumnPosition);
} else {
adaptor.close();
adaptor = null;
}
return adaptor;
} catch (RemoteException ex) {
adaptor.close();
throw ex;
} catch (RuntimeException ex) {
adaptor.close();
throw ex;
} finally {
data.recycle();
reply.recycle();
url.writeToParcel(data, 0);
int length = 0;
if (projection != null) {
length = projection.length;
}
data.writeInt(length);
for (int i = 0; i < length; i++) {
data.writeString(projection[i]);
}
data.writeString(selection);
if (selectionArgs != null) {
length = selectionArgs.length;
} else {
length = 0;
}
data.writeInt(length);
for (int i = 0; i < length; i++) {
data.writeString(selectionArgs[i]);
}
data.writeString(sortOrder);
data.writeStrongBinder(adaptor.getObserver().asBinder());
mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
IBulkCursor bulkCursor = BulkCursorNative.asInterface(reply.readStrongBinder());
if (bulkCursor != null) {
int rowCount = reply.readInt();
int idColumnPosition = reply.readInt();
boolean wantsAllOnMoveCalls = reply.readInt() != 0;
adaptor.initialize(bulkCursor, rowCount, idColumnPosition, wantsAllOnMoveCalls);
} else {
adaptor.close();
adaptor = null;
}
return adaptor;
} catch (RemoteException ex) {
adaptor.close();
throw ex;
} catch (RuntimeException ex) {
adaptor.close();
throw ex;
} 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();
data.recycle();
reply.recycle();
}
}

View File

@@ -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();
}

View File

@@ -109,9 +109,8 @@ public abstract class BulkCursorNative extends Binder implements IBulkCursor
case REQUERY_TRANSACTION: {
data.enforceInterface(IBulkCursor.descriptor);
IContentObserver observer =
IContentObserver.Stub.asInterface(data.readStrongBinder());
CursorWindow window = CursorWindow.CREATOR.createFromParcel(data);
int count = requery(observer, window);
IContentObserver.Stub.asInterface(data.readStrongBinder());
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);

View File

@@ -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,15 +88,12 @@ 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())) {
setWindow(mBulkCursor.getWindow(newPosition));
} else if (mWantsAllOnMoveCalls) {
mBulkCursor.onMove(newPosition);
}
} else {
if (mWindow == null
|| newPosition < mWindow.getStartPosition()
|| newPosition >= mWindow.getStartPosition() + mWindow.getNumRows()) {
setWindow(mBulkCursor.getWindow(newPosition));
} else if (mWantsAllOnMoveCalls) {
mBulkCursor.onMove(newPosition);
}
} catch (RemoteException ex) {
// We tried to get a window and failed
@@ -145,25 +144,19 @@ public final class BulkCursorToCursorAdaptor extends AbstractWindowedCursor {
throwIfCursorIsClosed();
try {
CursorWindow newWindow = new CursorWindow(false /* create a remote window */);
try {
mCount = mBulkCursor.requery(getObserver(), newWindow);
if (mCount != -1) {
mPos = -1;
closeWindow();
mCount = mBulkCursor.requery(getObserver());
if (mCount != -1) {
mPos = -1;
closeWindow();
// super.requery() will call onChanged. Do it here instead of relying on the
// observer from the far side so that observers can see a correct value for mCount
// when responding to onChanged.
super.requery();
return true;
} else {
deactivate();
return false;
}
} finally {
// Don't take ownership of the window until the next call to onMove.
newWindow.close();
// super.requery() will call onChanged. Do it here instead of relying on the
// observer from the far side so that observers can see a correct value for mCount
// when responding to onChanged.
super.requery();
return true;
} else {
deactivate();
return false;
}
} catch (Exception ex) {
Log.e(TAG, "Unable to requery because the remote process exception " + ex.getMessage());

View File

@@ -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();

View File

@@ -22,7 +22,6 @@ import android.content.res.Resources;
import android.database.sqlite.SQLiteClosable;
import android.database.sqlite.SQLiteException;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
@@ -31,6 +30,13 @@ import android.util.SparseIntArray;
/**
* A buffer containing multiple cursor rows.
* <p>
* A {@link CursorWindow} is read-write when created and used locally. When sent
* to a remote process (by writing it to a {@link Parcel}), the remote process
* receives a read-only view of the cursor window. Typically the cursor window
* will be allocated by the producer, filled with data, and then sent to the
* consumer for reading.
* </p>
*/
public class CursorWindow extends SQLiteClosable implements Parcelable {
private static final String STATS_TAG = "CursorWindowStats";
@@ -52,10 +58,11 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
private final CloseGuard mCloseGuard = CloseGuard.get();
private static native int nativeInitializeEmpty(int cursorWindowSize, boolean localOnly);
private static native int nativeInitializeFromBinder(IBinder nativeBinder);
private static native int nativeCreate(String name,
int cursorWindowSize, boolean localOnly);
private static native int nativeCreateFromParcel(Parcel parcel);
private static native void nativeDispose(int windowPtr);
private static native IBinder nativeGetBinder(int windowPtr);
private static native void nativeWriteToParcel(int windowPtr, Parcel parcel);
private static native void nativeClear(int windowPtr);
@@ -78,6 +85,30 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
private static native boolean nativePutDouble(int windowPtr, double value, int row, int column);
private static native boolean nativePutNull(int windowPtr, int row, int column);
/**
* Creates a new empty cursor window and gives it a name.
* <p>
* The cursor initially has no rows or columns. Call {@link #setNumColumns(int)} to
* set the number of columns before adding any rows to the cursor.
* </p>
*
* @param name The name of the cursor window, or null if none.
* @param localWindow True if this window will be used in this process only,
* false if it might be sent to another processes.
*
* @hide
*/
public CursorWindow(String name, boolean localWindow) {
mStartPos = 0;
mWindowPtr = nativeCreate(name, sCursorWindowSize, localWindow);
if (mWindowPtr == 0) {
throw new CursorWindowAllocationException("Cursor window allocation of " +
(sCursorWindowSize / 1024) + " kb failed. " + printStats());
}
mCloseGuard.open("close");
recordNewWindow(Binder.getCallingPid(), mWindowPtr);
}
/**
* Creates a new empty cursor window.
* <p>
@@ -89,20 +120,12 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
* false if it might be sent to another processes.
*/
public CursorWindow(boolean localWindow) {
mStartPos = 0;
mWindowPtr = nativeInitializeEmpty(sCursorWindowSize, localWindow);
if (mWindowPtr == 0) {
throw new CursorWindowAllocationException("Cursor window allocation of " +
(sCursorWindowSize / 1024) + " kb failed. " + printStats());
}
mCloseGuard.open("close");
recordNewWindow(Binder.getCallingPid(), mWindowPtr);
this(null, localWindow);
}
private CursorWindow(Parcel source) {
IBinder binder = source.readStrongBinder();
mStartPos = source.readInt();
mWindowPtr = nativeInitializeFromBinder(binder);
mWindowPtr = nativeCreateFromParcel(source);
if (mWindowPtr == 0) {
throw new CursorWindowAllocationException("Cursor window could not be "
+ "created from binder.");
@@ -687,8 +710,8 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeStrongBinder(nativeGetBinder(mWindowPtr));
dest.writeInt(mStartPos);
nativeWriteToParcel(mWindowPtr, dest);
if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
releaseReference();

View File

@@ -56,7 +56,7 @@ public interface IBulkCursor extends IInterface {
public void close() throws RemoteException;
public int requery(IContentObserver observer, CursorWindow window) throws RemoteException;
public int requery(IContentObserver observer) throws RemoteException;
boolean getWantsAllOnMoveCalls() throws RemoteException;

View File

@@ -155,7 +155,7 @@ public class SQLiteCursor extends AbstractWindowedCursor {
}
private void fillWindow(int startPos) {
clearOrCreateLocalWindow();
clearOrCreateLocalWindow(getDatabase().getPath());
mWindow.setStartPosition(startPos);
int count = getQuery().fillWindow(mWindow);
if (startPos == 0) { // fillWindow returns count(*) only for startPos = 0