diff options
46 files changed, 2458 insertions, 869 deletions
diff --git a/Android.mk b/Android.mk index 7717c762c5b3..369cdfd33226 100644 --- a/Android.mk +++ b/Android.mk @@ -317,7 +317,8 @@ libcore_to_document := \ xml/src/main/java/org/w3c non_base_dirs := \ - ../../external/apache-http/src/org/apache/http + ../../external/apache-http/src/org/apache/http \ + ../../external/oauth/core/src/main/java/net/oauth # These are relative to frameworks/base dirs_to_document := \ @@ -399,7 +400,7 @@ web_docs_sample_code_flags := \ ## SDK version identifiers used in the published docs # major[.minor] version for current SDK. (full releases only) -framework_docs_SDK_VERSION:=2.0.1 +framework_docs_SDK_VERSION:=2.1 # release version (ie "Release x") (full releases only) framework_docs_SDK_REL_ID:=1 # name of current SDK directory (full releases only) @@ -548,6 +549,7 @@ include $(BUILD_DROIDDOC) ext_dirs := \ ../../external/apache-http/src \ + ../../external/oauth/core/src/main/java \ ../../external/tagsoup/src ext_src_files := $(call all-java-files-under,$(ext_dirs)) diff --git a/api/current.xml b/api/current.xml index b03f826e13d9..3b6e031f38fb 100644 --- a/api/current.xml +++ b/api/current.xml @@ -52371,6 +52371,25 @@ <exception name="SQLException" type="android.database.SQLException"> </exception> </method> +<method name="insertWithOnConflict" + return="long" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="table" type="java.lang.String"> +</parameter> +<parameter name="nullColumnHack" type="java.lang.String"> +</parameter> +<parameter name="initialValues" type="android.content.ContentValues"> +</parameter> +<parameter name="conflictAlgorithm" type="int"> +</parameter> +</method> <method name="isDbLockedByCurrentThread" return="boolean" abstract="false" @@ -52806,6 +52825,27 @@ <parameter name="whereArgs" type="java.lang.String[]"> </parameter> </method> +<method name="updateWithOnConflict" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="table" type="java.lang.String"> +</parameter> +<parameter name="values" type="android.content.ContentValues"> +</parameter> +<parameter name="whereClause" type="java.lang.String"> +</parameter> +<parameter name="whereArgs" type="java.lang.String[]"> +</parameter> +<parameter name="conflictAlgorithm" type="int"> +</parameter> +</method> <method name="yieldIfContended" return="boolean" abstract="false" @@ -52897,6 +52937,81 @@ > </field> </class> +<class name="SQLiteDatabase.ConflictAlgorithm" + extends="java.lang.Object" + abstract="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +<field name="ABORT" + type="int" + transient="false" + volatile="false" + value="2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="FAIL" + type="int" + transient="false" + volatile="false" + value="3" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="IGNORE" + type="int" + transient="false" + volatile="false" + value="4" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="NONE" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="REPLACE" + type="int" + transient="false" + volatile="false" + value="5" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ROLLBACK" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> <interface name="SQLiteDatabase.CursorFactory" abstract="true" static="true" @@ -72158,7 +72273,7 @@ type="float" transient="false" volatile="false" - value="0.001f" + value="0.0010f" static="true" final="true" deprecated="not deprecated" @@ -83660,6 +83775,122 @@ </parameter> </method> </class> +<class name="ThumbnailUtils" + extends="java.lang.Object" + abstract="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<constructor name="ThumbnailUtils" + type="android.media.ThumbnailUtils" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</constructor> +<method name="createImageThumbnail" + return="android.graphics.Bitmap" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="cr" type="android.content.ContentResolver"> +</parameter> +<parameter name="filePath" type="java.lang.String"> +</parameter> +<parameter name="uri" type="android.net.Uri"> +</parameter> +<parameter name="origId" type="long"> +</parameter> +<parameter name="kind" type="int"> +</parameter> +<parameter name="saveMini" type="boolean"> +</parameter> +</method> +<method name="createVideoThumbnail" + return="android.graphics.Bitmap" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="filePath" type="java.lang.String"> +</parameter> +</method> +<method name="extractMiniThumb" + return="android.graphics.Bitmap" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="source" type="android.graphics.Bitmap"> +</parameter> +<parameter name="width" type="int"> +</parameter> +<parameter name="height" type="int"> +</parameter> +<parameter name="recycle" type="boolean"> +</parameter> +</method> +<field name="MINI_THUMB_TARGET_SIZE" + type="int" + transient="false" + volatile="false" + value="96" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="NO_RECYCLE_INPUT" + type="boolean" + transient="false" + volatile="false" + value="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="RECYCLE_INPUT" + type="boolean" + transient="false" + volatile="false" + value="true" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="THUMBNAIL_TARGET_SIZE" + type="int" + transient="false" + volatile="false" + value="320" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> <class name="ToneGenerator" extends="java.lang.Object" abstract="false" @@ -178437,6 +178668,17 @@ visibility="public" > </field> +<field name="FLAG_ALLOW_LOCK_WHILE_SCREEN_ON" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="FLAG_ALT_FOCUSABLE_IM" type="int" transient="false" @@ -209680,7 +209922,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="t" type="T"> +<parameter name="arg0" type="T"> </parameter> </method> </interface> diff --git a/core/java/android/app/BackupAgent.java b/core/java/android/app/BackupAgent.java index 2a586777ddf3..35b6fed71014 100644 --- a/core/java/android/app/BackupAgent.java +++ b/core/java/android/app/BackupAgent.java @@ -19,6 +19,7 @@ package android.app; import android.app.IBackupAgent; import android.backup.BackupDataInput; import android.backup.BackupDataOutput; +import android.backup.IBackupManager; import android.content.Context; import android.content.ContextWrapper; import android.os.Binder; @@ -94,12 +95,9 @@ public abstract class BackupAgent extends ContextWrapper { // ----- Core implementation ----- - - /** - * Returns the private interface called by the backup system. Applications will - * not typically override this. - */ - public IBinder onBind() { + + /** @hide */ + public final IBinder onBind() { return mBinder; } @@ -116,9 +114,10 @@ public abstract class BackupAgent extends ContextWrapper { public void doBackup(ParcelFileDescriptor oldState, ParcelFileDescriptor data, - ParcelFileDescriptor newState) throws RemoteException { + ParcelFileDescriptor newState, + int token, IBackupManager callbackBinder) throws RemoteException { // Ensure that we're running with the app's normal permission level - long token = Binder.clearCallingIdentity(); + long ident = Binder.clearCallingIdentity(); if (DEBUG) Log.v(TAG, "doBackup() invoked"); BackupDataOutput output = new BackupDataOutput(data.getFileDescriptor()); @@ -131,14 +130,20 @@ public abstract class BackupAgent extends ContextWrapper { Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex); throw ex; } finally { - Binder.restoreCallingIdentity(token); + Binder.restoreCallingIdentity(ident); + try { + callbackBinder.opComplete(token); + } catch (RemoteException e) { + // we'll time out anyway, so we're safe + } } } public void doRestore(ParcelFileDescriptor data, int appVersionCode, - ParcelFileDescriptor newState) throws RemoteException { + ParcelFileDescriptor newState, + int token, IBackupManager callbackBinder) throws RemoteException { // Ensure that we're running with the app's normal permission level - long token = Binder.clearCallingIdentity(); + long ident = Binder.clearCallingIdentity(); if (DEBUG) Log.v(TAG, "doRestore() invoked"); BackupDataInput input = new BackupDataInput(data.getFileDescriptor()); @@ -151,7 +156,12 @@ public abstract class BackupAgent extends ContextWrapper { Log.d(TAG, "onRestore (" + BackupAgent.this.getClass().getName() + ") threw", ex); throw ex; } finally { - Binder.restoreCallingIdentity(token); + Binder.restoreCallingIdentity(ident); + try { + callbackBinder.opComplete(token); + } catch (RemoteException e) { + // we'll time out anyway, so we're safe + } } } } diff --git a/core/java/android/app/IBackupAgent.aidl b/core/java/android/app/IBackupAgent.aidl index 9b0550fce64b..0de6ad9a83e2 100644 --- a/core/java/android/app/IBackupAgent.aidl +++ b/core/java/android/app/IBackupAgent.aidl @@ -16,6 +16,7 @@ package android.app; +import android.backup.IBackupManager; import android.os.ParcelFileDescriptor; /** @@ -25,7 +26,7 @@ import android.os.ParcelFileDescriptor; * * {@hide} */ -interface IBackupAgent { +oneway interface IBackupAgent { /** * Request that the app perform an incremental backup. * @@ -39,10 +40,18 @@ interface IBackupAgent { * * @param newState Read-write file, empty when onBackup() is called, * where the new state blob is to be recorded. + * + * @param token Opaque token identifying this transaction. This must + * be echoed back to the backup service binder once the new + * data has been written to the data and newState files. + * + * @param callbackBinder Binder on which to indicate operation completion, + * passed here as a convenience to the agent. */ void doBackup(in ParcelFileDescriptor oldState, in ParcelFileDescriptor data, - in ParcelFileDescriptor newState); + in ParcelFileDescriptor newState, + int token, IBackupManager callbackBinder); /** * Restore an entire data snapshot to the application. @@ -58,7 +67,15 @@ interface IBackupAgent { * @param newState Read-write file, empty when onRestore() is called, * that is to be written with the state description that holds after * the restore has been completed. + * + * @param token Opaque token identifying this transaction. This must + * be echoed back to the backup service binder once the agent is + * finished restoring the application based on the restore data + * contents. + * + * @param callbackBinder Binder on which to indicate operation completion, + * passed here as a convenience to the agent. */ void doRestore(in ParcelFileDescriptor data, int appVersionCode, - in ParcelFileDescriptor newState); + in ParcelFileDescriptor newState, int token, IBackupManager callbackBinder); } diff --git a/core/java/android/backup/IBackupManager.aidl b/core/java/android/backup/IBackupManager.aidl index 9d181bec49df..cb775f7504dc 100644 --- a/core/java/android/backup/IBackupManager.aidl +++ b/core/java/android/backup/IBackupManager.aidl @@ -130,4 +130,14 @@ interface IBackupManager { * @return An interface to the restore session, or null on error. */ IRestoreSession beginRestoreSession(String transportID); + + /** + * Notify the backup manager that a BackupAgent has completed the operation + * corresponding to the given token. + * + * @param token The transaction token passed to a BackupAgent's doBackup() or + * doRestore() method. + * {@hide} + */ + void opComplete(int token); } diff --git a/core/java/android/backup/RestoreSession.java b/core/java/android/backup/RestoreSession.java index 119fc52e7433..a884793ab7af 100644 --- a/core/java/android/backup/RestoreSession.java +++ b/core/java/android/backup/RestoreSession.java @@ -109,9 +109,7 @@ public class RestoreSession { /* * We wrap incoming binder calls with a private class implementation that - * redirects them into main-thread actions. This accomplishes two things: - * first, it ensures that the app's code is run on their own main thread, - * never with system Binder identity; and second, it serializes the restore + * redirects them into main-thread actions. This serializes the restore * progress callbacks nicely within the usual main-thread lifecycle pattern. */ private class RestoreObserverWrapper extends IRestoreObserver.Stub { diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index bc59c94526d6..d10c8f8efecb 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -27,6 +27,8 @@ import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.Environment; +import android.os.StatFs; import android.util.AndroidException; import android.util.DisplayMetrics; @@ -602,6 +604,89 @@ public abstract class PackageManager { */ @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_LIVE_WALLPAPER = "android.software.live_wallpaper"; + + // No-installation limit for internal flash: 10% or less space available + private static final double LOW_NAND_FLASH_TRESHOLD = 0.1; + + // SD-to-internal app size threshold: currently set to 1 MB + private static final long INSTALL_ON_SD_THRESHOLD = (1024 * 1024); + + private static final int INSTALL_ON_INTERNAL_FLASH = 0; + + /** + * Determines best place to install an application: either SD or internal FLASH. + * Tweak the algorithm for best results. + * @param tmpPackageFile APK file containing the application to install. + * @return <code>PKG_INSTALL_INTERNAL</code> if it is best to install package on internal + * storage, <code>PKG_INSTALL_ON_SD</code> if it is best to install package on SD card, + * and <code>PKG_CANNOT_FIT</code> if insufficient space to safely install the app. + * This response does not take into account the package's own flags. + * @hide + */ + public static int recommendAppInstallLocation(ApplicationInfo appInfo, Uri packageURI) { + // Initial implementation: + // Package size = code size + cache size + data size + // If code size > 1 MB, install on SD card. + // Else install on internal NAND flash, unless space on NAND is less than 5% + // 0 = install on internal FLASH + // 1 = install on SD card + // (-1) = insufficient space - package cannot be installed. + + if ((packageURI == null) || (appInfo == null)) { + return (-1); + } + + StatFs internalFlashStats = new StatFs(Environment.getDataDirectory().getPath()); + StatFs sdcardStats = new StatFs(Environment.getExternalStorageDirectory().getPath()); + + long totalInternalFlashSize = (long)internalFlashStats.getBlockCount() * + (long)internalFlashStats.getBlockSize(); + long availInternalFlashSize = (long)internalFlashStats.getAvailableBlocks() * + (long)internalFlashStats.getBlockSize(); + long availSDSize = (long)sdcardStats.getAvailableBlocks() * + (long)sdcardStats.getBlockSize(); + + double pctNandFree = (double)availInternalFlashSize / (double)totalInternalFlashSize; + + final String archiveFilePath = packageURI.getPath(); + File apkFile = new File(archiveFilePath); + long pkgLen = apkFile.length(); + + // Consider application flags preferences as well... + boolean installOnlyOnSD = ((appInfo.flags & PackageManager.INSTALL_ON_SDCARD) != 0); + + // These are not very precise measures, but I guess it is hard to estimate sizes + // before installing the package. + // As a shortcut, I am assuming that the package fits on NAND flash if the available + // space is three times that of the APK size. For SD, we only worry about the APK size. + // Since packages are downloaded into SD, this might not even be necessary. + boolean fitsOnSD = (pkgLen < availSDSize) && ((2 * pkgLen) < availInternalFlashSize); + boolean fitsOnInternalFlash = ((pkgLen * 3) < availInternalFlashSize); + + // Does not fit, recommend no installation. + if (!fitsOnSD && !fitsOnInternalFlash) { + return (-1); + } + + if (pkgLen < (INSTALL_ON_SD_THRESHOLD) && fitsOnInternalFlash && !(installOnlyOnSD)) { + // recommend internal NAND likely + if (pctNandFree < LOW_NAND_FLASH_TRESHOLD) { + // Low space on NAND (<10%) - install on SD + return INSTALL_ON_SDCARD; + } + return INSTALL_ON_INTERNAL_FLASH; + } else { + if (fitsOnSD) { + // Recommend SD card + return INSTALL_ON_SDCARD; + } else if (fitsOnInternalFlash && (pctNandFree >= LOW_NAND_FLASH_TRESHOLD) && + !(installOnlyOnSD)) { + return INSTALL_ON_INTERNAL_FLASH; + } else { + return (-1); + } + } + } /** * Retrieve overall information about an application package that is diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index 82490bb3e6a4..e3c25ec0ddb9 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -65,9 +65,8 @@ public class SQLiteDatabase extends SQLiteClosable { /** * Algorithms used in ON CONFLICT clause * http://www.sqlite.org/lang_conflict.html - * @hide */ - public enum ConflictAlgorithm { + public static final class ConflictAlgorithm { /** * When a constraint violation occurs, an immediate ROLLBACK occurs, * thus ending the current transaction, and the command aborts with a @@ -75,14 +74,14 @@ public class SQLiteDatabase extends SQLiteClosable { * (other than the implied transaction that is created on every command) * then this algorithm works the same as ABORT. */ - ROLLBACK("ROLLBACK"), + public static final int ROLLBACK = 1; /** * When a constraint violation occurs,no ROLLBACK is executed * so changes from prior commands within the same transaction * are preserved. This is the default behavior. */ - ABORT("ABORT"), + public static final int ABORT = 2; /** * When a constraint violation occurs, the command aborts with a return @@ -90,7 +89,7 @@ public class SQLiteDatabase extends SQLiteClosable { * the command made prior to encountering the constraint violation * are preserved and are not backed out. */ - FAIL("FAIL"), + public static final int FAIL = 3; /** * When a constraint violation occurs, the one row that contains @@ -99,7 +98,7 @@ public class SQLiteDatabase extends SQLiteClosable { * after the row that contained the constraint violation continue to be * inserted or updated normally. No error is returned. */ - IGNORE("IGNORE"), + public static final int IGNORE = 4; /** * When a UNIQUE constraint violation occurs, the pre-existing rows that @@ -114,15 +113,16 @@ public class SQLiteDatabase extends SQLiteClosable { * it does not invoke delete triggers on those rows. * This behavior might change in a future release. */ - REPLACE("REPLACE"); + public static final int REPLACE = 5; - private final String mValue; - ConflictAlgorithm(String value) { - mValue = value; - } - public String value() { - return mValue; - } + /** + * use the following when no conflict action is specified. + */ + public static final int NONE = 0; + private static final String[] VALUES = new String[] + {"", " OR ROLLBACK ", " OR ABORT ", " OR FAIL ", " OR IGNORE ", " OR REPLACE "}; + + private ConflictAlgorithm() {} // disable instantiation of this class } /** @@ -1334,7 +1334,7 @@ public class SQLiteDatabase extends SQLiteClosable { */ public long insert(String table, String nullColumnHack, ContentValues values) { try { - return insertWithOnConflict(table, nullColumnHack, values, null); + return insertWithOnConflict(table, nullColumnHack, values, ConflictAlgorithm.NONE); } catch (SQLException e) { Log.e(TAG, "Error inserting " + values, e); return -1; @@ -1356,7 +1356,7 @@ public class SQLiteDatabase extends SQLiteClosable { */ public long insertOrThrow(String table, String nullColumnHack, ContentValues values) throws SQLException { - return insertWithOnConflict(table, nullColumnHack, values, null); + return insertWithOnConflict(table, nullColumnHack, values, ConflictAlgorithm.NONE); } /** @@ -1408,12 +1408,14 @@ public class SQLiteDatabase extends SQLiteClosable { * @param initialValues this map contains the initial column values for the * row. The keys should be the column names and the values the * column values - * @param algorithm {@link ConflictAlgorithm} for insert conflict resolver - * @return the row ID of the newly inserted row, or -1 if an error occurred - * @hide + * @param conflictAlgorithm {@link ConflictAlgorithm} for insert conflict resolver + * @return the row ID of the newly inserted row + * OR the primary key of the existing row if the input param 'conflictAlgorithm' = + * {@link ConflictAlgorithm#IGNORE} + * OR -1 if any error */ public long insertWithOnConflict(String table, String nullColumnHack, - ContentValues initialValues, ConflictAlgorithm algorithm) { + ContentValues initialValues, int conflictAlgorithm) { if (!isOpen()) { throw new IllegalStateException("database not open"); } @@ -1421,10 +1423,7 @@ public class SQLiteDatabase extends SQLiteClosable { // Measurements show most sql lengths <= 152 StringBuilder sql = new StringBuilder(152); sql.append("INSERT"); - if (algorithm != null) { - sql.append(" OR "); - sql.append(algorithm.value()); - } + sql.append(ConflictAlgorithm.VALUES[conflictAlgorithm]); sql.append(" INTO "); sql.append(table); // Measurements show most values lengths < 40 @@ -1548,7 +1547,7 @@ public class SQLiteDatabase extends SQLiteClosable { * @return the number of rows affected */ public int update(String table, ContentValues values, String whereClause, String[] whereArgs) { - return updateWithOnConflict(table, values, whereClause, whereArgs, null); + return updateWithOnConflict(table, values, whereClause, whereArgs, ConflictAlgorithm.NONE); } /** @@ -1559,12 +1558,11 @@ public class SQLiteDatabase extends SQLiteClosable { * valid value that will be translated to NULL. * @param whereClause the optional WHERE clause to apply when updating. * Passing null will update all rows. - * @param algorithm {@link ConflictAlgorithm} for update conflict resolver + * @param conflictAlgorithm {@link ConflictAlgorithm} for update conflict resolver * @return the number of rows affected - * @hide */ public int updateWithOnConflict(String table, ContentValues values, - String whereClause, String[] whereArgs, ConflictAlgorithm algorithm) { + String whereClause, String[] whereArgs, int conflictAlgorithm) { if (!isOpen()) { throw new IllegalStateException("database not open"); } @@ -1575,12 +1573,7 @@ public class SQLiteDatabase extends SQLiteClosable { StringBuilder sql = new StringBuilder(120); sql.append("UPDATE "); - if (algorithm != null) { - sql.append("OR "); - sql.append(algorithm.value()); - sql.append(" "); - } - + sql.append(ConflictAlgorithm.VALUES[conflictAlgorithm]); sql.append(table); sql.append(" SET "); diff --git a/core/java/android/ddm/DdmHandleHeap.java b/core/java/android/ddm/DdmHandleHeap.java index 95fa0a265d15..fa0fbbfe1658 100644 --- a/core/java/android/ddm/DdmHandleHeap.java +++ b/core/java/android/ddm/DdmHandleHeap.java @@ -34,6 +34,7 @@ public class DdmHandleHeap extends ChunkHandler { public static final int CHUNK_HPIF = type("HPIF"); public static final int CHUNK_HPSG = type("HPSG"); public static final int CHUNK_HPDU = type("HPDU"); + public static final int CHUNK_HPDS = type("HPDS"); public static final int CHUNK_NHSG = type("NHSG"); public static final int CHUNK_HPGC = type("HPGC"); public static final int CHUNK_REAE = type("REAE"); @@ -53,6 +54,7 @@ public class DdmHandleHeap extends ChunkHandler { DdmServer.registerHandler(CHUNK_HPIF, mInstance); DdmServer.registerHandler(CHUNK_HPSG, mInstance); DdmServer.registerHandler(CHUNK_HPDU, mInstance); + DdmServer.registerHandler(CHUNK_HPDS, mInstance); DdmServer.registerHandler(CHUNK_NHSG, mInstance); DdmServer.registerHandler(CHUNK_HPGC, mInstance); DdmServer.registerHandler(CHUNK_REAE, mInstance); @@ -86,6 +88,8 @@ public class DdmHandleHeap extends ChunkHandler { return handleHPSGNHSG(request, false); } else if (type == CHUNK_HPDU) { return handleHPDU(request); + } else if (type == CHUNK_HPDS) { + return handleHPDS(request); } else if (type == CHUNK_NHSG) { return handleHPSGNHSG(request, true); } else if (type == CHUNK_HPGC) { @@ -167,7 +171,7 @@ public class DdmHandleHeap extends ChunkHandler { result = -1; } catch (IOException ioe) { result = -1; - } catch (RuntimeException ioe) { + } catch (RuntimeException re) { result = -1; } @@ -177,6 +181,38 @@ public class DdmHandleHeap extends ChunkHandler { } /* + * Handle a "HeaP Dump Streaming" request. + * + * This tells the VM to create a heap dump and send it directly to + * DDMS. The dumps are large enough that we don't want to copy the + * data into a byte[] and send it from here. + */ + private Chunk handleHPDS(Chunk request) { + ByteBuffer in = wrapChunk(request); + byte result; + + /* get the filename for the output file */ + if (Config.LOGD) + Log.d("ddm-heap", "Heap dump: [DDMS]"); + + String failMsg = null; + try { + Debug.dumpHprofDataDdms(); + } catch (UnsupportedOperationException uoe) { + failMsg = "hprof dumps not supported in this VM"; + } catch (RuntimeException re) { + failMsg = "Exception: " + re.getMessage(); + } + + if (failMsg != null) { + Log.w("ddm-heap", failMsg); + return createFailChunk(1, failMsg); + } else { + return null; + } + } + + /* * Handle a "HeaP Garbage Collection" request. */ private Chunk handleHPGC(Chunk request) { diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index 8e9b11bdcd32..9ee251ebbd8d 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -726,6 +726,18 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo } /** + * Collect "hprof" and send it to DDMS. This will cause a GC. + * + * @throws UnsupportedOperationException if the VM was built without + * HPROF support. + * + * @hide + */ + public static void dumpHprofDataDdms() { + VMDebug.dumpHprofDataDdms(); + } + + /** * Returns the number of sent transactions from this process. * @return The number of sent transactions or -1 if it could not read t. */ diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 1b938ee64660..211bc0aca7f6 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -28,7 +28,7 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.media.MiniThumbFile; -import android.media.ThumbnailUtil; +import android.media.ThumbnailUtils; import android.net.Uri; import android.os.Environment; import android.os.ParcelFileDescriptor; @@ -381,15 +381,15 @@ public final class MediaStore { filePath = c.getString(1); } if (isVideo) { - bitmap = ThumbnailUtil.createVideoThumbnail(filePath); + bitmap = ThumbnailUtils.createVideoThumbnail(filePath); if (kind == MICRO_KIND && bitmap != null) { - bitmap = ThumbnailUtil.extractMiniThumb(bitmap, - ThumbnailUtil.MINI_THUMB_TARGET_SIZE, - ThumbnailUtil.MINI_THUMB_TARGET_SIZE, - ThumbnailUtil.RECYCLE_INPUT); + bitmap = ThumbnailUtils.extractMiniThumb(bitmap, + ThumbnailUtils.MINI_THUMB_TARGET_SIZE, + ThumbnailUtils.MINI_THUMB_TARGET_SIZE, + ThumbnailUtils.RECYCLE_INPUT); } } else { - bitmap = ThumbnailUtil.createImageThumbnail(cr, filePath, uri, origId, + bitmap = ThumbnailUtils.createImageThumbnail(cr, filePath, uri, origId, kind, false); } } diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 8e15f89e6325..0af31f05ab34 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -369,6 +369,12 @@ public interface WindowManager extends ViewManager { */ public int flags; + /** Window flag: as long as this window is visible to the user, allow + * the lock screen to activate while the screen is on. + * This can be used independently, or in combination with + * {@link #FLAG_KEEP_SCREEN_ON} and/or {@link #FLAG_SHOW_WHEN_LOCKED} */ + public static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001; + /** Window flag: everything behind this window will be dimmed. * Use {@link #dimAmount} to control the amount of dim. */ public static final int FLAG_DIM_BEHIND = 0x00000002; diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 21577bf920ae..7bc5cced2115 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -827,6 +827,12 @@ public interface WindowManagerPolicy { public void systemReady(); /** + * Called when userActivity is signalled in the power manager. + * This is safe to call from any thread, with any window manager locks held or not. + */ + public void userActivity(); + + /** * Called when we have finished booting and can now display the home * screen to the user. This wilWl happen after systemReady(), and at * this point the display is active. diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl index a830ebdbce75..9da1066d1d69 100644 --- a/core/java/com/android/internal/backup/IBackupTransport.aidl +++ b/core/java/com/android/internal/backup/IBackupTransport.aidl @@ -102,7 +102,7 @@ interface IBackupTransport { int finishBackup(); /** - * Get the set of backups currently available over this transport. + * Get the set of all backups currently available over this transport. * * @return Descriptions of the set of restore images available for this device, * or null if an error occurred (the attempt should be rescheduled). @@ -110,11 +110,22 @@ interface IBackupTransport { RestoreSet[] getAvailableRestoreSets(); /** + * Get the identifying token of the backup set currently being stored from + * this device. This is used in the case of applications wishing to restore + * their last-known-good data. + * + * @return A token that can be passed to {@link #startRestore}, or 0 if there + * is no backup set available corresponding to the current device state. + */ + long getCurrentRestoreSet(); + + /** * Start restoring application data from backup. After calling this function, * alternate calls to {@link #nextRestorePackage} and {@link #nextRestoreData} * to walk through the actual application data. * - * @param token A backup token as returned by {@link #getAvailableRestoreSets}. + * @param token A backup token as returned by {@link #getAvailableRestoreSets} + * or {@link #getCurrentRestoreSet}. * @param packages List of applications to restore (if data is available). * Application data will be restored in the order given. * @return One of {@link BackupConstants#TRANSPORT_OK} (OK so far, call diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java index 12bc5a888fc2..23ec6470a7ab 100644 --- a/core/java/com/android/internal/backup/LocalTransport.java +++ b/core/java/com/android/internal/backup/LocalTransport.java @@ -33,6 +33,9 @@ public class LocalTransport extends IBackupTransport.Stub { private static final String TRANSPORT_DIR_NAME = "com.android.internal.backup.LocalTransport"; + // The single hardcoded restore set always has the same (nonzero!) token + private static final long RESTORE_TOKEN = 1; + private Context mContext; private PackageManager mPackageManager; private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup"); @@ -149,11 +152,16 @@ public class LocalTransport extends IBackupTransport.Stub { // Restore handling public RestoreSet[] getAvailableRestoreSets() throws android.os.RemoteException { // one hardcoded restore set - RestoreSet set = new RestoreSet("Local disk image", "flash", 0); + RestoreSet set = new RestoreSet("Local disk image", "flash", RESTORE_TOKEN); RestoreSet[] array = { set }; return array; } + public long getCurrentRestoreSet() { + // The hardcoded restore set always has the same token + return RESTORE_TOKEN; + } + public int startRestore(long token, PackageInfo[] packages) { if (DEBUG) Log.v(TAG, "start restore " + token); mRestorePackages = packages; diff --git a/core/jni/CursorWindow.cpp b/core/jni/CursorWindow.cpp index 78641899856d..694514e9a440 100644 --- a/core/jni/CursorWindow.cpp +++ b/core/jni/CursorWindow.cpp @@ -60,7 +60,7 @@ bool CursorWindow::initBuffer(bool localOnly) { //TODO Use a non-memory dealer mmap region for localOnly - mHeap = new MemoryDealer(new SharedHeap(mMaxSize, 0, "CursorWindow")); + mHeap = new MemoryDealer(mMaxSize, "CursorWindow"); if (mHeap != NULL) { mMemory = mHeap->allocate(mMaxSize); if (mMemory != NULL) { diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp index 93e4d2b815bb..bf613e1550b6 100644 --- a/core/jni/com_google_android_gles_jni_GLImpl.cpp +++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp @@ -24,6 +24,23 @@ #include <GLES/gl.h> #include <GLES/glext.h> +// Work around differences between the generated name and the actual name. + +#define glBlendEquation glBlendEquationOES +#define glBlendEquationSeparate glBlendEquationSeparateOES +#define glBlendFuncSeparate glBlendFuncSeparateOES +#define glGetTexGenfv glGetTexGenfvOES +#define glGetTexGeniv glGetTexGenivOES +#define glGetTexGenxv glGetTexGenxvOES +#define glTexGenf glTexGenfOES +#define glTexGenfv glTexGenfvOES +#define glTexGeni glTexGeniOES +#define glTexGeniv glTexGenivOES +#define glTexGenx glTexGenxOES +#define glTexGenxv glTexGenxvOES + + + /* special calls implemented in Android's GLES wrapper used to more * efficiently bound-check passed arrays */ extern "C" { @@ -59,6 +76,11 @@ static jmethodID allowIndirectBuffersID; static jfieldID positionID; static jfieldID limitID; static jfieldID elementSizeShiftID; +static jfieldID haveCheckedExtensionsID; +static jfieldID have_OES_blend_equation_separateID; +static jfieldID have_OES_blend_subtractID; +static jfieldID have_OES_framebuffer_objectID; +static jfieldID have_OES_texture_cube_mapID; /* Cache method IDs each time the class is loaded. */ @@ -73,6 +95,11 @@ nativeClassInitBuffer(JNIEnv *_env) jclass g11impClassLocal = _env->FindClass("com/google/android/gles_jni/GLImpl"); G11ImplClass = (jclass) _env->NewGlobalRef(g11impClassLocal); + haveCheckedExtensionsID = _env->GetFieldID(G11ImplClass, "haveCheckedExtensions", "Z"); + have_OES_blend_equation_separateID = _env->GetFieldID(G11ImplClass, "have_OES_blend_equation_separate", "Z"); + have_OES_blend_subtractID = _env->GetFieldID(G11ImplClass, "have_OES_blend_subtract", "Z"); + have_OES_framebuffer_objectID = _env->GetFieldID(G11ImplClass, "have_OES_framebuffer_object", "Z"); + have_OES_texture_cube_mapID = _env->GetFieldID(G11ImplClass, "have_OES_texture_cube_map", "Z"); getBasePointerID = _env->GetStaticMethodID(nioAccessClass, "getBasePointer", "(Ljava/nio/Buffer;)J"); @@ -194,6 +221,64 @@ getNumCompressedTextureFormats() { return numCompressedTextureFormats; } +// Check if the extension at the head of pExtensions is pExtension. Note that pExtensions is +// terminated by either 0 or space, while pExtension is terminated by 0. + +static bool +extensionEqual(const GLubyte* pExtensions, const GLubyte* pExtension) { + while (true) { + char a = *pExtensions++; + char b = *pExtension++; + bool aEnd = a == '\0' || a == ' '; + bool bEnd = b == '\0'; + if ( aEnd || bEnd) { + return aEnd == bEnd; + } + if ( a != b ) { + return false; + } + } +} + +static const GLubyte* +nextExtension(const GLubyte* pExtensions) { + while (true) { + char a = *pExtensions++; + if ( a == '\0') { + return pExtensions-1; + } else if ( a == ' ') { + return pExtensions; + } + } +} + +static bool +checkForExtension(const GLubyte* pExtensions, const GLubyte* pExtension) { + for (;*pExtensions != '\0'; pExtensions = nextExtension(pExtensions)) { + if (extensionEqual(pExtensions, pExtension)) { + return true; + } + } + return false; +} + +static bool +supportsExtension(JNIEnv *_env, jobject impl, jfieldID fieldId) { + if (!_env->GetBooleanField(impl, haveCheckedExtensionsID)) { + _env->SetBooleanField(impl, haveCheckedExtensionsID, true); + const GLubyte* sExtensions = glGetString(GL_EXTENSIONS); + _env->SetBooleanField(impl, have_OES_blend_equation_separateID, + checkForExtension(sExtensions, (const GLubyte*) "GL_OES_blend_equation_separate")); + _env->SetBooleanField(impl, have_OES_blend_subtractID, + checkForExtension(sExtensions, (const GLubyte*) "GL_OES_blend_subtract")); + _env->SetBooleanField(impl, have_OES_framebuffer_objectID, + checkForExtension(sExtensions, (const GLubyte*) "GL_OES_framebuffer_object")); + _env->SetBooleanField(impl, have_OES_texture_cube_mapID, + checkForExtension(sExtensions, (const GLubyte*) "GL_OES_texture_cube_map")); + } + return _env->GetBooleanField(impl, fieldId); +} + // -------------------------------------------------------------------------- /* void glActiveTexture ( GLenum texture ) */ @@ -6137,315 +6222,1084 @@ android_glWeightPointerOES__IIII static void android_glBindFramebufferOES__II (JNIEnv *_env, jobject _this, jint target, jint framebuffer) { - _env->ThrowNew(UOEClass, - "glBindFramebufferOES"); + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glBindFramebufferOES"); + return; + } + glBindFramebufferOES( + (GLint)target, + (GLint)framebuffer + ); } /* void glBindRenderbufferOES ( GLint target, GLint renderbuffer ) */ static void android_glBindRenderbufferOES__II (JNIEnv *_env, jobject _this, jint target, jint renderbuffer) { - _env->ThrowNew(UOEClass, - "glBindRenderbufferOES"); + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glBindRenderbufferOES"); + return; + } + glBindRenderbufferOES( + (GLint)target, + (GLint)renderbuffer + ); } /* void glBlendEquation ( GLint mode ) */ static void android_glBlendEquation__I (JNIEnv *_env, jobject _this, jint mode) { - _env->ThrowNew(UOEClass, - "glBlendEquation"); + if (! supportsExtension(_env, _this, have_OES_blend_subtractID)) { + _env->ThrowNew(UOEClass, + "glBlendEquation"); + return; + } + glBlendEquation( + (GLint)mode + ); } /* void glBlendEquationSeparate ( GLint modeRGB, GLint modeAlpha ) */ static void android_glBlendEquationSeparate__II (JNIEnv *_env, jobject _this, jint modeRGB, jint modeAlpha) { - _env->ThrowNew(UOEClass, - "glBlendEquationSeparate"); + if (! supportsExtension(_env, _this, have_OES_blend_equation_separateID)) { + _env->ThrowNew(UOEClass, + "glBlendEquationSeparate"); + return; + } + glBlendEquationSeparate( + (GLint)modeRGB, + (GLint)modeAlpha + ); } /* void glBlendFuncSeparate ( GLint srcRGB, GLint dstRGB, GLint srcAlpha, GLint dstAlpha ) */ static void android_glBlendFuncSeparate__IIII (JNIEnv *_env, jobject _this, jint srcRGB, jint dstRGB, jint srcAlpha, jint dstAlpha) { - _env->ThrowNew(UOEClass, - "glBlendFuncSeparate"); + if (! supportsExtension(_env, _this, have_OES_blend_equation_separateID)) { + _env->ThrowNew(UOEClass, + "glBlendFuncSeparate"); + return; + } + glBlendFuncSeparate( + (GLint)srcRGB, + (GLint)dstRGB, + (GLint)srcAlpha, + (GLint)dstAlpha + ); } /* GLint glCheckFramebufferStatusOES ( GLint target ) */ static jint android_glCheckFramebufferStatusOES__I (JNIEnv *_env, jobject _this, jint target) { - _env->ThrowNew(UOEClass, - "glCheckFramebufferStatusOES"); - return 0; + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glCheckFramebufferStatusOES"); + return 0; + } + GLint _returnValue = 0; + _returnValue = glCheckFramebufferStatusOES( + (GLint)target + ); + return _returnValue; } -/* void glDeleteFramebuffersOES ( GLint n, GLint *framebuffers ) */ +/* void glDeleteFramebuffersOES ( GLint n, GLuint *framebuffers ) */ static void android_glDeleteFramebuffersOES__I_3II (JNIEnv *_env, jobject _this, jint n, jintArray framebuffers_ref, jint offset) { - _env->ThrowNew(UOEClass, - "glDeleteFramebuffersOES"); + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glDeleteFramebuffersOES"); + return; + } + jint _exception = 0; + GLuint *framebuffers_base = (GLuint *) 0; + jint _remaining; + GLuint *framebuffers = (GLuint *) 0; + + if (!framebuffers_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "framebuffers == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(framebuffers_ref) - offset; + if (_remaining < n) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - offset < n"); + goto exit; + } + framebuffers_base = (GLuint *) + _env->GetPrimitiveArrayCritical(framebuffers_ref, (jboolean *)0); + framebuffers = framebuffers_base + offset; + + glDeleteFramebuffersOES( + (GLint)n, + (GLuint *)framebuffers + ); + +exit: + if (framebuffers_base) { + _env->ReleasePrimitiveArrayCritical(framebuffers_ref, framebuffers_base, + _exception ? JNI_ABORT: 0); + } } -/* void glDeleteFramebuffersOES ( GLint n, GLint *framebuffers ) */ +/* void glDeleteFramebuffersOES ( GLint n, GLuint *framebuffers ) */ static void android_glDeleteFramebuffersOES__ILjava_nio_IntBuffer_2 (JNIEnv *_env, jobject _this, jint n, jobject framebuffers_buf) { - _env->ThrowNew(UOEClass, - "glDeleteFramebuffersOES"); + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glDeleteFramebuffersOES"); + return; + } + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLuint *framebuffers = (GLuint *) 0; + + framebuffers = (GLuint *)getPointer(_env, framebuffers_buf, &_array, &_remaining); + if (_remaining < n) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < n"); + goto exit; + } + glDeleteFramebuffersOES( + (GLint)n, + (GLuint *)framebuffers + ); + +exit: + if (_array) { + releasePointer(_env, _array, framebuffers, _exception ? JNI_FALSE : JNI_TRUE); + } } -/* void glDeleteRenderbuffersOES ( GLint n, GLint *renderbuffers ) */ +/* void glDeleteRenderbuffersOES ( GLint n, GLuint *renderbuffers ) */ static void android_glDeleteRenderbuffersOES__I_3II (JNIEnv *_env, jobject _this, jint n, jintArray renderbuffers_ref, jint offset) { - _env->ThrowNew(UOEClass, - "glDeleteRenderbuffersOES"); + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glDeleteRenderbuffersOES"); + return; + } + jint _exception = 0; + GLuint *renderbuffers_base = (GLuint *) 0; + jint _remaining; + GLuint *renderbuffers = (GLuint *) 0; + + if (!renderbuffers_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "renderbuffers == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(renderbuffers_ref) - offset; + if (_remaining < n) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - offset < n"); + goto exit; + } + renderbuffers_base = (GLuint *) + _env->GetPrimitiveArrayCritical(renderbuffers_ref, (jboolean *)0); + renderbuffers = renderbuffers_base + offset; + + glDeleteRenderbuffersOES( + (GLint)n, + (GLuint *)renderbuffers + ); + +exit: + if (renderbuffers_base) { + _env->ReleasePrimitiveArrayCritical(renderbuffers_ref, renderbuffers_base, + _exception ? JNI_ABORT: 0); + } } -/* void glDeleteRenderbuffersOES ( GLint n, GLint *renderbuffers ) */ +/* void glDeleteRenderbuffersOES ( GLint n, GLuint *renderbuffers ) */ static void android_glDeleteRenderbuffersOES__ILjava_nio_IntBuffer_2 (JNIEnv *_env, jobject _this, jint n, jobject renderbuffers_buf) { - _env->ThrowNew(UOEClass, - "glDeleteRenderbuffersOES"); + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glDeleteRenderbuffersOES"); + return; + } + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLuint *renderbuffers = (GLuint *) 0; + + renderbuffers = (GLuint *)getPointer(_env, renderbuffers_buf, &_array, &_remaining); + if (_remaining < n) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < n"); + goto exit; + } + glDeleteRenderbuffersOES( + (GLint)n, + (GLuint *)renderbuffers + ); + +exit: + if (_array) { + releasePointer(_env, _array, renderbuffers, _exception ? JNI_FALSE : JNI_TRUE); + } } /* void glFramebufferRenderbufferOES ( GLint target, GLint attachment, GLint renderbuffertarget, GLint renderbuffer ) */ static void android_glFramebufferRenderbufferOES__IIII (JNIEnv *_env, jobject _this, jint target, jint attachment, jint renderbuffertarget, jint renderbuffer) { - _env->ThrowNew(UOEClass, - "glFramebufferRenderbufferOES"); + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glFramebufferRenderbufferOES"); + return; + } + glFramebufferRenderbufferOES( + (GLint)target, + (GLint)attachment, + (GLint)renderbuffertarget, + (GLint)renderbuffer + ); } /* void glFramebufferTexture2DOES ( GLint target, GLint attachment, GLint textarget, GLint texture, GLint level ) */ static void android_glFramebufferTexture2DOES__IIIII (JNIEnv *_env, jobject _this, jint target, jint attachment, jint textarget, jint texture, jint level) { - _env->ThrowNew(UOEClass, - "glFramebufferTexture2DOES"); + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glFramebufferTexture2DOES"); + return; + } + glFramebufferTexture2DOES( + (GLint)target, + (GLint)attachment, + (GLint)textarget, + (GLint)texture, + (GLint)level + ); } /* void glGenerateMipmapOES ( GLint target ) */ static void android_glGenerateMipmapOES__I (JNIEnv *_env, jobject _this, jint target) { - _env->ThrowNew(UOEClass, - "glGenerateMipmapOES"); + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glGenerateMipmapOES"); + return; + } + glGenerateMipmapOES( + (GLint)target + ); } -/* void glGenFramebuffersOES ( GLint n, GLint *framebuffers ) */ +/* void glGenFramebuffersOES ( GLint n, GLuint *framebuffers ) */ static void android_glGenFramebuffersOES__I_3II (JNIEnv *_env, jobject _this, jint n, jintArray framebuffers_ref, jint offset) { - _env->ThrowNew(UOEClass, - "glGenFramebuffersOES"); + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glGenFramebuffersOES"); + return; + } + jint _exception = 0; + GLuint *framebuffers_base = (GLuint *) 0; + jint _remaining; + GLuint *framebuffers = (GLuint *) 0; + + if (!framebuffers_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "framebuffers == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(framebuffers_ref) - offset; + if (_remaining < n) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - offset < n"); + goto exit; + } + framebuffers_base = (GLuint *) + _env->GetPrimitiveArrayCritical(framebuffers_ref, (jboolean *)0); + framebuffers = framebuffers_base + offset; + + glGenFramebuffersOES( + (GLint)n, + (GLuint *)framebuffers + ); + +exit: + if (framebuffers_base) { + _env->ReleasePrimitiveArrayCritical(framebuffers_ref, framebuffers_base, + _exception ? JNI_ABORT: 0); + } } -/* void glGenFramebuffersOES ( GLint n, GLint *framebuffers ) */ +/* void glGenFramebuffersOES ( GLint n, GLuint *framebuffers ) */ static void android_glGenFramebuffersOES__ILjava_nio_IntBuffer_2 (JNIEnv *_env, jobject _this, jint n, jobject framebuffers_buf) { - _env->ThrowNew(UOEClass, - "glGenFramebuffersOES"); + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glGenFramebuffersOES"); + return; + } + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLuint *framebuffers = (GLuint *) 0; + + framebuffers = (GLuint *)getPointer(_env, framebuffers_buf, &_array, &_remaining); + if (_remaining < n) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < n"); + goto exit; + } + glGenFramebuffersOES( + (GLint)n, + (GLuint *)framebuffers + ); + +exit: + if (_array) { + releasePointer(_env, _array, framebuffers, _exception ? JNI_FALSE : JNI_TRUE); + } } -/* void glGenRenderbuffersOES ( GLint n, GLint *renderbuffers ) */ +/* void glGenRenderbuffersOES ( GLint n, GLuint *renderbuffers ) */ static void android_glGenRenderbuffersOES__I_3II (JNIEnv *_env, jobject _this, jint n, jintArray renderbuffers_ref, jint offset) { - _env->ThrowNew(UOEClass, - "glGenRenderbuffersOES"); + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glGenRenderbuffersOES"); + return; + } + jint _exception = 0; + GLuint *renderbuffers_base = (GLuint *) 0; + jint _remaining; + GLuint *renderbuffers = (GLuint *) 0; + + if (!renderbuffers_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "renderbuffers == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(renderbuffers_ref) - offset; + if (_remaining < n) { + _exception = 1; + _env->ThrowNew(IAEClass, "length - offset < n"); + goto exit; + } + renderbuffers_base = (GLuint *) + _env->GetPrimitiveArrayCritical(renderbuffers_ref, (jboolean *)0); + renderbuffers = renderbuffers_base + offset; + + glGenRenderbuffersOES( + (GLint)n, + (GLuint *)renderbuffers + ); + +exit: + if (renderbuffers_base) { + _env->ReleasePrimitiveArrayCritical(renderbuffers_ref, renderbuffers_base, + _exception ? JNI_ABORT: 0); + } } -/* void glGenRenderbuffersOES ( GLint n, GLint *renderbuffers ) */ +/* void glGenRenderbuffersOES ( GLint n, GLuint *renderbuffers ) */ static void android_glGenRenderbuffersOES__ILjava_nio_IntBuffer_2 (JNIEnv *_env, jobject _this, jint n, jobject renderbuffers_buf) { - _env->ThrowNew(UOEClass, - "glGenRenderbuffersOES"); + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glGenRenderbuffersOES"); + return; + } + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLuint *renderbuffers = (GLuint *) 0; + + renderbuffers = (GLuint *)getPointer(_env, renderbuffers_buf, &_array, &_remaining); + if (_remaining < n) { + _exception = 1; + _env->ThrowNew(IAEClass, "remaining() < n"); + goto exit; + } + glGenRenderbuffersOES( + (GLint)n, + (GLuint *)renderbuffers + ); + +exit: + if (_array) { + releasePointer(_env, _array, renderbuffers, _exception ? JNI_FALSE : JNI_TRUE); + } } /* void glGetFramebufferAttachmentParameterivOES ( GLint target, GLint attachment, GLint pname, GLint *params ) */ static void android_glGetFramebufferAttachmentParameterivOES__III_3II (JNIEnv *_env, jobject _this, jint target, jint attachment, jint pname, jintArray params_ref, jint offset) { - _env->ThrowNew(UOEClass, - "glGetFramebufferAttachmentParameterivOES"); + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glGetFramebufferAttachmentParameterivOES"); + return; + } + jint _exception = 0; + GLint *params_base = (GLint *) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLint *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetFramebufferAttachmentParameterivOES( + (GLint)target, + (GLint)attachment, + (GLint)pname, + (GLint *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } } /* void glGetFramebufferAttachmentParameterivOES ( GLint target, GLint attachment, GLint pname, GLint *params ) */ static void android_glGetFramebufferAttachmentParameterivOES__IIILjava_nio_IntBuffer_2 (JNIEnv *_env, jobject _this, jint target, jint attachment, jint pname, jobject params_buf) { - _env->ThrowNew(UOEClass, - "glGetFramebufferAttachmentParameterivOES"); + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glGetFramebufferAttachmentParameterivOES"); + return; + } + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining); + glGetFramebufferAttachmentParameterivOES( + (GLint)target, + (GLint)attachment, + (GLint)pname, + (GLint *)params + ); + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } } /* void glGetRenderbufferParameterivOES ( GLint target, GLint pname, GLint *params ) */ static void android_glGetRenderbufferParameterivOES__II_3II (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) { - _env->ThrowNew(UOEClass, - "glGetRenderbufferParameterivOES"); + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glGetRenderbufferParameterivOES"); + return; + } + jint _exception = 0; + GLint *params_base = (GLint *) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLint *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetRenderbufferParameterivOES( + (GLint)target, + (GLint)pname, + (GLint *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } } /* void glGetRenderbufferParameterivOES ( GLint target, GLint pname, GLint *params ) */ static void android_glGetRenderbufferParameterivOES__IILjava_nio_IntBuffer_2 (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) { - _env->ThrowNew(UOEClass, - "glGetRenderbufferParameterivOES"); + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glGetRenderbufferParameterivOES"); + return; + } + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining); + glGetRenderbufferParameterivOES( + (GLint)target, + (GLint)pname, + (GLint *)params + ); + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } } /* void glGetTexGenfv ( GLint coord, GLint pname, GLfloat *params ) */ static void android_glGetTexGenfv__II_3FI (JNIEnv *_env, jobject _this, jint coord, jint pname, jfloatArray params_ref, jint offset) { - _env->ThrowNew(UOEClass, - "glGetTexGenfv"); + if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) { + _env->ThrowNew(UOEClass, + "glGetTexGenfv"); + return; + } + jint _exception = 0; + GLfloat *params_base = (GLfloat *) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetTexGenfv( + (GLint)coord, + (GLint)pname, + (GLfloat *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } } /* void glGetTexGenfv ( GLint coord, GLint pname, GLfloat *params ) */ static void android_glGetTexGenfv__IILjava_nio_FloatBuffer_2 (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) { - _env->ThrowNew(UOEClass, - "glGetTexGenfv"); + if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) { + _env->ThrowNew(UOEClass, + "glGetTexGenfv"); + return; + } + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining); + glGetTexGenfv( + (GLint)coord, + (GLint)pname, + (GLfloat *)params + ); + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } } /* void glGetTexGeniv ( GLint coord, GLint pname, GLint *params ) */ static void android_glGetTexGeniv__II_3II (JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) { - _env->ThrowNew(UOEClass, - "glGetTexGeniv"); + if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) { + _env->ThrowNew(UOEClass, + "glGetTexGeniv"); + return; + } + jint _exception = 0; + GLint *params_base = (GLint *) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLint *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetTexGeniv( + (GLint)coord, + (GLint)pname, + (GLint *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } } /* void glGetTexGeniv ( GLint coord, GLint pname, GLint *params ) */ static void android_glGetTexGeniv__IILjava_nio_IntBuffer_2 (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) { - _env->ThrowNew(UOEClass, - "glGetTexGeniv"); + if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) { + _env->ThrowNew(UOEClass, + "glGetTexGeniv"); + return; + } + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining); + glGetTexGeniv( + (GLint)coord, + (GLint)pname, + (GLint *)params + ); + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } } /* void glGetTexGenxv ( GLint coord, GLint pname, GLint *params ) */ static void android_glGetTexGenxv__II_3II (JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) { - _env->ThrowNew(UOEClass, - "glGetTexGenxv"); + if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) { + _env->ThrowNew(UOEClass, + "glGetTexGenxv"); + return; + } + jint _exception = 0; + GLint *params_base = (GLint *) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLint *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glGetTexGenxv( + (GLint)coord, + (GLint)pname, + (GLint *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } } /* void glGetTexGenxv ( GLint coord, GLint pname, GLint *params ) */ static void android_glGetTexGenxv__IILjava_nio_IntBuffer_2 (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) { - _env->ThrowNew(UOEClass, - "glGetTexGenxv"); + if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) { + _env->ThrowNew(UOEClass, + "glGetTexGenxv"); + return; + } + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining); + glGetTexGenxv( + (GLint)coord, + (GLint)pname, + (GLint *)params + ); + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } } /* GLboolean glIsFramebufferOES ( GLint framebuffer ) */ static jboolean android_glIsFramebufferOES__I (JNIEnv *_env, jobject _this, jint framebuffer) { - _env->ThrowNew(UOEClass, - "glIsFramebufferOES"); - return JNI_FALSE; + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glIsFramebufferOES"); + return JNI_FALSE; + } + GLboolean _returnValue = JNI_FALSE; + _returnValue = glIsFramebufferOES( + (GLint)framebuffer + ); + return _returnValue; } /* GLboolean glIsRenderbufferOES ( GLint renderbuffer ) */ static jboolean android_glIsRenderbufferOES__I (JNIEnv *_env, jobject _this, jint renderbuffer) { - _env->ThrowNew(UOEClass, - "glIsRenderbufferOES"); - return JNI_FALSE; + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glIsRenderbufferOES"); + return JNI_FALSE; + } + GLboolean _returnValue = JNI_FALSE; + _returnValue = glIsRenderbufferOES( + (GLint)renderbuffer + ); + return _returnValue; } /* void glRenderbufferStorageOES ( GLint target, GLint internalformat, GLint width, GLint height ) */ static void android_glRenderbufferStorageOES__IIII (JNIEnv *_env, jobject _this, jint target, jint internalformat, jint width, jint height) { - _env->ThrowNew(UOEClass, - "glRenderbufferStorageOES"); + if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) { + _env->ThrowNew(UOEClass, + "glRenderbufferStorageOES"); + return; + } + glRenderbufferStorageOES( + (GLint)target, + (GLint)internalformat, + (GLint)width, + (GLint)height + ); } /* void glTexGenf ( GLint coord, GLint pname, GLfloat param ) */ static void android_glTexGenf__IIF (JNIEnv *_env, jobject _this, jint coord, jint pname, jfloat param) { - _env->ThrowNew(UOEClass, - "glTexGenf"); + if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) { + _env->ThrowNew(UOEClass, + "glTexGenf"); + return; + } + glTexGenf( + (GLint)coord, + (GLint)pname, + (GLfloat)param + ); } /* void glTexGenfv ( GLint coord, GLint pname, GLfloat *params ) */ static void android_glTexGenfv__II_3FI (JNIEnv *_env, jobject _this, jint coord, jint pname, jfloatArray params_ref, jint offset) { - _env->ThrowNew(UOEClass, - "glTexGenfv"); + if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) { + _env->ThrowNew(UOEClass, + "glTexGenfv"); + return; + } + jint _exception = 0; + GLfloat *params_base = (GLfloat *) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLfloat *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glTexGenfv( + (GLint)coord, + (GLint)pname, + (GLfloat *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } } /* void glTexGenfv ( GLint coord, GLint pname, GLfloat *params ) */ static void android_glTexGenfv__IILjava_nio_FloatBuffer_2 (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) { - _env->ThrowNew(UOEClass, - "glTexGenfv"); + if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) { + _env->ThrowNew(UOEClass, + "glTexGenfv"); + return; + } + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLfloat *params = (GLfloat *) 0; + + params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining); + glTexGenfv( + (GLint)coord, + (GLint)pname, + (GLfloat *)params + ); + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } } /* void glTexGeni ( GLint coord, GLint pname, GLint param ) */ static void android_glTexGeni__III (JNIEnv *_env, jobject _this, jint coord, jint pname, jint param) { - _env->ThrowNew(UOEClass, - "glTexGeni"); + if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) { + _env->ThrowNew(UOEClass, + "glTexGeni"); + return; + } + glTexGeni( + (GLint)coord, + (GLint)pname, + (GLint)param + ); } /* void glTexGeniv ( GLint coord, GLint pname, GLint *params ) */ static void android_glTexGeniv__II_3II (JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) { - _env->ThrowNew(UOEClass, - "glTexGeniv"); + if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) { + _env->ThrowNew(UOEClass, + "glTexGeniv"); + return; + } + jint _exception = 0; + GLint *params_base = (GLint *) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLint *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glTexGeniv( + (GLint)coord, + (GLint)pname, + (GLint *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } } /* void glTexGeniv ( GLint coord, GLint pname, GLint *params ) */ static void android_glTexGeniv__IILjava_nio_IntBuffer_2 (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) { - _env->ThrowNew(UOEClass, - "glTexGeniv"); + if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) { + _env->ThrowNew(UOEClass, + "glTexGeniv"); + return; + } + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining); + glTexGeniv( + (GLint)coord, + (GLint)pname, + (GLint *)params + ); + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } } /* void glTexGenx ( GLint coord, GLint pname, GLint param ) */ static void android_glTexGenx__III (JNIEnv *_env, jobject _this, jint coord, jint pname, jint param) { - _env->ThrowNew(UOEClass, - "glTexGenx"); + if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) { + _env->ThrowNew(UOEClass, + "glTexGenx"); + return; + } + glTexGenx( + (GLint)coord, + (GLint)pname, + (GLint)param + ); } /* void glTexGenxv ( GLint coord, GLint pname, GLint *params ) */ static void android_glTexGenxv__II_3II (JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) { - _env->ThrowNew(UOEClass, - "glTexGenxv"); + if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) { + _env->ThrowNew(UOEClass, + "glTexGenxv"); + return; + } + jint _exception = 0; + GLint *params_base = (GLint *) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + if (!params_ref) { + _exception = 1; + _env->ThrowNew(IAEClass, "params == null"); + goto exit; + } + if (offset < 0) { + _exception = 1; + _env->ThrowNew(IAEClass, "offset < 0"); + goto exit; + } + _remaining = _env->GetArrayLength(params_ref) - offset; + params_base = (GLint *) + _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params = params_base + offset; + + glTexGenxv( + (GLint)coord, + (GLint)pname, + (GLint *)params + ); + +exit: + if (params_base) { + _env->ReleasePrimitiveArrayCritical(params_ref, params_base, + _exception ? JNI_ABORT: 0); + } } /* void glTexGenxv ( GLint coord, GLint pname, GLint *params ) */ static void android_glTexGenxv__IILjava_nio_IntBuffer_2 (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) { - _env->ThrowNew(UOEClass, - "glTexGenxv"); + if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) { + _env->ThrowNew(UOEClass, + "glTexGenxv"); + return; + } + jint _exception = 0; + jarray _array = (jarray) 0; + jint _remaining; + GLint *params = (GLint *) 0; + + params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining); + glTexGenxv( + (GLint)coord, + (GLint)pname, + (GLint *)params + ); + if (_array) { + releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + } } static const char *classPathName = "com/google/android/gles_jni/GLImpl"; diff --git a/docs/html/guide/developing/debug-tasks.jd b/docs/html/guide/developing/debug-tasks.jd index a980efc2fe0b..500ef588dc4c 100644 --- a/docs/html/guide/developing/debug-tasks.jd +++ b/docs/html/guide/developing/debug-tasks.jd @@ -58,8 +58,8 @@ Log.i("MyActivity", "MyClass.getView() — get item number " + position); <pre class="no-pretty-print"> I/MyActivity( 1557): MyClass.getView() — get item number 1 </pre> - <p>Logcat is also the place to look when debugging a web page in the Android browser. All -browser bugs will be output to logcat with the {@code WebCore} tag. + <p>Logcat is also the place to look when debugging a web page in the Android Browser app. See +<a href="#DebuggingWebPages">Debugging Web Pages</a> below.</p> </dl> <p>For more information about all the development tools provided with the Android SDK, see the <a @@ -148,10 +148,10 @@ following options (among others):</p> <h2 id="DebuggingWebPages">Debugging Web Pages</h2> -<p>If you're developing a web application for Android devices, you can debug your JavaScript on -Android using the Console APIs, which will output messages to logcat. If you're familiar +<p>If you're developing a web application for Android devices, you can debug your JavaScript in the +Android Browser using the Console APIs, which will output messages to logcat. If you're familiar debugging web pages with Firefox's FireBug or WebKit's Web Inspector, then you're probably familiar -with the Console APIs. The Android Browser (and {@link android.webkit.WebChromeClient}) supports +with the Console APIs. The Android Browser (and the {@link android.webkit.WebChromeClient}) supports most of the same APIs.</p> <p>When you call a function from the Console APIs (in the DOM's {@code window.console} object), @@ -162,19 +162,28 @@ console.log("Hello World"); </pre> <p>Then the logcat output from the Android Browser will look like this:</p> <pre class="no-pretty-print"> -W/browser ( 202): Console: Hello World :0 +W/browser ( 202): Console: Hello World http://www.example.com/hello.html :82 </pre> -<p class="note"><strong>Note:</strong> All Console messages from the Android -Browser are tagged with the name "browser" on Android platforms running API Level 7 or higher and -tagged with the name "WebCore" for platforms running API Level 6 or lower.</p> - -<p>Not all of the Console APIs available in Firefox or other WebKit browsers are implemented -on Android. Mostly, you need to depend on basic text logging provided by -functions like {@code console.log(String)}, {@code console.info(String)}, {@code -console.warn(String)}, and {@code console.error(String)}. Although other Console functions may not -be implemented, they will not raise run-time errors, but will simply not behave as you might -expect.</p> +<p>All Console messages from the Android Browser are tagged with the name "browser" on Android +platforms running API Level 7 or higher. On platforms running API Level 6 or lower, Browser +messages are tagged with the name "WebCore". The Android Browser also formats console messages +with the log message +preceded by "Console:" and then followed by the address and line number where the +message occurred. (The format for the address and line number will appear different from the example +above on platforms running API Level 6 or lower.)</p> + +<p>The Android Browser (and {@link android.webkit.WebChromeClient}) does not implement all of the +Console APIs provided by Firefox or other WebKit-based browsers. Primarily, you need to depend +on the basic text logging functions:</p> +<ul> + <li>{@code console.log(String)}</li> + <li>{@code console.info(String)}</li> + <li>{@code console.warn(String)}</li> + <li>{@code console.error(String)}</li> +</ul> +<p>Although the Android Browser may not fully implement other Console functions, they will not raise +run-time errors, but may not behave the same as they do on other desktop browsers.</p> <p>If you've implemented a custom {@link android.webkit.WebView} in your application, then in order to receive messages that are sent through the Console APIs, you must provide a {@link @@ -185,7 +194,7 @@ android.webkit.WebView} in your application, you can log debug messages like thi <pre> myWebView.setWebChromeClient(new WebChromeClient() { public void onConsoleMessage(String message, int lineNumber, String sourceID) { - Log.d("MyApplication", message); + Log.d("MyApplication", message + " -- From line " + lineNumber + " of " + sourceID); } }); </pre> @@ -195,13 +204,14 @@ within your {@link android.webkit.WebView}.</p> <p>When the "Hello World" log is executed through your {@link android.webkit.WebView}, it will now look like this:</p> <pre class="no-pretty-print"> -D/MyApplication ( 430): Hello World +D/MyApplication ( 430): Hello World -- From line 82 of http://www.example.com/hello.html </pre> <p class="note"><strong>Note:</strong> The {@link android.webkit.WebChromeClient#onConsoleMessage(String,int,String) onConsoleMessage()} callback -method was added with API Level 7. If you are targetting platforms running API Level 6 or lower, -then your Console messages will automatically be sent to logcat with the "WebCore" logging tag.</p> +method was added with API Level 7. If you are using a custom {@link +android.webkit.WebView} on a platform running API Level 6 or lower, then your Console messages will +automatically be sent to logcat with the "WebCore" logging tag.</p> diff --git a/include/binder/MemoryDealer.h b/include/binder/MemoryDealer.h index 03ac70a6b325..170f20d67a02 100644 --- a/include/binder/MemoryDealer.h +++ b/include/binder/MemoryDealer.h @@ -22,232 +22,35 @@ #include <sys/types.h> #include <binder/IMemory.h> -#include <utils/threads.h> #include <binder/MemoryHeapBase.h> namespace android { // ---------------------------------------------------------------------------- -class String8; -/* - * interface for implementing a "heap". A heap basically provides - * the IMemoryHeap interface for cross-process sharing and the - * ability to map/unmap pages within the heap. - */ -class HeapInterface : public virtual BnMemoryHeap -{ -public: - // all values must be page-aligned - virtual sp<IMemory> mapMemory(size_t offset, size_t size) = 0; - - HeapInterface(); -protected: - virtual ~HeapInterface(); -}; - -// ---------------------------------------------------------------------------- - -/* - * interface for implementing an allocator. An allocator provides - * methods for allocating and freeing memory blocks and dumping - * its state. - */ -class AllocatorInterface : public RefBase -{ -public: - enum { - PAGE_ALIGNED = 0x00000001 - }; - - virtual size_t allocate(size_t size, uint32_t flags = 0) = 0; - virtual status_t deallocate(size_t offset) = 0; - virtual size_t size() const = 0; - virtual void dump(const char* what, uint32_t flags = 0) const = 0; - virtual void dump(String8& res, - const char* what, uint32_t flags = 0) const = 0; - - AllocatorInterface(); -protected: - virtual ~AllocatorInterface(); -}; - -// ---------------------------------------------------------------------------- - -/* - * concrete implementation of HeapInterface on top of mmap() - */ -class SharedHeap : public HeapInterface, public MemoryHeapBase -{ -public: - SharedHeap(); - SharedHeap(size_t size, uint32_t flags = 0, char const * name = NULL); - virtual ~SharedHeap(); - virtual sp<IMemory> mapMemory(size_t offset, size_t size); -}; - -// ---------------------------------------------------------------------------- - -/* - * A simple templatized doubly linked-list implementation - */ - -template <typename NODE> -class LinkedList -{ - NODE* mFirst; - NODE* mLast; - -public: - LinkedList() : mFirst(0), mLast(0) { } - bool isEmpty() const { return mFirst == 0; } - NODE const* head() const { return mFirst; } - NODE* head() { return mFirst; } - NODE const* tail() const { return mLast; } - NODE* tail() { return mLast; } - - void insertAfter(NODE* node, NODE* newNode) { - newNode->prev = node; - newNode->next = node->next; - if (node->next == 0) mLast = newNode; - else node->next->prev = newNode; - node->next = newNode; - } - - void insertBefore(NODE* node, NODE* newNode) { - newNode->prev = node->prev; - newNode->next = node; - if (node->prev == 0) mFirst = newNode; - else node->prev->next = newNode; - node->prev = newNode; - } - - void insertHead(NODE* newNode) { - if (mFirst == 0) { - mFirst = mLast = newNode; - newNode->prev = newNode->next = 0; - } else { - newNode->prev = 0; - newNode->next = mFirst; - mFirst->prev = newNode; - mFirst = newNode; - } - } - - void insertTail(NODE* newNode) { - if (mLast == 0) { - insertHead(newNode); - } else { - newNode->prev = mLast; - newNode->next = 0; - mLast->next = newNode; - mLast = newNode; - } - } - - NODE* remove(NODE* node) { - if (node->prev == 0) mFirst = node->next; - else node->prev->next = node->next; - if (node->next == 0) mLast = node->prev; - else node->next->prev = node->prev; - return node; - } -}; - - -/* - * concrete implementation of AllocatorInterface using a simple - * best-fit allocation scheme - */ -class SimpleBestFitAllocator : public AllocatorInterface -{ -public: - - SimpleBestFitAllocator(size_t size); - virtual ~SimpleBestFitAllocator(); - - virtual size_t allocate(size_t size, uint32_t flags = 0); - virtual status_t deallocate(size_t offset); - virtual size_t size() const; - virtual void dump(const char* what, uint32_t flags = 0) const; - virtual void dump(String8& res, - const char* what, uint32_t flags = 0) const; - -private: - - struct chunk_t { - chunk_t(size_t start, size_t size) - : start(start), size(size), free(1), prev(0), next(0) { - } - size_t start; - size_t size : 28; - int free : 4; - mutable chunk_t* prev; - mutable chunk_t* next; - }; - - ssize_t alloc(size_t size, uint32_t flags); - chunk_t* dealloc(size_t start); - void dump_l(const char* what, uint32_t flags = 0) const; - void dump_l(String8& res, const char* what, uint32_t flags = 0) const; - - static const int kMemoryAlign; - mutable Mutex mLock; - LinkedList<chunk_t> mList; - size_t mHeapSize; -}; +class SimpleBestFitAllocator; // ---------------------------------------------------------------------------- class MemoryDealer : public RefBase { public: + MemoryDealer(size_t size, const char* name = 0); - enum { - READ_ONLY = MemoryHeapBase::READ_ONLY, - PAGE_ALIGNED = AllocatorInterface::PAGE_ALIGNED - }; - - // creates a memory dealer with the SharedHeap and SimpleBestFitAllocator - MemoryDealer(size_t size, uint32_t flags = 0, const char* name = 0); - - // provide a custom heap but use the SimpleBestFitAllocator - MemoryDealer(const sp<HeapInterface>& heap); - - // provide both custom heap and allocotar - MemoryDealer( - const sp<HeapInterface>& heap, - const sp<AllocatorInterface>& allocator); - - virtual sp<IMemory> allocate(size_t size, uint32_t flags = 0); + virtual sp<IMemory> allocate(size_t size); virtual void deallocate(size_t offset); - virtual void dump(const char* what, uint32_t flags = 0) const; - + virtual void dump(const char* what) const; sp<IMemoryHeap> getMemoryHeap() const { return heap(); } - sp<AllocatorInterface> getAllocator() const { return allocator(); } protected: virtual ~MemoryDealer(); -private: - const sp<HeapInterface>& heap() const; - const sp<AllocatorInterface>& allocator() const; - - class Allocation : public BnMemory { - public: - Allocation(const sp<MemoryDealer>& dealer, - ssize_t offset, size_t size, const sp<IMemory>& memory); - virtual ~Allocation(); - virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const; - private: - sp<MemoryDealer> mDealer; - ssize_t mOffset; - size_t mSize; - sp<IMemory> mMemory; - }; +private: + const sp<IMemoryHeap>& heap() const; + SimpleBestFitAllocator* allocator() const; - sp<HeapInterface> mHeap; - sp<AllocatorInterface> mAllocator; + sp<IMemoryHeap> mHeap; + SimpleBestFitAllocator* mAllocator; }; diff --git a/include/binder/MemoryHeapPmem.h b/include/binder/MemoryHeapPmem.h index dbf26ff1ffc6..aac164f72b1d 100644 --- a/include/binder/MemoryHeapPmem.h +++ b/include/binder/MemoryHeapPmem.h @@ -20,10 +20,10 @@ #include <stdlib.h> #include <stdint.h> -#include <binder/MemoryDealer.h> #include <binder/MemoryHeapBase.h> #include <binder/IMemory.h> #include <utils/SortedVector.h> +#include <utils/threads.h> namespace android { @@ -31,7 +31,7 @@ class MemoryHeapBase; // --------------------------------------------------------------------------- -class MemoryHeapPmem : public HeapInterface, public MemoryHeapBase +class MemoryHeapPmem : public MemoryHeapBase { public: class MemoryPmem : public BnMemory { diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h index 71344e6f89d7..26fcc9586877 100644 --- a/include/media/stagefright/AudioPlayer.h +++ b/include/media/stagefright/AudioPlayer.h @@ -47,7 +47,7 @@ public: // Return time in us. virtual int64_t getRealTimeUs(); - void start(); + status_t start(); void pause(); void resume(); diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index cad420a9b153..9d52882da786 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -2929,7 +2929,7 @@ void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue() AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid) : RefBase(), mAudioFlinger(audioFlinger), - mMemoryDealer(new MemoryDealer(1024*1024)), + mMemoryDealer(new MemoryDealer(1024*1024, "AudioFlinger::Client")), mPid(pid) { // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp index d5ffe7f6d388..18669f76dde0 100644 --- a/libs/binder/MemoryDealer.cpp +++ b/libs/binder/MemoryDealer.cpp @@ -17,12 +17,13 @@ #define LOG_TAG "MemoryDealer" #include <binder/MemoryDealer.h> +#include <binder/IPCThreadState.h> +#include <binder/MemoryBase.h> #include <utils/Log.h> -#include <binder/IPCThreadState.h> #include <utils/SortedVector.h> #include <utils/String8.h> -#include <binder/MemoryBase.h> +#include <utils/threads.h> #include <stdint.h> #include <stdio.h> @@ -40,90 +41,203 @@ namespace android { // ---------------------------------------------------------------------------- -HeapInterface::HeapInterface() { } -HeapInterface::~HeapInterface() { } +/* + * A simple templatized doubly linked-list implementation + */ + +template <typename NODE> +class LinkedList +{ + NODE* mFirst; + NODE* mLast; -// ---------------------------------------------------------------------------- +public: + LinkedList() : mFirst(0), mLast(0) { } + bool isEmpty() const { return mFirst == 0; } + NODE const* head() const { return mFirst; } + NODE* head() { return mFirst; } + NODE const* tail() const { return mLast; } + NODE* tail() { return mLast; } + + void insertAfter(NODE* node, NODE* newNode) { + newNode->prev = node; + newNode->next = node->next; + if (node->next == 0) mLast = newNode; + else node->next->prev = newNode; + node->next = newNode; + } -AllocatorInterface::AllocatorInterface() { } -AllocatorInterface::~AllocatorInterface() { } + void insertBefore(NODE* node, NODE* newNode) { + newNode->prev = node->prev; + newNode->next = node; + if (node->prev == 0) mFirst = newNode; + else node->prev->next = newNode; + node->prev = newNode; + } + + void insertHead(NODE* newNode) { + if (mFirst == 0) { + mFirst = mLast = newNode; + newNode->prev = newNode->next = 0; + } else { + newNode->prev = 0; + newNode->next = mFirst; + mFirst->prev = newNode; + mFirst = newNode; + } + } + + void insertTail(NODE* newNode) { + if (mLast == 0) { + insertHead(newNode); + } else { + newNode->prev = mLast; + newNode->next = 0; + mLast->next = newNode; + mLast = newNode; + } + } + + NODE* remove(NODE* node) { + if (node->prev == 0) mFirst = node->next; + else node->prev->next = node->next; + if (node->next == 0) mLast = node->prev; + else node->next->prev = node->prev; + return node; + } +}; // ---------------------------------------------------------------------------- -class SimpleMemory : public MemoryBase { +class Allocation : public MemoryBase { public: - SimpleMemory(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size); - virtual ~SimpleMemory(); + Allocation(const sp<MemoryDealer>& dealer, + const sp<IMemoryHeap>& heap, ssize_t offset, size_t size); + virtual ~Allocation(); +private: + sp<MemoryDealer> mDealer; }; +// ---------------------------------------------------------------------------- + +class SimpleBestFitAllocator +{ + enum { + PAGE_ALIGNED = 0x00000001 + }; +public: + SimpleBestFitAllocator(size_t size); + ~SimpleBestFitAllocator(); + + size_t allocate(size_t size, uint32_t flags = 0); + status_t deallocate(size_t offset); + size_t size() const; + void dump(const char* what) const; + void dump(String8& res, const char* what) const; + +private: + + struct chunk_t { + chunk_t(size_t start, size_t size) + : start(start), size(size), free(1), prev(0), next(0) { + } + size_t start; + size_t size : 28; + int free : 4; + mutable chunk_t* prev; + mutable chunk_t* next; + }; + + ssize_t alloc(size_t size, uint32_t flags); + chunk_t* dealloc(size_t start); + void dump_l(const char* what) const; + void dump_l(String8& res, const char* what) const; + + static const int kMemoryAlign; + mutable Mutex mLock; + LinkedList<chunk_t> mList; + size_t mHeapSize; +}; // ---------------------------------------------------------------------------- -MemoryDealer::Allocation::Allocation( - const sp<MemoryDealer>& dealer, ssize_t offset, size_t size, - const sp<IMemory>& memory) - : mDealer(dealer), mOffset(offset), mSize(size), mMemory(memory) +Allocation::Allocation( + const sp<MemoryDealer>& dealer, + const sp<IMemoryHeap>& heap, ssize_t offset, size_t size) + : MemoryBase(heap, offset, size), mDealer(dealer) { +#ifndef NDEBUG + void* const start_ptr = (void*)(intptr_t(heap->base()) + offset); + memset(start_ptr, 0xda, size); +#endif } -MemoryDealer::Allocation::~Allocation() +Allocation::~Allocation() { - if (mSize) { + size_t freedOffset = getOffset(); + size_t freedSize = getSize(); + if (freedSize) { /* NOTE: it's VERY important to not free allocations of size 0 because * they're special as they don't have any record in the allocator * and could alias some real allocation (their offset is zero). */ - mDealer->deallocate(mOffset); - } -} + mDealer->deallocate(freedOffset); + + // keep the size to unmap in excess + size_t pagesize = getpagesize(); + size_t start = freedOffset; + size_t end = start + freedSize; + start &= ~(pagesize-1); + end = (end + pagesize-1) & ~(pagesize-1); + + // give back to the kernel the pages we don't need + size_t free_start = freedOffset; + size_t free_end = free_start + freedSize; + if (start < free_start) + start = free_start; + if (end > free_end) + end = free_end; + start = (start + pagesize-1) & ~(pagesize-1); + end &= ~(pagesize-1); + + if (start < end) { + void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start); + size_t size = end-start; -sp<IMemoryHeap> MemoryDealer::Allocation::getMemory( - ssize_t* offset, size_t* size) const -{ - return mMemory->getMemory(offset, size); +#ifndef NDEBUG + memset(start_ptr, 0xdf, size); +#endif + + // MADV_REMOVE is not defined on Dapper based Goobuntu +#ifdef MADV_REMOVE + if (size) { + int err = madvise(start_ptr, size, MADV_REMOVE); + LOGW_IF(err, "madvise(%p, %u, MADV_REMOVE) returned %s", + start_ptr, size, err<0 ? strerror(errno) : "Ok"); + } +#endif + } + } } // ---------------------------------------------------------------------------- -MemoryDealer::MemoryDealer(size_t size, uint32_t flags, const char* name) - : mHeap(new SharedHeap(size, flags, name)), +MemoryDealer::MemoryDealer(size_t size, const char* name) + : mHeap(new MemoryHeapBase(size, 0, name)), mAllocator(new SimpleBestFitAllocator(size)) { } -MemoryDealer::MemoryDealer(const sp<HeapInterface>& heap) - : mHeap(heap), - mAllocator(new SimpleBestFitAllocator(heap->virtualSize())) -{ -} - -MemoryDealer::MemoryDealer( const sp<HeapInterface>& heap, - const sp<AllocatorInterface>& allocator) - : mHeap(heap), mAllocator(allocator) -{ -} - MemoryDealer::~MemoryDealer() { + delete mAllocator; } -sp<IMemory> MemoryDealer::allocate(size_t size, uint32_t flags) +sp<IMemory> MemoryDealer::allocate(size_t size) { sp<IMemory> memory; - const ssize_t offset = allocator()->allocate(size, flags); + const ssize_t offset = allocator()->allocate(size); if (offset >= 0) { - sp<IMemory> new_memory = heap()->mapMemory(offset, size); - if (new_memory != 0) { - memory = new Allocation(this, offset, size, new_memory); - } else { - LOGE("couldn't map [%8lx, %u]", offset, size); - if (size) { - /* NOTE: it's VERY important to not free allocations of size 0 - * because they're special as they don't have any record in the - * allocator and could alias some real allocation - * (their offset is zero). */ - allocator()->deallocate(offset); - } - } + memory = new Allocation(this, heap(), offset, size); } return memory; } @@ -133,16 +247,16 @@ void MemoryDealer::deallocate(size_t offset) allocator()->deallocate(offset); } -void MemoryDealer::dump(const char* what, uint32_t flags) const +void MemoryDealer::dump(const char* what) const { - allocator()->dump(what, flags); + allocator()->dump(what); } -const sp<HeapInterface>& MemoryDealer::heap() const { +const sp<IMemoryHeap>& MemoryDealer::heap() const { return mHeap; } -const sp<AllocatorInterface>& MemoryDealer::allocator() const { +SimpleBestFitAllocator* MemoryDealer::allocator() const { return mAllocator; } @@ -287,28 +401,28 @@ SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start) return 0; } -void SimpleBestFitAllocator::dump(const char* what, uint32_t flags) const +void SimpleBestFitAllocator::dump(const char* what) const { Mutex::Autolock _l(mLock); - dump_l(what, flags); + dump_l(what); } -void SimpleBestFitAllocator::dump_l(const char* what, uint32_t flags) const +void SimpleBestFitAllocator::dump_l(const char* what) const { String8 result; - dump_l(result, what, flags); + dump_l(result, what); LOGD("%s", result.string()); } void SimpleBestFitAllocator::dump(String8& result, - const char* what, uint32_t flags) const + const char* what) const { Mutex::Autolock _l(mLock); - dump_l(result, what, flags); + dump_l(result, what); } void SimpleBestFitAllocator::dump_l(String8& result, - const char* what, uint32_t flags) const + const char* what) const { size_t size = 0; int32_t i = 0; @@ -341,81 +455,10 @@ void SimpleBestFitAllocator::dump_l(String8& result, i++; cur = cur->next; } - snprintf(buffer, SIZE, " size allocated: %u (%u KB)\n", int(size), int(size/1024)); + snprintf(buffer, SIZE, + " size allocated: %u (%u KB)\n", int(size), int(size/1024)); result.append(buffer); } - -// ---------------------------------------------------------------------------- - -SharedHeap::SharedHeap() - : HeapInterface(), MemoryHeapBase() -{ -} -SharedHeap::SharedHeap(size_t size, uint32_t flags, char const * name) - : MemoryHeapBase(size, flags, name) -{ -} - -SharedHeap::~SharedHeap() -{ -} - -sp<IMemory> SharedHeap::mapMemory(size_t offset, size_t size) -{ - return new SimpleMemory(this, offset, size); -} - - -SimpleMemory::SimpleMemory(const sp<IMemoryHeap>& heap, - ssize_t offset, size_t size) - : MemoryBase(heap, offset, size) -{ -#ifndef NDEBUG - void* const start_ptr = (void*)(intptr_t(heap->base()) + offset); - memset(start_ptr, 0xda, size); -#endif -} - -SimpleMemory::~SimpleMemory() -{ - size_t freedOffset = getOffset(); - size_t freedSize = getSize(); - - // keep the size to unmap in excess - size_t pagesize = getpagesize(); - size_t start = freedOffset; - size_t end = start + freedSize; - start &= ~(pagesize-1); - end = (end + pagesize-1) & ~(pagesize-1); - - // give back to the kernel the pages we don't need - size_t free_start = freedOffset; - size_t free_end = free_start + freedSize; - if (start < free_start) - start = free_start; - if (end > free_end) - end = free_end; - start = (start + pagesize-1) & ~(pagesize-1); - end &= ~(pagesize-1); - - if (start < end) { - void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start); - size_t size = end-start; - -#ifndef NDEBUG - memset(start_ptr, 0xdf, size); -#endif - - // MADV_REMOVE is not defined on Dapper based Goobuntu -#ifdef MADV_REMOVE - if (size) { - int err = madvise(start_ptr, size, MADV_REMOVE); - LOGW_IF(err, "madvise(%p, %u, MADV_REMOVE) returned %s", - start_ptr, size, err<0 ? strerror(errno) : "Ok"); - } -#endif - } -} }; // namespace android diff --git a/libs/binder/MemoryHeapPmem.cpp b/libs/binder/MemoryHeapPmem.cpp index c66094761df5..16e92f939ee3 100644 --- a/libs/binder/MemoryHeapPmem.cpp +++ b/libs/binder/MemoryHeapPmem.cpp @@ -127,7 +127,7 @@ void SubRegionMemory::revoke() MemoryHeapPmem::MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap, uint32_t flags) - : HeapInterface(), MemoryHeapBase() + : MemoryHeapBase() { char const * const device = pmemHeap->getDevice(); #if HAVE_ANDROID_OS diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java index f6e63173b67b..df141c1919a2 100644 --- a/media/java/android/media/MiniThumbFile.java +++ b/media/java/android/media/MiniThumbFile.java @@ -17,7 +17,6 @@ package android.media; import android.graphics.Bitmap; -import android.media.ThumbnailUtil; import android.net.Uri; import android.os.Environment; import android.util.Log; diff --git a/media/java/android/media/ThumbnailUtil.java b/media/java/android/media/ThumbnailUtils.java index 0cf4e76d508c..225d4b6dea8f 100644 --- a/media/java/android/media/ThumbnailUtil.java +++ b/media/java/android/media/ThumbnailUtils.java @@ -16,13 +16,6 @@ package android.media; -import android.net.Uri; -import android.os.ParcelFileDescriptor; -import android.provider.BaseColumns; -import android.provider.MediaStore.Images; -import android.provider.MediaStore.Images.Thumbnails; -import android.util.Log; - import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; @@ -34,47 +27,171 @@ import android.graphics.Matrix; import android.graphics.Rect; import android.media.MediaMetadataRetriever; import android.media.MediaFile.MediaFileType; +import android.net.Uri; +import android.os.ParcelFileDescriptor; +import android.provider.BaseColumns; +import android.provider.MediaStore.Images; +import android.provider.MediaStore.Images.Thumbnails; +import android.util.Log; import java.io.FileDescriptor; import java.io.IOException; import java.io.OutputStream; /** - * Thumbnail generation routines for media provider. This class should only be used internaly. - * {@hide} THIS IS NOT FOR PUBLIC API. + * Thumbnail generation routines for media provider. */ -public class ThumbnailUtil { - private static final String TAG = "ThumbnailUtil"; - //Whether we should recycle the input (unless the output is the input). +public class ThumbnailUtils { + private static final String TAG = "ThumbnailUtils"; + + /* Maximum pixels size for created bitmap. */ + private static final int THUMBNAIL_MAX_NUM_PIXELS = 512 * 384; + private static final int MINI_THUMB_MAX_NUM_PIXELS = 128 * 128; + private static final int UNCONSTRAINED = -1; + + /* Whether we should rotate the resulting bitmap. */ + private static final boolean ROTATE_AS_NEEDED = true; + private static final boolean NO_ROTATE = false; + + /* Whether we should create bitmap in native memory. */ + private static final boolean USE_NATIVE = true; + private static final boolean NO_NATIVE = false; + + /** + * Constant used to indicate we should recycle the input in + * {@link #extractMiniThumb(Bitmap, int, int, boolean)} unless the output is the input. + */ public static final boolean RECYCLE_INPUT = true; + + /** + * Constant used to indicate we should not recycle the input in + * {@link #extractMiniThumb(Bitmap, int, int, boolean)}. + */ public static final boolean NO_RECYCLE_INPUT = false; - public static final boolean ROTATE_AS_NEEDED = true; - public static final boolean NO_ROTATE = false; - public static final boolean USE_NATIVE = true; - public static final boolean NO_NATIVE = false; + /** + * Constant used to indicate the dimension of normal thumbnail in + * {@link #extractMiniThumb(Bitmap, int, int, boolean)}. + */ public static final int THUMBNAIL_TARGET_SIZE = 320; + + /** + * Constant used to indicate the dimension of mini thumbnail in + * {@link #extractMiniThumb(Bitmap, int, int, boolean)}. + */ public static final int MINI_THUMB_TARGET_SIZE = 96; - public static final int THUMBNAIL_MAX_NUM_PIXELS = 512 * 384; - public static final int MINI_THUMB_MAX_NUM_PIXELS = 128 * 128; - public static final int UNCONSTRAINED = -1; - // Returns Options that set the native alloc flag for Bitmap decode. - public static BitmapFactory.Options createNativeAllocOptions() { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inNativeAlloc = true; - return options; + /** + * This method first examines if the thumbnail embedded in EXIF is bigger than our target + * size. If not, then it'll create a thumbnail from original image. Due to efficiency + * consideration, we want to let MediaThumbRequest avoid calling this method twice for + * both kinds, so it only requests for MICRO_KIND and set saveImage to true. + * + * This method always returns a "square thumbnail" for MICRO_KIND thumbnail. + * + * @param cr ContentResolver + * @param filePath file path needed by EXIF interface + * @param uri URI of original image + * @param origId image id + * @param kind either MINI_KIND or MICRO_KIND + * @param saveMini Whether to save MINI_KIND thumbnail obtained in this method. + * @return Bitmap + */ + public static Bitmap createImageThumbnail(ContentResolver cr, String filePath, Uri uri, + long origId, int kind, boolean saveMini) { + boolean wantMini = (kind == Images.Thumbnails.MINI_KIND || saveMini); + int targetSize = wantMini ? + THUMBNAIL_TARGET_SIZE : MINI_THUMB_TARGET_SIZE; + int maxPixels = wantMini ? + THUMBNAIL_MAX_NUM_PIXELS : MINI_THUMB_MAX_NUM_PIXELS; + SizedThumbnailBitmap sizedThumbnailBitmap = new SizedThumbnailBitmap(); + Bitmap bitmap = null; + MediaFileType fileType = MediaFile.getFileType(filePath); + if (fileType != null && fileType.fileType == MediaFile.FILE_TYPE_JPEG) { + createThumbnailFromEXIF(filePath, targetSize, maxPixels, sizedThumbnailBitmap); + bitmap = sizedThumbnailBitmap.mBitmap; + } + + if (bitmap == null) { + bitmap = makeBitmap(targetSize, maxPixels, uri, cr); + } + + if (bitmap == null) { + return null; + } + + if (saveMini) { + if (sizedThumbnailBitmap.mThumbnailData != null) { + storeThumbnail(cr, origId, + sizedThumbnailBitmap.mThumbnailData, + sizedThumbnailBitmap.mThumbnailWidth, + sizedThumbnailBitmap.mThumbnailHeight); + } else { + storeThumbnail(cr, origId, bitmap); + } + } + + if (kind == Images.Thumbnails.MICRO_KIND) { + // now we make it a "square thumbnail" for MICRO_KIND thumbnail + bitmap = extractMiniThumb(bitmap, + MINI_THUMB_TARGET_SIZE, + MINI_THUMB_TARGET_SIZE, RECYCLE_INPUT); + } + return bitmap; } + /** - * Make a bitmap from a given Uri. + * Create a video thumbnail for a video. May return null if the video is + * corrupt. * - * @param uri + * @param filePath */ - public static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, - Uri uri, ContentResolver cr) { - return makeBitmap(minSideLength, maxNumOfPixels, uri, cr, - NO_NATIVE); + public static Bitmap createVideoThumbnail(String filePath) { + Bitmap bitmap = null; + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + try { + retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY); + retriever.setDataSource(filePath); + bitmap = retriever.captureFrame(); + } catch (IllegalArgumentException ex) { + // Assume this is a corrupt video file + } catch (RuntimeException ex) { + // Assume this is a corrupt video file. + } finally { + try { + retriever.release(); + } catch (RuntimeException ex) { + // Ignore failures while cleaning up. + } + } + return bitmap; + } + + /** + * Creates a centered bitmap of the desired size. + * + * @param source original bitmap source + * @param width targeted width + * @param height targeted height + * @param recycle whether we want to recycle the input + */ + public static Bitmap extractMiniThumb( + Bitmap source, int width, int height, boolean recycle) { + if (source == null) { + return null; + } + + float scale; + if (source.getWidth() < source.getHeight()) { + scale = width / (float) source.getWidth(); + } else { + scale = height / (float) source.getHeight(); + } + Matrix matrix = new Matrix(); + matrix.setScale(scale, scale); + Bitmap miniThumbnail = transform(matrix, source, width, height, true, recycle); + return miniThumbnail; } /* @@ -96,7 +213,7 @@ public class ThumbnailUtil { * For example, BitmapFactory downsamples an image by 2 even though the * request is 3. So we round up the sample size to avoid OOM. */ - public static int computeSampleSize(BitmapFactory.Options options, + private static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) { int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels); @@ -140,7 +257,30 @@ public class ThumbnailUtil { } } - public static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, + /** + * Returns Options that set the native alloc flag for Bitmap decode. + */ + private static BitmapFactory.Options createNativeAllocOptions() { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inNativeAlloc = true; + return options; + } + + /** + * Make a bitmap from a given Uri, minimal side length, and maximum number of pixels. + */ + private static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, + Uri uri, ContentResolver cr) { + return makeBitmap(minSideLength, maxNumOfPixels, uri, cr, + NO_NATIVE); + } + + /** + * Make a bitmap from a given Uri, minimal side length, and maximum number of pixels. + * The image data will be read from specified ContentResolver and clients are allowed to specify + * whether they want the Bitmap be created in native memory. + */ + private static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, Uri uri, ContentResolver cr, boolean useNative) { ParcelFileDescriptor input = null; try { @@ -159,49 +299,18 @@ public class ThumbnailUtil { } } - // Rotates the bitmap by the specified degree. - // If a new bitmap is created, the original bitmap is recycled. - public static Bitmap rotate(Bitmap b, int degrees) { - if (degrees != 0 && b != null) { - Matrix m = new Matrix(); - m.setRotate(degrees, - (float) b.getWidth() / 2, (float) b.getHeight() / 2); - try { - Bitmap b2 = Bitmap.createBitmap( - b, 0, 0, b.getWidth(), b.getHeight(), m, true); - if (b != b2) { - b.recycle(); - b = b2; - } - } catch (OutOfMemoryError ex) { - // We have no memory to rotate. Return the original bitmap. - } - } - return b; - } - - private static void closeSilently(ParcelFileDescriptor c) { - if (c == null) return; - try { - c.close(); - } catch (Throwable t) { - // do nothing - } - } - - private static ParcelFileDescriptor makeInputStream( - Uri uri, ContentResolver cr) { - try { - return cr.openFileDescriptor(uri, "r"); - } catch (IOException ex) { - return null; - } - } - - public static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, - Uri uri, ContentResolver cr, ParcelFileDescriptor pfd, - BitmapFactory.Options options) { - Bitmap b = null; + /** + * Make a bitmap from a given Uri, minimal side length, and maximum number of pixels. + * The image data will be read from specified pfd if it's not null, otherwise + * a new input stream will be created using specified ContentResolver. + * + * Clients are allowed to pass their own BitmapFactory.Options used for bitmap decoding. A + * new BitmapFactory.Options will be created if options is null. + */ + private static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, + Uri uri, ContentResolver cr, ParcelFileDescriptor pfd, + BitmapFactory.Options options) { + Bitmap b = null; try { if (pfd == null) pfd = makeInputStream(uri, cr); if (pfd == null) return null; @@ -232,115 +341,50 @@ public class ThumbnailUtil { } /** - * Creates a centered bitmap of the desired size. - * @param source - * @param recycle whether we want to recycle the input - */ - public static Bitmap extractMiniThumb( - Bitmap source, int width, int height, boolean recycle) { - if (source == null) { - return null; - } - - float scale; - if (source.getWidth() < source.getHeight()) { - scale = width / (float) source.getWidth(); - } else { - scale = height / (float) source.getHeight(); - } - Matrix matrix = new Matrix(); - matrix.setScale(scale, scale); - Bitmap miniThumbnail = transform(matrix, source, width, height, true, recycle); - return miniThumbnail; - } - - /** - * Create a video thumbnail for a video. May return null if the video is - * corrupt. - * - * @param filePath + * Rotates the bitmap by the specified degree. + * If a new bitmap is created, the original bitmap is recycled. */ - public static Bitmap createVideoThumbnail(String filePath) { - Bitmap bitmap = null; - MediaMetadataRetriever retriever = new MediaMetadataRetriever(); - try { - retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY); - retriever.setDataSource(filePath); - bitmap = retriever.captureFrame(); - } catch (IllegalArgumentException ex) { - // Assume this is a corrupt video file - } catch (RuntimeException ex) { - // Assume this is a corrupt video file. - } finally { + private static Bitmap rotate(Bitmap b, int degrees) { + if (degrees != 0 && b != null) { + Matrix m = new Matrix(); + m.setRotate(degrees, + (float) b.getWidth() / 2, (float) b.getHeight() / 2); try { - retriever.release(); - } catch (RuntimeException ex) { - // Ignore failures while cleaning up. + Bitmap b2 = Bitmap.createBitmap( + b, 0, 0, b.getWidth(), b.getHeight(), m, true); + if (b != b2) { + b.recycle(); + b = b2; + } + } catch (OutOfMemoryError ex) { + // We have no memory to rotate. Return the original bitmap. } } - return bitmap; + return b; } - /** - * This method first examines if the thumbnail embedded in EXIF is bigger than our target - * size. If not, then it'll create a thumbnail from original image. Due to efficiency - * consideration, we want to let MediaThumbRequest avoid calling this method twice for - * both kinds, so it only requests for MICRO_KIND and set saveImage to true. - * - * This method always returns a "square thumbnail" for MICRO_KIND thumbnail. - * - * @param cr ContentResolver - * @param filePath file path needed by EXIF interface - * @param uri URI of original image - * @param origId image id - * @param kind either MINI_KIND or MICRO_KIND - * @param saveMini Whether to save MINI_KIND thumbnail obtained in this method. - * @return Bitmap - */ - public static Bitmap createImageThumbnail(ContentResolver cr, String filePath, Uri uri, - long origId, int kind, boolean saveMini) { - boolean wantMini = (kind == Images.Thumbnails.MINI_KIND || saveMini); - int targetSize = wantMini ? - ThumbnailUtil.THUMBNAIL_TARGET_SIZE : ThumbnailUtil.MINI_THUMB_TARGET_SIZE; - int maxPixels = wantMini ? - ThumbnailUtil.THUMBNAIL_MAX_NUM_PIXELS : ThumbnailUtil.MINI_THUMB_MAX_NUM_PIXELS; - SizedThumbnailBitmap sizedThumbnailBitmap = new SizedThumbnailBitmap(); - Bitmap bitmap = null; - MediaFileType fileType = MediaFile.getFileType(filePath); - if (fileType != null && fileType.fileType == MediaFile.FILE_TYPE_JPEG) { - createThumbnailFromEXIF(filePath, targetSize, maxPixels, sizedThumbnailBitmap); - bitmap = sizedThumbnailBitmap.mBitmap; - } - - if (bitmap == null) { - bitmap = ThumbnailUtil.makeBitmap(targetSize, maxPixels, uri, cr); - } + private static void closeSilently(ParcelFileDescriptor c) { + if (c == null) return; + try { + c.close(); + } catch (Throwable t) { + // do nothing + } + } - if (bitmap == null) { + private static ParcelFileDescriptor makeInputStream( + Uri uri, ContentResolver cr) { + try { + return cr.openFileDescriptor(uri, "r"); + } catch (IOException ex) { return null; } - - if (saveMini) { - if (sizedThumbnailBitmap.mThumbnailData != null) { - ThumbnailUtil.storeThumbnail(cr, origId, - sizedThumbnailBitmap.mThumbnailData, - sizedThumbnailBitmap.mThumbnailWidth, - sizedThumbnailBitmap.mThumbnailHeight); - } else { - ThumbnailUtil.storeThumbnail(cr, origId, bitmap); - } - } - - if (kind == Images.Thumbnails.MICRO_KIND) { - // now we make it a "square thumbnail" for MICRO_KIND thumbnail - bitmap = ThumbnailUtil.extractMiniThumb(bitmap, - ThumbnailUtil.MINI_THUMB_TARGET_SIZE, - ThumbnailUtil.MINI_THUMB_TARGET_SIZE, ThumbnailUtil.RECYCLE_INPUT); - } - return bitmap; } - public static Bitmap transform(Matrix scaler, + /** + * Transform source Bitmap to targeted width and height. + */ + private static Bitmap transform(Matrix scaler, Bitmap source, int targetWidth, int targetHeight, @@ -441,10 +485,6 @@ public class ThumbnailUtil { /** * Look up thumbnail uri by given imageId, it will be automatically created if it's not created * yet. Most of the time imageId is identical to thumbId, but it's not always true. - * @param req - * @param width - * @param height - * @return Uri Thumbnail uri */ private static Uri getImageThumbnailUri(ContentResolver cr, long origId, int width, int height) { Uri thumbUri = Images.Thumbnails.EXTERNAL_CONTENT_URI; @@ -513,10 +553,14 @@ public class ThumbnailUtil { } } - // SizedThumbnailBitmap contains the bitmap, which is downsampled either from - // the thumbnail in exif or the full image. - // mThumbnailData, mThumbnailWidth and mThumbnailHeight are set together only if mThumbnail is not null. - // The width/height of the sized bitmap may be different from mThumbnailWidth/mThumbnailHeight. + /** + * SizedThumbnailBitmap contains the bitmap, which is downsampled either from + * the thumbnail in exif or the full image. + * mThumbnailData, mThumbnailWidth and mThumbnailHeight are set together only if mThumbnail + * is not null. + * + * The width/height of the sized bitmap may be different from mThumbnailWidth/mThumbnailHeight. + */ private static class SizedThumbnailBitmap { public byte[] mThumbnailData; public Bitmap mBitmap; @@ -524,9 +568,11 @@ public class ThumbnailUtil { public int mThumbnailHeight; } - // Creates a bitmap by either downsampling from the thumbnail in EXIF or the full image. - // The functions returns a SizedThumbnailBitmap, - // which contains a downsampled bitmap and the thumbnail data in EXIF if exists. + /** + * Creates a bitmap by either downsampling from the thumbnail in EXIF or the full image. + * The functions returns a SizedThumbnailBitmap, + * which contains a downsampled bitmap and the thumbnail data in EXIF if exists. + */ private static void createThumbnailFromEXIF(String filePath, int targetSize, int maxPixels, SizedThumbnailBitmap sizedThumbBitmap) { if (filePath == null) return; diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index f4165ffede88..7bbd0b2e8e91 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -32,7 +32,6 @@ #include <binder/IServiceManager.h> #include <utils/Log.h> -#include <binder/MemoryDealer.h> #include <binder/Parcel.h> #include <binder/IPCThreadState.h> #include <utils/Timers.h> diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index ad0f42e95acc..74852dcd7a79 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -32,7 +32,6 @@ #include <media/AudioTrack.h> #include <utils/Log.h> -#include <binder/MemoryDealer.h> #include <binder/Parcel.h> #include <binder/IPCThreadState.h> #include <utils/Timers.h> diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp index 66de2eee69a4..162bebbad560 100644 --- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp +++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp @@ -253,7 +253,7 @@ sp<IMemory> MetadataRetrieverClient::captureFrame() return NULL; } size_t size = sizeof(VideoFrame) + frame->mSize; - mThumbnailDealer = new MemoryDealer(size); + mThumbnailDealer = new MemoryDealer(size, "MetadataRetrieverClient"); if (mThumbnailDealer == NULL) { LOGE("failed to create MemoryDealer"); delete frame; @@ -294,7 +294,7 @@ sp<IMemory> MetadataRetrieverClient::extractAlbumArt() return NULL; } size_t size = sizeof(MediaAlbumArt) + albumArt->mSize; - mAlbumArtDealer = new MemoryDealer(size); + mAlbumArtDealer = new MemoryDealer(size, "MetadataRetrieverClient"); if (mAlbumArtDealer == NULL) { LOGE("failed to create MemoryDealer object"); delete albumArt; diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp index 14842c099be4..efe7ebb641e3 100644 --- a/media/libstagefright/AudioPlayer.cpp +++ b/media/libstagefright/AudioPlayer.cpp @@ -58,12 +58,15 @@ void AudioPlayer::setSource(const sp<MediaSource> &source) { mSource = source; } -void AudioPlayer::start() { +status_t AudioPlayer::start() { CHECK(!mStarted); CHECK(mSource != NULL); status_t err = mSource->start(); - CHECK_EQ(err, OK); + + if (err != OK) { + return err; + } sp<MetaData> format = mSource->getFormat(); const char *mime; @@ -83,7 +86,11 @@ void AudioPlayer::start() { mSampleRate, numChannels, AudioSystem::PCM_16_BIT, DEFAULT_AUDIOSINK_BUFFERCOUNT, &AudioPlayer::AudioSinkCallback, this); - CHECK_EQ(err, OK); + if (err != OK) { + mSource->stop(); + + return err; + } mLatencyUs = (int64_t)mAudioSink->latency() * 1000; mFrameSize = mAudioSink->frameSize(); @@ -97,7 +104,14 @@ void AudioPlayer::start() { : AudioSystem::CHANNEL_OUT_MONO, 8192, 0, &AudioCallback, this, 0); - CHECK_EQ(mAudioTrack->initCheck(), OK); + if (mAudioTrack->initCheck() != OK) { + delete mAudioTrack; + mAudioTrack = NULL; + + mSource->stop(); + + return mAudioTrack->initCheck(); + } mLatencyUs = (int64_t)mAudioTrack->latency() * 1000; mFrameSize = mAudioTrack->frameSize(); @@ -106,6 +120,8 @@ void AudioPlayer::start() { } mStarted = true; + + return OK; } void AudioPlayer::pause() { diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 85019aae02cb..4e7738e637c3 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -378,7 +378,16 @@ status_t AwesomePlayer::play() { &AwesomePlayer::AudioNotify, this); mAudioPlayer->setSource(mAudioSource); - mAudioPlayer->start(); + status_t err = mAudioPlayer->start(); + + if (err != OK) { + delete mAudioPlayer; + mAudioPlayer = NULL; + + mFlags &= ~(PLAYING | FIRST_FRAME); + + return err; + } delete mTimeSource; mTimeSource = mAudioPlayer; diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 5370c394d390..6274a6c6a648 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -28,6 +28,7 @@ #include <string.h> #include <media/stagefright/DataSource.h> +#include "include/ESDS.h" #include <media/stagefright/MediaBuffer.h> #include <media/stagefright/MediaBufferGroup.h> #include <media/stagefright/MediaDebug.h> @@ -898,6 +899,21 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) { mLastTrack->meta->setData( kKeyESDS, kTypeESDS, &buffer[4], chunk_data_size - 4); + if (mPath.size() >= 2 + && mPath[mPath.size() - 2] == FOURCC('m', 'p', '4', 'a')) { + // Information from the ESDS must be relied on for proper + // setup of sample rate and channel count for MPEG4 Audio. + // The generic header appears to only contain generic + // information... + + status_t err = updateAudioTrackInfoFromESDS_MPEG4Audio( + &buffer[4], chunk_data_size - 4); + + if (err != OK) { + return err; + } + } + *offset += chunk_size; break; } @@ -1121,6 +1137,86 @@ sp<MediaSource> MPEG4Extractor::getTrack(size_t index) { track->meta, mDataSource, track->timescale, track->sampleTable); } +status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio( + const void *esds_data, size_t esds_size) { + ESDS esds(esds_data, esds_size); + const uint8_t *csd; + size_t csd_size; + if (esds.getCodecSpecificInfo( + (const void **)&csd, &csd_size) != OK) { + return ERROR_MALFORMED; + } + +#if 0 + printf("ESD of size %d\n", csd_size); + hexdump(csd, csd_size); +#endif + + if (csd_size < 2) { + return ERROR_MALFORMED; + } + + uint32_t objectType = csd[0] >> 3; + + if (objectType == 31) { + return ERROR_UNSUPPORTED; + } + + uint32_t freqIndex = (csd[0] & 7) << 1 | (csd[1] >> 7); + int32_t sampleRate = 0; + int32_t numChannels = 0; + if (freqIndex == 15) { + if (csd_size < 5) { + return ERROR_MALFORMED; + } + + sampleRate = (csd[1] & 0x7f) << 17 + | csd[2] << 9 + | csd[3] << 1 + | (csd[4] >> 7); + + numChannels = (csd[4] >> 3) & 15; + } else { + static uint32_t kSamplingRate[] = { + 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, + 16000, 12000, 11025, 8000, 7350 + }; + + if (freqIndex == 13 || freqIndex == 14) { + return ERROR_MALFORMED; + } + + sampleRate = kSamplingRate[freqIndex]; + numChannels = (csd[1] >> 3) & 15; + } + + if (numChannels == 0) { + return ERROR_UNSUPPORTED; + } + + int32_t prevSampleRate; + CHECK(mLastTrack->meta->findInt32(kKeySampleRate, &prevSampleRate)); + + if (prevSampleRate != sampleRate) { + LOGW("mpeg4 audio sample rate different from previous setting. " + "was: %d, now: %d", prevSampleRate, sampleRate); + } + + mLastTrack->meta->setInt32(kKeySampleRate, sampleRate); + + int32_t prevChannelCount; + CHECK(mLastTrack->meta->findInt32(kKeyChannelCount, &prevChannelCount)); + + if (prevChannelCount != numChannels) { + LOGW("mpeg4 audio channel count different from previous setting. " + "was: %d, now: %d", prevChannelCount, numChannels); + } + + mLastTrack->meta->setInt32(kKeyChannelCount, numChannels); + + return OK; +} + //////////////////////////////////////////////////////////////////////////////// MPEG4Source::MPEG4Source( diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 986dcb2f998d..e17fbb8ed31e 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -1183,7 +1183,7 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) { } size_t totalSize = def.nBufferCountActual * def.nBufferSize; - mDealer[portIndex] = new MemoryDealer(totalSize); + mDealer[portIndex] = new MemoryDealer(totalSize, "OMXCodec"); for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) { sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize); diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp index da8fe795da95..7365dfafcb52 100644 --- a/media/libstagefright/WAVExtractor.cpp +++ b/media/libstagefright/WAVExtractor.cpp @@ -178,7 +178,8 @@ status_t WAVExtractor::init() { mBitsPerSample = U16_LE_AT(&formatSpec[14]); - if (mBitsPerSample != 8 && mBitsPerSample != 16) { + if (mBitsPerSample != 8 && mBitsPerSample != 16 + && mBitsPerSample != 24) { return ERROR_UNSUPPORTED; } @@ -329,6 +330,24 @@ status_t WAVSource::read( buffer->release(); buffer = tmp; + } else if (mBitsPerSample == 24) { + // Convert 24-bit signed samples to 16-bit signed. + + const uint8_t *src = + (const uint8_t *)buffer->data() + buffer->range_offset(); + int16_t *dst = (int16_t *)src; + + size_t numSamples = buffer->range_length() / 3; + for (size_t i = 0; i < numSamples; ++i) { + int32_t x = (int32_t)(src[0] | src[1] << 8 | src[2] << 16); + x = (x << 8) >> 8; // sign extension + + x = x >> 8; + *dst++ = (int16_t)x; + src += 3; + } + + buffer->set_range(buffer->range_offset(), 2 * numSamples); } size_t bytesPerSample = mBitsPerSample >> 3; diff --git a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp index 36272eac8cc5..aa2a3d146f27 100644 --- a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp +++ b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp @@ -322,8 +322,10 @@ status_t AVCDecoder::read( crop_top = crop_left = 0; } - mFormat->setInt32(kKeyWidth, crop_right - crop_left + 1); - mFormat->setInt32(kKeyHeight, crop_bottom - crop_top + 1); + int32_t aligned_width = (crop_right - crop_left + 1 + 15) & ~15; + int32_t aligned_height = (crop_bottom - crop_top + 1 + 15) & ~15; + mFormat->setInt32(kKeyWidth, aligned_width); + mFormat->setInt32(kKeyHeight, aligned_height); mInputBuffer->release(); mInputBuffer = NULL; diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h index 1a1344654aea..3a63e8872b4e 100644 --- a/media/libstagefright/include/MPEG4Extractor.h +++ b/media/libstagefright/include/MPEG4Extractor.h @@ -65,6 +65,9 @@ private: status_t parseChunk(off_t *offset, int depth); status_t parseMetaData(off_t offset, size_t size); + status_t updateAudioTrackInfoFromESDS_MPEG4Audio( + const void *esds_data, size_t esds_size); + MPEG4Extractor(const MPEG4Extractor &); MPEG4Extractor &operator=(const MPEG4Extractor &); }; diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp index 6c36163fb23b..51fcaf5f4438 100644 --- a/media/libstagefright/omx/tests/OMXHarness.cpp +++ b/media/libstagefright/omx/tests/OMXHarness.cpp @@ -286,7 +286,7 @@ status_t Harness::testStateTransitions( return OK; } - sp<MemoryDealer> dealer = new MemoryDealer(8 * 1024 * 1024); + sp<MemoryDealer> dealer = new MemoryDealer(8 * 1024 * 1024, "OMXHarness"); IOMX::node_id node; status_t err = diff --git a/opengl/java/com/google/android/gles_jni/GLImpl.java b/opengl/java/com/google/android/gles_jni/GLImpl.java index 01a9c913626f..30b9325e651e 100644 --- a/opengl/java/com/google/android/gles_jni/GLImpl.java +++ b/opengl/java/com/google/android/gles_jni/GLImpl.java @@ -48,6 +48,12 @@ public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack { Buffer _pointSizePointerOES = null; Buffer _matrixIndexPointerOES = null; Buffer _weightPointerOES = null; + + private boolean haveCheckedExtensions; + private boolean have_OES_blend_equation_separate; + private boolean have_OES_blend_subtract; + private boolean have_OES_framebuffer_object; + private boolean have_OES_texture_cube_map; public GLImpl() { } @@ -1935,7 +1941,7 @@ public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack { int target ); - // C function void glDeleteFramebuffersOES ( GLint n, GLint *framebuffers ) + // C function void glDeleteFramebuffersOES ( GLint n, GLuint *framebuffers ) public native void glDeleteFramebuffersOES( int n, @@ -1943,14 +1949,14 @@ public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack { int offset ); - // C function void glDeleteFramebuffersOES ( GLint n, GLint *framebuffers ) + // C function void glDeleteFramebuffersOES ( GLint n, GLuint *framebuffers ) public native void glDeleteFramebuffersOES( int n, java.nio.IntBuffer framebuffers ); - // C function void glDeleteRenderbuffersOES ( GLint n, GLint *renderbuffers ) + // C function void glDeleteRenderbuffersOES ( GLint n, GLuint *renderbuffers ) public native void glDeleteRenderbuffersOES( int n, @@ -1958,7 +1964,7 @@ public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack { int offset ); - // C function void glDeleteRenderbuffersOES ( GLint n, GLint *renderbuffers ) + // C function void glDeleteRenderbuffersOES ( GLint n, GLuint *renderbuffers ) public native void glDeleteRenderbuffersOES( int n, @@ -1990,7 +1996,7 @@ public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack { int target ); - // C function void glGenFramebuffersOES ( GLint n, GLint *framebuffers ) + // C function void glGenFramebuffersOES ( GLint n, GLuint *framebuffers ) public native void glGenFramebuffersOES( int n, @@ -1998,14 +2004,14 @@ public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack { int offset ); - // C function void glGenFramebuffersOES ( GLint n, GLint *framebuffers ) + // C function void glGenFramebuffersOES ( GLint n, GLuint *framebuffers ) public native void glGenFramebuffersOES( int n, java.nio.IntBuffer framebuffers ); - // C function void glGenRenderbuffersOES ( GLint n, GLint *renderbuffers ) + // C function void glGenRenderbuffersOES ( GLint n, GLuint *renderbuffers ) public native void glGenRenderbuffersOES( int n, @@ -2013,7 +2019,7 @@ public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack { int offset ); - // C function void glGenRenderbuffersOES ( GLint n, GLint *renderbuffers ) + // C function void glGenRenderbuffersOES ( GLint n, GLuint *renderbuffers ) public native void glGenRenderbuffersOES( int n, diff --git a/opengl/tools/glgen/specs/jsr239/glspec-1.1extpack b/opengl/tools/glgen/specs/jsr239/glspec-1.1extpack index ca9e6d2c5e3e..d6012d946936 100644 --- a/opengl/tools/glgen/specs/jsr239/glspec-1.1extpack +++ b/opengl/tools/glgen/specs/jsr239/glspec-1.1extpack @@ -7,14 +7,14 @@ void glBlendFuncSeparate ( GLint srcRGB, GLint dstRGB, GLint srcAlpha, GLint dst GLint glCheckFramebufferStatusOES ( GLint target ) void glCompressedTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data ) void glCopyTexImage2D ( GLint target, GLint level, GLint internalformat, GLint x, GLint y, GLint width, GLint height, GLint border ) -void glDeleteFramebuffersOES ( GLint n, GLint *framebuffers ) -void glDeleteRenderbuffersOES ( GLint n, GLint *renderbuffers ) +void glDeleteFramebuffersOES ( GLint n, GLuint *framebuffers ) +void glDeleteRenderbuffersOES ( GLint n, GLuint *renderbuffers ) void glEnable ( GLint cap ) void glFramebufferRenderbufferOES ( GLint target, GLint attachment, GLint renderbuffertarget, GLint renderbuffer ) void glFramebufferTexture2DOES ( GLint target, GLint attachment, GLint textarget, GLint texture, GLint level ) void glGenerateMipmapOES ( GLint target ) -void glGenFramebuffersOES ( GLint n, GLint *framebuffers ) -void glGenRenderbuffersOES ( GLint n, GLint *renderbuffers ) +void glGenFramebuffersOES ( GLint n, GLuint *framebuffers ) +void glGenRenderbuffersOES ( GLint n, GLuint *renderbuffers ) void glGetFramebufferAttachmentParameterivOES ( GLint target, GLint attachment, GLint pname, GLint *params ) void glGetIntegerv ( GLint pname, GLint *params ) void glGetRenderbufferParameterivOES ( GLint target, GLint pname, GLint *params ) diff --git a/opengl/tools/glgen/specs/jsr239/glspec-checks b/opengl/tools/glgen/specs/jsr239/glspec-checks index c28e403002e9..9f8a793cc32f 100644 --- a/opengl/tools/glgen/specs/jsr239/glspec-checks +++ b/opengl/tools/glgen/specs/jsr239/glspec-checks @@ -29,28 +29,28 @@ glDrawTexfvOES check coords 5 glDrawTexivOES check coords 5 glDrawTexsvOES check coords 5 glDrawTexxvOES check coords 5 -glBindFramebufferOES unsupported -glBindRenderbufferOES unsupported -glBlendEquation unsupported -glBlendEquationSeparate unsupported -glBlendFuncSeparate unsupported -glCheckFramebufferStatusOES unsupported return 0 -glDeleteFramebuffersOES unsupported -glDeleteRenderbuffersOES unsupported -glFramebufferRenderbufferOES unsupported -glFramebufferStorageOES unsupported -glFramebufferTexture2DOES unsupported -glGenFramebuffersOES unsupported -glGenRenderbuffersOES unsupported -glGenerateMipmapOES unsupported +glBindFramebufferOES requires OES_framebuffer_object +glBindRenderbufferOES requires OES_framebuffer_object +glBlendEquation requires OES_blend_subtract +glBlendEquationSeparate requires OES_blend_equation_separate +glBlendFuncSeparate requires OES_blend_equation_separate +glCheckFramebufferStatusOES requires OES_framebuffer_object return 0 +glDeleteFramebuffersOES requires OES_framebuffer_object check framebuffers n +glDeleteRenderbuffersOES requires OES_framebuffer_object check renderbuffers n +glFramebufferRenderbufferOES requires OES_framebuffer_object +glFramebufferStorageOES requires OES_framebuffer_object +glFramebufferTexture2DOES requires OES_framebuffer_object +glGenFramebuffersOES requires OES_framebuffer_object check framebuffers n +glGenRenderbuffersOES requires OES_framebuffer_object check renderbuffers n +glGenerateMipmapOES requires OES_framebuffer_object +glGetFramebufferAttachmentParameterivOES requires OES_framebuffer_object +glGetRenderbufferParameterivOES requires OES_framebuffer_object +glIsFramebufferOES requires OES_framebuffer_object return JNI_FALSE +glIsRenderbufferOES requires OES_framebuffer_object return JNI_FALSE +glRenderbufferStorageOES requires OES_framebuffer_object +glGetTexGen requires OES_texture_cube_map +glTexGen requires OES_texture_cube_map +glTexGenf requires OES_texture_cube_map +glTexGeni requires OES_texture_cube_map +glTexGenx requires OES_texture_cube_map glGetBufferParameter unsupported -glGetFramebufferAttachmentParameterivOES unsupported -glGetRenderbufferParameterivOES unsupported -glGetTexGen unsupported -glIsFramebufferOES unsupported return JNI_FALSE -glIsRenderbufferOES unsupported return JNI_FALSE -glRenderbufferStorageOES unsupported return false -glTexGen unsupported -glTexGenf unsupported -glTexGeni unsupported -glTexGenx unsupported diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java index e79170a28a8b..2db4e8d2e243 100644 --- a/opengl/tools/glgen/src/JniCodeEmitter.java +++ b/opengl/tools/glgen/src/JniCodeEmitter.java @@ -211,6 +211,8 @@ public class JniCodeEmitter { index += 5; } else if (checks[index].equals("unsupported")) { index += 1; + } else if (checks[index].equals("requires")) { + index += 2; } else if (checks[index].equals("nullAllowed")) { return true; } else { @@ -243,6 +245,8 @@ public class JniCodeEmitter { index += 5; } else if (checks[index].equals("unsupported")) { index += 1; + } else if (checks[index].equals("requires")) { + index += 2; } else if (checks[index].equals("nullAllowed")) { index += 1; } else { @@ -263,6 +267,8 @@ public class JniCodeEmitter { while (index < checks.length) { if (checks[index].equals("unsupported")) { return true; + } else if (checks[index].equals("requires")) { + index += 2; } else if (checks[index].equals("return")) { index += 2; } else if (checks[index].startsWith("check")) { @@ -280,7 +286,34 @@ public class JniCodeEmitter { } return false; } - + + String isRequiresFunc(CFunc cfunc) { + String[] checks = mChecker.getChecks(cfunc.getName()); + int index = 1; + if (checks != null) { + while (index < checks.length) { + if (checks[index].equals("unsupported")) { + index += 1; + } else if (checks[index].equals("requires")) { + return checks[index+1]; + } else if (checks[index].equals("return")) { + index += 2; + } else if (checks[index].startsWith("check")) { + index += 3; + } else if (checks[index].equals("ifcheck")) { + index += 5; + } else if (checks[index].equals("nullAllowed")) { + index += 1; + } else { + System.out.println("Error: unknown keyword \"" + + checks[index] + "\""); + System.exit(0); + } + } + } + return null; + } + void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out, boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) { @@ -365,6 +398,9 @@ public class JniCodeEmitter { } else if (checks[index].equals("unsupported")) { // ignore index += 1; + } else if (checks[index].equals("requires")) { + // ignore + index += 2; } else if (checks[index].equals("nullAllowed")) { // ignore index += 1; @@ -776,7 +812,23 @@ public class JniCodeEmitter { out.println(); return; } - + + String requiresExtension = isRequiresFunc(cfunc); + if (requiresExtension != null) { + out.println(indent + + "if (! supportsExtension(_env, _this, have_" + requiresExtension + "ID)) {"); + out.println(indent + indent + + "_env->ThrowNew(UOEClass,"); + out.println(indent + indent + + " \"" + cfunc.getName() + "\");"); + if (isVoid) { + out.println(indent + indent + " return;"); + } else { + String retval = getErrorReturnValue(cfunc); + out.println(indent + indent + " return " + retval + ";"); + } + out.println(indent + "}"); + } if (mUseContextPointer) { out.println(indent + "android::gl::ogles_context_t *ctx = getContext(_env, _this);"); diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp index b3d1c6cb1512..c2464b05626e 100644 --- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp +++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp @@ -23,6 +23,23 @@ #include <GLES/gl.h> #include <GLES/glext.h> +// Work around differences between the generated name and the actual name. + +#define glBlendEquation glBlendEquationOES +#define glBlendEquationSeparate glBlendEquationSeparateOES +#define glBlendFuncSeparate glBlendFuncSeparateOES +#define glGetTexGenfv glGetTexGenfvOES +#define glGetTexGeniv glGetTexGenivOES +#define glGetTexGenxv glGetTexGenxvOES +#define glTexGenf glTexGenfOES +#define glTexGenfv glTexGenfvOES +#define glTexGeni glTexGeniOES +#define glTexGeniv glTexGenivOES +#define glTexGenx glTexGenxOES +#define glTexGenxv glTexGenxvOES + + + /* special calls implemented in Android's GLES wrapper used to more * efficiently bound-check passed arrays */ extern "C" { @@ -58,6 +75,11 @@ static jmethodID allowIndirectBuffersID; static jfieldID positionID; static jfieldID limitID; static jfieldID elementSizeShiftID; +static jfieldID haveCheckedExtensionsID; +static jfieldID have_OES_blend_equation_separateID; +static jfieldID have_OES_blend_subtractID; +static jfieldID have_OES_framebuffer_objectID; +static jfieldID have_OES_texture_cube_mapID; /* Cache method IDs each time the class is loaded. */ @@ -72,6 +94,11 @@ nativeClassInitBuffer(JNIEnv *_env) jclass g11impClassLocal = _env->FindClass("com/google/android/gles_jni/GLImpl"); G11ImplClass = (jclass) _env->NewGlobalRef(g11impClassLocal); + haveCheckedExtensionsID = _env->GetFieldID(G11ImplClass, "haveCheckedExtensions", "Z"); + have_OES_blend_equation_separateID = _env->GetFieldID(G11ImplClass, "have_OES_blend_equation_separate", "Z"); + have_OES_blend_subtractID = _env->GetFieldID(G11ImplClass, "have_OES_blend_subtract", "Z"); + have_OES_framebuffer_objectID = _env->GetFieldID(G11ImplClass, "have_OES_framebuffer_object", "Z"); + have_OES_texture_cube_mapID = _env->GetFieldID(G11ImplClass, "have_OES_texture_cube_map", "Z"); getBasePointerID = _env->GetStaticMethodID(nioAccessClass, "getBasePointer", "(Ljava/nio/Buffer;)J"); @@ -193,5 +220,63 @@ getNumCompressedTextureFormats() { return numCompressedTextureFormats; } +// Check if the extension at the head of pExtensions is pExtension. Note that pExtensions is +// terminated by either 0 or space, while pExtension is terminated by 0. + +static bool +extensionEqual(const GLubyte* pExtensions, const GLubyte* pExtension) { + while (true) { + char a = *pExtensions++; + char b = *pExtension++; + bool aEnd = a == '\0' || a == ' '; + bool bEnd = b == '\0'; + if ( aEnd || bEnd) { + return aEnd == bEnd; + } + if ( a != b ) { + return false; + } + } +} + +static const GLubyte* +nextExtension(const GLubyte* pExtensions) { + while (true) { + char a = *pExtensions++; + if ( a == '\0') { + return pExtensions-1; + } else if ( a == ' ') { + return pExtensions; + } + } +} + +static bool +checkForExtension(const GLubyte* pExtensions, const GLubyte* pExtension) { + for (;*pExtensions != '\0'; pExtensions = nextExtension(pExtensions)) { + if (extensionEqual(pExtensions, pExtension)) { + return true; + } + } + return false; +} + +static bool +supportsExtension(JNIEnv *_env, jobject impl, jfieldID fieldId) { + if (!_env->GetBooleanField(impl, haveCheckedExtensionsID)) { + _env->SetBooleanField(impl, haveCheckedExtensionsID, true); + const GLubyte* sExtensions = glGetString(GL_EXTENSIONS); + _env->SetBooleanField(impl, have_OES_blend_equation_separateID, + checkForExtension(sExtensions, (const GLubyte*) "GL_OES_blend_equation_separate")); + _env->SetBooleanField(impl, have_OES_blend_subtractID, + checkForExtension(sExtensions, (const GLubyte*) "GL_OES_blend_subtract")); + _env->SetBooleanField(impl, have_OES_framebuffer_objectID, + checkForExtension(sExtensions, (const GLubyte*) "GL_OES_framebuffer_object")); + _env->SetBooleanField(impl, have_OES_texture_cube_mapID, + checkForExtension(sExtensions, (const GLubyte*) "GL_OES_texture_cube_map")); + } + return _env->GetBooleanField(impl, fieldId); +} + // -------------------------------------------------------------------------- diff --git a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl index 76fea3f6a648..372710625e4c 100644 --- a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl +++ b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl @@ -47,6 +47,12 @@ public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack { Buffer _pointSizePointerOES = null; Buffer _matrixIndexPointerOES = null; Buffer _weightPointerOES = null; + + private boolean haveCheckedExtensions; + private boolean have_OES_blend_equation_separate; + private boolean have_OES_blend_subtract; + private boolean have_OES_framebuffer_object; + private boolean have_OES_texture_cube_map; public GLImpl() { } diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index 72e26f8775ae..62dcb0878f25 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -43,18 +43,20 @@ import android.os.Binder; import android.os.Bundle; import android.os.Environment; import android.os.Handler; +import android.os.HandlerThread; import android.os.IBinder; +import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; -import android.os.SystemProperties; import android.provider.Settings; import android.util.EventLog; import android.util.Log; import android.util.SparseArray; +import android.util.SparseIntArray; import com.android.internal.backup.BackupConstants; import com.android.internal.backup.IBackupTransport; @@ -98,20 +100,27 @@ class BackupManagerService extends IBackupManager.Stub { private static final int MSG_RUN_RESTORE = 3; private static final int MSG_RUN_CLEAR = 4; private static final int MSG_RUN_INITIALIZE = 5; + private static final int MSG_TIMEOUT = 6; // Timeout interval for deciding that a bind or clear-data has taken too long static final long TIMEOUT_INTERVAL = 10 * 1000; + // Timeout intervals for agent backup & restore operations + static final long TIMEOUT_BACKUP_INTERVAL = 30 * 1000; + static final long TIMEOUT_RESTORE_INTERVAL = 60 * 1000; + private Context mContext; private PackageManager mPackageManager; private IActivityManager mActivityManager; private PowerManager mPowerManager; private AlarmManager mAlarmManager; + IBackupManager mBackupManagerBinder; boolean mEnabled; // access to this is synchronized on 'this' boolean mProvisioned; PowerManager.WakeLock mWakelock; - final BackupHandler mBackupHandler = new BackupHandler(); + HandlerThread mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND); + BackupHandler mBackupHandler; PendingIntent mRunBackupIntent, mRunInitIntent; BroadcastReceiver mRunBackupReceiver, mRunInitReceiver; // map UIDs to the set of backup client services within that UID's app set @@ -185,6 +194,16 @@ class BackupManagerService extends IBackupManager.Stub { } } + // Bookkeeping of in-flight operations for timeout etc. purposes. The operation + // token is the index of the entry in the pending-operations list. + static final int OP_PENDING = 0; + static final int OP_ACKNOWLEDGED = 1; + static final int OP_TIMEOUT = -1; + + final SparseIntArray mCurrentOperations = new SparseIntArray(); + final Object mCurrentOpLock = new Object(); + final Random mTokenGenerator = new Random(); + // Where we keep our journal files and other bookkeeping File mBaseStateDir; File mDataDir; @@ -200,6 +219,115 @@ class BackupManagerService extends IBackupManager.Stub { HashSet<String> mPendingInits = new HashSet<String>(); // transport names volatile boolean mInitInProgress = false; + // ----- Asynchronous backup/restore handler thread ----- + + private class BackupHandler extends Handler { + public BackupHandler(Looper looper) { + super(looper); + } + + public void handleMessage(Message msg) { + + switch (msg.what) { + case MSG_RUN_BACKUP: + { + mLastBackupPass = System.currentTimeMillis(); + mNextBackupPass = mLastBackupPass + BACKUP_INTERVAL; + + IBackupTransport transport = getTransport(mCurrentTransport); + if (transport == null) { + Log.v(TAG, "Backup requested but no transport available"); + synchronized (mQueueLock) { + mBackupOrRestoreInProgress = false; + } + mWakelock.release(); + break; + } + + // snapshot the pending-backup set and work on that + ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>(); + synchronized (mQueueLock) { + // Do we have any work to do? + if (mPendingBackups.size() > 0) { + for (BackupRequest b: mPendingBackups.values()) { + queue.add(b); + } + if (DEBUG) Log.v(TAG, "clearing pending backups"); + mPendingBackups.clear(); + + // Start a new backup-queue journal file too + File oldJournal = mJournal; + mJournal = null; + + // At this point, we have started a new journal file, and the old + // file identity is being passed to the backup processing thread. + // When it completes successfully, that old journal file will be + // deleted. If we crash prior to that, the old journal is parsed + // at next boot and the journaled requests fulfilled. + (new PerformBackupTask(transport, queue, oldJournal)).run(); + } else { + Log.v(TAG, "Backup requested but nothing pending"); + synchronized (mQueueLock) { + mBackupOrRestoreInProgress = false; + } + mWakelock.release(); + } + } + break; + } + + case MSG_RUN_FULL_BACKUP: + break; + + case MSG_RUN_RESTORE: + { + RestoreParams params = (RestoreParams)msg.obj; + Log.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer); + (new PerformRestoreTask(params.transport, params.observer, + params.token)).run(); + break; + } + + case MSG_RUN_CLEAR: + { + ClearParams params = (ClearParams)msg.obj; + (new PerformClearTask(params.transport, params.packageInfo)).run(); + break; + } + + case MSG_RUN_INITIALIZE: + { + HashSet<String> queue; + + // Snapshot the pending-init queue and work on that + synchronized (mQueueLock) { + queue = new HashSet<String>(mPendingInits); + mPendingInits.clear(); + } + + (new PerformInitializeTask(queue)).run(); + break; + } + + case MSG_TIMEOUT: + { + synchronized (mCurrentOpLock) { + final int token = msg.arg1; + int state = mCurrentOperations.get(token, OP_TIMEOUT); + if (state == OP_PENDING) { + if (DEBUG) Log.v(TAG, "TIMEOUT: token=" + token); + mCurrentOperations.put(token, OP_TIMEOUT); + } + mCurrentOpLock.notifyAll(); + } + break; + } + } + } + } + + // ----- Main service implementation ----- + public BackupManagerService(Context context) { mContext = context; mPackageManager = context.getPackageManager(); @@ -208,6 +336,13 @@ class BackupManagerService extends IBackupManager.Stub { mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + mBackupManagerBinder = asInterface(asBinder()); + + // spin up the backup/restore handler thread + mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND); + mHandlerThread.start(); + mBackupHandler = new BackupHandler(mHandlerThread.getLooper()); + // Set up our bookkeeping boolean areEnabled = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.BACKUP_ENABLED, 0) != 0; @@ -506,7 +641,7 @@ class BackupManagerService extends IBackupManager.Stub { mTransports.put(name, transport); } else { mTransports.remove(name); - if (mCurrentTransport.equals(name)) { + if ((mCurrentTransport != null) && mCurrentTransport.equals(name)) { mCurrentTransport = null; } // Nothing further to do in the unregistration case @@ -593,95 +728,6 @@ class BackupManagerService extends IBackupManager.Stub { } }; - // ----- Run the actual backup process asynchronously ----- - - private class BackupHandler extends Handler { - public void handleMessage(Message msg) { - - switch (msg.what) { - case MSG_RUN_BACKUP: - { - mLastBackupPass = System.currentTimeMillis(); - mNextBackupPass = mLastBackupPass + BACKUP_INTERVAL; - - IBackupTransport transport = getTransport(mCurrentTransport); - if (transport == null) { - Log.v(TAG, "Backup requested but no transport available"); - synchronized (mQueueLock) { - mBackupOrRestoreInProgress = false; - } - mWakelock.release(); - break; - } - - // snapshot the pending-backup set and work on that - ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>(); - synchronized (mQueueLock) { - // Do we have any work to do? - if (mPendingBackups.size() > 0) { - for (BackupRequest b: mPendingBackups.values()) { - queue.add(b); - } - Log.v(TAG, "clearing pending backups"); - mPendingBackups.clear(); - - // Start a new backup-queue journal file too - File oldJournal = mJournal; - mJournal = null; - - // At this point, we have started a new journal file, and the old - // file identity is being passed to the backup processing thread. - // When it completes successfully, that old journal file will be - // deleted. If we crash prior to that, the old journal is parsed - // at next boot and the journaled requests fulfilled. - (new PerformBackupThread(transport, queue, oldJournal)).start(); - } else { - Log.v(TAG, "Backup requested but nothing pending"); - synchronized (mQueueLock) { - mBackupOrRestoreInProgress = false; - } - mWakelock.release(); - } - } - break; - } - - case MSG_RUN_FULL_BACKUP: - break; - - case MSG_RUN_RESTORE: - { - RestoreParams params = (RestoreParams)msg.obj; - Log.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer); - (new PerformRestoreThread(params.transport, params.observer, - params.token)).start(); - break; - } - - case MSG_RUN_CLEAR: - { - ClearParams params = (ClearParams)msg.obj; - (new PerformClearThread(params.transport, params.packageInfo)).start(); - break; - } - - case MSG_RUN_INITIALIZE: - { - HashSet<String> queue; - - // Snapshot the pending-init queue and work on that - synchronized (mQueueLock) { - queue = new HashSet<String>(mPendingInits); - mPendingInits.clear(); - } - - (new PerformInitializeThread(queue)).start(); - break; - } - } - } - } - // Add the backup agents in the given package to our set of known backup participants. // If 'packageName' is null, adds all backup agents in the whole system. void addPackageParticipantsLocked(String packageName) { @@ -978,16 +1024,44 @@ class BackupManagerService extends IBackupManager.Stub { } } + // ----- + // Utility methods used by the asynchronous-with-timeout backup/restore operations + boolean waitUntilOperationComplete(int token) { + int finalState = OP_PENDING; + synchronized (mCurrentOpLock) { + try { + while ((finalState = mCurrentOperations.get(token, OP_TIMEOUT)) == OP_PENDING) { + try { + mCurrentOpLock.wait(); + } catch (InterruptedException e) {} + } + } catch (IndexOutOfBoundsException e) { + // the operation has been mysteriously cleared from our + // bookkeeping -- consider this a success and ignore it. + } + } + mBackupHandler.removeMessages(MSG_TIMEOUT); + if (DEBUG) Log.v(TAG, "operation " + token + " complete: finalState=" + finalState); + return finalState == OP_ACKNOWLEDGED; + } + + void prepareOperationTimeout(int token, long interval) { + if (DEBUG) Log.v(TAG, "starting timeout: token=" + token + " interval=" + interval); + mCurrentOperations.put(token, OP_PENDING); + Message msg = mBackupHandler.obtainMessage(MSG_TIMEOUT, token, 0); + mBackupHandler.sendMessageDelayed(msg, interval); + } + // ----- Back up a set of applications via a worker thread ----- - class PerformBackupThread extends Thread { + class PerformBackupTask implements Runnable { private static final String TAG = "PerformBackupThread"; IBackupTransport mTransport; ArrayList<BackupRequest> mQueue; File mStateDir; File mJournal; - public PerformBackupThread(IBackupTransport transport, ArrayList<BackupRequest> queue, + public PerformBackupTask(IBackupTransport transport, ArrayList<BackupRequest> queue, File journal) { mTransport = transport; mQueue = queue; @@ -1000,7 +1074,6 @@ class BackupManagerService extends IBackupManager.Stub { } } - @Override public void run() { int status = BackupConstants.TRANSPORT_OK; long startRealtime = SystemClock.elapsedRealtime(); @@ -1158,6 +1231,7 @@ class BackupManagerService extends IBackupManager.Stub { ParcelFileDescriptor newState = null; PackageInfo packInfo; + int token = mTokenGenerator.nextInt(); try { // Look up the package info & signatures. This is first so that if it // throws an exception, there's no file setup yet that would need to @@ -1189,8 +1263,16 @@ class BackupManagerService extends IBackupManager.Stub { ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_TRUNCATE); - // Run the target's backup pass - agent.doBackup(savedState, backupData, newState); + // Initiate the target's backup pass + prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL); + agent.doBackup(savedState, backupData, newState, token, mBackupManagerBinder); + boolean success = waitUntilOperationComplete(token); + + if (!success) { + // timeout -- bail out into the failed-transaction logic + throw new RuntimeException("Backup timeout"); + } + logBackupComplete(packageName); if (DEBUG) Log.v(TAG, "doBackup() success"); } catch (Exception e) { @@ -1204,6 +1286,9 @@ class BackupManagerService extends IBackupManager.Stub { try { if (backupData != null) backupData.close(); } catch (IOException e) {} try { if (newState != null) newState.close(); } catch (IOException e) {} savedState = backupData = newState = null; + synchronized (mCurrentOpLock) { + mCurrentOperations.clear(); + } } // Now propagate the newly-backed-up data to the transport @@ -1299,7 +1384,7 @@ class BackupManagerService extends IBackupManager.Stub { return true; } - class PerformRestoreThread extends Thread { + class PerformRestoreTask implements Runnable { private IBackupTransport mTransport; private IRestoreObserver mObserver; private long mToken; @@ -1315,7 +1400,7 @@ class BackupManagerService extends IBackupManager.Stub { } } - PerformRestoreThread(IBackupTransport transport, IRestoreObserver observer, + PerformRestoreTask(IBackupTransport transport, IRestoreObserver observer, long restoreSetToken) { mTransport = transport; Log.d(TAG, "PerformRestoreThread mObserver=" + mObserver); @@ -1329,7 +1414,6 @@ class BackupManagerService extends IBackupManager.Stub { } } - @Override public void run() { long startRealtime = SystemClock.elapsedRealtime(); if (DEBUG) Log.v(TAG, "Beginning restore process mTransport=" + mTransport @@ -1579,6 +1663,7 @@ class BackupManagerService extends IBackupManager.Stub { ParcelFileDescriptor backupData = null; ParcelFileDescriptor newState = null; + int token = mTokenGenerator.nextInt(); try { // Run the transport's restore pass backupData = ParcelFileDescriptor.open(backupDataName, @@ -1602,7 +1687,14 @@ class BackupManagerService extends IBackupManager.Stub { ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_TRUNCATE); - agent.doRestore(backupData, appVersionCode, newState); + // Kick off the restore, checking for hung agents + prepareOperationTimeout(token, TIMEOUT_RESTORE_INTERVAL); + agent.doRestore(backupData, appVersionCode, newState, token, mBackupManagerBinder); + boolean success = waitUntilOperationComplete(token); + + if (!success) { + throw new RuntimeException("restore timeout"); + } // if everything went okay, remember the recorded state now // @@ -1635,20 +1727,20 @@ class BackupManagerService extends IBackupManager.Stub { try { if (backupData != null) backupData.close(); } catch (IOException e) {} try { if (newState != null) newState.close(); } catch (IOException e) {} backupData = newState = null; + mCurrentOperations.delete(token); } } } - class PerformClearThread extends Thread { + class PerformClearTask implements Runnable { IBackupTransport mTransport; PackageInfo mPackage; - PerformClearThread(IBackupTransport transport, PackageInfo packageInfo) { + PerformClearTask(IBackupTransport transport, PackageInfo packageInfo) { mTransport = transport; mPackage = packageInfo; } - @Override public void run() { try { // Clear the on-device backup state to ensure a full backup next time @@ -1678,14 +1770,13 @@ class BackupManagerService extends IBackupManager.Stub { } } - class PerformInitializeThread extends Thread { + class PerformInitializeTask implements Runnable { HashSet<String> mQueue; - PerformInitializeThread(HashSet<String> transportNames) { + PerformInitializeTask(HashSet<String> transportNames) { mQueue = transportNames; } - @Override public void run() { try { for (String transportName : mQueue) { @@ -2073,6 +2164,16 @@ class BackupManagerService extends IBackupManager.Stub { return mActiveRestoreSession; } + // Note that a currently-active backup agent has notified us that it has + // completed the given outstanding asynchronous backup/restore operation. + public void opComplete(int token) { + synchronized (mCurrentOpLock) { + if (DEBUG) Log.v(TAG, "opComplete: " + token); + mCurrentOperations.put(token, OP_ACKNOWLEDGED); + mCurrentOpLock.notifyAll(); + } + } + // ----- Restore session ----- class ActiveRestoreSession extends IRestoreSession.Stub { diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index cefd3124f80d..e14a9734c8c9 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -2011,6 +2011,10 @@ class PowerManagerService extends IPowerManager.Stub } } } + + if (mPolicy != null) { + mPolicy.userActivity(); + } } private int getAutoBrightnessValue(int sensorValue, int[] values) { diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 1d14e5e65684..88aadbd665ce 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -2385,7 +2385,8 @@ public class WindowManagerService extends IWindowManager.Stub // to provide the correct semantics while starting. final int mask = WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED - | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; + | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD + | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON; WindowManager.LayoutParams sa = win.mAppToken.startingWindow.mAttrs; sa.flags = (sa.flags&~mask) | (win.mAttrs.flags&mask); } |