diff options
author | Jeff Brown <jeffbrown@google.com> | 2011-10-06 13:11:04 -0700 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2011-10-06 14:40:13 -0700 |
commit | 3bc6bbc92cd2095f42039b5aadd0a14d0e5d9230 (patch) | |
tree | 39b62affe30e0c2895a0f8a52212a7f91bd80dd7 | |
parent | 3b2faf68e5a66ac67b28d6f79d4ba213b6c0d09c (diff) | |
download | frameworks_base-3bc6bbc92cd2095f42039b5aadd0a14d0e5d9230.zip frameworks_base-3bc6bbc92cd2095f42039b5aadd0a14d0e5d9230.tar.gz frameworks_base-3bc6bbc92cd2095f42039b5aadd0a14d0e5d9230.tar.bz2 |
Clean up CursorWindow code.
Bug: 5332296
The code is functionally equivalent, but a little more efficient
and much easier to maintain.
Change-Id: I90670a13799df05831843a5137ab234929281b7c
-rw-r--r-- | core/java/android/database/CursorWindow.java | 792 | ||||
-rw-r--r-- | core/java/android/database/CursorWindowAllocationException.java | 15 | ||||
-rw-r--r-- | core/java/android/database/sqlite/SQLiteQuery.java | 4 | ||||
-rw-r--r-- | core/jni/android_database_CursorWindow.cpp | 777 | ||||
-rw-r--r-- | core/jni/android_database_SQLiteQuery.cpp | 12 | ||||
-rw-r--r-- | include/android_runtime/AndroidRuntime.h | 4 | ||||
-rw-r--r-- | include/binder/CursorWindow.h | 28 | ||||
-rw-r--r-- | libs/binder/CursorWindow.cpp | 41 |
8 files changed, 815 insertions, 858 deletions
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java index f7cbf7a..183662f 100644 --- a/core/java/android/database/CursorWindow.java +++ b/core/java/android/database/CursorWindow.java @@ -18,6 +18,7 @@ package android.database; 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; @@ -39,538 +40,613 @@ public class CursorWindow extends SQLiteClosable implements Parcelable { Resources.getSystem().getInteger( com.android.internal.R.integer.config_cursorWindowSize) * 1024; - /** The pointer to the native window class. set by the native methods in - * android_database_CursorWindow.cpp + /** + * The native CursorWindow object pointer. (FOR INTERNAL USE ONLY) + * @hide */ - private int nWindow; + public int mWindowPtr; private int mStartPos; - /** - * Creates a new empty window. + private static native int nativeInitializeEmpty(int cursorWindowSize, boolean localOnly); + private static native int nativeInitializeFromBinder(IBinder nativeBinder); + private static native void nativeDispose(int windowPtr); + private static native IBinder nativeGetBinder(int windowPtr); + + private static native void nativeClear(int windowPtr); + + private static native int nativeGetNumRows(int windowPtr); + private static native boolean nativeSetNumColumns(int windowPtr, int columnNum); + private static native boolean nativeAllocRow(int windowPtr); + private static native void nativeFreeLastRow(int windowPtr); + + private static native int nativeGetType(int windowPtr, int row, int column); + private static native byte[] nativeGetBlob(int windowPtr, int row, int column); + private static native String nativeGetString(int windowPtr, int row, int column); + private static native long nativeGetLong(int windowPtr, int row, int column); + private static native double nativeGetDouble(int windowPtr, int row, int column); + private static native void nativeCopyStringToBuffer(int windowPtr, int row, int column, + CharArrayBuffer buffer); + + private static native boolean nativePutBlob(int windowPtr, byte[] value, int row, int column); + private static native boolean nativePutString(int windowPtr, String value, int row, int column); + private static native boolean nativePutLong(int windowPtr, long value, int row, int column); + 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. + * <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 localWindow true if this window will be used in this process only + * @param localWindow True if this window will be used in this process only, + * false if it might be sent to another processes. */ public CursorWindow(boolean localWindow) { mStartPos = 0; - int rslt = native_init(sCursorWindowSize, localWindow); - printDebugMsgIfError(rslt); - recordNewWindow(Binder.getCallingPid(), nWindow); + mWindowPtr = nativeInitializeEmpty(sCursorWindowSize, localWindow); + if (mWindowPtr == 0) { + throw new CursorWindowAllocationException("Cursor window allocation of " + + (sCursorWindowSize / 1024) + " kb failed. " + printStats()); + } + recordNewWindow(Binder.getCallingPid(), mWindowPtr); } - private void printDebugMsgIfError(int rslt) { - if (rslt > 0) { - // cursor window allocation failed. either low memory or too many cursors being open. - // print info to help in debugging this. - throw new CursorWindowAllocationException("Cursor Window allocation of " + - sCursorWindowSize/1024 + " kb failed. " + printStats()); + private CursorWindow(Parcel source) { + IBinder binder = source.readStrongBinder(); + mStartPos = source.readInt(); + mWindowPtr = nativeInitializeFromBinder(binder); + if (mWindowPtr == 0) { + throw new CursorWindowAllocationException("Cursor window could not be " + + "created from binder."); } } - /** - * 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. - */ - public int getStartPosition() { - return mStartPos; + @Override + protected void finalize() { + dispose(); } - /** - * Set the start position of cursor window - * @param pos - */ - public void setStartPosition(int pos) { - mStartPos = pos; - } - - /** - * Returns the number of rows in this window. - * - * @return the number of rows in this window. - */ - public int getNumRows() { - acquireReference(); - try { - return getNumRows_native(); - } finally { - releaseReference(); - } - } - - private native int getNumRows_native(); - /** - * Set number of Columns - * @param columnNum - * @return true if success - */ - public boolean setNumColumns(int columnNum) { - acquireReference(); - try { - return setNumColumns_native(columnNum); - } finally { - releaseReference(); + private void dispose() { + if (mWindowPtr != 0) { + recordClosingOfWindow(mWindowPtr); + nativeDispose(mWindowPtr); + mWindowPtr = 0; } } - - private native boolean setNumColumns_native(int columnNum); - + /** - * Allocate a row in cursor window - * @return false if cursor window is out of memory + * Closes the cursor window and frees its underlying resources when all other + * remaining references have been released. */ - public boolean allocRow(){ - acquireReference(); - try { - return allocRow_native(); - } finally { - releaseReference(); - } + public void close() { + releaseReference(); } - - private native boolean allocRow_native(); - + /** - * Free the last row + * Clears out the existing contents of the window, making it safe to reuse + * for new data. + * <p> + * The start position ({@link #getStartPosition()}), number of rows ({@link #getNumRows()}), + * and number of columns in the cursor are all reset to zero. + * </p> */ - public void freeLastRow(){ + public void clear() { acquireReference(); try { - freeLastRow_native(); + mStartPos = 0; + nativeClear(mWindowPtr); } finally { releaseReference(); } } - - private native void freeLastRow_native(); /** - * copy byte array to cursor window - * @param value - * @param row - * @param col - * @return false if fail to copy + * Gets the start position of this cursor window. + * The start position is the index of the first row that this window contains + * relative to the entire result set of the {@link Cursor}. + * + * @return The start position. */ - public boolean putBlob(byte[] value, int row, int col) { - acquireReference(); - try { - return putBlob_native(value, row - mStartPos, col); - } finally { - releaseReference(); - } + public int getStartPosition() { + return mStartPos; } - - private native boolean putBlob_native(byte[] value, int row, int col); /** - * Copy String to cursor window - * @param value - * @param row - * @param col - * @return false if fail to copy + * Sets the start position of this cursor window. + * The start position is the index of the first row that this window contains + * relative to the entire result set of the {@link Cursor}. + * + * @param pos The new start position. */ - public boolean putString(String value, int row, int col) { - acquireReference(); - try { - return putString_native(value, row - mStartPos, col); - } finally { - releaseReference(); - } + public void setStartPosition(int pos) { + mStartPos = pos; } - - private native boolean putString_native(String value, int row, int col); - + /** - * Copy integer to cursor window - * @param value - * @param row - * @param col - * @return false if fail to copy + * Gets the number of rows in this window. + * + * @return The number of rows in this cursor window. */ - public boolean putLong(long value, int row, int col) { + public int getNumRows() { acquireReference(); try { - return putLong_native(value, row - mStartPos, col); + return nativeGetNumRows(mWindowPtr); } finally { releaseReference(); } } - - private native boolean putLong_native(long value, int row, int col); - /** - * Copy double to cursor window - * @param value - * @param row - * @param col - * @return false if fail to copy + * Sets the number of columns in this window. + * <p> + * This method must be called before any rows are added to the window, otherwise + * it will fail to set the number of columns if it differs from the current number + * of columns. + * </p> + * + * @param columnNum The new number of columns. + * @return True if successful. */ - public boolean putDouble(double value, int row, int col) { + public boolean setNumColumns(int columnNum) { acquireReference(); try { - return putDouble_native(value, row - mStartPos, col); + return nativeSetNumColumns(mWindowPtr, columnNum); } finally { releaseReference(); } } - - private native boolean putDouble_native(double value, int row, int col); /** - * Set the [row, col] value to NULL - * @param row - * @param col - * @return false if fail to copy + * Allocates a new row at the end of this cursor window. + * + * @return True if successful, false if the cursor window is out of memory. */ - public boolean putNull(int row, int col) { + public boolean allocRow(){ acquireReference(); try { - return putNull_native(row - mStartPos, col); + return nativeAllocRow(mWindowPtr); } finally { releaseReference(); } } - - private native boolean putNull_native(int row, int col); - /** - * Returns {@code true} if given field is {@code NULL}. - * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return {@code true} if given field is {@code NULL} - * @deprecated use {@link #getType(int, int)} instead - */ - @Deprecated - public boolean isNull(int row, int col) { - return getType(row, col) == Cursor.FIELD_TYPE_NULL; - } - - /** - * Returns a byte array for the given field. - * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return a String value for the given field + * Frees the last row in this cursor window. */ - public byte[] getBlob(int row, int col) { + public void freeLastRow(){ acquireReference(); try { - return getBlob_native(row - mStartPos, col); + nativeFreeLastRow(mWindowPtr); } finally { releaseReference(); } } /** - * Returns the value at (<code>row</code>, <code>col</code>) as a <code>byte</code> array. - * - * <p>If the value is null, then <code>null</code> is returned. If the - * type of column <code>col</code> is a string type, then the result - * is the array of bytes that make up the internal representation of the - * string value. If the type of column <code>col</code> is integral or floating-point, - * then an {@link SQLiteException} is thrown. - */ - private native byte[] getBlob_native(int row, int col); - - /** - * Returns data type of the given column's value. - *<p> - * Returned column types are - * <ul> - * <li>{@link Cursor#FIELD_TYPE_NULL}</li> - * <li>{@link Cursor#FIELD_TYPE_INTEGER}</li> - * <li>{@link Cursor#FIELD_TYPE_FLOAT}</li> - * <li>{@link Cursor#FIELD_TYPE_STRING}</li> - * <li>{@link Cursor#FIELD_TYPE_BLOB}</li> - *</ul> - *</p> + * Returns true if the field at the specified row and column index + * has type {@link Cursor#FIELD_TYPE_NULL}. * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return the value type + * @param row The zero-based row index, relative to the cursor window's + * start position ({@link #getStartPosition()}). + * @param column The zero-based column index. + * @return True if the field has type {@link Cursor#FIELD_TYPE_NULL}. + * @deprecated Use {@link #getType(int, int)} instead. */ - public int getType(int row, int col) { - acquireReference(); - try { - return getType_native(row - mStartPos, col); - } finally { - releaseReference(); - } + @Deprecated + public boolean isNull(int row, int column) { + return getType(row, column) == Cursor.FIELD_TYPE_NULL; } /** - * Checks if a field contains either a blob or is null. + * Returns true if the field at the specified row and column index + * has type {@link Cursor#FIELD_TYPE_BLOB} or {@link Cursor#FIELD_TYPE_NULL}. * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return {@code true} if given field is {@code NULL} or a blob - * @deprecated use {@link #getType(int, int)} instead + * @param row The zero-based row index, relative to the cursor window's + * start position ({@link #getStartPosition()}). + * @param column The zero-based column index. + * @return True if the field has type {@link Cursor#FIELD_TYPE_BLOB} or + * {@link Cursor#FIELD_TYPE_NULL}. + * @deprecated Use {@link #getType(int, int)} instead. */ @Deprecated - public boolean isBlob(int row, int col) { - int type = getType(row, col); + public boolean isBlob(int row, int column) { + int type = getType(row, column); return type == Cursor.FIELD_TYPE_BLOB || type == Cursor.FIELD_TYPE_NULL; } /** - * Checks if a field contains a long + * Returns true if the field at the specified row and column index + * has type {@link Cursor#FIELD_TYPE_INTEGER}. * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return {@code true} if given field is a long - * @deprecated use {@link #getType(int, int)} instead + * @param row The zero-based row index, relative to the cursor window's + * start position ({@link #getStartPosition()}). + * @param column The zero-based column index. + * @return True if the field has type {@link Cursor#FIELD_TYPE_INTEGER}. + * @deprecated Use {@link #getType(int, int)} instead. */ @Deprecated - public boolean isLong(int row, int col) { - return getType(row, col) == Cursor.FIELD_TYPE_INTEGER; + public boolean isLong(int row, int column) { + return getType(row, column) == Cursor.FIELD_TYPE_INTEGER; } /** - * Checks if a field contains a float. + * Returns true if the field at the specified row and column index + * has type {@link Cursor#FIELD_TYPE_FLOAT}. * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return {@code true} if given field is a float - * @deprecated use {@link #getType(int, int)} instead + * @param row The zero-based row index, relative to the cursor window's + * start position ({@link #getStartPosition()}). + * @param column The zero-based column index. + * @return True if the field has type {@link Cursor#FIELD_TYPE_FLOAT}. + * @deprecated Use {@link #getType(int, int)} instead. */ @Deprecated - public boolean isFloat(int row, int col) { - return getType(row, col) == Cursor.FIELD_TYPE_FLOAT; + public boolean isFloat(int row, int column) { + return getType(row, column) == Cursor.FIELD_TYPE_FLOAT; } /** - * Checks if a field contains either a String or is null. + * Returns true if the field at the specified row and column index + * has type {@link Cursor#FIELD_TYPE_STRING} or {@link Cursor#FIELD_TYPE_NULL}. * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return {@code true} if given field is {@code NULL} or a String - * @deprecated use {@link #getType(int, int)} instead + * @param row The zero-based row index, relative to the cursor window's + * start position ({@link #getStartPosition()}). + * @param column The zero-based column index. + * @return True if the field has type {@link Cursor#FIELD_TYPE_STRING} + * or {@link Cursor#FIELD_TYPE_NULL}. + * @deprecated Use {@link #getType(int, int)} instead. */ @Deprecated - public boolean isString(int row, int col) { - int type = getType(row, col); + public boolean isString(int row, int column) { + int type = getType(row, column); return type == Cursor.FIELD_TYPE_STRING || type == Cursor.FIELD_TYPE_NULL; } - private native int getType_native(int row, int col); + /** + * Returns the type of the field at the specified row and column index. + * <p> + * The returned field types are: + * <ul> + * <li>{@link Cursor#FIELD_TYPE_NULL}</li> + * <li>{@link Cursor#FIELD_TYPE_INTEGER}</li> + * <li>{@link Cursor#FIELD_TYPE_FLOAT}</li> + * <li>{@link Cursor#FIELD_TYPE_STRING}</li> + * <li>{@link Cursor#FIELD_TYPE_BLOB}</li> + * </ul> + * </p> + * + * @param row The zero-based row index, relative to the cursor window's + * start position ({@link #getStartPosition()}). + * @param column The zero-based column index. + * @return The field type. + */ + public int getType(int row, int column) { + acquireReference(); + try { + return nativeGetType(mWindowPtr, row - mStartPos, column); + } finally { + releaseReference(); + } + } /** - * Returns a String for the given field. - * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return a String value for the given field + * Gets the value of the field at the specified row and column index as a byte array. + * <p> + * The result is determined as follows: + * <ul> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result + * is <code>null</code>.</li> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then the result + * is the blob value.</li> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result + * is the array of bytes that make up the internal representation of the + * string value.</li> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER} or + * {@link Cursor#FIELD_TYPE_FLOAT}, then a {@link SQLiteException} is thrown.</li> + * </ul> + * </p> + * + * @param row The zero-based row index, relative to the cursor window's + * start position ({@link #getStartPosition()}). + * @param column The zero-based column index. + * @return The value of the field as a byte array. */ - public String getString(int row, int col) { + public byte[] getBlob(int row, int column) { acquireReference(); try { - return getString_native(row - mStartPos, col); + return nativeGetBlob(mWindowPtr, row - mStartPos, column); } finally { releaseReference(); } } - + /** - * Returns the value at (<code>row</code>, <code>col</code>) as a <code>String</code>. + * Gets the value of the field at the specified row and column index as a string. + * <p> + * The result is determined as follows: + * <ul> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result + * is <code>null</code>.</li> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result + * is the string value.</li> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the result + * is a string representation of the integer in decimal, obtained by formatting the + * value with the <code>printf</code> family of functions using + * format specifier <code>%lld</code>.</li> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the result + * is a string representation of the floating-point value in decimal, obtained by + * formatting the value with the <code>printf</code> family of functions using + * format specifier <code>%g</code>.</li> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a + * {@link SQLiteException} is thrown.</li> + * </ul> + * </p> * - * <p>If the value is null, then <code>null</code> is returned. If the - * type of column <code>col</code> is integral, then the result is the string - * that is obtained by formatting the integer value with the <code>printf</code> - * family of functions using format specifier <code>%lld</code>. If the - * type of column <code>col</code> is floating-point, then the result is the string - * that is obtained by formatting the floating-point value with the - * <code>printf</code> family of functions using format specifier <code>%g</code>. - * If the type of column <code>col</code> is a blob type, then an - * {@link SQLiteException} is thrown. + * @param row The zero-based row index, relative to the cursor window's + * start position ({@link #getStartPosition()}). + * @param column The zero-based column index. + * @return The value of the field as a string. */ - private native String getString_native(int row, int col); + public String getString(int row, int column) { + acquireReference(); + try { + return nativeGetString(mWindowPtr, row - mStartPos, column); + } finally { + releaseReference(); + } + } /** - * copy the text for the given field in the provided char array. - * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @param buffer the CharArrayBuffer to copy the text into, - * If the requested string is larger than the buffer - * a new char buffer will be created to hold the string. and assigne to - * CharArrayBuffer.data + * Copies the text of the field at the specified row and column index into + * a {@link CharArrayBuffer}. + * <p> + * The buffer is populated as follows: + * <ul> + * <li>If the buffer is too small for the value to be copied, then it is + * automatically resized.</li> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the buffer + * is set to an empty string.</li> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the buffer + * is set to the contents of the string.</li> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the buffer + * is set to a string representation of the integer in decimal, obtained by formatting the + * value with the <code>printf</code> family of functions using + * format specifier <code>%lld</code>.</li> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the buffer is + * set to a string representation of the floating-point value in decimal, obtained by + * formatting the value with the <code>printf</code> family of functions using + * format specifier <code>%g</code>.</li> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a + * {@link SQLiteException} is thrown.</li> + * </ul> + * </p> + * + * @param row The zero-based row index, relative to the cursor window's + * start position ({@link #getStartPosition()}). + * @param column The zero-based column index. + * @param buffer The {@link CharArrayBuffer} to hold the string. It is automatically + * resized if the requested string is larger than the buffer's current capacity. */ - public void copyStringToBuffer(int row, int col, CharArrayBuffer buffer) { + public void copyStringToBuffer(int row, int column, CharArrayBuffer buffer) { if (buffer == null) { throw new IllegalArgumentException("CharArrayBuffer should not be null"); } - if (buffer.data == null) { - buffer.data = new char[64]; - } acquireReference(); try { - char[] newbuf = copyStringToBuffer_native( - row - mStartPos, col, buffer.data.length, buffer); - if (newbuf != null) { - buffer.data = newbuf; - } + nativeCopyStringToBuffer(mWindowPtr, row, column, buffer); } finally { releaseReference(); } } - - private native char[] copyStringToBuffer_native( - int row, int col, int bufferSize, CharArrayBuffer buffer); - + /** - * Returns a long for the given field. - * row is 0 based - * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return a long value for the given field + * Gets the value of the field at the specified row and column index as a <code>long</code>. + * <p> + * The result is determined as follows: + * <ul> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result + * is <code>0L</code>.</li> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result + * is the value obtained by parsing the string value with <code>strtoll</code>. + * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the result + * is the <code>long</code> value.</li> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the result + * is the floating-point value converted to a <code>long</code>.</li> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a + * {@link SQLiteException} is thrown.</li> + * </ul> + * </p> + * + * @param row The zero-based row index, relative to the cursor window's + * start position ({@link #getStartPosition()}). + * @param column The zero-based column index. + * @return The value of the field as a <code>long</code>. */ - public long getLong(int row, int col) { + public long getLong(int row, int column) { acquireReference(); try { - return getLong_native(row - mStartPos, col); + return nativeGetLong(mWindowPtr, row - mStartPos, column); } finally { releaseReference(); } } - - /** - * Returns the value at (<code>row</code>, <code>col</code>) as a <code>long</code>. - * - * <p>If the value is null, then <code>0L</code> is returned. If the - * type of column <code>col</code> is a string type, then the result - * is the <code>long</code> that is obtained by parsing the string value with - * <code>strtoll</code>. If the type of column <code>col</code> is - * floating-point, then the result is the floating-point value casted to a <code>long</code>. - * If the type of column <code>col</code> is a blob type, then an - * {@link SQLiteException} is thrown. - */ - private native long getLong_native(int row, int col); /** - * Returns a double for the given field. - * row is 0 based - * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return a double value for the given field + * Gets the value of the field at the specified row and column index as a + * <code>double</code>. + * <p> + * The result is determined as follows: + * <ul> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result + * is <code>0.0</code>.</li> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result + * is the value obtained by parsing the string value with <code>strtod</code>. + * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the result + * is the integer value converted to a <code>double</code>.</li> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the result + * is the <code>double</code> value.</li> + * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a + * {@link SQLiteException} is thrown.</li> + * </ul> + * </p> + * + * @param row The zero-based row index, relative to the cursor window's + * start position ({@link #getStartPosition()}). + * @param column The zero-based column index. + * @return The value of the field as a <code>double</code>. */ - public double getDouble(int row, int col) { + public double getDouble(int row, int column) { acquireReference(); try { - return getDouble_native(row - mStartPos, col); + return nativeGetDouble(mWindowPtr, row - mStartPos, column); } finally { releaseReference(); } } - + + /** + * Gets the value of the field at the specified row and column index as a + * <code>short</code>. + * <p> + * The result is determined by invoking {@link #getLong} and converting the + * result to <code>short</code>. + * </p> + * + * @param row The zero-based row index, relative to the cursor window's + * start position ({@link #getStartPosition()}). + * @param column The zero-based column index. + * @return The value of the field as a <code>short</code>. + */ + public short getShort(int row, int column) { + return (short) getLong(row, column); + } + + /** + * Gets the value of the field at the specified row and column index as an + * <code>int</code>. + * <p> + * The result is determined by invoking {@link #getLong} and converting the + * result to <code>int</code>. + * </p> + * + * @param row The zero-based row index, relative to the cursor window's + * start position ({@link #getStartPosition()}). + * @param column The zero-based column index. + * @return The value of the field as an <code>int</code>. + */ + public int getInt(int row, int column) { + return (int) getLong(row, column); + } + /** - * Returns the value at (<code>row</code>, <code>col</code>) as a <code>double</code>. + * Gets the value of the field at the specified row and column index as a + * <code>float</code>. + * <p> + * The result is determined by invoking {@link #getDouble} and converting the + * result to <code>float</code>. + * </p> * - * <p>If the value is null, then <code>0.0</code> is returned. If the - * type of column <code>col</code> is a string type, then the result - * is the <code>double</code> that is obtained by parsing the string value with - * <code>strtod</code>. If the type of column <code>col</code> is - * integral, then the result is the integer value casted to a <code>double</code>. - * If the type of column <code>col</code> is a blob type, then an - * {@link SQLiteException} is thrown. + * @param row The zero-based row index, relative to the cursor window's + * start position ({@link #getStartPosition()}). + * @param column The zero-based column index. + * @return The value of the field as an <code>float</code>. */ - private native double getDouble_native(int row, int col); + public float getFloat(int row, int column) { + return (float) getDouble(row, column); + } /** - * Returns a short for the given field. - * row is 0 based - * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return a short value for the given field + * Copies a byte array into the field at the specified row and column index. + * + * @param value The value to store. + * @param row The zero-based row index, relative to the cursor window's + * start position ({@link #getStartPosition()}). + * @param column The zero-based column index. + * @return True if successful. */ - public short getShort(int row, int col) { + public boolean putBlob(byte[] value, int row, int column) { acquireReference(); try { - return (short) getLong_native(row - mStartPos, col); + return nativePutBlob(mWindowPtr, value, row - mStartPos, column); } finally { releaseReference(); } } /** - * Returns an int for the given field. - * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return an int value for the given field + * Copies a string into the field at the specified row and column index. + * + * @param value The value to store. + * @param row The zero-based row index, relative to the cursor window's + * start position ({@link #getStartPosition()}). + * @param column The zero-based column index. + * @return True if successful. */ - public int getInt(int row, int col) { + public boolean putString(String value, int row, int column) { acquireReference(); try { - return (int) getLong_native(row - mStartPos, col); + return nativePutString(mWindowPtr, value, row - mStartPos, column); } finally { releaseReference(); } } - + /** - * Returns a float for the given field. - * row is 0 based - * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return a float value for the given field + * Puts a long integer into the field at the specified row and column index. + * + * @param value The value to store. + * @param row The zero-based row index, relative to the cursor window's + * start position ({@link #getStartPosition()}). + * @param column The zero-based column index. + * @return True if successful. */ - public float getFloat(int row, int col) { + public boolean putLong(long value, int row, int column) { acquireReference(); try { - return (float) getDouble_native(row - mStartPos, col); + return nativePutLong(mWindowPtr, value, row - mStartPos, column); } finally { releaseReference(); } - } - + } + /** - * Clears out the existing contents of the window, making it safe to reuse - * for new data. Note that the number of columns in the window may NOT - * change across a call to clear(). + * Puts a double-precision floating point value into the field at the + * specified row and column index. + * + * @param value The value to store. + * @param row The zero-based row index, relative to the cursor window's + * start position ({@link #getStartPosition()}). + * @param column The zero-based column index. + * @return True if successful. */ - public void clear() { + public boolean putDouble(double value, int row, int column) { acquireReference(); try { - mStartPos = 0; - native_clear(); + return nativePutDouble(mWindowPtr, value, row - mStartPos, column); } finally { releaseReference(); } } - /** Clears out the native side of things */ - private native void native_clear(); - /** - * Cleans up the native resources associated with the window. + * Puts a null value into the field at the specified row and column index. + * + * @param row The zero-based row index, relative to the cursor window's + * start position ({@link #getStartPosition()}). + * @param column The zero-based column index. + * @return True if successful. */ - public void close() { - releaseReference(); - } - - private native void close_native(); - - @Override - protected void finalize() { - if (nWindow == 0) { - return; + public boolean putNull(int row, int column) { + acquireReference(); + try { + return nativePutNull(mWindowPtr, row - mStartPos, column); + } finally { + releaseReference(); } - // due to bugs 3329504, 3502276, cursorwindow sometimes is closed in fialize() - // don't print any warning saying "don't release cursor in finzlize" - // because it is a bug in framework code - NOT an app bug. - recordClosingOfWindow(nWindow); - close_native(); } - + public static final Parcelable.Creator<CursorWindow> CREATOR = new Parcelable.Creator<CursorWindow>() { public CursorWindow createFromParcel(Parcel source) { @@ -591,30 +667,13 @@ public class CursorWindow extends SQLiteClosable implements Parcelable { } public void writeToParcel(Parcel dest, int flags) { - dest.writeStrongBinder(native_getBinder()); + dest.writeStrongBinder(nativeGetBinder(mWindowPtr)); dest.writeInt(mStartPos); } - private CursorWindow(Parcel source) { - IBinder nativeBinder = source.readStrongBinder(); - mStartPos = source.readInt(); - int rslt = native_init(nativeBinder); - printDebugMsgIfError(rslt); - } - - /** Get the binder for the native side of the window */ - private native IBinder native_getBinder(); - - /** Does the native side initialization for an empty window */ - private native int native_init(int cursorWindowSize, boolean localOnly); - - /** Does the native side initialization with an existing binder from another process */ - private native int native_init(IBinder nativeBinder); - @Override protected void onAllReferencesReleased() { - recordClosingOfWindow(nWindow); - close_native(); + dispose(); } private static final SparseIntArray sWindowToPidMap = new SparseIntArray(); @@ -637,6 +696,7 @@ public class CursorWindow extends SQLiteClosable implements Parcelable { sWindowToPidMap.delete(window); } } + private String printStats() { StringBuilder buff = new StringBuilder(); int myPid = Process.myPid(); diff --git a/core/java/android/database/CursorWindowAllocationException.java b/core/java/android/database/CursorWindowAllocationException.java index ba7df68..2e3227d 100644 --- a/core/java/android/database/CursorWindowAllocationException.java +++ b/core/java/android/database/CursorWindowAllocationException.java @@ -18,17 +18,12 @@ package android.database; /** * This exception is thrown when a CursorWindow couldn't be allocated, - * most probably due to memory not being available + * most probably due to memory not being available. + * + * @hide */ -class CursorWindowAllocationException extends java.lang.RuntimeException -{ - public CursorWindowAllocationException() - { - super(); - } - - public CursorWindowAllocationException(String description) - { +public class CursorWindowAllocationException extends RuntimeException { + public CursorWindowAllocationException(String description) { super(description); } } diff --git a/core/java/android/database/sqlite/SQLiteQuery.java b/core/java/android/database/sqlite/SQLiteQuery.java index dc882d9..06a41b2 100644 --- a/core/java/android/database/sqlite/SQLiteQuery.java +++ b/core/java/android/database/sqlite/SQLiteQuery.java @@ -79,7 +79,7 @@ public class SQLiteQuery extends SQLiteProgram { // if the start pos is not equal to 0, then most likely window is // too small for the data set, loading by another thread // is not safe in this situation. the native code will ignore maxRead - int numRows = native_fill_window(window, window.getStartPosition(), + int numRows = native_fill_window(window.mWindowPtr, window.getStartPosition(), mOffsetIndex, maxRead, lastPos); mDatabase.logTimeStat(mSql, timeStart); return numRows; @@ -154,7 +154,7 @@ public class SQLiteQuery extends SQLiteProgram { compileAndbindAllArgs(); } - private final native int native_fill_window(CursorWindow window, + private final native int native_fill_window(int windowPtr, int startPos, int offsetParam, int maxRead, int lastPos); private final native int native_column_count(); diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp index 419e464..14c6397 100644 --- a/core/jni/android_database_CursorWindow.cpp +++ b/core/jni/android_database_CursorWindow.cpp @@ -24,6 +24,7 @@ #include <utils/Log.h> #include <utils/String8.h> #include <utils/String16.h> +#include <utils/Unicode.h> #include <stdio.h> #include <string.h> @@ -33,69 +34,75 @@ #include "sqlite3_exception.h" #include "android_util_Binder.h" - namespace android { -static jfieldID gWindowField; -static jfieldID gBufferField; -static jfieldID gSizeCopiedField; +static struct { + jfieldID data; + jfieldID sizeCopied; +} gCharArrayBufferClassInfo; -#define GET_WINDOW(env, object) ((CursorWindow *)env->GetIntField(object, gWindowField)) -#define SET_WINDOW(env, object, window) (env->SetIntField(object, gWindowField, (int)window)) -#define SET_BUFFER(env, object, buf) (env->SetObjectField(object, gBufferField, buf)) -#define SET_SIZE_COPIED(env, object, size) (env->SetIntField(object, gSizeCopiedField, size)) +static jstring gEmptyString; -CursorWindow * get_window_from_object(JNIEnv * env, jobject javaWindow) -{ - return GET_WINDOW(env, javaWindow); +static void throwExceptionWithRowCol(JNIEnv* env, jint row, jint column) { + String8 msg; + msg.appendFormat("Couldn't read row %d, col %d from CursorWindow. " + "Make sure the Cursor is initialized correctly before accessing data from it.", + row, column); + jniThrowException(env, "java/lang/IllegalStateException", msg.string()); } -static jint native_init_empty(JNIEnv * env, jobject object, jint cursorWindowSize, - jboolean localOnly) -{ - uint8_t * data; - size_t size; - CursorWindow * window; +static void throwUnknownTypeException(JNIEnv * env, jint type) { + String8 msg; + msg.appendFormat("UNKNOWN type %d", type); + jniThrowException(env, "java/lang/IllegalStateException", msg.string()); +} - window = new CursorWindow(cursorWindowSize); +static jint nativeInitializeEmpty(JNIEnv* env, jclass clazz, + jint cursorWindowSize, jboolean localOnly) { + CursorWindow* window = new CursorWindow(cursorWindowSize); if (!window) { - return 1; + return 0; } if (!window->initBuffer(localOnly)) { delete window; - return 1; + return 0; } - LOG_WINDOW("native_init_empty: window = %p", window); - SET_WINDOW(env, object, window); - return 0; + LOG_WINDOW("nativeInitializeEmpty: window = %p", window); + return reinterpret_cast<jint>(window); } -static jint native_init_memory(JNIEnv * env, jobject object, jobject memObj) -{ - sp<IMemory> memory = interface_cast<IMemory>(ibinderForJavaObject(env, memObj)); +static jint nativeInitializeFromBinder(JNIEnv* env, jclass clazz, jobject binderObj) { + sp<IMemory> memory = interface_cast<IMemory>(ibinderForJavaObject(env, binderObj)); if (memory == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "Couldn't get native binder"); - return 1; + return 0; } - CursorWindow * window = new CursorWindow(); + CursorWindow* window = new CursorWindow(); if (!window) { - return 1; + return 0; } if (!window->setMemory(memory)) { delete window; - return 1; + return 0; } - LOG_WINDOW("native_init_memory: numRows = %d, numColumns = %d, window = %p", window->getNumRows(), window->getNumColumns(), window); - SET_WINDOW(env, object, window); - return 0; + LOG_WINDOW("nativeInitializeFromBinder: numRows = %d, numColumns = %d, window = %p", + window->getNumRows(), window->getNumColumns(), window); + return reinterpret_cast<jint>(window); } -static jobject native_getBinder(JNIEnv * env, jobject object) -{ - CursorWindow * window = GET_WINDOW(env, object); +static void nativeDispose(JNIEnv* env, jclass clazz, jint windowPtr) { + CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); + if (window) { + LOG_WINDOW("Closing window %p", window); + delete window; + } +} + +static jobject nativeGetBinder(JNIEnv * env, jclass clazz, jint windowPtr) { + CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); if (window) { sp<IMemory> memory = window->getMemory(); if (memory != NULL) { @@ -106,568 +113,484 @@ static jobject native_getBinder(JNIEnv * env, jobject object) return NULL; } -static void native_clear(JNIEnv * env, jobject object) -{ - CursorWindow * window = GET_WINDOW(env, object); -LOG_WINDOW("Clearing window %p", window); - if (window == NULL) { - jniThrowException(env, "java/lang/IllegalStateException", "clear() called after close()"); - return; - } +static void nativeClear(JNIEnv * env, jclass clazz, jint windowPtr) { + CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); + LOG_WINDOW("Clearing window %p", window); window->clear(); } -static void native_close(JNIEnv * env, jobject object) -{ - CursorWindow * window = GET_WINDOW(env, object); - if (window) { -LOG_WINDOW("Closing window %p", window); - delete window; - SET_WINDOW(env, object, 0); - } +static jint nativeGetNumRows(JNIEnv* env, jclass clazz, jint windowPtr) { + CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); + return window->getNumRows(); } -static void throwExceptionWithRowCol(JNIEnv * env, jint row, jint column) -{ - char buf[200]; - snprintf(buf, sizeof(buf), "Couldn't read row %d, col %d from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it", - row, column); - jniThrowException(env, "java/lang/IllegalStateException", buf); +static jboolean nativeSetNumColumns(JNIEnv* env, jclass clazz, jint windowPtr, + jint columnNum) { + CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); + return window->setNumColumns(columnNum); } -static void throwUnknowTypeException(JNIEnv * env, jint type) -{ - char buf[80]; - snprintf(buf, sizeof(buf), "UNKNOWN type %d", type); - jniThrowException(env, "java/lang/IllegalStateException", buf); +static jboolean nativeAllocRow(JNIEnv* env, jclass clazz, jint windowPtr) { + CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); + return window->allocRow() != NULL; } -static jlong getLong_native(JNIEnv * env, jobject object, jint row, jint column) -{ - int32_t err; - CursorWindow * window = GET_WINDOW(env, object); -LOG_WINDOW("Getting long for %d,%d from %p", row, column, window); +static void nativeFreeLastRow(JNIEnv* env, jclass clazz, jint windowPtr) { + CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); + window->freeLastRow(); +} - field_slot_t field; - err = window->read_field_slot(row, column, &field); - if (err != 0) { - throwExceptionWithRowCol(env, row, column); - return 0; - } +static jint nativeGetType(JNIEnv* env, jclass clazz, jint windowPtr, + jint row, jint column) { + CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); + LOG_WINDOW("returning column type affinity for %d,%d from %p", row, column, window); - uint8_t type = field.type; - if (type == FIELD_TYPE_INTEGER) { - int64_t value; - if (window->getLong(row, column, &value)) { - return value; - } - return 0; - } else if (type == FIELD_TYPE_STRING) { - uint32_t size = field.data.buffer.size; - if (size > 0) { -#if WINDOW_STORAGE_UTF8 - return strtoll((char const *)window->offsetToPtr(field.data.buffer.offset), NULL, 0); -#else - String8 ascii((char16_t *) window->offsetToPtr(field.data.buffer.offset), size / 2); - char const * str = ascii.string(); - return strtoll(str, NULL, 0); -#endif - } else { - return 0; - } - } else if (type == FIELD_TYPE_FLOAT) { - double value; - if (window->getDouble(row, column, &value)) { - return value; - } - return 0; - } else if (type == FIELD_TYPE_NULL) { - return 0; - } else if (type == FIELD_TYPE_BLOB) { - throw_sqlite3_exception(env, "Unable to convert BLOB to long"); - return 0; - } else { - throwUnknowTypeException(env, type); - return 0; + field_slot_t* fieldSlot = window->getFieldSlotWithCheck(row, column); + if (!fieldSlot) { + throwExceptionWithRowCol(env, row, column); + return NULL; } + return fieldSlot->type; } -static jbyteArray getBlob_native(JNIEnv* env, jobject object, jint row, jint column) -{ - int32_t err; - CursorWindow * window = GET_WINDOW(env, object); -LOG_WINDOW("Getting blob for %d,%d from %p", row, column, window); +static jbyteArray nativeGetBlob(JNIEnv* env, jclass clazz, jint windowPtr, + jint row, jint column) { + CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); + LOG_WINDOW("Getting blob for %d,%d from %p", row, column, window); - field_slot_t field; - err = window->read_field_slot(row, column, &field); - if (err != 0) { + field_slot_t* fieldSlot = window->getFieldSlotWithCheck(row, column); + if (!fieldSlot) { throwExceptionWithRowCol(env, row, column); return NULL; } - uint8_t type = field.type; + uint8_t type = fieldSlot->type; if (type == FIELD_TYPE_BLOB || type == FIELD_TYPE_STRING) { - jbyteArray byteArray = env->NewByteArray(field.data.buffer.size); + uint32_t size = fieldSlot->data.buffer.size; + jbyteArray byteArray = env->NewByteArray(size); if (!byteArray) { + env->ExceptionClear(); throw_sqlite3_exception(env, "Native could not create new byte[]"); return NULL; } - env->SetByteArrayRegion(byteArray, 0, field.data.buffer.size, - (const jbyte*)window->offsetToPtr(field.data.buffer.offset)); + env->SetByteArrayRegion(byteArray, 0, size, + reinterpret_cast<jbyte*>(window->offsetToPtr(fieldSlot->data.buffer.offset))); return byteArray; } else if (type == FIELD_TYPE_INTEGER) { - throw_sqlite3_exception(env, "INTEGER data in getBlob_native "); + throw_sqlite3_exception(env, "INTEGER data in nativeGetBlob "); } else if (type == FIELD_TYPE_FLOAT) { - throw_sqlite3_exception(env, "FLOAT data in getBlob_native "); + throw_sqlite3_exception(env, "FLOAT data in nativeGetBlob "); } else if (type == FIELD_TYPE_NULL) { // do nothing } else { - throwUnknowTypeException(env, type); + throwUnknownTypeException(env, type); } return NULL; } -static jstring getString_native(JNIEnv* env, jobject object, jint row, jint column) -{ - int32_t err; - CursorWindow * window = GET_WINDOW(env, object); -LOG_WINDOW("Getting string for %d,%d from %p", row, column, window); +static jstring nativeGetString(JNIEnv* env, jclass clazz, jint windowPtr, + jint row, jint column) { + CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); + LOG_WINDOW("Getting string for %d,%d from %p", row, column, window); - field_slot_t field; - err = window->read_field_slot(row, column, &field); - if (err != 0) { + field_slot_t* fieldSlot = window->getFieldSlotWithCheck(row, column); + if (!fieldSlot) { throwExceptionWithRowCol(env, row, column); return NULL; } - uint8_t type = field.type; + uint8_t type = fieldSlot->type; if (type == FIELD_TYPE_STRING) { - uint32_t size = field.data.buffer.size; - if (size > 0) { + uint32_t size = fieldSlot->data.buffer.size; #if WINDOW_STORAGE_UTF8 - // Pass size - 1 since the UTF8 is null terminated and we don't want a null terminator on the UTF16 string - String16 utf16((char const *)window->offsetToPtr(field.data.buffer.offset), size - 1); - return env->NewString((jchar const *)utf16.string(), utf16.size()); + return size > 1 ? env->NewStringUTF(window->getFieldSlotValueString(fieldSlot)) + : gEmptyString; #else - return env->NewString((jchar const *)window->offsetToPtr(field.data.buffer.offset), size / 2); + size_t chars = size / sizeof(char16_t); + return chars ? env->NewString(reinterpret_cast<jchar*>( + window->getFieldSlotValueString(fieldSlot)), chars) + : gEmptyString; #endif - } else { - return env->NewStringUTF(""); - } } else if (type == FIELD_TYPE_INTEGER) { - int64_t value; - if (window->getLong(row, column, &value)) { - char buf[32]; - snprintf(buf, sizeof(buf), "%lld", value); - return env->NewStringUTF(buf); - } - return NULL; + int64_t value = window->getFieldSlotValueLong(fieldSlot); + char buf[32]; + snprintf(buf, sizeof(buf), "%lld", value); + return env->NewStringUTF(buf); } else if (type == FIELD_TYPE_FLOAT) { - double value; - if (window->getDouble(row, column, &value)) { - char buf[32]; - snprintf(buf, sizeof(buf), "%g", value); - return env->NewStringUTF(buf); - } - return NULL; + double value = window->getFieldSlotValueDouble(fieldSlot); + char buf[32]; + snprintf(buf, sizeof(buf), "%g", value); + return env->NewStringUTF(buf); } else if (type == FIELD_TYPE_NULL) { return NULL; } else if (type == FIELD_TYPE_BLOB) { throw_sqlite3_exception(env, "Unable to convert BLOB to string"); return NULL; } else { - throwUnknowTypeException(env, type); + throwUnknownTypeException(env, type); return NULL; } } -/** - * Use this only to convert characters that are known to be within the - * 0-127 range for direct conversion to UTF-16 - */ -static jint charToJchar(const char* src, jchar* dst, jint bufferSize) -{ - int32_t len = strlen(src); +static jcharArray allocCharArrayBuffer(JNIEnv* env, jobject bufferObj, size_t size) { + jcharArray dataObj = jcharArray(env->GetObjectField(bufferObj, + gCharArrayBufferClassInfo.data)); + if (dataObj && size) { + jsize capacity = env->GetArrayLength(dataObj); + if (size_t(capacity) < size) { + env->DeleteLocalRef(dataObj); + dataObj = NULL; + } + } + if (!dataObj) { + jsize capacity = size; + if (capacity < 64) { + capacity = 64; + } + dataObj = env->NewCharArray(capacity); // might throw OOM + if (dataObj) { + env->SetObjectField(bufferObj, gCharArrayBufferClassInfo.data, dataObj); + } + } + return dataObj; +} - if (bufferSize < len) { - len = bufferSize; +static void fillCharArrayBufferUTF(JNIEnv* env, jobject bufferObj, + const char* str, size_t len) { + ssize_t size = utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(str), len); + if (size < 0) { + size = 0; // invalid UTF8 string + } + jcharArray dataObj = allocCharArrayBuffer(env, bufferObj, size); + if (dataObj) { + if (size) { + jchar* data = static_cast<jchar*>(env->GetPrimitiveArrayCritical(dataObj, NULL)); + utf8_to_utf16(reinterpret_cast<const uint8_t*>(str), len, + reinterpret_cast<char16_t*>(data)); + env->ReleasePrimitiveArrayCritical(dataObj, data, 0); + } + env->SetIntField(bufferObj, gCharArrayBufferClassInfo.sizeCopied, size); } +} - for (int i = 0; i < len; i++) { - *dst++ = (*src++ & 0x7F); +#if !WINDOW_STORAGE_UTF8 +static void fillCharArrayBuffer(JNIEnv* env, jobject bufferObj, + const char16_t* str, size_t len) { + jcharArray dataObj = allocCharArrayBuffer(env, bufferObj, len); + if (dataObj) { + if (len) { + jchar* data = static_cast<jchar*>(env->GetPrimitiveArrayCritical(dataObj, NULL)); + memcpy(data, str, len * sizeof(jchar)); + env->ReleasePrimitiveArrayCritical(dataObj, data, 0); + } + env->SetIntField(bufferObj, gCharArrayBufferClassInfo.sizeCopied, len); } - return len; } +#endif -static jcharArray copyStringToBuffer_native(JNIEnv* env, jobject object, jint row, - jint column, jint bufferSize, jobject buf) -{ - int32_t err; - CursorWindow * window = GET_WINDOW(env, object); -LOG_WINDOW("Copying string for %d,%d from %p", row, column, window); - - field_slot_t field; - err = window->read_field_slot(row, column, &field); - if (err != 0) { - jniThrowException(env, "java/lang/IllegalStateException", "Unable to get field slot"); - return NULL; +static void clearCharArrayBuffer(JNIEnv* env, jobject bufferObj) { + jcharArray dataObj = allocCharArrayBuffer(env, bufferObj, 0); + if (dataObj) { + env->SetIntField(bufferObj, gCharArrayBufferClassInfo.sizeCopied, 0); } +} - jcharArray buffer = (jcharArray)env->GetObjectField(buf, gBufferField); - if (buffer == NULL) { - jniThrowException(env, "java/lang/IllegalStateException", "buf should not be null"); - return NULL; +static void nativeCopyStringToBuffer(JNIEnv* env, jclass clazz, jint windowPtr, + jint row, jint column, jobject bufferObj) { + CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); + LOG_WINDOW("Copying string for %d,%d from %p", row, column, window); + + field_slot_t* fieldSlot = window->getFieldSlotWithCheck(row, column); + if (!fieldSlot) { + throwExceptionWithRowCol(env, row, column); + return; } - jchar* dst = env->GetCharArrayElements(buffer, NULL); - uint8_t type = field.type; - uint32_t sizeCopied = 0; - jcharArray newArray = NULL; + + uint8_t type = fieldSlot->type; if (type == FIELD_TYPE_STRING) { - uint32_t size = field.data.buffer.size; - if (size > 0) { + uint32_t size = fieldSlot->data.buffer.size; #if WINDOW_STORAGE_UTF8 - // Pass size - 1 since the UTF8 is null terminated and we don't want a null terminator on the UTF16 string - String16 utf16((char const *)window->offsetToPtr(field.data.buffer.offset), size - 1); - int32_t strSize = utf16.size(); - if (strSize > bufferSize || dst == NULL) { - newArray = env->NewCharArray(strSize); - env->SetCharArrayRegion(newArray, 0, strSize, (jchar const *)utf16.string()); - } else { - memcpy(dst, (jchar const *)utf16.string(), strSize * 2); - } - sizeCopied = strSize; + if (size > 1) { + fillCharArrayBufferUTF(env, bufferObj, + window->getFieldSlotValueString(fieldSlot), size - 1); + } else { + clearCharArrayBuffer(env, bufferObj); + } #else - sizeCopied = size/2 + size % 2; - if (size > bufferSize * 2 || dst == NULL) { - newArray = env->NewCharArray(sizeCopied); - memcpy(newArray, (jchar const *)window->offsetToPtr(field.data.buffer.offset), size); - } else { - memcpy(dst, (jchar const *)window->offsetToPtr(field.data.buffer.offset), size); - } -#endif + size_t chars = size / sizeof(char16_t); + if (chars) { + fillCharArrayBuffer(env, bufferObj, + window->getFieldSlotValueString(fieldSlot), chars); + } else { + clearCharArrayBuffer(env, bufferObj); } +#endif } else if (type == FIELD_TYPE_INTEGER) { - int64_t value; - if (window->getLong(row, column, &value)) { - char buf[32]; - int len; - snprintf(buf, sizeof(buf), "%lld", value); - sizeCopied = charToJchar(buf, dst, bufferSize); - } + int64_t value = window->getFieldSlotValueLong(fieldSlot); + char buf[32]; + snprintf(buf, sizeof(buf), "%lld", value); + fillCharArrayBufferUTF(env, bufferObj, buf, strlen(buf)); } else if (type == FIELD_TYPE_FLOAT) { - double value; - if (window->getDouble(row, column, &value)) { - char tempbuf[32]; - snprintf(tempbuf, sizeof(tempbuf), "%g", value); - sizeCopied = charToJchar(tempbuf, dst, bufferSize); - } + double value = window->getFieldSlotValueDouble(fieldSlot); + char buf[32]; + snprintf(buf, sizeof(buf), "%g", value); + fillCharArrayBufferUTF(env, bufferObj, buf, strlen(buf)); } else if (type == FIELD_TYPE_NULL) { + clearCharArrayBuffer(env, bufferObj); } else if (type == FIELD_TYPE_BLOB) { throw_sqlite3_exception(env, "Unable to convert BLOB to string"); } else { - LOGE("Unknown field type %d", type); - throw_sqlite3_exception(env, "UNKNOWN type in copyStringToBuffer_native()"); + throwUnknownTypeException(env, type); } - SET_SIZE_COPIED(env, buf, sizeCopied); - env->ReleaseCharArrayElements(buffer, dst, JNI_OK); - return newArray; } -static jdouble getDouble_native(JNIEnv* env, jobject object, jint row, jint column) -{ - int32_t err; - CursorWindow * window = GET_WINDOW(env, object); -LOG_WINDOW("Getting double for %d,%d from %p", row, column, window); +static jlong nativeGetLong(JNIEnv* env, jclass clazz, jint windowPtr, + jint row, jint column) { + CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); + LOG_WINDOW("Getting long for %d,%d from %p", row, column, window); - field_slot_t field; - err = window->read_field_slot(row, column, &field); - if (err != 0) { + field_slot_t* fieldSlot = window->getFieldSlotWithCheck(row, column); + if (!fieldSlot) { + throwExceptionWithRowCol(env, row, column); + return 0; + } + + uint8_t type = fieldSlot->type; + if (type == FIELD_TYPE_INTEGER) { + return window->getFieldSlotValueLong(fieldSlot); + } else if (type == FIELD_TYPE_STRING) { + uint32_t size = fieldSlot->data.buffer.size; +#if WINDOW_STORAGE_UTF8 + return size > 1 ? strtoll(window->getFieldSlotValueString(fieldSlot), NULL, 0) : 0L; +#else + size_t chars = size / sizeof(char16_t); + return chars ? strtoll(String8(window->getFieldSlotValueString(fieldSlot), chars) + .string(), NULL, 0) : 0L; +#endif + } else if (type == FIELD_TYPE_FLOAT) { + return jlong(window->getFieldSlotValueDouble(fieldSlot)); + } else if (type == FIELD_TYPE_NULL) { + return 0; + } else if (type == FIELD_TYPE_BLOB) { + throw_sqlite3_exception(env, "Unable to convert BLOB to long"); + return 0; + } else { + throwUnknownTypeException(env, type); + return 0; + } +} + +static jdouble nativeGetDouble(JNIEnv* env, jclass clazz, jint windowPtr, + jint row, jint column) { + CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); + LOG_WINDOW("Getting double for %d,%d from %p", row, column, window); + + field_slot_t* fieldSlot = window->getFieldSlotWithCheck(row, column); + if (!fieldSlot) { throwExceptionWithRowCol(env, row, column); return 0.0; } - uint8_t type = field.type; + uint8_t type = fieldSlot->type; if (type == FIELD_TYPE_FLOAT) { - double value; - if (window->getDouble(row, column, &value)) { - return value; - } - return 0.0; + return window->getFieldSlotValueDouble(fieldSlot); } else if (type == FIELD_TYPE_STRING) { - uint32_t size = field.data.buffer.size; - if (size > 0) { + uint32_t size = fieldSlot->data.buffer.size; #if WINDOW_STORAGE_UTF8 - return strtod((char const *)window->offsetToPtr(field.data.buffer.offset), NULL); + return size > 1 ? strtod(window->getFieldSlotValueString(fieldSlot), NULL) : 0.0; #else - String8 ascii((char16_t *) window->offsetToPtr(field.data.buffer.offset), size / 2); - char const * str = ascii.string(); - return strtod(str, NULL); + size_t chars = size / sizeof(char16_t); + return chars ? strtod(String8(window->getFieldSlotValueString(fieldSlot), chars) + .string(), NULL) : 0.0; #endif - } else { - return 0.0; - } } else if (type == FIELD_TYPE_INTEGER) { - int64_t value; - if (window->getLong(row, column, &value)) { - return (double) value; - } - return 0.0; + return jdouble(window->getFieldSlotValueLong(fieldSlot)); } else if (type == FIELD_TYPE_NULL) { return 0.0; } else if (type == FIELD_TYPE_BLOB) { throw_sqlite3_exception(env, "Unable to convert BLOB to double"); return 0.0; } else { - throwUnknowTypeException(env, type); + throwUnknownTypeException(env, type); return 0.0; } } -bool isNull_native(CursorWindow *window, jint row, jint column) -{ - LOG_WINDOW("Checking for NULL at %d,%d from %p", row, column, window); - - bool isNull; - if (window->getNull(row, column, &isNull)) { - return isNull; - } - - //TODO throw execption? - return true; -} - -static jint getNumRows(JNIEnv * env, jobject object) -{ - CursorWindow * window = GET_WINDOW(env, object); - return window->getNumRows(); -} - -static jboolean setNumColumns(JNIEnv * env, jobject object, jint columnNum) -{ - CursorWindow * window = GET_WINDOW(env, object); - return window->setNumColumns(columnNum); -} - -static jboolean allocRow(JNIEnv * env, jobject object) -{ - CursorWindow * window = GET_WINDOW(env, object); - return window->allocRow() != NULL; -} - -static jboolean putBlob_native(JNIEnv * env, jobject object, jbyteArray value, jint row, jint col) -{ - CursorWindow * window = GET_WINDOW(env, object); - if (!value) { - LOG_WINDOW("How did a null value send to here"); - return false; - } - field_slot_t * fieldSlot = window->getFieldSlotWithCheck(row, col); +static jboolean nativePutBlob(JNIEnv* env, jclass clazz, jint windowPtr, + jbyteArray valueObj, jint row, jint column) { + CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); + field_slot_t * fieldSlot = window->getFieldSlotWithCheck(row, column); if (fieldSlot == NULL) { LOG_WINDOW(" getFieldSlotWithCheck error "); return false; } - jint len = env->GetArrayLength(value); - int offset = window->alloc(len); + jsize len = env->GetArrayLength(valueObj); + uint32_t offset = window->alloc(len); if (!offset) { LOG_WINDOW("Failed allocating %u bytes", len); return false; } - jbyte * bytes = env->GetByteArrayElements(value, NULL); - window->copyIn(offset, (uint8_t const *)bytes, len); - // This must be updated after the call to alloc(), since that - // may move the field around in the window + void* value = env->GetPrimitiveArrayCritical(valueObj, NULL); + window->copyIn(offset, static_cast<const uint8_t*>(value), len); + env->ReleasePrimitiveArrayCritical(valueObj, value, JNI_ABORT); + fieldSlot->type = FIELD_TYPE_BLOB; fieldSlot->data.buffer.offset = offset; fieldSlot->data.buffer.size = len; - env->ReleaseByteArrayElements(value, bytes, JNI_ABORT); - LOG_WINDOW("%d,%d is BLOB with %u bytes @ %d", row, col, len, offset); + LOG_WINDOW("%d,%d is BLOB with %u bytes @ %d", row, column, len, offset); return true; } -static jboolean putString_native(JNIEnv * env, jobject object, jstring value, jint row, jint col) -{ - CursorWindow * window = GET_WINDOW(env, object); - if (!value) { - LOG_WINDOW("How did a null value send to here"); - return false; - } - field_slot_t * fieldSlot = window->getFieldSlotWithCheck(row, col); +static jboolean nativePutString(JNIEnv* env, jclass clazz, jint windowPtr, + jstring valueObj, jint row, jint column) { + CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); + field_slot_t * fieldSlot = window->getFieldSlotWithCheck(row, column); if (fieldSlot == NULL) { LOG_WINDOW(" getFieldSlotWithCheck error "); return false; } #if WINDOW_STORAGE_UTF8 - int len = env->GetStringUTFLength(value) + 1; - char const * valStr = env->GetStringUTFChars(value, NULL); + size_t size = env->GetStringUTFLength(valueObj) + 1; + const char* valueStr = env->GetStringUTFChars(valueObj, NULL); #else - int len = env->GetStringLength(value); - // GetStringLength return number of chars and one char takes 2 bytes - len *= 2; - const jchar* valStr = env->GetStringChars(value, NULL); + size_t size = env->GetStringLength(valueObj) * sizeof(jchar); + const jchar* valueStr = env->GetStringChars(valueObj, NULL); #endif - if (!valStr) { + if (!valueStr) { LOG_WINDOW("value can't be transfer to UTFChars"); return false; } - int offset = window->alloc(len); + uint32_t offset = window->alloc(size); if (!offset) { - LOG_WINDOW("Failed allocating %u bytes", len); + LOG_WINDOW("Failed allocating %u bytes", size); #if WINDOW_STORAGE_UTF8 - env->ReleaseStringUTFChars(value, valStr); + env->ReleaseStringUTFChars(valueObj, valueStr); #else - env->ReleaseStringChars(value, valStr); + env->ReleaseStringChars(valueObj, valueStr); #endif return false; } - window->copyIn(offset, (uint8_t const *)valStr, len); - - // This must be updated after the call to alloc(), since that - // may move the field around in the window - fieldSlot->type = FIELD_TYPE_STRING; - fieldSlot->data.buffer.offset = offset; - fieldSlot->data.buffer.size = len; + window->copyIn(offset, reinterpret_cast<const uint8_t*>(valueStr), size); - LOG_WINDOW("%d,%d is TEXT with %u bytes @ %d", row, col, len, offset); #if WINDOW_STORAGE_UTF8 - env->ReleaseStringUTFChars(value, valStr); + env->ReleaseStringUTFChars(valueObj, valueStr); #else - env->ReleaseStringChars(value, valStr); + env->ReleaseStringChars(valueObj, valueStr); #endif + fieldSlot->type = FIELD_TYPE_STRING; + fieldSlot->data.buffer.offset = offset; + fieldSlot->data.buffer.size = size; + LOG_WINDOW("%d,%d is TEXT with %u bytes @ %d", row, column, size, offset); return true; } -static jboolean putLong_native(JNIEnv * env, jobject object, jlong value, jint row, jint col) -{ - CursorWindow * window = GET_WINDOW(env, object); - if (!window->putLong(row, col, value)) { +static jboolean nativePutLong(JNIEnv* env, jclass clazz, jint windowPtr, + jlong value, jint row, jint column) { + CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); + if (!window->putLong(row, column, value)) { LOG_WINDOW(" getFieldSlotWithCheck error "); return false; } - LOG_WINDOW("%d,%d is INTEGER 0x%016llx", row, col, value); - + LOG_WINDOW("%d,%d is INTEGER 0x%016llx", row, column, value); return true; } -static jboolean putDouble_native(JNIEnv * env, jobject object, jdouble value, jint row, jint col) -{ - CursorWindow * window = GET_WINDOW(env, object); - if (!window->putDouble(row, col, value)) { +static jboolean nativePutDouble(JNIEnv* env, jclass clazz, jint windowPtr, + jdouble value, jint row, jint column) { + CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); + if (!window->putDouble(row, column, value)) { LOG_WINDOW(" getFieldSlotWithCheck error "); return false; } - LOG_WINDOW("%d,%d is FLOAT %lf", row, col, value); - + LOG_WINDOW("%d,%d is FLOAT %lf", row, column, value); return true; } -static jboolean putNull_native(JNIEnv * env, jobject object, jint row, jint col) -{ - CursorWindow * window = GET_WINDOW(env, object); - if (!window->putNull(row, col)) { +static jboolean nativePutNull(JNIEnv* env, jclass clazz, jint windowPtr, + jint row, jint column) { + CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); + if (!window->putNull(row, column)) { LOG_WINDOW(" getFieldSlotWithCheck error "); return false; } - LOG_WINDOW("%d,%d is NULL", row, col); - + LOG_WINDOW("%d,%d is NULL", row, column); return true; } -// free the last row -static void freeLastRow(JNIEnv * env, jobject object) { - CursorWindow * window = GET_WINDOW(env, object); - window->freeLastRow(); -} - -static jint getType_native(JNIEnv* env, jobject object, jint row, jint column) -{ - int32_t err; - CursorWindow * window = GET_WINDOW(env, object); - LOG_WINDOW("returning column type affinity for %d,%d from %p", row, column, window); - - if (isNull_native(window, row, column)) { - return FIELD_TYPE_NULL; - } - - field_slot_t field; - err = window->read_field_slot(row, column, &field); - if (err != 0) { - throwExceptionWithRowCol(env, row, column); - return NULL; - } - - return field.type; -} - static JNINativeMethod sMethods[] = { - /* name, signature, funcPtr */ - {"native_init", "(IZ)I", (void *)native_init_empty}, - {"native_init", "(Landroid/os/IBinder;)I", (void *)native_init_memory}, - {"native_getBinder", "()Landroid/os/IBinder;", (void *)native_getBinder}, - {"native_clear", "()V", (void *)native_clear}, - {"close_native", "()V", (void *)native_close}, - {"getLong_native", "(II)J", (void *)getLong_native}, - {"getBlob_native", "(II)[B", (void *)getBlob_native}, - {"getString_native", "(II)Ljava/lang/String;", (void *)getString_native}, - {"copyStringToBuffer_native", "(IIILandroid/database/CharArrayBuffer;)[C", (void *)copyStringToBuffer_native}, - {"getDouble_native", "(II)D", (void *)getDouble_native}, - {"getNumRows_native", "()I", (void *)getNumRows}, - {"setNumColumns_native", "(I)Z", (void *)setNumColumns}, - {"allocRow_native", "()Z", (void *)allocRow}, - {"putBlob_native", "([BII)Z", (void *)putBlob_native}, - {"putString_native", "(Ljava/lang/String;II)Z", (void *)putString_native}, - {"putLong_native", "(JII)Z", (void *)putLong_native}, - {"putDouble_native", "(DII)Z", (void *)putDouble_native}, - {"freeLastRow_native", "()V", (void *)freeLastRow}, - {"putNull_native", "(II)Z", (void *)putNull_native}, - {"getType_native", "(II)I", (void *)getType_native}, + /* name, signature, funcPtr */ + { "nativeInitializeEmpty", "(IZ)I", + (void*)nativeInitializeEmpty }, + { "nativeInitializeFromBinder", "(Landroid/os/IBinder;)I", + (void*)nativeInitializeFromBinder }, + { "nativeDispose", "(I)V", + (void*)nativeDispose }, + { "nativeGetBinder", "(I)Landroid/os/IBinder;", + (void*)nativeGetBinder }, + { "nativeClear", "(I)V", + (void*)nativeClear }, + { "nativeGetNumRows", "(I)I", + (void*)nativeGetNumRows }, + { "nativeSetNumColumns", "(II)Z", + (void*)nativeSetNumColumns }, + { "nativeAllocRow", "(I)Z", + (void*)nativeAllocRow }, + { "nativeFreeLastRow", "(I)V", + (void*)nativeFreeLastRow }, + { "nativeGetType", "(III)I", + (void*)nativeGetType }, + { "nativeGetBlob", "(III)[B", + (void*)nativeGetBlob }, + { "nativeGetString", "(III)Ljava/lang/String;", + (void*)nativeGetString }, + { "nativeGetLong", "(III)J", + (void*)nativeGetLong }, + { "nativeGetDouble", "(III)D", + (void*)nativeGetDouble }, + { "nativeCopyStringToBuffer", "(IIILandroid/database/CharArrayBuffer;)V", + (void*)nativeCopyStringToBuffer }, + { "nativePutBlob", "(I[BII)Z", + (void*)nativePutBlob }, + { "nativePutString", "(ILjava/lang/String;II)Z", + (void*)nativePutString }, + { "nativePutLong", "(IJII)Z", + (void*)nativePutLong }, + { "nativePutDouble", "(IDII)Z", + (void*)nativePutDouble }, + { "nativePutNull", "(III)Z", + (void*)nativePutNull }, }; +#define FIND_CLASS(var, className) \ + var = env->FindClass(className); \ + LOG_FATAL_IF(! var, "Unable to find class " className); + +#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ + var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find field " fieldName); + int register_android_database_CursorWindow(JNIEnv * env) { jclass clazz; + FIND_CLASS(clazz, "android/database/CharArrayBuffer"); - clazz = env->FindClass("android/database/CursorWindow"); - if (clazz == NULL) { - LOGE("Can't find android/database/CursorWindow"); - return -1; - } - - gWindowField = env->GetFieldID(clazz, "nWindow", "I"); - - if (gWindowField == NULL) { - LOGE("Error locating fields"); - return -1; - } - - clazz = env->FindClass("android/database/CharArrayBuffer"); - if (clazz == NULL) { - LOGE("Can't find android/database/CharArrayBuffer"); - return -1; - } + GET_FIELD_ID(gCharArrayBufferClassInfo.data, clazz, + "data", "[C"); + GET_FIELD_ID(gCharArrayBufferClassInfo.sizeCopied, clazz, + "sizeCopied", "I"); - gBufferField = env->GetFieldID(clazz, "data", "[C"); - - if (gBufferField == NULL) { - LOGE("Error locating fields data in CharArrayBuffer"); - return -1; - } - - gSizeCopiedField = env->GetFieldID(clazz, "sizeCopied", "I"); - - if (gSizeCopiedField == NULL) { - LOGE("Error locating fields sizeCopied in CharArrayBuffer"); - return -1; - } + gEmptyString = jstring(env->NewGlobalRef(env->NewStringUTF(""))); + LOG_FATAL_IF(!gEmptyString, "Unable to create empty string"); return AndroidRuntime::registerNativeMethods(env, "android/database/CursorWindow", sMethods, NELEM(sMethods)); diff --git a/core/jni/android_database_SQLiteQuery.cpp b/core/jni/android_database_SQLiteQuery.cpp index 9e42189..fe62256 100644 --- a/core/jni/android_database_SQLiteQuery.cpp +++ b/core/jni/android_database_SQLiteQuery.cpp @@ -35,12 +35,6 @@ namespace android { -sqlite3_stmt * compile(JNIEnv* env, jobject object, - sqlite3 * handle, jstring sqlString); - -// From android_database_CursorWindow.cpp -CursorWindow * get_window_from_object(JNIEnv * env, jobject javaWindow); - static jfieldID gHandleField; static jfieldID gStatementField; @@ -105,7 +99,7 @@ static int finish_program_and_get_row_count(sqlite3_stmt *statement) { return numRows; } -static jint native_fill_window(JNIEnv* env, jobject object, jobject javaWindow, +static jint native_fill_window(JNIEnv* env, jobject object, jint windowPtr, jint startPos, jint offsetParam, jint maxRead, jint lastPos) { int err; @@ -142,7 +136,7 @@ static jint native_fill_window(JNIEnv* env, jobject object, jobject javaWindow, } // Get the native window - window = get_window_from_object(env, javaWindow); + window = reinterpret_cast<CursorWindow*>(windowPtr); if (!window) { LOGE("Invalid CursorWindow"); jniThrowException(env, "java/lang/IllegalArgumentException", @@ -360,7 +354,7 @@ static jstring native_column_name(JNIEnv* env, jobject object, jint columnIndex) static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ - {"native_fill_window", "(Landroid/database/CursorWindow;IIII)I", + {"native_fill_window", "(IIIII)I", (void *)native_fill_window}, {"native_column_count", "()I", (void*)native_column_count}, {"native_column_name", "(I)Ljava/lang/String;", (void *)native_column_name}, diff --git a/include/android_runtime/AndroidRuntime.h b/include/android_runtime/AndroidRuntime.h index 32cd4f5..fd33d59 100644 --- a/include/android_runtime/AndroidRuntime.h +++ b/include/android_runtime/AndroidRuntime.h @@ -31,8 +31,6 @@ namespace android { -class CursorWindow; - class AndroidRuntime { public: @@ -133,8 +131,6 @@ private: static int javaThreadShell(void* args); }; -extern CursorWindow * get_window_from_object(JNIEnv * env, jobject javaWindow); - } #endif diff --git a/include/binder/CursorWindow.h b/include/binder/CursorWindow.h index f0b2909..d227244 100644 --- a/include/binder/CursorWindow.h +++ b/include/binder/CursorWindow.h @@ -143,8 +143,6 @@ public: */ uint32_t alloc(size_t size, bool aligned = false); - uint32_t read_field_slot(int row, int column, field_slot_t * slot); - /** * Copy data into the window at the given offset. */ @@ -181,6 +179,32 @@ public: return ((field_slot_t *)offsetToPtr(fieldDirOffset)) + column; } + int64_t getFieldSlotValueLong(field_slot_t* fieldSlot) { +#if WINDOW_STORAGE_INLINE_NUMERICS + return fieldSlot->data.l; +#else + return copyOutLong(fieldSlot->data.buffer.offset); +#endif + } + + double getFieldSlotValueDouble(field_slot_t* fieldSlot) { +#if WINDOW_STORAGE_INLINE_NUMERICS + return fieldSlot->data.d; +#else + return copyOutDouble(fieldSlot->data.buffer.offset); +#endif + } + +#if WINDOW_STORAGE_UTF8 + char* getFieldSlotValueString(field_slot_t* fieldSlot) { + return reinterpret_cast<char*>(offsetToPtr(fieldSlot->data.buffer.offset)); + } +#else + char16_t* getFieldSlotValueString(field_slot_t* fieldSlot) { + return reinterpret_cast<char16_t*>(offsetToPtr(fieldSlot->data.buffer.offset)); + } +#endif + private: uint8_t * mData; size_t mSize; diff --git a/libs/binder/CursorWindow.cpp b/libs/binder/CursorWindow.cpp index 47bbd04..b02374f 100644 --- a/libs/binder/CursorWindow.cpp +++ b/libs/binder/CursorWindow.cpp @@ -236,33 +236,6 @@ field_slot_t * CursorWindow::getFieldSlotWithCheck(int row, int column) return ((field_slot_t *)offsetToPtr(fieldDirOffset)) + column; } -uint32_t CursorWindow::read_field_slot(int row, int column, field_slot_t * slotOut) -{ - if (row < 0 || row >= mHeader->numRows || column < 0 || column >= mHeader->numColumns) { - LOGE("Can't read row# %d, col# %d from CursorWindow. Make sure your Cursor is initialized correctly.", - row, column); - return -1; - } - row_slot_t * rowSlot = getRowSlot(row); - if (!rowSlot) { - LOGE("Failed to find rowSlot for row %d", row); - return -1; - } - if (rowSlot->offset == 0 || rowSlot->offset >= mSize) { - LOGE("Invalid rowSlot, offset = %d", rowSlot->offset); - return -1; - } -LOG_WINDOW("Found field directory for %d,%d at rowSlot %d, offset %d", row, column, (uint8_t *)rowSlot - mData, rowSlot->offset); - field_slot_t * fieldDir = (field_slot_t *)offsetToPtr(rowSlot->offset); -LOG_WINDOW("Read field_slot_t %d,%d: offset = %d, size = %d, type = %d", row, column, fieldDir[column].data.buffer.offset, fieldDir[column].data.buffer.size, fieldDir[column].type); - - // Copy the data to the out param - slotOut->data.buffer.offset = fieldDir[column].data.buffer.offset; - slotOut->data.buffer.size = fieldDir[column].data.buffer.size; - slotOut->type = fieldDir[column].type; - return 0; -} - void CursorWindow::copyIn(uint32_t offset, uint8_t const * data, size_t size) { assert(offset + size <= mSize); @@ -370,12 +343,8 @@ bool CursorWindow::getLong(unsigned int row, unsigned int col, int64_t * valueOu if (!fieldSlot || fieldSlot->type != FIELD_TYPE_INTEGER) { return false; } - -#if WINDOW_STORAGE_INLINE_NUMERICS - *valueOut = fieldSlot->data.l; -#else - *valueOut = copyOutLong(fieldSlot->data.buffer.offset); -#endif + + *valueOut = getFieldSlotValueLong(fieldSlot); return true; } @@ -386,11 +355,7 @@ bool CursorWindow::getDouble(unsigned int row, unsigned int col, double * valueO return false; } -#if WINDOW_STORAGE_INLINE_NUMERICS - *valueOut = fieldSlot->data.d; -#else - *valueOut = copyOutDouble(fieldSlot->data.buffer.offset); -#endif + *valueOut = getFieldSlotValueDouble(fieldSlot); return true; } |