Merge "Phase 2 of test cleanup: moving test files from AndroidTests closer to their sources."
diff --git a/Android.mk b/Android.mk
index 7717c76..369cdfd 100644
--- a/Android.mk
+++ b/Android.mk
@@ -317,7 +317,8 @@
 	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 @@
 
 ## 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 @@
 
 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 b03f826..3b6e031 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 2a58677..35b6fed 100644
--- a/core/java/android/app/BackupAgent.java
+++ b/core/java/android/app/BackupAgent.java
@@ -19,6 +19,7 @@
 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 @@
 
 
     // ----- 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 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 @@
                 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 @@
                 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 9b0550f..0de6ad9 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 @@
  *
  * {@hide}
  */ 
-interface IBackupAgent {
+oneway interface IBackupAgent {
     /**
      * Request that the app perform an incremental backup.
      *
@@ -39,10 +40,18 @@
      *
      * @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 @@
      * @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 9d181be..cb775f7 100644
--- a/core/java/android/backup/IBackupManager.aidl
+++ b/core/java/android/backup/IBackupManager.aidl
@@ -130,4 +130,14 @@
      * @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 119fc52..a884793 100644
--- a/core/java/android/backup/RestoreSession.java
+++ b/core/java/android/backup/RestoreSession.java
@@ -109,9 +109,7 @@
 
     /*
      * 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 bc59c94..d10c8f8 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.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 @@
      */
     @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 82490bb..e3c25ec 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -65,9 +65,8 @@
     /**
      * 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 @@
          * (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 @@
          * 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 @@
          * 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 @@
          * 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 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 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 @@
      * @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 @@
         // 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 @@
      * @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 @@
      *            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 @@
 
         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 95fa0a2..fa0fbbf 100644
--- a/core/java/android/ddm/DdmHandleHeap.java
+++ b/core/java/android/ddm/DdmHandleHeap.java
@@ -34,6 +34,7 @@
     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 @@
         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 @@
             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 @@
             result = -1;
         } catch (IOException ioe) {
             result = -1;
-        } catch (RuntimeException ioe) {
+        } catch (RuntimeException re) {
             result = -1;
         }
 
@@ -177,6 +181,38 @@
     }
 
     /*
+     * 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 8e9b11b..9ee251e 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -726,6 +726,18 @@
     }
 
     /**
+     * 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 1b938ee..211bc0a 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -28,7 +28,7 @@
 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 @@
                         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 8e15f89..0af31f0 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -369,6 +369,12 @@
          */
         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 21577bf..7bc5cce 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -827,6 +827,12 @@
     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 a830ebd..9da1066 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -102,7 +102,7 @@
     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 @@
     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 12bc5a8..23ec647 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -33,6 +33,9 @@
     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 @@
     // 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 7864189..694514e 100644
--- a/core/jni/CursorWindow.cpp
+++ b/core/jni/CursorWindow.cpp
@@ -60,7 +60,7 @@
 {
     //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 93e4d2b..bf613e1 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 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 @@
 
     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 @@
     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 @@
 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 a980efc..500ef58 100644
--- a/docs/html/guide/developing/debug-tasks.jd
+++ b/docs/html/guide/developing/debug-tasks.jd
@@ -58,8 +58,8 @@
 <pre class="no-pretty-print">
 I/MyActivity( 1557): MyClass.getView() &mdash; 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 @@
 
 <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 @@
 </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>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>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>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 @@
 <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 @@
 <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 03ac70a..170f20d 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;
+private:
+    const sp<IMemoryHeap>&      heap() const;
+    SimpleBestFitAllocator*     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;
-    };
-
-    sp<HeapInterface>           mHeap;
-    sp<AllocatorInterface>      mAllocator;
+    sp<IMemoryHeap>             mHeap;
+    SimpleBestFitAllocator*     mAllocator;
 };
 
 
diff --git a/include/binder/MemoryHeapPmem.h b/include/binder/MemoryHeapPmem.h
index dbf26ff..aac164f 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 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 71344e6..26fcc95 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -47,7 +47,7 @@
     // 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 cad420a..9d52882 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -2929,7 +2929,7 @@
 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 d5ffe7f..18669f7 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;
 
-AllocatorInterface::AllocatorInterface() { }
-AllocatorInterface::~AllocatorInterface() { }
-
-// ----------------------------------------------------------------------------
-
-class SimpleMemory : public MemoryBase {
 public:
-    SimpleMemory(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
-    virtual ~SimpleMemory();
+                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;
+    }
 };
 
+// ----------------------------------------------------------------------------
+
+class Allocation : public MemoryBase {
+public:
+    Allocation(const sp<MemoryDealer>& dealer,
+            const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
+    virtual ~Allocation();
+private:
+    sp<MemoryDealer> mDealer;
+};
 
 // ----------------------------------------------------------------------------
 
-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) 
+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;
+};
+
+// ----------------------------------------------------------------------------
+
+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);
 
