diff options
-rw-r--r-- | api/current.xml | 60 | ||||
-rw-r--r-- | core/java/android/content/res/AssetFileDescriptor.java | 92 | ||||
-rw-r--r-- | core/java/android/database/DatabaseUtils.java | 29 | ||||
-rw-r--r-- | core/java/android/database/sqlite/SQLiteContentHelper.java | 92 | ||||
-rw-r--r-- | core/java/android/database/sqlite/SQLiteStatement.java | 32 | ||||
-rw-r--r-- | core/java/android/os/MemoryFile.java | 89 | ||||
-rw-r--r-- | core/java/android/os/ParcelFileDescriptor.java | 20 | ||||
-rw-r--r-- | core/jni/android_database_SQLiteStatement.cpp | 107 | ||||
-rw-r--r-- | core/tests/coretests/src/android/content/MemoryFileProvider.java | 51 | ||||
-rw-r--r-- | core/tests/coretests/src/android/content/MemoryFileProviderTest.java | 1 | ||||
-rw-r--r-- | core/tests/coretests/src/android/os/MemoryFileTest.java | 45 | ||||
-rw-r--r-- | graphics/java/android/graphics/BitmapFactory.java | 19 | ||||
-rw-r--r-- | preloaded-classes | 1 |
13 files changed, 263 insertions, 375 deletions
diff --git a/api/current.xml b/api/current.xml index a4f52b8..7b3b9e5 100644 --- a/api/current.xml +++ b/api/current.xml @@ -62314,6 +62314,38 @@ <parameter name="value" type="java.lang.Object"> </parameter> </method> +<method name="blobFileDescriptorForQuery" + return="android.os.ParcelFileDescriptor" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="db" type="android.database.sqlite.SQLiteDatabase"> +</parameter> +<parameter name="query" type="java.lang.String"> +</parameter> +<parameter name="selectionArgs" type="java.lang.String[]"> +</parameter> +</method> +<method name="blobFileDescriptorForQuery" + return="android.os.ParcelFileDescriptor" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="prog" type="android.database.sqlite.SQLiteStatement"> +</parameter> +<parameter name="selectionArgs" type="java.lang.String[]"> +</parameter> +</method> <method name="createDbFromSqlStatements" return="void" abstract="false" @@ -66129,6 +66161,17 @@ visibility="public" > </method> +<method name="simpleQueryForBlobFileDescriptor" + return="android.os.ParcelFileDescriptor" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="simpleQueryForLong" return="long" abstract="false" @@ -134578,6 +134621,23 @@ visibility="public" > </method> +<method name="fromData" + return="android.os.ParcelFileDescriptor" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="data" type="byte[]"> +</parameter> +<parameter name="name" type="java.lang.String"> +</parameter> +<exception name="IOException" type="java.io.IOException"> +</exception> +</method> <method name="fromSocket" return="android.os.ParcelFileDescriptor" abstract="false" diff --git a/core/java/android/content/res/AssetFileDescriptor.java b/core/java/android/content/res/AssetFileDescriptor.java index ccb8605..01ae1da 100644 --- a/core/java/android/content/res/AssetFileDescriptor.java +++ b/core/java/android/content/res/AssetFileDescriptor.java @@ -25,8 +25,6 @@ import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; -import java.nio.channels.FileChannel; /** * File descriptor of an entry in the AssetManager. This provides your own @@ -51,7 +49,7 @@ public class AssetFileDescriptor implements Parcelable { * @param startOffset The location within the file that the asset starts. * This must be 0 if length is UNKNOWN_LENGTH. * @param length The number of bytes of the asset, or - * {@link #UNKNOWN_LENGTH if it extends to the end of the file. + * {@link #UNKNOWN_LENGTH} if it extends to the end of the file. */ public AssetFileDescriptor(ParcelFileDescriptor fd, long startOffset, long length) { @@ -125,17 +123,6 @@ public class AssetFileDescriptor implements Parcelable { public void close() throws IOException { mFd.close(); } - - /** - * Checks whether this file descriptor is for a memory file. - */ - private boolean isMemoryFile() { - try { - return MemoryFile.isMemoryFile(mFd.getFileDescriptor()); - } catch (IOException e) { - return false; - } - } /** * Create and return a new auto-close input stream for this asset. This @@ -146,12 +133,6 @@ public class AssetFileDescriptor implements Parcelable { * should only call this once for a particular asset. */ public FileInputStream createInputStream() throws IOException { - if (isMemoryFile()) { - if (mLength > Integer.MAX_VALUE) { - throw new IOException("File length too large for a memory file: " + mLength); - } - return new AutoCloseMemoryFileInputStream(mFd, (int)mLength); - } if (mLength < 0) { return new ParcelFileDescriptor.AutoCloseInputStream(mFd); } @@ -280,66 +261,6 @@ public class AssetFileDescriptor implements Parcelable { super.reset(); } } - - /** - * An input stream that reads from a MemoryFile and closes it when the stream is closed. - * This extends FileInputStream just because {@link #createInputStream} returns - * a FileInputStream. All the FileInputStream methods are - * overridden to use the MemoryFile instead. - */ - private static class AutoCloseMemoryFileInputStream extends FileInputStream { - private ParcelFileDescriptor mParcelFd; - private MemoryFile mFile; - private InputStream mStream; - - public AutoCloseMemoryFileInputStream(ParcelFileDescriptor fd, int length) - throws IOException { - super(fd.getFileDescriptor()); - mParcelFd = fd; - mFile = new MemoryFile(fd.getFileDescriptor(), length, "r"); - mStream = mFile.getInputStream(); - } - - @Override - public int available() throws IOException { - return mStream.available(); - } - - @Override - public void close() throws IOException { - mParcelFd.close(); // must close ParcelFileDescriptor, not just the file descriptor, - // since it could be a subclass of ParcelFileDescriptor. - // E.g. ContentResolver.ParcelFileDescriptorInner.close() releases - // a content provider - mFile.close(); // to unmap the memory file from the address space. - mStream.close(); // doesn't actually do anything - } - - @Override - public FileChannel getChannel() { - return null; - } - - @Override - public int read() throws IOException { - return mStream.read(); - } - - @Override - public int read(byte[] buffer, int offset, int count) throws IOException { - return mStream.read(buffer, offset, count); - } - - @Override - public int read(byte[] buffer) throws IOException { - return mStream.read(buffer); - } - - @Override - public long skip(long count) throws IOException { - return mStream.skip(count); - } - } /** * An OutputStream you can create on a ParcelFileDescriptor, which will @@ -426,15 +347,4 @@ public class AssetFileDescriptor implements Parcelable { } }; - /** - * Creates an AssetFileDescriptor from a memory file. - * - * @hide - */ - public static AssetFileDescriptor fromMemoryFile(MemoryFile memoryFile) - throws IOException { - ParcelFileDescriptor fd = memoryFile.getParcelFileDescriptor(); - return new AssetFileDescriptor(fd, 0, memoryFile.length()); - } - } diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java index c07c3c6..03aa968 100644 --- a/core/java/android/database/DatabaseUtils.java +++ b/core/java/android/database/DatabaseUtils.java @@ -31,6 +31,7 @@ import android.database.sqlite.SQLiteFullException; import android.database.sqlite.SQLiteProgram; import android.database.sqlite.SQLiteStatement; import android.os.Parcel; +import android.os.ParcelFileDescriptor; import android.text.TextUtils; import android.util.Config; import android.util.Log; @@ -705,6 +706,34 @@ public class DatabaseUtils { } /** + * Utility method to run the query on the db and return the blob value in the + * first column of the first row. + * + * @return A read-only file descriptor for a copy of the blob value. + */ + public static ParcelFileDescriptor blobFileDescriptorForQuery(SQLiteDatabase db, + String query, String[] selectionArgs) { + SQLiteStatement prog = db.compileStatement(query); + try { + return blobFileDescriptorForQuery(prog, selectionArgs); + } finally { + prog.close(); + } + } + + /** + * Utility method to run the pre-compiled query and return the blob value in the + * first column of the first row. + * + * @return A read-only file descriptor for a copy of the blob value. + */ + public static ParcelFileDescriptor blobFileDescriptorForQuery(SQLiteStatement prog, + String[] selectionArgs) { + prog.bindAllArgsAsStrings(selectionArgs); + return prog.simpleQueryForBlobFileDescriptor(); + } + + /** * Reads a String out of a column in a Cursor and writes it to a ContentValues. * Adds nothing to the ContentValues if the column isn't present or if its value is null. * diff --git a/core/java/android/database/sqlite/SQLiteContentHelper.java b/core/java/android/database/sqlite/SQLiteContentHelper.java deleted file mode 100644 index 2800d86..0000000 --- a/core/java/android/database/sqlite/SQLiteContentHelper.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.database.sqlite; - -import android.content.res.AssetFileDescriptor; -import android.database.Cursor; -import android.os.MemoryFile; - -import java.io.FileNotFoundException; -import java.io.IOException; - -/** - * Some helper functions for using SQLite database to implement content providers. - * - * @hide - */ -public class SQLiteContentHelper { - - /** - * Runs an SQLite query and returns an AssetFileDescriptor for the - * blob in column 0 of the first row. If the first column does - * not contain a blob, an unspecified exception is thrown. - * - * @param db Handle to a readable database. - * @param sql SQL query, possibly with query arguments. - * @param selectionArgs Query argument values, or {@code null} for no argument. - * @return If no exception is thrown, a non-null AssetFileDescriptor is returned. - * @throws FileNotFoundException If the query returns no results or the - * value of column 0 is NULL, or if there is an error creating the - * asset file descriptor. - */ - public static AssetFileDescriptor getBlobColumnAsAssetFile(SQLiteDatabase db, String sql, - String[] selectionArgs) throws FileNotFoundException { - try { - MemoryFile file = simpleQueryForBlobMemoryFile(db, sql, selectionArgs); - if (file == null) { - throw new FileNotFoundException("No results."); - } - return AssetFileDescriptor.fromMemoryFile(file); - } catch (IOException ex) { - throw new FileNotFoundException(ex.toString()); - } - } - - /** - * Runs an SQLite query and returns a MemoryFile for the - * blob in column 0 of the first row. If the first column does - * not contain a blob, an unspecified exception is thrown. - * - * @return A memory file, or {@code null} if the query returns no results - * or the value column 0 is NULL. - * @throws IOException If there is an error creating the memory file. - */ - // TODO: make this native and use the SQLite blob API to reduce copying - private static MemoryFile simpleQueryForBlobMemoryFile(SQLiteDatabase db, String sql, - String[] selectionArgs) throws IOException { - Cursor cursor = db.rawQuery(sql, selectionArgs); - if (cursor == null) { - return null; - } - try { - if (!cursor.moveToFirst()) { - return null; - } - byte[] bytes = cursor.getBlob(0); - if (bytes == null) { - return null; - } - MemoryFile file = new MemoryFile(null, bytes.length); - file.writeBytes(bytes, 0, 0, bytes.length); - file.deactivate(); - return file; - } finally { - cursor.close(); - } - } - -} diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java index 97e39d6..14de60f 100644 --- a/core/java/android/database/sqlite/SQLiteStatement.java +++ b/core/java/android/database/sqlite/SQLiteStatement.java @@ -17,7 +17,11 @@ package android.database.sqlite; import android.database.DatabaseUtils; +import android.os.ParcelFileDescriptor; import android.os.SystemClock; +import android.util.Log; + +import java.io.IOException; import dalvik.system.BlockGuard; @@ -33,6 +37,9 @@ import dalvik.system.BlockGuard; @SuppressWarnings("deprecation") public class SQLiteStatement extends SQLiteProgram { + + private static final String TAG = "SQLiteStatement"; + private static final boolean READ = true; private static final boolean WRITE = false; @@ -150,6 +157,30 @@ public class SQLiteStatement extends SQLiteProgram } /** + * Executes a statement that returns a 1 by 1 table with a blob value. + * + * @return A read-only file descriptor for a copy of the blob value, or {@code null} + * if the value is null or could not be read for some reason. + * + * @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows + */ + public ParcelFileDescriptor simpleQueryForBlobFileDescriptor() { + synchronized(this) { + long timeStart = acquireAndLock(READ); + try { + ParcelFileDescriptor retValue = native_1x1_blob_ashmem(); + mDatabase.logTimeStat(mSql, timeStart); + return retValue; + } catch (IOException ex) { + Log.e(TAG, "simpleQueryForBlobFileDescriptor() failed", ex); + return null; + } finally { + releaseAndUnlock(); + } + } + } + + /** * Called before every method in this class before executing a SQL statement, * this method does the following: * <ul> @@ -244,4 +275,5 @@ public class SQLiteStatement extends SQLiteProgram private final native long native_executeInsert(); private final native long native_1x1_long(); private final native String native_1x1_string(); + private final native ParcelFileDescriptor native_1x1_blob_ashmem() throws IOException; } diff --git a/core/java/android/os/MemoryFile.java b/core/java/android/os/MemoryFile.java index a81e16b..f82702a 100644 --- a/core/java/android/os/MemoryFile.java +++ b/core/java/android/os/MemoryFile.java @@ -58,7 +58,6 @@ public class MemoryFile private int mAddress; // address of ashmem memory private int mLength; // total length of our ashmem region private boolean mAllowPurging = false; // true if our ashmem region is unpinned - private final boolean mOwnsRegion; // false if this is a ref to an existing ashmem region /** * Allocates a new ashmem region. The region is initially not purgable. @@ -70,38 +69,11 @@ public class MemoryFile public MemoryFile(String name, int length) throws IOException { mLength = length; mFD = native_open(name, length); - mAddress = native_mmap(mFD, length, PROT_READ | PROT_WRITE); - mOwnsRegion = true; - } - - /** - * Creates a reference to an existing memory file. Changes to the original file - * will be available through this reference. - * Calls to {@link #allowPurging(boolean)} on the returned MemoryFile will fail. - * - * @param fd File descriptor for an existing memory file, as returned by - * {@link #getFileDescriptor()}. This file descriptor will be closed - * by {@link #close()}. - * @param length Length of the memory file in bytes. - * @param mode File mode. Currently only "r" for read-only access is supported. - * @throws NullPointerException if <code>fd</code> is null. - * @throws IOException If <code>fd</code> does not refer to an existing memory file, - * or if the file mode of the existing memory file is more restrictive - * than <code>mode</code>. - * - * @hide - */ - public MemoryFile(FileDescriptor fd, int length, String mode) throws IOException { - if (fd == null) { - throw new NullPointerException("File descriptor is null."); - } - if (!isMemoryFile(fd)) { - throw new IllegalArgumentException("Not a memory file."); + if (length > 0) { + mAddress = native_mmap(mFD, length, PROT_READ | PROT_WRITE); + } else { + mAddress = 0; } - mLength = length; - mFD = fd; - mAddress = native_mmap(mFD, length, modeToProt(mode)); - mOwnsRegion = false; } /** @@ -122,7 +94,7 @@ public class MemoryFile * * @hide */ - public void deactivate() { + void deactivate() { if (!isDeactivated()) { try { native_munmap(mAddress, mLength); @@ -181,9 +153,6 @@ public class MemoryFile * @return previous value of allowPurging */ synchronized public boolean allowPurging(boolean allowPurging) throws IOException { - if (!mOwnsRegion) { - throw new IOException("Only the owner can make ashmem regions purgable."); - } boolean oldValue = mAllowPurging; if (oldValue != allowPurging) { native_pin(mFD, !allowPurging); @@ -260,28 +229,7 @@ public class MemoryFile } /** - * Gets a ParcelFileDescriptor for the memory file. See {@link #getFileDescriptor()} - * for caveats. This must be here to allow classes outside <code>android.os</code< to - * make ParcelFileDescriptors from MemoryFiles, as - * {@link ParcelFileDescriptor#ParcelFileDescriptor(FileDescriptor)} is package private. - * - * - * @return The file descriptor owned by this memory file object. - * The file descriptor is not duplicated. - * @throws IOException If the memory file has been closed. - * - * @hide - */ - public ParcelFileDescriptor getParcelFileDescriptor() throws IOException { - FileDescriptor fd = getFileDescriptor(); - return fd != null ? new ParcelFileDescriptor(fd) : null; - } - - /** - * Gets a FileDescriptor for the memory file. Note that this file descriptor - * is only safe to pass to {@link #MemoryFile(FileDescriptor,int)}). It - * should not be used with file descriptor operations that expect a file descriptor - * for a normal file. + * Gets a FileDescriptor for the memory file. * * The returned file descriptor is not duplicated. * @@ -294,17 +242,6 @@ public class MemoryFile } /** - * Checks whether the given file descriptor refers to a memory file. - * - * @throws IOException If <code>fd</code> is not a valid file descriptor. - * - * @hide - */ - public static boolean isMemoryFile(FileDescriptor fd) throws IOException { - return (native_get_size(fd) >= 0); - } - - /** * Returns the size of the memory file that the file descriptor refers to, * or -1 if the file descriptor does not refer to a memory file. * @@ -316,20 +253,6 @@ public class MemoryFile return native_get_size(fd); } - /** - * Converts a file mode string to a <code>prot</code> value as expected by - * native_mmap(). - * - * @throws IllegalArgumentException if the file mode is invalid. - */ - private static int modeToProt(String mode) { - if ("r".equals(mode)) { - return PROT_READ; - } else { - throw new IllegalArgumentException("Unsupported file mode: '" + mode + "'"); - } - } - private class MemoryInputStream extends InputStream { private int mMark = 0; diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java index d853f13..c1a1809 100644 --- a/core/java/android/os/ParcelFileDescriptor.java +++ b/core/java/android/os/ParcelFileDescriptor.java @@ -153,6 +153,26 @@ public class ParcelFileDescriptor implements Parcelable { private static native int createPipeNative(FileDescriptor[] outFds); /** + * Gets a file descriptor for a read-only copy of the given data. + * + * @param data Data to copy. + * @param name Name for the shared memory area that may back the file descriptor. + * This is purely informative and may be {@code null}. + * @return A ParcelFileDescriptor. + * @throws IOException if there is an error while creating the shared memory area. + */ + public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException { + if (data == null) return null; + MemoryFile file = new MemoryFile(name, data.length); + if (data.length > 0) { + file.writeBytes(data, 0, 0, data.length); + } + file.deactivate(); + FileDescriptor fd = file.getFileDescriptor(); + return fd != null ? new ParcelFileDescriptor(fd) : null; + } + + /** * Retrieve the actual FileDescriptor associated with this object. * * @return Returns the FileDescriptor associated with this object. diff --git a/core/jni/android_database_SQLiteStatement.cpp b/core/jni/android_database_SQLiteStatement.cpp index 2212d9a..0f3114b 100644 --- a/core/jni/android_database_SQLiteStatement.cpp +++ b/core/jni/android_database_SQLiteStatement.cpp @@ -18,17 +18,24 @@ #undef LOG_TAG #define LOG_TAG "SQLiteStatementCpp" +#include "android_util_Binder.h" + #include <jni.h> #include <JNIHelp.h> #include <android_runtime/AndroidRuntime.h> #include <sqlite3.h> +#include <cutils/ashmem.h> #include <utils/Log.h> +#include <fcntl.h> #include <stdio.h> #include <string.h> #include <unistd.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> #include "sqlite3_exception.h" @@ -133,6 +140,105 @@ static jstring native_1x1_string(JNIEnv* env, jobject object) return value; } +static jobject createParcelFileDescriptor(JNIEnv * env, int fd) +{ + // Create FileDescriptor object + jobject fileDesc = newFileDescriptor(env, fd); + if (fileDesc == NULL) { + // FileDescriptor constructor has thrown an exception + close(fd); + return NULL; + } + + // Wrap it in a ParcelFileDescriptor + jobject parcelFileDesc = newParcelFileDescriptor(env, fileDesc); + if (parcelFileDesc == NULL) { + // ParcelFileDescriptor constructor has thrown an exception + close(fd); + return NULL; + } + + return parcelFileDesc; +} + +// Creates an ashmem area, copies some data into it, and returns +// a ParcelFileDescriptor for the ashmem area. +static jobject create_ashmem_region_with_data(JNIEnv * env, + const void * data, int length) +{ + // Create ashmem area + int fd = ashmem_create_region(NULL, length); + if (fd < 0) { + LOGE("ashmem_create_region failed: %s", strerror(errno)); + jniThrowIOException(env, errno); + return NULL; + } + + if (length > 0) { + // mmap the ashmem area + void * ashmem_ptr = + mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ashmem_ptr == MAP_FAILED) { + LOGE("mmap failed: %s", strerror(errno)); + jniThrowIOException(env, errno); + close(fd); + return NULL; + } + + // Copy data to ashmem area + memcpy(ashmem_ptr, data, length); + + // munmap ashmem area + if (munmap(ashmem_ptr, length) < 0) { + LOGE("munmap failed: %s", strerror(errno)); + jniThrowIOException(env, errno); + close(fd); + return NULL; + } + } + + // Make ashmem area read-only + if (ashmem_set_prot_region(fd, PROT_READ) < 0) { + LOGE("ashmem_set_prot_region failed: %s", strerror(errno)); + jniThrowIOException(env, errno); + close(fd); + return NULL; + } + + // Wrap it in a ParcelFileDescriptor + return createParcelFileDescriptor(env, fd); +} + +static jobject native_1x1_blob_ashmem(JNIEnv* env, jobject object) +{ + int err; + sqlite3 * handle = GET_HANDLE(env, object); + sqlite3_stmt * statement = GET_STATEMENT(env, object); + jobject value = NULL; + + // Execute the statement + err = sqlite3_step(statement); + + // Handle the result + if (err == SQLITE_ROW) { + // No errors, read the data and return it + const void * blob = sqlite3_column_blob(statement, 0); + if (blob != NULL) { + int len = sqlite3_column_bytes(statement, 0); + if (len >= 0) { + value = create_ashmem_region_with_data(env, blob, len); + } + } + } else { + throw_sqlite3_exception_errcode(env, err, sqlite3_errmsg(handle)); + } + + // Reset the statment so it's ready to use again + sqlite3_reset(statement); + + return value; +} + static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ @@ -140,6 +246,7 @@ static JNINativeMethod sMethods[] = {"native_executeInsert", "()J", (void *)native_executeInsert}, {"native_1x1_long", "()J", (void *)native_1x1_long}, {"native_1x1_string", "()Ljava/lang/String;", (void *)native_1x1_string}, + {"native_1x1_blob_ashmem", "()Landroid/os/ParcelFileDescriptor;", (void *)native_1x1_blob_ashmem}, }; int register_android_database_SQLiteStatement(JNIEnv * env) diff --git a/core/tests/coretests/src/android/content/MemoryFileProvider.java b/core/tests/coretests/src/android/content/MemoryFileProvider.java index c4bc767..73530d7 100644 --- a/core/tests/coretests/src/android/content/MemoryFileProvider.java +++ b/core/tests/coretests/src/android/content/MemoryFileProvider.java @@ -16,16 +16,11 @@ package android.content; -import android.content.ContentProvider; -import android.content.ContentValues; -import android.content.Context; -import android.content.UriMatcher; -import android.content.res.AssetFileDescriptor; import android.database.Cursor; +import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; -import android.os.MemoryFile; import android.os.ParcelFileDescriptor; import android.util.Log; @@ -134,64 +129,34 @@ public class MemoryFileProvider extends ContentProvider { } @Override - public AssetFileDescriptor openAssetFile(Uri url, String mode) throws FileNotFoundException { + public ParcelFileDescriptor openFile(Uri url, String mode) throws FileNotFoundException { int match = sURLMatcher.match(url); switch (match) { case DATA_ID_BLOB: String sql = "SELECT _blob FROM data WHERE _id=" + url.getPathSegments().get(1); - return getBlobColumnAsAssetFile(url, mode, sql); + return getBlobColumnAsFile(url, mode, sql); case HUGE: try { - MemoryFile memoryFile = new MemoryFile(null, 5000000); - memoryFile.writeBytes(TEST_BLOB, 0, 1000000, TEST_BLOB.length); - memoryFile.deactivate(); - return AssetFileDescriptor.fromMemoryFile(memoryFile); + return ParcelFileDescriptor.fromData(TEST_BLOB, null); } catch (IOException ex) { throw new FileNotFoundException("Error reading " + url + ":" + ex.toString()); } case FILE: File file = getContext().getFileStreamPath(DATA_FILE); - ParcelFileDescriptor fd = - ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); - return new AssetFileDescriptor(fd, 0, AssetFileDescriptor.UNKNOWN_LENGTH); + return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); default: throw new FileNotFoundException("No files supported by provider at " + url); } } - private AssetFileDescriptor getBlobColumnAsAssetFile(Uri url, String mode, String sql) + private ParcelFileDescriptor getBlobColumnAsFile(Uri url, String mode, String sql) throws FileNotFoundException { if (!"r".equals(mode)) { throw new FileNotFoundException("Mode " + mode + " not supported for " + url); } - try { - SQLiteDatabase db = mOpenHelper.getReadableDatabase(); - MemoryFile file = simpleQueryForBlobMemoryFile(db, sql); - if (file == null) throw new FileNotFoundException("No such entry: " + url); - AssetFileDescriptor afd = AssetFileDescriptor.fromMemoryFile(file); - file.deactivate(); - // need to dup and then close? openFileHelper() doesn't do that though - return afd; - } catch (IOException ex) { - throw new FileNotFoundException("Error reading " + url + ":" + ex.toString()); - } - } - private MemoryFile simpleQueryForBlobMemoryFile(SQLiteDatabase db, String sql) throws IOException { - Cursor cursor = db.rawQuery(sql, null); - try { - if (!cursor.moveToFirst()) { - return null; - } - byte[] bytes = cursor.getBlob(0); - MemoryFile file = new MemoryFile(null, bytes.length); - file.writeBytes(bytes, 0, 0, bytes.length); - return file; - } finally { - if (cursor != null) { - cursor.close(); - } - } + SQLiteDatabase db = mOpenHelper.getReadableDatabase(); + return DatabaseUtils.blobFileDescriptorForQuery(db, sql, null); } @Override diff --git a/core/tests/coretests/src/android/content/MemoryFileProviderTest.java b/core/tests/coretests/src/android/content/MemoryFileProviderTest.java index 62b4e7e..bbe7c10 100644 --- a/core/tests/coretests/src/android/content/MemoryFileProviderTest.java +++ b/core/tests/coretests/src/android/content/MemoryFileProviderTest.java @@ -56,7 +56,6 @@ public class MemoryFileProviderTest extends AndroidTestCase { Uri uri = Uri.parse("content://android.content.MemoryFileProvider/huge"); InputStream in = resolver.openInputStream(uri); assertNotNull("Failed to open stream number " + i, in); - assertEquals(1000000, in.skip(1000000)); byte[] buf = new byte[MemoryFileProvider.TEST_BLOB.length]; int count = in.read(buf); assertEquals(buf.length, count); diff --git a/core/tests/coretests/src/android/os/MemoryFileTest.java b/core/tests/coretests/src/android/os/MemoryFileTest.java index 009a0e2..e627bb4 100644 --- a/core/tests/coretests/src/android/os/MemoryFileTest.java +++ b/core/tests/coretests/src/android/os/MemoryFileTest.java @@ -237,51 +237,6 @@ public class MemoryFileTest extends AndroidTestCase { } } - @SmallTest - public void testIsMemoryFile() throws Exception { - MemoryFile file = new MemoryFile("MemoryFileTest", 1000000); - FileDescriptor fd = file.getFileDescriptor(); - assertNotNull(fd); - assertTrue(fd.valid()); - assertTrue(MemoryFile.isMemoryFile(fd)); - file.close(); - - assertFalse(MemoryFile.isMemoryFile(FileDescriptor.in)); - assertFalse(MemoryFile.isMemoryFile(FileDescriptor.out)); - assertFalse(MemoryFile.isMemoryFile(FileDescriptor.err)); - - File tempFile = File.createTempFile("MemoryFileTest",".tmp", getContext().getFilesDir()); - assertNotNull(file); - FileOutputStream out = null; - try { - out = new FileOutputStream(tempFile); - FileDescriptor fileFd = out.getFD(); - assertNotNull(fileFd); - assertFalse(MemoryFile.isMemoryFile(fileFd)); - } finally { - if (out != null) { - out.close(); - } - tempFile.delete(); - } - } - - @SmallTest - public void testFileDescriptor() throws Exception { - MemoryFile file = new MemoryFile("MemoryFileTest", 1000000); - MemoryFile ref = new MemoryFile(file.getFileDescriptor(), file.length(), "r"); - byte[] buffer; - - // write to original, read from reference - file.writeBytes(testString, 0, 2000, testString.length); - buffer = new byte[testString.length]; - ref.readBytes(buffer, 2000, 0, testString.length); - compareBuffers(testString, buffer, testString.length); - - file.close(); - ref.close(); // Doesn't actually do anything, since the file descriptor is not dup(2):ed - } - private static final byte[] testString = new byte[] { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5, 0, 2, 8, 8, 4, 1, 9, 7, 1, 6, 9, 3, 9, 9, 3, 7, 5, 1, 0, 5, 8, 2, 0, 9, 7, 4, 9, 4, 4, 5, 9, 2, 3, 0, 7, 8, 1, 6, 4, 0, 6, 2, 8, 6, 2, 0, 8, 9, 9, 8, 6, 2, 8, 0, 3, 4, 8, 2, 5, 3, 4, 2, 1, 1, 7, 0, 6, 7, 9, 8, 2, 1, 4, 8, 0, 8, 6, 5, 1, 3, 2, 8, 2, 3, 0, 6, 6, 4, 7, 0, 9, 3, 8, 4, 4, 6, 0, 9, 5, 5, 0, 5, 8, 2, 2, 3, 1, 7, 2, diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index 5b8d62c..d2845cf 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -18,7 +18,6 @@ package android.graphics; import android.content.res.AssetManager; import android.content.res.Resources; -import android.os.MemoryFile; import android.util.DisplayMetrics; import android.util.TypedValue; @@ -532,18 +531,6 @@ public class BitmapFactory { * @return the decoded bitmap, or null */ public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) { - try { - if (MemoryFile.isMemoryFile(fd)) { - int mappedlength = MemoryFile.getSize(fd); - MemoryFile file = new MemoryFile(fd, mappedlength, "r"); - InputStream is = file.getInputStream(); - Bitmap bm = decodeStream(is, outPadding, opts); - return finishDecode(bm, outPadding, opts); - } - } catch (IOException ex) { - // invalid filedescriptor, no need to call nativeDecodeFileDescriptor() - return null; - } Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts); return finishDecode(bm, outPadding, opts); } @@ -630,12 +617,6 @@ public class BitmapFactory { */ public static LargeBitmap createLargeBitmap( FileDescriptor fd, boolean isShareable) throws IOException { - if (MemoryFile.isMemoryFile(fd)) { - int mappedlength = MemoryFile.getSize(fd); - MemoryFile file = new MemoryFile(fd, mappedlength, "r"); - InputStream is = file.getInputStream(); - return createLargeBitmap(is, isShareable); - } return nativeCreateLargeBitmap(fd, isShareable); } diff --git a/preloaded-classes b/preloaded-classes index 33dba37..3317286 100644 --- a/preloaded-classes +++ b/preloaded-classes @@ -138,7 +138,6 @@ android.database.CursorWrapper android.database.MatrixCursor android.database.sqlite.SQLiteClosable android.database.sqlite.SQLiteCompiledSql -android.database.sqlite.SQLiteContentHelper android.database.sqlite.SQLiteCursor android.database.sqlite.SQLiteDatabase android.database.sqlite.SQLiteDebug |