Merge "Use system IME for LockScreen password mode."
diff --git a/api/current.txt b/api/current.txt
index e946c06..9d593d8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -87,6 +87,7 @@
     field public static final java.lang.String RECEIVE_SMS = "android.permission.RECEIVE_SMS";
     field public static final java.lang.String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH";
     field public static final java.lang.String RECORD_AUDIO = "android.permission.RECORD_AUDIO";
+    field public static final java.lang.String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
     field public static final java.lang.String REORDER_TASKS = "android.permission.REORDER_TASKS";
     field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
     field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
@@ -855,6 +856,7 @@
     field public static final int state_window_focused = 16842909; // 0x101009d
     field public static final int staticWallpaperPreview = 16843569; // 0x1010331
     field public static final int stepSize = 16843078; // 0x1010146
+    field public static final int stopWithTask = 16843623; // 0x1010367
     field public static final int streamType = 16843273; // 0x1010209
     field public static final int stretchColumns = 16843081; // 0x1010149
     field public static final int stretchMode = 16843030; // 0x1010116
@@ -929,9 +931,9 @@
     field public static final int textEditPasteWindowLayout = 16843540; // 0x1010314
     field public static final int textEditSideNoPasteWindowLayout = 16843615; // 0x101035f
     field public static final int textEditSidePasteWindowLayout = 16843614; // 0x101035e
-    field public static final int textEditSuggestionItemLayout = 16843626; // 0x101036a
-    field public static final int textEditSuggestionsBottomWindowLayout = 16843624; // 0x1010368
-    field public static final int textEditSuggestionsTopWindowLayout = 16843625; // 0x1010369
+    field public static final int textEditSuggestionItemLayout = 16843627; // 0x101036b
+    field public static final int textEditSuggestionsBottomWindowLayout = 16843625; // 0x1010369
+    field public static final int textEditSuggestionsTopWindowLayout = 16843626; // 0x101036a
     field public static final int textFilterEnabled = 16843007; // 0x10100ff
     field public static final int textIsSelectable = 16843542; // 0x1010316
     field public static final int textOff = 16843045; // 0x1010125
@@ -943,7 +945,7 @@
     field public static final int textSelectHandleWindowStyle = 16843464; // 0x10102c8
     field public static final int textSize = 16842901; // 0x1010095
     field public static final int textStyle = 16842903; // 0x1010097
-    field public static final int textSuggestionsWindowStyle = 16843623; // 0x1010367
+    field public static final int textSuggestionsWindowStyle = 16843624; // 0x1010368
     field public static final int textViewStyle = 16842884; // 0x1010084
     field public static final int theme = 16842752; // 0x1010000
     field public static final int thickness = 16843360; // 0x1010260
@@ -3384,6 +3386,7 @@
     method public void onRebind(android.content.Intent);
     method public deprecated void onStart(android.content.Intent, int);
     method public int onStartCommand(android.content.Intent, int, int);
+    method public void onTaskRemoved(android.content.Intent);
     method public boolean onUnbind(android.content.Intent);
     method public final void startForeground(int, android.app.Notification);
     method public final void stopForeground(boolean);
@@ -5840,6 +5843,8 @@
     method public int describeContents();
     method public void dump(android.util.Printer, java.lang.String);
     field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int FLAG_STOP_WITH_TASK = 1; // 0x1
+    field public int flags;
     field public java.lang.String permission;
   }
 
@@ -22574,6 +22579,7 @@
     method public java.util.List<android.view.inputmethod.InputMethodInfo> getEnabledInputMethodList();
     method public java.util.List<android.view.inputmethod.InputMethodSubtype> getEnabledInputMethodSubtypeList(android.view.inputmethod.InputMethodInfo, boolean);
     method public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodList();
+    method public android.view.inputmethod.InputMethodSubtype getLastInputMethodSubtype();
     method public java.util.Map<android.view.inputmethod.InputMethodInfo, java.util.List<android.view.inputmethod.InputMethodSubtype>> getShortcutInputMethodsAndSubtypes();
     method public void hideSoftInputFromInputMethod(android.os.IBinder, int);
     method public boolean hideSoftInputFromWindow(android.os.IBinder, int);
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 0159edd..371268f 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -1,8 +1,8 @@
 /*
  * Main entry of app process.
- * 
+ *
  * Starts the interpreted runtime, then starts up the application.
- * 
+ *
  */
 
 #define LOG_TAG "appproc"
@@ -25,23 +25,13 @@
         "Usage: app_process [java-options] cmd-dir start-class-name [options]\n");
 }
 
-status_t app_init(const char* className, int argc, const char* const argv[])
-{
-    LOGV("Entered app_init()!\n");
-
-    AndroidRuntime* jr = AndroidRuntime::getRuntime();
-    jr->callMain(className, argc, argv);
-    
-    LOGV("Exiting app_init()!\n");
-    return NO_ERROR;
-}
-
 class AppRuntime : public AndroidRuntime
 {
 public:
     AppRuntime()
         : mParentDir(NULL)
         , mClassName(NULL)
+        , mClass(NULL)
         , mArgC(0)
         , mArgV(NULL)
     {
@@ -60,6 +50,35 @@
         return mClassName;
     }
 
+    virtual void onVmCreated(JNIEnv* env)
+    {
+        if (mClassName == NULL) {
+            return; // Zygote. Nothing to do here.
+        }
+
+        /*
+         * This is a little awkward because the JNI FindClass call uses the
+         * class loader associated with the native method we're executing in.
+         * If called in onStarted (from RuntimeInit.finishInit because we're
+         * launching "am", for example), FindClass would see that we're calling
+         * from a boot class' native method, and so wouldn't look for the class
+         * we're trying to look up in CLASSPATH. Unfortunately it needs to,
+         * because the "am" classes are not boot classes.
+         *
+         * The easiest fix is to call FindClass here, early on before we start
+         * executing boot class Java code and thereby deny ourselves access to
+         * non-boot classes.
+         */
+        char* slashClassName = toSlashClassName(mClassName);
+        mClass = env->FindClass(slashClassName);
+        if (mClass == NULL) {
+            LOGE("ERROR: could not find class '%s'\n", mClassName);
+        }
+        free(slashClassName);
+
+        mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));
+    }
+
     virtual void onStarted()
     {
         sp<ProcessState> proc = ProcessState::self();
@@ -67,8 +86,9 @@
             LOGV("App process: starting thread pool.\n");
             proc->startThreadPool();
         }
-        
-        app_init(mClassName, mArgC, mArgV);
+
+        AndroidRuntime* ar = AndroidRuntime::getRuntime();
+        ar->callMain(mClassName, mClass, mArgC, mArgV);
 
         if (ProcessState::self()->supportsProcesses()) {
             IPCThreadState::self()->stopProcess();
@@ -81,7 +101,7 @@
         if (proc->supportsProcesses()) {
             LOGV("App process: starting thread pool.\n");
             proc->startThreadPool();
-        }       
+        }
     }
 
     virtual void onExit(int code)
@@ -96,9 +116,10 @@
         AndroidRuntime::onExit(code);
     }
 
-    
+
     const char* mParentDir;
     const char* mClassName;
+    jclass mClass;
     int mArgC;
     const char* const* mArgV;
 };
@@ -120,7 +141,7 @@
     // These are global variables in ProcessState.cpp
     mArgC = argc;
     mArgV = argv;
-    
+
     mArgLen = 0;
     for (int i=0; i<argc; i++) {
         mArgLen += strlen(argv[i]) + 1;
@@ -139,7 +160,7 @@
     argv++;
 
     // Everything up to '--' or first non '-' arg goes to the vm
-    
+
     int i = runtime.addVmArguments(argc, argv);
 
     // Next arg is parent directory
@@ -151,7 +172,7 @@
     if (i < argc) {
         arg = argv[i++];
         if (0 == strcmp("--zygote", arg)) {
-            bool startSystemServer = (i < argc) ? 
+            bool startSystemServer = (i < argc) ?
                     strcmp(argv[i], "--start-system-server") == 0 : false;
             setArgv0(argv0, "zygote");
             set_process_name("zygote");
diff --git a/cmds/runtime/main_runtime.cpp b/cmds/runtime/main_runtime.cpp
index 83cb533..785e4cc 100644
--- a/cmds/runtime/main_runtime.cpp
+++ b/cmds/runtime/main_runtime.cpp
@@ -12,7 +12,7 @@
 
 #include <binder/IPCThreadState.h>
 #include <binder/ProcessState.h>
-#include <utils/Log.h>  
+#include <utils/Log.h>
 #include <cutils/zygote.h>
 
 #include <cutils/properties.h>
@@ -41,7 +41,7 @@
 #undef LOG_TAG
 #define LOG_TAG "runtime"
 
-static const char* ZYGOTE_ARGV[] = { 
+static const char* ZYGOTE_ARGV[] = {
     "--setuid=1000",
     "--setgid=1000",
     "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
@@ -68,7 +68,6 @@
 
 namespace android {
 
-extern status_t app_init(const char* className);
 extern void set_finish_init_func(void (*func)());
 
 
@@ -76,7 +75,7 @@
  * This class is used to kill this process (runtime) when the system_server dies.
  */
 class GrimReaper : public IBinder::DeathRecipient {
-public: 
+public:
     GrimReaper() { }
 
     virtual void binderDied(const wp<IBinder>& who)
@@ -170,7 +169,7 @@
 
 /*
  * Post-system-process initialization.
- * 
+ *
  * This function continues initialization after the system process
  * has been initialized.  It needs to be separate because the system
  * initialization needs to care of starting the Android runtime if it is not
@@ -210,17 +209,17 @@
 static void boot_init()
 {
     LOGI("Entered boot_init()!\n");
-    
+
     sp<ProcessState> proc(ProcessState::self());
     LOGD("ProcessState: %p\n", proc.get());
     proc->becomeContextManager(contextChecker, NULL);
-    
+
     if (proc->supportsProcesses()) {
         LOGI("Binder driver opened.  Multiprocess enabled.\n");
     } else {
         LOGI("Binder driver not found.  Processes not supported.\n");
     }
-    
+
     sp<BServiceManager> sm = new BServiceManager;
     proc->setContextObject(sm);
 }
@@ -258,7 +257,7 @@
     int res;
     time_t min_time = 1167652800; // jan 1 2007, type 'date -ud "1/1 12:00" +%s' to get value for current year
     struct timespec ts;
-    
+
     fd = open("/dev/alarm", O_RDWR);
     if(fd < 0) {
         LOGW("Unable to open alarm driver: %s\n", strerror(errno));
@@ -346,14 +345,14 @@
     int ic;
     int result = 1;
     pid_t systemPid;
-    
+
     sp<ProcessState> proc;
 
 #ifndef HAVE_ANDROID_OS
     /* Set stdout/stderr to unbuffered for MinGW/MSYS. */
     //setvbuf(stdout, NULL, _IONBF, 0);
     //setvbuf(stderr, NULL, _IONBF, 0);
-    
+
     LOGI("commandline args:\n");
     for (int i = 0; i < argc; i++)
         LOGI("  %2d: '%s'\n", i, argv[i]);
@@ -455,7 +454,7 @@
 
 #if 0
     // Hack to keep libc from beating the filesystem to death.  It's
-    // hitting /etc/localtime frequently, 
+    // hitting /etc/localtime frequently,
     //
     // This statement locks us into Pacific time.  We could do better,
     // but there's not much point until we're sure that the library
@@ -467,15 +466,15 @@
 
     /* track our progress through the boot sequence */
     const int LOG_BOOT_PROGRESS_START = 3000;
-    LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, 
+    LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
         ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
 
     validateTime();
 
     proc = ProcessState::self();
-    
+
     boot_init();
-    
+
     /* If we are in multiprocess mode, have zygote spawn the system
      * server process and call system_init(). If we are running in
      * single process mode just call system_init() directly.
@@ -488,8 +487,8 @@
         property_get("log.redirect-stdio", propBuf, "");
         logStdio = (strcmp(propBuf, "true") == 0);
 
-        zygote_run_oneshot((int)(!logStdio), 
-                sizeof(ZYGOTE_ARGV) / sizeof(ZYGOTE_ARGV[0]), 
+        zygote_run_oneshot((int)(!logStdio),
+                sizeof(ZYGOTE_ARGV) / sizeof(ZYGOTE_ARGV[0]),
                 ZYGOTE_ARGV);
 
         //start_process("/system/bin/mediaserver");
@@ -497,7 +496,7 @@
     } else {
 #ifndef HAVE_ANDROID_OS
         QuickRuntime* runt = new QuickRuntime();
-        runt->start("com/android/server/SystemServer", 
+        runt->start("com/android/server/SystemServer",
                     false /* spontaneously fork system server from zygote */);
 #endif
     }
@@ -506,11 +505,11 @@
 
     finish_system_init(proc);
     run(proc);
-    
+
 bail:
     if (proc != NULL) {
         proc->setContextObject(NULL);
     }
-    
+
     return 0;
 }
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index bb84bd1..be443d0 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -107,7 +107,7 @@
         : mEOS(false) {
     }
 
-    virtual void notify(int msg, int ext1, int ext2) {
+    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) {
         Mutex::Autolock autoLock(mLock);
 
         if (msg == MEDIA_ERROR || msg == MEDIA_PLAYBACK_COMPLETE) {
diff --git a/cmds/system_server/library/system_init.cpp b/cmds/system_server/library/system_init.cpp
index a29ba73..b615764 100644
--- a/cmds/system_server/library/system_init.cpp
+++ b/cmds/system_server/library/system_init.cpp
@@ -37,7 +37,7 @@
  * This class is used to kill this process when the runtime dies.
  */
 class GrimReaper : public IBinder::DeathRecipient {
-public: 
+public:
     GrimReaper() { }
 
     virtual void binderDied(const wp<IBinder>& who)
@@ -54,15 +54,15 @@
 extern "C" status_t system_init()
 {
     LOGI("Entered system_init()");
-    
+
     sp<ProcessState> proc(ProcessState::self());
-    
+
     sp<IServiceManager> sm = defaultServiceManager();
     LOGI("ServiceManager: %p\n", sm.get());
-    
+
     sp<GrimReaper> grim = new GrimReaper();
     sm->asBinder()->linkToDeath(grim, grim.get(), 0);
-    
+
     char propBuf[PROPERTY_VALUE_MAX];
     property_get("system_init.startsurfaceflinger", propBuf, "1");
     if (strcmp(propBuf, "1") == 0) {
@@ -97,12 +97,23 @@
     // the beginning of their processes's main(), before calling
     // the init function.
     LOGI("System server: starting Android runtime.\n");
-    
     AndroidRuntime* runtime = AndroidRuntime::getRuntime();
 
     LOGI("System server: starting Android services.\n");
-    runtime->callStatic("com/android/server/SystemServer", "init2");
-        
+    JNIEnv* env = runtime->getJNIEnv();
+    if (env == NULL) {
+        return UNKNOWN_ERROR;
+    }
+    jclass clazz = env->FindClass("com/android/server/SystemServer");
+    if (clazz == NULL) {
+        return UNKNOWN_ERROR;
+    }
+    jmethodID methodId = env->GetStaticMethodID(clazz, "init2", "()V");
+    if (methodId == NULL) {
+        return UNKNOWN_ERROR;
+    }
+    env->CallStaticVoidMethod(clazz, methodId);
+
     // If running in our own process, just go into the thread
     // pool.  Otherwise, call the initialization finished
     // func to let this process continue its initilization.
@@ -114,4 +125,3 @@
     }
     return NO_ERROR;
 }
-
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index ebe403b..fca6868 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -205,13 +205,6 @@
     public static final int RECENT_IGNORE_UNAVAILABLE = 0x0002;
 
     /**
-     * Flag for use with {@link #getRecentTasks}: also return the thumbnail
-     * bitmap (if available) for each recent task.
-     * @hide
-     */
-    public static final int TASKS_GET_THUMBNAILS = 0x0001000;
-    
-    /**
      * Return a list of the tasks that the user has recently launched, with
      * the most recent being first and older ones after in order.
      * 
@@ -241,7 +234,7 @@
     /**
      * Information you can retrieve about a particular task that is currently
      * "running" in the system.  Note that a running task does not mean the
-     * given task actual has a process it is actively running in; it simply
+     * given task actually has a process it is actively running in; it simply
      * means that the user has gone to it and never closed it, but currently
      * the system may have killed its process and is only holding on to its
      * last state in order to restart it when the user returns.
@@ -396,6 +389,55 @@
         return getRunningTasks(maxNum, 0, null);
     }
 
+    /**
+     * Remove some end of a task's activity stack that is not part of
+     * the main application.  The selected activities will be finished, so
+     * they are no longer part of the main task.
+     *
+     * @param taskId The identifier of the task.
+     * @param subTaskIndex The number of the sub-task; this corresponds
+     * to the index of the thumbnail returned by {@link #getTaskThumbnails(int)}.
+     * @return Returns true if the sub-task was found and was removed.
+     *
+     * @hide
+     */
+    public boolean removeSubTask(int taskId, int subTaskIndex)
+            throws SecurityException {
+        try {
+            return ActivityManagerNative.getDefault().removeSubTask(taskId, subTaskIndex);
+        } catch (RemoteException e) {
+            // System dead, we will be dead too soon!
+            return false;
+        }
+    }
+
+    /**
+     * If set, the process of the root activity of the task will be killed
+     * as part of removing the task.
+     * @hide
+     */
+    public static final int REMOVE_TASK_KILL_PROCESS = 0x0001;
+
+    /**
+     * Completely remove the given task.
+     *
+     * @param taskId Identifier of the task to be removed.
+     * @param flags Additional operational flags.  May be 0 or
+     * {@link #REMOVE_TASK_KILL_PROCESS}.
+     * @return Returns true if the given task was found and removed.
+     *
+     * @hide
+     */
+    public boolean removeTask(int taskId, int flags)
+            throws SecurityException {
+        try {
+            return ActivityManagerNative.getDefault().removeTask(taskId, flags);
+        } catch (RemoteException e) {
+            // System dead, we will be dead too soon!
+            return false;
+        }
+    }
+
     /** @hide */
     public static class TaskThumbnails implements Parcelable {
         public Bitmap mainThumbnail;
@@ -405,9 +447,6 @@
         /** @hide */
         public IThumbnailRetriever retriever;
 
-        /** @hide Magic for ActivityManagerService.  Not marshalled */
-        public ArrayList<Bitmap> otherThumbnails;
-
         public TaskThumbnails() {
         }
 
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index d41c2d0..4b09b34c 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1405,6 +1405,28 @@
             reply.writeInt(result ? 1 : 0);
             return true;
         }
+        
+        case REMOVE_SUB_TASK_TRANSACTION:
+        {
+            data.enforceInterface(IActivityManager.descriptor);
+            int taskId = data.readInt();
+            int subTaskIndex = data.readInt();
+            boolean result = removeSubTask(taskId, subTaskIndex);
+            reply.writeNoException();
+            reply.writeInt(result ? 1 : 0);
+            return true;
+        }
+
+        case REMOVE_TASK_TRANSACTION:
+        {
+            data.enforceInterface(IActivityManager.descriptor);
+            int taskId = data.readInt();
+            int fl = data.readInt();
+            boolean result = removeTask(taskId, fl);
+            reply.writeNoException();
+            reply.writeInt(result ? 1 : 0);
+            return true;
+        }
 
         }
 
@@ -3162,6 +3184,34 @@
         data.recycle();
         return result;
     }
+    
+    public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(taskId);
+        data.writeInt(subTaskIndex);
+        mRemote.transact(REMOVE_SUB_TASK_TRANSACTION, data, reply, 0);
+        reply.readException();
+        boolean result = reply.readInt() != 0;
+        reply.recycle();
+        data.recycle();
+        return result;
+    }
+
+    public boolean removeTask(int taskId, int flags) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(taskId);
+        data.writeInt(flags);
+        mRemote.transact(REMOVE_TASK_TRANSACTION, data, reply, 0);
+        reply.readException();
+        boolean result = reply.readInt() != 0;
+        reply.recycle();
+        data.recycle();
+        return result;
+    }
 
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 57a79a9..4dfba91 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -334,6 +334,7 @@
 
     private static final class ServiceArgsData {
         IBinder token;
+        boolean taskRemoved;
         int startId;
         int flags;
         Intent args;
@@ -534,10 +535,11 @@
             queueOrSendMessage(H.UNBIND_SERVICE, s);
         }
 
-        public final void scheduleServiceArgs(IBinder token, int startId,
+        public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
             int flags ,Intent args) {
             ServiceArgsData s = new ServiceArgsData();
             s.token = token;
+            s.taskRemoved = taskRemoved;
             s.startId = startId;
             s.flags = flags;
             s.args = args;
@@ -2129,7 +2131,13 @@
                 if (data.args != null) {
                     data.args.setExtrasClassLoader(s.getClassLoader());
                 }
-                int res = s.onStartCommand(data.args, data.flags, data.startId);
+                int res;
+                if (!data.taskRemoved) {
+                    res = s.onStartCommand(data.args, data.flags, data.startId);
+                } else {
+                    s.onTaskRemoved(data.args);
+                    res = Service.START_TASK_REMOVED_COMPLETE;
+                }
 
                 QueuedWork.waitToFinish();
 
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index a82234e..0e511f2 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -219,6 +219,7 @@
         {
             data.enforceInterface(IApplicationThread.descriptor);
             IBinder token = data.readStrongBinder();
+            boolean taskRemoved = data.readInt() != 0;
             int startId = data.readInt();
             int fl = data.readInt();
             Intent args;
@@ -227,7 +228,7 @@
             } else {
                 args = null;
             }
-            scheduleServiceArgs(token, startId, fl, args);
+            scheduleServiceArgs(token, taskRemoved, startId, fl, args);
             return true;
         }
 
@@ -688,11 +689,12 @@
         data.recycle();
     }
 
-    public final void scheduleServiceArgs(IBinder token, int startId,
+    public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
 	    int flags, Intent args) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeStrongBinder(token);
+        data.writeInt(taskRemoved ? 1 : 0);
         data.writeInt(startId);
         data.writeInt(flags);
         if (args != null) {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 5a15b08..bec697a 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -344,6 +344,10 @@
 
     // Multi-user APIs
     public boolean switchUser(int userid) throws RemoteException;
+    
+    public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException;
+
+    public boolean removeTask(int taskId, int flags) throws RemoteException;
 
     /*
      * Private non-Binder interfaces
@@ -561,4 +565,6 @@
     int START_ACTIVITIES_IN_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+121;
     int ACTIVITY_SLEPT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+122;
     int SWITCH_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+123;
+    int REMOVE_SUB_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+124;
+    int REMOVE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+125;
 }
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 55177a9..b29b088 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -73,8 +73,8 @@
             Intent intent, boolean rebind) throws RemoteException;
     void scheduleUnbindService(IBinder token,
             Intent intent) throws RemoteException;
-    void scheduleServiceArgs(IBinder token, int startId, int flags, Intent args)
-            throws RemoteException;
+    void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
+            int flags, Intent args) throws RemoteException;
     void scheduleStopService(IBinder token) throws RemoteException;
     static final int DEBUG_OFF = 0;
     static final int DEBUG_ON = 1;
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 05b9781..c179b35 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -371,6 +371,13 @@
     public static final int START_REDELIVER_INTENT = 3;
     
     /**
+     * Special constant for reporting that we are done processing
+     * {@link #onTaskRemoved(Intent)}.
+     * @hide
+     */
+    public static final int START_TASK_REMOVED_COMPLETE = 1000;
+
+    /**
      * This flag is set in {@link #onStartCommand} if the Intent is a
      * re-delivery of a previously delivered intent, because the service
      * had previously returned {@link #START_REDELIVER_INTENT} but had been
@@ -500,6 +507,19 @@
     }
     
     /**
+     * This is called if the service is currently running and the user has
+     * removed a task that comes from the service's application.  If you have
+     * set {@link android.content.pm.ServiceInfo#FLAG_STOP_WITH_TASK ServiceInfo.FLAG_STOP_WITH_TASK}
+     * then you will not receive this callback; instead, the service will simply
+     * be stopped.
+     *
+     * @param rootIntent The original root Intent that was used to launch
+     * the task that is being removed.
+     */
+    public void onTaskRemoved(Intent rootIntent) {
+    }
+
+    /**
      * Stop the service, if it was previously started.  This is the same as
      * calling {@link android.content.Context#stopService} for this particular service.
      *  
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 67cd4a2..54a8842 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2473,6 +2473,13 @@
             s.info.permission = str.length() > 0 ? str.toString().intern() : null;
         }
 
+        s.info.flags = 0;
+        if (sa.getBoolean(
+                com.android.internal.R.styleable.AndroidManifestService_stopWithTask,
+                false)) {
+            s.info.flags |= ServiceInfo.FLAG_STOP_WITH_TASK;
+        }
+
         sa.recycle();
 
         if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 087a4fe..612e345 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -33,17 +33,35 @@
      */
     public String permission;
 
+    /**
+     * Bit in {@link #flags}: If set, the service will automatically be
+     * stopped by the system if the user removes a task that is rooted
+     * in one of the application's activities.  Set from the
+     * {@link android.R.attr#stopWithTask} attribute.
+     */
+    public static final int FLAG_STOP_WITH_TASK = 0x0001;
+
+    /**
+     * Options that have been set in the service declaration in the
+     * manifest.
+     * These include:
+     * {@link #FLAG_STOP_WITH_TASK}
+     */
+    public int flags;
+
     public ServiceInfo() {
     }
 
     public ServiceInfo(ServiceInfo orig) {
         super(orig);
         permission = orig.permission;
+        flags = orig.flags;
     }
 
     public void dump(Printer pw, String prefix) {
         super.dumpFront(pw, prefix);
         pw.println(prefix + "permission=" + permission);
+        pw.println(prefix + "flags=0x" + Integer.toHexString(flags));
     }
     
     public String toString() {
@@ -59,6 +77,7 @@
     public void writeToParcel(Parcel dest, int parcelableFlags) {
         super.writeToParcel(dest, parcelableFlags);
         dest.writeString(permission);
+        dest.writeInt(flags);
     }
 
     public static final Creator<ServiceInfo> CREATOR =
@@ -74,5 +93,6 @@
     private ServiceInfo(Parcel source) {
         super(source);
         permission = source.readString();
+        flags = source.readInt();
     }
 }
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 0a13b4e6..6c6a72d 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1180,6 +1180,8 @@
         private static final String KEY_MAX_EXPOSURE_COMPENSATION = "max-exposure-compensation";
         private static final String KEY_MIN_EXPOSURE_COMPENSATION = "min-exposure-compensation";
         private static final String KEY_EXPOSURE_COMPENSATION_STEP = "exposure-compensation-step";
+        private static final String KEY_METERING_AREAS = "metering-areas";
+        private static final String KEY_MAX_NUM_METERING_AREAS = "max-num-metering-areas";
         private static final String KEY_ZOOM = "zoom";
         private static final String KEY_MAX_ZOOM = "max-zoom";
         private static final String KEY_ZOOM_RATIOS = "zoom-ratios";
@@ -1518,6 +1520,27 @@
             mMap.put(key, Integer.toString(value));
         }
 
+        private void set(String key, List<Area> areas) {
+            StringBuilder buffer = new StringBuilder();
+            for (int i = 0; i < areas.size(); i++) {
+                Area area = areas.get(i);
+                Rect rect = area.rect;
+                buffer.append('(');
+                buffer.append(rect.left);
+                buffer.append(',');
+                buffer.append(rect.top);
+                buffer.append(',');
+                buffer.append(rect.right);
+                buffer.append(',');
+                buffer.append(rect.bottom);
+                buffer.append(',');
+                buffer.append(area.weight);
+                buffer.append(')');
+                if (i != areas.size() - 1) buffer.append(',');
+            }
+            set(key, buffer.toString());
+        }
+
         /**
          * Returns the value of a String parameter.
          *
@@ -2562,7 +2585,8 @@
         }
 
         /**
-         * Gets the current focus areas.
+         * Gets the current focus areas. Camera driver uses the areas to decide
+         * focus.
          *
          * Before using this API or {@link #setFocusAreas(List<int>)}, apps
          * should call {@link #getMaxNumFocusArea()} to know the maximum number of
@@ -2610,25 +2634,76 @@
          * @see #getFocusAreas()
          * @hide
          */
-        public void setFocusAreas(List<Area> focusArea) {
-            StringBuilder buffer = new StringBuilder();
-            for (int i = 0; i < focusArea.size(); i++) {
-                Area area = focusArea.get(i);
-                Rect rect = area.rect;
-                buffer.append('(');
-                buffer.append(rect.left);
-                buffer.append(',');
-                buffer.append(rect.top);
-                buffer.append(',');
-                buffer.append(rect.right);
-                buffer.append(',');
-                buffer.append(rect.bottom);
-                buffer.append(',');
-                buffer.append(area.weight);
-                buffer.append(')');
-                if (i != focusArea.size() - 1) buffer.append(',');
-            }
-            set(KEY_FOCUS_AREAS, buffer.toString());
+        public void setFocusAreas(List<Area> focusAreas) {
+            set(KEY_FOCUS_AREAS, focusAreas);
+        }
+
+        /**
+         * Gets the maximum number of metering areas supported. This is the
+         * maximum length of the list in {@link #setMeteringArea(List<Area>)}
+         * and {@link #getMeteringArea()}.
+         *
+         * @return the maximum number of metering areas supported by the camera.
+         * @see #getMeteringAreas()
+         * @hide
+         */
+        public int getMaxNumMeteringAreas() {
+            return getInt(KEY_MAX_NUM_METERING_AREAS, 0);
+        }
+
+        /**
+         * Gets the current metering areas. Camera driver uses these areas to
+         * decide exposure.
+         *
+         * Before using this API or {@link #setMeteringAreas(List<int>)}, apps
+         * should call {@link #getMaxNumMeteringArea()} to know the maximum
+         * number of metering areas first. If the value is 0, metering area is
+         * not supported.
+         *
+         * Each metering area is a rectangle with specified weight. The
+         * direction is relative to the sensor orientation, that is, what the
+         * sensor sees. The direction is not affected by the rotation or
+         * mirroring of {@link #setDisplayOrientation(int)}. Coordinates of the
+         * rectangle range from -1000 to 1000. (-1000, -1000) is the upper left
+         * point. (1000, 1000) is the lower right point. The length and width of
+         * metering areas cannot be 0 or negative.
+         *
+         * The weight ranges from 1 to 1000. The sum of the weights of all
+         * metering areas must be 1000. Metering areas can partially overlap and
+         * the driver will add the weights in the overlap region. But apps
+         * should not set two metering areas that have identical coordinates.
+         *
+         * A special case of all-zero single metering area means driver to
+         * decide the metering area. For example, the driver may use more
+         * signals to decide metering areas and change them dynamically. Apps
+         * can set all-zero if they want the driver to decide metering areas.
+         *
+         * Metering areas are relative to the current field of view
+         * ({@link #getZoom()}). No matter what the zoom level is, (-1000,-1000)
+         * represents the top of the currently visible camera frame. The
+         * metering area cannot be set to be outside the current field of view,
+         * even when using zoom.
+         *
+         * No matter what metering areas are, the final exposure are compensated
+         * by {@link setExposureCompensation(int)}.
+         *
+         * @return a list of current metering areas
+         * @hide
+         */
+        public List<Area> getMeteringAreas() {
+            return splitArea(KEY_METERING_AREAS);
+        }
+
+        /**
+         * Sets metering areas. See {@link #getMeteringAreas()} for
+         * documentation.
+         *
+         * @param meteringArea the metering areas
+         * @see #getMeteringAreas()
+         * @hide
+         */
+        public void setMeteringAreas(List<Area> meteringAreas) {
+            set(KEY_METERING_AREAS, meteringAreas);
         }
 
         // Splits a comma delimited string to an ArrayList of String.
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 90e2e79..d7483ba 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -412,6 +412,7 @@
         
         public long time;
         
+        public static final byte CMD_NULL = -1;
         public static final byte CMD_UPDATE = 0;
         public static final byte CMD_START = 1;
         public static final byte CMD_OVERFLOW = 2;
@@ -466,16 +467,7 @@
         
         public HistoryItem(long time, Parcel src) {
             this.time = time;
-            int bat = src.readInt();
-            cmd = (byte)(bat&0xff);
-            batteryLevel = (byte)((bat>>8)&0xff);
-            batteryStatus = (byte)((bat>>16)&0xf);
-            batteryHealth = (byte)((bat>>20)&0xf);
-            batteryPlugType = (byte)((bat>>24)&0xf);
-            bat = src.readInt();
-            batteryTemperature = (char)(bat&0xffff);
-            batteryVoltage = (char)((bat>>16)&0xffff);
-            states = src.readInt();
+            readFromParcel(src);
         }
         
         public int describeContents() {
@@ -496,6 +488,28 @@
             dest.writeInt(states);
         }
         
+        public void writeDelta(Parcel dest, HistoryItem last) {
+            writeToParcel(dest, 0);
+        }
+
+        private void readFromParcel(Parcel src) {
+            int bat = src.readInt();
+            cmd = (byte)(bat&0xff);
+            batteryLevel = (byte)((bat>>8)&0xff);
+            batteryStatus = (byte)((bat>>16)&0xf);
+            batteryHealth = (byte)((bat>>20)&0xf);
+            batteryPlugType = (byte)((bat>>24)&0xf);
+            bat = src.readInt();
+            batteryTemperature = (char)(bat&0xffff);
+            batteryVoltage = (char)((bat>>16)&0xffff);
+            states = src.readInt();
+        }
+
+        public void readDelta(Parcel src, HistoryItem last) {
+            time = src.readLong();
+            readFromParcel(src);
+        }
+
         public void setTo(HistoryItem o) {
             time = o.time;
             cmd = o.cmd;
@@ -556,11 +570,14 @@
 
     public abstract boolean getNextHistoryLocked(HistoryItem out);
 
-    /**
-     * Return the current history of battery state changes.
-     */
-    public abstract HistoryItem getHistory();
-    
+    public abstract void finishIteratingHistoryLocked();
+
+    public abstract boolean startIteratingOldHistoryLocked();
+
+    public abstract boolean getNextOldHistoryLocked(HistoryItem out);
+
+    public abstract void finishIteratingOldHistoryLocked();
+
     /**
      * Return the base time offset for the battery history.
      */
@@ -1729,7 +1746,7 @@
         }
     }
 
-    void printBitDescriptions(PrintWriter pw, int oldval, int newval, BitDescription[] descriptions) {
+    static void printBitDescriptions(PrintWriter pw, int oldval, int newval, BitDescription[] descriptions) {
         int diff = oldval ^ newval;
         if (diff == 0) return;
         for (int i=0; i<descriptions.length; i++) {
@@ -1753,6 +1770,125 @@
         }
     }
     
+    public void prepareForDumpLocked() {
+    }
+
+    public static class HistoryPrinter {
+        int oldState = 0;
+        int oldStatus = -1;
+        int oldHealth = -1;
+        int oldPlug = -1;
+        int oldTemp = -1;
+        int oldVolt = -1;
+
+        public void printNextItem(PrintWriter pw, HistoryItem rec, long now) {
+            pw.print("  ");
+            TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
+            pw.print(" ");
+            if (rec.cmd == HistoryItem.CMD_START) {
+                pw.println(" START");
+            } else if (rec.cmd == HistoryItem.CMD_OVERFLOW) {
+                pw.println(" *OVERFLOW*");
+            } else {
+                if (rec.batteryLevel < 10) pw.print("00");
+                else if (rec.batteryLevel < 100) pw.print("0");
+                pw.print(rec.batteryLevel);
+                pw.print(" ");
+                if (rec.states < 0x10) pw.print("0000000");
+                else if (rec.states < 0x100) pw.print("000000");
+                else if (rec.states < 0x1000) pw.print("00000");
+                else if (rec.states < 0x10000) pw.print("0000");
+                else if (rec.states < 0x100000) pw.print("000");
+                else if (rec.states < 0x1000000) pw.print("00");
+                else if (rec.states < 0x10000000) pw.print("0");
+                pw.print(Integer.toHexString(rec.states));
+                if (oldStatus != rec.batteryStatus) {
+                    oldStatus = rec.batteryStatus;
+                    pw.print(" status=");
+                    switch (oldStatus) {
+                        case BatteryManager.BATTERY_STATUS_UNKNOWN:
+                            pw.print("unknown");
+                            break;
+                        case BatteryManager.BATTERY_STATUS_CHARGING:
+                            pw.print("charging");
+                            break;
+                        case BatteryManager.BATTERY_STATUS_DISCHARGING:
+                            pw.print("discharging");
+                            break;
+                        case BatteryManager.BATTERY_STATUS_NOT_CHARGING:
+                            pw.print("not-charging");
+                            break;
+                        case BatteryManager.BATTERY_STATUS_FULL:
+                            pw.print("full");
+                            break;
+                        default:
+                            pw.print(oldStatus);
+                            break;
+                    }
+                }
+                if (oldHealth != rec.batteryHealth) {
+                    oldHealth = rec.batteryHealth;
+                    pw.print(" health=");
+                    switch (oldHealth) {
+                        case BatteryManager.BATTERY_HEALTH_UNKNOWN:
+                            pw.print("unknown");
+                            break;
+                        case BatteryManager.BATTERY_HEALTH_GOOD:
+                            pw.print("good");
+                            break;
+                        case BatteryManager.BATTERY_HEALTH_OVERHEAT:
+                            pw.print("overheat");
+                            break;
+                        case BatteryManager.BATTERY_HEALTH_DEAD:
+                            pw.print("dead");
+                            break;
+                        case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE:
+                            pw.print("over-voltage");
+                            break;
+                        case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE:
+                            pw.print("failure");
+                            break;
+                        default:
+                            pw.print(oldHealth);
+                            break;
+                    }
+                }
+                if (oldPlug != rec.batteryPlugType) {
+                    oldPlug = rec.batteryPlugType;
+                    pw.print(" plug=");
+                    switch (oldPlug) {
+                        case 0:
+                            pw.print("none");
+                            break;
+                        case BatteryManager.BATTERY_PLUGGED_AC:
+                            pw.print("ac");
+                            break;
+                        case BatteryManager.BATTERY_PLUGGED_USB:
+                            pw.print("usb");
+                            break;
+                        default:
+                            pw.print(oldPlug);
+                            break;
+                    }
+                }
+                if (oldTemp != rec.batteryTemperature) {
+                    oldTemp = rec.batteryTemperature;
+                    pw.print(" temp=");
+                    pw.print(oldTemp);
+                }
+                if (oldVolt != rec.batteryVoltage) {
+                    oldVolt = rec.batteryVoltage;
+                    pw.print(" volt=");
+                    pw.print(oldVolt);
+                }
+                printBitDescriptions(pw, oldState, rec.states,
+                        HISTORY_STATE_DESCRIPTIONS);
+                pw.println();
+            }
+            oldState = rec.states;
+        }
+    }
+
     /**
      * Dumps a human-readable summary of the battery statistics to the given PrintWriter.
      *
@@ -1760,122 +1896,28 @@
      */
     @SuppressWarnings("unused")
     public void dumpLocked(PrintWriter pw) {
+        prepareForDumpLocked();
+
+        long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
+
         final HistoryItem rec = new HistoryItem();
         if (startIteratingHistoryLocked()) {
             pw.println("Battery History:");
-            long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
-            int oldState = 0;
-            int oldStatus = -1;
-            int oldHealth = -1;
-            int oldPlug = -1;
-            int oldTemp = -1;
-            int oldVolt = -1;
+            HistoryPrinter hprinter = new HistoryPrinter();
             while (getNextHistoryLocked(rec)) {
-                pw.print("  ");
-                TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
-                pw.print(" ");
-                if (rec.cmd == HistoryItem.CMD_START) {
-                    pw.println(" START");
-                } else if (rec.cmd == HistoryItem.CMD_OVERFLOW) {
-                    pw.println(" *OVERFLOW*");
-                } else {
-                    if (rec.batteryLevel < 10) pw.print("00");
-                    else if (rec.batteryLevel < 100) pw.print("0");
-                    pw.print(rec.batteryLevel);
-                    pw.print(" ");
-                    if (rec.states < 0x10) pw.print("0000000");
-                    else if (rec.states < 0x100) pw.print("000000");
-                    else if (rec.states < 0x1000) pw.print("00000");
-                    else if (rec.states < 0x10000) pw.print("0000");
-                    else if (rec.states < 0x100000) pw.print("000");
-                    else if (rec.states < 0x1000000) pw.print("00");
-                    else if (rec.states < 0x10000000) pw.print("0");
-                    pw.print(Integer.toHexString(rec.states));
-                    if (oldStatus != rec.batteryStatus) {
-                        oldStatus = rec.batteryStatus;
-                        pw.print(" status=");
-                        switch (oldStatus) {
-                            case BatteryManager.BATTERY_STATUS_UNKNOWN:
-                                pw.print("unknown");
-                                break;
-                            case BatteryManager.BATTERY_STATUS_CHARGING:
-                                pw.print("charging");
-                                break;
-                            case BatteryManager.BATTERY_STATUS_DISCHARGING:
-                                pw.print("discharging");
-                                break;
-                            case BatteryManager.BATTERY_STATUS_NOT_CHARGING:
-                                pw.print("not-charging");
-                                break;
-                            case BatteryManager.BATTERY_STATUS_FULL:
-                                pw.print("full");
-                                break;
-                            default:
-                                pw.print(oldStatus);
-                                break;
-                        }
-                    }
-                    if (oldHealth != rec.batteryHealth) {
-                        oldHealth = rec.batteryHealth;
-                        pw.print(" health=");
-                        switch (oldHealth) {
-                            case BatteryManager.BATTERY_HEALTH_UNKNOWN:
-                                pw.print("unknown");
-                                break;
-                            case BatteryManager.BATTERY_HEALTH_GOOD:
-                                pw.print("good");
-                                break;
-                            case BatteryManager.BATTERY_HEALTH_OVERHEAT:
-                                pw.print("overheat");
-                                break;
-                            case BatteryManager.BATTERY_HEALTH_DEAD:
-                                pw.print("dead");
-                                break;
-                            case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE:
-                                pw.print("over-voltage");
-                                break;
-                            case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE:
-                                pw.print("failure");
-                                break;
-                            default:
-                                pw.print(oldHealth);
-                                break;
-                        }
-                    }
-                    if (oldPlug != rec.batteryPlugType) {
-                        oldPlug = rec.batteryPlugType;
-                        pw.print(" plug=");
-                        switch (oldPlug) {
-                            case 0:
-                                pw.print("none");
-                                break;
-                            case BatteryManager.BATTERY_PLUGGED_AC:
-                                pw.print("ac");
-                                break;
-                            case BatteryManager.BATTERY_PLUGGED_USB:
-                                pw.print("usb");
-                                break;
-                            default:
-                                pw.print(oldPlug);
-                                break;
-                        }
-                    }
-                    if (oldTemp != rec.batteryTemperature) {
-                        oldTemp = rec.batteryTemperature;
-                        pw.print(" temp=");
-                        pw.print(oldTemp);
-                    }
-                    if (oldVolt != rec.batteryVoltage) {
-                        oldVolt = rec.batteryVoltage;
-                        pw.print(" volt=");
-                        pw.print(oldVolt);
-                    }
-                    printBitDescriptions(pw, oldState, rec.states,
-                            HISTORY_STATE_DESCRIPTIONS);
-                    pw.println();
-                }
-                oldState = rec.states;
+                hprinter.printNextItem(pw, rec, now);
             }
+            finishIteratingHistoryLocked();
+            pw.println("");
+        }
+
+        if (startIteratingOldHistoryLocked()) {
+            pw.println("Old battery History:");
+            HistoryPrinter hprinter = new HistoryPrinter();
+            while (getNextOldHistoryLocked(rec)) {
+                hprinter.printNextItem(pw, rec, now);
+            }
+            finishIteratingOldHistoryLocked();
             pw.println("");
         }
         
@@ -1918,6 +1960,8 @@
     
     @SuppressWarnings("unused")
     public void dumpCheckinLocked(PrintWriter pw, String[] args, List<ApplicationInfo> apps) {
+        prepareForDumpLocked();
+
         boolean isUnpluggedOnly = false;
         
         for (String arg : args) {
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index aa959b4..f7661b6 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -35,64 +35,64 @@
     //consider ParcelFileDescriptor A(fileDescriptor fd),  ParcelFileDescriptor B(A)
     //in this particular case fd.close might be invoked twice.
     private final ParcelFileDescriptor mParcelDescriptor;
-    
+
     /**
      * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied
      * and this file doesn't already exist, then create the file with
      * permissions such that any application can read it.
      */
     public static final int MODE_WORLD_READABLE = 0x00000001;
-    
+
     /**
      * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied
      * and this file doesn't already exist, then create the file with
      * permissions such that any application can write it.
      */
     public static final int MODE_WORLD_WRITEABLE = 0x00000002;
-    
+
     /**
      * For use with {@link #open}: open the file with read-only access.
      */
     public static final int MODE_READ_ONLY = 0x10000000;
-    
+
     /**
      * For use with {@link #open}: open the file with write-only access.
      */
     public static final int MODE_WRITE_ONLY = 0x20000000;
-    
+
     /**
      * For use with {@link #open}: open the file with read and write access.
      */
     public static final int MODE_READ_WRITE = 0x30000000;
-    
+
     /**
      * For use with {@link #open}: create the file if it doesn't already exist.
      */
     public static final int MODE_CREATE = 0x08000000;
-    
+
     /**
      * For use with {@link #open}: erase contents of file when opening.
      */
     public static final int MODE_TRUNCATE = 0x04000000;
-    
+
     /**
      * For use with {@link #open}: append to end of file while writing.
      */
     public static final int MODE_APPEND = 0x02000000;
-    
+
     /**
      * Create a new ParcelFileDescriptor accessing a given file.
-     * 
+     *
      * @param file The file to be opened.
      * @param mode The desired access mode, must be one of
      * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
      * {@link #MODE_READ_WRITE}; may also be any combination of
      * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
      * {@link #MODE_WORLD_READABLE}, and {@link #MODE_WORLD_WRITEABLE}.
-     * 
+     *
      * @return Returns a new ParcelFileDescriptor pointing to the given
      * file.
-     * 
+     *
      * @throws FileNotFoundException Throws FileNotFoundException if the given
      * file does not exist or can not be opened with the requested mode.
      */
@@ -106,12 +106,12 @@
                 security.checkWrite(path);
             }
         }
-        
+
         if ((mode&MODE_READ_WRITE) == 0) {
             throw new IllegalArgumentException(
                     "Must specify MODE_READ_ONLY, MODE_WRITE_ONLY, or MODE_READ_WRITE");
         }
-        
+
         FileDescriptor fd = Parcel.openFileDescriptor(path, mode);
         return fd != null ? new ParcelFileDescriptor(fd) : null;
     }
@@ -137,13 +137,10 @@
      *         specified Socket.
      */
     public static ParcelFileDescriptor fromSocket(Socket socket) {
-        FileDescriptor fd = getFileDescriptorFromSocket(socket);
+        FileDescriptor fd = socket.getFileDescriptor$();
         return fd != null ? new ParcelFileDescriptor(fd) : null;
     }
 
-    // Extracts the file descriptor from the specified socket and returns it untouched
-    private static native FileDescriptor getFileDescriptorFromSocket(Socket socket);
-
     /**
      * Create two ParcelFileDescriptors structured as a data pipe.  The first
      * ParcelFileDescriptor in the returned array is the read side; the second
@@ -187,26 +184,26 @@
 
     /**
      * Retrieve the actual FileDescriptor associated with this object.
-     * 
+     *
      * @return Returns the FileDescriptor associated with this object.
      */
     public FileDescriptor getFileDescriptor() {
         return mFileDescriptor;
     }
-    
+
     /**
      * Return the total size of the file representing this fd, as determined
      * by stat().  Returns -1 if the fd is not a file.
      */
     public native long getStatSize();
-    
+
     /**
      * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream,
      * and I really don't think we want it to be public.
      * @hide
      */
     public native long seekTo(long pos);
-    
+
     /**
      * Return the native fd int for this ParcelFileDescriptor.  The
      * ParcelFileDescriptor still owns the fd, and it still must be closed
@@ -218,9 +215,9 @@
         }
         return getFdNative();
     }
-    
+
     private native int getFdNative();
-    
+
     /**
      * Return the native fd int for this ParcelFileDescriptor and detach it
      * from the object here.  You are now responsible for closing the fd in
@@ -240,11 +237,11 @@
         Parcel.clearFileDescriptor(mFileDescriptor);
         return fd;
     }
-    
+
     /**
      * Close the ParcelFileDescriptor. This implementation closes the underlying
      * OS resources allocated to represent this stream.
-     * 
+     *
      * @throws IOException
      *             If an error occurs attempting to close this ParcelFileDescriptor.
      */
@@ -261,7 +258,7 @@
             Parcel.closeFileDescriptor(mFileDescriptor);
         }
     }
-    
+
     /**
      * An InputStream you can create on a ParcelFileDescriptor, which will
      * take care of calling {@link ParcelFileDescriptor#close
@@ -269,7 +266,7 @@
      */
     public static class AutoCloseInputStream extends FileInputStream {
         private final ParcelFileDescriptor mFd;
-        
+
         public AutoCloseInputStream(ParcelFileDescriptor fd) {
             super(fd.getFileDescriptor());
             mFd = fd;
@@ -284,7 +281,7 @@
             }
         }
     }
-    
+
     /**
      * An OutputStream you can create on a ParcelFileDescriptor, which will
      * take care of calling {@link ParcelFileDescriptor#close
@@ -292,7 +289,7 @@
      */
     public static class AutoCloseOutputStream extends FileOutputStream {
         private final ParcelFileDescriptor mFd;
-        
+
         public AutoCloseOutputStream(ParcelFileDescriptor fd) {
             super(fd.getFileDescriptor());
             mFd = fd;
@@ -307,12 +304,12 @@
             }
         }
     }
-    
+
     @Override
     public String toString() {
         return "{ParcelFileDescriptor: " + mFileDescriptor + "}";
     }
-    
+
     @Override
     protected void finalize() throws Throwable {
         try {
@@ -323,13 +320,13 @@
             super.finalize();
         }
     }
-    
+
     public ParcelFileDescriptor(ParcelFileDescriptor descriptor) {
         super();
         mParcelDescriptor = descriptor;
         mFileDescriptor = mParcelDescriptor.mFileDescriptor;
     }
-    
+
     /*package */ParcelFileDescriptor(FileDescriptor descriptor) {
         super();
         if (descriptor == null) {
@@ -338,7 +335,7 @@
         mFileDescriptor = descriptor;
         mParcelDescriptor = null;
     }
-    
+
     /* Parcelable interface */
     public int describeContents() {
         return Parcelable.CONTENTS_FILE_DESCRIPTOR;
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index c1dd911..ae605fb 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -70,7 +70,7 @@
     private static File RECOVERY_DIR = new File("/cache/recovery");
     private static File COMMAND_FILE = new File(RECOVERY_DIR, "command");
     private static File LOG_FILE = new File(RECOVERY_DIR, "log");
-    private static String LAST_LOG_FILENAME = "last_log";
+    private static String LAST_PREFIX = "last_";
 
     // Length limits for reading files.
     private static int LOG_FILE_MAX_LENGTH = 64 * 1024;
@@ -415,10 +415,11 @@
             Log.e(TAG, "Error reading recovery log", e);
         }
 
-        // Delete everything in RECOVERY_DIR except LAST_LOG_FILENAME
+        // Delete everything in RECOVERY_DIR except those beginning
+        // with LAST_PREFIX
         String[] names = RECOVERY_DIR.list();
         for (int i = 0; names != null && i < names.length; i++) {
-            if (names[i].equals(LAST_LOG_FILENAME)) continue;
+            if (names[i].startsWith(LAST_PREFIX)) continue;
             File f = new File(RECOVERY_DIR, names[i]);
             if (!f.delete()) {
                 Log.e(TAG, "Can't delete: " + f);
diff --git a/core/java/android/text/CharSequenceIterator.java b/core/java/android/text/CharSequenceIterator.java
index 4946406..4b8ac10 100644
--- a/core/java/android/text/CharSequenceIterator.java
+++ b/core/java/android/text/CharSequenceIterator.java
@@ -16,22 +16,18 @@
 
 package android.text;
 
-import android.util.MathUtils;
-
 import java.text.CharacterIterator;
 
 /** {@hide} */
 public class CharSequenceIterator implements CharacterIterator {
     private final CharSequence mValue;
 
-    private final int mStart;
-    private final int mEnd;
+    private final int mLength;
     private int mIndex;
 
     public CharSequenceIterator(CharSequence value) {
         mValue = value;
-        mStart = 0;
-        mEnd = value.length();
+        mLength = value.length();
         mIndex = 0;
     }
 
@@ -46,7 +42,7 @@
 
     /** {@inheritDoc} */
     public char current() {
-        if (mIndex == mEnd) {
+        if (mIndex == mLength) {
             return DONE;
         }
         return mValue.charAt(mIndex);
@@ -54,12 +50,12 @@
 
     /** {@inheritDoc} */
     public int getBeginIndex() {
-        return mStart;
+        return 0;
     }
 
     /** {@inheritDoc} */
     public int getEndIndex() {
-        return mEnd;
+        return mLength;
     }
 
     /** {@inheritDoc} */
@@ -69,27 +65,36 @@
 
     /** {@inheritDoc} */
     public char first() {
-        return setIndex(mStart);
+        return setIndex(0);
     }
 
     /** {@inheritDoc} */
     public char last() {
-        return setIndex(mEnd - 1);
+        return setIndex(mLength - 1);
     }
 
     /** {@inheritDoc} */
     public char next() {
+        if (mIndex == mLength) {
+            return DONE;
+        }
         return setIndex(mIndex + 1);
     }
 
     /** {@inheritDoc} */
     public char previous() {
+        if (mIndex == 0) {
+            return DONE;
+        }
         return setIndex(mIndex - 1);
     }
 
     /** {@inheritDoc} */
     public char setIndex(int index) {
-        mIndex = MathUtils.constrain(index, mStart, mEnd);
+        if ((index < 0) || (index > mLength)) {
+            throw new IllegalArgumentException("Valid range is [" + 0 + "..." + mLength + "]");
+        }
+        mIndex = index;
         return current();
     }
 }
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index ee6342a..ac5db62 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -37,6 +37,7 @@
 import android.text.style.StrikethroughSpan;
 import android.text.style.StyleSpan;
 import android.text.style.SubscriptSpan;
+import android.text.style.SuggestionSpan;
 import android.text.style.SuperscriptSpan;
 import android.text.style.TextAppearanceSpan;
 import android.text.style.TypefaceSpan;
@@ -566,7 +567,7 @@
     /** @hide */
     public static final int ANNOTATION = 18;
     /** @hide */
-    public static final int CORRECTION_SPAN = 19;
+    public static final int SUGGESTION_SPAN = 19;
 
     /**
      * Flatten a CharSequence and whatever styles can be copied across processes
@@ -712,6 +713,10 @@
                     readSpan(p, sp, new Annotation(p));
                     break;
 
+                case SUGGESTION_SPAN:
+                    readSpan(p, sp, new SuggestionSpan(p));
+                    break;
+
                 default:
                     throw new RuntimeException("bogus span encoding " + kind);
                 }
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index 80c0106..b25ba8d 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -390,7 +390,7 @@
         }
 
         private boolean isValidOffset(int offset) {
-            return offset >= 0 && offset < mCurrent.length();
+            return offset >= 0 && offset <= mCurrent.length();
         }
 
         private boolean isLetterOrDigit(int offset) {
@@ -404,7 +404,7 @@
         /** {@inheritDoc} */
         public int preceding(int offset) {
             // always round cursor index into valid string index
-            offset = MathUtils.constrain(offset, 0, mCurrent.length() - 1);
+            offset = MathUtils.constrain(offset, 0, mCurrent.length());
 
             do {
                 offset = mIterator.preceding(offset);
@@ -417,7 +417,7 @@
         /** {@inheritDoc} */
         public int following(int offset) {
             // always round cursor index into valid string index
-            offset = MathUtils.constrain(offset, 0, mCurrent.length() - 1);
+            offset = MathUtils.constrain(offset, 0, mCurrent.length());
 
             do {
                 offset = mIterator.following(offset);
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 5091c9e..7083641 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -26,7 +26,7 @@
 import java.util.Locale;
 
 /**
- * Sets correction candidates of words under this span.
+ * Holds suggestion candidates of words under this span.
  */
 public class SuggestionSpan implements ParcelableSpan {
 
@@ -139,7 +139,7 @@
 
     @Override
     public int getSpanTypeId() {
-        return TextUtils.CORRECTION_SPAN;
+        return TextUtils.SUGGESTION_SPAN;
     }
 
     public static final Parcelable.Creator<SuggestionSpan> CREATOR =
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index a39c7c7..eef2a33 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -505,6 +505,13 @@
         }
     }
 
+    /**
+     * Returns a list of enabled input method subtypes for the specified input method info.
+     * @param imi An input method info whose subtypes list will be returned.
+     * @param allowsImplicitlySelectedSubtypes A boolean flag to allow to return the implicitly
+     * selected subtypes. If an input method info doesn't have enabled subtypes, the framework
+     * will implicitly enable subtypes according to the current system language.
+     */
     public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi,
             boolean allowsImplicitlySelectedSubtypes) {
         try {
@@ -1429,16 +1436,26 @@
         }
     }
 
-    public void showInputMethodAndSubtypeEnabler(String topId) {
+    /**
+     * Show the settings for enabling subtypes of the specified input method.
+     * @param imiId An input method, whose subtypes settings will be shown. If imiId is null,
+     * subtypes of all input methods will be shown.
+     */
+    public void showInputMethodAndSubtypeEnabler(String imiId) {
         synchronized (mH) {
             try {
-                mService.showInputMethodAndSubtypeEnablerFromClient(mClient, topId);
+                mService.showInputMethodAndSubtypeEnablerFromClient(mClient, imiId);
             } catch (RemoteException e) {
                 Log.w(TAG, "IME died: " + mCurId, e);
             }
         }
     }
 
+    /**
+     * Returns the current input method subtype. This subtype is one of the subtypes in
+     * the current input method. This method returns null when the current input method doesn't
+     * have any input method subtype.
+     */
     public InputMethodSubtype getCurrentInputMethodSubtype() {
         synchronized (mH) {
             try {
@@ -1450,6 +1467,12 @@
         }
     }
 
+    /**
+     * Switch to a new input method subtype of the current input method.
+     * @param subtype A new input method subtype to switch.
+     * @return true if the current subtype was successfully switched. When the specified subtype is
+     * null, this method returns false.
+     */
     public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
         synchronized (mH) {
             try {
@@ -1461,6 +1484,9 @@
         }
     }
 
+    /**
+     * Returns a map of all shortcut input method info and their subtypes.
+     */
     public Map<InputMethodInfo, List<InputMethodSubtype>> getShortcutInputMethodsAndSubtypes() {
         synchronized (mH) {
             HashMap<InputMethodInfo, List<InputMethodSubtype>> ret =
@@ -1493,6 +1519,15 @@
         }
     }
 
+    /**
+     * Force switch to the last used input method and subtype. If the last input method didn't have
+     * any subtypes, the framework will simply switch to the last input method with no subtype
+     * specified.
+     * @param imeToken Supplies the identifying token given to an input method when it was started,
+     * which allows it to perform this operation on itself.
+     * @return true if the current input method and subtype was successfully switched to the last
+     * used input method and subtype.
+     */
     public boolean switchToLastInputMethod(IBinder imeToken) {
         synchronized (mH) {
             try {
@@ -1504,6 +1539,17 @@
         }
     }
 
+    public InputMethodSubtype getLastInputMethodSubtype() {
+        synchronized (mH) {
+            try {
+                return mService.getLastInputMethodSubtype();
+            } catch (RemoteException e) {
+                Log.w(TAG, "IME died: " + mCurId, e);
+                return null;
+            }
+        }
+    }
+
     void doDump(FileDescriptor fd, PrintWriter fout, String[] args) {
         final Printer p = new PrintWriterPrinter(fout);
         p.println("Input method client state for " + this + ":");
diff --git a/core/java/android/webkit/webdriver/WebDriver.java b/core/java/android/webkit/webdriver/WebDriver.java
new file mode 100644
index 0000000..7a25390
--- /dev/null
+++ b/core/java/android/webkit/webdriver/WebDriver.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit.webdriver;
+
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Message;
+import android.view.View;
+import android.webkit.ConsoleMessage;
+import android.webkit.GeolocationPermissions;
+import android.webkit.JsPromptResult;
+import android.webkit.JsResult;
+import android.webkit.ValueCallback;
+import android.webkit.WebChromeClient;
+import android.webkit.WebStorage;
+import android.webkit.WebView;
+
+/**
+ * Drives a web application by controlling the WebView. This class
+ * provides a DOM-like API allowing to get information about the page,
+ * navigate, and interact with the web application. This is particularly useful
+ * for testing a web application.
+ *
+ * <p/>{@link android.webkit.webdriver.WebDriver} should be created in the main
+ * thread, and invoked from another thread. Here is a sample usage:
+ *
+ * public class WebDriverStubActivity extends Activity {
+ *   private WebDriver mDriver;
+ *
+ *   public void onCreate(Bundle savedInstanceState) {
+ *       super.onCreate(savedInstanceState);
+ *       WebView view = new WebView(this);
+ *       mDriver = new WebDriver(view);
+ *       setContentView(view);
+ *   }
+ *
+ *
+ *   public WebDriver getDriver() {
+ *       return mDriver;
+ *   }
+ *}
+ *
+ * public class WebDriverTest extends
+ *       ActivityInstrumentationTestCase2<WebDriverStubActivity>{
+ *   private WebDriver mDriver;
+ *
+ *   public WebDriverTest() {
+ *       super(WebDriverStubActivity.class);
+ *   }
+ *
+ *   protected void setUp() throws Exception {
+ *       super.setUp();
+ *       mDriver = getActivity().getDriver();
+ *   }
+ *
+ *   public void testGetIsBlocking() {
+ *       mDriver.get("http://google.com");
+ *       assertTrue(mDriver.getPageSource().startsWith("<html"));
+ *   }
+ *}
+ *
+ * @hide
+ */
+public class WebDriver {
+    // Timeout for page load in milliseconds
+    private static final int LOADING_TIMEOUT = 30000;
+    // Timeout for executing JavaScript in the WebView in milliseconds
+    private static final int JS_EXECUTION_TIMEOUT = 10000;
+
+    // Commands posted to the handler
+    private static final int GET_URL = 1;
+    private static final int EXECUTE_SCRIPT = 2;
+
+    private static final long MAIN_THREAD = Thread.currentThread().getId();
+
+    // This is updated by a callabck from JavaScript when the result is ready
+    private String mJsResult;
+
+    // Used for synchronization
+    private final Object mSyncObject;
+
+    // Updated when the command is done executing in the main thread.
+    private volatile boolean mCommandDone;
+
+    private WebView mWebView;
+
+    // This Handler runs in the main UI thread
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == GET_URL) {
+                final String url = (String) msg.obj;
+                mWebView.loadUrl(url);
+            } else if (msg.what == EXECUTE_SCRIPT) {
+                executeScript((String) msg.obj);
+            }
+        }
+    };
+
+    public WebDriver(WebView webview) {
+        if (!mWebView.getSettings().getJavaScriptEnabled()) {
+            throw new RuntimeException("Javascript is disabled in the WebView. "
+                    + "Enable it to use WebDriver");
+        }
+        shouldRunInMainThread(true);
+        mSyncObject = new Object();
+        this.mWebView = webview;
+        WebchromeClientWrapper chromeWrapper = new WebchromeClientWrapper(
+                webview.getWebChromeClient(), this);
+        mWebView.setWebChromeClient(chromeWrapper);
+        mWebView.addJavascriptInterface(new JavascriptResultReady(),
+                "webdriver");
+    }
+
+    /**
+     * Loads a URL in the WebView. This function is blocking and will return
+     * when the page has finished loading.
+     *
+     * @param url The URL to load.
+     */
+    public void get(String url) {
+        executeCommand(GET_URL, url, LOADING_TIMEOUT);
+    }
+
+    /**
+     * @return The source page of the currently loaded page in WebView.
+     */
+    public String getPageSource() {
+        executeCommand(EXECUTE_SCRIPT, "return (new XMLSerializer())"
+                + ".serializeToString(document.documentElement);",
+                JS_EXECUTION_TIMEOUT);
+        return mJsResult;
+    }
+
+    private void executeScript(String script) {
+        mWebView.loadUrl("javascript:" + script);
+    }
+
+    private void shouldRunInMainThread(boolean value) {
+        assert (value == (MAIN_THREAD == Thread.currentThread().getId()));
+    }
+
+    /**
+     * Interface called from JavaScript when the result is ready.
+     */
+    private class JavascriptResultReady {
+
+        /**
+         * A callback from JavaScript to Java that passes the result as a
+         * parameter. This method is available from the WebView's
+         * JavaScript DOM as window.webdriver.resultReady().
+         *
+         * @param result The result that should be sent to Java from Javascript.
+         */
+        public void resultReady(String result) {
+            synchronized (mSyncObject) {
+                mJsResult = result;
+                mCommandDone = true;
+                mSyncObject.notify();
+            }
+        }
+    }
+
+    /* package */ void notifyCommandDone() {
+        synchronized (mSyncObject) {
+            mCommandDone = true;
+            mSyncObject.notify();
+        }
+    }
+
+    /**
+     * Executes the given command by posting a message to mHandler. This thread
+     * will block until the command which runs in the main thread is done.
+     *
+     * @param command The command to run.
+     * @param arg The argument for that command.
+     * @param timeout A timeout in milliseconds.
+     */
+    private void executeCommand(int command, String arg, long timeout) {
+        shouldRunInMainThread(false);
+
+        synchronized (mSyncObject) {
+            mCommandDone = false;
+            Message msg = mHandler.obtainMessage(command);
+            msg.obj = arg;
+            mHandler.sendMessage(msg);
+
+            long end = System.currentTimeMillis() + timeout;
+            while (!mCommandDone) {
+                if (System.currentTimeMillis() >= end) {
+                    throw new RuntimeException("Timeout executing command.");
+                }
+                try {
+                    mSyncObject.wait(timeout);
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+    }
+}
diff --git a/core/java/android/webkit/webdriver/WebchromeClientWrapper.java b/core/java/android/webkit/webdriver/WebchromeClientWrapper.java
new file mode 100644
index 0000000..ea33c5b
--- /dev/null
+++ b/core/java/android/webkit/webdriver/WebchromeClientWrapper.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit.webdriver;
+
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Message;
+import android.view.View;
+import android.webkit.ConsoleMessage;
+import android.webkit.GeolocationPermissions;
+import android.webkit.JsPromptResult;
+import android.webkit.JsResult;
+import android.webkit.ValueCallback;
+import android.webkit.WebChromeClient;
+import android.webkit.WebStorage;
+import android.webkit.WebView;
+
+/* package */ class WebchromeClientWrapper extends WebChromeClient {
+
+    private final WebChromeClient mDelegate;
+    private final WebDriver mDriver;
+
+    public WebchromeClientWrapper(WebChromeClient delegate, WebDriver driver) {
+        if (delegate == null) {
+            this.mDelegate = new WebChromeClient();
+        } else {
+            this.mDelegate = delegate;
+        }
+        this.mDriver = driver;
+    }
+
+    @Override
+    public void onProgressChanged(WebView view, int newProgress) {
+        if (newProgress == 100) {
+            mDriver.notifyCommandDone();
+        }
+        mDelegate.onProgressChanged(view, newProgress);
+    }
+
+    @Override
+    public void onReceivedTitle(WebView view, String title) {
+        mDelegate.onReceivedTitle(view, title);
+    }
+
+    @Override
+    public void onReceivedIcon(WebView view, Bitmap icon) {
+        mDelegate.onReceivedIcon(view, icon);
+    }
+
+    @Override
+    public void onReceivedTouchIconUrl(WebView view, String url,
+            boolean precomposed) {
+        mDelegate.onReceivedTouchIconUrl(view, url, precomposed);
+    }
+
+    @Override
+    public void onShowCustomView(View view,
+            CustomViewCallback callback) {
+        mDelegate.onShowCustomView(view, callback);
+    }
+
+    @Override
+    public void onHideCustomView() {
+        mDelegate.onHideCustomView();
+    }
+
+    @Override
+    public boolean onCreateWindow(WebView view, boolean dialog,
+            boolean userGesture, Message resultMsg) {
+        return mDelegate.onCreateWindow(view, dialog, userGesture, resultMsg);
+    }
+
+    @Override
+    public void onRequestFocus(WebView view) {
+        mDelegate.onRequestFocus(view);
+    }
+
+    @Override
+    public void onCloseWindow(WebView window) {
+        mDelegate.onCloseWindow(window);
+    }
+
+    @Override
+    public boolean onJsAlert(WebView view, String url, String message,
+            JsResult result) {
+        return mDelegate.onJsAlert(view, url, message, result);
+    }
+
+    @Override
+    public boolean onJsConfirm(WebView view, String url, String message,
+            JsResult result) {
+        return mDelegate.onJsConfirm(view, url, message, result);
+    }
+
+    @Override
+    public boolean onJsPrompt(WebView view, String url, String message,
+            String defaultValue, JsPromptResult result) {
+        return mDelegate.onJsPrompt(view, url, message, defaultValue, result);
+    }
+
+    @Override
+    public boolean onJsBeforeUnload(WebView view, String url, String message,
+            JsResult result) {
+        return mDelegate.onJsBeforeUnload(view, url, message, result);
+    }
+
+    @Override
+    public void onExceededDatabaseQuota(String url, String databaseIdentifier,
+            long currentQuota, long estimatedSize, long totalUsedQuota,
+            WebStorage.QuotaUpdater quotaUpdater) {
+        mDelegate.onExceededDatabaseQuota(url, databaseIdentifier, currentQuota,
+                estimatedSize, totalUsedQuota, quotaUpdater);
+    }
+
+    @Override
+    public void onReachedMaxAppCacheSize(long spaceNeeded, long totalUsedQuota,
+            WebStorage.QuotaUpdater quotaUpdater) {
+        mDelegate.onReachedMaxAppCacheSize(spaceNeeded, totalUsedQuota,
+                quotaUpdater);
+    }
+
+    @Override
+    public void onGeolocationPermissionsShowPrompt(String origin,
+            GeolocationPermissions.Callback callback) {
+        mDelegate.onGeolocationPermissionsShowPrompt(origin, callback);
+    }
+
+    @Override
+    public void onGeolocationPermissionsHidePrompt() {
+        mDelegate.onGeolocationPermissionsHidePrompt();
+    }
+
+    @Override
+    public boolean onJsTimeout() {
+        return mDelegate.onJsTimeout();
+    }
+
+    @Override
+    public void onConsoleMessage(String message, int lineNumber,
+            String sourceID) {
+        mDelegate.onConsoleMessage(message, lineNumber, sourceID);
+    }
+
+    @Override
+    public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
+        return mDelegate.onConsoleMessage(consoleMessage);
+    }
+
+    @Override
+    public Bitmap getDefaultVideoPoster() {
+        return mDelegate.getDefaultVideoPoster();
+    }
+
+    @Override
+    public View getVideoLoadingProgressView() {
+        return mDelegate.getVideoLoadingProgressView();
+    }
+
+    @Override
+    public void getVisitedHistory(ValueCallback<String[]> callback) {
+        mDelegate.getVisitedHistory(callback);
+    }
+
+    @Override
+    public void openFileChooser(ValueCallback<Uri> uploadFile,
+            String acceptType) {
+        mDelegate.openFileChooser(uploadFile, acceptType);
+    }
+
+    @Override
+    public void setInstallableWebApp() {
+        mDelegate.setInstallableWebApp();
+    }
+
+    @Override
+    public void setupAutoFill(Message msg) {
+        mDelegate.setupAutoFill(msg);
+    }
+}
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index f659ead..590a768 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -39,7 +39,7 @@
  * Children are drawn in a stack, with the most recently added child on top.
  * The size of the frame layout is the size of its largest child (plus padding), visible
  * or not (if the FrameLayout's parent permits). Views that are GONE are used for sizing
- * only if {@link #setMeasureAllChildren(boolean) setConsiderGoneChildrenWhenMeasuring()}
+ * only if {@link #setMeasureAllChildren(boolean) setMeasureAllChildren()}
  * is set to true.
  *
  * @attr ref android.R.styleable#FrameLayout_foreground
@@ -566,4 +566,3 @@
         }
     }
 }
-
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index d86504d..fcda673 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -36,6 +36,7 @@
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
 import android.util.Log;
+import android.util.LogWriter;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
 import android.util.Slog;
@@ -70,7 +71,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 54;
+    private static final int VERSION = 57;
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -154,11 +155,26 @@
     boolean mHaveBatteryLevel = false;
     boolean mRecordingHistory = true;
     int mNumHistoryItems;
+
+    static final int MAX_HISTORY_BUFFER = 64*1024; // 64KB
+    static final int MAX_MAX_HISTORY_BUFFER = 92*1024; // 92KB
+    final Parcel mHistoryBuffer = Parcel.obtain();
+    final HistoryItem mHistoryLastWritten = new HistoryItem();
+    final HistoryItem mHistoryLastLastWritten = new HistoryItem();
+    int mHistoryBufferLastPos = -1;
+    boolean mHistoryOverflow = false;
+    long mLastHistoryTime = 0;
+
+    final HistoryItem mHistoryCur = new HistoryItem();
+
     HistoryItem mHistory;
     HistoryItem mHistoryEnd;
     HistoryItem mHistoryLastEnd;
     HistoryItem mHistoryCache;
-    final HistoryItem mHistoryCur = new HistoryItem();
+
+    private HistoryItem mHistoryIterator;
+    private boolean mReadOverflow;
+    private boolean mIteratingHistory;
 
     int mStartCount;
 
@@ -1189,9 +1205,82 @@
         mBtHeadset = headset;
     }
 
+    int mChangedBufferStates = 0;
+
+    void addHistoryBufferLocked(long curTime) {
+        if (!mHaveBatteryLevel || !mRecordingHistory) {
+            return;
+        }
+
+        if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE
+                && (mHistoryBaseTime+curTime) < (mHistoryLastWritten.time+2000)
+                && ((mHistoryLastWritten.states^mHistoryCur.states)&mChangedBufferStates) == 0) {
+            // If the current is the same as the one before, then we no
+            // longer need the entry.
+            mHistoryBuffer.setDataSize(mHistoryBufferLastPos);
+            mHistoryBuffer.setDataPosition(mHistoryBufferLastPos);
+            mHistoryBufferLastPos = -1;
+            if (mHistoryLastLastWritten.cmd == HistoryItem.CMD_UPDATE
+                    && mHistoryLastLastWritten.same(mHistoryCur)) {
+                // If this results in us returning to the state written
+                // prior to the last one, then we can just delete the last
+                // written one and drop the new one.  Nothing more to do.
+                mHistoryLastWritten.setTo(mHistoryLastLastWritten);
+                mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL;
+                return;
+            }
+            mChangedBufferStates |= mHistoryLastWritten.states^mHistoryCur.states;
+            curTime = mHistoryLastWritten.time - mHistoryBaseTime;
+        } else {
+            mChangedBufferStates = 0;
+        }
+
+        final int dataSize = mHistoryBuffer.dataSize();
+        if (dataSize >= MAX_HISTORY_BUFFER) {
+            if (!mHistoryOverflow) {
+                mHistoryOverflow = true;
+                addHistoryBufferLocked(curTime, HistoryItem.CMD_OVERFLOW);
+            }
+
+            // Once we've reached the maximum number of items, we only
+            // record changes to the battery level and the most interesting states.
+            // Once we've reached the maximum maximum number of items, we only
+            // record changes to the battery level.
+            if (mHistoryLastWritten.batteryLevel == mHistoryCur.batteryLevel &&
+                    (dataSize >= MAX_MAX_HISTORY_BUFFER
+                            || ((mHistoryEnd.states^mHistoryCur.states)
+                                    & HistoryItem.MOST_INTERESTING_STATES) == 0)) {
+                return;
+            }
+        }
+
+        addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE);
+    }
+
+    void addHistoryBufferLocked(long curTime, byte cmd) {
+        int origPos = 0;
+        if (mIteratingHistory) {
+            origPos = mHistoryBuffer.dataPosition();
+            mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
+        }
+        mHistoryBufferLastPos = mHistoryBuffer.dataPosition();
+        mHistoryLastLastWritten.setTo(mHistoryLastWritten);
+        mHistoryLastWritten.setTo(mHistoryBaseTime + curTime, cmd, mHistoryCur);
+        mHistoryLastWritten.writeDelta(mHistoryBuffer, mHistoryLastLastWritten);
+        mLastHistoryTime = curTime;
+        if (DEBUG_HISTORY) Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos
+                + " now " + mHistoryBuffer.dataPosition()
+                + " size is now " + mHistoryBuffer.dataSize());
+        if (mIteratingHistory) {
+            mHistoryBuffer.setDataPosition(origPos);
+        }
+    }
+
     int mChangedStates = 0;
 
     void addHistoryRecordLocked(long curTime) {
+        addHistoryBufferLocked(curTime);
+
         if (!mHaveBatteryLevel || !mRecordingHistory) {
             return;
         }
@@ -1268,6 +1357,7 @@
     }
 
     void clearHistoryLocked() {
+        if (DEBUG_HISTORY) Slog.i(TAG, "********** CLEARING HISTORY!");
         if (mHistory != null) {
             mHistoryEnd.next = mHistoryCache;
             mHistoryCache = mHistory;
@@ -1275,6 +1365,15 @@
         }
         mNumHistoryItems = 0;
         mHistoryBaseTime = 0;
+        mLastHistoryTime = 0;
+
+        mHistoryBuffer.setDataSize(0);
+        mHistoryBuffer.setDataPosition(0);
+        mHistoryBuffer.setDataCapacity(MAX_HISTORY_BUFFER/2);
+        mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL;
+        mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
+        mHistoryBufferLastPos = -1;
+        mHistoryOverflow = false;
     }
 
     public void doUnplugLocked(long batteryUptime, long batteryRealtime) {
@@ -3910,11 +4009,13 @@
         mDischargeUnplugLevel = 0;
         mDischargeCurrentLevel = 0;
         initDischarge();
+        clearHistoryLocked();
     }
 
     public BatteryStatsImpl(Parcel p) {
         mFile = null;
         mHandler = null;
+        clearHistoryLocked();
         readFromParcel(p);
     }
 
@@ -3932,25 +4033,79 @@
         }
     }
 
-    private HistoryItem mHistoryIterator;
-
-    public boolean startIteratingHistoryLocked() {
+    @Override
+    public boolean startIteratingOldHistoryLocked() {
+        if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
+                + " pos=" + mHistoryBuffer.dataPosition());
+        mHistoryBuffer.setDataPosition(0);
+        mReadOverflow = false;
+        mIteratingHistory = true;
         return (mHistoryIterator = mHistory) != null;
     }
 
-    public boolean getNextHistoryLocked(HistoryItem out) {
+    @Override
+    public boolean getNextOldHistoryLocked(HistoryItem out) {
+        boolean end = mHistoryBuffer.dataPosition() >= mHistoryBuffer.dataSize();
+        if (!end) {
+            mHistoryLastWritten.readDelta(mHistoryBuffer, null);
+            mReadOverflow |= mHistoryLastWritten.cmd == HistoryItem.CMD_OVERFLOW;
+        }
         HistoryItem cur = mHistoryIterator;
         if (cur == null) {
+            if (!mReadOverflow && !end) {
+                Slog.w(TAG, "Old history ends before new history!");
+            }
             return false;
         }
         out.setTo(cur);
         mHistoryIterator = cur.next;
+        if (!mReadOverflow) {
+            if (end) {
+                Slog.w(TAG, "New history ends before old history!");
+            } else if (!out.same(mHistoryLastWritten)) {
+                long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
+                PrintWriter pw = new PrintWriter(new LogWriter(android.util.Log.WARN, TAG));
+                pw.println("Histories differ!");
+                pw.println("Old history:");
+                (new HistoryPrinter()).printNextItem(pw, out, now);
+                pw.println("New history:");
+                (new HistoryPrinter()).printNextItem(pw, mHistoryLastWritten, now);
+            }
+        }
         return true;
     }
 
     @Override
-    public HistoryItem getHistory() {
-        return mHistory;
+    public void finishIteratingOldHistoryLocked() {
+        mIteratingHistory = false;
+        mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
+    }
+
+    @Override
+    public boolean startIteratingHistoryLocked() {
+        if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
+                + " pos=" + mHistoryBuffer.dataPosition());
+        mHistoryBuffer.setDataPosition(0);
+        mReadOverflow = false;
+        mIteratingHistory = true;
+        return mHistoryBuffer.dataSize() > 0;
+    }
+
+    @Override
+    public boolean getNextHistoryLocked(HistoryItem out) {
+        boolean end = mHistoryBuffer.dataPosition() >= mHistoryBuffer.dataSize();
+        if (end) {
+            return false;
+        }
+
+        out.readDelta(mHistoryBuffer, null);
+        return true;
+    }
+
+    @Override
+    public void finishIteratingHistoryLocked() {
+        mIteratingHistory = false;
+        mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
     }
 
     @Override
@@ -4697,7 +4852,9 @@
             Slog.e("BatteryStats", "Error reading battery statistics", e);
         }
 
-        addHistoryRecordLocked(SystemClock.elapsedRealtime(), HistoryItem.CMD_START);
+        long now = SystemClock.elapsedRealtime();
+        addHistoryRecordLocked(now, HistoryItem.CMD_START);
+        addHistoryBufferLocked(now, HistoryItem.CMD_START);
     }
 
     public int describeContents() {
@@ -4705,30 +4862,54 @@
     }
 
     void readHistory(Parcel in) {
-        mHistory = mHistoryEnd = mHistoryCache = null;
-        mHistoryBaseTime = 0;
-        long time;
-        while ((time=in.readLong()) >= 0) {
-            HistoryItem rec = new HistoryItem(time, in);
-            addHistoryRecordLocked(rec);
-            if (rec.time > mHistoryBaseTime) {
-                mHistoryBaseTime = rec.time;
-            }
+        mHistoryBaseTime = in.readLong();
+
+        mHistoryBuffer.setDataSize(0);
+        mHistoryBuffer.setDataPosition(0);
+
+        int bufSize = in.readInt();
+        int curPos = in.dataPosition();
+        if (bufSize >= (MAX_MAX_HISTORY_BUFFER*3)) {
+            Slog.w(TAG, "File corrupt: history data buffer too large " + bufSize);
+        } else if ((bufSize&~3) != bufSize) {
+            Slog.w(TAG, "File corrupt: history data buffer not aligned " + bufSize);
+        } else {
+            if (DEBUG_HISTORY) Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize
+                    + " bytes at " + curPos);
+            mHistoryBuffer.appendFrom(in, curPos, bufSize);
+            in.setDataPosition(curPos + bufSize);
         }
 
-        long oldnow = SystemClock.elapsedRealtime() - (5*60*100);
+        long oldnow = SystemClock.elapsedRealtime() - (5*60*1000);
         if (oldnow > 0) {
             // If the system process has restarted, but not the entire
             // system, then the mHistoryBaseTime already accounts for
             // much of the elapsed time.  We thus want to adjust it back,
             // to avoid large gaps in the data.  We determine we are
             // in this case by arbitrarily saying it is so if at this
-            // point in boot the elapsed time is already more than 5 seconds.
+            // point in boot the elapsed time is already more than 5 minutes.
             mHistoryBaseTime -= oldnow;
         }
     }
 
+    void readOldHistory(Parcel in) {
+        mHistory = mHistoryEnd = mHistoryCache = null;
+        long time;
+        while ((time=in.readLong()) >= 0) {
+            HistoryItem rec = new HistoryItem(time, in);
+            addHistoryRecordLocked(rec);
+        }
+    }
+
     void writeHistory(Parcel out) {
+        out.writeLong(mLastHistoryTime);
+        out.writeInt(mHistoryBuffer.dataSize());
+        if (DEBUG_HISTORY) Slog.i(TAG, "***************** WRITING HISTORY: "
+                + mHistoryBuffer.dataSize() + " bytes at " + out.dataPosition());
+        out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
+    }
+
+    void writeOldHistory(Parcel out) {
         HistoryItem rec = mHistory;
         while (rec != null) {
             if (rec.time >= 0) rec.writeToParcel(out, 0);
@@ -4746,6 +4927,7 @@
         }
 
         readHistory(in);
+        readOldHistory(in);
 
         mStartCount = in.readInt();
         mBatteryUptime = in.readLong();
@@ -4935,6 +5117,9 @@
      * @param out the Parcel to be written to.
      */
     public void writeSummaryToParcel(Parcel out) {
+        // Need to update with current kernel wake lock counts.
+        updateKernelWakelocksLocked();
+
         final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
         final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
         final long NOW = getBatteryUptimeLocked(NOW_SYS);
@@ -4943,6 +5128,7 @@
         out.writeInt(VERSION);
 
         writeHistory(out);
+        writeOldHistory(out);
 
         out.writeInt(mStartCount);
         out.writeLong(computeBatteryUptime(NOW_SYS, STATS_SINCE_CHARGED));
@@ -5256,6 +5442,9 @@
 
     @SuppressWarnings("unused")
     void writeToParcelLocked(Parcel out, boolean inclUids, int flags) {
+        // Need to update with current kernel wake lock counts.
+        updateKernelWakelocksLocked();
+
         final long uSecUptime = SystemClock.uptimeMillis() * 1000;
         final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
         final long batteryUptime = getBatteryUptimeLocked(uSecUptime);
@@ -5358,6 +5547,11 @@
         }
     };
 
+    public void prepareForDumpLocked() {
+        // Need to retrieve current kernel wake lock stats before printing.
+        updateKernelWakelocksLocked();
+    }
+
     public void dumpLocked(PrintWriter pw) {
         if (DEBUG) {
             Printer pr = new PrintWriterPrinter(pw);
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 611d987..4ffa4e1 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -33,6 +33,7 @@
     List<InputMethodInfo> getEnabledInputMethodList();
     List<InputMethodSubtype> getEnabledInputMethodSubtypeList(in InputMethodInfo imi,
             boolean allowsImplicitlySelectedSubtypes);
+    InputMethodSubtype getLastInputMethodSubtype();
     // TODO: We should change the return type from List to List<Parcelable>
     // Currently there is a bug that aidl doesn't accept List<Parcelable>
     List getShortcutInputMethodsAndSubtypes();
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f29d83e..b628b9dc 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -1,19 +1,18 @@
-/* //device/libs/android_runtime/AndroidRuntime.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 #define LOG_TAG "AndroidRuntime"
 //#define LOG_NDEBUG 0
@@ -212,7 +211,7 @@
     if (value != NULL && strcmp(value, "true") == 0) {
         return 1;
     }
-    
+
     return 0;
 }
 
@@ -227,7 +226,7 @@
     { "isComputerOn", "()I",
         (void*) com_android_internal_os_RuntimeInit_isComputerOn },
     { "turnComputerOn", "()V",
-        (void*) com_android_internal_os_RuntimeInit_turnComputerOn },    
+        (void*) com_android_internal_os_RuntimeInit_turnComputerOn },
     { "getQwertyKeyboard", "()I",
         (void*) com_android_internal_os_RuntimeInit_getQwertyKeyboard },
 };
@@ -278,51 +277,16 @@
     return jniRegisterNativeMethods(env, className, gMethods, numMethods);
 }
 
-/*
- * Call a static Java Programming Language function that takes no arguments and returns void.
- */
-status_t AndroidRuntime::callStatic(const char* className, const char* methodName)
+status_t AndroidRuntime::callMain(const char* className,
+    jclass clazz, int argc, const char* const argv[])
 {
     JNIEnv* env;
-    jclass clazz;
-    jmethodID methodId;
-
-    env = getJNIEnv();
-    if (env == NULL)
-        return UNKNOWN_ERROR;
-
-    clazz = findClass(env, className);
-    if (clazz == NULL) {
-        LOGE("ERROR: could not find class '%s'\n", className);
-        return UNKNOWN_ERROR;
-    }
-    methodId = env->GetStaticMethodID(clazz, methodName, "()V");
-    if (methodId == NULL) {
-        LOGE("ERROR: could not find method %s.%s\n", className, methodName);
-        return UNKNOWN_ERROR;
-    }
-
-    env->CallStaticVoidMethod(clazz, methodId);
-
-    return NO_ERROR;
-}
-
-status_t AndroidRuntime::callMain(
-    const char* className, int argc, const char* const argv[])
-{
-    JNIEnv* env;
-    jclass clazz;
     jmethodID methodId;
 
     LOGD("Calling main entry %s", className);
 
     env = getJNIEnv();
-    if (env == NULL)
-        return UNKNOWN_ERROR;
-
-    clazz = findClass(env, className);
-    if (clazz == NULL) {
-        LOGE("ERROR: could not find class '%s'\n", className);
+    if (clazz == NULL || env == NULL) {
         return UNKNOWN_ERROR;
     }
 
@@ -352,70 +316,6 @@
 }
 
 /*
- * Find the named class.
- */
-jclass AndroidRuntime::findClass(JNIEnv* env, const char* className)
-{
-    if (env->ExceptionCheck()) {
-        LOGE("ERROR: exception pending on entry to findClass()");
-        return NULL;
-    }
-
-    /*
-     * This is a little awkward because the JNI FindClass call uses the
-     * class loader associated with the native method we're executing in.
-     * Because this native method is part of a "boot" class, JNI doesn't
-     * look for the class in CLASSPATH, which unfortunately is a likely
-     * location for it.  (Had we issued the FindClass call before calling
-     * into the VM -- at which point there isn't a native method frame on
-     * the stack -- the VM would have checked CLASSPATH.  We have to do
-     * this because we call into Java Programming Language code and
-     * bounce back out.)
-     *
-     * JNI lacks a "find class in a specific class loader" operation, so we
-     * have to do things the hard way.
-     */
-    jclass cls = NULL;
-
-    jclass javaLangClassLoader;
-    jmethodID getSystemClassLoader, loadClass;
-    jobject systemClassLoader;
-    jstring strClassName;
-
-    /* find the "system" class loader; none of this is expected to fail */
-    javaLangClassLoader = env->FindClass("java/lang/ClassLoader");
-    assert(javaLangClassLoader != NULL);
-    getSystemClassLoader = env->GetStaticMethodID(javaLangClassLoader,
-        "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
-    loadClass = env->GetMethodID(javaLangClassLoader,
-        "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
-    assert(getSystemClassLoader != NULL && loadClass != NULL);
-    systemClassLoader = env->CallStaticObjectMethod(javaLangClassLoader,
-        getSystemClassLoader);
-    assert(systemClassLoader != NULL);
-
-    /* create an object for the class name string; alloc could fail */
-    strClassName = env->NewStringUTF(className);
-    if (env->ExceptionCheck()) {
-        LOGE("ERROR: unable to convert '%s' to string", className);
-        return NULL;
-    }
-    LOGV("system class loader is %p, loading %p (%s)",
-        systemClassLoader, strClassName, className);
-
-    /* try to find the named class */
-    cls = (jclass) env->CallObjectMethod(systemClassLoader, loadClass,
-                        strClassName);
-    if (env->ExceptionCheck()) {
-        LOGE("ERROR: unable to load class '%s' from %p",
-            className, systemClassLoader);
-        return NULL;
-    }
-
-    return cls;
-}
-
-/*
  * The VM calls this through the "exit" hook.
  */
 static void runtime_exit(int code)
@@ -457,7 +357,7 @@
 int AndroidRuntime::addVmArguments(int argc, const char* const argv[])
 {
     int i;
-    
+
     for (i = 0; i<argc; i++) {
         if (argv[i][0] != '-') {
             return i;
@@ -890,6 +790,17 @@
     return result;
 }
 
+char* AndroidRuntime::toSlashClassName(const char* className)
+{
+    char* result = strdup(className);
+    for (char* cp = result; *cp != '\0'; cp++) {
+        if (*cp == '.') {
+            *cp = '/';
+        }
+    }
+    return result;
+}
+
 /*
  * Start the Android runtime.  This involves starting the virtual machine
  * and calling the "static void main(String[] args)" method in the class
@@ -900,20 +811,16 @@
     LOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",
             className != NULL ? className : "(unknown)");
 
-    char* slashClassName = NULL;
-    char* cp;
-    JNIEnv* env;
-
     blockSigpipe();
 
-    /* 
-     * 'startSystemServer == true' means runtime is obsolete and not run from 
+    /*
+     * 'startSystemServer == true' means runtime is obsolete and not run from
      * init.rc anymore, so we print out the boot start event here.
      */
     if (startSystemServer) {
         /* track our progress through the boot sequence */
         const int LOG_BOOT_PROGRESS_START = 3000;
-        LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, 
+        LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
                        ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
     }
 
@@ -922,7 +829,7 @@
         rootDir = "/system";
         if (!hasDir("/system")) {
             LOG_FATAL("No root directory specified, and /android does not exist.");
-            goto bail;
+            return;
         }
         setenv("ANDROID_ROOT", rootDir, 1);
     }
@@ -931,15 +838,18 @@
     //LOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
 
     /* start the virtual machine */
-    if (startVm(&mJavaVM, &env) != 0)
-        goto bail;
+    JNIEnv* env;
+    if (startVm(&mJavaVM, &env) != 0) {
+        return;
+    }
+    onVmCreated(env);
 
     /*
      * Register android functions.
      */
     if (startReg(env) < 0) {
         LOGE("Unable to register all android natives\n");
-        goto bail;
+        return;
     }
 
     /*
@@ -959,7 +869,7 @@
     classNameStr = env->NewStringUTF(className);
     assert(classNameStr != NULL);
     env->SetObjectArrayElement(strArray, 0, classNameStr);
-    startSystemServerStr = env->NewStringUTF(startSystemServer ? 
+    startSystemServerStr = env->NewStringUTF(startSystemServer ?
                                                  "true" : "false");
     env->SetObjectArrayElement(strArray, 1, startSystemServerStr);
 
@@ -967,20 +877,13 @@
      * Start VM.  This thread becomes the main thread of the VM, and will
      * not return until the VM exits.
      */
-    jclass startClass;
-    jmethodID startMeth;
-
-    slashClassName = strdup(className);
-    for (cp = slashClassName; *cp != '\0'; cp++)
-        if (*cp == '.')
-            *cp = '/';
-
-    startClass = env->FindClass(slashClassName);
+    char* slashClassName = toSlashClassName(className);
+    jclass startClass = env->FindClass(slashClassName);
     if (startClass == NULL) {
         LOGE("JavaVM unable to locate class '%s'\n", slashClassName);
         /* keep going */
     } else {
-        startMeth = env->GetStaticMethodID(startClass, "main",
+        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
             "([Ljava/lang/String;)V");
         if (startMeth == NULL) {
             LOGE("JavaVM unable to find main() in '%s'\n", className);
@@ -994,15 +897,13 @@
 #endif
         }
     }
+    free(slashClassName);
 
     LOGD("Shutting down VM\n");
     if (mJavaVM->DetachCurrentThread() != JNI_OK)
         LOGW("Warning: unable to detach main thread\n");
     if (mJavaVM->DestroyJavaVM() != 0)
         LOGW("Warning: VM did not shut down cleanly\n");
-
-bail:
-    free(slashClassName);
 }
 
 void AndroidRuntime::start()
@@ -1017,6 +918,11 @@
     exit(code);
 }
 
+void AndroidRuntime::onVmCreated(JNIEnv* env)
+{
+    // If AndroidRuntime had anything to do here, we'd have done it in 'start'.
+}
+
 /*
  * Get the JNIEnv pointer for this thread.
  *
@@ -1111,7 +1017,7 @@
  * into the VM before it really starts executing.
  */
 /*static*/ int AndroidRuntime::javaCreateThreadEtc(
-                                android_thread_func_t entryFunction, 
+                                android_thread_func_t entryFunction,
                                 void* userData,
                                 const char* threadName,
                                 int32_t threadPriority,
@@ -1299,7 +1205,7 @@
     REG_JNI(register_android_backup_BackupDataOutput),
     REG_JNI(register_android_backup_FileBackupHelperBase),
     REG_JNI(register_android_backup_BackupHelperDispatcher),
-    
+
     REG_JNI(register_android_app_ActivityThread),
     REG_JNI(register_android_app_NativeActivity),
     REG_JNI(register_android_view_InputChannel),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 05a46a8..1b22e2d 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -655,7 +655,6 @@
 

 #define kClassPathName  "android/graphics/Bitmap"

 

-int register_android_graphics_Bitmap(JNIEnv* env);

 int register_android_graphics_Bitmap(JNIEnv* env)

 {

     return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,

diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 1034fbd..258ffa5 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -12,6 +12,7 @@
 #include "CreateJavaOutputStreamAdaptor.h"
 #include "AutoDecodeCancel.h"
 #include "Utils.h"
+#include "JNIHelp.h"
 
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/Asset.h>
@@ -20,7 +21,6 @@
 #include <sys/mman.h>
 #include <sys/stat.h>
 
-jclass gOptions_class;
 jfieldID gOptions_justBoundsFieldID;
 jfieldID gOptions_sampleSizeFieldID;
 jfieldID gOptions_configFieldID;
@@ -34,12 +34,8 @@
 jfieldID gOptions_mimeFieldID;
 jfieldID gOptions_mCancelID;
 jfieldID gOptions_bitmapFieldID;
-jclass gBitmap_class;
 jfieldID gBitmap_nativeBitmapFieldID;
 
-static jclass gFileDescriptor_class;
-static jfieldID gFileDescriptor_descriptor;
-
 #if 0
     #define TRACE_BITMAP(code)  code
 #else
@@ -66,7 +62,7 @@
         { SkImageDecoder::kPNG_Format,  "image/png" },
         { SkImageDecoder::kWBMP_Format, "image/vnd.wap.wbmp" }
     };
-    
+
     const char* cstr = NULL;
     for (size_t i = 0; i < SK_ARRAY_COUNT(gMimeTypes); i++) {
         if (gMimeTypes[i].fFormat == format) {
@@ -127,7 +123,7 @@
                         (allowPurgeable && optionsPurgeable(env, options));
     bool preferQualityOverSpeed = false;
     jobject javaBitmap = NULL;
-    
+
     if (NULL != options) {
         sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
         if (optionsJustBounds(env, options)) {
@@ -137,7 +133,7 @@
         env->SetIntField(options, gOptions_widthFieldID, -1);
         env->SetIntField(options, gOptions_heightFieldID, -1);
         env->SetObjectField(options, gOptions_mimeFieldID, 0);
-        
+
         jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
         prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig);
         isMutable = env->GetBooleanField(options, gOptions_mutableFieldID);
@@ -151,7 +147,7 @@
     if (NULL == decoder) {
         return nullObjectReturn("SkImageDecoder::Factory returned null");
     }
-    
+
     decoder->setSampleSize(sampleSize);
     decoder->setDitherImage(doDither);
     decoder->setPreferQualityOverSpeed(preferQualityOverSpeed);
@@ -298,8 +294,7 @@
                                           jobject bitmapFactoryOptions) {
     NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
 
-    jint descriptor = env->GetIntField(fileDescriptor,
-                                       gFileDescriptor_descriptor);
+    jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
     bool isPurgeable = optionsPurgeable(env, bitmapFactoryOptions);
     bool isShareable = optionsShareable(env, bitmapFactoryOptions);
@@ -424,7 +419,7 @@
         }
 
         for (int i = 0; i < chunk->numYDivs; i++) {
-            chunk->yDivs[i] = int(chunk->yDivs[i] * scale + 0.5f);            
+            chunk->yDivs[i] = int(chunk->yDivs[i] * scale + 0.5f);
             if (i > 0 && chunk->yDivs[i] == chunk->yDivs[i - 1]) {
                 chunk->yDivs[i]++;
             }
@@ -460,7 +455,7 @@
 }
 
 static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) {
-    jint descriptor = env->GetIntField(fileDescriptor, gFileDescriptor_descriptor);
+    jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
     return ::lseek64(descriptor, 0, SEEK_CUR) != -1 ? JNI_TRUE : JNI_FALSE;
 }
 
@@ -504,12 +499,6 @@
     {   "requestCancel", "()V", (void*)nativeRequestCancel }
 };
 
-static jclass make_globalref(JNIEnv* env, const char classname[]) {
-    jclass c = env->FindClass(classname);
-    SkASSERT(c);
-    return (jclass)env->NewGlobalRef(c);
-}
-
 static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
                                 const char fieldname[], const char type[]) {
     jfieldID id = env->GetFieldID(clazz, fieldname, type);
@@ -517,35 +506,29 @@
     return id;
 }
 
-#define kClassPathName  "android/graphics/BitmapFactory"
-
-#define RETURN_ERR_IF_NULL(value) \
-    do { if (!(value)) { assert(0); return -1; } } while (false)
-
-int register_android_graphics_BitmapFactory(JNIEnv* env);
 int register_android_graphics_BitmapFactory(JNIEnv* env) {
-    gOptions_class = make_globalref(env, "android/graphics/BitmapFactory$Options");
-    gOptions_bitmapFieldID = getFieldIDCheck(env, gOptions_class, "inBitmap",
+    jclass options_class = env->FindClass("android/graphics/BitmapFactory$Options");
+    SkASSERT(options_class);
+    gOptions_bitmapFieldID = getFieldIDCheck(env, options_class, "inBitmap",
         "Landroid/graphics/Bitmap;");
-    gOptions_justBoundsFieldID = getFieldIDCheck(env, gOptions_class, "inJustDecodeBounds", "Z");
-    gOptions_sampleSizeFieldID = getFieldIDCheck(env, gOptions_class, "inSampleSize", "I");
-    gOptions_configFieldID = getFieldIDCheck(env, gOptions_class, "inPreferredConfig",
+    gOptions_justBoundsFieldID = getFieldIDCheck(env, options_class, "inJustDecodeBounds", "Z");
+    gOptions_sampleSizeFieldID = getFieldIDCheck(env, options_class, "inSampleSize", "I");
+    gOptions_configFieldID = getFieldIDCheck(env, options_class, "inPreferredConfig",
             "Landroid/graphics/Bitmap$Config;");
-    gOptions_mutableFieldID = getFieldIDCheck(env, gOptions_class, "inMutable", "Z");
-    gOptions_ditherFieldID = getFieldIDCheck(env, gOptions_class, "inDither", "Z");
-    gOptions_purgeableFieldID = getFieldIDCheck(env, gOptions_class, "inPurgeable", "Z");
-    gOptions_shareableFieldID = getFieldIDCheck(env, gOptions_class, "inInputShareable", "Z");
-    gOptions_preferQualityOverSpeedFieldID = getFieldIDCheck(env, gOptions_class,
+    gOptions_mutableFieldID = getFieldIDCheck(env, options_class, "inMutable", "Z");
+    gOptions_ditherFieldID = getFieldIDCheck(env, options_class, "inDither", "Z");
+    gOptions_purgeableFieldID = getFieldIDCheck(env, options_class, "inPurgeable", "Z");
+    gOptions_shareableFieldID = getFieldIDCheck(env, options_class, "inInputShareable", "Z");
+    gOptions_preferQualityOverSpeedFieldID = getFieldIDCheck(env, options_class,
             "inPreferQualityOverSpeed", "Z");
-    gOptions_widthFieldID = getFieldIDCheck(env, gOptions_class, "outWidth", "I");
-    gOptions_heightFieldID = getFieldIDCheck(env, gOptions_class, "outHeight", "I");
-    gOptions_mimeFieldID = getFieldIDCheck(env, gOptions_class, "outMimeType", "Ljava/lang/String;");
-    gOptions_mCancelID = getFieldIDCheck(env, gOptions_class, "mCancel", "Z");
+    gOptions_widthFieldID = getFieldIDCheck(env, options_class, "outWidth", "I");
+    gOptions_heightFieldID = getFieldIDCheck(env, options_class, "outHeight", "I");
+    gOptions_mimeFieldID = getFieldIDCheck(env, options_class, "outMimeType", "Ljava/lang/String;");
+    gOptions_mCancelID = getFieldIDCheck(env, options_class, "mCancel", "Z");
 
-    gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
-    gBitmap_nativeBitmapFieldID = getFieldIDCheck(env, gBitmap_class, "mNativeBitmap", "I");
-    gFileDescriptor_class = make_globalref(env, "java/io/FileDescriptor");
-    gFileDescriptor_descriptor = getFieldIDCheck(env, gFileDescriptor_class, "descriptor", "I");
+    jclass bitmap_class = env->FindClass("android/graphics/Bitmap");
+    SkASSERT(bitmap_class);
+    gBitmap_nativeBitmapFieldID = getFieldIDCheck(env, bitmap_class, "mNativeBitmap", "I");
 
     int ret = AndroidRuntime::registerNativeMethods(env,
                                     "android/graphics/BitmapFactory$Options",
@@ -554,6 +537,6 @@
     if (ret) {
         return ret;
     }
-    return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
+    return android::AndroidRuntime::registerNativeMethods(env, "android/graphics/BitmapFactory",
                                          gMethods, SK_ARRAY_COUNT(gMethods));
 }
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index ee3e209..d437929 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -28,6 +28,7 @@
 #include "SkBitmapRegionDecoder.h"
 #include "CreateJavaOutputStreamAdaptor.h"
 #include "Utils.h"
+#include "JNIHelp.h"
 
 #include <android_runtime/AndroidRuntime.h>
 #include "android_util_Binder.h"
@@ -39,9 +40,6 @@
 #include <utils/Asset.h>
 #include <sys/stat.h>
 
-static jclass gFileDescriptor_class;
-static jfieldID gFileDescriptor_descriptor;
-
 #if 0
     #define TRACE_BITMAP(code)  code
 #else
@@ -111,8 +109,7 @@
                                           jobject fileDescriptor, jboolean isShareable) {
     NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
 
-    jint descriptor = env->GetIntField(fileDescriptor,
-                                       gFileDescriptor_descriptor);
+    jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
     SkStream *stream = NULL;
     struct stat fdStat;
     int newFD;
@@ -300,25 +297,8 @@
 
 #define kClassPathName  "android/graphics/BitmapRegionDecoder"
 
-static jclass make_globalref(JNIEnv* env, const char classname[]) {
-    jclass c = env->FindClass(classname);
-    SkASSERT(c);
-    return (jclass)env->NewGlobalRef(c);
-}
-
-static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
-                                const char fieldname[], const char type[]) {
-    jfieldID id = env->GetFieldID(clazz, fieldname, type);
-    SkASSERT(id);
-    return id;
-}
-
-int register_android_graphics_BitmapRegionDecoder(JNIEnv* env);
 int register_android_graphics_BitmapRegionDecoder(JNIEnv* env)
 {
-
-    gFileDescriptor_class = make_globalref(env, "java/io/FileDescriptor");
-    gFileDescriptor_descriptor = getFieldIDCheck(env, gFileDescriptor_class, "descriptor", "I");
     return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
             gBitmapRegionDecoderMethods, SK_ARRAY_COUNT(gBitmapRegionDecoderMethods));
 }
diff --git a/core/jni/android/graphics/Camera.cpp b/core/jni/android/graphics/Camera.cpp
index 0d715fd..76d415a 100644
--- a/core/jni/android/graphics/Camera.cpp
+++ b/core/jni/android/graphics/Camera.cpp
@@ -98,7 +98,6 @@
     { "dotWithNormal",       "(FFF)F", (void*)Camera_dotWithNormal }
 };
 
-int register_android_graphics_Camera(JNIEnv* env);
 int register_android_graphics_Camera(JNIEnv* env) {
     jclass clazz = env->FindClass("android/graphics/Camera");
     if (clazz == 0) {
@@ -113,4 +112,3 @@
                                                gCameraMethods,
                                                SK_ARRAY_COUNT(gCameraMethods));
 }
-
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index 137acc6..6ce3f51 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -3,7 +3,6 @@
 #define RETURN_NULL_IF_NULL(value) \
     do { if (!(value)) { SkASSERT(0); return NULL; } } while (false)
 
-static jclass       gInputStream_Clazz;
 static jmethodID    gInputStream_resetMethodID;
 static jmethodID    gInputStream_markMethodID;
 static jmethodID    gInputStream_availableMethodID;
@@ -19,10 +18,10 @@
         SkASSERT(fCapacity > 0);
         fBytesRead  = 0;
     }
-    
+
 	virtual bool rewind() {
         JNIEnv* env = fEnv;
-        
+
         fBytesRead = 0;
 
         env->CallVoidMethod(fJavaInputStream, gInputStream_resetMethodID);
@@ -34,7 +33,7 @@
         }
         return true;
     }
-    
+
     size_t doRead(void* buffer, size_t size) {
         JNIEnv* env = fEnv;
         size_t bytesRead = 0;
@@ -43,7 +42,7 @@
             size_t requested = size;
             if (requested > fCapacity)
                 requested = fCapacity;
-            
+
             jint n = env->CallIntMethod(fJavaInputStream,
                                         gInputStream_readMethodID, fJavaByteArray, 0, requested);
             if (env->ExceptionCheck()) {
@@ -52,11 +51,11 @@
                 SkDebugf("---- read threw an exception\n");
                 return 0;
             }
-            
+
             if (n < 0) { // n == 0 should not be possible, see InputStream read() specifications.
                 break;  // eof
             }
-            
+
             env->GetByteArrayRegion(fJavaByteArray, 0, n,
                                     reinterpret_cast<jbyte*>(buffer));
             if (env->ExceptionCheck()) {
@@ -65,16 +64,16 @@
                 SkDebugf("---- read:GetByteArrayRegion threw an exception\n");
                 return 0;
             }
-            
+
             buffer = (void*)((char*)buffer + n);
             bytesRead += n;
             size -= n;
             fBytesRead += n;
         } while (size != 0);
-        
+
         return bytesRead;
     }
-    
+
     size_t doSkip(size_t size) {
         JNIEnv* env = fEnv;
 
@@ -92,7 +91,7 @@
 
         return (size_t)skipped;
     }
-    
+
     size_t doSize() {
         JNIEnv* env = fEnv;
         jint avail = env->CallIntMethod(fJavaInputStream,
@@ -105,7 +104,7 @@
         }
         return avail;
     }
-    
+
 	virtual size_t read(void* buffer, size_t size) {
         JNIEnv* env = fEnv;
         if (NULL == buffer) {
@@ -134,7 +133,7 @@
         }
         return this->doRead(buffer, size);
     }
-    
+
 private:
     JNIEnv*     fEnv;
     jobject     fJavaInputStream;   // the caller owns this object
@@ -148,19 +147,18 @@
     static bool gInited;
 
     if (!gInited) {
-        gInputStream_Clazz = env->FindClass("java/io/InputStream");
-        RETURN_NULL_IF_NULL(gInputStream_Clazz);
-        gInputStream_Clazz = (jclass)env->NewGlobalRef(gInputStream_Clazz);
+        jclass inputStream_Clazz = env->FindClass("java/io/InputStream");
+        RETURN_NULL_IF_NULL(inputStream_Clazz);
 
-        gInputStream_resetMethodID      = env->GetMethodID(gInputStream_Clazz,
+        gInputStream_resetMethodID      = env->GetMethodID(inputStream_Clazz,
                                                            "reset", "()V");
-        gInputStream_markMethodID       = env->GetMethodID(gInputStream_Clazz,
+        gInputStream_markMethodID       = env->GetMethodID(inputStream_Clazz,
                                                            "mark", "(I)V");
-        gInputStream_availableMethodID  = env->GetMethodID(gInputStream_Clazz,
+        gInputStream_availableMethodID  = env->GetMethodID(inputStream_Clazz,
                                                            "available", "()I");
-        gInputStream_readMethodID       = env->GetMethodID(gInputStream_Clazz,
+        gInputStream_readMethodID       = env->GetMethodID(inputStream_Clazz,
                                                            "read", "([BII)I");
-        gInputStream_skipMethodID       = env->GetMethodID(gInputStream_Clazz,
+        gInputStream_skipMethodID       = env->GetMethodID(inputStream_Clazz,
                                                            "skip", "(J)J");
 
         RETURN_NULL_IF_NULL(gInputStream_resetMethodID);
@@ -181,7 +179,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static jclass       gOutputStream_Clazz;
 static jmethodID    gOutputStream_writeMethodID;
 static jmethodID    gOutputStream_flushMethodID;
 
@@ -191,11 +188,11 @@
         : fEnv(env), fJavaOutputStream(stream), fJavaByteArray(storage) {
         fCapacity = env->GetArrayLength(storage);
     }
-    
+
 	virtual bool write(const void* buffer, size_t size) {
         JNIEnv* env = fEnv;
         jbyteArray storage = fJavaByteArray;
-        
+
         while (size > 0) {
             size_t requested = size;
             if (requested > fCapacity) {
@@ -210,7 +207,7 @@
                 SkDebugf("--- write:SetByteArrayElements threw an exception\n");
                 return false;
             }
-            
+
             fEnv->CallVoidMethod(fJavaOutputStream, gOutputStream_writeMethodID,
                                  storage, 0, requested);
             if (env->ExceptionCheck()) {
@@ -219,17 +216,17 @@
                 SkDebugf("------- write threw an exception\n");
                 return false;
             }
-            
+
             buffer = (void*)((char*)buffer + requested);
             size -= requested;
         }
         return true;
     }
-    
+
     virtual void flush() {
         fEnv->CallVoidMethod(fJavaOutputStream, gOutputStream_flushMethodID);
     }
-    
+
 private:
     JNIEnv*     fEnv;
     jobject     fJavaOutputStream;  // the caller owns this object
@@ -242,14 +239,13 @@
     static bool gInited;
 
     if (!gInited) {
-        gOutputStream_Clazz = env->FindClass("java/io/OutputStream");
-        RETURN_NULL_IF_NULL(gOutputStream_Clazz);
-        gOutputStream_Clazz = (jclass)env->NewGlobalRef(gOutputStream_Clazz);
+        jclass outputStream_Clazz = env->FindClass("java/io/OutputStream");
+        RETURN_NULL_IF_NULL(outputStream_Clazz);
 
-        gOutputStream_writeMethodID = env->GetMethodID(gOutputStream_Clazz,
+        gOutputStream_writeMethodID = env->GetMethodID(outputStream_Clazz,
                                                        "write", "([BII)V");
         RETURN_NULL_IF_NULL(gOutputStream_writeMethodID);
-        gOutputStream_flushMethodID = env->GetMethodID(gOutputStream_Clazz,
+        gOutputStream_flushMethodID = env->GetMethodID(outputStream_Clazz,
                                                        "flush", "()V");
         RETURN_NULL_IF_NULL(gOutputStream_flushMethodID);
 
@@ -258,4 +254,3 @@
 
     return new SkJavaOutputStream(env, stream, storage);
 }
-
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 6c28e65..64bd207 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -350,14 +350,10 @@
     SkASSERT(bitmap);
     SkASSERT(bitmap->pixelRef());
 
-    jobject obj = env->AllocObject(gBitmap_class);
-    if (obj) {
-        env->CallVoidMethod(obj, gBitmap_constructorMethodID,
-                            (jint)bitmap, buffer, isMutable, ninepatch, density);
-        if (hasException(env)) {
-            obj = NULL;
-        }
-    }
+    jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
+            static_cast<jint>(reinterpret_cast<uintptr_t>(bitmap)),
+            buffer, isMutable, ninepatch, density);
+    hasException(env); // For the side effect of logging.
     return obj;
 }
 
@@ -372,30 +368,19 @@
 {
     SkASSERT(bitmap != NULL);
 
-    jobject obj = env->AllocObject(gBitmapRegionDecoder_class);
-    if (hasException(env)) {
-        obj = NULL;
-        return obj;
-    }
-    if (obj) {
-        env->CallVoidMethod(obj, gBitmapRegionDecoder_constructorMethodID, (jint)bitmap);
-        if (hasException(env)) {
-            obj = NULL;
-        }
-    }
+    jobject obj = env->NewObject(gBitmapRegionDecoder_class,
+            gBitmapRegionDecoder_constructorMethodID,
+            static_cast<jint>(reinterpret_cast<uintptr_t>(bitmap)));
+    hasException(env); // For the side effect of logging.
     return obj;
 }
 
 jobject GraphicsJNI::createRegion(JNIEnv* env, SkRegion* region)
 {
     SkASSERT(region != NULL);
-    jobject obj = env->AllocObject(gRegion_class);
-    if (obj) {
-        env->CallVoidMethod(obj, gRegion_constructorMethodID, (jint)region, 0);
-        if (hasException(env)) {
-            obj = NULL;
-        }
-    }
+    jobject obj = env->NewObject(gRegion_class, gRegion_constructorMethodID,
+            static_cast<jint>(reinterpret_cast<uintptr_t>(region)), 0);
+    hasException(env); // For the side effect of logging.
     return obj;
 }
 
diff --git a/core/jni/android/graphics/Interpolator.cpp b/core/jni/android/graphics/Interpolator.cpp
index beec351..aa33c3d 100644
--- a/core/jni/android/graphics/Interpolator.cpp
+++ b/core/jni/android/graphics/Interpolator.cpp
@@ -61,7 +61,7 @@
 
     float* values = valueArray ? env->GetFloatArrayElements(valueArray, NULL) : NULL;
     result = interp->timeToValues(msec, (SkScalar*)values);
-    
+
     if (valueArray) {
         int n = env->GetArrayLength(valueArray);
         for (int i = 0; i < n; i++) {
@@ -69,7 +69,7 @@
         }
         env->ReleaseFloatArrayElements(valueArray, values, 0);
     }
-    
+
     return result;
 }
 
@@ -87,7 +87,6 @@
     { "nativeTimeToValues",     "(II[F)I",      (void*)Interpolator_timeToValues    }
 };
 
-int register_android_graphics_Interpolator(JNIEnv* env);
 int register_android_graphics_Interpolator(JNIEnv* env)
 {
     return android::AndroidRuntime::registerNativeMethods(env,
diff --git a/core/jni/android/graphics/LayerRasterizer.cpp b/core/jni/android/graphics/LayerRasterizer.cpp
index 7c458899..e5bc6f8 100644
--- a/core/jni/android/graphics/LayerRasterizer.cpp
+++ b/core/jni/android/graphics/LayerRasterizer.cpp
@@ -11,7 +11,7 @@
         SkASSERT(layer);
         SkASSERT(paint);
         layer->addLayer(*paint, SkFloatToScalar(dx), SkFloatToScalar(dy));
-    } 
+    }
 };
 
 /////////////////////////////////////////////////////////////////////////////////////////
@@ -23,7 +23,6 @@
     { "nativeAddLayer",     "(IIFF)V",  (void*)SkLayerRasterizerGlue::addLayer  }
 };
 
-int register_android_graphics_LayerRasterizer(JNIEnv* env);
 int register_android_graphics_LayerRasterizer(JNIEnv* env)
 {
     return android::AndroidRuntime::registerNativeMethods(env,
@@ -31,4 +30,3 @@
                                                        gLayerRasterizerMethods,
                                                        SK_ARRAY_COUNT(gLayerRasterizerMethods));
 }
-
diff --git a/core/jni/android/graphics/MaskFilter.cpp b/core/jni/android/graphics/MaskFilter.cpp
index d3f9b78..d954ddf 100644
--- a/core/jni/android/graphics/MaskFilter.cpp
+++ b/core/jni/android/graphics/MaskFilter.cpp
@@ -23,7 +23,7 @@
         ThrowIAE_IfNull(env, filter);
         return filter;
     }
- 
+
     static SkMaskFilter* createEmboss(JNIEnv* env, jobject, jfloatArray dirArray, float ambient, float specular, float radius) {
         SkScalar direction[3];
 
@@ -79,16 +79,14 @@
     result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array));  \
     if (result < 0) return result
 
-int register_android_graphics_MaskFilter(JNIEnv* env);
 int register_android_graphics_MaskFilter(JNIEnv* env)
 {
     int result;
-    
+
     REG(env, "android/graphics/MaskFilter", gMaskFilterMethods);
     REG(env, "android/graphics/BlurMaskFilter", gBlurMaskFilterMethods);
     REG(env, "android/graphics/EmbossMaskFilter", gEmbossMaskFilterMethods);
     REG(env, "android/graphics/TableMaskFilter", gTableMaskFilterMethods);
-    
+
     return 0;
 }
-
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index 7145433..c112423 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -23,11 +23,8 @@
     if (NULL == moov) {
         return NULL;
     }
-    jobject obj = env->AllocObject(gMovie_class);
-    if (obj) {
-        env->CallVoidMethod(obj, gMovie_constructorMethodID, (jint)moov);
-    }
-    return obj;
+    return env->NewObject(gMovie_class, gMovie_constructorMethodID,
+            static_cast<jint>(reinterpret_cast<uintptr_t>(moov)));
 }
 
 static SkMovie* J2Movie(JNIEnv* env, jobject movie) {
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index f9a3518..0c8a8a3 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -182,7 +182,6 @@
                                                         (void*)SkNinePatchGlue::getTransparentRegion   }
 };
 
-int register_android_graphics_NinePatch(JNIEnv* env);
 int register_android_graphics_NinePatch(JNIEnv* env)
 {
     return android::AndroidRuntime::registerNativeMethods(env,
diff --git a/core/jni/android/graphics/PathEffect.cpp b/core/jni/android/graphics/PathEffect.cpp
index cfa9ce4..0503614 100644
--- a/core/jni/android/graphics/PathEffect.cpp
+++ b/core/jni/android/graphics/PathEffect.cpp
@@ -19,12 +19,12 @@
                                    SkPathEffect* outer, SkPathEffect* inner) {
         return new SkComposePathEffect(outer, inner);
     }
-    
+
     static SkPathEffect* Sum_constructor(JNIEnv* env, jobject,
                                   SkPathEffect* first, SkPathEffect* second) {
         return new SkSumPathEffect(first, second);
     }
-    
+
     static SkPathEffect* Dash_constructor(JNIEnv* env, jobject,
                                       jfloatArray intervalArray, float phase) {
         AutoJavaFloatArray autoInterval(env, intervalArray);
@@ -32,30 +32,30 @@
         float*  values = autoInterval.ptr();
 
         SkAutoSTMalloc<32, SkScalar>    storage(count);
-        SkScalar*                       intervals = storage.get();        
+        SkScalar*                       intervals = storage.get();
         for (int i = 0; i < count; i++) {
             intervals[i] = SkFloatToScalar(values[i]);
         }
         return new SkDashPathEffect(intervals, count, SkFloatToScalar(phase));
     }
- 
+
     static SkPathEffect* OneD_constructor(JNIEnv* env, jobject,
                   const SkPath* shape, float advance, float phase, int style) {
         SkASSERT(shape != NULL);
         return new SkPath1DPathEffect(*shape, SkFloatToScalar(advance),
                      SkFloatToScalar(phase), (SkPath1DPathEffect::Style)style);
     }
-    
+
     static SkPathEffect* Corner_constructor(JNIEnv* env, jobject, float radius){
         return new SkCornerPathEffect(SkFloatToScalar(radius));
     }
-    
+
     static SkPathEffect* Discrete_constructor(JNIEnv* env, jobject,
                                               float length, float deviation) {
         return new SkDiscretePathEffect(SkFloatToScalar(length),
                                         SkFloatToScalar(deviation));
     }
-    
+
 };
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -95,11 +95,10 @@
                                                   SK_ARRAY_COUNT(array));  \
     if (result < 0) return result
 
-int register_android_graphics_PathEffect(JNIEnv* env);
 int register_android_graphics_PathEffect(JNIEnv* env)
 {
     int result;
-    
+
     REG(env, "android/graphics/PathEffect", gPathEffectMethods);
     REG(env, "android/graphics/ComposePathEffect", gComposePathEffectMethods);
     REG(env, "android/graphics/SumPathEffect", gSumPathEffectMethods);
@@ -107,7 +106,6 @@
     REG(env, "android/graphics/PathDashPathEffect", gPathDashPathEffectMethods);
     REG(env, "android/graphics/CornerPathEffect", gCornerPathEffectMethods);
     REG(env, "android/graphics/DiscretePathEffect", gDiscretePathEffectMethods);
-    
+
     return 0;
 }
-
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index 2445229..5c6ebdf 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -69,7 +69,7 @@
 
 static jboolean Region_op0(JNIEnv* env, jobject, SkRegion* dst, int left, int top, int right, int bottom, int op) {
     SkIRect ir;
-    
+
     ir.set(left, top, right, bottom);
     return dst->op(ir, (SkRegion::Op)op);
 }
@@ -84,16 +84,16 @@
     return dst->op(*region1, *region2, (SkRegion::Op)op);
 }
 
-////////////////////////////////////  These are methods, not static 
+////////////////////////////////////  These are methods, not static
 
 static jboolean Region_isEmpty(JNIEnv* env, jobject region) {
     return GetSkRegion(env, region)->isEmpty();
 }
- 
+
 static jboolean Region_isRect(JNIEnv* env, jobject region) {
     return GetSkRegion(env, region)->isRect();
 }
- 
+
 static jboolean Region_isComplex(JNIEnv* env, jobject region) {
     return GetSkRegion(env, region)->isComplex();
 }
@@ -101,21 +101,21 @@
 static jboolean Region_contains(JNIEnv* env, jobject region, int x, int y) {
     return GetSkRegion(env, region)->contains(x, y);
 }
- 
+
 static jboolean Region_quickContains(JNIEnv* env, jobject region, int left, int top, int right, int bottom) {
     return GetSkRegion(env, region)->quickContains(left, top, right, bottom);
 }
- 
+
 static jboolean Region_quickRejectIIII(JNIEnv* env, jobject region, int left, int top, int right, int bottom) {
     SkIRect ir;
     ir.set(left, top, right, bottom);
     return GetSkRegion(env, region)->quickReject(ir);
 }
- 
+
 static jboolean Region_quickRejectRgn(JNIEnv* env, jobject region, jobject other) {
     return GetSkRegion(env, region)->quickReject(*GetSkRegion(env, other));
 }
- 
+
 static void Region_translate(JNIEnv* env, jobject region, int x, int y, jobject dst) {
     SkRegion* rgn = GetSkRegion(env, region);
     if (dst)
@@ -171,13 +171,13 @@
     if (parcel == NULL) {
         return NULL;
     }
-    
+
     android::Parcel* p = android::parcelForJavaObject(env, parcel);
-    
+
     SkRegion* region = new SkRegion;
     size_t size = p->readInt32();
     region->unflatten(p->readInplace(size));
-    
+
     return region;
 }
 
@@ -186,7 +186,7 @@
     if (parcel == NULL) {
         return false;
     }
-    
+
     android::Parcel* p = android::parcelForJavaObject(env, parcel);
 
     size_t size = region->flatten(NULL);
@@ -208,7 +208,7 @@
 struct RgnIterPair {
     SkRegion            fRgn;   // a copy of the caller's region
     SkRegion::Iterator  fIter;  // an iterator acting upon the copy (fRgn)
-    
+
     RgnIterPair(const SkRegion& rgn) : fRgn(rgn) {
         // have our iterator reference our copy (fRgn), so we know it will be
         // unchanged for the lifetime of the iterator
@@ -218,7 +218,7 @@
 
 static RgnIterPair* RegionIter_constructor(JNIEnv* env, jobject, const SkRegion* region)
 {
-    SkASSERT(region);    
+    SkASSERT(region);
     return new RgnIterPair(*region);
 }
 
@@ -279,12 +279,11 @@
     { "nativeEquals",           "(II)Z",                            (void*)Region_equals            },
 };
 
-int register_android_graphics_Region(JNIEnv* env);
 int register_android_graphics_Region(JNIEnv* env)
 {
     jclass clazz = env->FindClass("android/graphics/Region");
     SkASSERT(clazz);
-    
+
     gRegion_nativeInstanceFieldID = env->GetFieldID(clazz, "mNativeRegion", "I");
     SkASSERT(gRegion_nativeInstanceFieldID);
 
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 7fdad10..f4cc9e4 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -35,7 +35,7 @@
         values[i] = SkScalarToFloat(hsv[i]);
     }
 }
- 
+
 static int Color_HSVToColor(JNIEnv* env, jobject, int alpha, jfloatArray hsvArray)
 {
     AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
@@ -45,7 +45,7 @@
     for (int i = 0; i < 3; i++) {
         hsv[i] = SkFloatToScalar(values[i]);
     }
-    
+
     return SkHSVToColor(alpha, hsv);
 }
 
@@ -104,7 +104,7 @@
     return NULL;
 #endif
 }
-    
+
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
 static SkShader* LinearGradient_create1(JNIEnv* env, jobject o,
@@ -129,7 +129,7 @@
             pos[i] = SkFloatToScalar(posValues[i]);
         }
     }
-    
+
     SkShader* shader = SkGradientShader::CreateLinear(pts,
                                 reinterpret_cast<const SkColor*>(colorValues),
                                 pos, count,
@@ -218,7 +218,7 @@
     SkColor colors[2];
     colors[0] = color0;
     colors[1] = color1;
-    
+
     SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
 
     ThrowIAE_IfNull(env, s);
@@ -237,7 +237,7 @@
 
     SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0);
     SkScalar*                   pos = NULL;
-    
+
     if (posArray) {
         AutoJavaFloatArray autoPos(env, posArray, count);
         const float* posValues = autoPos.ptr();
@@ -338,10 +338,10 @@
         jintArray jcolors, jfloatArray jpositions) {
     size_t      count = env->GetArrayLength(jcolors);
     const jint* colors = env->GetIntArrayElements(jcolors, NULL);
-    
+
     SkAutoSTMalloc<8, SkScalar> storage(jpositions ? count : 0);
     SkScalar*                   pos = NULL;
-    
+
     if (NULL != jpositions) {
         AutoJavaFloatArray autoPos(env, jpositions, count);
         const float* posValues = autoPos.ptr();
@@ -520,11 +520,10 @@
     result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array));  \
     if (result < 0) return result
 
-int register_android_graphics_Shader(JNIEnv* env);
 int register_android_graphics_Shader(JNIEnv* env)
 {
     int result;
-    
+
     REG(env, "android/graphics/Color", gColorMethods);
     REG(env, "android/graphics/Shader", gShaderMethods);
     REG(env, "android/graphics/BitmapShader", gBitmapShaderMethods);
@@ -532,7 +531,6 @@
     REG(env, "android/graphics/RadialGradient", gRadialGradientMethods);
     REG(env, "android/graphics/SweepGradient", gSweepGradientMethods);
     REG(env, "android/graphics/ComposeShader", gComposeShaderMethods);
-    
+
     return result;
 }
-
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 53a5c0a..b25598a 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -44,7 +44,7 @@
 static SkTypeface* Typeface_createFromTypeface(JNIEnv* env, jobject, SkTypeface* family, int style) {
     return SkTypeface::CreateFromTypeface(family, (SkTypeface::Style)style);
 }
- 
+
 static void Typeface_unref(JNIEnv* env, jobject obj, SkTypeface* face) {
     SkSafeUnref(face);
 }
@@ -64,7 +64,7 @@
     {
         delete fAsset;
     }
-    
+
     virtual const void* getMemoryBase()
     {
         return fMemoryBase;
@@ -75,38 +75,38 @@
         off64_t pos = fAsset->seek(0, SEEK_SET);
         return pos != (off64_t)-1;
     }
-    
+
 	virtual size_t read(void* buffer, size_t size)
     {
         ssize_t amount;
-        
+
         if (NULL == buffer)
         {
             if (0 == size)  // caller is asking us for our total length
                 return fAsset->getLength();
-            
+
             // asset->seek returns new total offset
             // we want to return amount that was skipped
-            
+
             off64_t oldOffset = fAsset->seek(0, SEEK_CUR);
             if (-1 == oldOffset)
                 return 0;
             off64_t newOffset = fAsset->seek(size, SEEK_CUR);
             if (-1 == newOffset)
                 return 0;
-            
+
             amount = newOffset - oldOffset;
         }
         else
         {
             amount = fAsset->read(buffer, size);
         }
-        
+
         if (amount < 0)
             amount = 0;
         return amount;
     }
-    
+
 private:
     Asset*      fAsset;
     const void* fMemoryBase;
@@ -115,21 +115,21 @@
 static SkTypeface* Typeface_createFromAsset(JNIEnv* env, jobject,
                                             jobject jassetMgr,
                                             jstring jpath) {
-    
+
     NPE_CHECK_RETURN_ZERO(env, jassetMgr);
     NPE_CHECK_RETURN_ZERO(env, jpath);
-    
+
     AssetManager* mgr = assetManagerForJavaObject(env, jassetMgr);
     if (NULL == mgr) {
         return NULL;
     }
-    
+
     AutoJavaStringToUTF8    str(env, jpath);
     Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
     if (NULL == asset) {
         return NULL;
     }
-    
+
     SkStream* stream = new AssetStream(asset, true);
     SkTypeface* face = SkTypeface::CreateFromStream(stream);
     // SkTypeFace::CreateFromStream calls ref() on the stream, so we
@@ -180,7 +180,6 @@
     { "setGammaForText", "(FF)V", (void*)Typeface_setGammaForText },
 };
 
-int register_android_graphics_Typeface(JNIEnv* env);
 int register_android_graphics_Typeface(JNIEnv* env)
 {
     return android::AndroidRuntime::registerNativeMethods(env,
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.cpp b/core/jni/android/graphics/YuvToJpegEncoder.cpp
index 0a0c5b3..8333e00 100644
--- a/core/jni/android/graphics/YuvToJpegEncoder.cpp
+++ b/core/jni/android/graphics/YuvToJpegEncoder.cpp
@@ -242,7 +242,6 @@
 
 #define kClassPathName  "android/graphics/YuvImage"
 
-int register_android_graphics_YuvImage(JNIEnv* env);
 int register_android_graphics_YuvImage(JNIEnv* env)
 {
     return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
diff --git a/core/jni/android_backup_BackupDataInput.cpp b/core/jni/android_backup_BackupDataInput.cpp
index b03dd16..c174a41 100644
--- a/core/jni/android_backup_BackupDataInput.cpp
+++ b/core/jni/android_backup_BackupDataInput.cpp
@@ -25,9 +25,6 @@
 namespace android
 {
 
-// java.io.FileDescriptor
-static jfieldID s_descriptorField = 0;
-
 // android.app.backup.BackupDataInput$EntityHeader
 static jfieldID s_keyField = 0;
 static jfieldID s_dataSizeField = 0;
@@ -35,9 +32,7 @@
 static int
 ctor_native(JNIEnv* env, jobject clazz, jobject fileDescriptor)
 {
-    int err;
-
-    int fd = env->GetIntField(fileDescriptor, s_descriptorField);
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     if (fd == -1) {
         return NULL;
     }
@@ -140,15 +135,7 @@
 {
     //LOGD("register_android_backup_BackupDataInput");
 
-    jclass clazz;
-
-    clazz = env->FindClass("java/io/FileDescriptor");
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
-    s_descriptorField = env->GetFieldID(clazz, "descriptor", "I");
-    LOG_FATAL_IF(s_descriptorField == NULL,
-            "Unable to find descriptor field in java.io.FileDescriptor");
-
-    clazz = env->FindClass("android/app/backup/BackupDataInput$EntityHeader");
+    jclass clazz = env->FindClass("android/app/backup/BackupDataInput$EntityHeader");
     LOG_FATAL_IF(clazz == NULL, "Unable to find class android.app.backup.BackupDataInput.EntityHeader");
     s_keyField = env->GetFieldID(clazz, "key", "Ljava/lang/String;");
     LOG_FATAL_IF(s_keyField == NULL,
diff --git a/core/jni/android_backup_BackupDataOutput.cpp b/core/jni/android_backup_BackupDataOutput.cpp
index b895d11..144a10c 100644
--- a/core/jni/android_backup_BackupDataOutput.cpp
+++ b/core/jni/android_backup_BackupDataOutput.cpp
@@ -25,14 +25,10 @@
 namespace android
 {
 
-static jfieldID s_descriptorField = 0;
-
 static int
 ctor_native(JNIEnv* env, jobject clazz, jobject fileDescriptor)
 {
-    int err;
-
-    int fd = env->GetIntField(fileDescriptor, s_descriptorField);
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     if (fd == -1) {
         return NULL;
     }
@@ -112,15 +108,6 @@
 int register_android_backup_BackupDataOutput(JNIEnv* env)
 {
     //LOGD("register_android_backup_BackupDataOutput");
-
-    jclass clazz;
-
-    clazz = env->FindClass("java/io/FileDescriptor");
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
-    s_descriptorField = env->GetFieldID(clazz, "descriptor", "I");
-    LOG_FATAL_IF(s_descriptorField == NULL,
-            "Unable to find descriptor field in java.io.FileDescriptor");
-
     return AndroidRuntime::registerNativeMethods(env, "android/app/backup/BackupDataOutput",
             g_methods, NELEM(g_methods));
 }
diff --git a/core/jni/android_backup_BackupHelperDispatcher.cpp b/core/jni/android_backup_BackupHelperDispatcher.cpp
index 26e7d66..49f1cd4 100644
--- a/core/jni/android_backup_BackupHelperDispatcher.cpp
+++ b/core/jni/android_backup_BackupHelperDispatcher.cpp
@@ -37,8 +37,6 @@
     int nameLength; // not including the NULL terminator, which is not written to the file
 };
 
-// java.io.FileDescriptor
-static jfieldID s_descriptorField = 0;
 static jfieldID s_chunkSizeField = 0;
 static jfieldID s_keyPrefixField = 0;
 
@@ -46,12 +44,11 @@
 readHeader_native(JNIEnv* env, jobject clazz, jobject headerObj, jobject fdObj)
 {
     chunk_header_v1 flattenedHeader;
-    int fd;
     ssize_t amt;
     String8 keyPrefix;
     char* buf;
 
-    fd = env->GetIntField(fdObj, s_descriptorField);
+    int fd = jniGetFDFromFileDescriptor(env, fdObj);
 
     amt = read(fd, &flattenedHeader.headerSize, sizeof(flattenedHeader.headerSize));
     if (amt != sizeof(flattenedHeader.headerSize)) {
@@ -128,9 +125,7 @@
 static int
 skipChunk_native(JNIEnv* env, jobject clazz, jobject fdObj, jint bytesToSkip)
 {
-    int fd;
-
-    fd = env->GetIntField(fdObj, s_descriptorField);
+    int fd = jniGetFDFromFileDescriptor(env, fdObj);
 
     lseek(fd, bytesToSkip, SEEK_CUR);
 
@@ -152,9 +147,8 @@
     int nameLength;
     int namePadding;
     int headerSize;
-    int fd;
 
-    fd = env->GetIntField(fdObj, s_descriptorField);
+    int fd = jniGetFDFromFileDescriptor(env, fdObj);
 
     nameObj = (jstring)env->GetObjectField(headerObj, s_keyPrefixField);
 
@@ -166,7 +160,7 @@
     pos = lseek(fd, 0, SEEK_CUR);
 
     lseek(fd, headerSize, SEEK_CUR);
-    
+
     return pos;
 }
 
@@ -175,13 +169,12 @@
 {
     int err;
     chunk_header_v1 header;
-    int fd;
     int namePadding;
     int prevPos;
     jstring nameObj;
     const char* buf;
 
-    fd = env->GetIntField(fdObj, s_descriptorField);
+    int fd = jniGetFDFromFileDescriptor(env, fdObj);
     prevPos = lseek(fd, 0, SEEK_CUR);
 
     nameObj = (jstring)env->GetObjectField(headerObj, s_keyPrefixField);
@@ -234,15 +227,7 @@
 
 int register_android_backup_BackupHelperDispatcher(JNIEnv* env)
 {
-    jclass clazz;
-
-    clazz = env->FindClass("java/io/FileDescriptor");
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
-    s_descriptorField = env->GetFieldID(clazz, "descriptor", "I");
-    LOG_FATAL_IF(s_descriptorField == NULL,
-            "Unable to find descriptor field in java.io.FileDescriptor");
-    
-    clazz = env->FindClass("android/app/backup/BackupHelperDispatcher$Header");
+    jclass clazz = env->FindClass("android/app/backup/BackupHelperDispatcher$Header");
     LOG_FATAL_IF(clazz == NULL,
             "Unable to find class android.app.backup.BackupHelperDispatcher.Header");
     s_chunkSizeField = env->GetFieldID(clazz, "chunkSize", "I");
@@ -251,7 +236,7 @@
     s_keyPrefixField = env->GetFieldID(clazz, "keyPrefix", "Ljava/lang/String;");
     LOG_FATAL_IF(s_keyPrefixField == NULL,
             "Unable to find keyPrefix field in android.app.backup.BackupHelperDispatcher.Header");
-    
+
     return AndroidRuntime::registerNativeMethods(env, "android/app/backup/BackupHelperDispatcher",
             g_methods, NELEM(g_methods));
 }
diff --git a/core/jni/android_backup_FileBackupHelperBase.cpp b/core/jni/android_backup_FileBackupHelperBase.cpp
index 0137a06..0dfd8db 100644
--- a/core/jni/android_backup_FileBackupHelperBase.cpp
+++ b/core/jni/android_backup_FileBackupHelperBase.cpp
@@ -25,9 +25,6 @@
 namespace android
 {
 
-// java.io.FileDescriptor
-static jfieldID s_descriptorField = 0;
-
 static int
 ctor(JNIEnv* env, jobject clazz)
 {
@@ -47,8 +44,8 @@
     int err;
 
     // all parameters have already been checked against null
-    int oldStateFD = oldState != NULL ? env->GetIntField(oldState, s_descriptorField) : -1;
-    int newStateFD = env->GetIntField(newState, s_descriptorField);
+    int oldStateFD = oldState != NULL ? jniGetFDFromFileDescriptor(env, oldState) : -1;
+    int newStateFD = jniGetFDFromFileDescriptor(env, newState);
     BackupDataWriter* dataStream = (BackupDataWriter*)data;
 
     const int fileCount = env->GetArrayLength(files);
@@ -102,7 +99,7 @@
     int err;
 
     RestoreHelperBase* restore = (RestoreHelperBase*)ptr;
-    int fd = env->GetIntField(fileDescriptor, s_descriptorField);
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
     err = restore->WriteSnapshot(fd);
 
@@ -121,14 +118,6 @@
 
 int register_android_backup_FileBackupHelperBase(JNIEnv* env)
 {
-    jclass clazz;
-
-    clazz = env->FindClass("java/io/FileDescriptor");
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
-    s_descriptorField = env->GetFieldID(clazz, "descriptor", "I");
-    LOG_FATAL_IF(s_descriptorField == NULL,
-            "Unable to find descriptor field in java.io.FileDescriptor");
-    
     return AndroidRuntime::registerNativeMethods(env, "android/app/backup/FileBackupHelperBase",
             g_methods, NELEM(g_methods));
 }
diff --git a/core/jni/android_content_res_ObbScanner.cpp b/core/jni/android_content_res_ObbScanner.cpp
index 404a87d..8837538 100644
--- a/core/jni/android_content_res_ObbScanner.cpp
+++ b/core/jni/android_content_res_ObbScanner.cpp
@@ -39,7 +39,7 @@
 static void android_content_res_ObbScanner_getObbInfo(JNIEnv* env, jobject clazz, jstring file,
         jobject obbInfo)
 {
-    const char* filePath = env->GetStringUTFChars(file, JNI_FALSE);
+    const char* filePath = env->GetStringUTFChars(file, NULL);
 
     sp<ObbFile> obb = new ObbFile();
     if (!obb->readFrom(filePath)) {
diff --git a/core/jni/android_database_SQLiteStatement.cpp b/core/jni/android_database_SQLiteStatement.cpp
index 97e0483..05ffbb1 100644
--- a/core/jni/android_database_SQLiteStatement.cpp
+++ b/core/jni/android_database_SQLiteStatement.cpp
@@ -143,7 +143,7 @@
 static jobject createParcelFileDescriptor(JNIEnv * env, int fd)
 {
     // Create FileDescriptor object
-    jobject fileDesc = newFileDescriptor(env, fd);
+    jobject fileDesc = jniCreateFileDescriptor(env, fd);
     if (fileDesc == NULL) {
         // FileDescriptor constructor has thrown an exception
         close(fd);
diff --git a/core/jni/android_emoji_EmojiFactory.cpp b/core/jni/android_emoji_EmojiFactory.cpp
index 1ebb36c..81dae88 100644
--- a/core/jni/android_emoji_EmojiFactory.cpp
+++ b/core/jni/android_emoji_EmojiFactory.cpp
@@ -93,8 +93,6 @@
 static pthread_once_t g_once = PTHREAD_ONCE_INIT;
 static bool lib_emoji_factory_is_ready;
 
-static jclass    gString_class;
-
 static jclass    gBitmap_class;
 static jmethodID gBitmap_constructorMethodID;
 
@@ -108,15 +106,11 @@
 
 static jobject create_java_EmojiFactory(
     JNIEnv* env, EmojiFactory* factory, jstring name) {
-  jobject obj = env->AllocObject(gEmojiFactory_class);
-  if (obj) {
-    env->CallVoidMethod(obj, gEmojiFactory_constructorMethodID,
-                        (jint)factory, name);
-    if (env->ExceptionCheck() != 0) {
-      LOGE("*** Uncaught exception returned from Java call!\n");
-      env->ExceptionDescribe();
-      obj = NULL;
-    }
+  jobject obj = env->NewObject(gEmojiFactory_class, gEmojiFactory_constructorMethodID,
+      static_cast<jint>(reinterpret_cast<uintptr_t>(factory)), name);
+  if (env->ExceptionCheck() != 0) {
+    LOGE("*** Uncaught exception returned from Java call!\n");
+    env->ExceptionDescribe();
   }
   return obj;
 }
@@ -182,17 +176,12 @@
     return NULL;
   }
 
-  jobject obj = env->AllocObject(gBitmap_class);
-  if (obj) {
-    env->CallVoidMethod(obj, gBitmap_constructorMethodID,
-                        reinterpret_cast<jint>(bitmap), NULL, false, NULL, -1);
-    if (env->ExceptionCheck() != 0) {
-      LOGE("*** Uncaught exception returned from Java call!\n");
-      env->ExceptionDescribe();
-      return NULL;
-    }
+  jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
+      static_cast<jint>(reinterpret_cast<uintptr_t>(bitmap)), NULL, false, NULL, -1);
+  if (env->ExceptionCheck() != 0) {
+    LOGE("*** Uncaught exception returned from Java call!\n");
+    env->ExceptionDescribe();
   }
-
   return obj;
 }
 
diff --git a/core/jni/android_hardware_UsbDevice.cpp b/core/jni/android_hardware_UsbDevice.cpp
index c2950ea..25f901b 100644
--- a/core/jni/android_hardware_UsbDevice.cpp
+++ b/core/jni/android_hardware_UsbDevice.cpp
@@ -54,13 +54,6 @@
 
 int register_android_hardware_UsbDevice(JNIEnv *env)
 {
-    jclass clazz = env->FindClass("android/hardware/usb/UsbDevice");
-    if (clazz == NULL) {
-        LOGE("Can't find android/hardware/usb/UsbDevice");
-        return -1;
-    }
-
     return AndroidRuntime::registerNativeMethods(env, "android/hardware/usb/UsbDevice",
             method_table, NELEM(method_table));
 }
-
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
index e259514..4d73bf3 100644
--- a/core/jni/android_hardware_UsbDeviceConnection.cpp
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -42,7 +42,7 @@
 android_hardware_UsbDeviceConnection_open(JNIEnv *env, jobject thiz, jstring deviceName,
         jobject fileDescriptor)
 {
-    int fd = getParcelFileDescriptorFD(env, fileDescriptor);
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy
     fd = dup(fd);
     if (fd < 0)
diff --git a/core/jni/android_media_JetPlayer.cpp b/core/jni/android_media_JetPlayer.cpp
index a7ffff4..e1240692 100644
--- a/core/jni/android_media_JetPlayer.cpp
+++ b/core/jni/android_media_JetPlayer.cpp
@@ -175,7 +175,7 @@
     lpJet->setEventCallback(jetPlayerEventCallback);
 
     LOGV("android_media_JetPlayer_openFileDescr(): trying to load JET file through its fd" );
-    EAS_RESULT result = lpJet->loadFromFD(getParcelFileDescriptorFD(env, fileDescriptor),
+    EAS_RESULT result = lpJet->loadFromFD(jniGetFDFromFileDescriptor(env, fileDescriptor),
         (long long)offset, (long long)length); // cast params to types used by EAS_FILE
 
     if(result==EAS_SUCCESS) {
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index db132ec..4a0e68e 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -1,16 +1,16 @@
 /*
  * Copyright 2008, The Android Open Source Project
  *
- * Licensed under the Apache License, Version 2.0 (the "License"); 
- * you may not use this file except in compliance with the License. 
- * You may obtain a copy of the License at 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
@@ -225,9 +225,6 @@
 
 int register_android_net_NetworkUtils(JNIEnv* env)
 {
-    jclass netutils = env->FindClass(NETUTILS_PKG_NAME);
-    LOG_FATAL_IF(netutils == NULL, "Unable to find class " NETUTILS_PKG_NAME);
-
     jclass dhcpInfoInternalClass = env->FindClass("android/net/DhcpInfoInternal");
     LOG_FATAL_IF(dhcpInfoInternalClass == NULL, "Unable to find class android/net/DhcpInfoInternal");
     dhcpInfoInternalFieldIds.constructorId = env->GetMethodID(dhcpInfoInternalClass, "<init>", "()V");
diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp
index 0c84f11..203b5ef 100644
--- a/core/jni/android_net_TrafficStats.cpp
+++ b/core/jni/android_net_TrafficStats.cpp
@@ -25,6 +25,7 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <cutils/logger.h>
 #include <jni.h>
+#include <ScopedUtfChars.h>
 #include <utils/misc.h>
 #include <utils/Log.h>
 
@@ -130,13 +131,14 @@
             "/sys/class/net/ppp0/statistics/rx_bytes");
 }
 
-static jlong getData(JNIEnv* env, char *what, jstring interface) {
+static jlong getData(JNIEnv* env, const char* what, jstring javaInterface) {
+    ScopedUtfChars interface(env, javaInterface);
+    if (interface.c_str() == NULL) {
+        return -1;
+    }
+
     char filename[80];
-    jboolean isCopy;
-
-    const char *interfaceStr = env->GetStringUTFChars(interface, &isCopy);
-    snprintf(filename, sizeof(filename), "/sys/class/net/%s/statistics/%s", interfaceStr, what);
-
+    snprintf(filename, sizeof(filename), "/sys/class/net/%s/statistics/%s", interface.c_str(), what);
     return readNumber(filename);
 }
 
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index 494dc27..9d17fe9 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "wifi"
 
 #include "jni.h"
+#include <ScopedUtfChars.h>
 #include <utils/misc.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/Log.h>
@@ -47,82 +48,100 @@
     }
 }
 
-static jint doIntCommand(const char *cmd)
+static jint doIntCommand(const char* fmt, ...)
 {
-    char reply[BUF_SIZE];
-
-    if (doCommand(cmd, reply, sizeof(reply)) != 0) {
-        return (jint)-1;
-    } else {
-        return (jint)atoi(reply);
+    char buf[BUF_SIZE];
+    va_list args;
+    va_start(args, fmt);
+    int byteCount = vsnprintf(buf, sizeof(buf), fmt, args);
+    va_end(args);
+    if (byteCount < 0 || byteCount >= BUF_SIZE) {
+        return -1;
     }
+    char reply[BUF_SIZE];
+    if (doCommand(buf, reply, sizeof(reply)) != 0) {
+        return -1;
+    }
+    return static_cast<jint>(atoi(reply));
 }
 
-static jboolean doBooleanCommand(const char *cmd, const char *expect)
+static jboolean doBooleanCommand(const char* expect, const char* fmt, ...)
 {
-    char reply[BUF_SIZE];
-
-    if (doCommand(cmd, reply, sizeof(reply)) != 0) {
-        return (jboolean)JNI_FALSE;
-    } else {
-        return (jboolean)(strcmp(reply, expect) == 0);
+    char buf[BUF_SIZE];
+    va_list args;
+    va_start(args, fmt);
+    int byteCount = vsnprintf(buf, sizeof(buf), fmt, args);
+    va_end(args);
+    if (byteCount < 0 || byteCount >= BUF_SIZE) {
+        return JNI_FALSE;
     }
+    char reply[BUF_SIZE];
+    if (doCommand(buf, reply, sizeof(reply)) != 0) {
+        return JNI_FALSE;
+    }
+    return (strcmp(reply, expect) == 0);
 }
 
 // Send a command to the supplicant, and return the reply as a String
-static jstring doStringCommand(JNIEnv *env, const char *cmd)
-{
-    char reply[4096];
-
-    if (doCommand(cmd, reply, sizeof(reply)) != 0) {
-        return env->NewStringUTF(NULL);
-    } else {
-        String16 str((char *)reply);
-        return env->NewString((const jchar *)str.string(), str.size());
+static jstring doStringCommand(JNIEnv* env, const char* fmt, ...) {
+    char buf[BUF_SIZE];
+    va_list args;
+    va_start(args, fmt);
+    int byteCount = vsnprintf(buf, sizeof(buf), fmt, args);
+    va_end(args);
+    if (byteCount < 0 || byteCount >= BUF_SIZE) {
+        return NULL;
     }
+    char reply[4096];
+    if (doCommand(buf, reply, sizeof(reply)) != 0) {
+        return NULL;
+    }
+    // TODO: why not just NewStringUTF?
+    String16 str((char *)reply);
+    return env->NewString((const jchar *)str.string(), str.size());
 }
 
-static jboolean android_net_wifi_isDriverLoaded(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_isDriverLoaded(JNIEnv* env, jobject)
 {
     return (jboolean)(::is_wifi_driver_loaded() == 1);
 }
 
-static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject)
 {
     return (jboolean)(::wifi_load_driver() == 0);
 }
 
-static jboolean android_net_wifi_unloadDriver(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_unloadDriver(JNIEnv* env, jobject)
 {
     return (jboolean)(::wifi_unload_driver() == 0);
 }
 
-static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject)
 {
     return (jboolean)(::wifi_start_supplicant() == 0);
 }
 
-static jboolean android_net_wifi_stopSupplicant(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_stopSupplicant(JNIEnv* env, jobject)
 {
-    return doBooleanCommand("TERMINATE", "OK");
+    return doBooleanCommand("OK", "TERMINATE");
 }
 
-static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject)
 {
     return (jboolean)(::wifi_stop_supplicant() == 0);
 }
 
-static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject)
 {
     return (jboolean)(::wifi_connect_to_supplicant() == 0);
 }
 
-static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject clazz)
+static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject)
 {
     ::wifi_close_supplicant_connection();
 }
 
-static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject clazz)
+static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject)
 {
     char buf[BUF_SIZE];
 
@@ -130,197 +149,143 @@
     if (nread > 0) {
         return env->NewStringUTF(buf);
     } else {
-        return  env->NewStringUTF(NULL);
+        return NULL;
     }
 }
 
-static jstring android_net_wifi_listNetworksCommand(JNIEnv* env, jobject clazz)
+static jstring android_net_wifi_listNetworksCommand(JNIEnv* env, jobject)
 {
     return doStringCommand(env, "LIST_NETWORKS");
 }
 
-static jint android_net_wifi_addNetworkCommand(JNIEnv* env, jobject clazz)
+static jint android_net_wifi_addNetworkCommand(JNIEnv* env, jobject)
 {
     return doIntCommand("ADD_NETWORK");
 }
 
-static jboolean android_net_wifi_wpsPbcCommand(JNIEnv* env, jobject clazz, jstring bssid)
+static jboolean android_net_wifi_wpsPbcCommand(JNIEnv* env, jobject, jstring javaBssid)
 {
-    char cmdstr[BUF_SIZE];
-    jboolean isCopy;
-
-    const char *bssidStr = env->GetStringUTFChars(bssid, &isCopy);
-    int numWritten = snprintf(cmdstr, sizeof(cmdstr), "WPS_PBC %s", bssidStr);
-    env->ReleaseStringUTFChars(bssid, bssidStr);
-
-    if ((numWritten == -1) || (numWritten >= sizeof(cmdstr))) {
-        return false;
+    ScopedUtfChars bssid(env, javaBssid);
+    if (bssid.c_str() == NULL) {
+        return JNI_FALSE;
     }
-    return doBooleanCommand(cmdstr, "OK");
+    return doBooleanCommand("OK", "WPS_PBC %s", bssid.c_str());
 }
 
-static jboolean android_net_wifi_wpsPinFromAccessPointCommand(JNIEnv* env, jobject clazz,
-        jstring bssid, jstring apPin)
+static jboolean android_net_wifi_wpsPinFromAccessPointCommand(JNIEnv* env, jobject,
+        jstring javaBssid, jstring javaApPin)
 {
-    char cmdstr[BUF_SIZE];
-    jboolean isCopy;
-
-    const char *bssidStr = env->GetStringUTFChars(bssid, &isCopy);
-    const char *apPinStr = env->GetStringUTFChars(apPin, &isCopy);
-    int numWritten = snprintf(cmdstr, sizeof(cmdstr), "WPS_REG %s %s", bssidStr, apPinStr);
-    env->ReleaseStringUTFChars(bssid, bssidStr);
-    env->ReleaseStringUTFChars(apPin, apPinStr);
-
-    if ((numWritten == -1) || (numWritten >= (int)sizeof(cmdstr))) {
-        return false;
+    ScopedUtfChars bssid(env, javaBssid);
+    if (bssid.c_str() == NULL) {
+        return JNI_FALSE;
     }
-    return doBooleanCommand(cmdstr, "OK");
+    ScopedUtfChars apPin(env, javaApPin);
+    if (apPin.c_str() == NULL) {
+        return JNI_FALSE;
+    }
+    return doBooleanCommand("OK", "WPS_REG %s %s", bssid.c_str(), apPin.c_str());
 }
 
-static jstring android_net_wifi_wpsPinFromDeviceCommand(JNIEnv* env, jobject clazz, jstring bssid)
+static jstring android_net_wifi_wpsPinFromDeviceCommand(JNIEnv* env, jobject, jstring javaBssid)
 {
-    char cmdstr[BUF_SIZE];
-    jboolean isCopy;
-
-    const char *bssidStr = env->GetStringUTFChars(bssid, &isCopy);
-    int numWritten = snprintf(cmdstr, sizeof(cmdstr), "WPS_PIN %s", bssidStr);
-    env->ReleaseStringUTFChars(bssid, bssidStr);
-
-    if ((numWritten == -1) || (numWritten >= (int)sizeof(cmdstr))) {
+    ScopedUtfChars bssid(env, javaBssid);
+    if (bssid.c_str() == NULL) {
         return NULL;
     }
-    return doStringCommand(env, cmdstr);
+    return doStringCommand(env, "WPS_PIN %s", bssid.c_str());
 }
 
-static jboolean android_net_wifi_setCountryCodeCommand(JNIEnv* env, jobject clazz, jstring country)
+static jboolean android_net_wifi_setCountryCodeCommand(JNIEnv* env, jobject, jstring javaCountry)
 {
-    char cmdstr[BUF_SIZE];
-    jboolean isCopy;
-
-    const char *countryStr = env->GetStringUTFChars(country, &isCopy);
-    int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER COUNTRY %s", countryStr);
-    env->ReleaseStringUTFChars(country, countryStr);
-
-    if ((numWritten == -1) || (numWritten >= (int)sizeof(cmdstr))) {
-        return false;
+    ScopedUtfChars country(env, javaCountry);
+    if (country.c_str() == NULL) {
+        return JNI_FALSE;
     }
-    return doBooleanCommand(cmdstr, "OK");
+    return doBooleanCommand("OK", "DRIVER COUNTRY %s", country.c_str());
 }
 
 static jboolean android_net_wifi_setNetworkVariableCommand(JNIEnv* env,
-                                                           jobject clazz,
+                                                           jobject,
                                                            jint netId,
-                                                           jstring name,
-                                                           jstring value)
+                                                           jstring javaName,
+                                                           jstring javaValue)
 {
-    char cmdstr[BUF_SIZE];
-    jboolean isCopy;
-
-    const char *nameStr = env->GetStringUTFChars(name, &isCopy);
-    const char *valueStr = env->GetStringUTFChars(value, &isCopy);
-
-    if (nameStr == NULL || valueStr == NULL)
+    ScopedUtfChars name(env, javaName);
+    if (name.c_str() == NULL) {
         return JNI_FALSE;
-
-    int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), "SET_NETWORK %d %s %s",
-                 netId, nameStr, valueStr) >= (int)sizeof(cmdstr);
-
-    env->ReleaseStringUTFChars(name, nameStr);
-    env->ReleaseStringUTFChars(value, valueStr);
-
-    return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+    }
+    ScopedUtfChars value(env, javaValue);
+    if (value.c_str() == NULL) {
+        return JNI_FALSE;
+    }
+    return doBooleanCommand("OK", "SET_NETWORK %d %s %s", netId, name.c_str(), value.c_str());
 }
 
 static jstring android_net_wifi_getNetworkVariableCommand(JNIEnv* env,
-                                                          jobject clazz,
+                                                          jobject,
                                                           jint netId,
-                                                          jstring name)
+                                                          jstring javaName)
 {
-    char cmdstr[BUF_SIZE];
-    jboolean isCopy;
-
-    const char *nameStr = env->GetStringUTFChars(name, &isCopy);
-
-    if (nameStr == NULL)
-        return env->NewStringUTF(NULL);
-
-    int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), "GET_NETWORK %d %s",
-                             netId, nameStr) >= (int)sizeof(cmdstr);
-
-    env->ReleaseStringUTFChars(name, nameStr);
-
-    return cmdTooLong ? env->NewStringUTF(NULL) : doStringCommand(env, cmdstr);
+    ScopedUtfChars name(env, javaName);
+    if (name.c_str() == NULL) {
+        return NULL;
+    }
+    return doStringCommand(env, "GET_NETWORK %d %s", netId, name.c_str());
 }
 
-static jboolean android_net_wifi_removeNetworkCommand(JNIEnv* env, jobject clazz, jint netId)
+static jboolean android_net_wifi_removeNetworkCommand(JNIEnv* env, jobject, jint netId)
 {
-    char cmdstr[BUF_SIZE];
-
-    int numWritten = snprintf(cmdstr, sizeof(cmdstr), "REMOVE_NETWORK %d", netId);
-    int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
-
-    return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+    return doBooleanCommand("OK", "REMOVE_NETWORK %d", netId);
 }
 
 static jboolean android_net_wifi_enableNetworkCommand(JNIEnv* env,
-                                                  jobject clazz,
+                                                  jobject,
                                                   jint netId,
                                                   jboolean disableOthers)
 {
-    char cmdstr[BUF_SIZE];
-    const char *cmd = disableOthers ? "SELECT_NETWORK" : "ENABLE_NETWORK";
-
-    int numWritten = snprintf(cmdstr, sizeof(cmdstr), "%s %d", cmd, netId);
-    int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
-
-    return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+    return doBooleanCommand("OK", "%s_NETWORK %d", disableOthers ? "SELECT" : "ENABLE", netId);
 }
 
-static jboolean android_net_wifi_disableNetworkCommand(JNIEnv* env, jobject clazz, jint netId)
+static jboolean android_net_wifi_disableNetworkCommand(JNIEnv* env, jobject, jint netId)
 {
-    char cmdstr[BUF_SIZE];
-
-    int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DISABLE_NETWORK %d", netId);
-    int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
-
-    return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+    return doBooleanCommand("OK", "DISABLE_NETWORK %d", netId);
 }
 
-static jstring android_net_wifi_statusCommand(JNIEnv* env, jobject clazz)
+static jstring android_net_wifi_statusCommand(JNIEnv* env, jobject)
 {
     return doStringCommand(env, "STATUS");
 }
 
-static jboolean android_net_wifi_pingCommand(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_pingCommand(JNIEnv* env, jobject)
 {
-    return doBooleanCommand("PING", "PONG");
+    return doBooleanCommand("PONG", "PING");
 }
 
-static jstring android_net_wifi_scanResultsCommand(JNIEnv* env, jobject clazz)
+static jstring android_net_wifi_scanResultsCommand(JNIEnv* env, jobject)
 {
     return doStringCommand(env, "SCAN_RESULTS");
 }
 
-static jboolean android_net_wifi_disconnectCommand(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_disconnectCommand(JNIEnv* env, jobject)
 {
-    return doBooleanCommand("DISCONNECT", "OK");
+    return doBooleanCommand("OK", "DISCONNECT");
 }
 
-static jboolean android_net_wifi_reconnectCommand(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_reconnectCommand(JNIEnv* env, jobject)
 {
-    return doBooleanCommand("RECONNECT", "OK");
+    return doBooleanCommand("OK", "RECONNECT");
 }
-static jboolean android_net_wifi_reassociateCommand(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_reassociateCommand(JNIEnv* env, jobject)
 {
-    return doBooleanCommand("REASSOCIATE", "OK");
+    return doBooleanCommand("OK", "REASSOCIATE");
 }
 
 static jboolean doSetScanMode(jboolean setActive)
 {
-    return doBooleanCommand((setActive ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE"), "OK");
+    return doBooleanCommand("OK", (setActive ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE"));
 }
 
-static jboolean android_net_wifi_scanCommand(JNIEnv* env, jobject clazz, jboolean forceActive)
+static jboolean android_net_wifi_scanCommand(JNIEnv* env, jobject, jboolean forceActive)
 {
     jboolean result;
 
@@ -328,43 +293,43 @@
     // The scan will still work.
     if (forceActive && !sScanModeActive)
         doSetScanMode(true);
-    result = doBooleanCommand("SCAN", "OK");
+    result = doBooleanCommand("OK", "SCAN");
     if (forceActive && !sScanModeActive)
         doSetScanMode(sScanModeActive);
     return result;
 }
 
-static jboolean android_net_wifi_setScanModeCommand(JNIEnv* env, jobject clazz, jboolean setActive)
+static jboolean android_net_wifi_setScanModeCommand(JNIEnv* env, jobject, jboolean setActive)
 {
     sScanModeActive = setActive;
     return doSetScanMode(setActive);
 }
 
-static jboolean android_net_wifi_startDriverCommand(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_startDriverCommand(JNIEnv* env, jobject)
 {
-    return doBooleanCommand("DRIVER START", "OK");
+    return doBooleanCommand("OK", "DRIVER START");
 }
 
-static jboolean android_net_wifi_stopDriverCommand(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_stopDriverCommand(JNIEnv* env, jobject)
 {
-    return doBooleanCommand("DRIVER STOP", "OK");
+    return doBooleanCommand("OK", "DRIVER STOP");
 }
 
-static jboolean android_net_wifi_startPacketFiltering(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_startPacketFiltering(JNIEnv* env, jobject)
 {
-    return doBooleanCommand("DRIVER RXFILTER-ADD 0", "OK")
-	&& doBooleanCommand("DRIVER RXFILTER-ADD 1", "OK")
-	&& doBooleanCommand("DRIVER RXFILTER-ADD 3", "OK")
-	&& doBooleanCommand("DRIVER RXFILTER-START", "OK");
+    return doBooleanCommand("OK", "DRIVER RXFILTER-ADD 0")
+            && doBooleanCommand("OK", "DRIVER RXFILTER-ADD 1")
+            && doBooleanCommand("OK", "DRIVER RXFILTER-ADD 3")
+            && doBooleanCommand("OK", "DRIVER RXFILTER-START");
 }
 
-static jboolean android_net_wifi_stopPacketFiltering(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_stopPacketFiltering(JNIEnv* env, jobject)
 {
-    jboolean result = doBooleanCommand("DRIVER RXFILTER-STOP", "OK");
+    jboolean result = doBooleanCommand("OK", "DRIVER RXFILTER-STOP");
     if (result) {
-	(void)doBooleanCommand("DRIVER RXFILTER-REMOVE 3", "OK");
-	(void)doBooleanCommand("DRIVER RXFILTER-REMOVE 1", "OK");
-	(void)doBooleanCommand("DRIVER RXFILTER-REMOVE 0", "OK");
+        (void)doBooleanCommand("OK", "DRIVER RXFILTER-REMOVE 3");
+        (void)doBooleanCommand("OK", "DRIVER RXFILTER-REMOVE 1");
+        (void)doBooleanCommand("OK", "DRIVER RXFILTER-REMOVE 0");
     }
 
     return result;
@@ -399,17 +364,17 @@
     return (jint)rssi;
 }
 
-static jint android_net_wifi_getRssiCommand(JNIEnv* env, jobject clazz)
+static jint android_net_wifi_getRssiCommand(JNIEnv* env, jobject)
 {
     return android_net_wifi_getRssiHelper("DRIVER RSSI");
 }
 
-static jint android_net_wifi_getRssiApproxCommand(JNIEnv* env, jobject clazz)
+static jint android_net_wifi_getRssiApproxCommand(JNIEnv* env, jobject)
 {
     return android_net_wifi_getRssiHelper("DRIVER RSSI-APPROX");
 }
 
-static jint android_net_wifi_getLinkSpeedCommand(JNIEnv* env, jobject clazz)
+static jint android_net_wifi_getLinkSpeedCommand(JNIEnv* env, jobject)
 {
     char reply[BUF_SIZE];
     int linkspeed;
@@ -423,33 +388,28 @@
     return (jint)linkspeed;
 }
 
-static jstring android_net_wifi_getMacAddressCommand(JNIEnv* env, jobject clazz)
+static jstring android_net_wifi_getMacAddressCommand(JNIEnv* env, jobject)
 {
     char reply[BUF_SIZE];
     char buf[BUF_SIZE];
 
     if (doCommand("DRIVER MACADDR", reply, sizeof(reply)) != 0) {
-        return env->NewStringUTF(NULL);
+        return NULL;
     }
     // reply comes back in the form "Macaddr = XX.XX.XX.XX.XX.XX" where XX
     // is the part of the string we're interested in.
-    if (sscanf(reply, "%*s = %255s", buf) == 1)
+    if (sscanf(reply, "%*s = %255s", buf) == 1) {
         return env->NewStringUTF(buf);
-    else
-        return env->NewStringUTF(NULL);
+    }
+    return NULL;
 }
 
-static jboolean android_net_wifi_setPowerModeCommand(JNIEnv* env, jobject clazz, jint mode)
+static jboolean android_net_wifi_setPowerModeCommand(JNIEnv* env, jobject, jint mode)
 {
-    char cmdstr[BUF_SIZE];
-
-    int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER POWERMODE %d", mode);
-    int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
-
-    return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+    return doBooleanCommand("OK", "DRIVER POWERMODE %d", mode);
 }
 
-static jint android_net_wifi_getPowerModeCommand(JNIEnv* env, jobject clazz)
+static jint android_net_wifi_getPowerModeCommand(JNIEnv* env, jobject)
 {
     char reply[BUF_SIZE];
     int power;
@@ -463,17 +423,12 @@
     return (jint)power;
 }
 
-static jboolean android_net_wifi_setBandCommand(JNIEnv* env, jobject clazz, jint band)
+static jboolean android_net_wifi_setBandCommand(JNIEnv* env, jobject, jint band)
 {
-    char cmdstr[25];
-
-    int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER SETBAND %d", band);
-    int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
-
-    return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+    return doBooleanCommand("OK", "DRIVER SETBAND %d", band);
 }
 
-static jint android_net_wifi_getBandCommand(JNIEnv* env, jobject clazz)
+static jint android_net_wifi_getBandCommand(JNIEnv* env, jobject)
 {
     char reply[25];
     int band;
@@ -487,94 +442,66 @@
     return (jint)band;
 }
 
-static jboolean android_net_wifi_setBluetoothCoexistenceModeCommand(JNIEnv* env, jobject clazz, jint mode)
+static jboolean android_net_wifi_setBluetoothCoexistenceModeCommand(JNIEnv* env, jobject, jint mode)
 {
-    char cmdstr[BUF_SIZE];
-
-    int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER BTCOEXMODE %d", mode);
-    int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
-
-    return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+    return doBooleanCommand("OK", "DRIVER BTCOEXMODE %d", mode);
 }
 
-static jboolean android_net_wifi_setBluetoothCoexistenceScanModeCommand(JNIEnv* env, jobject clazz, jboolean setCoexScanMode)
+static jboolean android_net_wifi_setBluetoothCoexistenceScanModeCommand(JNIEnv* env, jobject, jboolean setCoexScanMode)
 {
-    char cmdstr[BUF_SIZE];
-
-    int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER BTCOEXSCAN-%s", setCoexScanMode ? "START" : "STOP");
-    int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
-
-    return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+    return doBooleanCommand("OK", "DRIVER BTCOEXSCAN-%s", setCoexScanMode ? "START" : "STOP");
 }
 
-static jboolean android_net_wifi_saveConfigCommand(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_saveConfigCommand(JNIEnv* env, jobject)
 {
     // Make sure we never write out a value for AP_SCAN other than 1
-    (void)doBooleanCommand("AP_SCAN 1", "OK");
-    return doBooleanCommand("SAVE_CONFIG", "OK");
+    (void)doBooleanCommand("OK", "AP_SCAN 1");
+    return doBooleanCommand("OK", "SAVE_CONFIG");
 }
 
-static jboolean android_net_wifi_reloadConfigCommand(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_reloadConfigCommand(JNIEnv* env, jobject)
 {
-    return doBooleanCommand("RECONFIGURE", "OK");
+    return doBooleanCommand("OK", "RECONFIGURE");
 }
 
-static jboolean android_net_wifi_setScanResultHandlingCommand(JNIEnv* env, jobject clazz, jint mode)
+static jboolean android_net_wifi_setScanResultHandlingCommand(JNIEnv* env, jobject, jint mode)
 {
-    char cmdstr[BUF_SIZE];
-
-    int numWritten = snprintf(cmdstr, sizeof(cmdstr), "AP_SCAN %d", mode);
-    int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
-
-    return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+    return doBooleanCommand("OK", "AP_SCAN %d", mode);
 }
 
-static jboolean android_net_wifi_addToBlacklistCommand(JNIEnv* env, jobject clazz, jstring bssid)
+static jboolean android_net_wifi_addToBlacklistCommand(JNIEnv* env, jobject, jstring javaBssid)
 {
-    char cmdstr[BUF_SIZE];
-    jboolean isCopy;
-
-    const char *bssidStr = env->GetStringUTFChars(bssid, &isCopy);
-
-    int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), "BLACKLIST %s", bssidStr) >= (int)sizeof(cmdstr);
-
-    env->ReleaseStringUTFChars(bssid, bssidStr);
-
-    return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+    ScopedUtfChars bssid(env, javaBssid);
+    if (bssid.c_str() == NULL) {
+        return JNI_FALSE;
+    }
+    return doBooleanCommand("OK", "BLACKLIST %s", bssid.c_str());
 }
 
-static jboolean android_net_wifi_clearBlacklistCommand(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_clearBlacklistCommand(JNIEnv* env, jobject)
 {
-    return doBooleanCommand("BLACKLIST clear", "OK");
+    return doBooleanCommand("OK", "BLACKLIST clear");
 }
 
-static jboolean android_net_wifi_setSuspendOptimizationsCommand(JNIEnv* env, jobject clazz, jboolean enabled)
+static jboolean android_net_wifi_setSuspendOptimizationsCommand(JNIEnv* env, jobject, jboolean enabled)
 {
-    char cmdstr[BUF_SIZE];
-
-    snprintf(cmdstr, sizeof(cmdstr), "DRIVER SETSUSPENDOPT %d", enabled ? 0 : 1);
-    return doBooleanCommand(cmdstr, "OK");
+    return doBooleanCommand("OK", "DRIVER SETSUSPENDOPT %d", enabled ? 0 : 1);
 }
 
-static void android_net_wifi_enableBackgroundScanCommand(JNIEnv* env, jobject clazz, jboolean enable)
+static void android_net_wifi_enableBackgroundScanCommand(JNIEnv* env, jobject, jboolean enable)
 {
     //Note: BGSCAN-START and BGSCAN-STOP are documented in core/res/res/values/config.xml
     //and will need an update if the names are changed
     if (enable) {
-        doBooleanCommand("DRIVER BGSCAN-START", "OK");
-    }
-    else {
-        doBooleanCommand("DRIVER BGSCAN-STOP", "OK");
+        doBooleanCommand("OK", "DRIVER BGSCAN-START");
+    } else {
+        doBooleanCommand("OK", "DRIVER BGSCAN-STOP");
     }
 }
 
-static void android_net_wifi_setScanIntervalCommand(JNIEnv* env, jobject clazz, jint scanInterval)
+static void android_net_wifi_setScanIntervalCommand(JNIEnv* env, jobject, jint scanInterval)
 {
-    char cmdstr[BUF_SIZE];
-
-    int numWritten = snprintf(cmdstr, sizeof(cmdstr), "SCAN_INTERVAL %d", scanInterval);
-
-    if(numWritten < (int)sizeof(cmdstr)) doBooleanCommand(cmdstr, "OK");
+    doBooleanCommand("OK", "SCAN_INTERVAL %d", scanInterval);
 }
 
 
@@ -651,9 +578,6 @@
 
 int register_android_net_wifi_WifiManager(JNIEnv* env)
 {
-    jclass wifi = env->FindClass(WIFI_PKG_NAME);
-    LOG_FATAL_IF(wifi == NULL, "Unable to find class " WIFI_PKG_NAME);
-
     return AndroidRuntime::registerNativeMethods(env,
             WIFI_PKG_NAME, gWifiMethods, NELEM(gWifiMethods));
 }
diff --git a/core/jni/android_nio_utils.cpp b/core/jni/android_nio_utils.cpp
index 584e7a4..7cbbe12 100644
--- a/core/jni/android_nio_utils.cpp
+++ b/core/jni/android_nio_utils.cpp
@@ -32,20 +32,20 @@
     jlong pointer;
     jint offset;
     void *data;
-    
+
     pointer = _env->CallStaticLongMethod(gNioJNI.nioAccessClass,
                                          gNioJNI.getBasePointerID, buffer);
     if (pointer != 0L) {
         *array = NULL;
         return (void *) (jint) pointer;
     }
-    
+
     *array = (jarray) _env->CallStaticObjectMethod(gNioJNI.nioAccessClass,
                                                gNioJNI.getBaseArrayID, buffer);
     offset = _env->CallStaticIntMethod(gNioJNI.nioAccessClass,
                                        gNioJNI.getBaseArrayOffsetID, buffer);
     data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-    
+
     return (void *) ((char *) data + offset);
 }
 
@@ -94,8 +94,7 @@
 }
 
 namespace android {
-    
-int register_android_nio_utils(JNIEnv* env);
+
 int register_android_nio_utils(JNIEnv* env) {
     jclass localClass = findClass(env, "java/nio/NIOAccess");
     gNioJNI.getBasePointerID = findStaticMethod(env, localClass,
diff --git a/core/jni/android_opengl_GLES10.cpp b/core/jni/android_opengl_GLES10.cpp
index 2685d75..6c29d6c 100644
--- a/core/jni/android_opengl_GLES10.cpp
+++ b/core/jni/android_opengl_GLES10.cpp
@@ -2,21 +2,23 @@
 **
 ** Copyright 2009, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 // This source file is automatically generated
 
+#include "jni.h"
+#include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 
@@ -41,10 +43,6 @@
 
 static jclass nioAccessClass;
 static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
 static jmethodID getBasePointerID;
 static jmethodID getBaseArrayID;
 static jmethodID getBaseArrayOffsetID;
@@ -55,7 +53,7 @@
 /* Cache method IDs each time the class is loaded. */
 
 static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
 {
     jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
     nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -76,26 +74,6 @@
         _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
 }
 
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
-    nativeClassInitBuffer(_env);
-
-    jclass IAEClassLocal =
-        _env->FindClass("java/lang/IllegalArgumentException");
-    jclass OOMEClassLocal =
-         _env->FindClass("java/lang/OutOfMemoryError");
-    jclass UOEClassLocal =
-         _env->FindClass("java/lang/UnsupportedOperationException");
-    jclass AIOOBEClassLocal =
-         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
-    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
-    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
-    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
-    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
 static void *
 getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
 {
@@ -116,13 +94,13 @@
         *array = NULL;
         return (void *) (jint) pointer;
     }
-    
+
     *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
             getBaseArrayID, buffer);
     offset = _env->CallStaticIntMethod(nioAccessClass,
             getBaseArrayOffsetID, buffer);
     data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-    
+
     return (void *) ((char *) data + offset);
 }
 
@@ -141,7 +119,8 @@
         jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
         buf += position << elementSizeShift;
     } else {
-        _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+        jniThrowException(_env, "java/lang/IllegalArgumentException",
+                          "Must use a native order direct Buffer");
     }
     return (void*) buf;
 }
@@ -154,7 +133,6 @@
 }
 
 // --------------------------------------------------------------------------
-
 /* void glActiveTexture ( GLenum texture ) */
 static void
 android_glActiveTexture__I
@@ -431,16 +409,16 @@
     GLuint *textures = (GLuint *) 0;
 
     if (!textures_ref) {
-        _env->ThrowNew(IAEClass, "textures == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "textures == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(textures_ref) - offset;
     if (_remaining < n) {
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     textures_base = (GLuint *)
@@ -469,7 +447,7 @@
 
     textures = (GLuint *)getPointer(_env, textures_buf, &_array, &_remaining);
     if (_remaining < n) {
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glDeleteTextures(
@@ -560,7 +538,7 @@
 
     indices = (GLvoid *)getPointer(_env, indices_buf, &_array, &_remaining);
     if (_remaining < count) {
-        _env->ThrowNew(AIOOBEClass, "remaining() < count");
+        jniThrowException(_env, "java/lang/ArrayIndexOutOfBoundsException", "remaining() < count");
         goto exit;
     }
     glDrawElements(
@@ -627,11 +605,11 @@
     GLfloat *params = (GLfloat *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -661,7 +639,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -715,7 +693,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glFogfv(
@@ -748,11 +726,11 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -782,7 +760,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -836,7 +814,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glFogxv(
@@ -898,18 +876,18 @@
 
     if (!textures_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "textures == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "textures == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(textures_ref) - offset;
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     textures_base = (GLuint *)
@@ -940,7 +918,7 @@
     textures = (GLuint *)getPointer(_env, textures_buf, &_array, &_remaining);
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glGenTextures(
@@ -974,12 +952,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1316,7 +1294,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLint *)
@@ -1678,7 +1656,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glGetIntegerv(
@@ -1692,16 +1670,10 @@
     }
 }
 
-#include <string.h>
-
 /* const GLubyte * glGetString ( GLenum name ) */
-static
-jstring
-android_glGetString
-  (JNIEnv *_env, jobject _this, jint name) {
-    const char * chars = (const char *)glGetString((GLenum)name);
-    jstring output = _env->NewStringUTF(chars);
-    return output;
+static jstring android_glGetString(JNIEnv* _env, jobject, jint name) {
+    const char* chars = (const char*) glGetString((GLenum) name);
+    return _env->NewStringUTF(chars);
 }
 /* void glHint ( GLenum target, GLenum mode ) */
 static void
@@ -1732,11 +1704,11 @@
     GLfloat *params = (GLfloat *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1757,7 +1729,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -1802,7 +1774,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glLightModelfv(
@@ -1835,11 +1807,11 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1860,7 +1832,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -1905,7 +1877,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glLightModelxv(
@@ -1939,11 +1911,11 @@
     GLfloat *params = (GLfloat *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1990,7 +1962,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -2062,7 +2034,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glLightfv(
@@ -2097,11 +2069,11 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2148,7 +2120,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -2220,7 +2192,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glLightxv(
@@ -2269,11 +2241,11 @@
     GLfloat *m = (GLfloat *) 0;
 
     if (!m_ref) {
-        _env->ThrowNew(IAEClass, "m == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(m_ref) - offset;
@@ -2318,11 +2290,11 @@
     GLfixed *m = (GLfixed *) 0;
 
     if (!m_ref) {
-        _env->ThrowNew(IAEClass, "m == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(m_ref) - offset;
@@ -2387,11 +2359,11 @@
     GLfloat *params = (GLfloat *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2424,7 +2396,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -2482,7 +2454,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glMaterialfv(
@@ -2517,11 +2489,11 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2554,7 +2526,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -2612,7 +2584,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glMaterialxv(
@@ -2645,11 +2617,11 @@
     GLfloat *m = (GLfloat *) 0;
 
     if (!m_ref) {
-        _env->ThrowNew(IAEClass, "m == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(m_ref) - offset;
@@ -2694,11 +2666,11 @@
     GLfixed *m = (GLfixed *) 0;
 
     if (!m_ref) {
-        _env->ThrowNew(IAEClass, "m == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(m_ref) - offset;
@@ -3079,11 +3051,11 @@
     GLfloat *params = (GLfloat *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -3110,7 +3082,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -3162,7 +3134,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glTexEnvfv(
@@ -3197,11 +3169,11 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -3228,7 +3200,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -3280,7 +3252,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glTexEnvxv(
diff --git a/core/jni/android_opengl_GLES10Ext.cpp b/core/jni/android_opengl_GLES10Ext.cpp
index f17ef21..1154cef 100644
--- a/core/jni/android_opengl_GLES10Ext.cpp
+++ b/core/jni/android_opengl_GLES10Ext.cpp
@@ -2,21 +2,23 @@
 **
 ** Copyright 2009, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 // This source file is automatically generated
 
+#include "jni.h"
+#include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 
@@ -28,10 +30,6 @@
 
 static jclass nioAccessClass;
 static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
 static jmethodID getBasePointerID;
 static jmethodID getBaseArrayID;
 static jmethodID getBaseArrayOffsetID;
@@ -42,7 +40,7 @@
 /* Cache method IDs each time the class is loaded. */
 
 static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
 {
     jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
     nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -64,26 +62,6 @@
 }
 
 
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
-    nativeClassInitBuffer(_env);
-
-    jclass IAEClassLocal =
-        _env->FindClass("java/lang/IllegalArgumentException");
-    jclass OOMEClassLocal =
-         _env->FindClass("java/lang/OutOfMemoryError");
-    jclass UOEClassLocal =
-         _env->FindClass("java/lang/UnsupportedOperationException");
-    jclass AIOOBEClassLocal =
-         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
-    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
-    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
-    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
-    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
 static void *
 getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
 {
@@ -104,13 +82,13 @@
         *array = NULL;
         return (void *) (jint) pointer;
     }
-    
+
     *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
             getBaseArrayID, buffer);
     offset = _env->CallStaticIntMethod(nioAccessClass,
             getBaseArrayOffsetID, buffer);
     data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-    
+
     return (void *) ((char *) data + offset);
 }
 
@@ -123,7 +101,6 @@
 }
 
 // --------------------------------------------------------------------------
-
 /* GLbitfield glQueryMatrixxOES ( GLfixed *mantissa, GLint *exponent ) */
 static jint
 android_glQueryMatrixxOES___3II_3II
@@ -139,18 +116,18 @@
 
     if (!mantissa_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "mantissa == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "mantissa == null");
         goto exit;
     }
     if (mantissaOffset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "mantissaOffset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "mantissaOffset < 0");
         goto exit;
     }
     _mantissaRemaining = _env->GetArrayLength(mantissa_ref) - mantissaOffset;
     if (_mantissaRemaining < 16) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - mantissaOffset < 16");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - mantissaOffset < 16");
         goto exit;
     }
     mantissa_base = (GLfixed *)
@@ -159,18 +136,18 @@
 
     if (!exponent_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "exponent == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "exponent == null");
         goto exit;
     }
     if (exponentOffset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "exponentOffset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "exponentOffset < 0");
         goto exit;
     }
     _exponentRemaining = _env->GetArrayLength(exponent_ref) - exponentOffset;
     if (_exponentRemaining < 16) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - exponentOffset < 16");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - exponentOffset < 16");
         goto exit;
     }
     exponent_base = (GLint *)
@@ -210,13 +187,13 @@
     mantissa = (GLfixed *)getPointer(_env, mantissa_buf, &_mantissaArray, &_mantissaRemaining);
     if (_mantissaRemaining < 16) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < 16");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 16");
         goto exit;
     }
     exponent = (GLint *)getPointer(_env, exponent_buf, &_exponentArray, &_exponentRemaining);
     if (_exponentRemaining < 16) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < 16");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 16");
         goto exit;
     }
     _returnValue = glQueryMatrixxOES(
diff --git a/core/jni/android_opengl_GLES11.cpp b/core/jni/android_opengl_GLES11.cpp
index 1c326ba..d038f20 100644
--- a/core/jni/android_opengl_GLES11.cpp
+++ b/core/jni/android_opengl_GLES11.cpp
@@ -2,21 +2,23 @@
 **
 ** Copyright 2009, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 // This source file is automatically generated
 
+#include "jni.h"
+#include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 
@@ -35,10 +37,6 @@
 
 static jclass nioAccessClass;
 static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
 static jmethodID getBasePointerID;
 static jmethodID getBaseArrayID;
 static jmethodID getBaseArrayOffsetID;
@@ -49,7 +47,7 @@
 /* Cache method IDs each time the class is loaded. */
 
 static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
 {
     jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
     nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -71,26 +69,6 @@
 }
 
 
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
-    nativeClassInitBuffer(_env);
-
-    jclass IAEClassLocal =
-        _env->FindClass("java/lang/IllegalArgumentException");
-    jclass OOMEClassLocal =
-         _env->FindClass("java/lang/OutOfMemoryError");
-    jclass UOEClassLocal =
-         _env->FindClass("java/lang/UnsupportedOperationException");
-    jclass AIOOBEClassLocal =
-         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
-    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
-    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
-    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
-    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
 static void *
 getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
 {
@@ -111,13 +89,13 @@
         *array = NULL;
         return (void *) (jint) pointer;
     }
-    
+
     *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
             getBaseArrayID, buffer);
     offset = _env->CallStaticIntMethod(nioAccessClass,
             getBaseArrayOffsetID, buffer);
     data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-    
+
     return (void *) ((char *) data + offset);
 }
 
@@ -137,13 +115,13 @@
         jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
         buf += position << elementSizeShift;
     } else {
-        _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+        jniThrowException(_env, "java/lang/IllegalArgumentException",
+                          "Must use a native order direct Buffer");
     }
     return (void*) buf;
 }
 
 // --------------------------------------------------------------------------
-
 /* void glBindBuffer ( GLenum target, GLuint buffer ) */
 static void
 android_glBindBuffer__II
@@ -165,7 +143,7 @@
     if (data_buf) {
         data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
         if (_remaining < size) {
-            _env->ThrowNew(IAEClass, "remaining() < size");
+            jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < size");
             goto exit;
         }
     }
@@ -192,7 +170,7 @@
 
     data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
     if (_remaining < size) {
-        _env->ThrowNew(IAEClass, "remaining() < size");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < size");
         goto exit;
     }
     glBufferSubData(
@@ -217,11 +195,11 @@
     GLfloat *equation = (GLfloat *) 0;
 
     if (!equation_ref) {
-        _env->ThrowNew(IAEClass, "equation == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "equation == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(equation_ref) - offset;
@@ -268,11 +246,11 @@
     GLfixed *equation = (GLfixed *) 0;
 
     if (!equation_ref) {
-        _env->ThrowNew(IAEClass, "equation == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "equation == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(equation_ref) - offset;
@@ -343,16 +321,16 @@
     GLuint *buffers = (GLuint *) 0;
 
     if (!buffers_ref) {
-        _env->ThrowNew(IAEClass, "buffers == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "buffers == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(buffers_ref) - offset;
     if (_remaining < n) {
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     buffers_base = (GLuint *)
@@ -381,7 +359,7 @@
 
     buffers = (GLuint *)getPointer(_env, buffers_buf, &_array, &_remaining);
     if (_remaining < n) {
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glDeleteBuffers(
@@ -418,18 +396,18 @@
 
     if (!buffers_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "buffers == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "buffers == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(buffers_ref) - offset;
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     buffers_base = (GLuint *)
@@ -460,7 +438,7 @@
     buffers = (GLuint *)getPointer(_env, buffers_buf, &_array, &_remaining);
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glGenBuffers(
@@ -485,12 +463,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -540,18 +518,18 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLint *)
@@ -583,7 +561,7 @@
     params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glGetBufferParameteriv(
@@ -609,12 +587,12 @@
 
     if (!eqn_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "eqn == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "eqn == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(eqn_ref) - offset;
@@ -664,12 +642,12 @@
 
     if (!eqn_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "eqn == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "eqn == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(eqn_ref) - offset;
@@ -719,12 +697,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -774,12 +752,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -829,12 +807,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -882,7 +860,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -956,7 +934,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glGetLightfv(
@@ -982,12 +960,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1035,7 +1013,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -1109,7 +1087,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glGetLightxv(
@@ -1135,12 +1113,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1174,7 +1152,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -1234,7 +1212,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glGetMaterialfv(
@@ -1260,12 +1238,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1299,7 +1277,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -1359,7 +1337,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glGetMaterialxv(
@@ -1385,12 +1363,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1418,7 +1396,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -1472,7 +1450,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glGetTexEnvfv(
@@ -1498,12 +1476,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1531,7 +1509,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLint *)
@@ -1585,7 +1563,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glGetTexEnviv(
@@ -1611,12 +1589,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1644,7 +1622,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -1698,7 +1676,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glGetTexEnvxv(
@@ -1724,18 +1702,18 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -1767,7 +1745,7 @@
     params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glGetTexParameterfv(
@@ -1793,18 +1771,18 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLint *)
@@ -1836,7 +1814,7 @@
     params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glGetTexParameteriv(
@@ -1862,18 +1840,18 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -1905,7 +1883,7 @@
     params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glGetTexParameterxv(
@@ -1983,16 +1961,16 @@
     GLfloat *params = (GLfloat *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -2021,7 +1999,7 @@
 
     params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glPointParameterfv(
@@ -2054,16 +2032,16 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -2092,7 +2070,7 @@
 
     params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glPointParameterxv(
@@ -2160,11 +2138,11 @@
     GLint *params = (GLint *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2191,7 +2169,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLint *)
@@ -2243,7 +2221,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glTexEnviv(
@@ -2267,16 +2245,16 @@
     GLfloat *params = (GLfloat *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -2306,7 +2284,7 @@
 
     params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glTexParameterfv(
@@ -2341,16 +2319,16 @@
     GLint *params = (GLint *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLint *)
@@ -2380,7 +2358,7 @@
 
     params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glTexParameteriv(
@@ -2404,16 +2382,16 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -2443,7 +2421,7 @@
 
     params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glTexParameterxv(
diff --git a/core/jni/android_opengl_GLES11Ext.cpp b/core/jni/android_opengl_GLES11Ext.cpp
index 1390506..d6dc0fe 100644
--- a/core/jni/android_opengl_GLES11Ext.cpp
+++ b/core/jni/android_opengl_GLES11Ext.cpp
@@ -2,21 +2,23 @@
 **
 ** Copyright 2009, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 // This source file is automatically generated
 
+#include "jni.h"
+#include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 
@@ -37,10 +39,6 @@
 
 static jclass nioAccessClass;
 static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
 static jmethodID getBasePointerID;
 static jmethodID getBaseArrayID;
 static jmethodID getBaseArrayOffsetID;
@@ -51,7 +49,7 @@
 /* Cache method IDs each time the class is loaded. */
 
 static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
 {
     jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
     nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -73,26 +71,6 @@
 }
 
 
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
-    nativeClassInitBuffer(_env);
-
-    jclass IAEClassLocal =
-        _env->FindClass("java/lang/IllegalArgumentException");
-    jclass OOMEClassLocal =
-         _env->FindClass("java/lang/OutOfMemoryError");
-    jclass UOEClassLocal =
-         _env->FindClass("java/lang/UnsupportedOperationException");
-    jclass AIOOBEClassLocal =
-         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
-    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
-    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
-    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
-    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
 static void *
 getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
 {
@@ -113,13 +91,13 @@
         *array = NULL;
         return (void *) (jint) pointer;
     }
-    
+
     *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
             getBaseArrayID, buffer);
     offset = _env->CallStaticIntMethod(nioAccessClass,
             getBaseArrayOffsetID, buffer);
     data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-    
+
     return (void *) ((char *) data + offset);
 }
 
@@ -139,12 +117,12 @@
         jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
         buf += position << elementSizeShift;
     } else {
-        _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+        jniThrowException(_env, "java/lang/IllegalArgumentException",
+                          "Must use a native order direct Buffer");
     }
     return (void*) buf;
 }
 // --------------------------------------------------------------------------
-
 /* void glBlendEquationSeparateOES ( GLenum modeRGB, GLenum modeAlpha ) */
 static void
 android_glBlendEquationSeparateOES__II
@@ -224,16 +202,16 @@
     GLshort *coords = (GLshort *) 0;
 
     if (!coords_ref) {
-        _env->ThrowNew(IAEClass, "coords == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "coords == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(coords_ref) - offset;
     if (_remaining < 5) {
-        _env->ThrowNew(IAEClass, "length - offset < 5");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 5");
         goto exit;
     }
     coords_base = (GLshort *)
@@ -261,7 +239,7 @@
 
     coords = (GLshort *)getPointer(_env, coords_buf, &_array, &_remaining);
     if (_remaining < 5) {
-        _env->ThrowNew(IAEClass, "remaining() < 5");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 5");
         goto exit;
     }
     glDrawTexsvOES(
@@ -283,16 +261,16 @@
     GLint *coords = (GLint *) 0;
 
     if (!coords_ref) {
-        _env->ThrowNew(IAEClass, "coords == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "coords == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(coords_ref) - offset;
     if (_remaining < 5) {
-        _env->ThrowNew(IAEClass, "length - offset < 5");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 5");
         goto exit;
     }
     coords_base = (GLint *)
@@ -320,7 +298,7 @@
 
     coords = (GLint *)getPointer(_env, coords_buf, &_array, &_remaining);
     if (_remaining < 5) {
-        _env->ThrowNew(IAEClass, "remaining() < 5");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 5");
         goto exit;
     }
     glDrawTexivOES(
@@ -342,16 +320,16 @@
     GLfixed *coords = (GLfixed *) 0;
 
     if (!coords_ref) {
-        _env->ThrowNew(IAEClass, "coords == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "coords == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(coords_ref) - offset;
     if (_remaining < 5) {
-        _env->ThrowNew(IAEClass, "length - offset < 5");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 5");
         goto exit;
     }
     coords_base = (GLfixed *)
@@ -379,7 +357,7 @@
 
     coords = (GLfixed *)getPointer(_env, coords_buf, &_array, &_remaining);
     if (_remaining < 5) {
-        _env->ThrowNew(IAEClass, "remaining() < 5");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 5");
         goto exit;
     }
     glDrawTexxvOES(
@@ -414,16 +392,16 @@
     GLfloat *coords = (GLfloat *) 0;
 
     if (!coords_ref) {
-        _env->ThrowNew(IAEClass, "coords == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "coords == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(coords_ref) - offset;
     if (_remaining < 5) {
-        _env->ThrowNew(IAEClass, "length - offset < 5");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 5");
         goto exit;
     }
     coords_base = (GLfloat *)
@@ -451,7 +429,7 @@
 
     coords = (GLfloat *)getPointer(_env, coords_buf, &_array, &_remaining);
     if (_remaining < 5) {
-        _env->ThrowNew(IAEClass, "remaining() < 5");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 5");
         goto exit;
     }
     glDrawTexfvOES(
@@ -542,11 +520,11 @@
     GLfixed *equation = (GLfixed *) 0;
 
     if (!equation_ref) {
-        _env->ThrowNew(IAEClass, "equation == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "equation == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(equation_ref) - offset;
@@ -625,11 +603,11 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -692,18 +670,18 @@
 
     if (!eqn_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "eqn == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "eqn == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(eqn_ref) - offset;
     if (_remaining < 4) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < 4");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 4");
         goto exit;
     }
     eqn_base = (GLfixed *)
@@ -734,7 +712,7 @@
     eqn = (GLfixed *)getPointer(_env, eqn_buf, &_array, &_remaining);
     if (_remaining < 4) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < 4");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 4");
         goto exit;
     }
     glGetClipPlanexOES(
@@ -759,12 +737,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -814,12 +792,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -871,12 +849,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -928,12 +906,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -985,12 +963,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1050,11 +1028,11 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1112,11 +1090,11 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1174,11 +1152,11 @@
     GLfixed *m = (GLfixed *) 0;
 
     if (!m_ref) {
-        _env->ThrowNew(IAEClass, "m == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(m_ref) - offset;
@@ -1234,11 +1212,11 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1287,11 +1265,11 @@
     GLfixed *m = (GLfixed *) 0;
 
     if (!m_ref) {
-        _env->ThrowNew(IAEClass, "m == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(m_ref) - offset;
@@ -1384,11 +1362,11 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1498,11 +1476,11 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1562,11 +1540,11 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1647,16 +1625,16 @@
     GLuint *renderbuffers = (GLuint *) 0;
 
     if (!renderbuffers_ref) {
-        _env->ThrowNew(IAEClass, "renderbuffers == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "renderbuffers == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(renderbuffers_ref) - offset;
     if (_remaining < n) {
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     renderbuffers_base = (GLuint *)
@@ -1685,7 +1663,7 @@
 
     renderbuffers = (GLuint *)getPointer(_env, renderbuffers_buf, &_array, &_remaining);
     if (_remaining < n) {
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glDeleteRenderbuffersOES(
@@ -1710,18 +1688,18 @@
 
     if (!renderbuffers_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "renderbuffers == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "renderbuffers == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(renderbuffers_ref) - offset;
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     renderbuffers_base = (GLuint *)
@@ -1752,7 +1730,7 @@
     renderbuffers = (GLuint *)getPointer(_env, renderbuffers_buf, &_array, &_remaining);
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glGenRenderbuffersOES(
@@ -1789,18 +1767,18 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLint *)
@@ -1832,7 +1810,7 @@
     params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glGetRenderbufferParameterivOES(
@@ -1877,16 +1855,16 @@
     GLuint *framebuffers = (GLuint *) 0;
 
     if (!framebuffers_ref) {
-        _env->ThrowNew(IAEClass, "framebuffers == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "framebuffers == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(framebuffers_ref) - offset;
     if (_remaining < n) {
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     framebuffers_base = (GLuint *)
@@ -1915,7 +1893,7 @@
 
     framebuffers = (GLuint *)getPointer(_env, framebuffers_buf, &_array, &_remaining);
     if (_remaining < n) {
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glDeleteFramebuffersOES(
@@ -1940,18 +1918,18 @@
 
     if (!framebuffers_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "framebuffers == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "framebuffers == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(framebuffers_ref) - offset;
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     framebuffers_base = (GLuint *)
@@ -1982,7 +1960,7 @@
     framebuffers = (GLuint *)getPointer(_env, framebuffers_buf, &_array, &_remaining);
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glGenFramebuffersOES(
@@ -2043,18 +2021,18 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLint *)
@@ -2087,7 +2065,7 @@
     params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glGetFramebufferAttachmentParameterivOES(
@@ -2221,11 +2199,11 @@
     GLfloat *equation = (GLfloat *) 0;
 
     if (!equation_ref) {
-        _env->ThrowNew(IAEClass, "equation == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "equation == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(equation_ref) - offset;
@@ -2274,18 +2252,18 @@
 
     if (!eqn_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "eqn == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "eqn == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(eqn_ref) - offset;
     if (_remaining < 4) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < 4");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 4");
         goto exit;
     }
     eqn_base = (GLfloat *)
@@ -2316,7 +2294,7 @@
     eqn = (GLfloat *)getPointer(_env, eqn_buf, &_array, &_remaining);
     if (_remaining < 4) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < 4");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 4");
         goto exit;
     }
     glGetClipPlanefOES(
@@ -2359,11 +2337,11 @@
     GLfloat *params = (GLfloat *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2423,11 +2401,11 @@
     GLint *params = (GLint *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2487,11 +2465,11 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2542,12 +2520,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2599,12 +2577,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2656,12 +2634,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp
index 7ac0f6e..a53e4d7 100644
--- a/core/jni/android_opengl_GLES20.cpp
+++ b/core/jni/android_opengl_GLES20.cpp
@@ -2,21 +2,23 @@
 **
 ** Copyright 2009, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 // This source file is automatically generated
 
+#include "jni.h"
+#include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 
@@ -28,10 +30,6 @@
 
 static jclass nioAccessClass;
 static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
 static jmethodID getBasePointerID;
 static jmethodID getBaseArrayID;
 static jmethodID getBaseArrayOffsetID;
@@ -42,7 +40,7 @@
 /* Cache method IDs each time the class is loaded. */
 
 static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
 {
     jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
     nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -64,26 +62,6 @@
 }
 
 
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
-    nativeClassInitBuffer(_env);
-
-    jclass IAEClassLocal =
-        _env->FindClass("java/lang/IllegalArgumentException");
-    jclass OOMEClassLocal =
-         _env->FindClass("java/lang/OutOfMemoryError");
-    jclass UOEClassLocal =
-         _env->FindClass("java/lang/UnsupportedOperationException");
-    jclass AIOOBEClassLocal =
-         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
-    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
-    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
-    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
-    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
 static void *
 getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
 {
@@ -104,13 +82,13 @@
         *array = NULL;
         return (void *) (jint) pointer;
     }
-    
+
     *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
             getBaseArrayID, buffer);
     offset = _env->CallStaticIntMethod(nioAccessClass,
             getBaseArrayOffsetID, buffer);
     data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-    
+
     return (void *) ((char *) data + offset);
 }
 
@@ -130,7 +108,8 @@
         jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
         buf += position << elementSizeShift;
     } else {
-        _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+        jniThrowException(_env, "java/lang/IllegalArgumentException",
+                          "Must use a native order direct Buffer");
     }
     return (void*) buf;
 }
@@ -148,7 +127,6 @@
 }
 
 // --------------------------------------------------------------------------
-
 /* void glActiveTexture ( GLenum texture ) */
 static void
 android_glActiveTexture__I
@@ -175,7 +153,7 @@
     const char* _nativename = 0;
 
     if (!name) {
-        _env->ThrowNew(IAEClass, "name == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "name == null");
         goto exit;
     }
     _nativename = _env->GetStringUTFChars(name, 0);
@@ -297,7 +275,7 @@
     if (data_buf) {
         data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
         if (_remaining < size) {
-            _env->ThrowNew(IAEClass, "remaining() < size");
+            jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < size");
             goto exit;
         }
     }
@@ -324,7 +302,7 @@
 
     data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
     if (_remaining < size) {
-        _env->ThrowNew(IAEClass, "remaining() < size");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < size");
         goto exit;
     }
     glBufferSubData(
@@ -530,16 +508,16 @@
     GLuint *buffers = (GLuint *) 0;
 
     if (!buffers_ref) {
-        _env->ThrowNew(IAEClass, "buffers == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "buffers == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(buffers_ref) - offset;
     if (_remaining < n) {
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     buffers_base = (GLuint *)
@@ -568,7 +546,7 @@
 
     buffers = (GLuint *)getPointer(_env, buffers_buf, &_array, &_remaining);
     if (_remaining < n) {
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glDeleteBuffers(
@@ -591,11 +569,11 @@
     GLuint *framebuffers = (GLuint *) 0;
 
     if (!framebuffers_ref) {
-        _env->ThrowNew(IAEClass, "framebuffers == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "framebuffers == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(framebuffers_ref) - offset;
@@ -651,11 +629,11 @@
     GLuint *renderbuffers = (GLuint *) 0;
 
     if (!renderbuffers_ref) {
-        _env->ThrowNew(IAEClass, "renderbuffers == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "renderbuffers == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(renderbuffers_ref) - offset;
@@ -711,16 +689,16 @@
     GLuint *textures = (GLuint *) 0;
 
     if (!textures_ref) {
-        _env->ThrowNew(IAEClass, "textures == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "textures == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(textures_ref) - offset;
     if (_remaining < n) {
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     textures_base = (GLuint *)
@@ -749,7 +727,7 @@
 
     textures = (GLuint *)getPointer(_env, textures_buf, &_array, &_remaining);
     if (_remaining < n) {
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glDeleteTextures(
@@ -852,7 +830,7 @@
 
     indices = (GLvoid *)getPointer(_env, indices_buf, &_array, &_remaining);
     if (_remaining < count) {
-        _env->ThrowNew(AIOOBEClass, "remaining() < count");
+        jniThrowException(_env, "java/lang/ArrayIndexOutOfBoundsException", "remaining() < count");
         goto exit;
     }
     glDrawElements(
@@ -945,18 +923,18 @@
 
     if (!buffers_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "buffers == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "buffers == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(buffers_ref) - offset;
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     buffers_base = (GLuint *)
@@ -987,7 +965,7 @@
     buffers = (GLuint *)getPointer(_env, buffers_buf, &_array, &_remaining);
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glGenBuffers(
@@ -1021,12 +999,12 @@
 
     if (!framebuffers_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "framebuffers == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "framebuffers == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(framebuffers_ref) - offset;
@@ -1076,12 +1054,12 @@
 
     if (!renderbuffers_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "renderbuffers == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "renderbuffers == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(renderbuffers_ref) - offset;
@@ -1131,18 +1109,18 @@
 
     if (!textures_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "textures == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "textures == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(textures_ref) - offset;
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     textures_base = (GLuint *)
@@ -1173,7 +1151,7 @@
     textures = (GLuint *)getPointer(_env, textures_buf, &_array, &_remaining);
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glGenTextures(
@@ -1207,12 +1185,12 @@
 
     if (!length_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length == null");
         goto exit;
     }
     if (lengthOffset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "lengthOffset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "lengthOffset < 0");
         goto exit;
     }
     _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
@@ -1222,12 +1200,12 @@
 
     if (!size_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "size == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "size == null");
         goto exit;
     }
     if (sizeOffset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "sizeOffset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "sizeOffset < 0");
         goto exit;
     }
     _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset;
@@ -1237,12 +1215,12 @@
 
     if (!type_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "type == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "type == null");
         goto exit;
     }
     if (typeOffset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "typeOffset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "typeOffset < 0");
         goto exit;
     }
     _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset;
@@ -1252,12 +1230,12 @@
 
     if (!name_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "name == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "name == null");
         goto exit;
     }
     if (nameOffset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "nameOffset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "nameOffset < 0");
         goto exit;
     }
     _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset;
@@ -1352,12 +1330,12 @@
 
     if (!length_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length == null");
         goto exit;
     }
     if (lengthOffset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "lengthOffset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "lengthOffset < 0");
         goto exit;
     }
     _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
@@ -1367,12 +1345,12 @@
 
     if (!size_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "size == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "size == null");
         goto exit;
     }
     if (sizeOffset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "sizeOffset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "sizeOffset < 0");
         goto exit;
     }
     _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset;
@@ -1382,12 +1360,12 @@
 
     if (!type_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "type == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "type == null");
         goto exit;
     }
     if (typeOffset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "typeOffset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "typeOffset < 0");
         goto exit;
     }
     _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset;
@@ -1397,12 +1375,12 @@
 
     if (!name_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "name == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "name == null");
         goto exit;
     }
     if (nameOffset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "nameOffset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "nameOffset < 0");
         goto exit;
     }
     _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset;
@@ -1491,12 +1469,12 @@
 
     if (!count_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "count == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "count == null");
         goto exit;
     }
     if (countOffset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "countOffset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "countOffset < 0");
         goto exit;
     }
     _countRemaining = _env->GetArrayLength(count_ref) - countOffset;
@@ -1506,12 +1484,12 @@
 
     if (!shaders_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "shaders == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "shaders == null");
         goto exit;
     }
     if (shadersOffset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "shadersOffset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "shadersOffset < 0");
         goto exit;
     }
     _shadersRemaining = _env->GetArrayLength(shaders_ref) - shadersOffset;
@@ -1573,7 +1551,7 @@
     const char* _nativename = 0;
 
     if (!name) {
-        _env->ThrowNew(IAEClass, "name == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "name == null");
         goto exit;
     }
     _nativename = _env->GetStringUTFChars(name, 0);
@@ -1602,12 +1580,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1657,18 +1635,18 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLint *)
@@ -1700,7 +1678,7 @@
     params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glGetBufferParameteriv(
@@ -1735,12 +1713,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1790,12 +1768,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1849,12 +1827,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2191,7 +2169,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLint *)
@@ -2553,7 +2531,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glGetIntegerv(
@@ -2578,12 +2556,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2624,32 +2602,24 @@
     }
 }
 
-#include <string.h>
+#include <stdlib.h>
 
 /* void glGetProgramInfoLog ( GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog ) */
-static
-jstring
-android_glGetProgramInfoLog (JNIEnv *_env, jobject _this, jint shader) {
+static jstring android_glGetProgramInfoLog(JNIEnv *_env, jobject, jint shader) {
     GLint infoLen = 0;
-    jstring _result = 0;
-    char* buf = 0;
     glGetProgramiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
-    if (infoLen) {
-        char* buf = (char*) malloc(infoLen);
-        if (buf == 0) {
-            _env->ThrowNew(IAEClass, "out of memory");
-            goto exit;
-        }
-        glGetProgramInfoLog(shader, infoLen, NULL, buf);
-        _result = _env->NewStringUTF(buf);
-    } else {
-        _result = _env->NewStringUTF("");
+    if (!infoLen) {
+        return _env->NewStringUTF("");
     }
-exit:
-    if (buf) {
-            free(buf);
+    char* buf = (char*) malloc(infoLen);
+    if (buf == NULL) {
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory");
+        return NULL;
     }
-    return _result;
+    glGetProgramInfoLog(shader, infoLen, NULL, buf);
+    jstring result = _env->NewStringUTF(buf);
+    free(buf);
+    return result;
 }
 /* void glGetRenderbufferParameteriv ( GLenum target, GLenum pname, GLint *params ) */
 static void
@@ -2662,12 +2632,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2719,12 +2689,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2765,32 +2735,24 @@
     }
 }
 
-#include <string.h>
+#include <stdlib.h>
 
 /* void glGetShaderInfoLog ( GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog ) */
-static
-jstring
-android_glGetShaderInfoLog (JNIEnv *_env, jobject _this, jint shader) {
+static jstring android_glGetShaderInfoLog(JNIEnv *_env, jobject, jint shader) {
     GLint infoLen = 0;
-    jstring _result = 0;
-    char* buf = 0;
     glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
-    if (infoLen) {
-        char* buf = (char*) malloc(infoLen);
-        if (buf == 0) {
-            _env->ThrowNew(IAEClass, "out of memory");
-            goto exit;
-        }
-        glGetShaderInfoLog(shader, infoLen, NULL, buf);
-        _result = _env->NewStringUTF(buf);
-    } else {
-        _result = _env->NewStringUTF("");
+    if (!infoLen) {
+        return _env->NewStringUTF("");
     }
-exit:
-    if (buf) {
-            free(buf);
+    char* buf = (char*) malloc(infoLen);
+    if (buf == NULL) {
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory");
+        return NULL;
     }
-    return _result;
+    glGetShaderInfoLog(shader, infoLen, NULL, buf);
+    jstring result = _env->NewStringUTF(buf);
+    free(buf);
+    return result;
 }
 /* void glGetShaderPrecisionFormat ( GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision ) */
 static void
@@ -2806,12 +2768,12 @@
 
     if (!range_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "range == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "range == null");
         goto exit;
     }
     if (rangeOffset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "rangeOffset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "rangeOffset < 0");
         goto exit;
     }
     _rangeRemaining = _env->GetArrayLength(range_ref) - rangeOffset;
@@ -2821,12 +2783,12 @@
 
     if (!precision_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "precision == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "precision == null");
         goto exit;
     }
     if (precisionOffset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "precisionOffset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "precisionOffset < 0");
         goto exit;
     }
     _precisionRemaining = _env->GetArrayLength(precision_ref) - precisionOffset;
@@ -2894,12 +2856,12 @@
 
     if (!length_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length == null");
         goto exit;
     }
     if (lengthOffset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "lengthOffset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "lengthOffset < 0");
         goto exit;
     }
     _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
@@ -2909,12 +2871,12 @@
 
     if (!source_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "source == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "source == null");
         goto exit;
     }
     if (sourceOffset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "sourceOffset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "sourceOffset < 0");
         goto exit;
     }
     _sourceRemaining = _env->GetArrayLength(source_ref) - sourceOffset;
@@ -2961,16 +2923,10 @@
     }
 }
 
-#include <string.h>
-
 /* const GLubyte * glGetString ( GLenum name ) */
-static
-jstring
-android_glGetString
-  (JNIEnv *_env, jobject _this, jint name) {
-    const char * chars = (const char *)glGetString((GLenum)name);
-    jstring output = _env->NewStringUTF(chars);
-    return output;
+static jstring android_glGetString(JNIEnv* _env, jobject, jint name) {
+    const char* chars = (const char*) glGetString((GLenum) name);
+    return _env->NewStringUTF(chars);
 }
 /* void glGetTexParameterfv ( GLenum target, GLenum pname, GLfloat *params ) */
 static void
@@ -2983,18 +2939,18 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -3026,7 +2982,7 @@
     params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glGetTexParameterfv(
@@ -3052,18 +3008,18 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLint *)
@@ -3095,7 +3051,7 @@
     params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glGetTexParameteriv(
@@ -3121,12 +3077,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -3178,12 +3134,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -3232,7 +3188,7 @@
     const char* _nativename = 0;
 
     if (!name) {
-        _env->ThrowNew(IAEClass, "name == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "name == null");
         goto exit;
     }
     _nativename = _env->GetStringUTFChars(name, 0);
@@ -3261,12 +3217,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -3318,12 +3274,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -3566,11 +3522,11 @@
     GLvoid *binary = (GLvoid *) 0;
 
     if (!shaders_ref) {
-        _env->ThrowNew(IAEClass, "shaders == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "shaders == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _shadersRemaining = _env->GetArrayLength(shaders_ref) - offset;
@@ -3633,7 +3589,7 @@
     (JNIEnv *_env, jobject _this, jint shader, jstring string) {
 
     if (!string) {
-        _env->ThrowNew(IAEClass, "string == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "string == null");
         return;
     }
 
@@ -3754,16 +3710,16 @@
     GLfloat *params = (GLfloat *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -3793,7 +3749,7 @@
 
     params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glTexParameterfv(
@@ -3828,16 +3784,16 @@
     GLint *params = (GLint *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLint *)
@@ -3867,7 +3823,7 @@
 
     params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glTexParameteriv(
@@ -3928,11 +3884,11 @@
     GLfloat *v = (GLfloat *) 0;
 
     if (!v_ref) {
-        _env->ThrowNew(IAEClass, "v == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "v == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(v_ref) - offset;
@@ -3991,11 +3947,11 @@
     GLint *v = (GLint *) 0;
 
     if (!v_ref) {
-        _env->ThrowNew(IAEClass, "v == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "v == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(v_ref) - offset;
@@ -4055,11 +4011,11 @@
     GLfloat *v = (GLfloat *) 0;
 
     if (!v_ref) {
-        _env->ThrowNew(IAEClass, "v == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "v == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(v_ref) - offset;
@@ -4119,11 +4075,11 @@
     GLint *v = (GLint *) 0;
 
     if (!v_ref) {
-        _env->ThrowNew(IAEClass, "v == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "v == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(v_ref) - offset;
@@ -4184,11 +4140,11 @@
     GLfloat *v = (GLfloat *) 0;
 
     if (!v_ref) {
-        _env->ThrowNew(IAEClass, "v == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "v == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(v_ref) - offset;
@@ -4249,11 +4205,11 @@
     GLint *v = (GLint *) 0;
 
     if (!v_ref) {
-        _env->ThrowNew(IAEClass, "v == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "v == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(v_ref) - offset;
@@ -4315,11 +4271,11 @@
     GLfloat *v = (GLfloat *) 0;
 
     if (!v_ref) {
-        _env->ThrowNew(IAEClass, "v == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "v == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(v_ref) - offset;
@@ -4381,11 +4337,11 @@
     GLint *v = (GLint *) 0;
 
     if (!v_ref) {
-        _env->ThrowNew(IAEClass, "v == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "v == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(v_ref) - offset;
@@ -4434,11 +4390,11 @@
     GLfloat *value = (GLfloat *) 0;
 
     if (!value_ref) {
-        _env->ThrowNew(IAEClass, "value == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "value == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(value_ref) - offset;
@@ -4489,11 +4445,11 @@
     GLfloat *value = (GLfloat *) 0;
 
     if (!value_ref) {
-        _env->ThrowNew(IAEClass, "value == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "value == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(value_ref) - offset;
@@ -4544,11 +4500,11 @@
     GLfloat *value = (GLfloat *) 0;
 
     if (!value_ref) {
-        _env->ThrowNew(IAEClass, "value == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "value == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(value_ref) - offset;
@@ -4627,11 +4583,11 @@
     GLfloat *values = (GLfloat *) 0;
 
     if (!values_ref) {
-        _env->ThrowNew(IAEClass, "values == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "values == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(values_ref) - offset;
@@ -4689,11 +4645,11 @@
     GLfloat *values = (GLfloat *) 0;
 
     if (!values_ref) {
-        _env->ThrowNew(IAEClass, "values == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "values == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(values_ref) - offset;
@@ -4752,11 +4708,11 @@
     GLfloat *values = (GLfloat *) 0;
 
     if (!values_ref) {
-        _env->ThrowNew(IAEClass, "values == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "values == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(values_ref) - offset;
@@ -4816,11 +4772,11 @@
     GLfloat *values = (GLfloat *) 0;
 
     if (!values_ref) {
-        _env->ThrowNew(IAEClass, "values == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "values == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(values_ref) - offset;
diff --git a/core/jni/android_os_FileUtils.cpp b/core/jni/android_os_FileUtils.cpp
index 2b4a955..89dce89 100644
--- a/core/jni/android_os_FileUtils.cpp
+++ b/core/jni/android_os_FileUtils.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 2006, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
@@ -145,7 +145,7 @@
 jboolean android_os_FileUtils_getFileStatus(JNIEnv* env, jobject clazz, jstring path, jobject fileStatus) {
     const char* pathStr = env->GetStringUTFChars(path, NULL);
     jboolean ret = false;
-    
+
     struct stat s;
     int res = stat(pathStr, &s);
     if (res == 0) {
@@ -165,9 +165,9 @@
             env->SetLongField(fileStatus, gFileStatusCtimeFieldID, s.st_ctime);
         }
     }
-    
+
     env->ReleaseStringUTFChars(path, pathStr);
-    
+
     return ret;
 }
 
@@ -183,11 +183,6 @@
 
 int register_android_os_FileUtils(JNIEnv* env)
 {
-    jclass clazz;
-
-    clazz = env->FindClass(kFileUtilsPathName);
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.FileUtils");
-    
     jclass fileStatusClass = env->FindClass("android/os/FileUtils$FileStatus");
     LOG_FATAL_IF(fileStatusClass == NULL, "Unable to find class android.os.FileUtils$FileStatus");
 
diff --git a/core/jni/android_os_MemoryFile.cpp b/core/jni/android_os_MemoryFile.cpp
index ee8d836..7134191 100644
--- a/core/jni/android_os_MemoryFile.cpp
+++ b/core/jni/android_os_MemoryFile.cpp
@@ -148,17 +148,10 @@
             (void*)android_os_MemoryFile_get_size}
 };
 
-static const char* const kClassPathName = "android/os/MemoryFile";
-
 int register_android_os_MemoryFile(JNIEnv* env)
 {
-    jclass clazz;
-
-    clazz = env->FindClass(kClassPathName);
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.FileUtils");
-
     return AndroidRuntime::registerNativeMethods(
-        env, kClassPathName,
+        env, "android/os/MemoryFile",
         methods, NELEM(methods));
 }
 
diff --git a/core/jni/android_os_ParcelFileDescriptor.cpp b/core/jni/android_os_ParcelFileDescriptor.cpp
index 1f737f9..4ec131c 100644
--- a/core/jni/android_os_ParcelFileDescriptor.cpp
+++ b/core/jni/android_os_ParcelFileDescriptor.cpp
@@ -29,43 +29,11 @@
 namespace android
 {
 
-static struct file_descriptor_offsets_t
-{
-    jclass mClass;
-    jmethodID mConstructor;
-    jfieldID mDescriptor;
-} gFileDescriptorOffsets;
-
-static struct socket_offsets_t
-{
-    jfieldID mSocketImpl;
-} gSocketOffsets;
-
-static struct socket_impl_offsets_t
-{
-    jfieldID mFileDescriptor;
-} gSocketImplOffsets;
-
 static struct parcel_file_descriptor_offsets_t
 {
-    jclass mClass;
     jfieldID mFileDescriptor;
 } gParcelFileDescriptorOffsets;
 
-static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromSocket(JNIEnv* env,
-    jobject clazz, jobject object)
-{
-    jobject socketImpl = env->GetObjectField(object, gSocketOffsets.mSocketImpl);
-    jobject fileDescriptor = env->GetObjectField(socketImpl, gSocketImplOffsets.mFileDescriptor);
-    jint fd = env->GetIntField(fileDescriptor, gFileDescriptorOffsets.mDescriptor);
-    jobject fileDescriptorClone = env->NewObject(gFileDescriptorOffsets.mClass,
-        gFileDescriptorOffsets.mConstructor);
-    if (fileDescriptorClone != NULL) {
-        env->SetIntField(fileDescriptorClone, gFileDescriptorOffsets.mDescriptor, dup(fd));
-    }
-    return fileDescriptorClone;
-}
-
 static int android_os_ParcelFileDescriptor_createPipeNative(JNIEnv* env,
     jobject clazz, jobjectArray outFds)
 {
@@ -75,11 +43,7 @@
     }
 
     for (int i=0; i<2; i++) {
-        jobject fdObj = env->NewObject(gFileDescriptorOffsets.mClass,
-                gFileDescriptorOffsets.mConstructor);
-        if (fdObj != NULL) {
-            env->SetIntField(fdObj, gFileDescriptorOffsets.mDescriptor, fds[i]);
-        }
+        jobject fdObj = jniCreateFileDescriptor(env, fds[i]);
         env->SetObjectArrayElement(outFds, i, fdObj);
     }
 
@@ -90,7 +54,7 @@
 {
     jobject descriptor = env->GetObjectField(clazz, gParcelFileDescriptorOffsets.mFileDescriptor);
     if (descriptor == NULL) return -1;
-    return env->GetIntField(descriptor, gFileDescriptorOffsets.mDescriptor);
+    return jniGetFDFromFileDescriptor(env, descriptor);
 }
 
 static jlong android_os_ParcelFileDescriptor_getStatSize(JNIEnv* env,
@@ -101,16 +65,16 @@
         jniThrowException(env, "java/lang/IllegalArgumentException", "bad file descriptor");
         return -1;
     }
-    
+
     struct stat st;
     if (fstat(fd, &st) != 0) {
         return -1;
     }
-    
+
     if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
         return st.st_size;
     }
-    
+
     return -1;
 }
 
@@ -122,7 +86,7 @@
         jniThrowException(env, "java/lang/IllegalArgumentException", "bad file descriptor");
         return -1;
     }
-    
+
     return lseek(fd, pos, SEEK_SET);
 }
 
@@ -138,8 +102,6 @@
 }
 
 static const JNINativeMethod gParcelFileDescriptorMethods[] = {
-    {"getFileDescriptorFromSocket", "(Ljava/net/Socket;)Ljava/io/FileDescriptor;",
-        (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromSocket},
     {"createPipeNative", "([Ljava/io/FileDescriptor;)I",
         (void*)android_os_ParcelFileDescriptor_createPipeNative},
     {"getStatSize", "()J",
@@ -154,31 +116,8 @@
 
 int register_android_os_ParcelFileDescriptor(JNIEnv* env)
 {
-    jclass clazz;
-
-    clazz = env->FindClass("java/net/Socket");
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.net.Socket");
-    gSocketOffsets.mSocketImpl = env->GetFieldID(clazz, "impl", "Ljava/net/SocketImpl;");
-    LOG_FATAL_IF(gSocketOffsets.mSocketImpl == NULL,
-        "Unable to find impl field in java.net.Socket");
-
-    clazz = env->FindClass("java/net/SocketImpl");
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.net.SocketImpl");
-    gSocketImplOffsets.mFileDescriptor = env->GetFieldID(clazz, "fd", "Ljava/io/FileDescriptor;");
-    LOG_FATAL_IF(gSocketImplOffsets.mFileDescriptor == NULL,
-                 "Unable to find fd field in java.net.SocketImpl");
-
-    clazz = env->FindClass("java/io/FileDescriptor");
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
-    gFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
-    gFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V");
-    gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I");
-    LOG_FATAL_IF(gFileDescriptorOffsets.mDescriptor == NULL,
-                 "Unable to find descriptor field in java.io.FileDescriptor");
-    
-    clazz = env->FindClass(kParcelFileDescriptorPathName);
+    jclass clazz = env->FindClass(kParcelFileDescriptorPathName);
     LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
-    gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
     gParcelFileDescriptorOffsets.mFileDescriptor = env->GetFieldID(clazz, "mFileDescriptor", "Ljava/io/FileDescriptor;");
     LOG_FATAL_IF(gParcelFileDescriptorOffsets.mFileDescriptor == NULL,
                  "Unable to find mFileDescriptor field in android.os.ParcelFileDescriptor");
diff --git a/core/jni/android_pim_EventRecurrence.cpp b/core/jni/android_pim_EventRecurrence.cpp
index 9056c90..44e898d 100644
--- a/core/jni/android_pim_EventRecurrence.cpp
+++ b/core/jni/android_pim_EventRecurrence.cpp
@@ -28,7 +28,6 @@
     jfieldID count;

 };

 

-static jclass clazz;

 static jfieldID freq_field;

 static jfieldID until_field;

 static jfieldID count_field;

@@ -87,8 +86,7 @@
         jniThrowNullPointerException(env, "EventRecurrence.parse str parameter null");

         return ;

     }

-    jboolean isCopy;

-    const jchar* jchars = env->GetStringChars(jstr, &isCopy);

+    const jchar* jchars = env->GetStringChars(jstr, NULL);

     jsize len = env->GetStringLength(jstr);

     String16 str(jchars, len);

     env->ReleaseStringChars(jstr, jchars);

@@ -156,7 +154,7 @@
 

 int register_android_pim_EventRecurrence(JNIEnv* env)

 {

-    clazz = env->FindClass(CLASS_NAME);

+    jclass clazz = env->FindClass(CLASS_NAME);

     if (clazz == NULL) {

         LOGE("Field lookup unable to find class '%s'\n", CLASS_NAME);

         return -1;

diff --git a/core/jni/android_text_AndroidBidi.cpp b/core/jni/android_text_AndroidBidi.cpp
index 53028c3..d50a69f 100644
--- a/core/jni/android_text_AndroidBidi.cpp
+++ b/core/jni/android_text_AndroidBidi.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 2010, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
@@ -24,8 +24,8 @@
 #include "unicode/ubidi.h"
 
 namespace android {
-    
-static jint runBidi(JNIEnv* env, jobject obj, jint dir, jcharArray chsArray, 
+
+static jint runBidi(JNIEnv* env, jobject obj, jint dir, jcharArray chsArray,
                     jbyteArray infoArray, int n, jboolean haveInfo)
 {
     // Parameters are checked on java side
@@ -63,9 +63,6 @@
 
 int register_android_text_AndroidBidi(JNIEnv* env)
 {
-    jclass clazz = env->FindClass("android/text/AndroidBidi");
-    LOG_ASSERT(clazz, "Cannot find android/text/AndroidBidi");
-    
     return AndroidRuntime::registerNativeMethods(env, "android/text/AndroidBidi",
             gMethods, NELEM(gMethods));
 }
diff --git a/core/jni/android_text_AndroidCharacter.cpp b/core/jni/android_text_AndroidCharacter.cpp
index 0d0f5fa..dacbe41 100644
--- a/core/jni/android_text_AndroidCharacter.cpp
+++ b/core/jni/android_text_AndroidCharacter.cpp
@@ -191,9 +191,6 @@
 
 int register_android_text_AndroidCharacter(JNIEnv* env)
 {
-    jclass clazz = env->FindClass("android/text/AndroidCharacter");
-    LOG_ASSERT(clazz, "Cannot find android/text/AndroidCharacter");
-
     return AndroidRuntime::registerNativeMethods(env, "android/text/AndroidCharacter",
             gMethods, NELEM(gMethods));
 }
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 8ea7e90..b0e92e4 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -169,7 +169,7 @@
 
     env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
 
-    jobject fileDesc = newFileDescriptor(env, fd);
+    jobject fileDesc = jniCreateFileDescriptor(env, fd);
     if (fileDesc == NULL) {
         close(fd);
         return NULL;
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 8618b79..0681195 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -131,13 +131,6 @@
     jmethodID mLogE;
 } gLogOffsets;
 
-static struct file_descriptor_offsets_t
-{
-    jclass mClass;
-    jmethodID mConstructor;
-    jfieldID mDescriptor;
-} gFileDescriptorOffsets;
-
 static struct parcel_file_descriptor_offsets_t
 {
     jclass mClass;
@@ -591,17 +584,6 @@
     return NULL;
 }
 
-jobject newFileDescriptor(JNIEnv* env, int fd)
-{
-    jobject object = env->NewObject(
-            gFileDescriptorOffsets.mClass, gFileDescriptorOffsets.mConstructor);
-    if (object != NULL) {
-        //LOGI("Created new FileDescriptor %p with fd %d\n", object, fd);
-        env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, fd);
-    }
-    return object;
-}
-
 jobject newParcelFileDescriptor(JNIEnv* env, jobject fileDesc)
 {
     return env->NewObject(
@@ -1358,8 +1340,8 @@
 {
     Parcel* parcel = parcelForJavaObject(env, clazz);
     if (parcel != NULL) {
-        const status_t err = parcel->writeDupFileDescriptor(
-                env->GetIntField(object, gFileDescriptorOffsets.mDescriptor));
+        const status_t err =
+                parcel->writeDupFileDescriptor(jniGetFDFromFileDescriptor(env, object));
         if (err != NO_ERROR) {
             jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
         }
@@ -1459,13 +1441,7 @@
         if (fd < 0) return NULL;
         fd = dup(fd);
         if (fd < 0) return NULL;
-        jobject object = env->NewObject(
-                gFileDescriptorOffsets.mClass, gFileDescriptorOffsets.mConstructor);
-        if (object != NULL) {
-            //LOGI("Created new FileDescriptor %p with fd %d\n", object, fd);
-            env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, fd);
-        }
-        return object;
+        return jniCreateFileDescriptor(env, fd);
     }
     return NULL;
 }
@@ -1512,7 +1488,7 @@
         jniThrowException(env, "java/io/FileNotFoundException", strerror(errno));
         return NULL;
     }
-    jobject object = newFileDescriptor(env, fd);
+    jobject object = jniCreateFileDescriptor(env, fd);
     if (object == NULL) {
         close(fd);
     }
@@ -1525,7 +1501,7 @@
         jniThrowNullPointerException(env, NULL);
         return NULL;
     }
-    int origfd = env->GetIntField(orig, gFileDescriptorOffsets.mDescriptor);
+    int origfd = jniGetFDFromFileDescriptor(env, orig);
     if (origfd < 0) {
         jniThrowException(env, "java/lang/IllegalArgumentException", "bad FileDescriptor");
         return NULL;
@@ -1536,7 +1512,7 @@
         jniThrowIOException(env, errno);
         return NULL;
     }
-    jobject object = newFileDescriptor(env, fd);
+    jobject object = jniCreateFileDescriptor(env, fd);
     if (object == NULL) {
         close(fd);
     }
@@ -1549,9 +1525,9 @@
         jniThrowNullPointerException(env, NULL);
         return;
     }
-    int fd = env->GetIntField(object, gFileDescriptorOffsets.mDescriptor);
+    int fd = jniGetFDFromFileDescriptor(env, object);
     if (fd >= 0) {
-        env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, -1);
+        jniSetFileDescriptorOfFD(env, object, -1);
         //LOGI("Closing ParcelFileDescriptor %d\n", fd);
         close(fd);
     }
@@ -1563,9 +1539,9 @@
         jniThrowNullPointerException(env, NULL);
         return;
     }
-    int fd = env->GetIntField(object, gFileDescriptorOffsets.mDescriptor);
+    int fd = jniGetFDFromFileDescriptor(env, object);
     if (fd >= 0) {
-        env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, -1);
+        jniSetFileDescriptorOfFD(env, object, -1);
     }
 }
 
@@ -1794,15 +1770,6 @@
         clazz, "e", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I");
     assert(gLogOffsets.mLogE);
 
-    clazz = env->FindClass("java/io/FileDescriptor");
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
-    gFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
-    gFileDescriptorOffsets.mConstructor
-        = env->GetMethodID(clazz, "<init>", "()V");
-    gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I");
-    LOG_FATAL_IF(gFileDescriptorOffsets.mDescriptor == NULL,
-                 "Unable to find descriptor field in java.io.FileDescriptor");
-
     clazz = env->FindClass("android/os/ParcelFileDescriptor");
     LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
     gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
@@ -1842,13 +1809,3 @@
         return -1;
     return 0;
 }
-
-namespace android {
-
-// Returns the Unix file descriptor for a ParcelFileDescriptor object
-int getParcelFileDescriptorFD(JNIEnv* env, jobject object)
-{
-    return env->GetIntField(object, gFileDescriptorOffsets.mDescriptor);
-}
-
-}
diff --git a/core/jni/android_util_Binder.h b/core/jni/android_util_Binder.h
index 495e76a..0122691 100644
--- a/core/jni/android_util_Binder.h
+++ b/core/jni/android_util_Binder.h
@@ -2,16 +2,16 @@
 **
 ** Copyright 2006, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
@@ -29,7 +29,6 @@
 // Note: does not type checking; must guarantee jobject is a Java Parcel
 extern Parcel* parcelForJavaObject(JNIEnv* env, jobject obj);
 
-extern jobject newFileDescriptor(JNIEnv* env, int fd);
 extern jobject newParcelFileDescriptor(JNIEnv* env, jobject fileDesc);
 
 }
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 91d37d3..5d51110 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -35,9 +35,6 @@
 static jclass gIntegerClass;
 static jfieldID gIntegerValueID;
 
-static jclass gListClass;
-static jfieldID gListItemsID;
-
 static jclass gLongClass;
 static jfieldID gLongValueID;
 
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 0068de7..e5c28489 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -103,17 +103,6 @@
     }
 }
 
-
-static void fakeProcessEntry(void* arg)
-{
-    String8* cls = (String8*)arg;
-
-    AndroidRuntime* jr = AndroidRuntime::getRuntime();
-    jr->callMain(cls->string(), 0, NULL);
-
-    delete cls;
-}
-
 jint android_os_Process_myPid(JNIEnv* env, jobject clazz)
 {
     return getpid();
@@ -915,11 +904,6 @@
 
 int register_android_os_Process(JNIEnv* env)
 {
-    jclass clazz;
-
-    clazz = env->FindClass(kProcessPathName);
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Process");
-
     return AndroidRuntime::registerNativeMethods(
         env, kProcessPathName,
         methods, NELEM(methods));
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index f31bba9..314c2ee 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -595,13 +595,11 @@
 // Logging
 // ----------------------------------------------------------------------------
 
-jfieldID gFileDescriptorField;
-
 static void
 android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor)
 {
 #ifdef USE_OPENGL_RENDERER
-    int fd = env->GetIntField(javaFileDescriptor, gFileDescriptorField);
+    int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
     android::uirenderer::DisplayList::outputLogBuffer(fd);
 #endif // USE_OPENGL_RENDERER
 }
@@ -736,12 +734,6 @@
 
 int register_android_app_ActivityThread(JNIEnv* env)
 {
-    jclass fileDescriptorClass = env->FindClass("java/io/FileDescriptor");
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
-    gFileDescriptorField = env->GetFieldID(fileDescriptorClass, "descriptor", "I");
-    LOG_FATAL_IF(gFileDescriptorField == NULL,
-                 "Unable to find descriptor field in java.io.FileDescriptor");
-
     return AndroidRuntime::registerNativeMethods(
             env, kActivityThreadPathName,
             gActivityThreadMethods, NELEM(gActivityThreadMethods));
diff --git a/core/jni/com_android_internal_graphics_NativeUtils.cpp b/core/jni/com_android_internal_graphics_NativeUtils.cpp
index 319946f..9cc43606 100644
--- a/core/jni/com_android_internal_graphics_NativeUtils.cpp
+++ b/core/jni/com_android_internal_graphics_NativeUtils.cpp
@@ -29,11 +29,6 @@
 namespace android
 {
 
-static jclass class_fileDescriptor;
-static jfieldID field_fileDescriptor_descriptor;
-static jmethodID method_fileDescriptor_init;
-
-
 static jboolean scrollRect(JNIEnv* env, jobject graphics2D, jobject canvas, jobject rect, int dx, int dy) {
     if (canvas == NULL) {
         jniThrowNullPointerException(env, NULL);
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 61efcf2..5f2065a 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -29,9 +29,6 @@
 
 namespace android {
 
-static jclass gDisplay_class;
-static jclass gContext_class;
-static jclass gSurface_class;
 static jclass gConfig_class;
 
 static jmethodID gConfig_ctorID;
@@ -44,21 +41,6 @@
 static jfieldID gSurface_SurfaceFieldID;
 static jfieldID gBitmap_NativeBitmapFieldID;
 
-static __attribute__((noinline))
-bool hasException(JNIEnv *env) {
-    if (env->ExceptionCheck() != 0) {
-        env->ExceptionDescribe();
-        return true;
-    }
-    return false;
-}
-
-static __attribute__((noinline))
-jclass make_globalref(JNIEnv* env, const char classname[]) {
-    jclass c = env->FindClass(classname);
-    return (jclass)env->NewGlobalRef(c);
-}
-
 static inline EGLDisplay getDisplay(JNIEnv* env, jobject o) {
     if (!o) return EGL_NO_DISPLAY;
     return (EGLDisplay)env->GetIntField(o, gDisplay_EGLDisplayFieldID);
@@ -77,18 +59,20 @@
 }
 static void nativeClassInit(JNIEnv *_env, jclass eglImplClass)
 {
-    gDisplay_class = make_globalref(_env, "com/google/android/gles_jni/EGLDisplayImpl");
-    gContext_class = make_globalref(_env, "com/google/android/gles_jni/EGLContextImpl");
-    gSurface_class = make_globalref(_env, "com/google/android/gles_jni/EGLSurfaceImpl");
-    gConfig_class  = make_globalref(_env, "com/google/android/gles_jni/EGLConfigImpl");
+    jclass config_class = _env->FindClass("com/google/android/gles_jni/EGLConfigImpl");
+    gConfig_class = (jclass) _env->NewGlobalRef(config_class);
+    gConfig_ctorID = _env->GetMethodID(gConfig_class,  "<init>", "(I)V");
+    gConfig_EGLConfigFieldID = _env->GetFieldID(gConfig_class,  "mEGLConfig",  "I");
 
-    gConfig_ctorID  = _env->GetMethodID(gConfig_class,  "<init>", "(I)V");
+    jclass display_class = _env->FindClass("com/google/android/gles_jni/EGLDisplayImpl");
+    gDisplay_EGLDisplayFieldID = _env->GetFieldID(display_class, "mEGLDisplay", "I");
 
-    gDisplay_EGLDisplayFieldID = _env->GetFieldID(gDisplay_class, "mEGLDisplay", "I");
-    gContext_EGLContextFieldID = _env->GetFieldID(gContext_class, "mEGLContext", "I");
-    gSurface_EGLSurfaceFieldID = _env->GetFieldID(gSurface_class, "mEGLSurface", "I");
-    gSurface_NativePixelRefFieldID = _env->GetFieldID(gSurface_class, "mNativePixelRef", "I");
-    gConfig_EGLConfigFieldID   = _env->GetFieldID(gConfig_class,  "mEGLConfig",  "I");
+    jclass context_class = _env->FindClass("com/google/android/gles_jni/EGLContextImpl");
+    gContext_EGLContextFieldID = _env->GetFieldID(context_class, "mEGLContext", "I");
+
+    jclass surface_class = _env->FindClass("com/google/android/gles_jni/EGLSurfaceImpl");
+    gSurface_EGLSurfaceFieldID = _env->GetFieldID(surface_class, "mEGLSurface", "I");
+    gSurface_NativePixelRefFieldID = _env->GetFieldID(surface_class, "mNativePixelRef", "I");
 
     jclass bitmap_class = _env->FindClass("android/graphics/Bitmap");
     gBitmap_NativeBitmapFieldID = _env->GetFieldID(bitmap_class, "mNativeBitmap", "I");
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index bf613e1..8777131 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -2,21 +2,23 @@
 **
 ** Copyright 2006, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 // This source file is automatically generated
 
+#include "jni.h"
+#include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 
@@ -64,10 +66,6 @@
 
 static jclass nioAccessClass;
 static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
 static jclass G11ImplClass;
 static jmethodID getBasePointerID;
 static jmethodID getBaseArrayID;
@@ -85,7 +83,7 @@
 /* Cache method IDs each time the class is loaded. */
 
 static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
 {
     jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
     nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -115,26 +113,6 @@
         _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
 }
 
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
-    nativeClassInitBuffer(_env);
-
-    jclass IAEClassLocal =
-        _env->FindClass("java/lang/IllegalArgumentException");
-    jclass OOMEClassLocal =
-         _env->FindClass("java/lang/OutOfMemoryError");
-    jclass UOEClassLocal =
-         _env->FindClass("java/lang/UnsupportedOperationException");
-    jclass AIOOBEClassLocal =
-         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
-    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
-    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
-    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
-    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
 static void *
 getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
 {
@@ -155,7 +133,7 @@
         *array = NULL;
         return (void *) (jint) pointer;
     }
-    
+
     *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
             getBaseArrayID, buffer);
     if (*array == NULL) {
@@ -164,7 +142,7 @@
     offset = _env->CallStaticIntMethod(nioAccessClass,
             getBaseArrayOffsetID, buffer);
     data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-    
+
     return (void *) ((char *) data + offset);
 }
 
@@ -208,7 +186,8 @@
                 releasePointer(_env, array, buf, 0);
             }
         } else {
-            _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+            jniThrowException(_env, "java/lang/IllegalArgumentException",
+                              "Must use a native order direct Buffer");
         }
     }
     return buf;
@@ -251,7 +230,7 @@
         }
     }
 }
-    
+
 static bool
 checkForExtension(const GLubyte* pExtensions, const GLubyte* pExtension) {
     for (;*pExtensions != '\0'; pExtensions = nextExtension(pExtensions)) {
@@ -280,7 +259,6 @@
 }
 
 // --------------------------------------------------------------------------
-
 /* void glActiveTexture ( GLenum texture ) */
 static void
 android_glActiveTexture__I
@@ -557,16 +535,16 @@
     GLuint *textures = (GLuint *) 0;
 
     if (!textures_ref) {
-        _env->ThrowNew(IAEClass, "textures == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "textures == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(textures_ref) - offset;
     if (_remaining < n) {
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     textures_base = (GLuint *)
@@ -595,7 +573,7 @@
 
     textures = (GLuint *)getPointer(_env, textures_buf, &_array, &_remaining);
     if (_remaining < n) {
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glDeleteTextures(
@@ -686,7 +664,7 @@
 
     indices = (GLvoid *)getPointer(_env, indices_buf, &_array, &_remaining);
     if (_remaining < count) {
-        _env->ThrowNew(AIOOBEClass, "remaining() < count");
+        jniThrowException(_env, "java/lang/ArrayIndexOutOfBoundsException", "remaining() < count");
         goto exit;
     }
     glDrawElements(
@@ -753,11 +731,11 @@
     GLfloat *params = (GLfloat *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -787,7 +765,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -841,7 +819,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glFogfv(
@@ -874,11 +852,11 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -908,7 +886,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -962,7 +940,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glFogxv(
@@ -1024,18 +1002,18 @@
 
     if (!textures_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "textures == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "textures == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(textures_ref) - offset;
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     textures_base = (GLuint *)
@@ -1066,7 +1044,7 @@
     textures = (GLuint *)getPointer(_env, textures_buf, &_array, &_remaining);
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glGenTextures(
@@ -1100,12 +1078,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1442,7 +1420,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLint *)
@@ -1804,7 +1782,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glGetIntegerv(
@@ -1818,16 +1796,10 @@
     }
 }
 
-#include <string.h>
-
 /* const GLubyte * glGetString ( GLenum name ) */
-static
-jstring
-android_glGetString
-  (JNIEnv *_env, jobject _this, jint name) {
-    const char * chars = (const char *)glGetString((GLenum)name);
-    jstring output = _env->NewStringUTF(chars);
-    return output;
+static jstring android_glGetString(JNIEnv *_env, jobject, jint name) {
+    const char* chars = (const char*) glGetString((GLenum) name);
+    return _env->NewStringUTF(chars);
 }
 /* void glHint ( GLenum target, GLenum mode ) */
 static void
@@ -1858,11 +1830,11 @@
     GLfloat *params = (GLfloat *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1883,7 +1855,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -1928,7 +1900,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glLightModelfv(
@@ -1961,11 +1933,11 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1986,7 +1958,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -2031,7 +2003,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glLightModelxv(
@@ -2065,11 +2037,11 @@
     GLfloat *params = (GLfloat *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2116,7 +2088,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -2188,7 +2160,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glLightfv(
@@ -2223,11 +2195,11 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2274,7 +2246,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -2346,7 +2318,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glLightxv(
@@ -2395,11 +2367,11 @@
     GLfloat *m = (GLfloat *) 0;
 
     if (!m_ref) {
-        _env->ThrowNew(IAEClass, "m == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(m_ref) - offset;
@@ -2444,11 +2416,11 @@
     GLfixed *m = (GLfixed *) 0;
 
     if (!m_ref) {
-        _env->ThrowNew(IAEClass, "m == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(m_ref) - offset;
@@ -2513,11 +2485,11 @@
     GLfloat *params = (GLfloat *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2550,7 +2522,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -2608,7 +2580,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glMaterialfv(
@@ -2643,11 +2615,11 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2680,7 +2652,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -2738,7 +2710,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glMaterialxv(
@@ -2771,11 +2743,11 @@
     GLfloat *m = (GLfloat *) 0;
 
     if (!m_ref) {
-        _env->ThrowNew(IAEClass, "m == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(m_ref) - offset;
@@ -2820,11 +2792,11 @@
     GLfixed *m = (GLfixed *) 0;
 
     if (!m_ref) {
-        _env->ThrowNew(IAEClass, "m == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(m_ref) - offset;
@@ -3205,11 +3177,11 @@
     GLfloat *params = (GLfloat *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -3236,7 +3208,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -3288,7 +3260,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glTexEnvfv(
@@ -3323,11 +3295,11 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -3354,7 +3326,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -3406,7 +3378,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glTexEnvxv(
@@ -3569,18 +3541,18 @@
 
     if (!mantissa_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "mantissa == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "mantissa == null");
         goto exit;
     }
     if (mantissaOffset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "mantissaOffset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "mantissaOffset < 0");
         goto exit;
     }
     _mantissaRemaining = _env->GetArrayLength(mantissa_ref) - mantissaOffset;
     if (_mantissaRemaining < 16) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - mantissaOffset < 16");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - mantissaOffset < 16");
         goto exit;
     }
     mantissa_base = (GLfixed *)
@@ -3589,18 +3561,18 @@
 
     if (!exponent_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "exponent == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "exponent == null");
         goto exit;
     }
     if (exponentOffset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "exponentOffset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "exponentOffset < 0");
         goto exit;
     }
     _exponentRemaining = _env->GetArrayLength(exponent_ref) - exponentOffset;
     if (_exponentRemaining < 16) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - exponentOffset < 16");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - exponentOffset < 16");
         goto exit;
     }
     exponent_base = (GLint *)
@@ -3640,13 +3612,13 @@
     mantissa = (GLfixed *)getPointer(_env, mantissa_buf, &_mantissaArray, &_mantissaRemaining);
     if (_mantissaRemaining < 16) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < 16");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 16");
         goto exit;
     }
     exponent = (GLint *)getPointer(_env, exponent_buf, &_exponentArray, &_exponentRemaining);
     if (_exponentRemaining < 16) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < 16");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 16");
         goto exit;
     }
     _returnValue = glQueryMatrixxOES(
@@ -3685,7 +3657,7 @@
     if (data_buf) {
         data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
         if (_remaining < size) {
-            _env->ThrowNew(IAEClass, "remaining() < size");
+            jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < size");
             goto exit;
         }
     }
@@ -3712,7 +3684,7 @@
 
     data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
     if (_remaining < size) {
-        _env->ThrowNew(IAEClass, "remaining() < size");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < size");
         goto exit;
     }
     glBufferSubData(
@@ -3737,16 +3709,16 @@
     GLfloat *equation = (GLfloat *) 0;
 
     if (!equation_ref) {
-        _env->ThrowNew(IAEClass, "equation == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "equation == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(equation_ref) - offset;
     if (_remaining < 4) {
-        _env->ThrowNew(IAEClass, "length - offset < 4");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 4");
         goto exit;
     }
     equation_base = (GLfloat *)
@@ -3775,7 +3747,7 @@
 
     equation = (GLfloat *)getPointer(_env, equation_buf, &_array, &_remaining);
     if (_remaining < 4) {
-        _env->ThrowNew(IAEClass, "remaining() < 4");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 4");
         goto exit;
     }
     glClipPlanef(
@@ -3798,16 +3770,16 @@
     GLfixed *equation = (GLfixed *) 0;
 
     if (!equation_ref) {
-        _env->ThrowNew(IAEClass, "equation == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "equation == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(equation_ref) - offset;
     if (_remaining < 4) {
-        _env->ThrowNew(IAEClass, "length - offset < 4");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 4");
         goto exit;
     }
     equation_base = (GLfixed *)
@@ -3836,7 +3808,7 @@
 
     equation = (GLfixed *)getPointer(_env, equation_buf, &_array, &_remaining);
     if (_remaining < 4) {
-        _env->ThrowNew(IAEClass, "remaining() < 4");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 4");
         goto exit;
     }
     glClipPlanex(
@@ -3883,16 +3855,16 @@
     GLuint *buffers = (GLuint *) 0;
 
     if (!buffers_ref) {
-        _env->ThrowNew(IAEClass, "buffers == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "buffers == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(buffers_ref) - offset;
     if (_remaining < n) {
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     buffers_base = (GLuint *)
@@ -3921,7 +3893,7 @@
 
     buffers = (GLuint *)getPointer(_env, buffers_buf, &_array, &_remaining);
     if (_remaining < n) {
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glDeleteBuffers(
@@ -3958,18 +3930,18 @@
 
     if (!buffers_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "buffers == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "buffers == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(buffers_ref) - offset;
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     buffers_base = (GLuint *)
@@ -4000,7 +3972,7 @@
     buffers = (GLuint *)getPointer(_env, buffers_buf, &_array, &_remaining);
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glGenBuffers(
@@ -4025,12 +3997,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -4073,7 +4045,7 @@
 static void
 android_glGetBufferParameteriv__II_3II
   (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
-    _env->ThrowNew(UOEClass,
+    jniThrowException(_env, "java/lang/UnsupportedOperationException",
         "glGetBufferParameteriv");
 }
 
@@ -4081,7 +4053,7 @@
 static void
 android_glGetBufferParameteriv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
-    _env->ThrowNew(UOEClass,
+    jniThrowException(_env, "java/lang/UnsupportedOperationException",
         "glGetBufferParameteriv");
 }
 
@@ -4096,12 +4068,12 @@
 
     if (!eqn_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "eqn == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "eqn == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(eqn_ref) - offset;
@@ -4151,12 +4123,12 @@
 
     if (!eqn_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "eqn == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "eqn == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(eqn_ref) - offset;
@@ -4206,12 +4178,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -4261,12 +4233,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -4316,12 +4288,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -4369,7 +4341,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -4443,7 +4415,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glGetLightfv(
@@ -4469,12 +4441,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -4522,7 +4494,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -4596,7 +4568,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glGetLightxv(
@@ -4622,12 +4594,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -4661,7 +4633,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -4721,7 +4693,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glGetMaterialfv(
@@ -4747,12 +4719,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -4786,7 +4758,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -4846,7 +4818,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glGetMaterialxv(
@@ -4872,12 +4844,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -4905,7 +4877,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLint *)
@@ -4959,7 +4931,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glGetTexEnviv(
@@ -4985,12 +4957,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -5018,7 +4990,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -5072,7 +5044,7 @@
     }
     if (_remaining < _needed) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glGetTexEnvxv(
@@ -5098,18 +5070,18 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -5141,7 +5113,7 @@
     params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glGetTexParameterfv(
@@ -5167,18 +5139,18 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLint *)
@@ -5210,7 +5182,7 @@
     params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glGetTexParameteriv(
@@ -5236,18 +5208,18 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -5279,7 +5251,7 @@
     params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glGetTexParameterxv(
@@ -5357,16 +5329,16 @@
     GLfloat *params = (GLfloat *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -5395,7 +5367,7 @@
 
     params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glPointParameterfv(
@@ -5428,16 +5400,16 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -5466,7 +5438,7 @@
 
     params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glPointParameterxv(
@@ -5534,11 +5506,11 @@
     GLint *params = (GLint *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -5565,7 +5537,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "length - offset < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
         goto exit;
     }
     params_base = (GLint *)
@@ -5617,7 +5589,7 @@
             break;
     }
     if (_remaining < _needed) {
-        _env->ThrowNew(IAEClass, "remaining() < needed");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
         goto exit;
     }
     glTexEnviv(
@@ -5641,16 +5613,16 @@
     GLfloat *params = (GLfloat *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLfloat *)
@@ -5680,7 +5652,7 @@
 
     params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glTexParameterfv(
@@ -5715,16 +5687,16 @@
     GLint *params = (GLint *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLint *)
@@ -5754,7 +5726,7 @@
 
     params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glTexParameteriv(
@@ -5778,16 +5750,16 @@
     GLfixed *params = (GLfixed *) 0;
 
     if (!params_ref) {
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "length - offset < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
         goto exit;
     }
     params_base = (GLfixed *)
@@ -5817,7 +5789,7 @@
 
     params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
     if (_remaining < 1) {
-        _env->ThrowNew(IAEClass, "remaining() < 1");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
         goto exit;
     }
     glTexParameterxv(
@@ -5875,16 +5847,16 @@
     GLfloat *coords = (GLfloat *) 0;
 
     if (!coords_ref) {
-        _env->ThrowNew(IAEClass, "coords == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "coords == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(coords_ref) - offset;
     if (_remaining < 5) {
-        _env->ThrowNew(IAEClass, "length - offset < 5");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 5");
         goto exit;
     }
     coords_base = (GLfloat *)
@@ -5912,7 +5884,7 @@
 
     coords = (GLfloat *)getPointer(_env, coords_buf, &_array, &_remaining);
     if (_remaining < 5) {
-        _env->ThrowNew(IAEClass, "remaining() < 5");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 5");
         goto exit;
     }
     glDrawTexfvOES(
@@ -5947,16 +5919,16 @@
     GLint *coords = (GLint *) 0;
 
     if (!coords_ref) {
-        _env->ThrowNew(IAEClass, "coords == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "coords == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(coords_ref) - offset;
     if (_remaining < 5) {
-        _env->ThrowNew(IAEClass, "length - offset < 5");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 5");
         goto exit;
     }
     coords_base = (GLint *)
@@ -5984,7 +5956,7 @@
 
     coords = (GLint *)getPointer(_env, coords_buf, &_array, &_remaining);
     if (_remaining < 5) {
-        _env->ThrowNew(IAEClass, "remaining() < 5");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 5");
         goto exit;
     }
     glDrawTexivOES(
@@ -6019,16 +5991,16 @@
     GLshort *coords = (GLshort *) 0;
 
     if (!coords_ref) {
-        _env->ThrowNew(IAEClass, "coords == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "coords == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(coords_ref) - offset;
     if (_remaining < 5) {
-        _env->ThrowNew(IAEClass, "length - offset < 5");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 5");
         goto exit;
     }
     coords_base = (GLshort *)
@@ -6056,7 +6028,7 @@
 
     coords = (GLshort *)getPointer(_env, coords_buf, &_array, &_remaining);
     if (_remaining < 5) {
-        _env->ThrowNew(IAEClass, "remaining() < 5");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 5");
         goto exit;
     }
     glDrawTexsvOES(
@@ -6091,16 +6063,16 @@
     GLfixed *coords = (GLfixed *) 0;
 
     if (!coords_ref) {
-        _env->ThrowNew(IAEClass, "coords == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "coords == null");
         goto exit;
     }
     if (offset < 0) {
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(coords_ref) - offset;
     if (_remaining < 5) {
-        _env->ThrowNew(IAEClass, "length - offset < 5");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 5");
         goto exit;
     }
     coords_base = (GLfixed *)
@@ -6128,7 +6100,7 @@
 
     coords = (GLfixed *)getPointer(_env, coords_buf, &_array, &_remaining);
     if (_remaining < 5) {
-        _env->ThrowNew(IAEClass, "remaining() < 5");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 5");
         goto exit;
     }
     glDrawTexxvOES(
@@ -6223,7 +6195,7 @@
 android_glBindFramebufferOES__II
   (JNIEnv *_env, jobject _this, jint target, jint framebuffer) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glBindFramebufferOES");
             return;
     }
@@ -6238,7 +6210,7 @@
 android_glBindRenderbufferOES__II
   (JNIEnv *_env, jobject _this, jint target, jint renderbuffer) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glBindRenderbufferOES");
             return;
     }
@@ -6253,7 +6225,7 @@
 android_glBlendEquation__I
   (JNIEnv *_env, jobject _this, jint mode) {
     if (! supportsExtension(_env, _this, have_OES_blend_subtractID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glBlendEquation");
             return;
     }
@@ -6267,7 +6239,7 @@
 android_glBlendEquationSeparate__II
   (JNIEnv *_env, jobject _this, jint modeRGB, jint modeAlpha) {
     if (! supportsExtension(_env, _this, have_OES_blend_equation_separateID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glBlendEquationSeparate");
             return;
     }
@@ -6282,7 +6254,7 @@
 android_glBlendFuncSeparate__IIII
   (JNIEnv *_env, jobject _this, jint srcRGB, jint dstRGB, jint srcAlpha, jint dstAlpha) {
     if (! supportsExtension(_env, _this, have_OES_blend_equation_separateID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glBlendFuncSeparate");
             return;
     }
@@ -6299,7 +6271,7 @@
 android_glCheckFramebufferStatusOES__I
   (JNIEnv *_env, jobject _this, jint target) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glCheckFramebufferStatusOES");
             return 0;
     }
@@ -6315,7 +6287,7 @@
 android_glDeleteFramebuffersOES__I_3II
   (JNIEnv *_env, jobject _this, jint n, jintArray framebuffers_ref, jint offset) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glDeleteFramebuffersOES");
             return;
     }
@@ -6326,18 +6298,18 @@
 
     if (!framebuffers_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "framebuffers == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "framebuffers == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(framebuffers_ref) - offset;
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     framebuffers_base = (GLuint *)
@@ -6361,7 +6333,7 @@
 android_glDeleteFramebuffersOES__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint n, jobject framebuffers_buf) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glDeleteFramebuffersOES");
             return;
     }
@@ -6373,7 +6345,7 @@
     framebuffers = (GLuint *)getPointer(_env, framebuffers_buf, &_array, &_remaining);
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glDeleteFramebuffersOES(
@@ -6392,7 +6364,7 @@
 android_glDeleteRenderbuffersOES__I_3II
   (JNIEnv *_env, jobject _this, jint n, jintArray renderbuffers_ref, jint offset) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glDeleteRenderbuffersOES");
             return;
     }
@@ -6403,18 +6375,18 @@
 
     if (!renderbuffers_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "renderbuffers == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "renderbuffers == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(renderbuffers_ref) - offset;
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     renderbuffers_base = (GLuint *)
@@ -6438,7 +6410,7 @@
 android_glDeleteRenderbuffersOES__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint n, jobject renderbuffers_buf) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glDeleteRenderbuffersOES");
             return;
     }
@@ -6450,7 +6422,7 @@
     renderbuffers = (GLuint *)getPointer(_env, renderbuffers_buf, &_array, &_remaining);
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glDeleteRenderbuffersOES(
@@ -6469,7 +6441,7 @@
 android_glFramebufferRenderbufferOES__IIII
   (JNIEnv *_env, jobject _this, jint target, jint attachment, jint renderbuffertarget, jint renderbuffer) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glFramebufferRenderbufferOES");
             return;
     }
@@ -6486,7 +6458,7 @@
 android_glFramebufferTexture2DOES__IIIII
   (JNIEnv *_env, jobject _this, jint target, jint attachment, jint textarget, jint texture, jint level) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glFramebufferTexture2DOES");
             return;
     }
@@ -6504,7 +6476,7 @@
 android_glGenerateMipmapOES__I
   (JNIEnv *_env, jobject _this, jint target) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glGenerateMipmapOES");
             return;
     }
@@ -6518,7 +6490,7 @@
 android_glGenFramebuffersOES__I_3II
   (JNIEnv *_env, jobject _this, jint n, jintArray framebuffers_ref, jint offset) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glGenFramebuffersOES");
             return;
     }
@@ -6529,18 +6501,18 @@
 
     if (!framebuffers_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "framebuffers == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "framebuffers == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(framebuffers_ref) - offset;
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     framebuffers_base = (GLuint *)
@@ -6564,7 +6536,7 @@
 android_glGenFramebuffersOES__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint n, jobject framebuffers_buf) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glGenFramebuffersOES");
             return;
     }
@@ -6576,7 +6548,7 @@
     framebuffers = (GLuint *)getPointer(_env, framebuffers_buf, &_array, &_remaining);
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glGenFramebuffersOES(
@@ -6595,7 +6567,7 @@
 android_glGenRenderbuffersOES__I_3II
   (JNIEnv *_env, jobject _this, jint n, jintArray renderbuffers_ref, jint offset) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glGenRenderbuffersOES");
             return;
     }
@@ -6606,18 +6578,18 @@
 
     if (!renderbuffers_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "renderbuffers == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "renderbuffers == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(renderbuffers_ref) - offset;
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "length - offset < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
         goto exit;
     }
     renderbuffers_base = (GLuint *)
@@ -6641,7 +6613,7 @@
 android_glGenRenderbuffersOES__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint n, jobject renderbuffers_buf) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glGenRenderbuffersOES");
             return;
     }
@@ -6653,7 +6625,7 @@
     renderbuffers = (GLuint *)getPointer(_env, renderbuffers_buf, &_array, &_remaining);
     if (_remaining < n) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "remaining() < n");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
         goto exit;
     }
     glGenRenderbuffersOES(
@@ -6672,7 +6644,7 @@
 android_glGetFramebufferAttachmentParameterivOES__III_3II
   (JNIEnv *_env, jobject _this, jint target, jint attachment, jint pname, jintArray params_ref, jint offset) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glGetFramebufferAttachmentParameterivOES");
             return;
     }
@@ -6683,12 +6655,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -6715,7 +6687,7 @@
 android_glGetFramebufferAttachmentParameterivOES__IIILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint attachment, jint pname, jobject params_buf) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glGetFramebufferAttachmentParameterivOES");
             return;
     }
@@ -6741,7 +6713,7 @@
 android_glGetRenderbufferParameterivOES__II_3II
   (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glGetRenderbufferParameterivOES");
             return;
     }
@@ -6752,12 +6724,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -6783,7 +6755,7 @@
 android_glGetRenderbufferParameterivOES__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glGetRenderbufferParameterivOES");
             return;
     }
@@ -6808,7 +6780,7 @@
 android_glGetTexGenfv__II_3FI
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jfloatArray params_ref, jint offset) {
     if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glGetTexGenfv");
             return;
     }
@@ -6819,12 +6791,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -6850,7 +6822,7 @@
 android_glGetTexGenfv__IILjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
     if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glGetTexGenfv");
             return;
     }
@@ -6875,7 +6847,7 @@
 android_glGetTexGeniv__II_3II
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) {
     if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glGetTexGeniv");
             return;
     }
@@ -6886,12 +6858,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -6917,7 +6889,7 @@
 android_glGetTexGeniv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
     if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glGetTexGeniv");
             return;
     }
@@ -6942,7 +6914,7 @@
 android_glGetTexGenxv__II_3II
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) {
     if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glGetTexGenxv");
             return;
     }
@@ -6953,12 +6925,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -6984,7 +6956,7 @@
 android_glGetTexGenxv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
     if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glGetTexGenxv");
             return;
     }
@@ -7009,7 +6981,7 @@
 android_glIsFramebufferOES__I
   (JNIEnv *_env, jobject _this, jint framebuffer) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glIsFramebufferOES");
             return JNI_FALSE;
     }
@@ -7025,7 +6997,7 @@
 android_glIsRenderbufferOES__I
   (JNIEnv *_env, jobject _this, jint renderbuffer) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glIsRenderbufferOES");
             return JNI_FALSE;
     }
@@ -7041,7 +7013,7 @@
 android_glRenderbufferStorageOES__IIII
   (JNIEnv *_env, jobject _this, jint target, jint internalformat, jint width, jint height) {
     if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glRenderbufferStorageOES");
             return;
     }
@@ -7058,7 +7030,7 @@
 android_glTexGenf__IIF
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jfloat param) {
     if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glTexGenf");
             return;
     }
@@ -7074,7 +7046,7 @@
 android_glTexGenfv__II_3FI
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jfloatArray params_ref, jint offset) {
     if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glTexGenfv");
             return;
     }
@@ -7085,12 +7057,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -7116,7 +7088,7 @@
 android_glTexGenfv__IILjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
     if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glTexGenfv");
             return;
     }
@@ -7141,7 +7113,7 @@
 android_glTexGeni__III
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jint param) {
     if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glTexGeni");
             return;
     }
@@ -7157,7 +7129,7 @@
 android_glTexGeniv__II_3II
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) {
     if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glTexGeniv");
             return;
     }
@@ -7168,12 +7140,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -7199,7 +7171,7 @@
 android_glTexGeniv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
     if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glTexGeniv");
             return;
     }
@@ -7224,7 +7196,7 @@
 android_glTexGenx__III
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jint param) {
     if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glTexGenx");
             return;
     }
@@ -7240,7 +7212,7 @@
 android_glTexGenxv__II_3II
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) {
     if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glTexGenxv");
             return;
     }
@@ -7251,12 +7223,12 @@
 
     if (!params_ref) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "params == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
         goto exit;
     }
     if (offset < 0) {
         _exception = 1;
-        _env->ThrowNew(IAEClass, "offset < 0");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
         goto exit;
     }
     _remaining = _env->GetArrayLength(params_ref) - offset;
@@ -7282,7 +7254,7 @@
 android_glTexGenxv__IILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
     if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
-        _env->ThrowNew(UOEClass,
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
             "glTexGenxv");
             return;
     }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2a4d1b2..7f18121 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -607,6 +607,13 @@
         android:label="@string/permlab_reorderTasks"
         android:description="@string/permdesc_reorderTasks" />
 
+    <!-- Allows an application to change to remove/kill tasks -->
+    <permission android:name="android.permission.REMOVE_TASKS"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="signature"
+        android:label="@string/permlab_removeTasks"
+        android:description="@string/permdesc_removeTasks" />
+
     <!-- Allows an application to modify the current configuration, such
          as locale. -->
     <permission android:name="android.permission.CHANGE_CONFIGURATION"
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 80beaa5..9b04f78 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1169,6 +1169,10 @@
              component specific values). -->
         <attr name="enabled" />
         <attr name="exported" />
+        <!-- If set to true, this service with be automatically stopped
+             when the user remove a task rooted in an activity owned by
+             the application.  The default is false. -->
+        <attr name="stopWithTask" format="boolean" />
     </declare-styleable>
     
     <!-- The <code>receiver</code> tag declares an
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index d5c374d..778d934 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1656,6 +1656,7 @@
   <public type="attr" name="state_hovered" />
   <public type="attr" name="state_drag_can_accept" />
   <public type="attr" name="state_drag_hovered" />
+  <public type="attr" name="stopWithTask" />
 
   <public type="style" name="Theme.Holo.Light.NoActionBar" />
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8ef9a3b..bc419ec 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -506,6 +506,13 @@
         tasks to the foreground and background. Malicious applications can force
         themselves to the front without your control.</string>
 
+    <!-- Title of an application permission, allowing an application to remove/kill tasks -->
+    <string name="permlab_removeTasks">stop running applications</string>
+    <!-- Description of an application permission, allowing an application to remove/kill tasks -->
+    <string name="permdesc_removeTasks">Allows an application to remove
+        tasks and kill their applications. Malicious applications can disrupt
+        the behavior of other applications.</string>
+
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_setDebugApp">enable application debugging</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
index 3667c7b..d22356d 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
@@ -182,6 +182,7 @@
                 }
                 config.proxySettings = ProxySettings.NONE;
                 networks.add(config);
+                mLinkProperties = null;
             }
         }
 
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
index e138200..adf1883c8 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
@@ -242,10 +242,10 @@
 
         initializeNetworkStates();
 
-        if (mWifiManager.isWifiEnabled()) {
-            log("Clear Wifi before we start the test.");
-            removeConfiguredNetworksAndDisableWifi();
-        }
+        mWifiManager.setWifiEnabled(true);
+        log("Clear Wifi before we start the test.");
+        sleep(SHORT_TIMEOUT);
+        removeConfiguredNetworksAndDisableWifi();
         mWifiRegexs = mCM.getTetherableWifiRegexs();
      }
 
@@ -633,13 +633,13 @@
      * Disconnect from the current AP and remove configured networks.
      */
     public boolean disconnectAP() {
-        if (mWifiManager.isWifiEnabled()) {
-            // remove saved networks
-            List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks();
-            for (WifiConfiguration wifiConfig: wifiConfigList) {
-                log("remove wifi configuration: " + wifiConfig.toString());
-                mWifiManager.forgetNetwork(wifiConfig.networkId);
-            }
+        // remove saved networks
+        List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks();
+        log("size of wifiConfigList: " + wifiConfigList.size());
+        for (WifiConfiguration wifiConfig: wifiConfigList) {
+            log("remove wifi configuration: " + wifiConfig.networkId);
+            int netId = wifiConfig.networkId;
+            mWifiManager.forgetNetwork(netId);
         }
         return true;
     }
@@ -655,20 +655,23 @@
      * Remove configured networks and disable wifi
      */
     public boolean removeConfiguredNetworksAndDisableWifi() {
-            if (!disconnectAP()) {
-                return false;
-            }
-            // Disable Wifi
-            if (!mWifiManager.setWifiEnabled(false)) {
-                return false;
-            }
-            // Wait for the actions to be completed
-            try {
-                Thread.sleep(SHORT_TIMEOUT);
-            } catch (InterruptedException e) {}
+        if (!disconnectAP()) {
+           return false;
+        }
+        sleep(SHORT_TIMEOUT);
+        if (!mWifiManager.setWifiEnabled(false)) {
+            return false;
+        }
+        sleep(SHORT_TIMEOUT);
         return true;
     }
 
+    private void sleep(long sleeptime) {
+        try {
+            Thread.sleep(sleeptime);
+        } catch (InterruptedException e) {}
+    }
+
     /**
      * Set airplane mode
      */
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
index fe79e6c..22b1759 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
@@ -72,10 +72,8 @@
     @Override
     public void setUp() throws Exception {
         super.setUp();
-        log("before we launch the test activity, we preserve all the configured networks.");
         mRunner = ((ConnectivityManagerTestRunner)getInstrumentation());
         mWifiManager = (WifiManager) mRunner.getContext().getSystemService(Context.WIFI_SERVICE);
-        enabledNetworks = getEnabledNetworks(mWifiManager.getConfiguredNetworks());
 
         mAct = getActivity();
         mWifiManager.asyncConnect(mAct, new WifiServiceHandler());
@@ -123,42 +121,9 @@
     public void tearDown() throws Exception {
         log("tearDown()");
         mAct.removeConfiguredNetworksAndDisableWifi();
-        reEnableNetworks(enabledNetworks);
         super.tearDown();
     }
 
-    private Set<WifiConfiguration> getEnabledNetworks(List<WifiConfiguration> configuredNetworks) {
-        Set<WifiConfiguration> networks = new HashSet<WifiConfiguration>();
-        for (WifiConfiguration wifiConfig : configuredNetworks) {
-            if (wifiConfig.status == Status.ENABLED || wifiConfig.status == Status.CURRENT) {
-                networks.add(wifiConfig);
-                log("remembering enabled network " + wifiConfig.SSID +
-                        " status is " + wifiConfig.status);
-            }
-        }
-        return networks;
-    }
-
-    private void reEnableNetworks(Set<WifiConfiguration> enabledNetworks) {
-        if (!mWifiManager.isWifiEnabled()) {
-            log("reEnableNetworks: enable Wifi");
-            mWifiManager.setWifiEnabled(true);
-            sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT,
-                    "interruped while waiting for wifi to be enabled");
-        }
-
-        for (WifiConfiguration config : enabledNetworks) {
-            if (DEBUG) {
-                log("recover wifi configuration: " + config.toString());
-            }
-            config.SSID = "\"" + config.SSID + "\"";
-            config.networkId = -1;
-            mWifiManager.connectNetwork(config);
-            sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT,
-                    "interruped while connecting to " + config.SSID);
-        }
-    }
-
     /**
      * Connect to the provided Wi-Fi network
      * @param config is the network configuration
diff --git a/core/tests/overlaytests/Android.mk b/core/tests/overlaytests/Android.mk
new file mode 100644
index 0000000..bf69442
--- /dev/null
+++ b/core/tests/overlaytests/Android.mk
@@ -0,0 +1,4 @@
+# Dummy makefile to halt recursive directory traversal.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
diff --git a/core/tests/overlaytests/OverlayTest/Android.mk b/core/tests/overlaytests/OverlayTest/Android.mk
new file mode 100644
index 0000000..f7f67f6
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_PACKAGE_NAME := OverlayTest
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/OverlayTest/AndroidManifest.xml b/core/tests/overlaytests/OverlayTest/AndroidManifest.xml
new file mode 100644
index 0000000..9edba12
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/AndroidManifest.xml
@@ -0,0 +1,10 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.overlaytest">
+    <uses-permission android:name="android.permission.RUN_INSTRUMENTATION"/>
+    <application>
+        <uses-library android:name="android.test.runner"/>
+    </application>
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+        android:targetPackage="com.android.overlaytest"
+        android:label="Runtime resource overlay tests"/>
+</manifest>
diff --git a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
new file mode 100644
index 0000000..85b49ce
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
@@ -0,0 +1,118 @@
+package com.android.overlaytest;
+
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.test.AndroidTestCase;
+import java.io.InputStream;
+import java.util.Locale;
+
+public abstract class OverlayBaseTest extends AndroidTestCase {
+    private Resources mResources;
+    protected boolean mWithOverlay; // will be set by subclasses
+
+    protected void setUp() {
+        mResources = getContext().getResources();
+    }
+
+    private int calculateRawResourceChecksum(int resId) throws Throwable {
+        InputStream input = null;
+        try {
+            input = mResources.openRawResource(resId);
+            int ch, checksum = 0;
+            while ((ch = input.read()) != -1) {
+                checksum = (checksum + ch) % 0xffddbb00;
+            }
+            return checksum;
+        } finally {
+            input.close();
+        }
+    }
+
+    private void setLocale(String code) {
+        Locale locale = new Locale(code);
+        Locale.setDefault(locale);
+        Configuration config = new Configuration();
+        config.locale = locale;
+        mResources.updateConfiguration(config, mResources.getDisplayMetrics());
+    }
+
+    private void assertResource(int resId, boolean ewo, boolean ew) throws Throwable {
+        boolean expected = mWithOverlay ? ew : ewo;
+        boolean actual = mResources.getBoolean(resId);
+        assertEquals(expected, actual);
+    }
+
+    private void assertResource(int resId, String ewo, String ew) throws Throwable {
+        String expected = mWithOverlay ? ew : ewo;
+        String actual = mResources.getString(resId);
+        assertEquals(expected, actual);
+    }
+
+    private void assertResource(int resId, int[] ewo, int[] ew) throws Throwable {
+        int[] expected = mWithOverlay ? ew : ewo;
+        int[] actual = mResources.getIntArray(resId);
+        assertEquals("length:", expected.length, actual.length);
+        for (int i = 0; i < actual.length; ++i) {
+            assertEquals("index " + i + ":", actual[i], expected[i]);
+        }
+    }
+
+    public void testBooleanOverlay() throws Throwable {
+        // config_automatic_brightness_available has overlay (default config)
+        final int resId = com.android.internal.R.bool.config_automatic_brightness_available;
+        assertResource(resId, false, true);
+    }
+
+    public void testBoolean() throws Throwable {
+        // config_bypass_keyguard_if_slider_open has no overlay
+        final int resId = com.android.internal.R.bool.config_bypass_keyguard_if_slider_open;
+        assertResource(resId, true, true);
+    }
+
+    public void testStringOverlay() throws Throwable {
+        // phoneTypeCar has an overlay (default config), which shouldn't shadow
+        // the Swedish translation
+        final int resId = com.android.internal.R.string.phoneTypeCar;
+        setLocale("sv_SE");
+        assertResource(resId, "Bil", "Bil");
+    }
+
+    public void testStringSwedishOverlay() throws Throwable {
+        // phoneTypeWork has overlay (no default config, only for lang=sv)
+        final int resId = com.android.internal.R.string.phoneTypeWork;
+        setLocale("en_US");
+        assertResource(resId, "Work", "Work");
+        setLocale("sv_SE");
+        assertResource(resId, "Arbete", "Jobb");
+    }
+
+    public void testString() throws Throwable {
+        // phoneTypeHome has no overlay
+        final int resId = com.android.internal.R.string.phoneTypeHome;
+        setLocale("en_US");
+        assertResource(resId, "Home", "Home");
+        setLocale("sv_SE");
+        assertResource(resId, "Hem", "Hem");
+    }
+
+    public void testIntegerArrayOverlay() throws Throwable {
+        // config_scrollBarrierVibePattern has overlay (default config)
+        final int resId = com.android.internal.R.array.config_scrollBarrierVibePattern;
+        assertResource(resId, new int[]{0, 15, 10, 10}, new int[]{100, 200, 300});
+    }
+
+    public void testIntegerArray() throws Throwable {
+        // config_virtualKeyVibePattern has no overlay
+        final int resId = com.android.internal.R.array.config_virtualKeyVibePattern;
+        final int[] expected = {0, 10, 20, 30};
+        assertResource(resId, expected, expected);
+    }
+
+    public void testAsset() throws Throwable {
+        // drawable/default_background.jpg has overlay (default config)
+        final int resId = com.android.internal.R.drawable.default_wallpaper;
+        int actual = calculateRawResourceChecksum(resId);
+        int expected = mWithOverlay ? 0x000051da : 0x0014ebce;
+        assertEquals(expected, actual);
+    }
+}
diff --git a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java
new file mode 100644
index 0000000..1292d03
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java
@@ -0,0 +1,7 @@
+package com.android.overlaytest;
+
+public class WithOverlayTest extends OverlayBaseTest {
+    public WithOverlayTest() {
+        mWithOverlay = true;
+    }
+}
diff --git a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java
new file mode 100644
index 0000000..630ff8f
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java
@@ -0,0 +1,7 @@
+package com.android.overlaytest;
+
+public class WithoutOverlayTest extends OverlayBaseTest {
+    public WithoutOverlayTest() {
+        mWithOverlay = false;
+    }
+}
diff --git a/core/tests/overlaytests/OverlayTestOverlay/Android.mk b/core/tests/overlaytests/OverlayTestOverlay/Android.mk
new file mode 100644
index 0000000..cf32c9f
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTestOverlay/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := com.android.overlaytest.overlay
+
+LOCAL_AAPT_FLAGS := -o
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/OverlayTestOverlay/AndroidManifest.xml b/core/tests/overlaytests/OverlayTestOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..bcbb0d1
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTestOverlay/AndroidManifest.xml
@@ -0,0 +1,6 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.overlaytest.overlay"
+        android:versionCode="1"
+        android:versionName="1.0">
+    <overlay-package android:name="android"/>
+</manifest>
diff --git a/core/tests/overlaytests/OverlayTestOverlay/res/drawable/default_wallpaper.jpg b/core/tests/overlaytests/OverlayTestOverlay/res/drawable/default_wallpaper.jpg
new file mode 100644
index 0000000..0d944d0
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTestOverlay/res/drawable/default_wallpaper.jpg
Binary files differ
diff --git a/core/tests/overlaytests/OverlayTestOverlay/res/values-sv/config.xml b/core/tests/overlaytests/OverlayTestOverlay/res/values-sv/config.xml
new file mode 100644
index 0000000..bc52367
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTestOverlay/res/values-sv/config.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="phoneTypeWork">Jobb</string>
+</resources>
diff --git a/core/tests/overlaytests/OverlayTestOverlay/res/values/config.xml b/core/tests/overlaytests/OverlayTestOverlay/res/values/config.xml
new file mode 100644
index 0000000..794f475
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTestOverlay/res/values/config.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <bool name="config_automatic_brightness_available">true</bool>
+    <string name="phoneTypeCar">Automobile</string>
+    <integer-array name="config_scrollBarrierVibePattern">
+        <item>100</item>
+        <item>200</item>
+        <item>300</item>
+    </integer-array>
+    <!-- The following integer does not exist in the original package. Idmap
+         generation should therefore ignore it. -->
+    <integer name="integer_not_in_original_package">0</integer>
+</resources>
diff --git a/core/tests/overlaytests/README b/core/tests/overlaytests/README
new file mode 100644
index 0000000..4b3e6f2
--- /dev/null
+++ b/core/tests/overlaytests/README
@@ -0,0 +1,15 @@
+Unit tests for runtime resource overlay
+=======================================
+
+As of this writing, runtime resource overlay is only triggered for
+/system/framework/framework-res.apk. Because of this, installation of
+overlay packages require the Android platform be rebooted. However, the
+regular unit tests (triggered via development/testrunner/runtest.py)
+cannot handle reboots. As a workaround, this directory contains a shell
+script which will trigger the tests in a non-standard way.
+
+Once runtime resource overlay may be applied to applications, the tests
+in this directory should be moved to core/tests/coretests. Also, by
+applying runtime resource overlay to a dedicated test application, the
+test cases would not need to assume default values for non-overlaid
+resources.
diff --git a/core/tests/overlaytests/runtests.sh b/core/tests/overlaytests/runtests.sh
new file mode 100755
index 0000000..0ad9efb
--- /dev/null
+++ b/core/tests/overlaytests/runtests.sh
@@ -0,0 +1,89 @@
+#!/bin/bash
+
+adb="adb"
+if [[ $# -gt 0 ]]; then
+	adb="adb $*" # for setting -e, -d or -s <serial>
+fi
+
+function atexit()
+{
+	local retval=$?
+
+	if [[ $retval -eq 0 ]]; then
+		rm $log
+	else
+		echo "There were errors, please check log at $log"
+	fi
+}
+
+log=$(mktemp)
+trap "atexit" EXIT
+failures=0
+
+function compile_module()
+{
+	local android_mk="$1"
+
+	echo "Compiling .${android_mk:${#PWD}}"
+	ONE_SHOT_MAKEFILE="$android_mk" make -C "../../../../../" files | tee -a $log
+	if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
+		exit 1
+	fi
+}
+
+function wait_for_boot_completed()
+{
+	echo "Rebooting device"
+	$adb wait-for-device logcat -c
+	$adb wait-for-device logcat | grep -m 1 -e 'PowerManagerService.*bootCompleted' >/dev/null
+}
+
+function disable_overlay()
+{
+	echo "Disabling overlay"
+	$adb shell rm /vendor/overlay/framework/framework-res.apk
+	$adb shell rm /data/resource-cache/vendor@overlay@framework@framework-res.apk@idmap
+}
+
+function enable_overlay()
+{
+	echo "Enabling overlay"
+	$adb shell ln -s /data/app/com.android.overlaytest.overlay.apk /vendor/overlay/framework/framework-res.apk
+}
+
+function instrument()
+{
+	local class="$1"
+
+	echo "Instrumenting $class"
+	$adb shell am instrument -w -e class $class com.android.overlaytest/android.test.InstrumentationTestRunner | tee -a $log
+}
+
+function sync()
+{
+	echo "Syncing to device"
+	$adb remount | tee -a $log
+	$adb sync data | tee -a $log
+}
+
+# build and sync
+compile_module "$PWD/OverlayTest/Android.mk"
+compile_module "$PWD/OverlayTestOverlay/Android.mk"
+sync
+
+# instrument test (without overlay)
+$adb shell stop
+disable_overlay
+$adb shell start
+wait_for_boot_completed
+instrument "com.android.overlaytest.WithoutOverlayTest"
+
+# instrument test (with overlay)
+$adb shell stop
+enable_overlay
+$adb shell start
+wait_for_boot_completed
+instrument "com.android.overlaytest.WithOverlayTest"
+
+# cleanup
+exit $(grep -c -e '^FAILURES' $log)
diff --git a/docs/html/guide/developing/tools/logcat.jd b/docs/html/guide/developing/tools/logcat.jd
index d4ee68a..546e3ea 100644
--- a/docs/html/guide/developing/tools/logcat.jd
+++ b/docs/html/guide/developing/tools/logcat.jd
@@ -2,7 +2,6 @@
 parent.title=Tools
 parent.link=index.html
 @jd:body
-<div></div>
 
   <p>The Android logging system provides a mechanism for collecting and viewing system debug
   output. Logs from various applications and portions of the system are collected in a series of
@@ -23,7 +22,7 @@
 
   <p>You can run <code>logcat</code> as an adb command or directly in a shell prompt
   of your emulator or connected device. To view log output using adb, navigate to your SDK
-  <code>platform-tools/</code> directory and execute:/p>
+  <code>platform-tools/</code> directory and execute:</p>
   <pre>
 $ adb logcat
 </pre>
diff --git a/docs/html/guide/market/billing/billing_admin.jd b/docs/html/guide/market/billing/billing_admin.jd
index 723113d..939bbaa 100755
--- a/docs/html/guide/market/billing/billing_admin.jd
+++ b/docs/html/guide/market/billing/billing_admin.jd
@@ -97,7 +97,7 @@
 
 <img src="{@docRoot}images/billing_list_form.png" height="840" id="figure3" />
 <p class="img-caption">
-  f<strong>Figure 3.</strong> The Create New In-app Product page lets you add items to an
+  <strong>Figure 3.</strong> The Create New In-app Product page lets you add items to an
   application's product list.
 </p>
 
diff --git a/docs/html/guide/market/billing/billing_integrate.jd b/docs/html/guide/market/billing/billing_integrate.jd
index f57ebe3..59344ba 100755
--- a/docs/html/guide/market/billing/billing_integrate.jd
+++ b/docs/html/guide/market/billing/billing_integrate.jd
@@ -163,11 +163,11 @@
 <p>When the download is complete, the Android SDK and AVD Manager saves the component into the
 following directory:</p>
 
-<p><code>&lt;sdk&gt;/google-market_billing/</code></p>
+<p><code>&lt;sdk&gt;/extras/google/market_billing/</code></p>
 
 <p>If you want to see an end-to-end demonstration of in-app billing before you integrate in-app
 billing into your own application, you can build and run the sample application. Building and
-running the sample application involves three tasks:<p>
+running the sample application involves three tasks:</p>
 
 <ul>
   <li>Configuring and building the sample application.</li>
@@ -501,7 +501,7 @@
 
 <p>To use this helper method, you pass in a <code>String</code> that corresponds to one of the five
 types of billing requests. The method returns a Bundle that has the three required keys defined. The
-following sections show you how to use this helper method when you send a billing request.<p>
+following sections show you how to use this helper method when you send a billing request.</p>
 
 <p class="caution"><strong>Important</strong>: You must make all in-app billing requests from your
 application's main thread.</p>
diff --git a/docs/html/guide/practices/design/accessibility.jd b/docs/html/guide/practices/design/accessibility.jd
index a2b314e..a66a974 100644
--- a/docs/html/guide/practices/design/accessibility.jd
+++ b/docs/html/guide/practices/design/accessibility.jd
@@ -60,8 +60,9 @@
 <li>Make all of your user interface controls accessible with a trackball or directional
 controller (d-pad).</li>
 <li>Label your {@link android.widget.ImageButton}, {@link android.widget.EditText}, and other input
-widgets using the <a href="{@docRoot}reference/android/view/View#attr_android:contentDescription"
->{@code android:contentDescription}</a> attribute.</li>
+widgets using the <a
+href="{@docRoot}reference/android/view/View.html#attr_android:contentDescription">{@code
+android:contentDescription}</a> attribute.</li>
 </ul>
 
 
@@ -100,8 +101,9 @@
 </ul>
 
 <p>When working with a view that is not focusable by default, you can make it focusable from the XML
-layout file by setting the <a href="{@docRoot}reference/android/view/View#attr_android:focusable"
->{@code android:focusable}</a> attribute to {@code "true"}.</p>
+layout file by setting the <a
+href="{@docRoot}reference/android/view/View.html#attr_android:focusable">{@code
+android:focusable}</a> attribute to {@code "true"}.</p>
 
 
 
@@ -181,13 +183,13 @@
 application, these visual cues are often useless.</p>
 
 <p>To provide textual information about these widgets (as an alternative to the visual cues), you
-should use the <a href="{@docRoot}reference/android/view/View#attr_android:contentDescription"
+should use the <a href="{@docRoot}reference/android/view/View.html#attr_android:contentDescription"
 >{@code android:contentDescription}</a> attribute. The text you provide in this attribute
 is not visible on the screen, but if a user has enabled accessibility speech tools then the
 description in this attribute is read aloud to the user.</p>
 
 <p>You should set the <a
-href="{@docRoot}reference/android/view/View#attr_android:contentDescription" >{@code
+href="{@docRoot}reference/android/view/View.html#attr_android:contentDescription" >{@code
 android:contentDescription}</a> attribute on every {@link android.widget.ImageButton}, {@link
 android.widget.EditText}, {@link android.widget.CheckBox}, and on any other input widgets that might
 benefit users with extra information.</p>
diff --git a/docs/html/guide/practices/design/jni.jd b/docs/html/guide/practices/design/jni.jd
new file mode 100644
index 0000000..3e9ddc4
--- /dev/null
+++ b/docs/html/guide/practices/design/jni.jd
@@ -0,0 +1,715 @@
+page.title=JNI Tips
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+<ol>
+  <li><a href="#what">What is JNI?</a></li>
+  <li><a href="#JavaVM_and_JNIEnv">JavaVM and JNIEnv</a></li>
+  <li><a href="#threads">Threads</a></li>
+  <li><a href="#jclass_jmethodID_and_jfieldID">jclass, jmethodID, and jfieldID</a></li>
+  <li><a href="#local_and_global_references">Local and Global References</a></li>
+  <li><a href="#UTF_8_and_UTF_16_strings">UTF-8 and UTF-16 Strings</a></li>
+  <li><a href="#arrays">Primitive Arrays</a></li>
+  <li><a href="#region_calls">Region Calls</a></li>
+  <li><a href="#exceptions">Exceptions</a></li>
+  <li><a href="#extended_checking">Extended Checking</a> </li>
+  <li><a href="#native_libraries">Native Libraries</a></li>
+  <li><a href="#64_bit">64-bit Considerations</a></li>
+  <li><a href="#unsupported">Unsupported Features</a></li>
+  <li><a href="#faq_ULE">FAQ: UnsatisfiedLinkError</a></li>
+  <li><a href="#faq_FindClass">FAQ: FindClass didn't find my class</a></li>
+  <li><a href="#faq_sharing">FAQ: Sharing raw data with native code</a></li>
+</ol>
+
+</div>
+</div>
+
+<a name="what_is_jni" id="what_is_jni"></a>
+<h2>What is JNI?</h2>
+
+<p>JNI is the Java Native Interface.  It defines a way for code written in the
+Java programming language to interact with native
+code, e.g. functions written in C/C++.  It's VM-neutral, has support for loading code from
+dynamic shared libraries, and while cumbersome at times is reasonably efficient.</p>
+
+<p>You really should read through the
+<a href="http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html">JNI spec for J2SE 6</a>
+to get a sense for how JNI works and what features are available.  Some
+aspects of the interface aren't immediately obvious on
+first reading, so you may find the next few sections handy.
+The more detailed <i>JNI Programmer's Guide and Specification</i> can be found
+<a href="http://java.sun.com/docs/books/jni/html/jniTOC.html">here</a>.</p>
+
+
+<a name="JavaVM_and_JNIEnv" id="JavaVM_and_JNIEnv"></a>
+<h2>JavaVM and JNIEnv</h2>
+
+<p>JNI defines two key data structures, "JavaVM" and "JNIEnv".  Both of these are essentially
+pointers to pointers to function tables.  (In the C++ version, they're classes with a
+pointer to a function table and a member function for each JNI function that indirects through
+the table.)  The JavaVM provides the "invocation interface" functions,
+which allow you to create and destroy the VM.  In theory you can have multiple VMs per process,
+but Android's VM only allows one.</p>
+
+<p>The JNIEnv provides most of the JNI functions.  Your native functions all receive a JNIEnv as
+the first argument.</p>
+
+<p>On some VMs, the JNIEnv is used for thread-local storage.  For this reason, <strong>you cannot share a JNIEnv between threads</strong>.
+If a piece of code has no other way to get its JNIEnv, you should share
+the JavaVM, and use JavaVM-&gt;GetEnv to discover the thread's JNIEnv. (Assuming it has one; see <code>AttachCurrentThread</code> below.)</p>
+
+<p>The C declarations of JNIEnv and JavaVM are different from the C++
+declarations.  "jni.h" provides different typedefs
+depending on whether it's included into ".c" or ".cpp".  For this reason it's a bad idea to
+include JNIEnv arguments in header files included by both languages.  (Put another way: if your
+header file requires "#ifdef __cplusplus", you may have to do some extra work if anything in
+that header refers to JNIEnv.)</p>
+
+<a name="threads" id="threads"></a>
+<h2>Threads</h2>
+
+<p>All VM threads are Linux threads, scheduled by the kernel.  They're usually
+started using Java language features (notably <code>Thread.start()</code>),
+but they can also be created elsewhere and then attached to the VM.  For
+example, a thread started with <code>pthread_create</code> can be attached
+with the JNI <code>AttachCurrentThread</code> or
+<code>AttachCurrentThreadAsDaemon</code> functions.  Until a thread is
+attached to the VM, it has no JNIEnv, and
+<strong>cannot make JNI calls</strong>.</p>
+
+<p>Attaching a natively-created thread causes the VM to allocate and initialize
+a <code>Thread</code> object, add it to the "main" <code>ThreadGroup</code>,
+and add the thread to the set that is visible to the debugger.  Calling
+<code>AttachCurrentThread</code> on an already-attached thread is a no-op.</p>
+
+<p>The Dalvik VM does not suspend threads executing native code.  If
+garbage collection is in progress, or the debugger has issued a suspend
+request, the VM will pause the thread the next time it makes a JNI call.</p>
+
+<p>Threads attached through JNI <strong>must call
+<code>DetachCurrentThread</code> before they exit</strong>.
+If coding this directly is awkward, in Android &gt;= 2.0 ("Eclair") you
+can use <code>pthread_key_create</code> to define a destructor
+function that will be called before the thread exits, and
+call <code>DetachCurrentThread</code> from there.  (Use that
+key with <code>pthread_setspecific</code> to store the JNIEnv in
+thread-local-storage; that way it'll be passed into your destructor as
+the argument.)</p>
+
+
+<a name="jclass_jmethodID_and_jfieldID" id="jclass_jmethodID_and_jfieldID"></a>
+<h2>jclass, jmethodID, and jfieldID</h2>
+
+<p>If you want to access an object's field from native code, you would do the following:</p>
+
+<ul>
+<li> Get the class object reference for the class with <code>FindClass</code></li>
+<li> Get the field ID for the field with <code>GetFieldID</code></li>
+<li> Get the contents of the field with something appropriate, e.g.
+<code>GetIntField</code></li>
+</ul>
+
+<p>Similarly, to call a method, you'd first get a class object reference and then a method ID.  The IDs are often just
+pointers to internal VM data structures.  Looking them up may require several string
+comparisons, but once you have them the actual call to get the field or invoke the method
+is very quick.</p>
+
+<p>If performance is important, it's useful to look the values up once and cache the results
+in your native code.  Because we are limiting ourselves to one VM per process, it's reasonable
+to store this data in a static local structure.</p>
+
+<p>The class references, field IDs, and method IDs are guaranteed valid until the class is unloaded.  Classes
+are only unloaded if all classes associated with a ClassLoader can be garbage collected,
+which is rare but will not be impossible in our system.  Note however that
+the <code>jclass</code>
+is a class reference and <strong>must be protected</strong> with a call
+to <code>NewGlobalRef</code> (see the next section).</p>
+
+<p>If you would like to cache the IDs when a class is loaded, and automatically re-cache them
+if the class is ever unloaded and reloaded, the correct way to initialize
+the IDs is to add a piece of code that looks like this to the appropriate class:</p>
+
+<pre>    /*
+     * We use a class initializer to allow the native code to cache some
+     * field offsets.
+     */
+
+    /*
+     * A native function that looks up and caches interesting
+     * class/field/method IDs for this class.  Returns false on failure.
+     */
+    native private static boolean nativeClassInit();
+
+    /*
+     * Invoke the native initializer when the class is loaded.
+     */
+    static {
+        if (!nativeClassInit())
+            throw new RuntimeException("native init failed");
+    }</pre>
+
+<p>Create a nativeClassInit method in your C/C++ code that performs the ID lookups.  The code
+will be executed once, when the class is initialized.  If the class is ever unloaded and
+then reloaded, it will be executed again.  (See the implementation of java.io.FileDescriptor
+for an example in our source tree.)</p>
+
+<a name="local_and_global_references" id="local_and_global_references"></a>
+<h2>Local and Global References</h2>
+
+<p>Every object that JNI returns is a "local reference".  This means that it's valid for the
+duration of the current native method in the current thread.
+<strong>Even if the object itself continues to live on after the native method returns, the reference is not valid.</strong>
+This applies to all sub-classes of <code>jobject</code>, including
+<code>jclass</code>, <code>jstring</code>, and <code>jarray</code>.
+(Dalvik VM will warn you about most reference mis-uses when extended JNI
+checks are enabled.)</p>
+
+<p>If you want to hold on to a reference for a longer period, you must use
+a "global" reference.  The <code>NewGlobalRef</code> function takes the
+local reference as an argument and returns a global one.
+The global reference is guaranteed to be valid until you call
+<code>DeleteGlobalRef</code>.</p>
+
+<p>This pattern is commonly used when caching copies of class objects obtained
+from <code>FindClass</code>, e.g.:</p>
+<pre>jclass* localClass = env-&gt;FindClass("MyClass");
+jclass* globalClass = (jclass*) env-&gt;NewGlobalRef(localClass);</pre>
+
+<p>All JNI methods accept both local and global references as arguments.
+It's possible for references to the same object to have different values;
+for example, the return values from consecutive calls to
+<code>NewGlobalRef</code> on the same object may be different.
+<strong>To see if two references refer to the same object,
+you must use the <code>IsSameObject</code> function.</strong>  Never compare
+references with "==" in native code.</p>
+
+<p>One consequence of this is that you
+<strong>must not assume object references are constant or unique</strong>
+in native code.  The 32-bit value representing an object may be different
+from one invocation of a method to the next, and it's possible that two
+different objects could have the same 32-bit value on consecutive calls.  Do
+not use <code>jobject</code> values as keys.</p>
+
+<p>Programmers are required to "not excessively allocate" local references.  In practical terms this means
+that if you're creating large numbers of local references, perhaps while running through an array of
+Objects, you should free them manually with
+<code>DeleteLocalRef</code> instead of letting JNI do it for you.  The
+VM is only required to reserve slots for
+16 local references, so if you need more than that you should either delete as you go or use
+<code>EnsureLocalCapacity</code> to reserve more.</p>
+
+<p>Note: method and field IDs are just 32-bit identifiers, not object
+references, and should not be passed to <code>NewGlobalRef</code>.  The raw data
+pointers returned by functions like <code>GetStringUTFChars</code>
+and <code>GetByteArrayElements</code> are also not objects.</p>
+
+<p>One unusual case deserves separate mention.  If you attach a native
+thread to the VM with AttachCurrentThread, the code you are running will
+never "return" to the VM until the thread detaches from the VM.  Any local
+references you create will have to be deleted manually unless you're going
+to detach the thread soon.</p>
+
+<a name="UTF_8_and_UTF_16_strings" id="UTF_8_and_UTF_16_strings"></a>
+<h2>UTF-8 and UTF-16 Strings</h2>
+
+<p>The Java programming language uses UTF-16.  For convenience, JNI provides methods that work with "modified UTF-8" encoding
+as well.  (Some VMs use the modified UTF-8 internally to store strings; ours do not.)  The
+modified encoding only supports the 8- and 16-bit forms, and stores ASCII NUL values in a 16-bit encoding.
+The nice thing about it is that you can count on having C-style zero-terminated strings,
+suitable for use with standard libc string functions.  The down side is that you cannot pass
+arbitrary UTF-8 data into the VM and expect it to work correctly.</p>
+
+<p>It's usually best to operate with UTF-16 strings.  With our current VMs, the
+<code>GetStringChars</code> method
+does not require a copy, whereas <code>GetStringUTFChars</code> requires a malloc and a UTF conversion.  Note that
+<strong>UTF-16 strings are not zero-terminated</strong>, and \u0000 is allowed,
+so you need to hang on to the string length as well as
+the string pointer.</p>
+
+<p><strong>Don't forget to Release the strings you Get</strong>.  The
+string functions return <code>jchar*</code> or <code>jbyte*</code>, which
+are C-style pointers to primitive data rather than local references.  They
+are guaranteed valid until Release is called, which means they are not
+released when the native method returns.</p>
+
+<p><strong>Data passed to NewStringUTF must be in "modified" UTF-8 format</strong>.  A
+common mistake is reading character data from a file or network stream
+and handing it to <code>NewStringUTF</code> without filtering it.
+Unless you know the data is 7-bit ASCII, you need to strip out high-ASCII
+characters or convert them to proper "modified" UTF-8 form.  If you don't,
+the UTF-16 conversion will likely not be what you expect.  The extended
+JNI checks will scan strings and warn you about invalid data, but they
+won't catch everything.</p>
+
+<a name="arrays" id="arrays"></a>
+<h2>Primitive Arrays</h2>
+
+<p>JNI provides functions for accessing the contents of array objects.
+While arrays of objects must be accessed one entry at a time, arrays of
+primitives can be read and written directly as if they were declared in C.</p>
+
+<p>To make the interface as efficient as possible without constraining
+the VM implementation,
+the <code>Get&lt;PrimitiveType&gt;ArrayElements</code> family of calls
+allows the VM to either return a pointer to the actual elements, or
+allocate some memory and make a copy.  Either way, the raw pointer returned
+is guaranteed to be valid until the corresponding <code>Release</code> call
+is issued (which implies that, if the data wasn't copied, the array object
+will be pinned down and can't be relocated as part of compacting the heap).
+<strong>You must Release every array you Get.</strong>  Also, if the Get
+call fails, you must ensure that your code doesn't try to Release a NULL
+pointer later.</p>
+
+<p>You can determine whether or not the data was copied by passing in a
+non-NULL pointer for the <code>isCopy</code> argument.  This is rarely
+useful.</p>
+
+<p>The <code>Release</code> call takes a <code>mode</code> argument that can
+have one of three values.  The actions performed by the VM depend upon
+whether it returned a pointer to the actual data or a copy of it:</p>
+
+<ul>
+    <li><code>0</code>
+    <ul>
+        <li>Actual: the array object is un-pinned.
+        <li>Copy: data is copied back.  The buffer with the copy is freed.
+    </ul>
+    <li><code>JNI_COMMIT</code>
+    <ul>
+        <li>Actual: does nothing.
+        <li>Copy: data is copied back.  The buffer with the copy
+        <strong>is not freed</strong>.
+    </ul>
+    <li><code>JNI_ABORT</code>
+    <ul>
+        <li>Actual: the array object is un-pinned.  Earlier
+        writes are <strong>not</strong> aborted.
+        <li>Copy: the buffer with the copy is freed; any changes to it are lost.
+    </ul>
+</ul>
+
+<p>One reason for checking the <code>isCopy</code> flag is to know if
+you need to call <code>Release</code> with <code>JNI_COMMIT</code>
+after making changes to an array &mdash; if you're alternating between making
+changes and executing code that uses the contents of the array, you may be
+able to
+skip the no-op commit.  Another possible reason for checking the flag is for
+efficient handling of <code>JNI_ABORT</code>.  For example, you might want
+to get an array, modify it in place, pass pieces to other functions, and
+then discard the changes.  If you know that JNI is making a new copy for
+you, there's no need to create another "editable" copy.  If JNI is passing
+you the original, then you do need to make your own copy.</p>
+
+<p>Some have asserted that you can skip the <code>Release</code> call if
+<code>*isCopy</code> is false.  This is not the case.  If no copy buffer was
+allocated, then the original memory must be pinned down and can't be moved by
+the garbage collector.</p>
+
+<p>Also note that the <code>JNI_COMMIT</code> flag does NOT release the array,
+and you will need to call <code>Release</code> again with a different flag
+eventually.</p>
+
+
+<a name="region_calls" id="region_calls"></a>
+<h2>Region Calls</h2>
+
+<p>There is an alternative to calls like <code>Get&lt;Type&gt;ArrayElements</code>
+and <code>GetStringChars</code> that may be very helpful when all you want
+to do is copy data in or out.  Consider the following:</p>
+
+<pre>
+    jbyte* data = env->GetByteArrayElements(array, NULL);
+    if (data != NULL) {
+        memcpy(buffer, data, len);
+        env->ReleaseByteArrayElements(array, data, JNI_ABORT);
+    }</pre>
+
+<p>This grabs the array, copies the first <code>len</code> byte
+elements out of it, and then releases the array.  Depending upon the VM
+policies the <code>Get</code> call will either pin or copy the array contents.
+We copy the data (for perhaps a second time), then call Release; in this case
+we use <code>JNI_ABORT</code> so there's no chance of a third copy.</p>
+
+<p>We can accomplish the same thing with this:</p>
+<pre>
+    env->GetByteArrayRegion(array, 0, len, buffer);</pre>
+
+<p>This has several advantages:</p>
+<ul>
+    <li>Requires one JNI call instead of 2, reducing overhead.
+    <li>Doesn't require pinning or extra data copies.
+    <li>Reduces the risk of programmer error &mdash; no risk of forgetting
+    to call <code>Release</code> after something fails.
+</ul>
+
+<p>Similarly, you can use the <code>Set&lt;Type&gt;ArrayRegion</code> call
+to copy data into an array, and <code>GetStringRegion</code> or
+<code>GetStringUTFRegion</code> to copy characters out of a
+<code>String</code>.
+
+
+<a name="exceptions" id="exceptions"></a>
+<h2>Exception</h2>
+
+<p><strong>You may not call most JNI functions while an exception is pending.</strong>
+Your code is expected to notice the exception (via the function's return value,
+<code>ExceptionCheck()</code>, or <code>ExceptionOccurred()</code>) and return,
+or clear the exception and handle it.</p>
+
+<p>The only JNI functions that you are allowed to call while an exception is
+pending are:</p>
+<ul>
+    <li>DeleteGlobalRef
+    <li>DeleteLocalRef
+    <li>DeleteWeakGlobalRef
+    <li>ExceptionCheck
+    <li>ExceptionClear
+    <li>ExceptionDescribe
+    <li>ExceptionOccurred
+    <li>MonitorExit
+    <li>PopLocalFrame
+    <li>PushLocalFrame
+    <li>Release&lt;PrimitiveType&gt;ArrayElements
+    <li>ReleasePrimitiveArrayCritical
+    <li>ReleaseStringChars
+    <li>ReleaseStringCritical
+    <li>ReleaseStringUTFChars
+</ul>
+
+<p>Many JNI calls can throw an exception, but often provide a simpler way
+of checking for failure.  For example, if <code>NewString</code> returns
+a non-NULL value, you don't need to check for an exception.  However, if
+you call a method (using a function like <code>CallObjectMethod</code>),
+you must always check for an exception, because the return value is not
+going to be valid if an exception was thrown.</p>
+
+<p>Note that exceptions thrown by interpreted code do not "leap over" native code,
+and C++ exceptions thrown by native code are not handled by Dalvik.
+The JNI <code>Throw</code> and <code>ThrowNew</code> instructions just
+set an exception pointer in the current thread.  Upon returning to the VM from
+native code, the exception will be noted and handled appropriately.</p>
+
+<p>Native code can "catch" an exception by calling <code>ExceptionCheck</code> or
+<code>ExceptionOccurred</code>, and clear it with
+<code>ExceptionClear</code>.  As usual,
+discarding exceptions without handling them can lead to problems.</p>
+
+<p>There are no built-in functions for manipulating the Throwable object
+itself, so if you want to (say) get the exception string you will need to
+find the Throwable class, look up the method ID for
+<code>getMessage "()Ljava/lang/String;"</code>, invoke it, and if the result
+is non-NULL use <code>GetStringUTFChars</code> to get something you can
+hand to printf or a LOG macro.</p>
+
+
+<a name="extended_checking" id="extended_checking"></a>
+<h2>Extended Checking</h2>
+
+<p>JNI does very little error checking.  Calling <code>SetIntField</code>
+on an Object field will succeed, even if the field is marked
+<code>private</code> and <code>final</code>.  The
+goal is to minimize the overhead on the assumption that, if you've written it in native code,
+you probably did it for performance reasons.</p>
+
+<p>In Dalvik, you can enable additional checks by setting the
+"<code>-Xcheck:jni</code>" flag.  If the flag is set, the VM directs
+the JavaVM and JNIEnv pointers to a different table of functions.
+These functions perform an extended series of checks before calling the
+standard implementation.</p>
+
+<p>The additional tests include:</p>
+
+<ul>
+<li> Check for null pointers where not allowed.</li>
+<li> Verify argument type correctness (jclass is a class object,
+jfieldID points to field data, jstring is a java.lang.String).</li>
+<li> Field type correctness, e.g. don't store a HashMap in a String field.</li>
+<li> Ensure jmethodID is appropriate when making a static or virtual
+method call.</li>
+<li> Check to see if an exception is pending on calls where pending exceptions are not legal.</li>
+<li> Check for calls to inappropriate functions between Critical get/release calls.</li>
+<li> Check that JNIEnv structs aren't being shared between threads.</li>
+<li> Make sure local references aren't used outside their allowed lifespan.</li>
+<li> UTF-8 strings contain only valid "modified UTF-8" data.</li>
+</ul>
+
+<p>Accessibility of methods and fields (i.e. public vs. private) is not
+checked.</p>
+
+<p>For a description of how to enable CheckJNI for Android apps, see
+<a href="embedded-vm-control.html">Controlling the Embedded VM</a>.
+It's currently enabled by default in the Android emulator and on
+"engineering" device builds.</p>
+
+<p>JNI checks can be modified with the <code>-Xjniopts</code> command-line
+flag.  Currently supported values include:</p>
+
+<dl>
+<dt>forcecopy
+<dd>When set, any function that can return a copy of the original data
+(array of primitive values, UTF-16 chars) will always do so.  The buffers
+are over-allocated and surrounded with a guard pattern to help identify
+code writing outside the buffer, and the contents are erased before the
+storage is freed to trip up code that uses the data after calling Release.
+This will have a noticeable performance impact on some applications.
+<dt>warnonly
+<dd>By default, JNI "warnings" cause the VM to abort.  With this flag
+it continues on.
+</dl>
+
+
+<a name="native_libraries" id="native_libraries"></a>
+<h2>Native Libraries</h2>
+
+<p>You can load native code from shared libraries with the standard
+<code>System.loadLibrary()</code> call.  The
+preferred way to get at your native code is:</p>
+
+<ul>
+<li> Call <code>System.loadLibrary()</code> from a static class
+initializer.  (See the earlier example, where one is used to call
+<code>nativeClassInit()</code>.)  The argument is the "undecorated"
+library name, e.g. to load "libfubar.so" you would pass in "fubar".</li>
+<li> Provide a native function: <code><strong>jint JNI_OnLoad(JavaVM* vm, void* reserved)</strong></code></li>
+<li>In <code>JNI_OnLoad</code>, register all of your native methods.  You
+should declare
+the methods "static" so the names don't take up space in the symbol table
+on the device.</li>
+</ul>
+
+<p>The <code>JNI_OnLoad</code> function should look something like this if
+written in C:</p>
+<pre>jint JNI_OnLoad(JavaVM* vm, void* reserved)
+{
+    JNIEnv* env;
+    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK)
+        return -1;
+
+    /* get class with (*env)->FindClass */
+    /* register methods with (*env)->RegisterNatives */
+
+    return JNI_VERSION_1_6;
+}</pre>
+
+<p>You can also call <code>System.load()</code> with the full path name of the
+shared library.  For Android apps, you may find it useful to get the full
+path to the application's private data storage area from the context object.</p>
+
+<p>This is the recommended approach, but not the only approach.  The VM does
+not require explicit registration, nor that you provide a
+<code>JNI_OnLoad</code> function.
+You can instead use "discovery" of native methods that are named in a
+specific way (see <a href="http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/design.html#wp615">
+    the JNI spec</a> for details), though this is less desirable.
+It requires more space in the shared object symbol table,
+loading is slower because it requires string searches through all of the
+loaded shared libraries, and if a method signature is wrong you won't know
+about it until the first time the method is actually used.</p>
+
+<p>One other note about <code>JNI_OnLoad</code>: any <code>FindClass</code>
+calls you make from there will happen in the context of the class loader
+that was used to load the shared library.  Normally <code>FindClass</code>
+uses the loader associated with the method at the top of the interpreted
+stack, or if there isn't one (because the thread was just attached to
+the VM) it uses the "system" class loader.  This makes
+<code>JNI_OnLoad</code> a convenient place to look up and cache class
+object references.</p>
+
+
+<a name="64_bit" id="64_bit"></a>
+<h2>64-bit Considerations</h2>
+
+<p>Android is currently expected to run on 32-bit platforms.  In theory it
+could be built for a 64-bit system, but that is not a goal at this time.
+For the most part this isn't something that you will need to worry about
+when interacting with native code,
+but it becomes significant if you plan to store pointers to native
+structures in integer fields in an object.  To support architectures
+that use 64-bit pointers, <strong>you need to stash your native pointers in a
+<code>long</code> field rather than an <code>int</code></strong>.
+
+
+<a name="unsupported" id="unsupported"></a>
+<h2>Unsupported Features</h2>
+
+<p>All JNI 1.6 features are supported, with the following exceptions:</p>
+<ul>
+    <li><code>DefineClass</code> is not implemented.  Dalvik does not use
+    Java bytecodes or class files, so passing in binary class data
+    doesn't work.  Translation facilities may be added in a future
+    version of the VM.</li>
+    <li>"Weak global" references are implemented, but may only be passed
+    to <code>NewLocalRef</code>, <code>NewGlobalRef</code>, and
+    <code>DeleteWeakGlobalRef</code>.  (The spec strongly encourages
+    programmers to create hard references to weak globals before doing
+    anything with them, so this should not be at all limiting.)</li>
+    <li><code>GetObjectRefType</code> (new in JNI 1.6) is implemented but not fully
+    functional &mdash; it can't always tell the difference between "local" and
+    "global" references.</li>
+</ul>
+
+<p>For backward compatibility, you may need to be aware of:</p>
+<ul>
+    <li>Until Android 2.0 ("Eclair"), the '$' character was not properly
+    converted to "_00024" during searches for method names.  Working
+    around this requires using explicit registration or moving the
+    native methods out of inner classes.
+    <li>Until Android 2.0 ("Eclair"), it was not possible to use a <code>pthread_key_create</code>
+    destructor function to avoid the VM's "thread must be detached before
+    exit" check.  (The VM also uses a pthread key destructor function,
+    so it'd be a race to see which gets called first.)
+    <li>"Weak global" references were not implemented until Android 2.2 ("Froyo").
+    Older VMs will vigorously reject attempts to use them.  You can use
+    the Android platform version constants to test for support.
+</ul>
+
+
+<a name="faq_ULE" id="faq_ULE"></a>
+<h2>FAQ: UnsatisfiedLinkError</h2>
+
+<p>When working on native code it's not uncommon to see a failure like this:</p>
+<pre>java.lang.UnsatisfiedLinkError: Library foo not found</pre>
+
+<p>In some cases it means what it says &mdash; the library wasn't found.  In
+other cases the library exists but couldn't be opened by dlopen(), and
+the details of the failure can be found in the exception's detail message.</p>
+
+<p>Common reasons why you might encounter "library not found" exceptions:</p>
+<ul>
+    <li>The library doesn't exist or isn't accessible to the app.  Use
+    <code>adb shell ls -l &lt;path&gt;</code> to check its presence
+    and permissions.
+    <li>The library wasn't built with the NDK.  This can result in
+    dependencies on functions or libraries that don't exist on the device.
+</ul>
+
+<p>Another class of <code>UnsatisfiedLinkError</code> failures looks like:</p>
+<pre>java.lang.UnsatisfiedLinkError: myfunc
+        at Foo.myfunc(Native Method)
+        at Foo.main(Foo.java:10)</pre>
+
+<p>In logcat, you'll see:</p>
+<pre>W/dalvikvm(  880): No implementation found for native LFoo;.myfunc ()V</pre>
+
+<p>This means that the VM tried to find a matching method but was unsuccessful.
+Some common reasons for this are:</p>
+<ul>
+    <li>The library isn't getting loaded.  Check the logcat output for
+    messages about library loading.
+    <li>The method isn't being found due to a name or signature mismatch.  This
+    is commonly caused by:
+    <ul>
+        <li>For lazy method lookup, failing to declare C++ functions
+        with <code>extern C</code>.  You can use <code>arm-eabi-nm</code>
+        to see the symbols as they appear in the library; if they look
+        mangled (e.g. <code>_Z15Java_Foo_myfuncP7_JNIEnvP7_jclass</code>
+        rather than <code>Java_Foo_myfunc</code>) then you need to
+        adjust the declaration.
+        <li>For explicit registration, minor errors when entering the
+        method signature.  Make sure that what you're passing to the
+        registration call matches the signature in the log file.
+        Remember that 'B' is <code>byte</code> and 'Z' is <code>boolean</code>.
+        Class name components in signatures start with 'L', end with ';',
+        use '/' to separate package/class names, and use '$' to separate
+        inner-class names
+        (e.g. <code>Ljava/util/Map$Entry;</code>).
+    </ul>
+</ul>
+
+<p>Using <code>javah</code> to automatically generate JNI headers may help
+avoid some problems.
+
+
+<a name="faq_FindClass" id="faq_FindClass"></a>
+<h2>FAQ: FindClass didn't find my class</h2>
+
+<p>Make sure that the class name string has the correct format.  JNI class
+names start with the package name and are separated with slashes,
+e.g. <code>java/lang/String</code>.  If you're looking up an array class,
+you need to start with the appropriate number of square brackets and
+must also wrap the class with 'L' and ';', so a one-dimensional array of
+<code>String</code> would be <code>[Ljava/lang/String;</code>.</p>
+
+<p>If the class name looks right, you could be running into a class loader
+issue.  <code>FindClass</code> wants to start the class search in the
+class loader associated with your code.  It examines the VM call stack,
+which will look something like:
+<pre>    Foo.myfunc(Native Method)
+    Foo.main(Foo.java:10)
+    dalvik.system.NativeStart.main(Native Method)</pre>
+
+<p>The topmost method is <code>Foo.myfunc</code>.  <code>FindClass</code>
+finds the <code>ClassLoader</code> object associated with the <code>Foo</code>
+class and uses that.</p>
+
+<p>This usually does what you want.  You can get into trouble if you
+create a thread outside the VM (perhaps by calling <code>pthread_create</code>
+and then attaching it to the VM with <code>AttachCurrentThread</code>).
+Now the stack trace looks like this:</p>
+<pre>    dalvik.system.NativeStart.run(Native Method)</pre>
+
+<p>The topmost method is <code>NativeStart.run</code>, which isn't part of
+your application.  If you call <code>FindClass</code> from this thread, the
+VM will start in the "system" class loader instead of the one associated
+with your application, so attempts to find app-specific classes will fail.</p>
+
+<p>There are a few ways to work around this:</p>
+<ul>
+    <li>Do your <code>FindClass</code> lookups once, in
+    <code>JNI_OnLoad</code>, and cache the class references for later
+    use.  Any <code>FindClass</code> calls made as part of executing
+    <code>JNI_OnLoad</code> will use the class loader associated with
+    the function that called <code>System.loadLibrary</code> (this is a
+    special rule, provided to make library initialization more convenient).
+    If your app code is loading the library, <code>FindClass</code>
+    will use the correct class loader.
+    <li>Pass an instance of the class into the functions that need
+    it, e.g. declare your native method to take a Class argument and
+    then pass <code>Foo.class</code> in.
+    <li>Cache a reference to the <code>ClassLoader</code> object somewhere
+    handy, and issue <code>loadClass</code> calls directly.  This requires
+    some effort.
+</ul>
+
+
+<a name="faq_sharing" id="faq_sharing"></a>
+<h2>FAQ: Sharing raw data with native code</h2>
+
+<p>You may find yourself in a situation where you need to access a large
+buffer of raw data from code written in Java and C/C++.  Common examples
+include manipulation of bitmaps or sound samples.  There are two
+basic approaches.</p>
+
+<p>You can store the data in a <code>byte[]</code>.  This allows very fast
+access from code written in Java.  On the native side, however, you're
+not guaranteed to be able to access the data without having to copy it.  In
+some implementations, <code>GetByteArrayElements</code> and
+<code>GetPrimitiveArrayCritical</code> will return actual pointers to the
+raw data in the managed heap, but in others it will allocate a buffer
+on the native heap and copy the data over.</p>
+
+<p>The alternative is to store the data in a direct byte buffer.  These
+can be created with <code>java.nio.ByteBuffer.allocateDirect</code>, or
+the JNI <code>NewDirectByteBuffer</code> function.  Unlike regular
+byte buffers, the storage is not allocated on the managed heap, and can
+always be accessed directly from native code (get the address
+with <code>GetDirectBufferAddress</code>).  Depending on how direct
+byte buffer access is implemented in the VM, accessing the data from code
+written in Java can be very slow.</p>
+
+<p>The choice of which to use depends on two factors:</p>
+<ol>
+    <li>Will most of the data accesses happen from code written in Java
+    or in C/C++?
+    <li>If the data is eventually being passed to a system API, what form
+    must it be in?  (For example, if the data is eventually passed to a
+    function that takes a byte[], doing processing in a direct
+    <code>ByteBuffer</code> might be unwise.)
+</ol>
+
+<p>If there's no clear winner, use a direct byte buffer.  Support for them
+is built directly into JNI, and access to them from code written in
+Java can be made faster with VM improvements.</p>
diff --git a/docs/html/guide/practices/design/performance.jd b/docs/html/guide/practices/design/performance.jd
index fe69d7d..c41f971 100644
--- a/docs/html/guide/practices/design/performance.jd
+++ b/docs/html/guide/practices/design/performance.jd
@@ -375,6 +375,9 @@
 <p>Native code is primarily useful when you have an existing native codebase
 that you want to port to Android, not for "speeding up" parts of a Java app.</p>
 
+<p>If you do need to use native code, you should read our
+<a href="{@docRoot}guide/practices/design/jni.html">JNI Tips</a>.</p>
+
 <p>(See also <em>Effective Java</em> item 54.)</p>
 
 <a name="closing_notes" id="closing_notes"></a>
diff --git a/docs/html/guide/publishing/licensing.jd b/docs/html/guide/publishing/licensing.jd
index 4184ecb..a9b182e 100644
--- a/docs/html/guide/publishing/licensing.jd
+++ b/docs/html/guide/publishing/licensing.jd
@@ -368,7 +368,7 @@
 
 <ol>
 <li><a href="#download-sdk">Downloading the latest SDK</a>, if you haven't already done so </li>
-<li><a href="#runtime-setup">Setting up the runtime environment</a> for development</a></li>
+<li><a href="#runtime-setup">Setting up the runtime environment</a> for development</li>
 <li><a href="#download-lvl">Downloading the Market Licensing component</a> into your SDK </li>
 <li><a href="#lvl-setup">Setting up the Licensing Verification Library</a></li>
 <li><a href="#add-library">Including the LVL library project in your application</a></li>
@@ -582,9 +582,9 @@
 <p>When the download is complete, the Android SDK and AVD Manager installs both
 the LVL library project and the example application into these directories: </p>
 
-<p style="margin-left:2em"><code>&lt;<em>sdk</em>&gt;/market_licensing/library/</code>
+<p style="margin-left:2em"><code>&lt;<em>sdk</em>&gt;/extras/google/market_licensing/library/</code>
 &nbsp;&nbsp;(the LVL library project)<br />
-<code>&lt;<em>sdk</em>&gt;/market_licensing/sample/</code>&nbsp;&nbsp;(the example
+<code>&lt;<em>sdk</em>&gt;/extras/google/market_licensing/sample/</code>&nbsp;&nbsp;(the example
 application)</p>
 
 <p>If you aren't familiar with how to download components into your SDK, see the
@@ -1530,7 +1530,7 @@
 licensing is published (or will be published). </li>
 <li>In the account home page, locate the "Edit profile" link and click it. </li>
 <li>In the Edit Profile page, locate the "Licensing" pane, shown below. Your
-public key for licensing is given in the "Public key" text box. </p>
+public key for licensing is given in the "Public key" text box. </li>
 </ol>
 
 <p>To add the public key to your application, simply copy/paste the key string
diff --git a/docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd b/docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd
index bd542bd..f22e5b2 100644
--- a/docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd
+++ b/docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd
@@ -11,7 +11,7 @@
   <li>A task contains a collection of activities in the order in which the user interacts with
 them</li>
   <li>Tasks can move to the background and retain the state of each activity in order for the user
-to perform other tasks without loosing their work</li>
+to perform other tasks without losing their work</li>
 </ul>
 
 <h2>In this document</h2>
@@ -181,7 +181,7 @@
 system still
 knows that the activity has a place in the back stack, but when the activity is brought to the
 top of the stack the system must recreate it (rather than resume it). In order to
-avoid loosing the user's work, you should proactively retain it by implementing the {@link
+avoid losing the user's work, you should proactively retain it by implementing the {@link
 android.app.Activity#onSaveInstanceState onSaveInstanceState()} callback
 methods in your activity.</p>
 
@@ -201,7 +201,7 @@
 started (instead of being placed within the current task); or, when you start an activity, you want
 to bring forward an existing instance of it (instead of creating a new
 instance on top of the back stack); or, you want your back stack to be cleared of all
-activitiesstart an activity except for the root activity when the user leaves the task.</p>
+activities except for the root activity when the user leaves the task.</p>
 
 <p>You can do these things and more, with attributes in the
 <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
@@ -566,4 +566,4 @@
 respond, continue with the <b><a
 href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent
 Filters</a></b> document.</p>
--->
\ No newline at end of file
+-->
diff --git a/docs/html/sdk/download.jd b/docs/html/sdk/download.jd
index 81b4ff6..44fe5e4 100644
--- a/docs/html/sdk/download.jd
+++ b/docs/html/sdk/download.jd
@@ -1,4 +1,93 @@
-sdk.redirect=true
+page.title=Download an Archived Android SDK
+hide_license_footer=true
 
 @jd:body
 
+<script type="text/javascript">
+  function verify() {
+    document.getElementById('download-button').disabled =
+!document.getElementById('checkbox').checked;
+  }
+  function submit() {
+    var location = window.location.href;
+    if (location.indexOf('?v=') != -1) {
+      var filename = location.substring(location.indexOf('=')+1,location.length);
+      if (document.getElementById('checkbox').checked) {
+        document.location = "http://dl.google.com/android/" + filename;
+      }
+      document.getElementById('click-download').setAttribute("href", "http://dl.google.com/android/"
++ filename);
+      $("#terms-form").hide(500);
+      $("#next-steps").show(500);
+      document.getElementById('checkbox').disabled=true;
+      document.getElementById('download-button').disabled=true;
+    } else {
+      alert("You have not selected an SDK version. Please return to the SDK Archives page");
+    }
+  }
+</script>
+
+<div id="terms-form">
+    <p>Please carefully review the Android SDK License Agreement before downloading the SDK.
+The License Agreement constitutes a contract between you and Google with respect to your use of the
+SDK.</p>
+    <p class="note"><strong>Note:</strong> You must agree to this license agreement in order to
+download one of the archived SDKs, because these SDK packages contain Google software (whereas, the
+<a href="http://developer.android.com/sdk/index.html">current SDK</a> packages do not require a
+license agreement, because they contain only the open sourced SDK tools).</p>
+
+  <iframe id="terms" style="border:1px solid #888;margin:0 0 1em;height:400px;width:95%;"
+src="terms_body.html">
+  </iframe>
+
+  <p>
+    <input type="checkbox" id="checkbox" onclick="verify()" />
+    <label for="checkbox">I agree to the terms of the Android SDK License Agreement.</label>
+  </p>
+  <p>
+    <input type="submit" value="Download" id="download-button" disabled="disabled"
+onclick="submit()" />
+  </p>
+  <p>
+  <script language="javascript">
+    var loc = window.location.href;
+    if (loc.indexOf('?v=') != -1) {
+      var filename = loc.substring(loc.indexOf('=')+1,loc.length);
+      document.write("File: " + filename);
+    }
+  </script>
+  </p>
+</div><!-- end terms-form -->
+
+<noscript>
+  <p><strong>Please enable Javascript in your browser in order to agree to the terms and download
+the SDK.</strong></p>
+</noscript>
+
+<div class="special" id="next-steps" style="display:none">
+  <p>Your download should be underway. If not, <a id="click-download">click here to start the
+download</a>.</p>
+  <p>Beware that you've just downloaded a very old version of the Android SDK, which is not
+recommended. We no longer maintain documentation about how to install these archived SDKs nor
+support the tools contained within.</p>
+  <p>We recommend that you instead download the latest <a
+href="http://developer.android.com/sdk/index.html">Android SDK starter package</a>, which includes
+the latest SDK tools and allows you to develop against any version of the Android platform, back to
+Android 1.1.</p>
+</div>
+
+<script type="text/javascript">
+  var loc = window.location.href;
+  var filename = loc.substring(loc.indexOf('=')+1,loc.length);
+  version = filename.substring(filename.indexOf('.')-1,filename.lastIndexOf('.'));
+  $(".addVersionPath").each(function(i) {
+    var oldHref = $(this).attr("href");
+    $(this).attr({href: "/sdk/" + version + "/" + oldHref});
+  });
+</script>
+
+
+
+
+
+
diff --git a/docs/html/sdk/older_releases.jd b/docs/html/sdk/older_releases.jd
index 77f7e43..870ff04 100644
--- a/docs/html/sdk/older_releases.jd
+++ b/docs/html/sdk/older_releases.jd
@@ -47,7 +47,7 @@
     <td>Windows</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-windows-1.6_r1.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.6_r1.zip">android-sdk-
 windows-1 .6_r1.zip</a>
     </td>
     <td>260529085 bytes</td>
@@ -57,7 +57,7 @@
     <td>Mac OS X (intel)</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.6_r1.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.6_r1.zip">android-sdk-
 mac_x86-1 .6_r1.zip</a>
     </td>
     <td>247412515 bytes</td>
@@ -67,7 +67,7 @@
     <td>Linux (i386)</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.6_r1.tgz">android-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.6_r1.tgz">android-
 sdk- linux_x86-1.6_r1.tgz</a>
     </td>
     <td>238224860 bytes</td>
@@ -92,7 +92,7 @@
     <td>Windows</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-windows-1.5_r3.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.5_r3.zip">android-sdk-
 windows-1 .5_r3.zip</a>
     </td>
     <td>191477853 bytes</td>
@@ -102,7 +102,7 @@
     <td>Mac OS X (intel)</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.5_r3.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.5_r3.zip">android-sdk-
 mac_x86-1 .5_r3.zip</a>
     </td>
     <td>183024673 bytes</td>
@@ -112,7 +112,7 @@
     <td>Linux (i386)</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.5_r3.zip">android-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.5_r3.zip">android-
 sdk- linux_x86-1.5_r3.zip</a>
     </td>
     <td>178117561 bytes</td>
@@ -137,7 +137,7 @@
     <td>Windows</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-windows-1.1_r1.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.1_r1.zip">android-sdk-
 windows-1
 .1_r1.zip</a>
     </td>
@@ -148,7 +148,7 @@
     <td>Mac OS X (intel)</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.1_r1.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.1_r1.zip">android-sdk-
 mac_x86-1
 .1_r1.zip</a>
     </td>
@@ -159,7 +159,7 @@
     <td>Linux (i386)</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.1_r1.zip">android-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.1_r1.zip">android-
 sdk-
 linux_x86-1.1_r1.zip</a>
     </td>
@@ -185,7 +185,7 @@
     <td>Windows</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-windows-1.0_r2.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.0_r2.zip">android-sdk-
 windows-1
 .0_r2.zip</a>
     </td>
@@ -196,7 +196,7 @@
     <td>Mac OS X (intel)</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.0_r2.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.0_r2.zip">android-sdk-
 mac_x86-1
 .0_r2.zip</a>
     </td>
@@ -207,7 +207,7 @@
     <td>Linux (i386)</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.0_r2.zip">android-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.0_r2.zip">android-
 sdk-
 linux_x86-1.0_r2.zip</a>
     </td>
@@ -241,7 +241,7 @@
     <td>Windows</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-windows-1.5_r2.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.5_r2.zip">android-sdk-
 windows-1 .5_r2.zip</a>
     </td>
     <td>178346828 bytes</td>
@@ -251,7 +251,7 @@
     <td>Mac OS X (intel)</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.5_r2.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.5_r2.zip">android-sdk-
 mac_x86-1 .5_r2.zip</a>
     </td>
     <td>169945128 bytes</td>
@@ -261,7 +261,7 @@
     <td>Linux (i386)</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.5_r2.zip">android-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.5_r2.zip">android-
 sdk- linux_x86-1.5_r2.zip</a>
     </td>
     <td>165035130 bytes</td>
@@ -286,7 +286,7 @@
     <td>Windows</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-windows-1.5_r1.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.5_r1.zip">android-sdk-
 windows-1 .5_r1.zip</a>
     </td>
     <td>176263368 bytes</td>
@@ -296,7 +296,7 @@
     <td>Mac OS X (intel)</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.5_r1.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.5_r1.zip">android-sdk-
 mac_x86-1 .5_r1.zip</a>
     </td>
     <td>167848675 bytes</td>
@@ -306,7 +306,7 @@
     <td>Linux (i386)</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.5_r1.zip">android-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.5_r1.zip">android-
 sdk- linux_x86-1.5_r1.zip</a>
     </td>
     <td>162938845 bytes</td>
@@ -331,7 +331,7 @@
     <td>Windows</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-windows-1.0_r1.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.0_r1.zip">android-sdk-
 windows-1 .0_r1.zip</a>
     </td>
     <td>89.7 MB bytes</td>
@@ -341,7 +341,7 @@
     <td>Mac OS X (intel)</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.0_r1.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.0_r1.zip">android-sdk-
 mac_x86-1 .0_r1.zip</a>
     </td>
     <td>87.5 MB bytes</td>
@@ -351,7 +351,7 @@
     <td>Linux (i386)</td>
     <td>
   <a
-href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.0_r1.zip">android-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.0_r1.zip">android-
 sdk- linux_x86-1.0_r1.zip</a>
     </td>
     <td>87.8 MB bytes</td>
diff --git a/docs/html/sdk/terms_body.html b/docs/html/sdk/terms_body.html
new file mode 100644
index 0000000..8c55b37
--- /dev/null
+++ b/docs/html/sdk/terms_body.html
@@ -0,0 +1,336 @@
+
+ 
+<p>This is the Android Software Development Kit License Agreement.</p> 
+ 
+<h2> 
+	1. Introduction
+</h2> 
+<p> 
+	1.1 The Android Software Development Kit (referred to in this License Agreement as the "SDK"
+and specifically including the Android system files, packaged APIs, and Google APIs add-ons) is
+licensed to you subject to the terms of this License Agreement. This License Agreement forms a
+legally binding contract between you and Google in relation to your use of the SDK.
+ 
+</p> 
+<p> 
+	1.2 "Google" means Google Inc., a Delaware corporation with principal place of business at
+1600 Amphitheatre Parkway, Mountain View, CA 94043, United States.
+</p> 
+<h2> 
+	2. Accepting this License Agreement
+</h2> 
+<p> 
+	2.1 In order to use the SDK, you must first agree to this License Agreement. You may not use
+the SDK if you do not accept this License Agreement.
+</p> 
+<p> 
+	2.2 You can accept this License Agreement by:
+</p> 
+<p> 
+	(A) clicking to accept or agree to this License Agreement, where this option is made
+available to you; or
+</p> 
+<p> 
+	(B) by actually using the SDK. In this case, you agree that use of the SDK constitutes
+acceptance of the Licensing Agreement from that point onwards.
+</p> 
+<p> 
+	2.3 You may not use the SDK and may not accept the Licensing Agreement if you are a person
+barred from receiving the SDK under the laws of the United States or other countries including the
+country in which you are resident or from which you use the SDK.
+</p> 
+<p> 
+	2.4 If you are agreeing to be bound by this License Agreement on behalf of your employer or
+other entity, you represent and warrant that you have full legal authority to bind your employer or
+such entity to this License Agreement. If you do not have the requisite authority, you may not
+accept the Licensing Agreement or use the SDK on behalf of your employer or other entity.
+</p> 
+<h2> 
+	3. SDK License from Google
+</h2> 
+<p> 
+	3.1 Subject to the terms of this License Agreement, Google grants you a limited, worldwide,
+royalty-free, non- assignable and non-exclusive license to use the SDK solely to develop
+applications to run on the Android platform.
+</p> 
+<p> 
+	3.2 You agree that Google or third parties own all legal right, title and interest in and to
+the SDK, including any Intellectual Property Rights that subsist in the SDK. "Intellectual Property
+Rights" means any and all rights under patent law, copyright law, trade secret law, trademark law,
+and any and all other proprietary rights. Google reserves all rights not expressly granted to you. 
+ 
+</p> 
+<p> 
+	3.3 Except to the extent required by applicable third party licenses, you may not copy
+(except for backup purposes), modify, adapt, redistribute, decompile, reverse engineer, disassemble,
+or create derivative works of the SDK or any part of the SDK. Except to the extent required by
+applicable third party licenses, you may not load any part of the SDK onto a mobile handset or any
+other hardware device except a personal computer, combine any part of the SDK with other software,
+or distribute any software or device incorporating a part of the SDK. 
+</p> 
+<p> 
+	3.4 Use, reproduction and distribution of components of the SDK licensed under an open
+source software license are governed solely by the terms of that open source software license and
+not this License Agreement.
+</p> 
+<p> 
+	3.5 You agree that the form and nature of the SDK that Google provides may change without
+prior notice to you and that future versions of the SDK may be incompatible with applications
+developed on previous versions of the SDK. You agree that Google may stop (permanently or
+temporarily) providing the SDK (or any features within the SDK) to you or to users generally at
+Google's sole discretion, without prior notice to you.
+</p> 
+<p> 
+	3.6 Nothing in this License Agreement gives you a right to use any of Google's trade names,
+trademarks, service marks, logos, domain names, or other distinctive brand features.
+</p> 
+<p> 
+	3.7 You agree that you will not remove, obscure, or alter any proprietary rights notices
+(including copyright and trademark notices) that may be affixed to or contained within the SDK.
+</p> 
+<h2> 
+	4. Use of the SDK by You
+</h2> 
+<p> 
+	4.1 Google agrees that it obtains no right, title or interest from you (or your licensors)
+under this License Agreement in or to any software applications that you develop using the SDK,
+including any intellectual property rights that subsist in those applications. 
+</p> 
+<p> 
+	4.2 You agree to use the SDK and write applications only for purposes that are permitted by
+(a) this License Agreement and (b) any applicable law, regulation or generally accepted practices or
+guidelines in the relevant jurisdictions (including any laws regarding the export of data or
+software to and from the United States or other relevant countries).
+</p> 
+<p> 
+	4.3 You agree that if you use the SDK to develop applications for general public users, you
+will protect the privacy and legal rights of those users. If the users provide you with user names,
+passwords, or other login information or personal information, your must make the users aware that
+the information will be available to your application, and you must provide legally adequate privacy
+notice and protection for those users. If your application stores personal or sensitive information
+provided by users, it must do so securely. If the user provides your application with Google Account
+information, your application may only use that information to access the user's Google Account
+when, and for the limited purposes for which, the user has given you permission to do so.
+</p> 
+<p> 
+	4.4 You agree that you will not engage in any activity with the SDK, including the
+development or distribution of an application, that interferes with, disrupts, damages, or accesses
+in an unauthorized manner the servers, networks, or other properties or services of any third party
+including, but not limited to, Google or any mobile communications carrier.
+</p> 
+<p> 
+	4.5 You agree that you are solely responsible for (and that Google has no responsibility to
+you or to any third party for) any data, content, or resources that you create, transmit or display
+through the Android platform and/or applications for the Android platform, and for the consequences
+of your actions (including any loss or damage which Google may suffer) by doing so.
+</p> 
+<p> 
+	4.6 You agree that you are solely responsible for (and that Google has no responsibility to
+you or to any third party for) any breach of your obligations under this License Agreement, any
+applicable third party contract or Terms of Service, or any applicable law or regulation, and for
+the consequences (including any loss or damage which Google or any third party may suffer) of any
+such breach.
+</p> 
+<h2> 
+	5. Your Developer Credentials
+</h2> 
+<p> 
+	5.1 You agree that you are responsible for maintaining the confidentiality of any developer
+credentials that may be issued to you by Google or which you may choose yourself and that you will
+be solely responsible for all applications that are developed under your developer credentials.
+</p> 
+<h2> 
+	6. Privacy and Information
+</h2> 
+<p> 
+	6.1 In order to continually innovate and improve the SDK, Google may collect certain usage
+statistics from the software including but not limited to a unique identifier, associated IP
+address, version number of the software, and information on which tools and/or services in the SDK
+are being used and how they are being used. Before any of this information is collected, the SDK
+will notify you and seek your consent. If you withhold consent, the information will not be
+collected.
+</p> 
+<p> 
+	6.2 The data collected is examined in the aggregate to improve the SDK and is maintained in
+accordance with Google's Privacy Policy.
+</p> 
+<h2> 
+	7. Third Party Applications for the Android Platform
+</h2> 
+<p> 
+	7.1 If you use the SDK to run applications developed by a third party or that access data,
+content or resources provided by a third party, you agree that Google is not responsible for those
+applications, data, content, or resources. You understand that all data, content or resources which
+you may access through such third party applications are the sole responsibility of the person from
+which they originated and that Google is not liable for any loss or damage that you may experience
+as a result of the use or access of any of those third party applications, data, content, or
+resources.
+</p> 
+<p> 
+	7.2 You should be aware the data, content, and resources presented to you through such a
+third party application may be protected by intellectual property rights which are owned by the
+providers (or by other persons or companies on their behalf). You may not modify, rent, lease, loan,
+sell, distribute or create derivative works based on these data, content, or resources (either in
+whole or in part) unless you have been specifically given permission to do so by the relevant
+owners.
+</p> 
+<p> 
+	7.3 You acknowledge that your use of such third party applications, data, content, or
+resources may be subject to separate terms between you and the relevant third party. In that case,
+this License Agreement does not affect your legal relationship with these third parties.
+</p> 
+<h2> 
+	8. Using Android APIs
+</h2> 
+<p> 
+	8.1 Google Data APIs
+</p> 
+<p> 
+	8.1.1 If you use any API to retrieve data from Google, you acknowledge that the data may be
+protected by intellectual property rights which are owned by Google or those parties that provide
+the data (or by other persons or companies on their behalf). Your use of any such API may be subject
+to additional Terms of Service. You may not modify, rent, lease, loan, sell, distribute or create
+derivative works based on this data (either in whole or in part) unless allowed by the relevant
+Terms of Service.
+</p> 
+<p> 
+	8.1.2 If you use any API to retrieve a user's data from Google, you acknowledge and agree
+that you shall retrieve data only with the user's explicit consent and only when, and for the
+limited purposes for which, the user has given you permission to do so. 
+ 
+</p> 
+<h2> 
+	9. Terminating this License Agreement
+</h2> 
+<p> 
+	9.1 This License Agreement will continue to apply until terminated by either you or Google
+as set out below.
+</p> 
+<p> 
+	9.2 If you want to terminate this License Agreement, you may do so by ceasing your use of
+the SDK and any relevant developer credentials.
+</p> 
+<p> 
+	9.3 Google may at any time, terminate this License Agreement with you if:
+</p> 
+<p> 
+	(A) you have breached any provision of this License Agreement; or
+</p> 
+<p> 
+	(B) Google is required to do so by law; or
+</p> 
+<p> 
+	(C) the partner with whom Google offered certain parts of SDK (such as APIs) to you has
+terminated its relationship with Google or ceased to offer certain parts of the SDK to you; or
+</p> 
+<p> 
+	(D) Google decides to no longer providing the SDK or certain parts of the SDK to users in
+the country in which you are resident or from which you use the service, or the provision of the SDK
+or certain SDK services to you by Google is, in Google's sole discretion, no longer commercially
+viable.
+</p> 
+<p> 
+	9.4 When this License Agreement comes to an end, all of the legal rights, obligations and
+liabilities that you and Google have benefited from, been subject to (or which have accrued over
+time whilst this License Agreement has been in force) or which are expressed to continue
+indefinitely, shall be unaffected by this cessation, and the provisions of paragraph 14.7 shall
+continue to apply to such rights, obligations and liabilities indefinitely.
+</p> 
+<h2> 
+	10. DISCLAIMER OF WARRANTIES
+</h2> 
+<p> 
+	10.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF THE SDK IS AT YOUR SOLE RISK AND
+THAT THE SDK IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND FROM GOOGLE.
+</p> 
+<p> 
+	10.2 YOUR USE OF THE SDK AND ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE
+OF THE SDK IS AT YOUR OWN DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR
+COMPUTER SYSTEM OR OTHER DEVICE OR LOSS OF DATA THAT RESULTS FROM SUCH USE.
+</p> 
+<p> 
+	10.3 GOOGLE FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER
+EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES AND CONDITIONS OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+</p> 
+<h2> 
+	11. LIMITATION OF LIABILITY
+</h2> 
+<p> 
+	11.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT GOOGLE, ITS SUBSIDIARIES AND AFFILIATES, AND
+ITS LICENSORS SHALL NOT BE LIABLE TO YOU UNDER ANY THEORY OF LIABILITY FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL CONSEQUENTIAL OR EXEMPLARY DAMAGES THAT MAY BE INCURRED BY YOU, INCLUDING ANY
+LOSS OF DATA, WHETHER OR NOT GOOGLE OR ITS REPRESENTATIVES HAVE BEEN ADVISED OF OR SHOULD HAVE BEEN
+AWARE OF THE POSSIBILITY OF ANY SUCH LOSSES ARISING.
+</p> 
+<h2> 
+	12. Indemnification
+</h2> 
+<p> 
+	12.1 To the maximum extent permitted by law, you agree to defend, indemnify and hold
+harmless Google, its affiliates and their respective directors, officers, employees and agents from
+and against any and all claims, actions, suits or proceedings, as well as any and all losses,
+liabilities, damages, costs and expenses (including reasonable attorneys fees) arising out of or
+accruing from (a) your use of the SDK, (b) any application you develop on the SDK that infringes any
+copyright, trademark, trade secret, trade dress, patent or other intellectual property right of any
+person or defames any person or violates their rights of publicity or privacy, and (c) any
+non-compliance by you with this License Agreement.
+</p> 
+<h2> 
+	13. Changes to the License Agreement
+</h2> 
+<p> 
+	13.1 Google may make changes to the License Agreement as it distributes new versions of the
+SDK. When these changes are made, Google will make a new version of the License Agreement available
+on the website where the SDK is made available.
+</p> 
+<h2> 
+	14. General Legal Terms
+</h2> 
+<p> 
+	14.1 This License Agreement constitute the whole legal agreement between you and Google and
+govern your use of the SDK (excluding any services which Google may provide to you under a separate
+written agreement), and completely replace any prior agreements between you and Google in relation
+to the SDK.
+</p> 
+<p> 
+	14.2 You agree that if Google does not exercise or enforce any legal right or remedy which
+is contained in this License Agreement (or which Google has the benefit of under any applicable
+law), this will not be taken to be a formal waiver of Google's rights and that those rights or
+remedies will still be available to Google.
+</p> 
+<p> 
+	14.3 If any court of law, having the jurisdiction to decide on this matter, rules that any
+provision of this License Agreement is invalid, then that provision will be removed from this
+License Agreement without affecting the rest of this License Agreement. The remaining provisions of
+this License Agreement will continue to be valid and enforceable.
+</p> 
+<p> 
+	14.4 You acknowledge and agree that each member of the group of companies of which Google is
+the parent shall be third party beneficiaries to this License Agreement and that such other
+companies shall be entitled to directly enforce, and rely upon, any provision of this License
+Agreement that confers a benefit on (or rights in favor of) them. Other than this, no other person
+or company shall be third party beneficiaries to this License Agreement.
+</p> 
+<p> 
+	14.5 EXPORT RESTRICTIONS. THE SDK IS SUBJECT TO UNITED STATES EXPORT LAWS AND REGULATIONS.
+YOU MUST COMPLY WITH ALL DOMESTIC AND INTERNATIONAL EXPORT LAWS AND REGULATIONS THAT APPLY TO THE
+SDK. THESE LAWS INCLUDE RESTRICTIONS ON DESTINATIONS, END USERS AND END USE.
+</p> 
+<p> 
+	14.6 The rights granted in this License Agreement may not be assigned or transferred by
+either you or Google without the prior written approval of the other party. Neither you nor Google
+shall be permitted to delegate their responsibilities or obligations under this License Agreement
+without the prior written approval of the other party.
+</p> 
+<p> 
+	14.7 This License Agreement, and your relationship with Google under this License Agreement,
+shall be governed by the laws of the State of California without regard to its conflict of laws
+provisions. You and Google agree to submit to the exclusive jurisdiction of the courts located
+within the county of Santa Clara, California to resolve any legal matter arising from this License
+Agreement. Notwithstanding this, you agree that Google shall still be allowed to apply for
+injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction.
+</p> 
+<p> 
+	<em>April 10, 2009</em> 
+</p> 
\ No newline at end of file
diff --git a/include/android_runtime/AndroidRuntime.h b/include/android_runtime/AndroidRuntime.h
index 22c9b72..b02a057 100644
--- a/include/android_runtime/AndroidRuntime.h
+++ b/include/android_runtime/AndroidRuntime.h
@@ -46,17 +46,13 @@
         const char* className, const JNINativeMethod* gMethods, int numMethods);
 
     /**
-     * Call a static Java function that takes no arguments and returns void.
-     */
-    status_t callStatic(const char* className, const char* methodName);
-
-    /**
      * Call a class's static main method with the given arguments,
      */
-    status_t callMain(const char* className, int argc, const char* const argv[]);
+    status_t callMain(const char* className, jclass clazz, int argc,
+        const char* const argv[]);
 
     /**
-     * Find a class, with the input either of the form 
+     * Find a class, with the input either of the form
      * "package/class" or "package.class".
      */
     static jclass findClass(JNIEnv* env, const char* className);
@@ -67,7 +63,14 @@
     void start();       // start in android.util.RuntimeInit
 
     static AndroidRuntime* getRuntime();
-    
+
+    /**
+     * This gets called after the VM has been created, but before we
+     * run any code. Override it to make any FindClass calls that need
+     * to use CLASSPATH.
+     */
+    virtual void onVmCreated(JNIEnv* env);
+
     /**
      * This gets called after the JavaVM has initialized.  Override it
      * with the system's native entry point.
@@ -98,6 +101,9 @@
     /** return a pointer to the JNIEnv pointer for this thread */
     static JNIEnv* getJNIEnv();
 
+    /** return a new string corresponding to 'className' with all '.'s replaced by '/'s. */
+    static char* toSlashClassName(const char* className);
+
 private:
     static int startReg(JNIEnv* env);
     void parseExtraOpts(char* extraOptsBuf);
@@ -112,7 +118,7 @@
      * Thread creation helpers.
      */
     static int javaCreateThreadEtc(
-                                android_thread_func_t entryFunction, 
+                                android_thread_func_t entryFunction,
                                 void* userData,
                                 const char* threadName,
                                 int32_t threadPriority,
@@ -121,9 +127,6 @@
     static int javaThreadShell(void* args);
 };
 
-// Returns the Unix file descriptor for a ParcelFileDescriptor object
-extern int getParcelFileDescriptorFD(JNIEnv* env, jobject object);
-
 extern CursorWindow * get_window_from_object(JNIEnv * env, jobject javaWindow);
 
 }
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 7930f47..e272839 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -308,6 +308,44 @@
     // 0.3333, EV is -2.
     // Example value: "0.333333333" or "0.5". Read only.
     static const char KEY_EXPOSURE_COMPENSATION_STEP[];
+    // The maximum number of metering areas supported. This is the maximum
+    // length of KEY_METERING_AREAS.
+    // Example value: "0" or "2". Read only.
+    static const char KEY_MAX_NUM_METERING_AREAS[];
+    // Current metering areas. Camera driver uses these areas to decide
+    // exposure.
+    //
+    // Before accessing this parameter, apps should check
+    // KEY_MAX_NUM_METERING_AREAS first to know the maximum number of metering
+    // areas first. If the value is 0, metering area is not supported.
+    //
+    // Each metering area is a rectangle with specified weight. The direction is
+    // relative to the sensor orientation, that is, what the sensor sees. The
+    // direction is not affected by the rotation or mirroring of
+    // CAMERA_CMD_SET_DISPLAY_ORIENTATION. Coordinates of the rectangle range
+    // from -1000 to 1000. (-1000, -1000) is the upper left point. (1000, 1000)
+    // is the lower right point. The length and width of metering areas cannot
+    // be 0 or negative.
+    //
+    // The weight ranges from 1 to 1000. The sum of the weights of all metering
+    // areas must be 1000. Metering areas can partially overlap and the driver
+    // will add the weights in the overlap region. But apps should not set two
+    // metering areas that have identical coordinates.
+    //
+    // A special case of all-zero single metering area means driver to decide
+    // the metering area. For example, the driver may use more signals to decide
+    // metering areas and change them dynamically. Apps can set all-zero if they
+    // want the driver to decide metering areas.
+    //
+    // Metering areas are relative to the current field of view (KEY_ZOOM).
+    // No matter what the zoom level is, (-1000,-1000) represents the top of the
+    // currently visible camera frame. The metering area cannot be set to be
+    // outside the current field of view, even when using zoom.
+    //
+    // No matter what metering areas are, the final exposure are compensated
+    // by KEY_EXPOSURE_COMPENSATION.
+    // Example value: "(-10,-10,0,0,300),(0,0,10,10,700)". Read/write.
+    static const char KEY_METERING_AREAS[];
     // Current zoom value.
     // Example value: "0" or "6". Read/write.
     static const char KEY_ZOOM[];
diff --git a/include/media/IMediaPlayerClient.h b/include/media/IMediaPlayerClient.h
index eee6c97..daec1c7 100644
--- a/include/media/IMediaPlayerClient.h
+++ b/include/media/IMediaPlayerClient.h
@@ -28,7 +28,7 @@
 public:
     DECLARE_META_INTERFACE(MediaPlayerClient);
 
-    virtual void notify(int msg, int ext1, int ext2) = 0;
+    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 447942b..e1b6dd6 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -55,7 +55,8 @@
 
 
 // callback mechanism for passing messages to MediaPlayer object
-typedef void (*notify_callback_f)(void* cookie, int msg, int ext1, int ext2);
+typedef void (*notify_callback_f)(void* cookie,
+        int msg, int ext1, int ext2, const Parcel *obj);
 
 // abstract base class - use MediaPlayerInterface
 class MediaPlayerBase : public RefBase
@@ -159,9 +160,10 @@
         mCookie = cookie; mNotify = notifyFunc;
     }
 
-    void        sendEvent(int msg, int ext1=0, int ext2=0) {
+    void        sendEvent(int msg, int ext1=0, int ext2=0,
+                          const Parcel *obj=NULL) {
         Mutex::Autolock autoLock(mNotifyLock);
-        if (mNotify) mNotify(mCookie, msg, ext1, ext2);
+        if (mNotify) mNotify(mCookie, msg, ext1, ext2, obj);
     }
 
 private:
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 528eeb9..748e489 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -37,6 +37,7 @@
     MEDIA_BUFFERING_UPDATE  = 3,
     MEDIA_SEEK_COMPLETE     = 4,
     MEDIA_SET_VIDEO_SIZE    = 5,
+    MEDIA_TIMED_TEXT        = 99,
     MEDIA_ERROR             = 100,
     MEDIA_INFO              = 200,
 };
@@ -129,7 +130,7 @@
 class MediaPlayerListener: virtual public RefBase
 {
 public:
-    virtual void notify(int msg, int ext1, int ext2) = 0;
+    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = 0;
 };
 
 class MediaPlayer : public BnMediaPlayerClient,
@@ -166,7 +167,7 @@
             status_t        setLooping(int loop);
             bool            isLooping();
             status_t        setVolume(float leftVolume, float rightVolume);
-            void            notify(int msg, int ext1, int ext2);
+            void            notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
     static  sp<IMemory>     decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
     static  sp<IMemory>     decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
             status_t        invoke(const Parcel& request, Parcel *reply);
diff --git a/include/utils/AssetManager.h b/include/utils/AssetManager.h
index 9e2bf37..a8c7ddb 100644
--- a/include/utils/AssetManager.h
+++ b/include/utils/AssetManager.h
@@ -222,6 +222,7 @@
     {
         String8 path;
         FileType type;
+        String8 idmap;
     };
 
     Asset* openInPathLocked(const char* fileName, AccessMode mode,
@@ -262,6 +263,16 @@
     void setLocaleLocked(const char* locale);
     void updateResourceParamsLocked() const;
 
+    bool createIdmapFileLocked(const String8& originalPath, const String8& overlayPath,
+                               const String8& idmapPath);
+
+    bool isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath,
+                            const String8& idmapPath);
+
+    Asset* openIdmapLocked(const struct asset_path& ap) const;
+
+    bool getZipEntryCrcLocked(const String8& zipPath, const char* entryFilename, uint32_t* pCrc);
+
     class SharedZip : public RefBase {
     public:
         static sp<SharedZip> get(const String8& path);
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index 35792dc..173412e 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -1798,9 +1798,9 @@
     ~ResTable();
 
     status_t add(const void* data, size_t size, void* cookie,
-                 bool copyData=false);
+                 bool copyData=false, const void* idmap = NULL);
     status_t add(Asset* asset, void* cookie,
-                 bool copyData=false);
+                 bool copyData=false, const void* idmap = NULL);
     status_t add(ResTable* src);
 
     status_t getError() const;
@@ -2046,6 +2046,24 @@
 
     void getLocales(Vector<String8>* locales) const;
 
+    // Generate an idmap.
+    //
+    // Return value: on success: NO_ERROR; caller is responsible for free-ing
+    // outData (using free(3)). On failure, any status_t value other than
+    // NO_ERROR; the caller should not free outData.
+    status_t createIdmap(const ResTable& overlay, uint32_t originalCrc, uint32_t overlayCrc,
+                         void** outData, size_t* outSize) const;
+
+    enum {
+        IDMAP_HEADER_SIZE_BYTES = 3 * sizeof(uint32_t),
+    };
+    // Retrieve idmap meta-data.
+    //
+    // This function only requires the idmap header (the first
+    // IDMAP_HEADER_SIZE_BYTES) bytes of an idmap file.
+    static bool getIdmapInfo(const void* idmap, size_t size,
+                             uint32_t* pOriginalCrc, uint32_t* pOverlayCrc);
+
 #ifndef HAVE_ANDROID_OS
     void print(bool inclValues) const;
     static String8 normalizeForOutput(const char* input);
@@ -2059,7 +2077,7 @@
     struct bag_set;
 
     status_t add(const void* data, size_t size, void* cookie,
-                 Asset* asset, bool copyData);
+                 Asset* asset, bool copyData, const Asset* idmap);
 
     ssize_t getResourcePackageIndex(uint32_t resID) const;
     ssize_t getEntry(
@@ -2068,7 +2086,7 @@
         const ResTable_type** outType, const ResTable_entry** outEntry,
         const Type** outTypeClass) const;
     status_t parsePackage(
-        const ResTable_package* const pkg, const Header* const header);
+        const ResTable_package* const pkg, const Header* const header, uint32_t idmap_id);
 
     void print_value(const Package* pkg, const Res_value& value) const;
     
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index d57f2c9..6ed85d7 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -338,7 +338,7 @@
 
 status_t Parcel::setDataCapacity(size_t size)
 {
-    if (size > mDataSize) return continueWrite(size);
+    if (size > mDataCapacity) return continueWrite(size);
     return NO_ERROR;
 }
 
@@ -386,10 +386,12 @@
     }
     int numObjects = lastIndex - firstIndex + 1;
 
-    // grow data
-    err = growData(len);
-    if (err != NO_ERROR) {
-        return err;
+    if ((mDataSize+len) > mDataCapacity) {
+        // grow data
+        err = growData(len);
+        if (err != NO_ERROR) {
+            return err;
+        }
     }
 
     // append data
@@ -1384,8 +1386,10 @@
                 return NO_MEMORY;
             }
         } else {
-            mDataSize = desired;
-            LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
+            if (mDataSize > desired) {
+                mDataSize = desired;
+                LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
+            }
             if (mDataPos > desired) {
                 mDataPos = desired;
                 LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp
index 1e7abae..214cd4d 100644
--- a/libs/camera/CameraParameters.cpp
+++ b/libs/camera/CameraParameters.cpp
@@ -68,6 +68,8 @@
 const char CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION[] = "max-exposure-compensation";
 const char CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION[] = "min-exposure-compensation";
 const char CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP[] = "exposure-compensation-step";
+const char CameraParameters::KEY_MAX_NUM_METERING_AREAS[] = "max-num-metering-areas";
+const char CameraParameters::KEY_METERING_AREAS[] = "metering-areas";
 const char CameraParameters::KEY_ZOOM[] = "zoom";
 const char CameraParameters::KEY_MAX_ZOOM[] = "max-zoom";
 const char CameraParameters::KEY_ZOOM_RATIOS[] = "zoom-ratios";
diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp
index 6e57d93..e41dd39 100644
--- a/libs/utils/AssetManager.cpp
+++ b/libs/utils/AssetManager.cpp
@@ -37,6 +37,19 @@
 #include <errno.h>
 #include <assert.h>
 #include <strings.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    typeof (exp) _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+#endif
 
 using namespace android;
 
@@ -49,6 +62,7 @@
 static const char* kAssetsRoot = "assets";
 static const char* kAppZipName = NULL; //"classes.jar";
 static const char* kSystemAssets = "framework/framework-res.apk";
+static const char* kIdmapCacheDir = "resource-cache";
 
 static const char* kExcludeExtension = ".EXCLUDE";
 
@@ -56,6 +70,35 @@
 
 static volatile int32_t gCount = 0;
 
+namespace {
+    // Transform string /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap
+    String8 idmapPathForPackagePath(const String8& pkgPath)
+    {
+        const char* root = getenv("ANDROID_DATA");
+        LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set");
+        String8 path(root);
+        path.appendPath(kIdmapCacheDir);
+
+        char buf[256]; // 256 chars should be enough for anyone...
+        strncpy(buf, pkgPath.string(), 255);
+        buf[255] = '\0';
+        char* filename = buf;
+        while (*filename && *filename == '/') {
+            ++filename;
+        }
+        char* p = filename;
+        while (*p) {
+            if (*p == '/') {
+                *p = '@';
+            }
+            ++p;
+        }
+        path.appendPath(filename);
+        path.append("@idmap");
+
+        return path;
+    }
+}
 
 /*
  * ===========================================================================
@@ -123,7 +166,7 @@
             return true;
         }
     }
-    
+
     LOGV("In %p Asset %s path: %s", this,
          ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string());
 
@@ -134,9 +177,181 @@
         *cookie = (void*)mAssetPaths.size();
     }
 
+    // add overlay packages for /system/framework; apps are handled by the
+    // (Java) package manager
+    if (strncmp(path.string(), "/system/framework/", 18) == 0) {
+        // When there is an environment variable for /vendor, this
+        // should be changed to something similar to how ANDROID_ROOT
+        // and ANDROID_DATA are used in this file.
+        String8 overlayPath("/vendor/overlay/framework/");
+        overlayPath.append(path.getPathLeaf());
+        if (TEMP_FAILURE_RETRY(access(overlayPath.string(), R_OK)) == 0) {
+            asset_path oap;
+            oap.path = overlayPath;
+            oap.type = ::getFileType(overlayPath.string());
+            bool addOverlay = (oap.type == kFileTypeRegular); // only .apks supported as overlay
+            if (addOverlay) {
+                oap.idmap = idmapPathForPackagePath(overlayPath);
+
+                if (isIdmapStaleLocked(ap.path, oap.path, oap.idmap)) {
+                    addOverlay = createIdmapFileLocked(ap.path, oap.path, oap.idmap);
+                }
+            }
+            if (addOverlay) {
+                mAssetPaths.add(oap);
+            } else {
+                LOGW("failed to add overlay package %s\n", overlayPath.string());
+            }
+        }
+    }
+
     return true;
 }
 
+bool AssetManager::isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath,
+                                      const String8& idmapPath)
+{
+    struct stat st;
+    if (TEMP_FAILURE_RETRY(stat(idmapPath.string(), &st)) == -1) {
+        if (errno == ENOENT) {
+            return true; // non-existing idmap is always stale
+        } else {
+            LOGW("failed to stat file %s: %s\n", idmapPath.string(), strerror(errno));
+            return false;
+        }
+    }
+    if (st.st_size < ResTable::IDMAP_HEADER_SIZE_BYTES) {
+        LOGW("file %s has unexpectedly small size=%zd\n", idmapPath.string(), (size_t)st.st_size);
+        return false;
+    }
+    int fd = TEMP_FAILURE_RETRY(::open(idmapPath.string(), O_RDONLY));
+    if (fd == -1) {
+        LOGW("failed to open file %s: %s\n", idmapPath.string(), strerror(errno));
+        return false;
+    }
+    char buf[ResTable::IDMAP_HEADER_SIZE_BYTES];
+    ssize_t bytesLeft = ResTable::IDMAP_HEADER_SIZE_BYTES;
+    for (;;) {
+        ssize_t r = TEMP_FAILURE_RETRY(read(fd, buf + ResTable::IDMAP_HEADER_SIZE_BYTES - bytesLeft,
+                                            bytesLeft));
+        if (r < 0) {
+            TEMP_FAILURE_RETRY(close(fd));
+            return false;
+        }
+        bytesLeft -= r;
+        if (bytesLeft == 0) {
+            break;
+        }
+    }
+    TEMP_FAILURE_RETRY(close(fd));
+
+    uint32_t cachedOriginalCrc, cachedOverlayCrc;
+    if (!ResTable::getIdmapInfo(buf, ResTable::IDMAP_HEADER_SIZE_BYTES,
+                                &cachedOriginalCrc, &cachedOverlayCrc)) {
+        return false;
+    }
+
+    uint32_t actualOriginalCrc, actualOverlayCrc;
+    if (!getZipEntryCrcLocked(originalPath, "resources.arsc", &actualOriginalCrc)) {
+        return false;
+    }
+    if (!getZipEntryCrcLocked(overlayPath, "resources.arsc", &actualOverlayCrc)) {
+        return false;
+    }
+    return cachedOriginalCrc != actualOriginalCrc || cachedOverlayCrc != actualOverlayCrc;
+}
+
+bool AssetManager::getZipEntryCrcLocked(const String8& zipPath, const char* entryFilename,
+                                        uint32_t* pCrc)
+{
+    asset_path ap;
+    ap.path = zipPath;
+    const ZipFileRO* zip = getZipFileLocked(ap);
+    if (zip == NULL) {
+        return false;
+    }
+    const ZipEntryRO entry = zip->findEntryByName(entryFilename);
+    if (entry == NULL) {
+        return false;
+    }
+    if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, (long*)pCrc)) {
+        return false;
+    }
+    return true;
+}
+
+bool AssetManager::createIdmapFileLocked(const String8& originalPath, const String8& overlayPath,
+                                         const String8& idmapPath)
+{
+    LOGD("%s: originalPath=%s overlayPath=%s idmapPath=%s\n",
+         __FUNCTION__, originalPath.string(), overlayPath.string(), idmapPath.string());
+    ResTable tables[2];
+    const String8* paths[2] = { &originalPath, &overlayPath };
+    uint32_t originalCrc, overlayCrc;
+    bool retval = false;
+    ssize_t offset = 0;
+    int fd = 0;
+    uint32_t* data = NULL;
+    size_t size;
+
+    for (int i = 0; i < 2; ++i) {
+        asset_path ap;
+        ap.type = kFileTypeRegular;
+        ap.path = *paths[i];
+        Asset* ass = openNonAssetInPathLocked("resources.arsc", Asset::ACCESS_BUFFER, ap);
+        if (ass == NULL) {
+            LOGW("failed to find resources.arsc in %s\n", ap.path.string());
+            goto error;
+        }
+        tables[i].add(ass, (void*)1, false);
+    }
+
+    if (!getZipEntryCrcLocked(originalPath, "resources.arsc", &originalCrc)) {
+        LOGW("failed to retrieve crc for resources.arsc in %s\n", originalPath.string());
+        goto error;
+    }
+    if (!getZipEntryCrcLocked(overlayPath, "resources.arsc", &overlayCrc)) {
+        LOGW("failed to retrieve crc for resources.arsc in %s\n", overlayPath.string());
+        goto error;
+    }
+
+    if (tables[0].createIdmap(tables[1], originalCrc, overlayCrc,
+                              (void**)&data, &size) != NO_ERROR) {
+        LOGW("failed to generate idmap data for file %s\n", idmapPath.string());
+        goto error;
+    }
+
+    // This should be abstracted (eg replaced by a stand-alone
+    // application like dexopt, triggered by something equivalent to
+    // installd).
+    fd = TEMP_FAILURE_RETRY(::open(idmapPath.string(), O_WRONLY | O_CREAT | O_TRUNC, 0644));
+    if (fd == -1) {
+        LOGW("failed to write idmap file %s (open: %s)\n", idmapPath.string(), strerror(errno));
+        goto error_free;
+    }
+    for (;;) {
+        ssize_t written = TEMP_FAILURE_RETRY(write(fd, data + offset, size));
+        if (written < 0) {
+            LOGW("failed to write idmap file %s (write: %s)\n", idmapPath.string(),
+                 strerror(errno));
+            goto error_close;
+        }
+        size -= (size_t)written;
+        offset += written;
+        if (size == 0) {
+            break;
+        }
+    }
+
+    retval = true;
+error_close:
+    TEMP_FAILURE_RETRY(close(fd));
+error_free:
+    free(data);
+error:
+    return retval;
+}
+
 bool AssetManager::addDefaultAssets()
 {
     const char* root = getenv("ANDROID_ROOT");
@@ -405,6 +620,7 @@
         ResTable* sharedRes = NULL;
         bool shared = true;
         const asset_path& ap = mAssetPaths.itemAt(i);
+        Asset* idmap = openIdmapLocked(ap);
         LOGV("Looking for resource asset in '%s'\n", ap.path.string());
         if (ap.type != kFileTypeDirectory) {
             if (i == 0) {
@@ -434,7 +650,7 @@
                     // can quickly copy it out for others.
                     LOGV("Creating shared resources for %s", ap.path.string());
                     sharedRes = new ResTable();
-                    sharedRes->add(ass, (void*)(i+1), false);
+                    sharedRes->add(ass, (void*)(i+1), false, idmap);
                     sharedRes = const_cast<AssetManager*>(this)->
                         mZipSet.setZipResourceTable(ap.path, sharedRes);
                 }
@@ -458,7 +674,7 @@
                 rt->add(sharedRes);
             } else {
                 LOGV("Parsing resources for %s", ap.path.string());
-                rt->add(ass, (void*)(i+1), !shared);
+                rt->add(ass, (void*)(i+1), !shared, idmap);
             }
 
             if (!shared) {
@@ -499,6 +715,21 @@
     res->setParameters(mConfig);
 }
 
+Asset* AssetManager::openIdmapLocked(const struct asset_path& ap) const
+{
+    Asset* ass = NULL;
+    if (ap.idmap.size() != 0) {
+        ass = const_cast<AssetManager*>(this)->
+            openAssetFromFileLocked(ap.idmap, Asset::ACCESS_BUFFER);
+        if (ass) {
+            LOGV("loading idmap %s\n", ap.idmap.string());
+        } else {
+            LOGW("failed to load idmap %s\n", ap.idmap.string());
+        }
+    }
+    return ass;
+}
+
 const ResTable& AssetManager::getResources(bool required) const
 {
     const ResTable* rt = getResTable(required);
diff --git a/libs/utils/README b/libs/utils/README
index 36a706d..01741e0 100644
--- a/libs/utils/README
+++ b/libs/utils/README
@@ -1,4 +1,6 @@
 Android Utility Function Library
+================================
+
 
 If you need a feature that is native to Linux but not present on other
 platforms, construct a platform-dependent implementation that shares
@@ -12,3 +14,276 @@
 layer.  The goal is to provide an optimized solution for Linux with
 reasonable implementations for other platforms.
 
+
+
+Resource overlay
+================
+
+
+Introduction
+------------
+
+Overlay packages are special .apk files which provide no code but
+additional resource values (and possibly new configurations) for
+resources in other packages. When an application requests resources,
+the system will return values from either the application's original
+package or any associated overlay package. Any redirection is completely
+transparent to the calling application.
+
+Resource values have the following precedence table, listed in
+descending precedence.
+
+ * overlay package, matching config (eg res/values-en-land)
+
+ * original package, matching config
+
+ * overlay package, no config (eg res/values)
+
+ * original package, no config
+
+During compilation, overlay packages are differentiated from regular
+packages by passing the -o flag to aapt.
+
+
+Background
+----------
+
+This section provides generic background material on resources in
+Android.
+
+
+How resources are bundled in .apk files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Android .apk files are .zip files, usually housing .dex code,
+certificates and resources, though packages containing resources but
+no code are possible. Resources can be divided into the following
+categories; a `configuration' indicates a set of phone language, display
+density, network operator, etc.
+
+ * assets: uncompressed, raw files packaged as part of an .apk and
+           explicitly referenced by filename. These files are
+           independent of configuration.
+
+ * res/drawable: bitmap or xml graphics. Each file may have different
+                 values depending on configuration.
+
+ * res/values: integers, strings, etc. Each resource may have different
+               values depending on configuration.
+
+Resource meta information and information proper is stored in a binary
+format in a named file resources.arsc, bundled as part of the .apk.
+
+Resource IDs and lookup
+~~~~~~~~~~~~~~~~~~~~~~~
+During compilation, the aapt tool gathers application resources and
+generates a resources.arsc file. Each resource name is assigned an
+integer ID 0xppttiii (translated to a symbolic name via R.java), where
+
+ * pp: corresponds to the package namespace (details below).
+
+ * tt: corresponds to the resource type (string, int, etc). Every
+       resource of the same type within the same package has the same
+       tt value, but depending on available types, the actual numerical
+       value may be different between packages.
+
+ * iiii: sequential number, assigned in the order resources are found.
+
+Resource values are specified paired with a set of configuration
+constraints (the default being the empty set), eg res/values-sv-port
+which imposes restrictions on language (Swedish) and display orientation
+(portrait). During lookup, every constraint set is matched against the
+current configuration, and the value corresponding to the best matching
+constraint set is returned (ResourceTypes.{h,cpp}).
+
+Parsing of resources.arsc is handled by ResourceTypes.cpp; this utility
+is governed by AssetManager.cpp, which tracks loaded resources per
+process.
+
+Assets are looked up by path and filename in AssetManager.cpp. The path
+to resources in res/drawable are located by ResourceTypes.cpp and then
+handled like assets by AssetManager.cpp. Other resources are handled
+solely by ResourceTypes.cpp.
+
+Package ID as namespace
+~~~~~~~~~~~~~~~~~~~~~~~
+The pp part of a resource ID defines a namespace. Android currently
+defines two namespaces:
+
+ * 0x01: system resources (pre-installed in framework-res.apk)
+
+ * 0x7f: application resources (bundled in the application .apk)
+
+ResourceTypes.cpp supports package IDs between 0x01 and 0x7f
+(inclusive); values outside this range are invalid.
+
+Each running (Dalvik) process is assigned a unique instance of
+AssetManager, which in turn keeps a forest structure of loaded
+resource.arsc files. Normally, this forest is structured as follows,
+where mPackageMap is the internal vector employed in ResourceTypes.cpp.
+
+mPackageMap[0x00] -> system package
+mPackageMap[0x01] -> NULL
+mPackageMap[0x02] -> NULL
+...
+mPackageMap[0x7f - 2] -> NULL
+mPackageMap[0x7f - 1] -> application package
+
+
+
+The resource overlay extension
+------------------------------
+
+The resource overlay mechanism aims to (partly) shadow and extend
+existing resources with new values for defined and new configurations.
+Technically, this is achieved by adding resource-only packages (called
+overlay packages) to existing resource namespaces, like so:
+
+mPackageMap[0x00] -> system package -> system overlay package
+mPackageMap[0x01] -> NULL
+mPackageMap[0x02] -> NULL
+...
+mPackageMap[0x7f - 2] -> NULL
+mPackageMap[0x7f - 1] -> application package -> overlay 1 -> overlay 2
+
+The use of overlay resources is completely transparent to
+applications; no additional resource identifiers are introduced, only
+configuration/value pairs. Any number of overlay packages may be loaded
+at a time; overlay packages are agnostic to what they target -- both
+system and application resources are fair game.
+
+The package targeted by an overlay package is called the target or
+original package.
+
+Resource overlay operates on symbolic resources names. Hence, to
+override the string/str1 resources in a package, the overlay package
+would include a resource also named string/str1. The end user does not
+have to worry about the numeric resources IDs assigned by aapt, as this
+is resolved automatically by the system.
+
+As of this writing, the use of resource overlay has not been fully
+explored. Until it has, only OEMs are trusted to use resource overlay.
+For this reason, overlay packages must reside in /system/overlay.
+
+
+Resource ID mapping
+~~~~~~~~~~~~~~~~~~~
+Resource identifiers must be coherent within the same namespace (ie
+PackageGroup in ResourceTypes.cpp). Calling applications will refer to
+resources using the IDs defined in the original package, but there is no
+guarantee aapt has assigned the same ID to the corresponding resource in
+an overlay package. To translate between the two, a resource ID mapping
+{original ID -> overlay ID} is created during package installation
+(PackageManagerService.java) and used during resource lookup. The
+mapping is stored in /data/resource-cache, with a @idmap file name
+suffix.
+
+The idmap file format is documented in a separate section, below.
+
+
+Package management
+~~~~~~~~~~~~~~~~~~
+Packages are managed by the PackageManagerService. Addition and removal
+of packages are monitored via the inotify framework, exposed via
+android.os.FileObserver.
+
+During initialization of a Dalvik process, ActivityThread.java requests
+the process' AssetManager (by proxy, via AssetManager.java and JNI)
+to load a list of packages. This list includes overlay packages, if
+present.
+
+When a target package or a corresponding overlay package is installed,
+the target package's process is stopped and a new idmap is generated.
+This is similar to how applications are stopped when their packages are
+upgraded.
+
+
+Creating overlay packages
+-------------------------
+
+Overlay packages should contain no code, define (some) resources with
+the same type and name as in the original package, and be compiled with
+the -o flag passed to aapt.
+
+The aapt -o flag instructs aapt to create an overlay package.
+Technically, this means the package will be assigned package id 0x00.
+
+There are no restrictions on overlay packages names, though the naming
+convention <original.package.name>.overlay.<name> is recommended.
+
+
+Example overlay package
+~~~~~~~~~~~~~~~~~~~~~~~
+
+To overlay the resource bool/b in package com.foo.bar, to be applied
+when the display is in landscape mode, create a new package with
+no source code and a single .xml file under res/values-land, with
+an entry for bool/b. Compile with aapt -o and place the results in
+/system/overlay by adding the following to Android.mk:
+
+LOCAL_AAPT_FLAGS := -o com.foo.bar
+LOCAL_MODULE_PATH := $(TARGET_OUT)/overlay
+
+
+The ID map (idmap) file format
+------------------------------
+
+The idmap format is designed for lookup performance. However, leading
+and trailing undefined overlay values are discarded to reduce the memory
+footprint.
+
+
+idmap grammar
+~~~~~~~~~~~~~
+All atoms (names in square brackets) are uint32_t integers. The
+idmap-magic constant spells "idmp" in ASCII. Offsets are given relative
+to the data_header, not to the beginning of the file.
+
+map          := header data
+header       := idmap-magic <crc32-original-pkg> <crc32-overlay-pkg>
+idmap-magic  := <0x706d6469>
+data         := data_header type_block+
+data_header  := <m> header_block{m}
+header_block := <0> | <type_block_offset>
+type_block   := <n> <id_offset> entry{n}
+entry        := <resource_id_in_target_package>
+
+
+idmap example
+~~~~~~~~~~~~~
+Given a pair of target and overlay packages with CRC sums 0x216a8fe2
+and 0x6b9beaec, each defining the following resources
+
+Name          Target package  Overlay package
+string/str0   0x7f010000      -
+string/str1   0x7f010001      0x7f010000
+string/str2   0x7f010002      -
+string/str3   0x7f010003      0x7f010001
+string/str4   0x7f010004      -
+bool/bool0    0x7f020000      -
+integer/int0  0x7f030000      0x7f020000
+integer/int1  0x7f030001      -
+
+the corresponding resource map is
+
+0x706d6469 0x216a8fe2 0x6b9beaec 0x00000003 \
+0x00000004 0x00000000 0x00000009 0x00000003 \
+0x00000001 0x7f010000 0x00000000 0x7f010001 \
+0x00000001 0x00000000 0x7f020000
+
+or, formatted differently
+
+0x706d6469  # magic: all idmap files begin with this constant
+0x216a8fe2  # CRC32 of the resources.arsc file in the original package
+0x6b9beaec  # CRC32 of the resources.arsc file in the overlay package
+0x00000003  # header; three types (string, bool, integer) in the target package
+0x00000004  #   header_block for type 0 (string) is located at offset 4
+0x00000000  #   no bool type exists in overlay package -> no header_block
+0x00000009  #   header_block for type 2 (integer) is located at offset 9
+0x00000003  # header_block for string; overlay IDs span 3 elements
+0x00000001  #   the first string in target package is entry 1 == offset
+0x7f010000  #   target 0x7f01001 -> overlay 0x7f010000
+0x00000000  #   str2 not defined in overlay package
+0x7f010001  #   target 0x7f010003 -> overlay 0x7f010001
+0x00000001  # header_block for integer; overlay IDs span 1 element
+0x00000000  #   offset == 0
+0x7f020000  #   target 0x7f030000 -> overlay 0x7f020000
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index ac9cdf9..784c9d2 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -63,6 +63,10 @@
 #endif
 #endif
 
+#define IDMAP_MAGIC         0x706d6469
+// size measured in sizeof(uint32_t)
+#define IDMAP_HEADER_SIZE (ResTable::IDMAP_HEADER_SIZE_BYTES / sizeof(uint32_t))
+
 static void printToLogFunc(void* cookie, const char* txt)
 {
     LOGV("%s", txt);
@@ -214,6 +218,81 @@
     outData->colors = (uint32_t*) data;
 }
 
+static bool assertIdmapHeader(const uint32_t* map, size_t sizeBytes)
+{
+    if (sizeBytes < ResTable::IDMAP_HEADER_SIZE_BYTES) {
+        LOGW("idmap assertion failed: size=%d bytes\n", sizeBytes);
+        return false;
+    }
+    if (*map != htodl(IDMAP_MAGIC)) { // htodl: map data expected to be in correct endianess
+        LOGW("idmap assertion failed: invalid magic found (is 0x%08x, expected 0x%08x)\n",
+             *map, htodl(IDMAP_MAGIC));
+        return false;
+    }
+    return true;
+}
+
+static status_t idmapLookup(const uint32_t* map, size_t sizeBytes, uint32_t key, uint32_t* outValue)
+{
+    // see README for details on the format of map
+    if (!assertIdmapHeader(map, sizeBytes)) {
+        return UNKNOWN_ERROR;
+    }
+    map = map + IDMAP_HEADER_SIZE; // skip ahead to data segment
+    // size of data block, in uint32_t
+    const size_t size = (sizeBytes - ResTable::IDMAP_HEADER_SIZE_BYTES) / sizeof(uint32_t);
+    const uint32_t type = Res_GETTYPE(key) + 1; // add one, idmap stores "public" type id
+    const uint32_t entry = Res_GETENTRY(key);
+    const uint32_t typeCount = *map;
+
+    if (type > typeCount) {
+        LOGW("Resource ID map: type=%d exceeds number of types=%d\n", type, typeCount);
+        return UNKNOWN_ERROR;
+    }
+    if (typeCount > size) {
+        LOGW("Resource ID map: number of types=%d exceeds size of map=%d\n", typeCount, size);
+        return UNKNOWN_ERROR;
+    }
+    const uint32_t typeOffset = map[type];
+    if (typeOffset == 0) {
+        *outValue = 0;
+        return NO_ERROR;
+    }
+    if (typeOffset + 1 > size) {
+        LOGW("Resource ID map: type offset=%d exceeds reasonable value, size of map=%d\n",
+             typeOffset, size);
+        return UNKNOWN_ERROR;
+    }
+    const uint32_t entryCount = map[typeOffset];
+    const uint32_t entryOffset = map[typeOffset + 1];
+    if (entryCount == 0 || entry < entryOffset || entry - entryOffset > entryCount - 1) {
+        *outValue = 0;
+        return NO_ERROR;
+    }
+    const uint32_t index = typeOffset + 2 + entry - entryOffset;
+    if (index > size) {
+        LOGW("Resource ID map: entry index=%d exceeds size of map=%d\n", index, size);
+        *outValue = 0;
+        return NO_ERROR;
+    }
+    *outValue = map[index];
+
+    return NO_ERROR;
+}
+
+static status_t getIdmapPackageId(const uint32_t* map, size_t mapSize, uint32_t *outId)
+{
+    if (!assertIdmapHeader(map, mapSize)) {
+        return UNKNOWN_ERROR;
+    }
+    const uint32_t* p = map + IDMAP_HEADER_SIZE + 1;
+    while (*p == 0) {
+        ++p;
+    }
+    *outId = (map[*p + IDMAP_HEADER_SIZE + 2] >> 24) & 0x000000ff;
+    return NO_ERROR;
+}
+
 Res_png_9patch* Res_png_9patch::deserialize(const void* inData)
 {
     if (sizeof(void*) != sizeof(int32_t)) {
@@ -1290,7 +1369,13 @@
 
 struct ResTable::Header
 {
-    Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL) { }
+    Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL),
+        resourceIDMap(NULL), resourceIDMapSize(0) { }
+
+    ~Header()
+    {
+        free(resourceIDMap);
+    }
 
     ResTable* const                 owner;
     void*                           ownedData;
@@ -1301,6 +1386,8 @@
     void*                           cookie;
 
     ResStringPool                   values;
+    uint32_t*                       resourceIDMap;
+    size_t                          resourceIDMapSize;
 };
 
 struct ResTable::Type
@@ -1716,12 +1803,13 @@
     return ((ssize_t)mPackageMap[Res_GETPACKAGE(resID)+1])-1;
 }
 
-status_t ResTable::add(const void* data, size_t size, void* cookie, bool copyData)
+status_t ResTable::add(const void* data, size_t size, void* cookie, bool copyData,
+                       const void* idmap)
 {
-    return add(data, size, cookie, NULL, copyData);
+    return add(data, size, cookie, NULL, copyData, reinterpret_cast<const Asset*>(idmap));
 }
 
-status_t ResTable::add(Asset* asset, void* cookie, bool copyData)
+status_t ResTable::add(Asset* asset, void* cookie, bool copyData, const void* idmap)
 {
     const void* data = asset->getBuffer(true);
     if (data == NULL) {
@@ -1729,7 +1817,7 @@
         return UNKNOWN_ERROR;
     }
     size_t size = (size_t)asset->getLength();
-    return add(data, size, cookie, asset, copyData);
+    return add(data, size, cookie, asset, copyData, reinterpret_cast<const Asset*>(idmap));
 }
 
 status_t ResTable::add(ResTable* src)
@@ -1757,19 +1845,30 @@
 }
 
 status_t ResTable::add(const void* data, size_t size, void* cookie,
-                       Asset* asset, bool copyData)
+                       Asset* asset, bool copyData, const Asset* idmap)
 {
     if (!data) return NO_ERROR;
     Header* header = new Header(this);
     header->index = mHeaders.size();
     header->cookie = cookie;
+    if (idmap != NULL) {
+        const size_t idmap_size = idmap->getLength();
+        const void* idmap_data = const_cast<Asset*>(idmap)->getBuffer(true);
+        header->resourceIDMap = (uint32_t*)malloc(idmap_size);
+        if (header->resourceIDMap == NULL) {
+            delete header;
+            return (mError = NO_MEMORY);
+        }
+        memcpy((void*)header->resourceIDMap, idmap_data, idmap_size);
+        header->resourceIDMapSize = idmap_size;
+    }
     mHeaders.add(header);
 
     const bool notDeviceEndian = htods(0xf0) != 0xf0;
 
     LOAD_TABLE_NOISY(
-        LOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%p, asset=%p, copy=%d\n",
-             data, size, cookie, asset, copyData));
+        LOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%p, asset=%p, copy=%d "
+             "idmap=%p\n", data, size, cookie, asset, copyData, idmap));
     
     if (copyData || notDeviceEndian) {
         header->ownedData = malloc(size);
@@ -1836,7 +1935,16 @@
                      dtohl(header->header->packageCount));
                 return (mError=BAD_TYPE);
             }
-            if (parsePackage((ResTable_package*)chunk, header) != NO_ERROR) {
+            uint32_t idmap_id = 0;
+            if (idmap != NULL) {
+                uint32_t tmp;
+                if (getIdmapPackageId(header->resourceIDMap,
+                                      header->resourceIDMapSize,
+                                      &tmp) == NO_ERROR) {
+                    idmap_id = tmp;
+                }
+            }
+            if (parsePackage((ResTable_package*)chunk, header, idmap_id) != NO_ERROR) {
                 return mError;
             }
             curPackage++;
@@ -1858,6 +1966,7 @@
     if (mError != NO_ERROR) {
         LOGW("No string values found in resource table!");
     }
+
     TABLE_NOISY(LOGV("Returning from add with mError=%d\n", mError));
     return mError;
 }
@@ -2002,17 +2111,38 @@
     size_t ip = grp->packages.size();
     while (ip > 0) {
         ip--;
+        int T = t;
+        int E = e;
 
         const Package* const package = grp->packages[ip];
+        if (package->header->resourceIDMap) {
+            uint32_t overlayResID = 0x0;
+            status_t retval = idmapLookup(package->header->resourceIDMap,
+                                          package->header->resourceIDMapSize,
+                                          resID, &overlayResID);
+            if (retval == NO_ERROR && overlayResID != 0x0) {
+                // for this loop iteration, this is the type and entry we really want
+                LOGV("resource map 0x%08x -> 0x%08x\n", resID, overlayResID);
+                T = Res_GETTYPE(overlayResID);
+                E = Res_GETENTRY(overlayResID);
+            } else {
+                // resource not present in overlay package, continue with the next package
+                continue;
+            }
+        }
 
         const ResTable_type* type;
         const ResTable_entry* entry;
         const Type* typeClass;
-        ssize_t offset = getEntry(package, t, e, desiredConfig, &type, &entry, &typeClass);
+        ssize_t offset = getEntry(package, T, E, desiredConfig, &type, &entry, &typeClass);
         if (offset <= 0) {
-            if (offset < 0) {
+            // No {entry, appropriate config} pair found in package. If this
+            // package is an overlay package (ip != 0), this simply means the
+            // overlay package did not specify a default.
+            // Non-overlay packages are still required to provide a default.
+            if (offset < 0 && ip == 0) {
                 LOGW("Failure getting entry for 0x%08x (t=%d e=%d) in package %zd (error %d)\n",
-                        resID, t, e, ip, (int)offset);
+                        resID, T, E, ip, (int)offset);
                 rc = offset;
                 goto out;
             }
@@ -2044,13 +2174,16 @@
 
         if (outSpecFlags != NULL) {
             if (typeClass->typeSpecFlags != NULL) {
-                *outSpecFlags |= dtohl(typeClass->typeSpecFlags[e]);
+                *outSpecFlags |= dtohl(typeClass->typeSpecFlags[E]);
             } else {
                 *outSpecFlags = -1;
             }
         }
-        
-        if (bestPackage != NULL && bestItem.isMoreSpecificThan(thisConfig)) {
+
+        if (bestPackage != NULL &&
+            (bestItem.isMoreSpecificThan(thisConfig) || bestItem.diff(thisConfig) == 0)) {
+            // Discard thisConfig not only if bestItem is more specific, but also if the two configs
+            // are identical (diff == 0), or overlay packages will not take effect.
             continue;
         }
         
@@ -2250,21 +2383,45 @@
 
     TABLE_NOISY(LOGI("Building bag: %p\n", (void*)resID));
     
+    ResTable_config bestConfig;
+    memset(&bestConfig, 0, sizeof(bestConfig));
+
     // Now collect all bag attributes from all packages.
     size_t ip = grp->packages.size();
     while (ip > 0) {
         ip--;
+        int T = t;
+        int E = e;
 
         const Package* const package = grp->packages[ip];
+        if (package->header->resourceIDMap) {
+            uint32_t overlayResID = 0x0;
+            status_t retval = idmapLookup(package->header->resourceIDMap,
+                                          package->header->resourceIDMapSize,
+                                          resID, &overlayResID);
+            if (retval == NO_ERROR && overlayResID != 0x0) {
+                // for this loop iteration, this is the type and entry we really want
+                LOGV("resource map 0x%08x -> 0x%08x\n", resID, overlayResID);
+                T = Res_GETTYPE(overlayResID);
+                E = Res_GETENTRY(overlayResID);
+            } else {
+                // resource not present in overlay package, continue with the next package
+                continue;
+            }
+        }
 
         const ResTable_type* type;
         const ResTable_entry* entry;
         const Type* typeClass;
-        LOGV("Getting entry pkg=%p, t=%d, e=%d\n", package, t, e);
-        ssize_t offset = getEntry(package, t, e, &mParams, &type, &entry, &typeClass);
+        LOGV("Getting entry pkg=%p, t=%d, e=%d\n", package, T, E);
+        ssize_t offset = getEntry(package, T, E, &mParams, &type, &entry, &typeClass);
         LOGV("Resulting offset=%d\n", offset);
         if (offset <= 0) {
-            if (offset < 0) {
+            // No {entry, appropriate config} pair found in package. If this
+            // package is an overlay package (ip != 0), this simply means the
+            // overlay package did not specify a default.
+            // Non-overlay packages are still required to provide a default.
+            if (offset < 0 && ip == 0) {
                 if (set) free(set);
                 return offset;
             }
@@ -2277,6 +2434,15 @@
             continue;
         }
 
+        if (set != NULL && !type->config.isBetterThan(bestConfig, NULL)) {
+            continue;
+        }
+        bestConfig = type->config;
+        if (set) {
+            free(set);
+            set = NULL;
+        }
+
         const uint16_t entrySize = dtohs(entry->size);
         const uint32_t parent = entrySize >= sizeof(ResTable_map_entry)
             ? dtohl(((const ResTable_map_entry*)entry)->parent.ident) : 0;
@@ -2288,43 +2454,41 @@
         TABLE_NOISY(LOGI("Found map: size=%p parent=%p count=%d\n",
                          entrySize, parent, count));
 
-        if (set == NULL) {
-            // If this map inherits from another, we need to start
-            // with its parent's values.  Otherwise start out empty.
-            TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n",
-                         entrySize, parent));
-            if (parent) {
-                const bag_entry* parentBag;
-                uint32_t parentTypeSpecFlags = 0;
-                const ssize_t NP = getBagLocked(parent, &parentBag, &parentTypeSpecFlags);
-                const size_t NT = ((NP >= 0) ? NP : 0) + N;
-                set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
-                if (set == NULL) {
-                    return NO_MEMORY;
-                }
-                if (NP > 0) {
-                    memcpy(set+1, parentBag, NP*sizeof(bag_entry));
-                    set->numAttrs = NP;
-                    TABLE_NOISY(LOGI("Initialized new bag with %d inherited attributes.\n", NP));
-                } else {
-                    TABLE_NOISY(LOGI("Initialized new bag with no inherited attributes.\n"));
-                    set->numAttrs = 0;
-                }
-                set->availAttrs = NT;
-                set->typeSpecFlags = parentTypeSpecFlags;
-            } else {
-                set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N);
-                if (set == NULL) {
-                    return NO_MEMORY;
-                }
-                set->numAttrs = 0;
-                set->availAttrs = N;
-                set->typeSpecFlags = 0;
+        // If this map inherits from another, we need to start
+        // with its parent's values.  Otherwise start out empty.
+        TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n",
+                           entrySize, parent));
+        if (parent) {
+            const bag_entry* parentBag;
+            uint32_t parentTypeSpecFlags = 0;
+            const ssize_t NP = getBagLocked(parent, &parentBag, &parentTypeSpecFlags);
+            const size_t NT = ((NP >= 0) ? NP : 0) + N;
+            set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
+            if (set == NULL) {
+                return NO_MEMORY;
             }
+            if (NP > 0) {
+                memcpy(set+1, parentBag, NP*sizeof(bag_entry));
+                set->numAttrs = NP;
+                TABLE_NOISY(LOGI("Initialized new bag with %d inherited attributes.\n", NP));
+            } else {
+                TABLE_NOISY(LOGI("Initialized new bag with no inherited attributes.\n"));
+                set->numAttrs = 0;
+            }
+            set->availAttrs = NT;
+            set->typeSpecFlags = parentTypeSpecFlags;
+        } else {
+            set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N);
+            if (set == NULL) {
+                return NO_MEMORY;
+            }
+            set->numAttrs = 0;
+            set->availAttrs = N;
+            set->typeSpecFlags = 0;
         }
 
         if (typeClass->typeSpecFlags != NULL) {
-            set->typeSpecFlags |= dtohl(typeClass->typeSpecFlags[e]);
+            set->typeSpecFlags |= dtohl(typeClass->typeSpecFlags[E]);
         } else {
             set->typeSpecFlags = -1;
         }
@@ -3870,7 +4034,7 @@
 }
 
 status_t ResTable::parsePackage(const ResTable_package* const pkg,
-                                const Header* const header)
+                                const Header* const header, uint32_t idmap_id)
 {
     const uint8_t* base = (const uint8_t*)pkg;
     status_t err = validate_chunk(&pkg->header, sizeof(*pkg),
@@ -3904,8 +4068,12 @@
     
     Package* package = NULL;
     PackageGroup* group = NULL;
-    uint32_t id = dtohl(pkg->id);
-    if (id != 0 && id < 256) {
+    uint32_t id = idmap_id != 0 ? idmap_id : dtohl(pkg->id);
+    // If at this point id == 0, pkg is an overlay package without a
+    // corresponding idmap. During regular usage, overlay packages are
+    // always loaded alongside their idmaps, but during idmap creation
+    // the package is temporarily loaded by itself.
+    if (id < 256) {
     
         package = new Package(this, header, pkg);
         if (package == NULL) {
@@ -3958,7 +4126,7 @@
             return (mError=err);
         }
     } else {
-        LOG_ALWAYS_FATAL("Skins not supported!");
+        LOG_ALWAYS_FATAL("Package id out of range");
         return NO_ERROR;
     }
 
@@ -4112,6 +4280,136 @@
     return NO_ERROR;
 }
 
+status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, uint32_t overlayCrc,
+                               void** outData, size_t* outSize) const
+{
+    // see README for details on the format of map
+    if (mPackageGroups.size() == 0) {
+        return UNKNOWN_ERROR;
+    }
+    if (mPackageGroups[0]->packages.size() == 0) {
+        return UNKNOWN_ERROR;
+    }
+
+    Vector<Vector<uint32_t> > map;
+    const PackageGroup* pg = mPackageGroups[0];
+    const Package* pkg = pg->packages[0];
+    size_t typeCount = pkg->types.size();
+    // starting size is header + first item (number of types in map)
+    *outSize = (IDMAP_HEADER_SIZE + 1) * sizeof(uint32_t);
+    const String16 overlayPackage(overlay.mPackageGroups[0]->packages[0]->package->name);
+    const uint32_t pkg_id = pkg->package->id << 24;
+
+    for (size_t typeIndex = 0; typeIndex < typeCount; ++typeIndex) {
+        ssize_t offset = -1;
+        const Type* typeConfigs = pkg->getType(typeIndex);
+        ssize_t mapIndex = map.add();
+        if (mapIndex < 0) {
+            return NO_MEMORY;
+        }
+        Vector<uint32_t>& vector = map.editItemAt(mapIndex);
+        for (size_t entryIndex = 0; entryIndex < typeConfigs->entryCount; ++entryIndex) {
+            uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
+                | (0x00ff0000 & ((typeIndex+1)<<16))
+                | (0x0000ffff & (entryIndex));
+            resource_name resName;
+            if (!this->getResourceName(resID, &resName)) {
+                return UNKNOWN_ERROR;
+            }
+
+            const String16 overlayType(resName.type, resName.typeLen);
+            const String16 overlayName(resName.name, resName.nameLen);
+            uint32_t overlayResID = overlay.identifierForName(overlayName.string(),
+                                                              overlayName.size(),
+                                                              overlayType.string(),
+                                                              overlayType.size(),
+                                                              overlayPackage.string(),
+                                                              overlayPackage.size());
+            if (overlayResID != 0) {
+                // overlay package has package ID == 0, use original package's ID instead
+                overlayResID |= pkg_id;
+            }
+            vector.push(overlayResID);
+            if (overlayResID != 0 && offset == -1) {
+                offset = Res_GETENTRY(resID);
+            }
+#if 0
+            if (overlayResID != 0) {
+                LOGD("%s/%s 0x%08x -> 0x%08x\n",
+                     String8(String16(resName.type)).string(),
+                     String8(String16(resName.name)).string(),
+                     resID, overlayResID);
+            }
+#endif
+        }
+
+        if (offset != -1) {
+            // shave off leading and trailing entries which lack overlay values
+            vector.removeItemsAt(0, offset);
+            vector.insertAt((uint32_t)offset, 0, 1);
+            while (vector.top() == 0) {
+                vector.pop();
+            }
+            // reserve space for number and offset of entries, and the actual entries
+            *outSize += (2 + vector.size()) * sizeof(uint32_t);
+        } else {
+            // no entries of current type defined in overlay package
+            vector.clear();
+            // reserve space for type offset
+            *outSize += 1 * sizeof(uint32_t);
+        }
+    }
+
+    if ((*outData = malloc(*outSize)) == NULL) {
+        return NO_MEMORY;
+    }
+    uint32_t* data = (uint32_t*)*outData;
+    *data++ = htodl(IDMAP_MAGIC);
+    *data++ = htodl(originalCrc);
+    *data++ = htodl(overlayCrc);
+    const size_t mapSize = map.size();
+    *data++ = htodl(mapSize);
+    size_t offset = mapSize;
+    for (size_t i = 0; i < mapSize; ++i) {
+        const Vector<uint32_t>& vector = map.itemAt(i);
+        const size_t N = vector.size();
+        if (N == 0) {
+            *data++ = htodl(0);
+        } else {
+            offset++;
+            *data++ = htodl(offset);
+            offset += N;
+        }
+    }
+    for (size_t i = 0; i < mapSize; ++i) {
+        const Vector<uint32_t>& vector = map.itemAt(i);
+        const size_t N = vector.size();
+        if (N == 0) {
+            continue;
+        }
+        *data++ = htodl(N - 1); // do not count the offset (which is vector's first element)
+        for (size_t j = 0; j < N; ++j) {
+            const uint32_t& overlayResID = vector.itemAt(j);
+            *data++ = htodl(overlayResID);
+        }
+    }
+
+    return NO_ERROR;
+}
+
+bool ResTable::getIdmapInfo(const void* idmap, size_t sizeBytes,
+                            uint32_t* pOriginalCrc, uint32_t* pOverlayCrc)
+{
+    const uint32_t* map = (const uint32_t*)idmap;
+    if (!assertIdmapHeader(map, sizeBytes)) {
+        return false;
+    }
+    *pOriginalCrc = map[1];
+    *pOverlayCrc = map[2];
+    return true;
+}
+
+
 #ifndef HAVE_ANDROID_OS
 #define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string())
 
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 0b0d145a..1e4b585 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1120,6 +1120,7 @@
         mOnErrorListener = null;
         mOnInfoListener = null;
         mOnVideoSizeChangedListener = null;
+        mOnTimedTextListener = null;
         _release();
     }
 
@@ -1301,6 +1302,7 @@
     private static final int MEDIA_BUFFERING_UPDATE = 3;
     private static final int MEDIA_SEEK_COMPLETE = 4;
     private static final int MEDIA_SET_VIDEO_SIZE = 5;
+    private static final int MEDIA_TIMED_TEXT = 99;
     private static final int MEDIA_ERROR = 100;
     private static final int MEDIA_INFO = 200;
 
@@ -1369,6 +1371,11 @@
                 }
                 // No real default action so far.
                 return;
+            case MEDIA_TIMED_TEXT:
+                if (mOnTimedTextListener != null) {
+                    mOnTimedTextListener.onTimedText(mMediaPlayer, (String)msg.obj);
+                }
+                return;
 
             case MEDIA_NOP: // interface test message - ignore
                 break;
@@ -1545,6 +1552,39 @@
 
     private OnVideoSizeChangedListener mOnVideoSizeChangedListener;
 
+    /**
+     * Interface definition of a callback to be invoked when a
+     * timed text is available for display.
+     * {@hide}
+     */
+    public interface OnTimedTextListener
+    {
+        /**
+         * Called to indicate the video size
+         *
+         * @param mp             the MediaPlayer associated with this callback
+         * @param text           the timed text sample which contains the
+         *                       text needed to be displayed.
+         * {@hide}
+         */
+        public void onTimedText(MediaPlayer mp, String text);
+    }
+
+    /**
+     * Register a callback to be invoked when a timed text is available
+     * for display.
+     *
+     * @param listener the callback that will be run
+     * {@hide}
+     */
+    public void setOnTimedTextListener(OnTimedTextListener listener)
+    {
+        mOnTimedTextListener = listener;
+    }
+
+    private OnTimedTextListener mOnTimedTextListener;
+
+
     /* Do not change these values without updating their counterparts
      * in include/media/mediaplayer.h!
      */
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index a219623..2ba9b3f 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -241,7 +241,7 @@
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
         return;
     }
-    int fd = getParcelFileDescriptorFD(env, fileDescriptor);
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     if (offset < 0 || length < 0 || fd < 0) {
         if (offset < 0) {
             LOGE("negative offset (%lld)", offset);
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index ecbd288..23a77d4 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -69,7 +69,7 @@
 public:
     JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
     ~JNIMediaPlayerListener();
-    void notify(int msg, int ext1, int ext2);
+    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
 private:
     JNIMediaPlayerListener();
     jclass      mClass;     // Reference to MediaPlayer class
@@ -102,10 +102,23 @@
     env->DeleteGlobalRef(mClass);
 }
 
-void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2)
+void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
 {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
-    env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, 0);
+    if (obj && obj->dataSize() > 0) {
+        jbyteArray jArray = env->NewByteArray(obj->dataSize());
+        if (jArray != NULL) {
+            jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
+            memcpy(nArray, obj->data(), obj->dataSize());
+            env->ReleaseByteArrayElements(jArray, nArray, 0);
+            env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
+                    msg, ext1, ext2, jArray);
+            env->DeleteLocalRef(jArray);
+        }
+    } else {
+        env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
+                msg, ext1, ext2, NULL);
+    }
 }
 
 // ----------------------------------------------------------------------------
@@ -325,7 +338,7 @@
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
         return;
     }
-    int fd = getParcelFileDescriptorFD(env, fileDescriptor);
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     LOGV("setDataSourceFD: fd %d", fd);
     process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
 }
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index a8a46c1..2c246958 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -253,7 +253,7 @@
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
         return;
     }
-    int fd = getParcelFileDescriptorFD(env, fileDescriptor);
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
     status_t opStatus = mr->setOutputFile(fd, offset, length);
     process_media_recorder_call(env, opStatus, "java/io/IOException", "setOutputFile failed.");
@@ -267,7 +267,7 @@
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
         return;
     }
-    int fd = getParcelFileDescriptorFD(env, fileDescriptor);
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
     status_t opStatus = mr->setOutputFileAuxiliary(fd);
     process_media_recorder_call(env, opStatus, "java/io/IOException", "setOutputFile failed.");
@@ -404,38 +404,32 @@
 
     clazz = env->FindClass("android/media/MediaRecorder");
     if (clazz == NULL) {
-        jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaRecorder");
         return;
     }
 
     fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
     if (fields.context == NULL) {
-        jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaRecorder.mNativeContext");
         return;
     }
 
     fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
     if (fields.surface == NULL) {
-        jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaRecorder.mSurface");
         return;
     }
 
     jclass surface = env->FindClass("android/view/Surface");
     if (surface == NULL) {
-        jniThrowException(env, "java/lang/RuntimeException", "Can't find android/view/Surface");
         return;
     }
 
     fields.surface_native = env->GetFieldID(surface, ANDROID_VIEW_SURFACE_JNI_ID, "I");
     if (fields.surface_native == NULL) {
-        jniThrowException(env, "java/lang/RuntimeException", "Can't find Surface.mSurface");
         return;
     }
 
     fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
                                                "(Ljava/lang/Object;IIILjava/lang/Object;)V");
     if (fields.post_event == NULL) {
-        jniThrowException(env, "java/lang/RuntimeException", "MediaRecorder.postEventFromNative");
         return;
     }
 }
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 06058dc..a3dd136 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -303,7 +303,7 @@
         return NULL;
     }
 
-    int fd = getParcelFileDescriptorFD(env, fileDescriptor);
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     char* data = mp->extractAlbumArt(fd);
     if (!data) {
         return NULL;
@@ -335,15 +335,11 @@
     LOGV("native_init");
     jclass clazz = env->FindClass(kClassMediaScanner);
     if (clazz == NULL) {
-        const char* err = "Can't find android/media/MediaScanner";
-        jniThrowException(env, kRunTimeException, err);
         return;
     }
 
     fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
     if (fields.context == NULL) {
-        const char* err = "Can't find MediaScanner.mNativeContext";
-        jniThrowException(env, kRunTimeException, err);
         return;
     }
 }
@@ -426,5 +422,3 @@
     return AndroidRuntime::registerNativeMethods(env,
                 kClassMediaScanner, gMethods, NELEM(gMethods));
 }
-
-
diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp
index 447f931..03d3388 100644
--- a/media/jni/soundpool/android_media_SoundPool.cpp
+++ b/media/jni/soundpool/android_media_SoundPool.cpp
@@ -60,7 +60,7 @@
     LOGV("android_media_SoundPool_load_FD");
     SoundPool *ap = MusterSoundPool(env, thiz);
     if (ap == NULL) return 0;
-    return ap->load(getParcelFileDescriptorFD(env, fileDescriptor),
+    return ap->load(jniGetFDFromFileDescriptor(env, fileDescriptor),
             int64_t(offset), int64_t(length), int(priority));
 }
 
diff --git a/media/libmedia/IMediaPlayerClient.cpp b/media/libmedia/IMediaPlayerClient.cpp
index bf51829..1f135c4 100644
--- a/media/libmedia/IMediaPlayerClient.cpp
+++ b/media/libmedia/IMediaPlayerClient.cpp
@@ -35,13 +35,16 @@
     {
     }
 
-    virtual void notify(int msg, int ext1, int ext2)
+    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayerClient::getInterfaceDescriptor());
         data.writeInt32(msg);
         data.writeInt32(ext1);
         data.writeInt32(ext2);
+        if (obj && obj->dataSize() > 0) {
+            data.appendFrom(const_cast<Parcel *>(obj), 0, obj->dataSize());
+        }
         remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);
     }
 };
@@ -59,7 +62,12 @@
             int msg = data.readInt32();
             int ext1 = data.readInt32();
             int ext2 = data.readInt32();
-            notify(msg, ext1, ext2);
+            Parcel obj;
+            if (data.dataAvail() > 0) {
+                obj.appendFrom(const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail());
+            }
+
+            notify(msg, ext1, ext2, &obj);
             return NO_ERROR;
         } break;
         default:
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 0ee0249a..e80e742 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -551,7 +551,7 @@
     return mPlayer->attachAuxEffect(effectId);
 }
 
-void MediaPlayer::notify(int msg, int ext1, int ext2)
+void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
 {
     LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
     bool send = true;
@@ -641,6 +641,9 @@
         mVideoWidth = ext1;
         mVideoHeight = ext2;
         break;
+    case MEDIA_TIMED_TEXT:
+        LOGV("Received timed text message");
+        break;
     default:
         LOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
         break;
@@ -653,7 +656,7 @@
     if ((listener != 0) && send) {
         Mutex::Autolock _l(mNotifyLock);
         LOGV("callback application");
-        listener->notify(msg, ext1, ext2);
+        listener->notify(msg, ext1, ext2, obj);
         LOGV("back from callback");
     }
 }
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 9c9ac97..6b97708 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1022,7 +1022,8 @@
     return NO_ERROR;
 }
 
-void MediaPlayerService::Client::notify(void* cookie, int msg, int ext1, int ext2)
+void MediaPlayerService::Client::notify(
+        void* cookie, int msg, int ext1, int ext2, const Parcel *obj)
 {
     Client* client = static_cast<Client*>(cookie);
 
@@ -1039,7 +1040,7 @@
         client->addNewMetadataUpdate(metadata_type);
     }
     LOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2);
-    client->mClient->notify(msg, ext1, ext2);
+    client->mClient->notify(msg, ext1, ext2, obj);
 }
 
 
@@ -1623,7 +1624,8 @@
     return mError;
 }
 
-void MediaPlayerService::AudioCache::notify(void* cookie, int msg, int ext1, int ext2)
+void MediaPlayerService::AudioCache::notify(
+        void* cookie, int msg, int ext1, int ext2, const Parcel *obj)
 {
     LOGV("notify(%p, %d, %d, %d)", cookie, msg, ext1, ext2);
     AudioCache* p = static_cast<AudioCache*>(cookie);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index ff6ccf54..5539a37 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -156,7 +156,8 @@
 
                 sp<IMemoryHeap> getHeap() const { return mHeap; }
 
-        static  void            notify(void* cookie, int msg, int ext1, int ext2);
+        static  void            notify(void* cookie, int msg,
+                                       int ext1, int ext2, const Parcel *obj);
         virtual status_t        dump(int fd, const Vector<String16>& args) const;
 
     private:
@@ -287,7 +288,8 @@
 
                 status_t        setDataSource(const sp<IStreamSource> &source);
 
-        static  void            notify(void* cookie, int msg, int ext1, int ext2);
+        static  void            notify(void* cookie, int msg,
+                                       int ext1, int ext2, const Parcel *obj);
 
                 pid_t           pid() const { return mPid; }
         virtual status_t        dump(int fd, const Vector<String16>& args) const;
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 93d4236..1bfdd8e 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG_HDCP
+#undef DEBUG_HDCP
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "AwesomePlayer"
@@ -184,7 +184,8 @@
       mFlags(0),
       mExtractorFlags(0),
       mVideoBuffer(NULL),
-      mDecryptHandle(NULL) {
+      mDecryptHandle(NULL),
+      mLastVideoTimeUs(-1) {
     CHECK_EQ(mClient.connect(), (status_t)OK);
 
     DataSource::RegisterDefaultSniffers();
@@ -470,28 +471,13 @@
 
     mVideoRenderer.clear();
 
-    if (mVideoBuffer) {
-        mVideoBuffer->release();
-        mVideoBuffer = NULL;
-    }
-
     if (mRTSPController != NULL) {
         mRTSPController->disconnect();
         mRTSPController.clear();
     }
 
     if (mVideoSource != NULL) {
-        mVideoSource->stop();
-
-        // The following hack is necessary to ensure that the OMX
-        // component is completely released by the time we may try
-        // to instantiate it again.
-        wp<MediaSource> tmp = mVideoSource;
-        mVideoSource.clear();
-        while (tmp.promote() != NULL) {
-            usleep(1000);
-        }
-        IPCThreadState::self()->flushCommands();
+        shutdownVideoDecoder_l();
     }
 
     mDurationUs = -1;
@@ -510,6 +496,7 @@
     mFileSource.clear();
 
     mBitrate = -1;
+    mLastVideoTimeUs = -1;
 }
 
 void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
@@ -1012,7 +999,7 @@
     Mutex::Autolock autoLock(mLock);
 
     mSurface = surface;
-    mNativeWindow = surface;
+    setNativeWindow_l(surface);
 }
 
 void AwesomePlayer::setSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {
@@ -1020,9 +1007,57 @@
 
     mSurface.clear();
     if (surfaceTexture != NULL) {
-        mNativeWindow = new SurfaceTextureClient(surfaceTexture);
+        setNativeWindow_l(new SurfaceTextureClient(surfaceTexture));
+    }
+}
+
+void AwesomePlayer::shutdownVideoDecoder_l() {
+    if (mVideoBuffer) {
+        mVideoBuffer->release();
+        mVideoBuffer = NULL;
     }
 
+    mVideoSource->stop();
+
+    // The following hack is necessary to ensure that the OMX
+    // component is completely released by the time we may try
+    // to instantiate it again.
+    wp<MediaSource> tmp = mVideoSource;
+    mVideoSource.clear();
+    while (tmp.promote() != NULL) {
+        usleep(1000);
+    }
+    IPCThreadState::self()->flushCommands();
+}
+
+void AwesomePlayer::setNativeWindow_l(const sp<ANativeWindow> &native) {
+    mNativeWindow = native;
+
+    if (mVideoSource == NULL) {
+        return;
+    }
+
+    LOGI("attempting to reconfigure to use new surface");
+
+    bool wasPlaying = (mFlags & PLAYING) != 0;
+
+    pause_l();
+    mVideoRenderer.clear();
+
+    shutdownVideoDecoder_l();
+
+    CHECK_EQ(initVideoDecoder(), (status_t)OK);
+
+    if (mLastVideoTimeUs >= 0) {
+        mSeeking = SEEK;
+        mSeekNotificationSent = true;
+        mSeekTimeUs = mLastVideoTimeUs;
+        mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
+    }
+
+    if (wasPlaying) {
+        play_l();
+    }
 }
 
 void AwesomePlayer::setAudioSink(
@@ -1412,6 +1447,8 @@
     int64_t timeUs;
     CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
 
+    mLastVideoTimeUs = timeUs;
+
     if (mSeeking == SEEK_VIDEO_ONLY) {
         if (mSeekTimeUs > timeUs) {
             LOGI("XXX mSeekTimeUs = %lld us, timeUs = %lld us",
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 4095fbf..7621f2c 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -146,7 +146,8 @@
 
     int64_t thumbNailTime;
     if (frameTimeUs < 0) {
-        if (!trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) {
+        if (!trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)
+                || thumbNailTime < 0) {
             thumbNailTime = 0;
         }
         options.setSeekTo(thumbNailTime, mode);
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 7fd7724..8c61064 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -218,6 +218,8 @@
     DrmManagerClient *mDrmManagerClient;
     sp<DecryptHandle> mDecryptHandle;
 
+    int64_t mLastVideoTimeUs;
+
     status_t setDataSource_l(
             const char *uri,
             const KeyedVector<String8, String8> *headers = NULL);
@@ -267,6 +269,9 @@
 
     status_t startAudioPlayer_l();
 
+    void shutdownVideoDecoder_l();
+    void setNativeWindow_l(const sp<ANativeWindow> &native);
+
     AwesomePlayer(const AwesomePlayer &);
     AwesomePlayer &operator=(const AwesomePlayer &);
 };
diff --git a/opengl/java/android/opengl/GLES10.java b/opengl/java/android/opengl/GLES10.java
index 7c0f949..790acbd 100644
--- a/opengl/java/android/opengl/GLES10.java
+++ b/opengl/java/android/opengl/GLES10.java
@@ -1,18 +1,19 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
 
 // This source file is automatically generated
 
diff --git a/opengl/java/android/opengl/GLES10Ext.java b/opengl/java/android/opengl/GLES10Ext.java
index 116ab9d..81fc59e 100644
--- a/opengl/java/android/opengl/GLES10Ext.java
+++ b/opengl/java/android/opengl/GLES10Ext.java
@@ -1,18 +1,19 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
 
 // This source file is automatically generated
 
diff --git a/opengl/java/android/opengl/GLES11.java b/opengl/java/android/opengl/GLES11.java
index b24c043..1ca179b 100644
--- a/opengl/java/android/opengl/GLES11.java
+++ b/opengl/java/android/opengl/GLES11.java
@@ -1,18 +1,19 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
 
 // This source file is automatically generated
 
diff --git a/opengl/java/android/opengl/GLES11Ext.java b/opengl/java/android/opengl/GLES11Ext.java
index a9a7a22..25d5467 100644
--- a/opengl/java/android/opengl/GLES11Ext.java
+++ b/opengl/java/android/opengl/GLES11Ext.java
@@ -1,18 +1,19 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
 
 // This source file is automatically generated
 
diff --git a/opengl/java/android/opengl/GLES20.java b/opengl/java/android/opengl/GLES20.java
index 700164b..635f811 100644
--- a/opengl/java/android/opengl/GLES20.java
+++ b/opengl/java/android/opengl/GLES20.java
@@ -1,18 +1,19 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
 
 // This source file is automatically generated
 
diff --git a/opengl/java/com/google/android/gles_jni/GLImpl.java b/opengl/java/com/google/android/gles_jni/GLImpl.java
index 50f6760..090c0cb7 100644
--- a/opengl/java/com/google/android/gles_jni/GLImpl.java
+++ b/opengl/java/com/google/android/gles_jni/GLImpl.java
@@ -1,18 +1,19 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+/* //device/java/android/com/google/android/gles_jni/GLImpl.java
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
 
 // This source file is automatically generated
 
diff --git a/opengl/java/javax/microedition/khronos/opengles/GL.java b/opengl/java/javax/microedition/khronos/opengles/GL.java
index d5b60c6..3b78f3d 100644
--- a/opengl/java/javax/microedition/khronos/opengles/GL.java
+++ b/opengl/java/javax/microedition/khronos/opengles/GL.java
@@ -1,18 +1,19 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+/* //device/java/android/javax/microedition/khronos/opengles/GL.java
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
 
 package javax.microedition.khronos.opengles;
 
diff --git a/opengl/java/javax/microedition/khronos/opengles/GL10.java b/opengl/java/javax/microedition/khronos/opengles/GL10.java
index f48ecde..4fcfb52 100644
--- a/opengl/java/javax/microedition/khronos/opengles/GL10.java
+++ b/opengl/java/javax/microedition/khronos/opengles/GL10.java
@@ -1,18 +1,19 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+/* //device/java/android/javax/microedition/khronos/opengles/GL10.java
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
 
 // This source file is automatically generated
 
diff --git a/opengl/java/javax/microedition/khronos/opengles/GL10Ext.java b/opengl/java/javax/microedition/khronos/opengles/GL10Ext.java
index f3252ab..562b20a 100644
--- a/opengl/java/javax/microedition/khronos/opengles/GL10Ext.java
+++ b/opengl/java/javax/microedition/khronos/opengles/GL10Ext.java
@@ -1,18 +1,19 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+/* //device/java/android/javax/microedition/khronos/opengles/GL10Ext.java
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
 
 // This source file is automatically generated
 
diff --git a/opengl/java/javax/microedition/khronos/opengles/GL11.java b/opengl/java/javax/microedition/khronos/opengles/GL11.java
index 943a5be..3ba110c 100644
--- a/opengl/java/javax/microedition/khronos/opengles/GL11.java
+++ b/opengl/java/javax/microedition/khronos/opengles/GL11.java
@@ -1,18 +1,19 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+/* //device/java/android/javax/microedition/khronos/opengles/GL11.java
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
 
 // This source file is automatically generated
 
diff --git a/opengl/java/javax/microedition/khronos/opengles/GL11Ext.java b/opengl/java/javax/microedition/khronos/opengles/GL11Ext.java
index 842db7a..459a1ab 100644
--- a/opengl/java/javax/microedition/khronos/opengles/GL11Ext.java
+++ b/opengl/java/javax/microedition/khronos/opengles/GL11Ext.java
@@ -1,18 +1,19 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+/* //device/java/android/javax/microedition/khronos/opengles/GL11Ext.java
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
 
 // This source file is automatically generated
 
diff --git a/opengl/java/javax/microedition/khronos/opengles/GL11ExtensionPack.java b/opengl/java/javax/microedition/khronos/opengles/GL11ExtensionPack.java
index 97d5fd8..933c91e 100644
--- a/opengl/java/javax/microedition/khronos/opengles/GL11ExtensionPack.java
+++ b/opengl/java/javax/microedition/khronos/opengles/GL11ExtensionPack.java
@@ -1,18 +1,19 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+/* //device/java/android/javax/microedition/khronos/opengles/GL11ExtensionPack.java
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
 
 // This source file is automatically generated
 
diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen
index 6c1a231..31f4190 100755
--- a/opengl/tools/glgen/gen
+++ b/opengl/tools/glgen/gen
@@ -21,7 +21,7 @@
 echo "package android.graphics;" > out/android/graphics/Canvas.java
 echo "public interface Canvas {}" >> out/android/graphics/Canvas.java
 
-echo "package android.app; import android.content.pm.IPackageManager; public class ActivityThread { public static final ActivityThread currentActivityThread() { return null; } public static final String currentPackageName(){ return null; } public static IPackageManager getPackageManager() { return null;} }" > out/android/app/ActivityThread.java
+echo "package android.app; import android.content.pm.IPackageManager; public class AppGlobals { public static IPackageManager getPackageManager() { return null;} }" > out/android/app/AppGlobals.java
 # echo "package android.content; import android.content.pm.PackageManager; public interface Context { public PackageManager getPackageManager(); }" > out/android/content/Context.java
 echo "package android.content.pm; public class ApplicationInfo {public int targetSdkVersion;}" > out/android/content/pm/ApplicationInfo.java
 echo "package android.content.pm; public interface IPackageManager {ApplicationInfo getApplicationInfo(java.lang.String packageName, int flags) throws android.os.RemoteException;}" > out/android/content/pm/IPackageManager.java
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index 9d8c5a0..9fa2b74 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -58,7 +58,7 @@
         } else if (baseType.equals("void")) {
             // nothing.
         } else {
-            throw new RuntimeException("Uknown primitive basetype " + baseType);
+            throw new RuntimeException("Unknown primitive basetype " + baseType);
         }
         return jniName;
     }
@@ -200,15 +200,9 @@
                 if (emitExceptionCheck) {
                     out.println(iii + indent + "_exception = 1;");
                 }
-                out.println(iii + indent +
-                            (mUseCPlusPlus ? "_env" : "(*_env)") +
-                            "->ThrowNew(" +
-                            (mUseCPlusPlus ? "" : "_env, ") +
-                            "IAEClass, " +
-                            "\"" +
-                            (isBuffer ?
-                             "remaining()" : "length - " + offset) +
-                            " < needed\");");
+                out.println(iii + indent + "jniThrowException(_env, " +
+                        "\"java/lang/IllegalArgumentException\", " +
+                        "\"" + (isBuffer ? "remaining()" : "length - " + offset) + " < needed\");");
                 out.println(iii + indent + "goto exit;");
                 needsExit = true;
                 out.println(iii + "}");
@@ -302,7 +296,7 @@
         }
         return false;
     }
-    
+
     String isRequiresFunc(CFunc cfunc) {
         String[] checks = mChecker.getChecks(cfunc.getName());
         int index = 1;
@@ -329,109 +323,94 @@
         }
         return null;
     }
-    
+
     void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out,
             boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) {
 
-                String[] checks = mChecker.getChecks(cfunc.getName());
+        String[] checks = mChecker.getChecks(cfunc.getName());
 
-                boolean lastWasIfcheck = false;
+        boolean lastWasIfcheck = false;
 
-                int index = 1;
-                if (checks != null) {
-                    while (index < checks.length) {
-                        if (checks[index].startsWith("check")) {
-                            if (lastWasIfcheck) {
-                                printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
-                                                      offset, remaining, iii);
-                            }
-                            lastWasIfcheck = false;
-                            if (cname != null && !cname.equals(checks[index + 1])) {
-                                index += 3;
-                                continue;
-                            }
-                            out.println(iii + "if (" + remaining + " < " +
-                                        checks[index + 2] +
-                                        ") {");
-                            if (emitExceptionCheck) {
-                                out.println(iii + indent + "_exception = 1;");
-                            }
-                    String exceptionClassName = "IAEClass";
+        int index = 1;
+        if (checks != null) {
+            while (index < checks.length) {
+                if (checks[index].startsWith("check")) {
+                    if (lastWasIfcheck) {
+                        printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
+                                offset, remaining, iii);
+                    }
+                    lastWasIfcheck = false;
+                    if (cname != null && !cname.equals(checks[index + 1])) {
+                        index += 3;
+                        continue;
+                    }
+                    out.println(iii + "if (" + remaining + " < " + checks[index + 2] + ") {");
+                    if (emitExceptionCheck) {
+                        out.println(iii + indent + "_exception = 1;");
+                    }
+                    String exceptionClassName = "java/lang/IllegalArgumentException";
                     // If the "check" keyword was of the form
                     // "check_<class name>", use the class name in the
                     // exception to be thrown
                     int underscore = checks[index].indexOf('_');
                     if (underscore >= 0) {
-                    exceptionClassName = checks[index].substring(underscore + 1) + "Class";
-                    }
-                            out.println(iii + indent +
-                                        (mUseCPlusPlus ? "_env" : "(*_env)") +
-                                        "->ThrowNew(" +
-                                        (mUseCPlusPlus ? "" : "_env, ") +
-                        exceptionClassName + ", " +
-                                        "\"" +
-                                        (isBuffer ?
-                                         "remaining()" : "length - " + offset) +
-                                        " < " + checks[index + 2] +
-                                        "\");");
-
-                            out.println(iii + indent + "goto exit;");
-                            needsExit = true;
-                            out.println(iii + "}");
-
-                            index += 3;
-                        } else if (checks[index].equals("ifcheck")) {
-                            String[] matches = checks[index + 4].split(",");
-
-                            if (!lastWasIfcheck) {
-                                out.println(iii + "int _needed;");
-                                out.println(iii +
-                                            "switch (" +
-                                            checks[index + 3] +
-                                            ") {");
-                            }
-
-                            for (int i = 0; i < matches.length; i++) {
-                                out.println("#if defined(" + matches[i] + ")");
-                                out.println(iii +
-                                            "    case " +
-                                            matches[i] +
-                                            ":");
-                                out.println("#endif // defined(" + matches[i] + ")");
-                            }
-                            out.println(iii +
-                                        "        _needed = " +
-                                        checks[index + 2] +
-                                        ";");
-                            out.println(iii +
-                                        "        break;");
-
-                            lastWasIfcheck = true;
-                            index += 5;
-                        } else if (checks[index].equals("return")) {
-                            // ignore
-                            index += 2;
-                        } 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;
+                        String abbr = checks[index].substring(underscore + 1);
+                        if (abbr.equals("AIOOBE")) {
+                            exceptionClassName = "java/lang/ArrayIndexOutOfBoundsException";
                         } else {
-                            System.out.println("Error: unknown keyword \"" +
-                                               checks[index] + "\"");
-                            System.exit(0);
+                            throw new RuntimeException("unknown exception abbreviation: " + abbr);
                         }
                     }
-                }
+                    out.println(iii + indent + "jniThrowException(_env, " +
+                            "\"" + exceptionClassName + "\", " +
+                            "\"" + (isBuffer ? "remaining()" : "length - " + offset) + " < " + checks[index + 2] + "\");");
 
-                if (lastWasIfcheck) {
-                    printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii);
+                    out.println(iii + indent + "goto exit;");
+                    needsExit = true;
+                    out.println(iii + "}");
+
+                    index += 3;
+                } else if (checks[index].equals("ifcheck")) {
+                    String[] matches = checks[index + 4].split(",");
+
+                    if (!lastWasIfcheck) {
+                        out.println(iii + "int _needed;");
+                        out.println(iii + "switch (" + checks[index + 3] + ") {");
+                    }
+
+                    for (int i = 0; i < matches.length; i++) {
+                        out.println("#if defined(" + matches[i] + ")");
+                        out.println(iii + "    case " + matches[i] + ":");
+                        out.println("#endif // defined(" + matches[i] + ")");
+                    }
+                    out.println(iii + "        _needed = " + checks[index + 2] + ";");
+                    out.println(iii + "        break;");
+
+                    lastWasIfcheck = true;
+                    index += 5;
+                } else if (checks[index].equals("return")) {
+                    // ignore
+                    index += 2;
+                } 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;
+                } else {
+                    System.out.println("Error: unknown keyword \"" + checks[index] + "\"");
+                    System.exit(0);
                 }
             }
+        }
+
+        if (lastWasIfcheck) {
+            printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii);
+        }
+    }
 
     boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, List<Integer> nonPrimitiveArgs) {
         if (nonPrimitiveArgs.size() > 0) {
@@ -817,7 +796,7 @@
         boolean isUnsupported = isUnsupportedFunc(cfunc);
         if (isUnsupported) {
             out.println(indent +
-                        "_env->ThrowNew(UOEClass,");
+                        "jniThrowException(_env, \"java/lang/UnsupportedOperationException\",");
             out.println(indent +
                         "    \"" + cfunc.getName() + "\");");
             if (!isVoid) {
@@ -828,13 +807,13 @@
             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,");
+                        "jniThrowException(_env, \"java/lang/UnsupportedOperationException\",");
             out.println(indent + indent +
                         "    \"" + cfunc.getName() + "\");");
             if (isVoid) {
@@ -945,7 +924,8 @@
                 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
                 String decl = type.getDeclaration();
                 out.println(indent + "if (!" + cname + ") {");
-                out.println(indent + "    _env->ThrowNew(IAEClass, \"" + cname + " == null\");");
+                out.println(indent + "    jniThrowException(_env, " +
+                        "\"java/lang/IllegalArgumentException\", \"" + cname + " == null\");");
                 out.println(indent + "    goto exit;");
                 needsExit = true;
                 out.println(indent + "}");
@@ -978,13 +958,9 @@
                     if (emitExceptionCheck) {
                         out.println(indent + indent + "_exception = 1;");
                     }
-                    out.println(indent + "    " +
-                                (mUseCPlusPlus ? "_env" : "(*_env)") +
-                                "->ThrowNew(" +
-                                (mUseCPlusPlus ? "" : "_env, ") +
-                                "IAEClass, " +
-                                "\"" + cname +
-                                " == null\");");
+                    out.println(indent + "    jniThrowException(_env, " +
+                            "\"java/lang/IllegalArgumentException\", " +
+                            "\"" + cname + " == null\");");
                     out.println(indent + "    goto exit;");
                     needsExit = true;
                     out.println(indent + "}");
@@ -993,12 +969,8 @@
                     if (emitExceptionCheck) {
                         out.println(indent + indent + "_exception = 1;");
                     }
-                    out.println(indent + "    " +
-                                (mUseCPlusPlus ? "_env" : "(*_env)") +
-                                "->ThrowNew(" +
-                                (mUseCPlusPlus ? "" : "_env, ") +
-                                "IAEClass, " +
-                                "\"" + offset + " < 0\");");
+                    out.println(indent + "    jniThrowException(_env, " +
+                            "\"java/lang/IllegalArgumentException\", \"" + offset + " < 0\");");
                     out.println(indent + "    goto exit;");
                     needsExit = true;
                     out.println(indent + "}");
diff --git a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
index 294d1ce..5d418d7 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
@@ -1,21 +1,23 @@
 **
 ** Copyright 2009, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 // This source file is automatically generated
 
+#include "jni.h"
+#include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 
@@ -27,10 +29,6 @@
 
 static jclass nioAccessClass;
 static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
 static jmethodID getBasePointerID;
 static jmethodID getBaseArrayID;
 static jmethodID getBaseArrayOffsetID;
@@ -41,7 +39,7 @@
 /* Cache method IDs each time the class is loaded. */
 
 static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
 {
     jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
     nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -63,26 +61,6 @@
 }
 
 
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
-    nativeClassInitBuffer(_env);
-
-    jclass IAEClassLocal =
-        _env->FindClass("java/lang/IllegalArgumentException");
-    jclass OOMEClassLocal =
-         _env->FindClass("java/lang/OutOfMemoryError");
-    jclass UOEClassLocal =
-         _env->FindClass("java/lang/UnsupportedOperationException");
-    jclass AIOOBEClassLocal =
-         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
-    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
-    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
-    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
-    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
 static void *
 getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
 {
@@ -103,13 +81,13 @@
         *array = NULL;
         return (void *) (jint) pointer;
     }
-    
+
     *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
             getBaseArrayID, buffer);
     offset = _env->CallStaticIntMethod(nioAccessClass,
             getBaseArrayOffsetID, buffer);
     data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-    
+
     return (void *) ((char *) data + offset);
 }
 
@@ -122,4 +100,3 @@
 }
 
 // --------------------------------------------------------------------------
-
diff --git a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
index e1c09f4..35a3c33 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
@@ -1,21 +1,23 @@
 **
 ** Copyright 2009, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 // This source file is automatically generated
 
+#include "jni.h"
+#include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 
@@ -40,10 +42,6 @@
 
 static jclass nioAccessClass;
 static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
 static jmethodID getBasePointerID;
 static jmethodID getBaseArrayID;
 static jmethodID getBaseArrayOffsetID;
@@ -54,7 +52,7 @@
 /* Cache method IDs each time the class is loaded. */
 
 static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
 {
     jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
     nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -75,26 +73,6 @@
         _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
 }
 
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
-    nativeClassInitBuffer(_env);
-
-    jclass IAEClassLocal =
-        _env->FindClass("java/lang/IllegalArgumentException");
-    jclass OOMEClassLocal =
-         _env->FindClass("java/lang/OutOfMemoryError");
-    jclass UOEClassLocal =
-         _env->FindClass("java/lang/UnsupportedOperationException");
-    jclass AIOOBEClassLocal =
-         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
-    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
-    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
-    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
-    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
 static void *
 getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
 {
@@ -115,13 +93,13 @@
         *array = NULL;
         return (void *) (jint) pointer;
     }
-    
+
     *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
             getBaseArrayID, buffer);
     offset = _env->CallStaticIntMethod(nioAccessClass,
             getBaseArrayOffsetID, buffer);
     data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-    
+
     return (void *) ((char *) data + offset);
 }
 
@@ -140,7 +118,8 @@
         jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
         buf += position << elementSizeShift;
     } else {
-        _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+        jniThrowException(_env, "java/lang/IllegalArgumentException",
+                          "Must use a native order direct Buffer");
     }
     return (void*) buf;
 }
@@ -153,4 +132,3 @@
 }
 
 // --------------------------------------------------------------------------
-
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
index 2548b32..9b29a44 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
@@ -1,21 +1,23 @@
 **
 ** Copyright 2009, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 // This source file is automatically generated
 
+#include "jni.h"
+#include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 
@@ -36,10 +38,6 @@
 
 static jclass nioAccessClass;
 static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
 static jmethodID getBasePointerID;
 static jmethodID getBaseArrayID;
 static jmethodID getBaseArrayOffsetID;
@@ -50,7 +48,7 @@
 /* Cache method IDs each time the class is loaded. */
 
 static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
 {
     jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
     nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -72,26 +70,6 @@
 }
 
 
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
-    nativeClassInitBuffer(_env);
-
-    jclass IAEClassLocal =
-        _env->FindClass("java/lang/IllegalArgumentException");
-    jclass OOMEClassLocal =
-         _env->FindClass("java/lang/OutOfMemoryError");
-    jclass UOEClassLocal =
-         _env->FindClass("java/lang/UnsupportedOperationException");
-    jclass AIOOBEClassLocal =
-         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
-    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
-    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
-    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
-    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
 static void *
 getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
 {
@@ -112,13 +90,13 @@
         *array = NULL;
         return (void *) (jint) pointer;
     }
-    
+
     *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
             getBaseArrayID, buffer);
     offset = _env->CallStaticIntMethod(nioAccessClass,
             getBaseArrayOffsetID, buffer);
     data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-    
+
     return (void *) ((char *) data + offset);
 }
 
@@ -138,9 +116,9 @@
         jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
         buf += position << elementSizeShift;
     } else {
-        _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+        jniThrowException(_env, "java/lang/IllegalArgumentException",
+                          "Must use a native order direct Buffer");
     }
     return (void*) buf;
 }
 // --------------------------------------------------------------------------
-
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
index 4c297f7..823079f 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
@@ -1,21 +1,23 @@
 **
 ** Copyright 2009, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 // This source file is automatically generated
 
+#include "jni.h"
+#include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 
@@ -34,10 +36,6 @@
 
 static jclass nioAccessClass;
 static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
 static jmethodID getBasePointerID;
 static jmethodID getBaseArrayID;
 static jmethodID getBaseArrayOffsetID;
@@ -48,7 +46,7 @@
 /* Cache method IDs each time the class is loaded. */
 
 static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
 {
     jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
     nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -70,26 +68,6 @@
 }
 
 
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
-    nativeClassInitBuffer(_env);
-
-    jclass IAEClassLocal =
-        _env->FindClass("java/lang/IllegalArgumentException");
-    jclass OOMEClassLocal =
-         _env->FindClass("java/lang/OutOfMemoryError");
-    jclass UOEClassLocal =
-         _env->FindClass("java/lang/UnsupportedOperationException");
-    jclass AIOOBEClassLocal =
-         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
-    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
-    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
-    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
-    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
 static void *
 getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
 {
@@ -110,13 +88,13 @@
         *array = NULL;
         return (void *) (jint) pointer;
     }
-    
+
     *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
             getBaseArrayID, buffer);
     offset = _env->CallStaticIntMethod(nioAccessClass,
             getBaseArrayOffsetID, buffer);
     data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-    
+
     return (void *) ((char *) data + offset);
 }
 
@@ -136,10 +114,10 @@
         jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
         buf += position << elementSizeShift;
     } else {
-        _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+        jniThrowException(_env, "java/lang/IllegalArgumentException",
+                          "Must use a native order direct Buffer");
     }
     return (void*) buf;
 }
 
 // --------------------------------------------------------------------------
-
diff --git a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
index e451e9a..13a2577 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
@@ -1,21 +1,23 @@
 **
 ** Copyright 2009, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 // This source file is automatically generated
 
+#include "jni.h"
+#include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 
@@ -27,10 +29,6 @@
 
 static jclass nioAccessClass;
 static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
 static jmethodID getBasePointerID;
 static jmethodID getBaseArrayID;
 static jmethodID getBaseArrayOffsetID;
@@ -41,7 +39,7 @@
 /* Cache method IDs each time the class is loaded. */
 
 static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
 {
     jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
     nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -63,26 +61,6 @@
 }
 
 
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
-    nativeClassInitBuffer(_env);
-
-    jclass IAEClassLocal =
-        _env->FindClass("java/lang/IllegalArgumentException");
-    jclass OOMEClassLocal =
-         _env->FindClass("java/lang/OutOfMemoryError");
-    jclass UOEClassLocal =
-         _env->FindClass("java/lang/UnsupportedOperationException");
-    jclass AIOOBEClassLocal =
-         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
-    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
-    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
-    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
-    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
 static void *
 getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
 {
@@ -103,13 +81,13 @@
         *array = NULL;
         return (void *) (jint) pointer;
     }
-    
+
     *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
             getBaseArrayID, buffer);
     offset = _env->CallStaticIntMethod(nioAccessClass,
             getBaseArrayOffsetID, buffer);
     data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-    
+
     return (void *) ((char *) data + offset);
 }
 
@@ -129,7 +107,8 @@
         jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
         buf += position << elementSizeShift;
     } else {
-        _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+        jniThrowException(_env, "java/lang/IllegalArgumentException",
+                          "Must use a native order direct Buffer");
     }
     return (void*) buf;
 }
@@ -147,4 +126,3 @@
 }
 
 // --------------------------------------------------------------------------
-
diff --git a/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp b/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp
index d92f5159..ce6ab24 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp
@@ -1,27 +1,19 @@
-#include <string.h>
+#include <stdlib.h>
 
 /* void glGetProgramInfoLog ( GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog ) */
-static
-jstring
-android_glGetProgramInfoLog (JNIEnv *_env, jobject _this, jint shader) {
+static jstring android_glGetProgramInfoLog(JNIEnv *_env, jobject, jint shader) {
     GLint infoLen = 0;
-    jstring _result = 0;
-    char* buf = 0;
     glGetProgramiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
-    if (infoLen) {
-        char* buf = (char*) malloc(infoLen);
-        if (buf == 0) {
-            _env->ThrowNew(IAEClass, "out of memory");
-            goto exit;
-        }
-        glGetProgramInfoLog(shader, infoLen, NULL, buf);
-        _result = _env->NewStringUTF(buf);
-    } else {
-        _result = _env->NewStringUTF("");
+    if (!infoLen) {
+        return _env->NewStringUTF("");
     }
-exit:
-    if (buf) {
-            free(buf);
+    char* buf = (char*) malloc(infoLen);
+    if (buf == NULL) {
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory");
+        return NULL;
     }
-    return _result;
-}
\ No newline at end of file
+    glGetProgramInfoLog(shader, infoLen, NULL, buf);
+    jstring result = _env->NewStringUTF(buf);
+    free(buf);
+    return result;
+}
diff --git a/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp b/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp
index 5441d66..dd656b6 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp
@@ -1,27 +1,19 @@
-#include <string.h>
+#include <stdlib.h>
 
 /* void glGetShaderInfoLog ( GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog ) */
-static
-jstring
-android_glGetShaderInfoLog (JNIEnv *_env, jobject _this, jint shader) {
+static jstring android_glGetShaderInfoLog(JNIEnv *_env, jobject, jint shader) {
     GLint infoLen = 0;
-    jstring _result = 0;
-    char* buf = 0;
     glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
-    if (infoLen) {
-        char* buf = (char*) malloc(infoLen);
-        if (buf == 0) {
-            _env->ThrowNew(IAEClass, "out of memory");
-            goto exit;
-        }
-        glGetShaderInfoLog(shader, infoLen, NULL, buf);
-        _result = _env->NewStringUTF(buf);
-    } else {
-        _result = _env->NewStringUTF("");
+    if (!infoLen) {
+        return _env->NewStringUTF("");
     }
-exit:
-    if (buf) {
-            free(buf);
+    char* buf = (char*) malloc(infoLen);
+    if (buf == NULL) {
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory");
+        return NULL;
     }
-    return _result;
-}
\ No newline at end of file
+    glGetShaderInfoLog(shader, infoLen, NULL, buf);
+    jstring result = _env->NewStringUTF(buf);
+    free(buf);
+    return result;
+}
diff --git a/opengl/tools/glgen/stubs/gles11/glGetString.cpp b/opengl/tools/glgen/stubs/gles11/glGetString.cpp
index a400859..239fe4a 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetString.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetString.cpp
@@ -1,11 +1,5 @@
-#include <string.h>

-

 /* const GLubyte * glGetString ( GLenum name ) */

-static

-jstring

-android_glGetString

-  (JNIEnv *_env, jobject _this, jint name) {

-    const char * chars = (const char *)glGetString((GLenum)name);

-    jstring output = _env->NewStringUTF(chars);

-    return output;

+static jstring android_glGetString(JNIEnv* _env, jobject, jint name) {

+    const char* chars = (const char*) glGetString((GLenum) name);

+    return _env->NewStringUTF(chars);

 }

diff --git a/opengl/tools/glgen/stubs/gles11/glShaderSource.cpp b/opengl/tools/glgen/stubs/gles11/glShaderSource.cpp
index c274108..125fd0f 100644
--- a/opengl/tools/glgen/stubs/gles11/glShaderSource.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glShaderSource.cpp
@@ -6,7 +6,7 @@
     (JNIEnv *_env, jobject _this, jint shader, jstring string) {
 
     if (!string) {
-        _env->ThrowNew(IAEClass, "string == null");
+        jniThrowException(_env, "java/lang/IllegalArgumentException", "string == null");
         return;
     }
 
diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
index c2464b0..f7315ee 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
@@ -1,21 +1,23 @@
 **
 ** Copyright 2006, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 // This source file is automatically generated
 
+#include "jni.h"
+#include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 
@@ -63,10 +65,6 @@
 
 static jclass nioAccessClass;
 static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
 static jclass G11ImplClass;
 static jmethodID getBasePointerID;
 static jmethodID getBaseArrayID;
@@ -84,7 +82,7 @@
 /* Cache method IDs each time the class is loaded. */
 
 static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
 {
     jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
     nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -114,26 +112,6 @@
         _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
 }
 
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
-    nativeClassInitBuffer(_env);
-
-    jclass IAEClassLocal =
-        _env->FindClass("java/lang/IllegalArgumentException");
-    jclass OOMEClassLocal =
-         _env->FindClass("java/lang/OutOfMemoryError");
-    jclass UOEClassLocal =
-         _env->FindClass("java/lang/UnsupportedOperationException");
-    jclass AIOOBEClassLocal =
-         _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
-    IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
-    OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
-    UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
-    AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
 static void *
 getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
 {
@@ -154,7 +132,7 @@
         *array = NULL;
         return (void *) (jint) pointer;
     }
-    
+
     *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
             getBaseArrayID, buffer);
     if (*array == NULL) {
@@ -163,7 +141,7 @@
     offset = _env->CallStaticIntMethod(nioAccessClass,
             getBaseArrayOffsetID, buffer);
     data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-    
+
     return (void *) ((char *) data + offset);
 }
 
@@ -207,7 +185,8 @@
                 releasePointer(_env, array, buf, 0);
             }
         } else {
-            _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+            jniThrowException(_env, "java/lang/IllegalArgumentException",
+                              "Must use a native order direct Buffer");
         }
     }
     return buf;
@@ -250,7 +229,7 @@
         }
     }
 }
-    
+
 static bool
 checkForExtension(const GLubyte* pExtensions, const GLubyte* pExtension) {
     for (;*pExtensions != '\0'; pExtensions = nextExtension(pExtensions)) {
@@ -279,4 +258,3 @@
 }
 
 // --------------------------------------------------------------------------
-
diff --git a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
index 3727106..cd730aa 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
+++ b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
@@ -18,7 +18,7 @@
 
 package com.google.android.gles_jni;
 
-import android.app.ActivityThread;
+import android.app.AppGlobals;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.os.Build;
@@ -64,7 +64,7 @@
     private static boolean allowIndirectBuffers(String appName) {
         boolean result = false;
         int version = 0;
-        IPackageManager pm = ActivityThread.getPackageManager();
+        IPackageManager pm = AppGlobals.getPackageManager();
         try {
             ApplicationInfo applicationInfo = pm.getApplicationInfo(appName, 0);
             if (applicationInfo != null) {
diff --git a/opengl/tools/glgen/stubs/jsr239/glGetString.cpp b/opengl/tools/glgen/stubs/jsr239/glGetString.cpp
index a400859..cd6e3f3 100644
--- a/opengl/tools/glgen/stubs/jsr239/glGetString.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/glGetString.cpp
@@ -1,11 +1,5 @@
-#include <string.h>

-

 /* const GLubyte * glGetString ( GLenum name ) */

-static

-jstring

-android_glGetString

-  (JNIEnv *_env, jobject _this, jint name) {

-    const char * chars = (const char *)glGetString((GLenum)name);

-    jstring output = _env->NewStringUTF(chars);

-    return output;

+static jstring android_glGetString(JNIEnv *_env, jobject, jint name) {

+    const char* chars = (const char*) glGetString((GLenum) name);

+    return _env->NewStringUTF(chars);

 }

diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java
index 8c6eefb3..7d4629e 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java
@@ -410,7 +410,7 @@
 
     void updateRunningTasks() {
         mRunningTaskList = mActivityManager.getRunningTasks(MAX_TASKS,
-                ActivityManager.TASKS_GET_THUMBNAILS, mThumbnailReceiver);
+                0, mThumbnailReceiver);
         if (DBG) Log.v(TAG, "Portrait: " + mPortraitMode);
         for (RunningTaskInfo r : mRunningTaskList) {
             if (r.thumbnail != null) {
@@ -441,8 +441,7 @@
         final ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
 
         final List<ActivityManager.RecentTaskInfo> recentTasks =
-                am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE
-                        | ActivityManager.TASKS_GET_THUMBNAILS);
+                am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
 
         ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
                     .resolveActivityInfo(pm, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
index a39bef8..cfb4975 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
@@ -429,8 +429,7 @@
                 mContext.getSystemService(Context.ACTIVITY_SERVICE);
 
         final List<ActivityManager.RecentTaskInfo> recentTasks =
-                am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE
-                        | ActivityManager.TASKS_GET_THUMBNAILS);
+                am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
 
         ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
                     .resolveActivityInfo(pm, 0);
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index 5c3b43fc..dca795c 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -26,11 +26,15 @@
 #include "AudioResamplerSinc.h"
 #include "AudioResamplerCubic.h"
 
+#ifdef __arm__
+#include <machine/cpu-features.h>
+#endif
+
 namespace android {
 
-#ifdef __ARM_ARCH_5E__  // optimized asm option
+#ifdef __ARM_HAVE_HALFWORD_MULTIPLY // optimized asm option
     #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
-#endif // __ARM_ARCH_5E__
+#endif // __ARM_HAVE_HALFWORD_MULTIPLY
 // ----------------------------------------------------------------------------
 
 class AudioResamplerOrder1 : public AudioResampler {
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 1455764..7028772 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1399,6 +1399,24 @@
         }
     }
 
+    public InputMethodSubtype getLastInputMethodSubtype() {
+        synchronized (mMethodMap) {
+            final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
+            // TODO: Handle the case of the last IME with no subtypes
+            if (lastIme == null || TextUtils.isEmpty(lastIme.first)
+                    || TextUtils.isEmpty(lastIme.second)) return null;
+            final InputMethodInfo lastImi = mMethodMap.get(lastIme.first);
+            if (lastImi == null) return null;
+            try {
+                final int lastSubtypeHash = Integer.valueOf(lastIme.second);
+                return lastImi.getSubtypeAt(getSubtypeIdFromHashCode(
+                        lastImi, lastSubtypeHash));
+            } catch (NumberFormatException e) {
+                return null;
+            }
+        }
+    }
+
     private void setInputMethodWithSubtypeId(IBinder token, String id, int subtypeId) {
         synchronized (mMethodMap) {
             if (token == null) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 9990b7b..31b7f86 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -441,8 +441,7 @@
     /**
      * List of intents that were used to start the most recent tasks.
      */
-    final ArrayList<TaskRecord> mRecentTasks
-            = new ArrayList<TaskRecord>();
+    final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>();
 
     /**
      * All of the applications we currently have running organized by name.
@@ -450,8 +449,7 @@
      * returned by the package manager), and the keys are ApplicationRecord
      * objects.
      */
-    final ProcessMap<ProcessRecord> mProcessNames
-            = new ProcessMap<ProcessRecord>();
+    final ProcessMap<ProcessRecord> mProcessNames = new ProcessMap<ProcessRecord>();
 
     /**
      * The currently running heavy-weight process, if any.
@@ -480,8 +478,7 @@
      * <p>NOTE: This object is protected by its own lock, NOT the global
      * activity manager lock!
      */
-    final SparseArray<ProcessRecord> mPidsSelfLocked
-            = new SparseArray<ProcessRecord>();
+    final SparseArray<ProcessRecord> mPidsSelfLocked = new SparseArray<ProcessRecord>();
 
     /**
      * All of the processes that have been forced to be foreground.  The key
@@ -2981,7 +2978,10 @@
         
         synchronized (this) {
             if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
-                Process.killProcess(app.pid);
+                Slog.w(TAG, "Killing " + app + ": background ANR");
+                EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+                        app.processName, app.setAdj, "background ANR");
+                Process.killProcessQuiet(app.pid);
                 return;
             }
     
@@ -3446,7 +3446,9 @@
                     bringDownServiceLocked(sr, true);
                 }
             }
-            Process.killProcess(pid);
+            EventLog.writeEvent(EventLogTags.AM_KILL, pid,
+                    app.processName, app.setAdj, "start timeout");
+            Process.killProcessQuiet(pid);
             if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
                 Slog.w(TAG, "Unattached app died before backup, skipping");
                 try {
@@ -3492,7 +3494,7 @@
                     + " (IApplicationThread " + thread + "); dropping process");
             EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
             if (pid > 0 && pid != MY_PID) {
-                Process.killProcess(pid);
+                Process.killProcessQuiet(pid);
             } else {
                 try {
                     thread.scheduleExit();
@@ -3890,18 +3892,17 @@
             }
             for (int i=0; i<intents.length; i++) {
                 Intent intent = intents[i];
-                if (intent == null) {
-                    throw new IllegalArgumentException("Null intent at index " + i);
+                if (intent != null) {
+                    if (intent.hasFileDescriptors()) {
+                        throw new IllegalArgumentException("File descriptors passed in Intent");
+                    }
+                    if (type == INTENT_SENDER_BROADCAST &&
+                            (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
+                        throw new IllegalArgumentException(
+                                "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
+                    }
+                    intents[i] = new Intent(intent);
                 }
-                if (intent.hasFileDescriptors()) {
-                    throw new IllegalArgumentException("File descriptors passed in Intent");
-                }
-                if (type == INTENT_SENDER_BROADCAST &&
-                        (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
-                    throw new IllegalArgumentException(
-                            "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
-                }
-                intents[i] = new Intent(intent);
             }
             if (resolvedTypes != null && resolvedTypes.length != intents.length) {
                 throw new IllegalArgumentException(
@@ -4832,11 +4833,6 @@
                 throw new SecurityException(msg);
             }
 
-            final boolean canReadFb = (flags&ActivityManager.TASKS_GET_THUMBNAILS) != 0
-                    && checkCallingPermission(
-                            android.Manifest.permission.READ_FRAME_BUFFER)
-                            == PackageManager.PERMISSION_GRANTED;
-
             int pos = mMainStack.mHistory.size()-1;
             ActivityRecord next =
                 pos >= 0 ? (ActivityRecord)mMainStack.mHistory.get(pos) : null;
@@ -4876,13 +4872,6 @@
                     ci.id = curTask.taskId;
                     ci.baseActivity = r.intent.getComponent();
                     ci.topActivity = top.intent.getComponent();
-                    if (canReadFb) {
-                        if (top.state == ActivityState.RESUMED) {
-                            ci.thumbnail = top.stack.screenshotActivities(top);
-                        } else if (top.thumbHolder != null) {
-                            ci.thumbnail = top.thumbHolder.lastThumbnail;
-                        }
-                    }
                     if (top.thumbHolder != null) {
                         ci.description = top.thumbHolder.lastDescription;
                     }
@@ -4955,8 +4944,6 @@
 
             IPackageManager pm = AppGlobals.getPackageManager();
             
-            ActivityRecord resumed = mMainStack.mResumedActivity;
-            
             final int N = mRecentTasks.size();
             ArrayList<ActivityManager.RecentTaskInfo> res
                     = new ArrayList<ActivityManager.RecentTaskInfo>(
@@ -5002,75 +4989,122 @@
         }
     }
 
-    public ActivityManager.TaskThumbnails getTaskThumbnails(int id) {
-        synchronized (this) {
-            enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
-                    "getTaskThumbnail()");
-            ActivityRecord resumed = mMainStack.mResumedActivity;
-            final int N = mRecentTasks.size();
-            for (int i=0; i<N; i++) {
-                TaskRecord tr = mRecentTasks.get(i);
-                if (tr.taskId == id) {
-                    final ActivityManager.TaskThumbnails thumbs
-                            = new ActivityManager.TaskThumbnails();
-                    if (resumed != null && resumed.thumbHolder == tr) {
-                        thumbs.mainThumbnail = resumed.stack.screenshotActivities(resumed);
-                    } else {
-                        thumbs.mainThumbnail = tr.lastThumbnail;
-                    }
-                    // How many different sub-thumbnails?
-                    final int NA = mMainStack.mHistory.size();
-                    int j = 0;
-                    ThumbnailHolder holder = null;
-                    while (j < NA) {
-                        ActivityRecord ar = (ActivityRecord)mMainStack.mHistory.get(j);
-                        j++;
-                        if (ar.task == tr) {
-                            holder = ar.thumbHolder;
-                            break;
-                        }
-                    }
-                    ArrayList<Bitmap> bitmaps = new ArrayList<Bitmap>();
-                    thumbs.otherThumbnails = bitmaps;
-                    ActivityRecord lastActivity = null;
-                    while (j < NA) {
-                        ActivityRecord ar = (ActivityRecord)mMainStack.mHistory.get(j);
-                        j++;
-                        if (ar.task != tr) {
-                            break;
-                        }
-                        lastActivity = ar;
-                        if (ar.thumbHolder != holder && holder != null) {
-                            thumbs.numSubThumbbails++;
-                            holder = ar.thumbHolder;
-                            bitmaps.add(holder.lastThumbnail);
-                        }
-                    }
-                    if (lastActivity != null && bitmaps.size() > 0) {
-                        if (resumed == lastActivity) {
-                            Bitmap bm = lastActivity.stack.screenshotActivities(lastActivity);
-                            if (bm != null) {
-                                bitmaps.remove(bitmaps.size()-1);
-                                bitmaps.add(bm);
-                            }
-                        }
-                    }
-                    if (thumbs.numSubThumbbails > 0) {
-                        thumbs.retriever = new IThumbnailRetriever.Stub() {
-                            public Bitmap getThumbnail(int index) {
-                                if (index < 0 || index >= thumbs.otherThumbnails.size()) {
-                                    return null;
-                                }
-                                return thumbs.otherThumbnails.get(index);
-                            }
-                        };
-                    }
-                    return thumbs;
-                }
+    private TaskRecord taskForIdLocked(int id) {
+        final int N = mRecentTasks.size();
+        for (int i=0; i<N; i++) {
+            TaskRecord tr = mRecentTasks.get(i);
+            if (tr.taskId == id) {
+                return tr;
             }
         }
         return null;
     }
+
+    public ActivityManager.TaskThumbnails getTaskThumbnails(int id) {
+        synchronized (this) {
+            enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
+                    "getTaskThumbnails()");
+            TaskRecord tr = taskForIdLocked(id);
+            if (tr != null) {
+                return mMainStack.getTaskThumbnailsLocked(tr);
+            }
+        }
+        return null;
+    }
+
+    public boolean removeSubTask(int taskId, int subTaskIndex) {
+        synchronized (this) {
+            enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS,
+                    "removeSubTask()");
+            long ident = Binder.clearCallingIdentity();
+            try {
+                return mMainStack.removeTaskActivitiesLocked(taskId, subTaskIndex) != null;
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    private void removeTaskProcessesLocked(ActivityRecord root) {
+        TaskRecord tr = root.task;
+        Intent baseIntent = new Intent(
+                tr.intent != null ? tr.intent : tr.affinityIntent);
+        ComponentName component = baseIntent.getComponent();
+        if (component == null) {
+            Slog.w(TAG, "Now component for base intent of task: " + tr);
+            return;
+        }
+
+        // Find any running services associated with this app.
+        ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
+        for (ServiceRecord sr : mServices.values()) {
+            if (sr.packageName.equals(component.getPackageName())) {
+                services.add(sr);
+            }
+        }
+
+        // Take care of any running services associated with the app.
+        for (int i=0; i<services.size(); i++) {
+            ServiceRecord sr = services.get(i);
+            if (sr.startRequested) {
+                if ((sr.serviceInfo.flags&ServiceInfo.FLAG_STOP_WITH_TASK) != 0) {
+                    stopServiceLocked(sr);
+                } else {
+                    sr.pendingStarts.add(new ServiceRecord.StartItem(sr, true,
+                            sr.makeNextStartId(), baseIntent, -1));
+                    if (sr.app != null && sr.app.thread != null) {
+                        sendServiceArgsLocked(sr, false);
+                    }
+                }
+            }
+        }
+
+        // Find any running processes associated with this app.
+        ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
+        SparseArray<ProcessRecord> appProcs
+                = mProcessNames.getMap().get(component.getPackageName());
+        if (appProcs != null) {
+            for (int i=0; i<appProcs.size(); i++) {
+                procs.add(appProcs.valueAt(i));
+            }
+        }
+
+        // Kill the running processes.
+        for (int i=0; i<procs.size(); i++) {
+            ProcessRecord pr = procs.get(i);
+            if (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
+                Slog.i(TAG, "Killing " + pr + ": remove task");
+                EventLog.writeEvent(EventLogTags.AM_KILL, pr.pid,
+                        pr.processName, pr.setAdj, "remove task");
+                Process.killProcessQuiet(pr.pid);
+            } else {
+                pr.waitingToKill = "remove task";
+            }
+        }
+    }
+
+    public boolean removeTask(int taskId, int flags) {
+        synchronized (this) {
+            enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS,
+                    "removeTask()");
+            long ident = Binder.clearCallingIdentity();
+            try {
+                ActivityRecord r = mMainStack.removeTaskActivitiesLocked(taskId, -1);
+                if (r != null) {
+                    mRecentTasks.remove(r.task);
+
+                    if ((flags&ActivityManager.REMOVE_TASK_KILL_PROCESS) != 0) {
+                        removeTaskProcessesLocked(r);
+                    }
+
+                    return true;
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+        return false;
+    }
     
     private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
         int j;
@@ -5123,21 +5157,18 @@
             }
             final long origId = Binder.clearCallingIdentity();
             try {
-                int N = mRecentTasks.size();
-                for (int i=0; i<N; i++) {
-                    TaskRecord tr = mRecentTasks.get(i);
-                    if (tr.taskId == task) {
-                        if ((flags&ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
-                            mMainStack.mUserLeaving = true;
-                        }
-                        if ((flags&ActivityManager.MOVE_TASK_WITH_HOME) != 0) {
-                            // Caller wants the home activity moved with it.  To accomplish this,
-                            // we'll just move the home task to the top first.
-                            mMainStack.moveHomeToFrontLocked();
-                        }
-                        mMainStack.moveTaskToFrontLocked(tr, null);
-                        return;
+                TaskRecord tr = taskForIdLocked(task);
+                if (tr != null) {
+                    if ((flags&ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
+                        mMainStack.mUserLeaving = true;
                     }
+                    if ((flags&ActivityManager.MOVE_TASK_WITH_HOME) != 0) {
+                        // Caller wants the home activity moved with it.  To accomplish this,
+                        // we'll just move the home task to the top first.
+                        mMainStack.moveHomeToFrontLocked();
+                    }
+                    mMainStack.moveTaskToFrontLocked(tr, null);
+                    return;
                 }
                 for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
                     ActivityRecord hr = (ActivityRecord)mMainStack.mHistory.get(i);
@@ -6661,11 +6692,10 @@
             }
             if (app.pid > 0 && app.pid != MY_PID) {
                 handleAppCrashLocked(app);
-                Slog.i(ActivityManagerService.TAG, "Killing "
-                        + app.processName + " (pid=" + app.pid + "): user's request");
+                Slog.i(ActivityManagerService.TAG, "Killing " + app + ": user's request");
                 EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
                         app.processName, app.setAdj, "user's request after error");
-                Process.killProcess(app.pid);
+                Process.killProcessQuiet(app.pid);
             }
         }
     }
@@ -8946,7 +8976,7 @@
                         + " in dying process " + proc.processName);
                 EventLog.writeEvent(EventLogTags.AM_KILL, capp.pid,
                         capp.processName, capp.setAdj, "dying provider " + proc.processName);
-                Process.killProcess(capp.pid);
+                Process.killProcessQuiet(capp.pid);
             }
         }
         
@@ -9453,7 +9483,7 @@
                 if (si.doneExecutingCount > 0) {
                     flags |= Service.START_FLAG_REDELIVERY;
                 }
-                r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
+                r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
             } catch (RemoteException e) {
                 // Remote process gone...  we'll let the normal cleanup take
                 // care of this.
@@ -9539,11 +9569,8 @@
         // pending arguments, then fake up one so its onStartCommand() will
         // be called.
         if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
-            r.lastStartId++;
-            if (r.lastStartId < 1) {
-                r.lastStartId = 1;
-            }
-            r.pendingStarts.add(new ServiceRecord.StartItem(r, r.lastStartId, null, -1));
+            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
+                    null, -1));
         }
         
         sendServiceArgsLocked(r, true);
@@ -9897,11 +9924,7 @@
             }
             r.startRequested = true;
             r.callStart = false;
-            r.lastStartId++;
-            if (r.lastStartId < 1) {
-                r.lastStartId = 1;
-            }
-            r.pendingStarts.add(new ServiceRecord.StartItem(r, r.lastStartId,
+            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                     service, targetPermissionUid));
             r.lastActivity = SystemClock.uptimeMillis();
             synchronized (r.stats.getBatteryStats()) {
@@ -9943,6 +9966,15 @@
         }
     }
 
+    private void stopServiceLocked(ServiceRecord service) {
+        synchronized (service.stats.getBatteryStats()) {
+            service.stats.stopRunningLocked();
+        }
+        service.startRequested = false;
+        service.callStart = false;
+        bringDownServiceLocked(service, false);
+    }
+
     public int stopService(IApplicationThread caller, Intent service,
             String resolvedType) {
         // Refuse possible leaked file descriptors
@@ -9966,14 +9998,12 @@
             ServiceLookupResult r = findServiceLocked(service, resolvedType);
             if (r != null) {
                 if (r.record != null) {
-                    synchronized (r.record.stats.getBatteryStats()) {
-                        r.record.stats.stopRunningLocked();
-                    }
-                    r.record.startRequested = false;
-                    r.record.callStart = false;
                     final long origId = Binder.clearCallingIdentity();
-                    bringDownServiceLocked(r.record, false);
-                    Binder.restoreCallingIdentity(origId);
+                    try {
+                        stopServiceLocked(r.record);
+                    } finally {
+                        Binder.restoreCallingIdentity(origId);
+                    }
                     return 1;
                 }
                 return -1;
@@ -10035,7 +10065,7 @@
                         }
                     }
                     
-                    if (r.lastStartId != startId) {
+                    if (r.getLastStartId() != startId) {
                         return false;
                     }
                     
@@ -10476,7 +10506,7 @@
                         case Service.START_NOT_STICKY: {
                             // We are done with the associated start arguments.
                             r.findDeliveredStart(startId, true);
-                            if (r.lastStartId == startId) {
+                            if (r.getLastStartId() == startId) {
                                 // There is no more work, and this service
                                 // doesn't want to hang around if killed.
                                 r.stopIfKilled = true;
@@ -10496,6 +10526,12 @@
                             }
                             break;
                         }
+                        case Service.START_TASK_REMOVED_COMPLETE: {
+                            // Special processing for onTaskRemoved().  Don't
+                            // impact normal onStartCommand() processing.
+                            r.findDeliveredStart(startId, true);
+                            break;
+                        }
                         default:
                             throw new IllegalArgumentException(
                                     "Unknown service start result: " + res);
@@ -12885,23 +12921,31 @@
                 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
                         "Setting process group of " + app.processName
                         + " to " + app.curSchedGroup);
-                if (true) {
-                    long oldId = Binder.clearCallingIdentity();
-                    try {
-                        Process.setProcessGroup(app.pid, app.curSchedGroup);
-                    } catch (Exception e) {
-                        Slog.w(TAG, "Failed setting process group of " + app.pid
-                                + " to " + app.curSchedGroup);
-                        e.printStackTrace();
-                    } finally {
-                        Binder.restoreCallingIdentity(oldId);
-                    }
-                }
-                if (false) {
-                    if (app.thread != null) {
+                if (app.waitingToKill != null &&
+                        app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
+                    Slog.i(TAG, "Killing " + app + ": " + app.waitingToKill);
+                    EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+                            app.processName, app.setAdj, app.waitingToKill);
+                    Process.killProcessQuiet(app.pid);
+                } else {
+                    if (true) {
+                        long oldId = Binder.clearCallingIdentity();
                         try {
-                            app.thread.setSchedulingGroup(app.curSchedGroup);
-                        } catch (RemoteException e) {
+                            Process.setProcessGroup(app.pid, app.curSchedGroup);
+                        } catch (Exception e) {
+                            Slog.w(TAG, "Failed setting process group of " + app.pid
+                                    + " to " + app.curSchedGroup);
+                            e.printStackTrace();
+                        } finally {
+                            Binder.restoreCallingIdentity(oldId);
+                        }
+                    }
+                    if (false) {
+                        if (app.thread != null) {
+                            try {
+                                app.thread.setSchedulingGroup(app.curSchedGroup);
+                            } catch (RemoteException e) {
+                            }
                         }
                     }
                 }
@@ -13024,7 +13068,9 @@
                         + (app.thread != null ? app.thread.asBinder() : null)
                         + ")\n");
                     if (app.pid > 0 && app.pid != MY_PID) {
-                        Process.killProcess(app.pid);
+                        EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+                                app.processName, app.setAdj, "empty");
+                        Process.killProcessQuiet(app.pid);
                     } else {
                         try {
                             app.thread.scheduleExit();
@@ -13090,7 +13136,9 @@
                             + (app.thread != null ? app.thread.asBinder() : null)
                             + ")\n");
                         if (app.pid > 0 && app.pid != MY_PID) {
-                            Process.killProcess(app.pid);
+                            EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+                                    app.processName, app.setAdj, "empty");
+                            Process.killProcessQuiet(app.pid);
                         } else {
                             try {
                                 app.thread.scheduleExit();
@@ -13147,7 +13195,9 @@
                               + (app.thread != null ? app.thread.asBinder() : null)
                               + ")\n");
                         if (app.pid > 0 && app.pid != MY_PID) {
-                            Process.killProcess(app.pid);
+                            EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+                                    app.processName, app.setAdj, "old background");
+                            Process.killProcessQuiet(app.pid);
                         } else {
                             try {
                                 app.thread.scheduleExit();
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index e1d380b..9558895 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -21,8 +21,10 @@
 import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
 
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.app.IActivityManager;
+import android.app.IThumbnailRetriever;
 import static android.app.IActivityManager.START_CLASS_NOT_FOUND;
 import static android.app.IActivityManager.START_DELIVERED_TO_TOP;
 import static android.app.IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
@@ -69,7 +71,7 @@
 /**
  * State and management of a single stack of activities.
  */
-final public class ActivityStack {
+final class ActivityStack {
     static final String TAG = ActivityManagerService.TAG;
     static final boolean localLOGV = ActivityManagerService.localLOGV;
     static final boolean DEBUG_SWITCH = ActivityManagerService.DEBUG_SWITCH;
@@ -135,14 +137,14 @@
      * The back history of all previous (and possibly still
      * running) activities.  It contains HistoryRecord objects.
      */
-    final ArrayList mHistory = new ArrayList();
+    final ArrayList<ActivityRecord> mHistory = new ArrayList<ActivityRecord>();
     
     /**
      * List of running activities, sorted by recent usage.
      * The first entry in the list is the least recently used.
      * It contains HistoryRecord objects.
      */
-    final ArrayList mLRUActivities = new ArrayList();
+    final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<ActivityRecord>();
 
     /**
      * List of activities that are waiting for a new activity
@@ -346,7 +348,7 @@
     final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
         int i = mHistory.size()-1;
         while (i >= 0) {
-            ActivityRecord r = (ActivityRecord)mHistory.get(i);
+            ActivityRecord r = mHistory.get(i);
             if (!r.finishing && r != notTop) {
                 return r;
             }
@@ -358,7 +360,7 @@
     final ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
         int i = mHistory.size()-1;
         while (i >= 0) {
-            ActivityRecord r = (ActivityRecord)mHistory.get(i);
+            ActivityRecord r = mHistory.get(i);
             if (!r.finishing && !r.delayedResume && r != notTop) {
                 return r;
             }
@@ -379,7 +381,7 @@
     final ActivityRecord topRunningActivityLocked(IBinder token, int taskId) {
         int i = mHistory.size()-1;
         while (i >= 0) {
-            ActivityRecord r = (ActivityRecord)mHistory.get(i);
+            ActivityRecord r = mHistory.get(i);
             // Note: the taskId check depends on real taskId fields being non-zero
             if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
                 return r;
@@ -425,7 +427,7 @@
 
         final int N = mHistory.size();
         for (int i=(N-1); i>=0; i--) {
-            ActivityRecord r = (ActivityRecord)mHistory.get(i);
+            ActivityRecord r = mHistory.get(i);
             if (!r.finishing && r.task != cp
                     && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
                 cp = r.task;
@@ -469,7 +471,7 @@
 
         final int N = mHistory.size();
         for (int i=(N-1); i>=0; i--) {
-            ActivityRecord r = (ActivityRecord)mHistory.get(i);
+            ActivityRecord r = mHistory.get(i);
             if (!r.finishing) {
                 if (r.intent.getComponent().equals(cls)) {
                     //Slog.i(TAG, "Found matching class!");
@@ -504,6 +506,7 @@
         }
 
         r.app = app;
+        app.waitingToKill = null;
 
         if (localLOGV) Slog.v(TAG, "Launching: " + r);
 
@@ -678,7 +681,7 @@
         }
         // Ensure activities are no longer sleeping.
         for (int i=mHistory.size()-1; i>=0; i--) {
-            ActivityRecord r = (ActivityRecord)mHistory.get(i);
+            ActivityRecord r = mHistory.get(i);
             r.setSleeping(false);
         }
         mGoingToSleepActivities.clear();
@@ -724,7 +727,7 @@
             // Make sure any stopped but visible activities are now sleeping.
             // This ensures that the activity's onStop() is called.
             for (int i=mHistory.size()-1; i>=0; i--) {
-                ActivityRecord r = (ActivityRecord)mHistory.get(i);
+                ActivityRecord r = mHistory.get(i);
                 if (r.state == ActivityState.STOPPING || r.state == ActivityState.STOPPED) {
                     r.setSleeping(true);
                 }
@@ -862,7 +865,7 @@
         synchronized (mService) {
             int index = indexOfTokenLocked(token);
             if (index >= 0) {
-                r = (ActivityRecord)mHistory.get(index);
+                r = mHistory.get(index);
                 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
                 if (mPausingActivity == r) {
                     r.state = ActivityState.PAUSED;
@@ -1024,7 +1027,7 @@
         ActivityRecord r;
         boolean behindFullscreen = false;
         for (; i>=0; i--) {
-            r = (ActivityRecord)mHistory.get(i);
+            r = mHistory.get(i);
             if (DEBUG_VISBILITY) Slog.v(
                     TAG, "Make visible? " + r + " finishing=" + r.finishing
                     + " state=" + r.state);
@@ -1108,7 +1111,7 @@
         // Now for any activities that aren't visible to the user, make
         // sure they no longer are keeping the screen frozen.
         while (i >= 0) {
-            r = (ActivityRecord)mHistory.get(i);
+            r = mHistory.get(i);
             if (DEBUG_VISBILITY) Slog.v(
                     TAG, "Make invisible? " + r + " finishing=" + r.finishing
                     + " state=" + r.state
@@ -1499,7 +1502,7 @@
             // If starting in an existing task, find where that is...
             boolean startIt = true;
             for (int i = NH-1; i >= 0; i--) {
-                ActivityRecord p = (ActivityRecord)mHistory.get(i);
+                ActivityRecord p = mHistory.get(i);
                 if (p.finishing) {
                     continue;
                 }
@@ -1646,7 +1649,7 @@
         int replyChainEnd = -1;
         int lastReparentPos = -1;
         for (int i=mHistory.size()-1; i>=-1; i--) {
-            ActivityRecord below = i >= 0 ? (ActivityRecord)mHistory.get(i) : null;
+            ActivityRecord below = i >= 0 ? mHistory.get(i) : null;
             
             if (below != null && below.finishing) {
                 continue;
@@ -1700,7 +1703,7 @@
                         // bottom of the activity stack.  This also keeps it
                         // correctly ordered with any activities we previously
                         // moved.
-                        ActivityRecord p = (ActivityRecord)mHistory.get(0);
+                        ActivityRecord p = mHistory.get(0);
                         if (target.taskAffinity != null
                                 && target.taskAffinity.equals(p.task.affinity)) {
                             // If the activity currently at the bottom has the
@@ -1727,7 +1730,7 @@
                         int dstPos = 0;
                         ThumbnailHolder curThumbHolder = target.thumbHolder;
                         for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
-                            p = (ActivityRecord)mHistory.get(srcPos);
+                            p = mHistory.get(srcPos);
                             if (p.finishing) {
                                 continue;
                             }
@@ -1764,7 +1767,7 @@
                             // like these are all in the reply chain.
                             replyChainEnd = targetI+1;
                             while (replyChainEnd < mHistory.size() &&
-                                    ((ActivityRecord)mHistory.get(
+                                    (mHistory.get(
                                                 replyChainEnd)).task == task) {
                                 replyChainEnd++;
                             }
@@ -1774,7 +1777,7 @@
                         }
                         ActivityRecord p = null;
                         for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
-                            p = (ActivityRecord)mHistory.get(srcPos);
+                            p = mHistory.get(srcPos);
                             if (p.finishing) {
                                 continue;
                             }
@@ -1834,7 +1837,7 @@
                     }
                     ActivityRecord p = null;
                     for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
-                        p = (ActivityRecord)mHistory.get(srcPos);
+                        p = mHistory.get(srcPos);
                         if (p.finishing) {
                             continue;
                         }
@@ -1852,7 +1855,7 @@
                         replyChainEnd = targetI;
                     }
                     for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
-                        ActivityRecord p = (ActivityRecord)mHistory.get(srcPos);
+                        ActivityRecord p = mHistory.get(srcPos);
                         if (p.finishing) {
                             continue;
                         }
@@ -1881,7 +1884,7 @@
                     // below so it remains singleTop.
                     if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
                         for (int j=lastReparentPos-1; j>=0; j--) {
-                            ActivityRecord p = (ActivityRecord)mHistory.get(j);
+                            ActivityRecord p = mHistory.get(j);
                             if (p.finishing) {
                                 continue;
                             }
@@ -1922,7 +1925,7 @@
         // First find the requested task.
         while (i > 0) {
             i--;
-            ActivityRecord r = (ActivityRecord)mHistory.get(i);
+            ActivityRecord r = mHistory.get(i);
             if (r.task.taskId == taskId) {
                 i++;
                 break;
@@ -1932,7 +1935,7 @@
         // Now clear it.
         while (i > 0) {
             i--;
-            ActivityRecord r = (ActivityRecord)mHistory.get(i);
+            ActivityRecord r = mHistory.get(i);
             if (r.finishing) {
                 continue;
             }
@@ -1944,7 +1947,7 @@
                 ActivityRecord ret = r;
                 while (i < (mHistory.size()-1)) {
                     i++;
-                    r = (ActivityRecord)mHistory.get(i);
+                    r = mHistory.get(i);
                     if (r.task.taskId != taskId) {
                         break;
                     }
@@ -1980,6 +1983,28 @@
     }
 
     /**
+     * Completely remove all activities associated with an existing
+     * task starting at a specified index.
+     */
+    private final void performClearTaskAtIndexLocked(int taskId, int i) {
+        while (i < (mHistory.size()-1)) {
+            ActivityRecord r = mHistory.get(i);
+            if (r.task.taskId != taskId) {
+                // Whoops hit the end.
+                return;
+            }
+            if (r.finishing) {
+                i++;
+                continue;
+            }
+            if (!finishActivityLocked(r, i, Activity.RESULT_CANCELED,
+                    null, "clear")) {
+                i++;
+            }
+        }
+    }
+
+    /**
      * Completely remove all activities associated with an existing task.
      */
     private final void performClearTaskLocked(int taskId) {
@@ -1988,37 +2013,23 @@
         // First find the requested task.
         while (i > 0) {
             i--;
-            ActivityRecord r = (ActivityRecord)mHistory.get(i);
+            ActivityRecord r = mHistory.get(i);
             if (r.task.taskId == taskId) {
                 i++;
                 break;
             }
         }
 
-        // Now clear it.
+        // Now find the start and clear it.
         while (i > 0) {
             i--;
-            ActivityRecord r = (ActivityRecord)mHistory.get(i);
+            ActivityRecord r = mHistory.get(i);
             if (r.finishing) {
                 continue;
             }
             if (r.task.taskId != taskId) {
                 // We hit the bottom.  Now finish it all...
-                while (i < (mHistory.size()-1)) {
-                    i++;
-                    r = (ActivityRecord)mHistory.get(i);
-                    if (r.task.taskId != taskId) {
-                        // Whoops hit the end.
-                        return;
-                    }
-                    if (r.finishing) {
-                        continue;
-                    }
-                    if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
-                            null, "clear")) {
-                        i--;
-                    }
-                }
+                performClearTaskAtIndexLocked(taskId, i+1);
                 return;
             }
         }
@@ -2032,7 +2043,7 @@
         int i = mHistory.size();
         while (i > 0) {
             i--;
-            ActivityRecord candidate = (ActivityRecord)mHistory.get(i);
+            ActivityRecord candidate = mHistory.get(i);
             if (candidate.task.taskId != task) {
                 break;
             }
@@ -2049,9 +2060,9 @@
      * brought to the front.
      */
     private final ActivityRecord moveActivityToFrontLocked(int where) {
-        ActivityRecord newTop = (ActivityRecord)mHistory.remove(where);
+        ActivityRecord newTop = mHistory.remove(where);
         int top = mHistory.size();
-        ActivityRecord oldTop = (ActivityRecord)mHistory.get(top-1);
+        ActivityRecord oldTop = mHistory.get(top-1);
         mHistory.add(top, newTop);
         oldTop.frontOfTask = false;
         newTop.frontOfTask = true;
@@ -2094,7 +2105,7 @@
             if (DEBUG_RESULTS) Slog.v(
                 TAG, "Sending result to " + resultTo + " (index " + index + ")");
             if (index >= 0) {
-                sourceRecord = (ActivityRecord)mHistory.get(index);
+                sourceRecord = mHistory.get(index);
                 if (requestCode >= 0 && !sourceRecord.finishing) {
                     resultRecord = sourceRecord;
                 }
@@ -2576,7 +2587,7 @@
             // this case should never happen.
             final int N = mHistory.size();
             ActivityRecord prev =
-                N > 0 ? (ActivityRecord)mHistory.get(N-1) : null;
+                N > 0 ? mHistory.get(N-1) : null;
             r.setTask(prev != null
                     ? prev.task
                     : new TaskRecord(mService.mCurTask, r.info, intent), null, true);
@@ -3021,7 +3032,7 @@
             // Get the activity record.
             int index = indexOfTokenLocked(token);
             if (index >= 0) {
-                ActivityRecord r = (ActivityRecord)mHistory.get(index);
+                ActivityRecord r = mHistory.get(index);
 
                 if (fromTimeout) {
                     reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
@@ -3153,12 +3164,12 @@
         if (index < 0) {
             return false;
         }
-        ActivityRecord r = (ActivityRecord)mHistory.get(index);
+        ActivityRecord r = mHistory.get(index);
 
         // Is this the last activity left?
         boolean lastActivity = true;
         for (int i=mHistory.size()-1; i>=0; i--) {
-            ActivityRecord p = (ActivityRecord)mHistory.get(i);
+            ActivityRecord p = mHistory.get(i);
             if (!p.finishing && p != r) {
                 lastActivity = false;
                 break;
@@ -3193,7 +3204,7 @@
                 System.identityHashCode(r),
                 r.task.taskId, r.shortComponentName, reason);
         if (index < (mHistory.size()-1)) {
-            ActivityRecord next = (ActivityRecord)mHistory.get(index+1);
+            ActivityRecord next = mHistory.get(index+1);
             if (next.task == r.task) {
                 if (r.frontOfTask) {
                     // The next activity is now the front of the task.
@@ -3249,7 +3260,7 @@
 
         if (mResumedActivity == r) {
             boolean endTask = index <= 0
-                    || ((ActivityRecord)mHistory.get(index-1)).task != r.task;
+                    || (mHistory.get(index-1)).task != r.task;
             if (DEBUG_TRANSITION) Slog.v(TAG,
                     "Prepare close transition: finishing " + r);
             mService.mWindowManager.prepareAppTransition(endTask
@@ -3391,6 +3402,7 @@
         // Get rid of any pending idle timeouts.
         mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
         mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
+        mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
     }
 
     private final void removeActivityFromHistoryLocked(ActivityRecord r) {
@@ -3516,7 +3528,7 @@
             
             int index = indexOfTokenLocked(token);
             if (index >= 0) {
-                ActivityRecord r = (ActivityRecord)mHistory.get(index);
+                ActivityRecord r = mHistory.get(index);
                 if (r.state == ActivityState.DESTROYING) {
                     final long origId = Binder.clearCallingIdentity();
                     removeActivityFromHistoryLocked(r);
@@ -3558,7 +3570,7 @@
     final void moveHomeToFrontLocked() {
         TaskRecord homeTask = null;
         for (int i=mHistory.size()-1; i>=0; i--) {
-            ActivityRecord hr = (ActivityRecord)mHistory.get(i);
+            ActivityRecord hr = mHistory.get(i);
             if (hr.isHomeActivity) {
                 homeTask = hr.task;
                 break;
@@ -3576,7 +3588,7 @@
         final int task = tr.taskId;
         int top = mHistory.size()-1;
 
-        if (top < 0 || ((ActivityRecord)mHistory.get(top)).task.taskId == task) {
+        if (top < 0 || (mHistory.get(top)).task.taskId == task) {
             // nothing to do!
             return;
         }
@@ -3591,7 +3603,7 @@
         // Shift all activities with this task up to the top
         // of the stack, keeping them in the same internal order.
         while (pos >= 0) {
-            ActivityRecord r = (ActivityRecord)mHistory.get(pos);
+            ActivityRecord r = mHistory.get(pos);
             if (localLOGV) Slog.v(
                 TAG, "At " + pos + " ckp " + r.task + ": " + r);
             if (r.task.taskId == task) {
@@ -3680,7 +3692,7 @@
         // Shift all activities with this task down to the bottom
         // of the stack, keeping them in the same internal order.
         while (pos < N) {
-            ActivityRecord r = (ActivityRecord)mHistory.get(pos);
+            ActivityRecord r = mHistory.get(pos);
             if (localLOGV) Slog.v(
                 TAG, "At " + pos + " ckp " + r.task + ": " + r);
             if (r.task.taskId == task) {
@@ -3714,6 +3726,106 @@
         return true;
     }
     
+    public ActivityManager.TaskThumbnails getTaskThumbnailsLocked(TaskRecord tr) {
+        TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true);
+        ActivityRecord resumed = mResumedActivity;
+        if (resumed != null && resumed.thumbHolder == tr) {
+            info.mainThumbnail = resumed.stack.screenshotActivities(resumed);
+        } else {
+            info.mainThumbnail = tr.lastThumbnail;
+        }
+        return info;
+    }
+
+    public ActivityRecord removeTaskActivitiesLocked(int taskId, int subTaskIndex) {
+        TaskAccessInfo info = getTaskAccessInfoLocked(taskId, false);
+        if (info.root == null) {
+            Slog.w(TAG, "removeTaskLocked: unknown taskId " + taskId);
+            return null;
+        }
+
+        if (subTaskIndex < 0) {
+            // Just remove the entire task.
+            performClearTaskAtIndexLocked(taskId, info.rootIndex);
+            return info.root;
+        }
+
+        if (subTaskIndex >= info.subtasks.size()) {
+            Slog.w(TAG, "removeTaskLocked: unknown subTaskIndex " + subTaskIndex);
+            return null;
+        }
+
+        // Remove all of this task's activies starting at the sub task.
+        TaskAccessInfo.SubTask subtask = info.subtasks.get(subTaskIndex);
+        performClearTaskAtIndexLocked(taskId, subtask.index);
+        return subtask.activity;
+    }
+
+    public TaskAccessInfo getTaskAccessInfoLocked(int taskId, boolean inclThumbs) {
+        ActivityRecord resumed = mResumedActivity;
+        final TaskAccessInfo thumbs = new TaskAccessInfo();
+        // How many different sub-thumbnails?
+        final int NA = mHistory.size();
+        int j = 0;
+        ThumbnailHolder holder = null;
+        while (j < NA) {
+            ActivityRecord ar = mHistory.get(j);
+            if (!ar.finishing && ar.task.taskId == taskId) {
+                holder = ar.thumbHolder;
+                break;
+            }
+            j++;
+        }
+
+        if (j >= NA) {
+            return thumbs;
+        }
+
+        thumbs.root = mHistory.get(j);
+        thumbs.rootIndex = j;
+
+        ArrayList<TaskAccessInfo.SubTask> subtasks = new ArrayList<TaskAccessInfo.SubTask>();
+        thumbs.subtasks = subtasks;
+        ActivityRecord lastActivity = null;
+        while (j < NA) {
+            ActivityRecord ar = mHistory.get(j);
+            j++;
+            if (ar.finishing) {
+                continue;
+            }
+            if (ar.task.taskId != taskId) {
+                break;
+            }
+            lastActivity = ar;
+            if (ar.thumbHolder != holder && holder != null) {
+                thumbs.numSubThumbbails++;
+                holder = ar.thumbHolder;
+                TaskAccessInfo.SubTask sub = new TaskAccessInfo.SubTask();
+                sub.thumbnail = holder.lastThumbnail;
+                sub.activity = ar;
+                sub.index = j-1;
+                subtasks.add(sub);
+            }
+        }
+        if (lastActivity != null && subtasks.size() > 0) {
+            if (resumed == lastActivity) {
+                TaskAccessInfo.SubTask sub = subtasks.get(subtasks.size()-1);
+                sub.thumbnail = lastActivity.stack.screenshotActivities(lastActivity);
+            }
+        }
+        if (thumbs.numSubThumbbails > 0) {
+            thumbs.retriever = new IThumbnailRetriever.Stub() {
+                public Bitmap getThumbnail(int index) {
+                    if (index < 0 || index >= thumbs.subtasks.size()) {
+                        return null;
+                    }
+                    return thumbs.subtasks.get(index).thumbnail;
+                }
+            };
+        }
+        return thumbs;
+    }
+
     private final void logStartActivity(int tag, ActivityRecord r,
             TaskRecord task) {
         EventLog.writeEvent(tag,
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index 963a691..b4fdc9f 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -449,6 +449,7 @@
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         boolean isCheckin = false;
+        boolean noOutput = false;
         if (args != null) {
             for (String arg : args) {
                 if ("--checkin".equals(arg)) {
@@ -457,10 +458,22 @@
                     synchronized (mStats) {
                         mStats.resetAllStatsLocked();
                         pw.println("Battery stats reset.");
+                        noOutput = true;
                     }
+                } else if ("--write".equals(arg)) {
+                    synchronized (mStats) {
+                        mStats.writeSyncLocked();
+                        pw.println("Battery stats written.");
+                        noOutput = true;
+                    }
+                } else {
+                    pw.println("Unknown option: " + arg);
                 }
             }
         }
+        if (noOutput) {
+            return;
+        }
         if (isCheckin) {
             List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(0);
             synchronized (mStats) {
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 353ff6d..e39c239 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -65,6 +65,7 @@
     boolean foregroundServices; // Running any services that are foreground?
     boolean bad;                // True if disabled in the bad process list
     boolean killedBackground;   // True when proc has been killed due to too many bg
+    String waitingToKill;       // Process is waiting to be killed when in the bg; reason
     IBinder forcingToForeground;// Token that is forcing this process to be foreground
     int adjSeq;                 // Sequence id for identifying oom_adj assignment cycles
     int lruSeq;                 // Sequence id for identifying LRU update cycles
@@ -202,8 +203,9 @@
                 pw.print(" lastLowMemory=");
                 TimeUtils.formatDuration(lastLowMemory, now, pw);
                 pw.print(" reportLowMemory="); pw.println(reportLowMemory);
-        if (killedBackground) {
-            pw.print(prefix); pw.print("killedBackground="); pw.println(killedBackground);
+        if (killedBackground || waitingToKill != null) {
+            pw.print(prefix); pw.print("killedBackground="); pw.print(killedBackground);
+                    pw.print(" waitingToKill="); pw.println(waitingToKill);
         }
         if (debugging || crashing || crashDialog != null || notResponding
                 || anrDialog != null || bad) {
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 1a617dd..da00c0c 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -84,7 +84,6 @@
     boolean startRequested; // someone explicitly called start?
     boolean stopIfKilled;   // last onStart() said to stop if service killed?
     boolean callStart;      // last onStart() has asked to alway be called on restart.
-    int lastStartId;        // identifier of most recent start request.
     int executeNesting;     // number of outstanding operations keeping foreground.
     long executingStart;    // start time of last execute request.
     int crashCount;         // number of times proc has crashed with service running
@@ -96,8 +95,11 @@
 
     String stringName;      // caching of toString
     
+    private int lastStartId;    // identifier of most recent start request.
+
     static class StartItem {
         final ServiceRecord sr;
+        final boolean taskRemoved;
         final int id;
         final Intent intent;
         final int targetPermissionUid;
@@ -108,8 +110,10 @@
 
         String stringName;      // caching of toString
 
-        StartItem(ServiceRecord _sr, int _id, Intent _intent, int _targetPermissionUid) {
+        StartItem(ServiceRecord _sr, boolean _taskRemoved, int _id, Intent _intent,
+                int _targetPermissionUid) {
             sr = _sr;
+            taskRemoved = _taskRemoved;
             id = _id;
             intent = _intent;
             targetPermissionUid = _targetPermissionUid;
@@ -321,6 +325,18 @@
         return null;
     }
     
+    public int getLastStartId() {
+        return lastStartId;
+    }
+
+    public int makeNextStartId() {
+        lastStartId++;
+        if (lastStartId < 1) {
+            lastStartId = 1;
+        }
+        return lastStartId;
+    }
+
     public void postNotification() {
         final int appUid = appInfo.uid;
         final int appPid = app.pid;
diff --git a/services/java/com/android/server/am/TaskAccessInfo.java b/services/java/com/android/server/am/TaskAccessInfo.java
new file mode 100644
index 0000000..5618c1aa
--- /dev/null
+++ b/services/java/com/android/server/am/TaskAccessInfo.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import java.util.ArrayList;
+
+import android.app.ActivityManager.TaskThumbnails;
+import android.graphics.Bitmap;
+
+final class TaskAccessInfo extends TaskThumbnails {
+    final static class SubTask {
+        Bitmap thumbnail;
+        ActivityRecord activity;
+        int index;
+    }
+    
+    public ActivityRecord root;
+    public int rootIndex;
+    
+    public ArrayList<SubTask> subtasks;
+}
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 11dde75..16b55c3 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -1336,6 +1336,19 @@
         }
         mPendingPackages.clear();
 
+        /*
+         * Make sure all the updated system packages have their shared users
+         * associated with them.
+         */
+        final Iterator<PackageSetting> disabledIt = mDisabledSysPackages.values().iterator();
+        while (disabledIt.hasNext()) {
+            final PackageSetting disabledPs = disabledIt.next();
+            final Object id = getUserIdLPr(disabledPs.userId);
+            if (id != null && id instanceof SharedUserSetting) {
+                disabledPs.sharedUser = (SharedUserSetting) id;
+            }
+        }
+
         readStoppedLPw();
 
         mReadMessages.append("Read completed successfully: " + mPackages.size() + " packages, "
diff --git a/services/jni/com_android_server_AlarmManagerService.cpp b/services/jni/com_android_server_AlarmManagerService.cpp
index aa8c9b3..c9a702a 100644
--- a/services/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/jni/com_android_server_AlarmManagerService.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 2006, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
@@ -84,7 +84,7 @@
     struct timespec ts;
     ts.tv_sec = seconds;
     ts.tv_nsec = nanoseconds;
-    
+
 	int result = ioctl(fd, ANDROID_ALARM_SET(type), &ts);
 	if (result < 0)
 	{
@@ -97,18 +97,18 @@
 {
 #ifdef HAVE_ANDROID_OS
 	int result = 0;
-	
+
 	do
 	{
 		result = ioctl(fd, ANDROID_ALARM_WAIT);
 	} while (result < 0 && errno == EINTR);
-	
+
 	if (result < 0)
 	{
         LOGE("Unable to wait on alarm: %s\n", strerror(errno));
         return 0;
     }
-    
+
     return result;
 #endif
 }
@@ -124,14 +124,6 @@
 
 int register_android_server_AlarmManagerService(JNIEnv* env)
 {
-    jclass clazz = env->FindClass("com/android/server/AlarmManagerService");
-
-    if (clazz == NULL)
-	{
-        LOGE("Can't find com/android/server/AlarmManagerService");
-        return -1;
-    }
-
     return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService",
                                     sMethods, NELEM(sMethods));
 }
diff --git a/services/jni/com_android_server_UsbService.cpp b/services/jni/com_android_server_UsbService.cpp
index 00ee7e3..9cd04f6 100644
--- a/services/jni/com_android_server_UsbService.cpp
+++ b/services/jni/com_android_server_UsbService.cpp
@@ -37,13 +37,6 @@
 namespace android
 {
 
-static struct file_descriptor_offsets_t
-{
-    jclass mClass;
-    jmethodID mConstructor;
-    jfieldID mDescriptor;
-} gFileDescriptorOffsets;
-
 static struct parcel_file_descriptor_offsets_t
 {
     jclass mClass;
@@ -167,11 +160,8 @@
     int newFD = dup(fd);
     usb_device_close(device);
 
-    jobject fileDescriptor = env->NewObject(gFileDescriptorOffsets.mClass,
-        gFileDescriptorOffsets.mConstructor);
-    if (fileDescriptor != NULL) {
-        env->SetIntField(fileDescriptor, gFileDescriptorOffsets.mDescriptor, newFD);
-    } else {
+    jobject fileDescriptor = jniCreateFileDescriptor(env, newFD);
+    if (fileDescriptor == NULL) {
         return NULL;
     }
     return env->NewObject(gParcelFileDescriptorOffsets.mClass,
@@ -221,11 +211,8 @@
         LOGE("could not open %s", DRIVER_NAME);
         return NULL;
     }
-    jobject fileDescriptor = env->NewObject(gFileDescriptorOffsets.mClass,
-        gFileDescriptorOffsets.mConstructor);
-    if (fileDescriptor != NULL) {
-        env->SetIntField(fileDescriptor, gFileDescriptorOffsets.mDescriptor, fd);
-    } else {
+    jobject fileDescriptor = jniCreateFileDescriptor(env, fd);
+    if (fileDescriptor == NULL) {
         return NULL;
     }
     return env->NewObject(gParcelFileDescriptorOffsets.mClass,
@@ -260,14 +247,6 @@
         return -1;
     }
 
-    clazz = env->FindClass("java/io/FileDescriptor");
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
-    gFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
-    gFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V");
-    gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I");
-    LOG_FATAL_IF(gFileDescriptorOffsets.mDescriptor == NULL,
-                 "Unable to find descriptor field in java.io.FileDescriptor");
-
     clazz = env->FindClass("android/os/ParcelFileDescriptor");
     LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
     gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 24c31c7..8c2851a78 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -569,7 +569,9 @@
             if (defaultApnContext != null) {
                 if (defaultApnContext.getState() == State.FAILED) {
                     cleanUpConnection(false, defaultApnContext);
-                    defaultApnContext.getDataConnection().resetRetryCount();
+                    if (defaultApnContext.getDataConnection() != null) {
+                        defaultApnContext.getDataConnection().resetRetryCount();
+                    }
                 }
                 trySetupData(Phone.REASON_GPRS_ATTACHED, Phone.APN_TYPE_DEFAULT);
             }
diff --git a/tests/ActivityTests/AndroidManifest.xml b/tests/ActivityTests/AndroidManifest.xml
index 6fa27ed..de3b6d1 100644
--- a/tests/ActivityTests/AndroidManifest.xml
+++ b/tests/ActivityTests/AndroidManifest.xml
@@ -17,6 +17,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.google.android.test.activity">
     <uses-permission android:name="android.permission.GET_TASKS" />
+    <uses-permission android:name="android.permission.REORDER_TASKS" />
+    <uses-permission android:name="android.permission.REMOVE_TASKS" />
     <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
     <application android:label="ActivityTest">
         <activity android:name="ActivityTestMain">
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
index 8c5c35a..583c13c 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -23,6 +23,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.Application;
+import android.content.ActivityNotFoundException;
 import android.os.Bundle;
 import android.graphics.BitmapFactory;
 import android.graphics.Bitmap;
@@ -43,7 +44,11 @@
 import android.util.Log;
 
 public class ActivityTestMain extends Activity {
-    private void addThumbnail(LinearLayout container, Bitmap bm) {
+    ActivityManager mAm;
+
+    private void addThumbnail(LinearLayout container, Bitmap bm,
+            final ActivityManager.RecentTaskInfo task,
+            final ActivityManager.TaskThumbnails thumbs, final int subIndex) {
         ImageView iv = new ImageView(this);
         if (bm != null) {
             iv.setImageBitmap(bm);
@@ -52,24 +57,72 @@
         int w = getResources().getDimensionPixelSize(android.R.dimen.thumbnail_width);
         int h = getResources().getDimensionPixelSize(android.R.dimen.thumbnail_height);
         container.addView(iv, new LinearLayout.LayoutParams(w, h));
+
+        iv.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (task.id >= 0 && thumbs != null) {
+                    if (subIndex < (thumbs.numSubThumbbails-1)) {
+                        mAm.removeSubTask(task.id, subIndex+1);
+                    }
+                    mAm.moveTaskToFront(task.id, ActivityManager.MOVE_TASK_WITH_HOME);
+                } else {
+                    try {
+                        startActivity(task.baseIntent);
+                    } catch (ActivityNotFoundException e) {
+                        Log.w("foo", "Unable to start task: " + e);
+                    }
+                }
+                buildUi();
+            }
+        });
+        iv.setOnLongClickListener(new View.OnLongClickListener() {
+            @Override
+            public boolean onLongClick(View v) {
+                if (task.id >= 0 && thumbs != null) {
+                    if (subIndex < 0) {
+                        mAm.removeTask(task.id, ActivityManager.REMOVE_TASK_KILL_PROCESS);
+                    } else {
+                        mAm.removeSubTask(task.id, subIndex);
+                    }
+                    buildUi();
+                    return true;
+                }
+                return false;
+            }
+        });
     }
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        ActivityManager am = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
+        mAm = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
+    }
 
+    @Override
+    protected void onStart() {
+        super.onStart();
+        buildUi();
+    }
+
+    private View scrollWrap(View view) {
+        ScrollView scroller = new ScrollView(this);
+        scroller.addView(view, new ScrollView.LayoutParams(ScrollView.LayoutParams.MATCH_PARENT,
+                ScrollView.LayoutParams.MATCH_PARENT));
+        return scroller;
+    }
+
+    private void buildUi() {
         LinearLayout top = new LinearLayout(this);
         top.setOrientation(LinearLayout.VERTICAL);
 
-        List<ActivityManager.RecentTaskInfo> recents = am.getRecentTasks(10,
+        List<ActivityManager.RecentTaskInfo> recents = mAm.getRecentTasks(10,
                 ActivityManager.RECENT_WITH_EXCLUDED);
         if (recents != null) {
             for (int i=0; i<recents.size(); i++) {
                 ActivityManager.RecentTaskInfo r = recents.get(i);
-                ActivityManager.TaskThumbnails tt = r != null
-                        ? am.getTaskThumbnails(r.persistentId) : null;
+                ActivityManager.TaskThumbnails tt = mAm.getTaskThumbnails(r.persistentId);
                 TextView tv = new TextView(this);
                 tv.setText(r.baseIntent.getComponent().flattenToShortString());
                 top.addView(tv, new LinearLayout.LayoutParams(
@@ -77,9 +130,9 @@
                         LinearLayout.LayoutParams.WRAP_CONTENT));
                 LinearLayout item = new LinearLayout(this);
                 item.setOrientation(LinearLayout.HORIZONTAL);
-                addThumbnail(item, tt != null ? tt.mainThumbnail : null);
+                addThumbnail(item, tt != null ? tt.mainThumbnail : null, r, tt, -1);
                 for (int j=0; j<tt.numSubThumbbails; j++) {
-                    addThumbnail(item, tt.getSubThumbnail(j));
+                    addThumbnail(item, tt.getSubThumbnail(j), r, tt, j);
                 }
                 top.addView(item, new LinearLayout.LayoutParams(
                         LinearLayout.LayoutParams.WRAP_CONTENT,
@@ -89,11 +142,4 @@
 
         setContentView(scrollWrap(top));
     }
-
-    private View scrollWrap(View view) {
-        ScrollView scroller = new ScrollView(this);
-        scroller.addView(view, new ScrollView.LayoutParams(ScrollView.LayoutParams.MATCH_PARENT,
-                ScrollView.LayoutParams.MATCH_PARENT));
-        return scroller;
-    }
 }
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 15570e4..fa84e93 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -40,6 +40,7 @@
           mWantUTF16(false), mValues(false),
           mCompressionMethod(0), mOutputAPKFile(NULL),
           mManifestPackageNameOverride(NULL), mInstrumentationPackageNameOverride(NULL),
+          mIsOverlayPackage(false),
           mAutoAddOverlay(false), mAssetSourceDir(NULL), mProguardFile(NULL),
           mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
           mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL),
@@ -92,6 +93,8 @@
     void setManifestPackageNameOverride(const char * val) { mManifestPackageNameOverride = val; }
     const char* getInstrumentationPackageNameOverride() const { return mInstrumentationPackageNameOverride; }
     void setInstrumentationPackageNameOverride(const char * val) { mInstrumentationPackageNameOverride = val; }
+    bool getIsOverlayPackage() const { return mIsOverlayPackage; }
+    void setIsOverlayPackage(bool val) { mIsOverlayPackage = val; }
     bool getAutoAddOverlay() { return mAutoAddOverlay; }
     void setAutoAddOverlay(bool val) { mAutoAddOverlay = val; }
 
@@ -219,6 +222,7 @@
     const char* mOutputAPKFile;
     const char* mManifestPackageNameOverride;
     const char* mInstrumentationPackageNameOverride;
+    bool        mIsOverlayPackage;
     bool        mAutoAddOverlay;
     const char* mAssetSourceDir;
     const char* mProguardFile;
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 266a02f..1e63131 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -68,6 +68,7 @@
         "        [-S resource-sources [-S resource-sources ...]] "
         "        [-F apk-file] [-J R-file-dir] \\\n"
         "        [--product product1,product2,...] \\\n"
+        "        [-o] \\\n"
         "        [raw-files-dir [raw-files-dir] ...]\n"
         "\n"
         "   Package the android resources.  It will read assets and resources that are\n"
@@ -105,6 +106,7 @@
         "   -j  specify a jar or zip file containing classes to include\n"
         "   -k  junk path of file(s) added\n"
         "   -m  make package directories under location specified by -J\n"
+        "   -o  create overlay package (ie only resources; expects <overlay-package> in manifest)\n"
 #if 0
         "   -p  pseudolocalize the default configuration\n"
 #endif
@@ -275,6 +277,9 @@
             case 'm':
                 bundle.setMakePackageDirs(true);
                 break;
+            case 'o':
+                bundle.setIsOverlayPackage(true);
+                break;
 #if 0
             case 'p':
                 bundle.setPseudolocalize(true);
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 3dcc093..a88476e 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -3696,7 +3696,9 @@
 {
     sp<Package> p = mPackages.valueFor(package);
     if (p == NULL) {
-        if (mIsAppPackage) {
+        if (mBundle->getIsOverlayPackage()) {
+            p = new Package(package, 0x00);
+        } else if (mIsAppPackage) {
             if (mHaveAppPackage) {
                 fprintf(stderr, "Adding multiple application package resources; only one is allowed.\n"
                                 "Use -x to create extended resources.\n");