-sp<IMemoryHeap> MemoryDealer::Allocation::getMemory(
-    ssize_t* offset, size_t* size) const
-{
-    return mMemory->getMemory(offset, size);
+        // 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
+        }
+    }
 }
 
 // ----------------------------------------------------------------------------
 
-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 @@
     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 @@
     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 @@
         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 c660947..16e92f9 100644
--- a/libs/binder/MemoryHeapPmem.cpp
+++ b/libs/binder/MemoryHeapPmem.cpp
@@ -127,7 +127,7 @@
 
 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 f6e6317..df141c1 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
similarity index 82%
rename from media/java/android/media/ThumbnailUtil.java
rename to media/java/android/media/ThumbnailUtils.java
index 0cf4e76..225d4b6 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.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 static final boolean RECYCLE_INPUT = true;
-    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;
+public class ThumbnailUtils {
+    private static final String TAG = "ThumbnailUtils";
 
-    public static final int THUMBNAIL_TARGET_SIZE = 320;
-    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;
+    /* 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;
 
-    // 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;
-    }
+    /* 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;
+
     /**
-     * Make a bitmap from a given Uri.
-     *
-     * @param uri
+     * Constant used to indicate we should recycle the input in
+     * {@link #extractMiniThumb(Bitmap, int, int, boolean)} unless the output is the input.
      */
-    public static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels,
-            Uri uri, ContentResolver cr) {
-        return makeBitmap(minSideLength, maxNumOfPixels, uri, cr,
-                NO_NATIVE);
+    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;
+
+    /**
+     * 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;
+
+    /**
+     * 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;
+    }
+
+    /**
+     * Create a video thumbnail for a video. May return null if the video is
+     * corrupt.
+     *
+     * @param filePath
+     */
+    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 @@
      * 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 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,9 +299,52 @@
         }
     }
 
-    // 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) {
+    /**
+     * 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;
+            if (options == null) options = new BitmapFactory.Options();
+
+            FileDescriptor fd = pfd.getFileDescriptor();
+            options.inSampleSize = 1;
+            options.inJustDecodeBounds = true;
+            BitmapFactory.decodeFileDescriptor(fd, null, options);
+            if (options.mCancel || options.outWidth == -1
+                    || options.outHeight == -1) {
+                return null;
+            }
+            options.inSampleSize = computeSampleSize(
+                    options, minSideLength, maxNumOfPixels);
+            options.inJustDecodeBounds = false;
+
+            options.inDither = false;
+            options.inPreferredConfig = Bitmap.Config.ARGB_8888;
+            b = BitmapFactory.decodeFileDescriptor(fd, null, options);
+        } catch (OutOfMemoryError ex) {
+            Log.e(TAG, "Got oom exception ", ex);
+            return null;
+        } finally {
+            closeSilently(pfd);
+        }
+        return b;
+    }
+
+    /**
+     * Rotates the bitmap by the specified degree.
+     * If a new bitmap is created, the original bitmap is recycled.
+     */
+    private static Bitmap rotate(Bitmap b, int degrees) {
         if (degrees != 0 && b != null) {
             Matrix m = new Matrix();
             m.setRotate(degrees,
@@ -198,149 +381,10 @@
         }
     }
 
-    public 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;
-            if (options == null) options = new BitmapFactory.Options();
-
-            FileDescriptor fd = pfd.getFileDescriptor();
-            options.inSampleSize = 1;
-            options.inJustDecodeBounds = true;
-            BitmapFactory.decodeFileDescriptor(fd, null, options);
-            if (options.mCancel || options.outWidth == -1
-                    || options.outHeight == -1) {
-                return null;
-            }
-            options.inSampleSize = computeSampleSize(
-                    options, minSideLength, maxNumOfPixels);
-            options.inJustDecodeBounds = false;
-
-            options.inDither = false;
-            options.inPreferredConfig = Bitmap.Config.ARGB_8888;
-            b = BitmapFactory.decodeFileDescriptor(fd, null, options);
-        } catch (OutOfMemoryError ex) {
-            Log.e(TAG, "Got oom exception ", ex);
-            return null;
-        } finally {
-            closeSilently(pfd);
-        }
-        return b;
-    }
-
     /**
-     * Creates a centered bitmap of the desired size.
-     * @param source
-     * @param recycle whether we want to recycle the input
+     * Transform source Bitmap to targeted width and height.
      */
-    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
-     */
-    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;
-    }
-
-    /**
-     * 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);
-        }
-
-        if (bitmap == null) {
-            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,
+    private static Bitmap transform(Matrix scaler,
             Bitmap source,
             int targetWidth,
             int targetHeight,
@@ -441,10 +485,6 @@
     /**
      * 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 @@
         }
     }
 
-    // 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 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 f4165ff..7bbd0b2 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 ad0f42e..74852dc 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 66de2ee..162bebb 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -253,7 +253,7 @@
         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 @@
         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 14842c0..efe7ebb 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -58,12 +58,15 @@
     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 @@
                 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 @@
                     : 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 @@
     }
 
     mStarted = true;
+
+    return OK;
 }
 
 void AudioPlayer::pause() {
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 85019aa..4e7738e 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -378,7 +378,16 @@
                         &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 5370c39..6274a6c 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 @@
             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 @@
             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 986dcb2..e17fbb8 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1183,7 +1183,7 @@
     }
 
     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 da8fe79..7365dfa 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -178,7 +178,8 @@
 
             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 @@
 
         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 36272ea..aa2a3d1 100644
--- a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
+++ b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
@@ -322,8 +322,10 @@
                 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 1a13446..3a63e88 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -65,6 +65,9 @@
     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 6c36163..51fcaf5 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -286,7 +286,7 @@
         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 01a9c91..30b9325 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 @@
     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 @@
         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 @@
         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 @@
         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 @@
         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 @@
         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 @@
         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 ca9e6d2..d6012d9 100644
--- a/opengl/tools/glgen/specs/jsr239/glspec-1.1extpack
+++ b/opengl/tools/glgen/specs/jsr239/glspec-1.1extpack
@@ -7,14 +7,14 @@
 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 c28e403..9f8a793 100644
--- a/opengl/tools/glgen/specs/jsr239/glspec-checks
+++ b/opengl/tools/glgen/specs/jsr239/glspec-checks
@@ -29,28 +29,28 @@
 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 e79170a..2db4e8d 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -211,6 +211,8 @@
                     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 @@
                     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 @@
             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 @@
         }
         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 @@
                         } 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 @@
             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 b3d1c6c..c2464b0 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 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 @@
 
     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 @@
     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 76fea3f..3727106 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
+++ b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
@@ -47,6 +47,12 @@
     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 72e26f8..62dcb08 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -43,18 +43,20 @@
 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 @@
     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 @@
         }
     }
 
+    // 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 @@
     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 @@
         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 @@
                 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 @@
         }
     };
 
-    // ----- 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 @@
         }
     }
 
+    // -----
+    // 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 @@
             }
         }
 
-        @Override
         public void run() {
             int status = BackupConstants.TRANSPORT_OK;
             long startRealtime = SystemClock.elapsedRealtime();
@@ -1158,6 +1231,7 @@
             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 @@
                         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 @@
                 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 @@
         return true;
     }
 
-    class PerformRestoreThread extends Thread {
+    class PerformRestoreTask implements Runnable {
         private IBackupTransport mTransport;
         private IRestoreObserver mObserver;
         private long mToken;
@@ -1315,7 +1400,7 @@
             }
         }
 
-        PerformRestoreThread(IBackupTransport transport, IRestoreObserver observer,
+        PerformRestoreTask(IBackupTransport transport, IRestoreObserver observer,
                 long restoreSetToken) {
             mTransport = transport;
             Log.d(TAG, "PerformRestoreThread mObserver=" + mObserver);
@@ -1329,7 +1414,6 @@
             }
         }
 
-        @Override
         public void run() {
             long startRealtime = SystemClock.elapsedRealtime();
             if (DEBUG) Log.v(TAG, "Beginning restore process mTransport=" + mTransport
@@ -1579,6 +1663,7 @@
             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 @@
                             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 @@
                 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 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 @@
         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 cefd312..e14a973 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -2011,6 +2011,10 @@
                 }
             }
         }
+
+        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 1d14e5e..88aadbd 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -2385,7 +2385,8 @@
                     // 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);
                 }