Merge "Revert "Add new MotionEvent actions for button press and release."" into mnc-dev
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 515d761..4100fa3 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -137,6 +137,9 @@
         { REQ,      "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable" },
         { REQ,      "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable" },
     } },
+    { "regulators",  "Voltage and Current Regulators", 0, {
+        { REQ,      "/sys/kernel/debug/tracing/events/regulator/enable" },
+    } },
 };
 
 /* Command line options */
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 969677f..1be6232 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -193,6 +193,30 @@
 /*****************************************************************************/
 
 /*
+ * Get a reference to the sensor manager. ASensorManager is a singleton
+ * per package as different packages may have access to different sensors.
+ *
+ * Deprecated: Use ASensorManager_getInstanceForPackage(const char*) instead.
+ *
+ * Example:
+ *
+ *     ASensorManager* sensorManager = ASensorManager_getInstance();
+ *
+ */
+__attribute__ ((deprecated)) ASensorManager* ASensorManager_getInstance();
+
+/*
+ * Get a reference to the sensor manager. ASensorManager is a singleton
+ * per package as different packages may have access to different sensors.
+ *
+ * Example:
+ *
+ *    ASensorManager* sensorManager = ASensorManager_getInstanceForPackage("foo.bar.baz");
+ *
+ */
+ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName);
+
+/*
  * Returns the list of available sensors.
  */
 int ASensorManager_getSensorList(ASensorManager* manager, ASensorList* list);
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 721b218..09300a2 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -62,9 +62,10 @@
     public:
         ProxyConsumerListener(const wp<ConsumerListener>& consumerListener);
         virtual ~ProxyConsumerListener();
-        virtual void onFrameAvailable(const BufferItem& item);
-        virtual void onBuffersReleased();
-        virtual void onSidebandStreamChanged();
+        virtual void onFrameAvailable(const BufferItem& item) override;
+        virtual void onFrameReplaced(const BufferItem& item) override;
+        virtual void onBuffersReleased() override;
+        virtual void onSidebandStreamChanged() override;
     private:
         // mConsumerListener is a weak reference to the IConsumerListener.  This is
         // the raison d'etre of ProxyConsumerListener.
diff --git a/include/gui/BufferQueueConsumer.h b/include/gui/BufferQueueConsumer.h
index 0f42613..cde302f 100644
--- a/include/gui/BufferQueueConsumer.h
+++ b/include/gui/BufferQueueConsumer.h
@@ -47,7 +47,7 @@
     // returned.  The presentation time is in nanoseconds, and the time base
     // is CLOCK_MONOTONIC.
     virtual status_t acquireBuffer(BufferItem* outBuffer,
-            nsecs_t expectedPresent);
+            nsecs_t expectedPresent, uint64_t maxFrameNumber = 0) override;
 
     // See IGraphicBufferConsumer::detachBuffer
     virtual status_t detachBuffer(int slot);
@@ -148,9 +148,6 @@
     // Retrieve the sideband buffer stream, if any.
     virtual sp<NativeHandle> getSidebandStream() const;
 
-    // See IGraphicBufferConsumer::setShadowQueueSize
-    virtual void setShadowQueueSize(size_t size);
-
     // dump our state in a String
     virtual void dump(String8& result, const char* prefix) const;
 
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index a22015c..d7686ec 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -275,12 +275,6 @@
     // buffer as the number of frames that have elapsed since it was last queued
     uint64_t mBufferAge;
 
-    // mConsumerHasShadowQueue determines if acquireBuffer should be more
-    // cautious about dropping buffers so that it always returns a buffer that
-    // is represented in the consumer's shadow queue.
-    bool mConsumerHasShadowQueue;
-    size_t mConsumerShadowQueueSize;
-
 }; // class BufferQueueCore
 
 } // namespace android
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
index d56fa89..f46bf01 100644
--- a/include/gui/ConsumerBase.h
+++ b/include/gui/ConsumerBase.h
@@ -38,15 +38,9 @@
         protected ConsumerListener {
 public:
     struct FrameAvailableListener : public virtual RefBase {
-        // onFrameAvailable() is called each time an additional frame becomes
-        // available for consumption. This means that frames that are queued
-        // while in asynchronous mode only trigger the callback if no previous
-        // frames are pending. Frames queued while in synchronous mode always
-        // trigger the callback.
-        //
-        // This is called without any lock held and can be called concurrently
-        // by multiple threads.
+        // See IConsumerListener::onFrame{Available,Replaced}
         virtual void onFrameAvailable(const BufferItem& item) = 0;
+        virtual void onFrameReplaced(const BufferItem& /* item */) {}
     };
 
     virtual ~ConsumerBase();
@@ -104,14 +98,16 @@
 
     // Implementation of the IConsumerListener interface.  These
     // calls are used to notify the ConsumerBase of asynchronous events in the
-    // BufferQueue.  The onFrameAvailable and onBuffersReleased methods should
-    // not need to be overridden by derived classes, but if they are overridden
-    // the ConsumerBase implementation must be called from the derived class.
-    // The ConsumerBase version of onSidebandStreamChanged does nothing and can
-    // be overriden by derived classes if they want the notification.
-    virtual void onFrameAvailable(const BufferItem& item);
-    virtual void onBuffersReleased();
-    virtual void onSidebandStreamChanged();
+    // BufferQueue.  The onFrameAvailable, onFrameReplaced, and
+    // onBuffersReleased methods should not need to be overridden by derived
+    // classes, but if they are overridden the ConsumerBase implementation must
+    // be called from the derived class. The ConsumerBase version of
+    // onSidebandStreamChanged does nothing and can be overriden by derived
+    // classes if they want the notification.
+    virtual void onFrameAvailable(const BufferItem& item) override;
+    virtual void onFrameReplaced(const BufferItem& item) override;
+    virtual void onBuffersReleased() override;
+    virtual void onSidebandStreamChanged() override;
 
     // freeBufferLocked frees up the given buffer slot.  If the slot has been
     // initialized this will release the reference to the GraphicBuffer in that
@@ -156,7 +152,8 @@
     // initialization that must take place the first time a buffer is assigned
     // to a slot.  If it is overridden the derived class's implementation must
     // call ConsumerBase::acquireBufferLocked.
-    virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen);
+    virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen,
+            uint64_t maxFrameNumber = 0);
 
     // releaseBufferLocked relinquishes control over a buffer, returning that
     // control to the BufferQueue.
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index 4912580..c35c7be 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -241,7 +241,8 @@
 
     // acquireBufferLocked overrides the ConsumerBase method to update the
     // mEglSlots array in addition to the ConsumerBase behavior.
-    virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen);
+    virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen,
+            uint64_t maxFrameNumber = 0) override;
 
     // releaseBufferLocked overrides the ConsumerBase method to update the
     // mEglSlots array in addition to the ConsumerBase.
diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h
index 0be09a2..6363a3a 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/include/gui/IGraphicBufferConsumer.h
@@ -69,6 +69,12 @@
     // returned.  The presentation time is in nanoseconds, and the time base
     // is CLOCK_MONOTONIC.
     //
+    // If maxFrameNumber is non-zero, it indicates that acquireBuffer should
+    // only return a buffer with a frame number less than or equal to
+    // maxFrameNumber. If no such frame is available (such as when a buffer has
+    // been replaced but the consumer has not received the onFrameReplaced
+    // callback), then PRESENT_LATER will be returned.
+    //
     // Return of NO_ERROR means the operation completed as normal.
     //
     // Return of a positive value means the operation could not be completed
@@ -78,7 +84,8 @@
     //
     // Return of a negative value means an error has occurred:
     // * INVALID_OPERATION - too many buffers have been acquired
-    virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen) = 0;
+    virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen,
+            uint64_t maxFrameNumber = 0) = 0;
 
     // detachBuffer attempts to remove all ownership of the buffer in the given
     // slot from the buffer queue. If this call succeeds, the slot will be
@@ -248,11 +255,6 @@
     // Retrieve the sideband buffer stream, if any.
     virtual sp<NativeHandle> getSidebandStream() const = 0;
 
-    // setShadowQueueSize notifies the BufferQueue that the consumer is
-    // shadowing its queue and allows it to limit the number of buffers it is
-    // permitted to drop during acquire so as to not get out of sync.
-    virtual void setShadowQueueSize(size_t size) = 0;
-
     // dump state into a string
     virtual void dump(String8& result, const char* prefix) const = 0;
 
diff --git a/include/gui/SensorManager.h b/include/gui/SensorManager.h
index d0c63d4..4c34e12 100644
--- a/include/gui/SensorManager.h
+++ b/include/gui/SensorManager.h
@@ -17,10 +17,14 @@
 #ifndef ANDROID_GUI_SENSOR_MANAGER_H
 #define ANDROID_GUI_SENSOR_MANAGER_H
 
+#include <map>
+
 #include <stdint.h>
 #include <sys/types.h>
 
 #include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
 
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
@@ -47,6 +51,56 @@
     public ASensorManager
 {
 public:
+    static SensorManager& getInstanceForPackage(const String16& packageName) {
+        Mutex::Autolock _l(sLock);
+
+        SensorManager* sensorManager;
+        std::map<String16, SensorManager*>::iterator iterator =
+                sPackageInstances.find(packageName);
+
+        if (iterator != sPackageInstances.end()) {
+            sensorManager = iterator->second;
+        } else {
+            String16 opPackageName = packageName;
+
+            // It is possible that the calling code has no access to the package name.
+            // In this case we will get the packages for the calling UID and pick the
+            // first one for attributing the app op. This will work correctly for
+            // runtime permissions as for legacy apps we will toggle the app op for
+            // all packages in the UID. The caveat is that the operation may be attributed
+            // to the wrong package and stats based on app ops may be slightly off.
+            if (opPackageName.size() <= 0) {
+                sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
+                if (binder != 0) {
+                    const uid_t uid = IPCThreadState::self()->getCallingUid();
+                    Vector<String16> packages;
+                    interface_cast<IPermissionController>(binder)->getPackagesForUid(uid, packages);
+                    if (!packages.isEmpty()) {
+                        opPackageName = packages[0];
+                    } else {
+                        ALOGE("No packages for calling UID");
+                    }
+                } else {
+                    ALOGE("Cannot get permission service");
+                }
+            }
+
+            sensorManager = new SensorManager(opPackageName);
+
+            // If we had no package name, we looked it up from the UID and the sensor
+            // manager instance we created should also be mapped to the empty package
+            // name, to avoid looking up the packages for a UID and get the same result.
+            if (packageName.size() <= 0) {
+                sPackageInstances.insert(std::make_pair(String16(), sensorManager));
+            }
+
+            // Stash the per package sensor manager.
+            sPackageInstances.insert(std::make_pair(opPackageName, sensorManager));
+        }
+
+        return *sensorManager;
+    }
+
     SensorManager(const String16& opPackageName);
     ~SensorManager();
 
@@ -62,6 +116,9 @@
     status_t assertStateLocked() const;
 
 private:
+    static Mutex sLock;
+    static std::map<String16, SensorManager*> sPackageInstances;
+
     mutable Mutex mLock;
     mutable sp<ISensorServer> mSensorServer;
     mutable Sensor const** mSensorList;
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 1b197a4..015866b 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -1347,6 +1347,10 @@
     if (err != NO_ERROR) return 0;
 
     native_handle* h = native_handle_create(numFds, numInts);
+    if (!h) {
+        return 0;
+    }
+
     for (int i=0 ; err==NO_ERROR && i<numFds ; i++) {
         h->data[i] = dup(readFileDescriptor());
         if (h->data[i] < 0) err = BAD_VALUE;
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 2fcbaf2..ccbb5a2 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -39,6 +39,14 @@
     }
 }
 
+void BufferQueue::ProxyConsumerListener::onFrameReplaced(
+        const BufferItem& item) {
+    sp<ConsumerListener> listener(mConsumerListener.promote());
+    if (listener != NULL) {
+        listener->onFrameReplaced(item);
+    }
+}
+
 void BufferQueue::ProxyConsumerListener::onBuffersReleased() {
     sp<ConsumerListener> listener(mConsumerListener.promote());
     if (listener != NULL) {
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 336ddb6..4174676 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -36,7 +36,7 @@
 BufferQueueConsumer::~BufferQueueConsumer() {}
 
 status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
-        nsecs_t expectedPresent) {
+        nsecs_t expectedPresent, uint64_t maxFrameNumber) {
     ATRACE_CALL();
     Mutex::Autolock lock(mCore->mMutex);
 
@@ -89,17 +89,12 @@
         // the timestamps are being auto-generated by Surface. If the app isn't
         // generating timestamps explicitly, it probably doesn't want frames to
         // be discarded based on them.
-        //
-        // If the consumer is shadowing our queue, we also make sure that we
-        // don't drop so many buffers that the consumer hasn't received the
-        // onFrameAvailable callback for the buffer it acquires. That is, we
-        // want the buffer we return to be in the consumer's shadow queue.
-        size_t droppableBuffers = mCore->mConsumerShadowQueueSize > 1 ?
-                mCore->mConsumerShadowQueueSize - 1 : 0;
         while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
-            if (mCore->mConsumerHasShadowQueue && droppableBuffers == 0) {
-                BQ_LOGV("acquireBuffer: no droppable buffers in consumer's"
-                        " shadow queue, continuing");
+            const BufferItem& bufferItem(mCore->mQueue[1]);
+
+            // If dropping entry[0] would leave us with a buffer that the
+            // consumer is not yet ready for, don't drop it.
+            if (maxFrameNumber && bufferItem.mFrameNumber > maxFrameNumber) {
                 break;
             }
 
@@ -112,7 +107,6 @@
             //
             // We may want to add an additional criterion: don't drop the
             // earlier buffer if entry[1]'s fence hasn't signaled yet.
-            const BufferItem& bufferItem(mCore->mQueue[1]);
             nsecs_t desiredPresent = bufferItem.mTimestamp;
             if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
                     desiredPresent > expectedPresent) {
@@ -137,18 +131,22 @@
             }
             mCore->mQueue.erase(front);
             front = mCore->mQueue.begin();
-            --droppableBuffers;
         }
 
-        // See if the front buffer is due
+        // See if the front buffer is ready to be acquired
         nsecs_t desiredPresent = front->mTimestamp;
-        if (desiredPresent > expectedPresent &&
-                desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) {
+        bool bufferIsDue = desiredPresent <= expectedPresent ||
+                desiredPresent > expectedPresent + MAX_REASONABLE_NSEC;
+        bool consumerIsReady = maxFrameNumber > 0 ?
+                front->mFrameNumber <= maxFrameNumber : true;
+        if (!bufferIsDue || !consumerIsReady) {
             BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64
-                    " (%" PRId64 ") now=%" PRId64,
+                    " (%" PRId64 ") now=%" PRId64 " frame=%" PRIu64
+                    " consumer=%" PRIu64,
                     desiredPresent, expectedPresent,
                     desiredPresent - expectedPresent,
-                    systemTime(CLOCK_MONOTONIC));
+                    systemTime(CLOCK_MONOTONIC),
+                    front->mFrameNumber, maxFrameNumber);
             return PRESENT_LATER;
         }
 
@@ -553,14 +551,6 @@
     return mCore->mSidebandStream;
 }
 
-void BufferQueueConsumer::setShadowQueueSize(size_t size) {
-    ATRACE_CALL();
-    BQ_LOGV("setShadowQueueSize: %zu", size);
-    Mutex::Autolock lock(mCore->mMutex);
-    mCore->mConsumerHasShadowQueue = true;
-    mCore->mConsumerShadowQueueSize = size;
-}
-
 void BufferQueueConsumer::dump(String8& result, const char* prefix) const {
     mCore->dump(result, prefix);
 }
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 37171ed..e784644 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -71,9 +71,7 @@
     mIsAllocating(false),
     mIsAllocatingCondition(),
     mAllowAllocation(true),
-    mBufferAge(0),
-    mConsumerHasShadowQueue(false),
-    mConsumerShadowQueueSize(0)
+    mBufferAge(0)
 {
     if (allocator == NULL) {
         sp<ISurfaceComposer> composer(ComposerService::getComposerService());
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 7251d36..e318484 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -871,6 +871,7 @@
     mCore->mBufferHasBeenQueued = false;
     mCore->mDequeueBufferCannotBlock =
             mCore->mConsumerControlledByApp && producerControlledByApp;
+    mCore->mAllowAllocation = true;
 
     return status;
 }
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index e576018..072ab44 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -114,6 +114,21 @@
     }
 }
 
+void ConsumerBase::onFrameReplaced(const BufferItem &item) {
+    CB_LOGV("onFrameReplaced");
+
+    sp<FrameAvailableListener> listener;
+    {
+        Mutex::Autolock lock(mMutex);
+        listener = mFrameAvailableListener.promote();
+    }
+
+    if (listener != NULL) {
+        CB_LOGV("actually calling onFrameReplaced");
+        listener->onFrameReplaced(item);
+    }
+}
+
 void ConsumerBase::onBuffersReleased() {
     Mutex::Autolock lock(mMutex);
 
@@ -196,8 +211,8 @@
 }
 
 status_t ConsumerBase::acquireBufferLocked(BufferItem *item,
-        nsecs_t presentWhen) {
-    status_t err = mConsumer->acquireBuffer(item, presentWhen);
+        nsecs_t presentWhen, uint64_t maxFrameNumber) {
+    status_t err = mConsumer->acquireBuffer(item, presentWhen, maxFrameNumber);
     if (err != NO_ERROR) {
         return err;
     }
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 96c0841..9fcac2d 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -344,8 +344,9 @@
 }
 
 status_t GLConsumer::acquireBufferLocked(BufferItem *item,
-        nsecs_t presentWhen) {
-    status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen);
+        nsecs_t presentWhen, uint64_t maxFrameNumber) {
+    status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen,
+            maxFrameNumber);
     if (err != NO_ERROR) {
         return err;
     }
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index 480dfb6..b86f4c5 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -52,7 +52,6 @@
     SET_CONSUMER_USAGE_BITS,
     SET_TRANSFORM_HINT,
     GET_SIDEBAND_STREAM,
-    SET_SHADOW_QUEUE_SIZE,
     DUMP,
 };
 
@@ -67,10 +66,12 @@
 
     virtual ~BpGraphicBufferConsumer();
 
-    virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) {
+    virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen,
+            uint64_t maxFrameNumber) {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
         data.writeInt64(presentWhen);
+        data.writeUint64(maxFrameNumber);
         status_t result = remote()->transact(ACQUIRE_BUFFER, data, &reply);
         if (result != NO_ERROR) {
             return result;
@@ -270,17 +271,6 @@
         return stream;
     }
 
-    virtual void setShadowQueueSize(size_t size) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        data.writeInt64(static_cast<int64_t>(size));
-        status_t result = remote()->transact(SET_SHADOW_QUEUE_SIZE, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("setShadowQueueSize failed (%d)", result);
-            return;
-        }
-    }
-
     virtual void dump(String8& result, const char* prefix) const {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
@@ -307,7 +297,8 @@
             CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
             BufferItem item;
             int64_t presentWhen = data.readInt64();
-            status_t result = acquireBuffer(&item, presentWhen);
+            uint64_t maxFrameNumber = data.readUint64();
+            status_t result = acquireBuffer(&item, presentWhen, maxFrameNumber);
             status_t err = reply->write(item);
             if (err) return err;
             reply->writeInt32(result);
@@ -435,12 +426,6 @@
             }
             return NO_ERROR;
         }
-        case SET_SHADOW_QUEUE_SIZE: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            size_t size = static_cast<size_t>(data.readInt64());
-            setShadowQueueSize(size);
-            return NO_ERROR;
-        }
         case DUMP: {
             CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
             String8 result = data.readString8();
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 25f7607..b2abdb1 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -444,6 +444,11 @@
 #define EGL_OPENGL_ES3_BIT_KHR				    0x00000040
 #endif
 
+#ifndef EGL_KHR_create_context_no_error
+#define EGL_KHR_create_context_no_error 1
+#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR   0x31B3
+#endif /* EGL_KHR_create_context_no_error */
+
 #ifndef EGL_KHR_surfaceless_context
 #define EGL_KHR_surfaceless_context 1
 /* No tokens/entry points, just relaxes an error condition */
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 4da9f92..18ad300 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -86,6 +86,9 @@
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 LOCAL_CFLAGS += -fvisibility=hidden
 
+# TODO: This is to work around b/20093774. Remove after root cause is fixed
+LOCAL_LDFLAGS_arm += -Wl,--hash-style,both
+
 include $(BUILD_SHARED_LIBRARY)
 
 
@@ -111,6 +114,9 @@
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 LOCAL_CFLAGS += -fvisibility=hidden
 
+# TODO: This is to work around b/20093774. Remove after root cause is fixed
+LOCAL_LDFLAGS_arm += -Wl,--hash-style,both
+
 # Symlink libGLESv3.so -> libGLESv2.so
 # Platform modules should link against libGLESv2.so (-lGLESv2), but NDK apps
 # will be linked against libGLESv3.so.
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index f5b90dd..5444631 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -103,6 +103,7 @@
         "EGL_ANDROID_recordable "               // mandatory
         "EGL_KHR_partial_update "               // strongly recommended
         "EGL_EXT_buffer_age "                   // strongly recommended with partial_update
+        "EGL_KHR_create_context_no_error "
         ;
 
 // extensions not exposed to applications but used by the ANDROID system
diff --git a/opengl/tools/glgen/src/JType.java b/opengl/tools/glgen/src/JType.java
index c6e227e..5803a44 100644
--- a/opengl/tools/glgen/src/JType.java
+++ b/opengl/tools/glgen/src/JType.java
@@ -191,6 +191,84 @@
         (baseType.indexOf("Buffer") != -1);
     }
 
+    public JType getArrayTypeForTypedBuffer() {
+      if (!isTypedBuffer()) {
+          throw new RuntimeException("Not typed buffer type " + this);
+      }
+      switch (baseType) {
+        case "java.nio.ByteBuffer":
+          return new JType("byte", false, true);
+        case "java.nio.BooleanBuffer":
+          return new JType("boolean", false, true);
+        case "java.nio.ShortBuffer":
+          return new JType("short", false, true);
+        case "java.nio.CharBuffer":
+          return new JType("char", false, true);
+        case "java.nio.IntBuffer":
+          return new JType("int", false, true);
+        case "java.nio.LongBuffer":
+          return new JType("long", false, true);
+        case "java.nio.FloatBuffer":
+          return new JType("float", false, true);
+        case "java.nio.DoubleBuffer":
+          return new JType("double", false, true);
+        default:
+          throw new RuntimeException("Unknown typed buffer type " + this);
+      }
+    }
+
+    public String getArrayGetterForPrimitiveArray() {
+      if (!isArray() || isClass()) {
+          throw new RuntimeException("Not array type " + this);
+      }
+      switch (baseType) {
+        case "byte":
+          return "GetByteArrayElements";
+        case "boolean":
+          return "GetBooleanArrayElements";
+        case "short":
+          return "GetShortArrayElements";
+        case "char":
+          return "GetCharArrayElements";
+        case "int":
+          return "GetIntArrayElements";
+        case "long":
+          return "GetLongArrayElements";
+        case "float":
+          return "GetFloatArrayElements";
+        case "double":
+          return "GetDoubleArrayElements";
+        default:
+          throw new RuntimeException("Unknown array type " + this);
+      }
+    }
+
+    public String getArrayReleaserForPrimitiveArray() {
+      if (!isArray() || isClass()) {
+          throw new RuntimeException("Not array type " + this);
+      }
+      switch (baseType) {
+        case "byte":
+          return "ReleaseByteArrayElements";
+        case "boolean":
+          return "ReleaseBooleanArrayElements";
+        case "short":
+          return "ReleaseShortArrayElements";
+        case "char":
+          return "ReleaseCharArrayElements";
+        case "int":
+          return "ReleaseIntArrayElements";
+        case "long":
+          return "ReleaseLongArrayElements";
+        case "float":
+          return "ReleaseFloatArrayElements";
+        case "double":
+          return "ReleaseDoubleArrayElements";
+        default:
+          throw new RuntimeException("Unknown array type " + this);
+      }
+    }
+
     public boolean isEGLHandle() {
     return !isPrimitive() &&
         (baseType.startsWith("EGL"));
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index e51b7a2..1bed05b 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -812,6 +812,7 @@
         List<Integer> stringArgs = new ArrayList<Integer>();
         int numBufferArgs = 0;
         List<String> bufferArgNames = new ArrayList<String>();
+        List<JType> bufferArgTypes = new ArrayList<JType>();
 
         // Emit JNI signature (arguments)
         //
@@ -835,6 +836,7 @@
                     int cIndex = jfunc.getArgCIndex(i);
                     String cname = cfunc.getArgName(cIndex);
                     bufferArgNames.add(cname);
+                    bufferArgTypes.add(jfunc.getArgType(i));
                     numBufferArgs++;
                 }
             }
@@ -948,12 +950,25 @@
 
         // Emit a single _array or multiple _XXXArray variables
         if (numBufferArgs == 1) {
+            JType bufferType = bufferArgTypes.get(0);
+            if (bufferType.isTypedBuffer()) {
+                String typedArrayType = getJniType(bufferType.getArrayTypeForTypedBuffer());
+                out.println(indent + typedArrayType + " _array = (" + typedArrayType + ") 0;");
+            } else {
                 out.println(indent + "jarray _array = (jarray) 0;");
-                out.println(indent + "jint _bufferOffset = (jint) 0;");
+            }
+            out.println(indent + "jint _bufferOffset = (jint) 0;");
         } else {
             for (int i = 0; i < numBufferArgs; i++) {
-                out.println(indent + "jarray _" + bufferArgNames.get(i) +
-                            "Array = (jarray) 0;");
+                JType bufferType = bufferArgTypes.get(0);
+                if (bufferType.isTypedBuffer()) {
+                    String typedArrayType = getJniType(bufferType.getArrayTypeForTypedBuffer());
+                    out.println(indent + typedArrayType + " _" + bufferArgNames.get(i) +
+                                "Array = (" + typedArrayType + ") 0;");
+                } else {
+                    out.println(indent + "jarray _" + bufferArgNames.get(i) +
+                                "Array = (jarray) 0;");
+                }
                 out.println(indent + "jint _" + bufferArgNames.get(i) +
                             "BufferOffset = (jint) 0;");
             }
@@ -1135,9 +1150,10 @@
                                 "_base = (" +
                                 cfunc.getArgType(cIndex).getDeclaration() +
                                 ")");
+                    String arrayGetter = jfunc.getArgType(idx).getArrayGetterForPrimitiveArray();
                     out.println(indent + "    " +
                                 (mUseCPlusPlus ? "_env" : "(*_env)") +
-                                "->GetPrimitiveArrayCritical(" +
+                                "->" + arrayGetter + "(" +
                                 (mUseCPlusPlus ? "" : "_env, ") +
                                 jfunc.getArgName(idx) +
                                 "_ref, (jboolean *)0);");
@@ -1209,7 +1225,7 @@
                                     cfunc.getArgType(cIndex).getDeclaration() +
                                     ")getPointer(_env, " +
                                     cname +
-                                    "_buf, &" + array + ", &" + remaining + ", &" + bufferOffset +
+                                    "_buf, (jarray*)&" + array + ", &" + remaining + ", &" + bufferOffset +
                                     ");");
                     }
 
@@ -1244,9 +1260,17 @@
                 } else {
                     out.println(indent + "if (" + cname +" == NULL) {");
                 }
-                out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);");
-                out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");");
-                out.println(indent + "}");
+                JType argType = jfunc.getArgType(idx);
+                if (argType.isTypedBuffer()) {
+                    String arrayGetter = argType.getArrayTypeForTypedBuffer().getArrayGetterForPrimitiveArray();
+                    out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->" + arrayGetter + "(" + array + ", (jboolean *) 0);");
+                    out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");");
+                    out.println(indent + "}");
+                } else {
+                    out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);");
+                    out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");");
+                    out.println(indent + "}");
+                }
              }
         }
 
@@ -1336,12 +1360,13 @@
                     // the need to write back to the Java array
                     out.println(indent +
                                 "if (" + jfunc.getArgName(idx) + "_base) {");
+                    String arrayReleaser = jfunc.getArgType(idx).getArrayReleaserForPrimitiveArray();
                     out.println(indent + indent +
                                 (mUseCPlusPlus ? "_env" : "(*_env)") +
-                                "->ReleasePrimitiveArrayCritical(" +
+                                "->" + arrayReleaser + "(" +
                                 (mUseCPlusPlus ? "" : "_env, ") +
                                 jfunc.getArgName(idx) + "_ref, " +
-                                cfunc.getArgName(cIndex) +
+                                "(j" + jfunc.getArgType(idx).getBaseType() + "*)" + cfunc.getArgName(cIndex) +
                                 "_base,");
                     out.println(indent + indent + indent +
                                 (cfunc.getArgType(cIndex).isConst() ?
@@ -1350,17 +1375,32 @@
                     out.println(indent + "}");
                 } else if (jfunc.getArgType(idx).isBuffer()) {
                     if (! isPointerFunc) {
+                        JType argType = jfunc.getArgType(idx);
                         String array = numBufferArgs <= 1 ? "_array" :
                             "_" + cfunc.getArgName(cIndex) + "Array";
                         out.println(indent + "if (" + array + ") {");
-                        out.println(indent + indent +
-                                    "releasePointer(_env, " + array + ", " +
-                                    cfunc.getArgName(cIndex) +
-                                    ", " +
-                                    (cfunc.getArgType(cIndex).isConst() ?
-                                     "JNI_FALSE" : (emitExceptionCheck ?
-                                     "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) +
-                                    ");");
+                        if (argType.isTypedBuffer()) {
+                            String arrayReleaser =
+                                argType.getArrayTypeForTypedBuffer().getArrayReleaserForPrimitiveArray();
+                            out.println(indent + indent +
+                                "_env->" + arrayReleaser + "(" + array + ", " +
+                                "(j" + argType.getArrayTypeForTypedBuffer().getBaseType() + "*)" +
+                                cfunc.getArgName(cIndex) +
+                                ", " +
+                                (cfunc.getArgType(cIndex).isConst() ?
+                                    "JNI_ABORT" : (emitExceptionCheck ?
+                                        "_exception ? JNI_ABORT : 0" : "0")) +
+                                ");");
+                        } else {
+                            out.println(indent + indent +
+                                "releasePointer(_env, " + array + ", " +
+                                cfunc.getArgName(cIndex) +
+                                ", " +
+                                (cfunc.getArgType(cIndex).isConst() ?
+                                    "JNI_FALSE" : (emitExceptionCheck ?
+                                        "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) +
+                                ");");
+                        }
                         out.println(indent + "}");
                     }
                 }
diff --git a/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp b/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp
index f09c171..6199637 100755
--- a/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp
@@ -27,7 +27,7 @@
     }
     _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
     attrib_list_base = (EGLint *)
-        _env->GetPrimitiveArrayCritical(attrib_list_ref, (jboolean *)0);
+        _env->GetIntArrayElements(attrib_list_ref, (jboolean *)0);
     attrib_list = attrib_list_base + offset;
     attrib_list_sentinel = false;
     for (int i = _remaining - 1; i >= 0; i--)  {
@@ -53,7 +53,7 @@
 
 exit:
     if (attrib_list_base) {
-        _env->ReleasePrimitiveArrayCritical(attrib_list_ref, attrib_list_base,
+        _env->ReleaseIntArrayElements(attrib_list_ref, attrib_list_base,
             JNI_ABORT);
     }
     if (_exception) {
@@ -71,4 +71,3 @@
     }
     return android_eglCreatePbufferFromClientBuffer(_env, _this, dpy, buftype, buffer, config, attrib_list_ref, offset);
 }
-
diff --git a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
index 0b6bf58..cc7b85d 100644
--- a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
@@ -41,7 +41,7 @@
 
     _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
     attrib_list_base = (EGLint *)
-        _env->GetPrimitiveArrayCritical(attrib_list_ref, (jboolean *)0);
+        _env->GetIntArrayElements(attrib_list_ref, (jboolean *)0);
     attrib_list = attrib_list_base + offset;
     attrib_list_sentinel = 0;
     for (int i = _remaining - 1; i >= 0; i--)  {
@@ -66,7 +66,7 @@
 
 exit:
     if (attrib_list_base) {
-        _env->ReleasePrimitiveArrayCritical(attrib_list_ref, attrib_list_base,
+        _env->ReleaseIntArrayElements(attrib_list_ref, attrib_list_base,
             JNI_ABORT);
     }
     if (_exception) {
@@ -123,7 +123,7 @@
 
     _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
     attrib_list_base = (EGLint *)
-        _env->GetPrimitiveArrayCritical(attrib_list_ref, (jboolean *)0);
+        _env->GetIntArrayElements(attrib_list_ref, (jboolean *)0);
     attrib_list = attrib_list_base + offset;
     attrib_list_sentinel = 0;
     for (int i = _remaining - 1; i >= 0; i--)  {
@@ -148,7 +148,7 @@
 
 exit:
     if (attrib_list_base) {
-        _env->ReleasePrimitiveArrayCritical(attrib_list_ref, attrib_list_base,
+        _env->ReleaseIntArrayElements(attrib_list_ref, attrib_list_base,
             JNI_ABORT);
     }
     if (_exception) {
diff --git a/opengl/tools/glgen/stubs/gles11/common.cpp b/opengl/tools/glgen/stubs/gles11/common.cpp
index f7bcb9d..18ec5e3 100644
--- a/opengl/tools/glgen/stubs/gles11/common.cpp
+++ b/opengl/tools/glgen/stubs/gles11/common.cpp
@@ -100,6 +100,116 @@
     return NULL;
 }
 
+class ByteArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jbyteArray array, jboolean* is_copy) {
+        return _env->GetByteArrayElements(array, is_copy);
+    }
+};
+class BooleanArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jbooleanArray array, jboolean* is_copy) {
+        return _env->GetBooleanArrayElements(array, is_copy);
+    }
+};
+class CharArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jcharArray array, jboolean* is_copy) {
+        return _env->GetCharArrayElements(array, is_copy);
+    }
+};
+class ShortArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jshortArray array, jboolean* is_copy) {
+        return _env->GetShortArrayElements(array, is_copy);
+    }
+};
+class IntArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jintArray array, jboolean* is_copy) {
+        return _env->GetIntArrayElements(array, is_copy);
+    }
+};
+class LongArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jlongArray array, jboolean* is_copy) {
+        return _env->GetLongArrayElements(array, is_copy);
+    }
+};
+class FloatArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jfloatArray array, jboolean* is_copy) {
+        return _env->GetFloatArrayElements(array, is_copy);
+    }
+};
+class DoubleArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jdoubleArray array, jboolean* is_copy) {
+        return _env->GetDoubleArrayElements(array, is_copy);
+    }
+};
+
+template<typename JTYPEARRAY, typename ARRAYGETTER>
+static void*
+getArrayPointer(JNIEnv *_env, JTYPEARRAY array, jboolean* is_copy) {
+    return ARRAYGETTER::Get(_env, array, is_copy);
+}
+
+class ByteArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jbyteArray array, jbyte* data, jboolean commit) {
+        _env->ReleaseByteArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class BooleanArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jbooleanArray array, jboolean* data, jboolean commit) {
+        _env->ReleaseBooleanArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class CharArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jcharArray array, jchar* data, jboolean commit) {
+        _env->ReleaseCharArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class ShortArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jshortArray array, jshort* data, jboolean commit) {
+        _env->ReleaseShortArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class IntArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jintArray array, jint* data, jboolean commit) {
+        _env->ReleaseIntArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class LongArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jlongArray array, jlong* data, jboolean commit) {
+        _env->ReleaseLongArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class FloatArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jfloatArray array, jfloat* data, jboolean commit) {
+        _env->ReleaseFloatArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class DoubleArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jdoubleArray array, jdouble* data, jboolean commit) {
+        _env->ReleaseDoubleArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+
+template<typename JTYPEARRAY, typename NTYPEARRAY, typename ARRAYRELEASER>
+static void
+releaseArrayPointer(JNIEnv *_env, JTYPEARRAY array, NTYPEARRAY data, jboolean commit) {
+    ARRAYRELEASER::Release(_env, array, data, commit);
+}
+
 static void
 releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit)
 {
@@ -203,7 +313,8 @@
     return needed;
 }
 
-template <typename JTYPEARRAY, typename CTYPE, void GET(GLenum, CTYPE*)>
+template <typename JTYPEARRAY, typename ARRAYGETTER, typename NTYPEARRAY,
+          typename ARRAYRELEASER, typename CTYPE, void GET(GLenum, CTYPE*)>
 static void
 get
   (JNIEnv *_env, jobject _this, jint pname, JTYPEARRAY params_ref, jint offset) {
@@ -238,8 +349,8 @@
         _exceptionMessage = "length - offset < needed";
         goto exit;
     }
-    params_base = (CTYPE *)
-        _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+    params_base = (CTYPE *) getArrayPointer<JTYPEARRAY, ARRAYGETTER>(
+        _env, params_ref, (jboolean *)0);
     params = params_base + offset;
 
     GET(
@@ -249,8 +360,8 @@
 
 exit:
     if (params_base) {
-        _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
-            _exception ? JNI_ABORT: 0);
+        releaseArrayPointer<JTYPEARRAY, NTYPEARRAY, ARRAYRELEASER>(
+            _env, params_ref, params_base, !_exception);
     }
     if (_exception) {
         jniThrowException(_env, _exceptionType, _exceptionMessage);
@@ -258,20 +369,21 @@
 }
 
 
-template <typename CTYPE, void GET(GLenum, CTYPE*)>
+template <typename CTYPE, typename JTYPEARRAY, typename ARRAYGETTER, typename NTYPEARRAY,
+          typename ARRAYRELEASER, void GET(GLenum, CTYPE*)>
 static void
 getarray
   (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
     jint _exception = 0;
     const char * _exceptionType;
     const char * _exceptionMessage;
-    jarray _array = (jarray) 0;
+    JTYPEARRAY _array = (JTYPEARRAY) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     CTYPE *params = (CTYPE *) 0;
     int _needed = 0;
 
-    params = (CTYPE *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    params = (CTYPE *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     _remaining /= sizeof(CTYPE);    // convert from bytes to item count
     _needed = getNeededCount(pname);
     // if we didn't find this pname, we just assume the user passed
@@ -284,7 +396,8 @@
         goto exit;
     }
     if (params == NULL) {
-        char * _paramsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        char * _paramsBase = (char *) getArrayPointer<JTYPEARRAY, ARRAYGETTER>(
+            _env, _array, (jboolean *) 0);
         params = (CTYPE *) (_paramsBase + _bufferOffset);
     }
     GET(
@@ -294,7 +407,8 @@
 
 exit:
     if (_array) {
-        releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+        releaseArrayPointer<JTYPEARRAY, NTYPEARRAY, ARRAYRELEASER>(
+            _env, _array, (NTYPEARRAY)params, _exception ? JNI_FALSE : JNI_TRUE);
     }
     if (_exception) {
         jniThrowException(_env, _exceptionType, _exceptionMessage);
diff --git a/opengl/tools/glgen/stubs/gles11/glDrawElementsInstanced.cpp b/opengl/tools/glgen/stubs/gles11/glDrawElementsInstanced.cpp
index d844152..86decfb 100644
--- a/opengl/tools/glgen/stubs/gles11/glDrawElementsInstanced.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glDrawElementsInstanced.cpp
@@ -36,4 +36,3 @@
         (GLsizei)instanceCount
     );
 }
-
diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp
index 7d414d8..a8d63d9 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp
@@ -32,7 +32,7 @@
     }
     _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
     length_base = (GLsizei *)
-        _env->GetPrimitiveArrayCritical(length_ref, (jboolean *)0);
+        _env->GetIntArrayElements(length_ref, (jboolean *)0);
     length = length_base + lengthOffset;
 
     if (!size_ref) {
@@ -49,7 +49,7 @@
     }
     _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset;
     size_base = (GLint *)
-        _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0);
+        _env->GetIntArrayElements(size_ref, (jboolean *)0);
     size = size_base + sizeOffset;
 
     if (!type_ref) {
@@ -66,7 +66,7 @@
     }
     _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset;
     type_base = (GLenum *)
-        _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0);
+        _env->GetIntArrayElements(type_ref, (jboolean *)0);
     type = type_base + typeOffset;
 
     if (!name_ref) {
@@ -83,7 +83,7 @@
     }
     _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset;
     name_base = (char *)
-        _env->GetPrimitiveArrayCritical(name_ref, (jboolean *)0);
+        _env->GetByteArrayElements(name_ref, (jboolean *)0);
     name = name_base + nameOffset;
 
     glGetActiveAttrib(
@@ -98,19 +98,19 @@
 
 exit:
     if (name_base) {
-        _env->ReleasePrimitiveArrayCritical(name_ref, name_base,
+        _env->ReleaseByteArrayElements(name_ref, (jbyte*)name_base,
             _exception ? JNI_ABORT: 0);
     }
     if (type_base) {
-        _env->ReleasePrimitiveArrayCritical(type_ref, type_base,
+        _env->ReleaseIntArrayElements(type_ref, (jint*)type_base,
             _exception ? JNI_ABORT: 0);
     }
     if (size_base) {
-        _env->ReleasePrimitiveArrayCritical(size_ref, size_base,
+        _env->ReleaseIntArrayElements(size_ref, (jint*)size_base,
             _exception ? JNI_ABORT: 0);
     }
     if (length_base) {
-        _env->ReleasePrimitiveArrayCritical(length_ref, length_base,
+        _env->ReleaseIntArrayElements(length_ref, (jint*)length_base,
             _exception ? JNI_ABORT: 0);
     }
     if (_exception) {
@@ -122,11 +122,11 @@
 static void
 android_glGetActiveAttrib__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B
   (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jbyte name) {
-    jarray _lengthArray = (jarray) 0;
+    jintArray _lengthArray = (jintArray) 0;
     jint _lengthBufferOffset = (jint) 0;
-    jarray _sizeArray = (jarray) 0;
+    jintArray _sizeArray = (jintArray) 0;
     jint _sizeBufferOffset = (jint) 0;
-    jarray _typeArray = (jarray) 0;
+    jintArray _typeArray = (jintArray) 0;
     jint _typeBufferOffset = (jint) 0;
     jint _lengthRemaining;
     GLsizei *length = (GLsizei *) 0;
@@ -135,19 +135,19 @@
     jint _typeRemaining;
     GLenum *type = (GLenum *) 0;
 
-    length = (GLsizei *)getPointer(_env, length_buf, &_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
-    size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
-    type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset);
+    length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
+    size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
+    type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset);
     if (length == NULL) {
-        char * _lengthBase = (char *)_env->GetPrimitiveArrayCritical(_lengthArray, (jboolean *) 0);
+        char * _lengthBase = (char *)_env->GetIntArrayElements(_lengthArray, (jboolean *) 0);
         length = (GLsizei *) (_lengthBase + _lengthBufferOffset);
     }
     if (size == NULL) {
-        char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0);
+        char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0);
         size = (GLint *) (_sizeBase + _sizeBufferOffset);
     }
     if (type == NULL) {
-        char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0);
+        char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0);
         type = (GLenum *) (_typeBase + _typeBufferOffset);
     }
     glGetActiveAttrib(
@@ -160,13 +160,13 @@
         reinterpret_cast<char *>(name)
     );
     if (_typeArray) {
-        releasePointer(_env, _typeArray, type, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE);
     }
     if (_sizeArray) {
-        releasePointer(_env, _sizeArray, size, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _sizeArray, (jint*)size, JNI_TRUE);
     }
     if (_lengthArray) {
-        releasePointer(_env, _lengthArray, length, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _lengthArray, (jint*)length, JNI_TRUE);
     }
 }
 
@@ -211,7 +211,7 @@
     }
     _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset;
     size_base = (GLint *)
-        _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0);
+        _env->GetIntArrayElements(size_ref, (jboolean *)0);
     size = size_base + sizeOffset;
 
     if (!type_ref) {
@@ -228,7 +228,7 @@
     }
     _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset;
     type_base = (GLenum *)
-        _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0);
+        _env->GetIntArrayElements(type_ref, (jboolean *)0);
     type = type_base + typeOffset;
 
     glGetActiveAttrib(
@@ -242,11 +242,11 @@
     );
 exit:
     if (type_base) {
-        _env->ReleasePrimitiveArrayCritical(type_ref, type_base,
+        _env->ReleaseIntArrayElements(type_ref, (jint*)type_base,
             _exception ? JNI_ABORT: 0);
     }
     if (size_base) {
-        _env->ReleasePrimitiveArrayCritical(size_ref, size_base,
+        _env->ReleaseIntArrayElements(size_ref, (jint*)size_base,
             _exception ? JNI_ABORT: 0);
     }
     if (_exception != 1) {
@@ -269,9 +269,9 @@
 static jstring
 android_glGetActiveAttrib2
   (JNIEnv *_env, jobject _this, jint program, jint index, jobject size_buf, jobject type_buf) {
-    jarray _sizeArray = (jarray) 0;
+    jintArray _sizeArray = (jintArray) 0;
     jint _sizeBufferOffset = (jint) 0;
-    jarray _typeArray = (jarray) 0;
+    jintArray _typeArray = (jintArray) 0;
     jint _typeBufferOffset = (jint) 0;
     jint _lengthRemaining;
     GLsizei *length = (GLsizei *) 0;
@@ -294,14 +294,14 @@
         return NULL;
     }
 
-    size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
-    type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset);
+    size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
+    type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset);
     if (size == NULL) {
-        char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0);
+        char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0);
         size = (GLint *) (_sizeBase + _sizeBufferOffset);
     }
     if (type == NULL) {
-        char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0);
+        char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0);
         type = (GLenum *) (_typeBase + _typeBufferOffset);
     }
     glGetActiveAttrib(
@@ -315,10 +315,10 @@
     );
 
     if (_typeArray) {
-        releasePointer(_env, _typeArray, type, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE);
     }
     if (_sizeArray) {
-        releasePointer(_env, _sizeArray, size, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _sizeArray, (jint*)size, JNI_TRUE);
     }
     result = _env->NewStringUTF(buf);
     if (buf) {
diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp
index a7376ba..68e8389 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp
@@ -32,7 +32,7 @@
     }
     _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
     length_base = (GLsizei *)
-        _env->GetPrimitiveArrayCritical(length_ref, (jboolean *)0);
+        _env->GetIntArrayElements(length_ref, (jboolean *)0);
     length = length_base + lengthOffset;
 
     if (!size_ref) {
@@ -49,7 +49,7 @@
     }
     _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset;
     size_base = (GLint *)
-        _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0);
+        _env->GetIntArrayElements(size_ref, (jboolean *)0);
     size = size_base + sizeOffset;
 
     if (!type_ref) {
@@ -66,7 +66,7 @@
     }
     _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset;
     type_base = (GLenum *)
-        _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0);
+        _env->GetIntArrayElements(type_ref, (jboolean *)0);
     type = type_base + typeOffset;
 
     if (!name_ref) {
@@ -83,7 +83,7 @@
     }
     _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset;
     name_base = (char *)
-        _env->GetPrimitiveArrayCritical(name_ref, (jboolean *)0);
+        _env->GetByteArrayElements(name_ref, (jboolean *)0);
     name = name_base + nameOffset;
 
     glGetActiveUniform(
@@ -98,19 +98,19 @@
 
 exit:
     if (name_base) {
-        _env->ReleasePrimitiveArrayCritical(name_ref, name_base,
+        _env->ReleaseByteArrayElements(name_ref, (jbyte*)name_base,
             _exception ? JNI_ABORT: 0);
     }
     if (type_base) {
-        _env->ReleasePrimitiveArrayCritical(type_ref, type_base,
+        _env->ReleaseIntArrayElements(type_ref, (jint*)type_base,
             _exception ? JNI_ABORT: 0);
     }
     if (size_base) {
-        _env->ReleasePrimitiveArrayCritical(size_ref, size_base,
+        _env->ReleaseIntArrayElements(size_ref, (jint*)size_base,
             _exception ? JNI_ABORT: 0);
     }
     if (length_base) {
-        _env->ReleasePrimitiveArrayCritical(length_ref, length_base,
+        _env->ReleaseIntArrayElements(length_ref, (jint*)length_base,
             _exception ? JNI_ABORT: 0);
     }
     if (_exception) {
@@ -122,11 +122,11 @@
 static void
 android_glGetActiveUniform__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B
   (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jbyte name) {
-    jarray _lengthArray = (jarray) 0;
+    jintArray _lengthArray = (jintArray) 0;
     jint _lengthBufferOffset = (jint) 0;
-    jarray _sizeArray = (jarray) 0;
+    jintArray _sizeArray = (jintArray) 0;
     jint _sizeBufferOffset = (jint) 0;
-    jarray _typeArray = (jarray) 0;
+    jintArray _typeArray = (jintArray) 0;
     jint _typeBufferOffset = (jint) 0;
     jint _lengthRemaining;
     GLsizei *length = (GLsizei *) 0;
@@ -135,19 +135,19 @@
     jint _typeRemaining;
     GLenum *type = (GLenum *) 0;
 
-    length = (GLsizei *)getPointer(_env, length_buf, &_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
-    size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
-    type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset);
+    length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
+    size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
+    type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset);
     if (length == NULL) {
-        char * _lengthBase = (char *)_env->GetPrimitiveArrayCritical(_lengthArray, (jboolean *) 0);
+        char * _lengthBase = (char *)_env->GetIntArrayElements(_lengthArray, (jboolean *) 0);
         length = (GLsizei *) (_lengthBase + _lengthBufferOffset);
     }
     if (size == NULL) {
-        char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0);
+        char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0);
         size = (GLint *) (_sizeBase + _sizeBufferOffset);
     }
     if (type == NULL) {
-        char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0);
+        char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0);
         type = (GLenum *) (_typeBase + _typeBufferOffset);
     }
     glGetActiveUniform(
@@ -160,13 +160,13 @@
         reinterpret_cast<char *>(name)
     );
     if (_typeArray) {
-        releasePointer(_env, _typeArray, type, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE);
     }
     if (_sizeArray) {
-        releasePointer(_env, _sizeArray, size, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _sizeArray, (jint*)size, JNI_TRUE);
     }
     if (_lengthArray) {
-        releasePointer(_env, _lengthArray, length, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _lengthArray, (jint*)length, JNI_TRUE);
     }
 }
 
@@ -214,7 +214,7 @@
     }
     _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset;
     size_base = (GLint *)
-        _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0);
+        _env->GetIntArrayElements(size_ref, (jboolean *)0);
     size = size_base + sizeOffset;
 
     if (!type_ref) {
@@ -231,7 +231,7 @@
     }
     _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset;
     type_base = (GLenum *)
-        _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0);
+        _env->GetIntArrayElements(type_ref, (jboolean *)0);
     type = type_base + typeOffset;
 
     glGetActiveUniform(
@@ -246,11 +246,11 @@
 
 exit:
     if (type_base) {
-        _env->ReleasePrimitiveArrayCritical(type_ref, type_base,
+        _env->ReleaseIntArrayElements(type_ref, (jint*)type_base,
             _exception ? JNI_ABORT: 0);
     }
     if (size_base) {
-        _env->ReleasePrimitiveArrayCritical(size_ref, size_base,
+        _env->ReleaseIntArrayElements(size_ref, (jint*)size_base,
             _exception ? JNI_ABORT: 0);
     }
     if (_exception != 1) {
@@ -272,9 +272,9 @@
 static jstring
 android_glGetActiveUniform2
   (JNIEnv *_env, jobject _this, jint program, jint index, jobject size_buf, jobject type_buf) {
-    jarray _sizeArray = (jarray) 0;
+    jintArray _sizeArray = (jintArray) 0;
     jint _sizeBufferOffset = (jint) 0;
-    jarray _typeArray = (jarray) 0;
+    jintArray _typeArray = (jintArray) 0;
     jint _typeBufferOffset = (jint) 0;
     jint _sizeRemaining;
     GLint *size = (GLint *) 0;
@@ -294,15 +294,15 @@
         return NULL;
     }
 
-    size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
-    type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset);
+    size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
+    type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset);
 
     if (size == NULL) {
-        char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0);
+        char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0);
         size = (GLint *) (_sizeBase + _sizeBufferOffset);
     }
     if (type == NULL) {
-        char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0);
+        char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0);
         type = (GLenum *) (_typeBase + _typeBufferOffset);
     }
     glGetActiveUniform(
@@ -316,10 +316,10 @@
     );
 
     if (_typeArray) {
-        releasePointer(_env, _typeArray, type, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE);
     }
     if (_sizeArray) {
-        releasePointer(_env, _sizeArray, size, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _sizeArray, (jint*)size, JNI_TRUE);
     }
     result = _env->NewStringUTF(buf);
     if (buf) {
diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveUniformBlockName.cpp b/opengl/tools/glgen/stubs/gles11/glGetActiveUniformBlockName.cpp
index bb6ae7c..6104c84 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetActiveUniformBlockName.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetActiveUniformBlockName.cpp
@@ -25,7 +25,7 @@
         goto exit;
     }
     _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
-    _length_base = (GLsizei*)_env->GetPrimitiveArrayCritical(
+    _length_base = (GLsizei*)_env->GetIntArrayElements(
             length_ref, (jboolean*)0);
     _length = _length_base + lengthOffset;
 
@@ -42,7 +42,7 @@
         goto exit;
     }
     _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset;
-    _name_base = (GLchar*)_env->GetPrimitiveArrayCritical(
+    _name_base = (GLchar*)_env->GetByteArrayElements(
             name_ref, (jboolean*)0);
     _name = _name_base + nameOffset;
 
@@ -56,11 +56,11 @@
 
 exit:
     if (_name_base) {
-        _env->ReleasePrimitiveArrayCritical(name_ref, _name_base,
+        _env->ReleaseByteArrayElements(name_ref, (jbyte*)_name_base,
             _exception ? JNI_ABORT: 0);
     }
     if (_length_base) {
-        _env->ReleasePrimitiveArrayCritical(length_ref, _length_base,
+        _env->ReleaseIntArrayElements(length_ref, (jint*)_length_base,
             _exception ? JNI_ABORT: 0);
     }
     if (_exception) {
@@ -124,4 +124,3 @@
     free(name);
     return result;
 }
-
diff --git a/opengl/tools/glgen/stubs/gles11/glGetBooleanv.cpp b/opengl/tools/glgen/stubs/gles11/glGetBooleanv.cpp
index 00c52af..7874bd8 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetBooleanv.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetBooleanv.cpp
@@ -2,12 +2,14 @@
 static void
 android_glGetBooleanv__I_3ZI
   (JNIEnv *_env, jobject _this, jint pname, jbooleanArray params_ref, jint offset) {
-    get<jbooleanArray, GLboolean, glGetBooleanv>(_env, _this, pname, params_ref, offset);
+    get<jbooleanArray, BooleanArrayGetter, jboolean*, BooleanArrayReleaser, GLboolean, glGetBooleanv>(
+        _env, _this, pname, params_ref, offset);
 }
 
 /* void glGetBooleanv ( GLenum pname, GLboolean *params ) */
 static void
 android_glGetBooleanv__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
-    getarray<GLboolean, glGetBooleanv>(_env, _this, pname, params_buf);
+    getarray<GLboolean, jintArray, IntArrayGetter, jint*, IntArrayReleaser, glGetBooleanv>(
+        _env, _this, pname, params_buf);
 }
diff --git a/opengl/tools/glgen/stubs/gles11/glGetFloatv.cpp b/opengl/tools/glgen/stubs/gles11/glGetFloatv.cpp
index 71c399d..2f41fd1 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetFloatv.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetFloatv.cpp
@@ -2,12 +2,14 @@
 static void
 android_glGetFloatv__I_3FI
   (JNIEnv *_env, jobject _this, jint pname, jfloatArray params_ref, jint offset) {
-    get<jfloatArray, GLfloat, glGetFloatv>(_env, _this, pname, params_ref, offset);
+    get<jfloatArray, FloatArrayGetter, jfloat*, FloatArrayReleaser, GLfloat, glGetFloatv>(
+        _env, _this, pname, params_ref, offset);
 }
 
 /* void glGetFloatv ( GLenum pname, GLfloat *params ) */
 static void
 android_glGetFloatv__ILjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
-    getarray<GLfloat, glGetFloatv>(_env, _this, pname, params_buf);
+    getarray<GLfloat, jfloatArray, FloatArrayGetter, jfloat*, FloatArrayReleaser, glGetFloatv>(
+        _env, _this, pname, params_buf);
 }
diff --git a/opengl/tools/glgen/stubs/gles11/glGetIntegerv.cpp b/opengl/tools/glgen/stubs/gles11/glGetIntegerv.cpp
index 9000ece..c960f31 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetIntegerv.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetIntegerv.cpp
@@ -2,13 +2,14 @@
 static void
 android_glGetIntegerv__I_3II
   (JNIEnv *_env, jobject _this, jint pname, jintArray params_ref, jint offset) {
-    get<jintArray, GLint, glGetIntegerv>(_env, _this, pname, params_ref, offset);
+    get<jintArray, IntArrayGetter, jint*, IntArrayReleaser, GLint, glGetIntegerv>(
+        _env, _this, pname, params_ref, offset);
 }
 
 /* void glGetIntegerv ( GLenum pname, GLint *params ) */
 static void
 android_glGetIntegerv__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
-    getarray<GLint, glGetIntegerv>(_env, _this, pname, params_buf);
+    getarray<GLint, jintArray, IntArrayGetter, jint*, IntArrayReleaser, glGetIntegerv>(
+        _env, _this, pname, params_buf);
 }
-
diff --git a/opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp b/opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp
index c995d9c..d9808ef 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp
@@ -26,7 +26,7 @@
     }
     _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
     length_base = (GLsizei *)
-        _env->GetPrimitiveArrayCritical(length_ref, (jboolean *)0);
+        _env->GetIntArrayElements(length_ref, (jboolean *)0);
     length = length_base + lengthOffset;
 
     if (!source_ref) {
@@ -43,7 +43,7 @@
     }
     _sourceRemaining = _env->GetArrayLength(source_ref) - sourceOffset;
     source_base = (char *)
-        _env->GetPrimitiveArrayCritical(source_ref, (jboolean *)0);
+        _env->GetByteArrayElements(source_ref, (jboolean *)0);
     source = source_base + sourceOffset;
 
     glGetShaderSource(
@@ -55,11 +55,11 @@
 
 exit:
     if (source_base) {
-        _env->ReleasePrimitiveArrayCritical(source_ref, source_base,
+        _env->ReleaseByteArrayElements(source_ref, (jbyte*)source_base,
             _exception ? JNI_ABORT: 0);
     }
     if (length_base) {
-        _env->ReleasePrimitiveArrayCritical(length_ref, length_base,
+        _env->ReleaseIntArrayElements(length_ref, (jint*)length_base,
             _exception ? JNI_ABORT: 0);
     }
     if (_exception) {
@@ -71,14 +71,14 @@
 static void
 android_glGetShaderSource__IILjava_nio_IntBuffer_2B
   (JNIEnv *_env, jobject _this, jint shader, jint bufsize, jobject length_buf, jbyte source) {
-    jarray _array = (jarray) 0;
+    jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLsizei *length = (GLsizei *) 0;
 
-    length = (GLsizei *)getPointer(_env, length_buf, &_array, &_remaining, &_bufferOffset);
+    length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (length == NULL) {
-        char * _lengthBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        char * _lengthBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
         length = (GLsizei *) (_lengthBase + _bufferOffset);
     }
     glGetShaderSource(
@@ -88,7 +88,7 @@
         reinterpret_cast<char *>(source)
     );
     if (_array) {
-        releasePointer(_env, _array, length, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _array, (jint*)length, JNI_TRUE);
     }
 }
 
diff --git a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp
index a977693..cb656c8 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp
@@ -32,7 +32,7 @@
     }
     _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
     length_base = (GLsizei *)
-        _env->GetPrimitiveArrayCritical(length_ref, (jboolean *)0);
+        _env->GetIntArrayElements(length_ref, (jboolean *)0);
     length = length_base + lengthOffset;
 
     if (!size_ref) {
@@ -49,7 +49,7 @@
     }
     _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset;
     size_base = (GLint *)
-        _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0);
+        _env->GetIntArrayElements(size_ref, (jboolean *)0);
     size = size_base + sizeOffset;
 
     if (!type_ref) {
@@ -66,7 +66,7 @@
     }
     _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset;
     type_base = (GLenum *)
-        _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0);
+        _env->GetIntArrayElements(type_ref, (jboolean *)0);
     type = type_base + typeOffset;
 
     if (!name_ref) {
@@ -83,7 +83,7 @@
     }
     _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset;
     name_base = (char *)
-        _env->GetPrimitiveArrayCritical(name_ref, (jboolean *)0);
+        _env->GetByteArrayElements(name_ref, (jboolean *)0);
     name = name_base + nameOffset;
 
     glGetTransformFeedbackVarying(
@@ -98,19 +98,19 @@
 
 exit:
     if (name_base) {
-        _env->ReleasePrimitiveArrayCritical(name_ref, name_base,
+        _env->ReleaseByteArrayElements(name_ref, (jbyte*)name_base,
             _exception ? JNI_ABORT: 0);
     }
     if (type_base) {
-        _env->ReleasePrimitiveArrayCritical(type_ref, type_base,
+        _env->ReleaseIntArrayElements(type_ref, (jint*)type_base,
             _exception ? JNI_ABORT: 0);
     }
     if (size_base) {
-        _env->ReleasePrimitiveArrayCritical(size_ref, size_base,
+        _env->ReleaseIntArrayElements(size_ref, (jint*)size_base,
             _exception ? JNI_ABORT: 0);
     }
     if (length_base) {
-        _env->ReleasePrimitiveArrayCritical(length_ref, length_base,
+        _env->ReleaseIntArrayElements(length_ref, (jint*)length_base,
             _exception ? JNI_ABORT: 0);
     }
     if (_exception) {
@@ -122,11 +122,11 @@
 static void
 android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B
   (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jbyte name) {
-    jarray _lengthArray = (jarray) 0;
+    jintArray _lengthArray = (jintArray) 0;
     jint _lengthBufferOffset = (jint) 0;
-    jarray _sizeArray = (jarray) 0;
+    jintArray _sizeArray = (jintArray) 0;
     jint _sizeBufferOffset = (jint) 0;
-    jarray _typeArray = (jarray) 0;
+    jintArray _typeArray = (jintArray) 0;
     jint _typeBufferOffset = (jint) 0;
     jint _lengthRemaining;
     GLsizei *length = (GLsizei *) 0;
@@ -135,19 +135,19 @@
     jint _typeRemaining;
     GLenum *type = (GLenum *) 0;
 
-    length = (GLsizei *)getPointer(_env, length_buf, &_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
-    size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
-    type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset);
+    length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
+    size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
+    type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset);
     if (length == NULL) {
-        char * _lengthBase = (char *)_env->GetPrimitiveArrayCritical(_lengthArray, (jboolean *) 0);
+        char * _lengthBase = (char *)_env->GetIntArrayElements(_lengthArray, (jboolean *) 0);
         length = (GLsizei *) (_lengthBase + _lengthBufferOffset);
     }
     if (size == NULL) {
-        char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0);
+        char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0);
         size = (GLint *) (_sizeBase + _sizeBufferOffset);
     }
     if (type == NULL) {
-        char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0);
+        char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0);
         type = (GLenum *) (_typeBase + _typeBufferOffset);
     }
     glGetTransformFeedbackVarying(
@@ -164,13 +164,13 @@
         (char *)static_cast<uintptr_t>(name)
     );
     if (_typeArray) {
-        releasePointer(_env, _typeArray, type, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE);
     }
     if (_sizeArray) {
-        releasePointer(_env, _sizeArray, size, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _sizeArray, (jint*)size, JNI_TRUE);
     }
     if (_lengthArray) {
-        releasePointer(_env, _lengthArray, length, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _lengthArray, (jint*)length, JNI_TRUE);
     }
 }
 
@@ -215,7 +215,7 @@
     }
     _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset;
     size_base = (GLint *)
-        _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0);
+        _env->GetIntArrayElements(size_ref, (jboolean *)0);
     size = size_base + sizeOffset;
 
     if (!type_ref) {
@@ -232,7 +232,7 @@
     }
     _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset;
     type_base = (GLenum *)
-        _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0);
+        _env->GetIntArrayElements(type_ref, (jboolean *)0);
     type = type_base + typeOffset;
 
     glGetTransformFeedbackVarying(
@@ -246,11 +246,11 @@
     );
 exit:
     if (type_base) {
-        _env->ReleasePrimitiveArrayCritical(type_ref, type_base,
+        _env->ReleaseIntArrayElements(type_ref, (jint*)type_base,
             _exception ? JNI_ABORT: 0);
     }
     if (size_base) {
-        _env->ReleasePrimitiveArrayCritical(size_ref, size_base,
+        _env->ReleaseIntArrayElements(size_ref, (jint*)size_base,
             _exception ? JNI_ABORT: 0);
     }
     if (_exception != 1) {
@@ -273,9 +273,9 @@
 static jstring
 android_glGetTransformFeedbackVarying2
   (JNIEnv *_env, jobject _this, jint program, jint index, jobject size_buf, jobject type_buf) {
-    jarray _sizeArray = (jarray) 0;
+    jintArray _sizeArray = (jintArray) 0;
     jint _sizeBufferOffset = (jint) 0;
-    jarray _typeArray = (jarray) 0;
+    jintArray _typeArray = (jintArray) 0;
     jint _typeBufferOffset = (jint) 0;
     jint _lengthRemaining;
     GLsizei *length = (GLsizei *) 0;
@@ -298,14 +298,14 @@
         return NULL;
     }
 
-    size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
-    type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset);
+    size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
+    type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset);
     if (size == NULL) {
-        char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0);
+        char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0);
         size = (GLint *) (_sizeBase + _sizeBufferOffset);
     }
     if (type == NULL) {
-        char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0);
+        char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0);
         type = (GLenum *) (_typeBase + _typeBufferOffset);
     }
     glGetTransformFeedbackVarying(
@@ -319,10 +319,10 @@
     );
 
     if (_typeArray) {
-        releasePointer(_env, _typeArray, type, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE);
     }
     if (_sizeArray) {
-        releasePointer(_env, _sizeArray, size, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _sizeArray, (jint*)size, JNI_TRUE);
     }
     result = _env->NewStringUTF(buf);
     if (buf) {
diff --git a/opengl/tools/glgen/stubs/gles11/glGetUniformIndices.cpp b/opengl/tools/glgen/stubs/gles11/glGetUniformIndices.cpp
index fb137ab..13ef01e 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetUniformIndices.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetUniformIndices.cpp
@@ -49,7 +49,7 @@
         _exceptionMessage = "not enough space in uniformIndices";
         goto exit;
     }
-    _indices_base = (GLuint*)_env->GetPrimitiveArrayCritical(
+    _indices_base = (GLuint*)_env->GetIntArrayElements(
             uniformIndices_ref, 0);
     _indices = _indices_base + uniformIndicesOffset;
 
@@ -57,8 +57,8 @@
 
 exit:
     if (_indices_base) {
-        _env->ReleasePrimitiveArrayCritical(uniformIndices_ref, _indices_base,
-                _exception ? JNI_ABORT : 0);
+        _env->ReleaseIntArrayElements(uniformIndices_ref, (jint*)_indices_base,
+            _exception ? JNI_ABORT : 0);
     }
     for (_i = _count - 1; _i >= 0; _i--) {
         if (_names[_i]) {
@@ -85,7 +85,7 @@
     jint _count = 0;
     jint _i;
     const char** _names = NULL;
-    jarray _uniformIndicesArray = (jarray)0;
+    jintArray _uniformIndicesArray = (jintArray)0;
     jint _uniformIndicesRemaining;
     jint _uniformIndicesOffset = 0;
     GLuint* _indices = NULL;
@@ -118,11 +118,11 @@
     }
 
     _indices = (GLuint*)getPointer(_env, uniformIndices_buf,
-            &_uniformIndicesArray, &_uniformIndicesRemaining,
+            (jarray*)&_uniformIndicesArray, &_uniformIndicesRemaining,
             &_uniformIndicesOffset);
     if (!_indices) {
-        _indicesBase = (char*)_env->GetPrimitiveArrayCritical(
-                _uniformIndicesArray, 0);
+        _indicesBase = (char*)_env->GetIntArrayElements(
+            _uniformIndicesArray, 0);
         _indices = (GLuint*)(_indicesBase + _uniformIndicesOffset);
     }
     if (_uniformIndicesRemaining < _count) {
@@ -136,7 +136,8 @@
 
 exit:
     if (_uniformIndicesArray) {
-        releasePointer(_env, _uniformIndicesArray, _indicesBase, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(
+            _env, _uniformIndicesArray, (jint*)_indicesBase, JNI_TRUE);
     }
     for (_i = _count - 1; _i >= 0; _i--) {
         if (_names[_i]) {
@@ -151,4 +152,3 @@
         jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
-
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index dbba9c1..6267a4c 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -79,7 +79,7 @@
     sensor_t const* list;
     ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
 
-    result.appendFormat("halVersion %d\n", getHalDeviceVersion());
+    result.appendFormat("halVersion 0x%08x\n", getHalDeviceVersion());
     result.appendFormat("%d h/w sensors:\n", int(count));
 
     Mutex::Autolock _l(mLock);
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index c7bcaef..ae8b3b3 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -214,7 +214,7 @@
     // add to our handle->SensorInterface mapping
     mSensorMap.add(sensor.getHandle(), s);
     // create an entry in the mLastEventSeen array
-    mLastEventSeen.add(sensor.getHandle(), event);
+    mLastEventSeen.add(sensor.getHandle(), NULL);
 
     return sensor;
 }
@@ -240,13 +240,21 @@
                 "can't dump SensorService from pid=%d, uid=%d\n",
                 IPCThreadState::self()->getCallingPid(),
                 IPCThreadState::self()->getCallingUid());
-    } else if (args.size() > 0) {
+    } else {
         if (args.size() > 1) {
            return INVALID_OPERATION;
         }
         Mutex::Autolock _l(mLock);
         SensorDevice& dev(SensorDevice::getInstance());
-        if (args[0] == String16("restrict") && mCurrentOperatingMode == NORMAL) {
+        if (args.size() == 1 && args[0] == String16("restrict")) {
+            // If already in restricted mode. Ignore.
+            if (mCurrentOperatingMode == RESTRICTED) {
+                return status_t(NO_ERROR);
+            }
+            // If in any mode other than normal, ignore.
+            if (mCurrentOperatingMode != NORMAL) {
+                return INVALID_OPERATION;
+            }
             mCurrentOperatingMode = RESTRICTED;
             dev.disableAllSensors();
             // Clear all pending flush connections for all active sensors. If one of the active
@@ -255,132 +263,107 @@
             for (size_t i=0 ; i< mActiveSensors.size(); ++i) {
                 mActiveSensors.valueAt(i)->clearAllPendingFlushConnections();
             }
-        } else if (args[0] == String16("enable") && mCurrentOperatingMode == RESTRICTED) {
-            mCurrentOperatingMode = NORMAL;
-            dev.enableAllSensors();
-        }
-        return status_t(NO_ERROR);
-    } else {
-        Mutex::Autolock _l(mLock);
-        result.append("Sensor List:\n");
-        for (size_t i=0 ; i<mSensorList.size() ; i++) {
-            const Sensor& s(mSensorList[i]);
-            const sensors_event_t& e(mLastEventSeen.valueFor(s.getHandle()));
-            result.appendFormat(
-                    "%-15s| %-10s| version=%d |%-20s| 0x%08x | \"%s\" | type=%d |",
-                    s.getName().string(),
-                    s.getVendor().string(),
-                    s.getVersion(),
-                    s.getStringType().string(),
-                    s.getHandle(),
-                    s.getRequiredPermission().string(),
-                    s.getType());
+            return status_t(NO_ERROR);
+        } else if (args.size() == 1 && args[0] == String16("enable")) {
+            // If currently in restricted mode, reset back to NORMAL mode else ignore.
+            if (mCurrentOperatingMode == RESTRICTED) {
+                mCurrentOperatingMode = NORMAL;
+                dev.enableAllSensors();
+            }
+            return status_t(NO_ERROR);
+        } else {
+            // Default dump the sensor list and debugging information.
+            result.append("Sensor List:\n");
+            for (size_t i=0 ; i<mSensorList.size() ; i++) {
+                const Sensor& s(mSensorList[i]);
+                result.appendFormat(
+                        "%-15s| %-10s| version=%d |%-20s| 0x%08x | \"%s\" | type=%d |",
+                        s.getName().string(),
+                        s.getVendor().string(),
+                        s.getVersion(),
+                        s.getStringType().string(),
+                        s.getHandle(),
+                        s.getRequiredPermission().string(),
+                        s.getType());
 
-            const int reportingMode = s.getReportingMode();
-            if (reportingMode == AREPORTING_MODE_CONTINUOUS) {
-                result.append(" continuous | ");
-            } else if (reportingMode == AREPORTING_MODE_ON_CHANGE) {
-                result.append(" on-change | ");
-            } else if (reportingMode == AREPORTING_MODE_ONE_SHOT) {
-                result.append(" one-shot | ");
-            } else {
-                result.append(" special-trigger | ");
+                const int reportingMode = s.getReportingMode();
+                if (reportingMode == AREPORTING_MODE_CONTINUOUS) {
+                    result.append(" continuous | ");
+                } else if (reportingMode == AREPORTING_MODE_ON_CHANGE) {
+                    result.append(" on-change | ");
+                } else if (reportingMode == AREPORTING_MODE_ONE_SHOT) {
+                    result.append(" one-shot | ");
+                } else {
+                    result.append(" special-trigger | ");
+                }
+
+                if (s.getMaxDelay() > 0) {
+                    result.appendFormat("minRate=%.2fHz | ", 1e6f / s.getMaxDelay());
+                } else {
+                    result.appendFormat("maxDelay=%dus |", s.getMaxDelay());
+                }
+
+                if (s.getMinDelay() > 0) {
+                    result.appendFormat("maxRate=%.2fHz | ", 1e6f / s.getMinDelay());
+                } else {
+                    result.appendFormat("minDelay=%dus |", s.getMinDelay());
+                }
+
+                if (s.getFifoMaxEventCount() > 0) {
+                    result.appendFormat("FifoMax=%d events | ",
+                            s.getFifoMaxEventCount());
+                } else {
+                    result.append("no batching | ");
+                }
+
+                if (s.isWakeUpSensor()) {
+                    result.appendFormat("wakeUp | ");
+                } else {
+                    result.appendFormat("non-wakeUp | ");
+                }
+
+                const CircularBuffer* buf = mLastEventSeen.valueFor(s.getHandle());
+                if (buf != NULL && s.getRequiredPermission().isEmpty()) {
+                    buf->printBuffer(result);
+                } else {
+                    result.append("last=<> \n");
+                }
+                result.append("\n");
+            }
+            SensorFusion::getInstance().dump(result);
+            SensorDevice::getInstance().dump(result);
+
+            result.append("Active sensors:\n");
+            for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
+                int handle = mActiveSensors.keyAt(i);
+                result.appendFormat("%s (handle=0x%08x, connections=%zu)\n",
+                        getSensorName(handle).string(),
+                        handle,
+                        mActiveSensors.valueAt(i)->getNumConnections());
             }
 
-            if (s.getMaxDelay() > 0) {
-                result.appendFormat("minRate=%.2fHz | ", 1e6f / s.getMaxDelay());
-            } else {
-                result.appendFormat("maxDelay=%dus |", s.getMaxDelay());
+            result.appendFormat("Socket Buffer size = %d events\n",
+                                mSocketBufferSize/sizeof(sensors_event_t));
+            result.appendFormat("WakeLock Status: %s \n", mWakeLockAcquired ? "acquired" : "not held");
+            result.appendFormat("Mode :");
+            switch(mCurrentOperatingMode) {
+               case NORMAL:
+                   result.appendFormat(" NORMAL\n");
+                   break;
+               case RESTRICTED:
+                   result.appendFormat(" RESTRICTED\n");
+                   break;
+               case DATA_INJECTION:
+                   result.appendFormat(" DATA_INJECTION\n");
             }
+            result.appendFormat("%zd active connections\n", mActiveConnections.size());
 
-            if (s.getMinDelay() > 0) {
-                result.appendFormat("maxRate=%.2fHz | ", 1e6f / s.getMinDelay());
-            } else {
-                result.appendFormat("minDelay=%dus |", s.getMinDelay());
-            }
-
-            if (s.getFifoMaxEventCount() > 0) {
-                result.appendFormat("FifoMax=%d events | ",
-                        s.getFifoMaxEventCount());
-            } else {
-                result.append("no batching | ");
-            }
-
-            if (s.isWakeUpSensor()) {
-                result.appendFormat("wakeUp | ");
-            } else {
-                result.appendFormat("non-wakeUp | ");
-            }
-
-            switch (s.getType()) {
-                case SENSOR_TYPE_ROTATION_VECTOR:
-                case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR:
-                    result.appendFormat(
-                            "last=<%5.1f,%5.1f,%5.1f,%5.1f,%5.1f, %" PRId64 ">\n",
-                            e.data[0], e.data[1], e.data[2], e.data[3], e.data[4], e.timestamp);
-                    break;
-                case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
-                case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
-                    result.appendFormat(
-                            "last=<%5.1f,%5.1f,%5.1f,%5.1f,%5.1f,%5.1f, %" PRId64 ">\n",
-                            e.data[0], e.data[1], e.data[2], e.data[3], e.data[4], e.data[5],
-                            e.timestamp);
-                    break;
-                case SENSOR_TYPE_GAME_ROTATION_VECTOR:
-                    result.appendFormat(
-                            "last=<%5.1f,%5.1f,%5.1f,%5.1f, %" PRId64 ">\n",
-                            e.data[0], e.data[1], e.data[2], e.data[3], e.timestamp);
-                    break;
-                case SENSOR_TYPE_SIGNIFICANT_MOTION:
-                case SENSOR_TYPE_STEP_DETECTOR:
-                    result.appendFormat( "last=<%f %" PRId64 ">\n", e.data[0], e.timestamp);
-                    break;
-                case SENSOR_TYPE_STEP_COUNTER:
-                    result.appendFormat( "last=<%" PRIu64 ", %" PRId64 ">\n", e.u64.step_counter,
-                                         e.timestamp);
-                    break;
-                default:
-                    // default to 3 values
-                    result.appendFormat(
-                            "last=<%5.1f,%5.1f,%5.1f, %" PRId64 ">\n",
-                            e.data[0], e.data[1], e.data[2], e.timestamp);
-                    break;
-            }
-            result.append("\n");
-        }
-        SensorFusion::getInstance().dump(result);
-        SensorDevice::getInstance().dump(result);
-
-        result.append("Active sensors:\n");
-        for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
-            int handle = mActiveSensors.keyAt(i);
-            result.appendFormat("%s (handle=0x%08x, connections=%zu)\n",
-                    getSensorName(handle).string(),
-                    handle,
-                    mActiveSensors.valueAt(i)->getNumConnections());
-        }
-
-        result.appendFormat("Socket Buffer size = %d events\n",
-                            mSocketBufferSize/sizeof(sensors_event_t));
-        result.appendFormat("WakeLock Status: %s \n", mWakeLockAcquired ? "acquired" : "not held");
-        result.appendFormat("Mode :");
-        switch(mCurrentOperatingMode) {
-           case NORMAL:
-               result.appendFormat(" NORMAL\n");
-               break;
-           case RESTRICTED:
-               result.appendFormat(" RESTRICTED\n");
-               break;
-           case DATA_INJECTION:
-               result.appendFormat(" DATA_INJECTION\n");
-        }
-        result.appendFormat("%zd active connections\n", mActiveConnections.size());
-
-        for (size_t i=0 ; i < mActiveConnections.size() ; i++) {
-            sp<SensorEventConnection> connection(mActiveConnections[i].promote());
-            if (connection != 0) {
-                result.appendFormat("Connection Number: %zu \n", i);
-                connection->dump(result);
+            for (size_t i=0 ; i < mActiveConnections.size() ; i++) {
+                sp<SensorEventConnection> connection(mActiveConnections[i].promote());
+                if (connection != 0) {
+                    result.appendFormat("Connection Number: %zu \n", i);
+                    connection->dump(result);
+                }
             }
         }
     }
@@ -610,19 +593,15 @@
 
 void SensorService::recordLastValueLocked(
         const sensors_event_t* buffer, size_t count) {
-    const sensors_event_t* last = NULL;
     for (size_t i = 0; i < count; i++) {
-        const sensors_event_t* event = &buffer[i];
-        if (event->type != SENSOR_TYPE_META_DATA) {
-            if (last && event->sensor != last->sensor) {
-                mLastEventSeen.editValueFor(last->sensor) = *last;
+        if (buffer[i].type != SENSOR_TYPE_META_DATA) {
+            CircularBuffer* &circular_buf = mLastEventSeen.editValueFor(buffer[i].sensor);
+            if (circular_buf == NULL) {
+                circular_buf = new CircularBuffer(buffer[i].type);
             }
-            last = event;
+            circular_buf->addEvent(buffer[i]);
         }
     }
-    if (last) {
-        mLastEventSeen.editValueFor(last->sensor) = *last;
-    }
 }
 
 void SensorService::sortEventBuffer(sensors_event_t* buffer, size_t count)
@@ -839,14 +818,24 @@
             if (sensor->getSensor().getReportingMode() == AREPORTING_MODE_ON_CHANGE) {
                 // NOTE: The wake_up flag of this event may get set to
                 // WAKE_UP_SENSOR_EVENT_NEEDS_ACK if this is a wake_up event.
-                sensors_event_t& event(mLastEventSeen.editValueFor(handle));
-                if (event.version == sizeof(sensors_event_t)) {
-                    if (isWakeUpSensorEvent(event) && !mWakeLockAcquired) {
-                        setWakeLockAcquiredLocked(true);
-                    }
-                    connection->sendEvents(&event, 1, NULL);
-                    if (!connection->needsWakeLock() && mWakeLockAcquired) {
-                        checkWakeLockStateLocked();
+                CircularBuffer *circular_buf = mLastEventSeen.valueFor(handle);
+                if (circular_buf) {
+                    sensors_event_t event;
+                    memset(&event, 0, sizeof(event));
+                    // It is unlikely that this buffer is empty as the sensor is already active.
+                    // One possible corner case may be two applications activating an on-change
+                    // sensor at the same time.
+                    if(circular_buf->populateLastEvent(&event)) {
+                        event.sensor = handle;
+                        if (event.version == sizeof(sensors_event_t)) {
+                            if (isWakeUpSensorEvent(event) && !mWakeLockAcquired) {
+                                setWakeLockAcquiredLocked(true);
+                            }
+                            connection->sendEvents(&event, 1, NULL);
+                            if (!connection->needsWakeLock() && mWakeLockAcquired) {
+                                checkWakeLockStateLocked();
+                            }
+                        }
                     }
                 }
             }
@@ -1108,6 +1097,29 @@
     return (packageName.find(".cts.") != -1);
 }
 
+int SensorService::getNumEventsForSensorType(int sensor_event_type) {
+    switch (sensor_event_type) {
+        case SENSOR_TYPE_ROTATION_VECTOR:
+        case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR:
+            return 5;
+
+        case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
+        case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
+            return 6;
+
+        case SENSOR_TYPE_GAME_ROTATION_VECTOR:
+            return 4;
+
+        case SENSOR_TYPE_SIGNIFICANT_MOTION:
+        case SENSOR_TYPE_STEP_DETECTOR:
+        case SENSOR_TYPE_STEP_COUNTER:
+            return 1;
+
+         default:
+            return 3;
+    }
+}
+
 // ---------------------------------------------------------------------------
 SensorService::SensorRecord::SensorRecord(
         const sp<SensorEventConnection>& connection)
@@ -1168,6 +1180,85 @@
     mPendingFlushConnections.clear();
 }
 
+// --------------------------------------------------------------------------
+SensorService::CircularBuffer::CircularBuffer(int sensor_event_type) {
+    mNextInd = 0;
+    mTrimmedSensorEventArr = new TrimmedSensorEvent *[CIRCULAR_BUF_SIZE];
+    mSensorType = sensor_event_type;
+    const int numData = SensorService::getNumEventsForSensorType(mSensorType);
+    for (int i = 0; i < CIRCULAR_BUF_SIZE; ++i) {
+        mTrimmedSensorEventArr[i] = new TrimmedSensorEvent(numData, mSensorType);
+    }
+}
+
+void SensorService::CircularBuffer::addEvent(const sensors_event_t& sensor_event) {
+    TrimmedSensorEvent *curr_event = mTrimmedSensorEventArr[mNextInd];
+    curr_event->mTimestamp = sensor_event.timestamp;
+    if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
+        curr_event->mStepCounter = sensor_event.u64.step_counter;
+    } else {
+        memcpy(curr_event->mData, sensor_event.data,
+                 sizeof(float) * SensorService::getNumEventsForSensorType(mSensorType));
+    }
+    time_t rawtime = time(NULL);
+    struct tm * timeinfo = localtime(&rawtime);
+    curr_event->mHour = timeinfo->tm_hour;
+    curr_event->mMin = timeinfo->tm_min;
+    curr_event->mSec = timeinfo->tm_sec;
+    mNextInd = (mNextInd + 1) % CIRCULAR_BUF_SIZE;
+}
+
+void SensorService::CircularBuffer::printBuffer(String8& result) const {
+    const int numData = SensorService::getNumEventsForSensorType(mSensorType);
+    int i = mNextInd, eventNum = 1;
+    result.appendFormat("last %d events = < ", CIRCULAR_BUF_SIZE);
+    do {
+        if (mTrimmedSensorEventArr[i]->mTimestamp == -1) {
+            // Sentinel, ignore.
+            i = (i + 1) % CIRCULAR_BUF_SIZE;
+            continue;
+        }
+        result.appendFormat("%d) ", eventNum++);
+        if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
+            result.appendFormat("%llu,", mTrimmedSensorEventArr[i]->mStepCounter);
+        } else {
+            for (int j = 0; j < numData; ++j) {
+                result.appendFormat("%5.1f,", mTrimmedSensorEventArr[i]->mData[j]);
+            }
+        }
+        result.appendFormat("%lld %02d:%02d:%02d ", mTrimmedSensorEventArr[i]->mTimestamp,
+                mTrimmedSensorEventArr[i]->mHour, mTrimmedSensorEventArr[i]->mMin,
+                mTrimmedSensorEventArr[i]->mSec);
+        i = (i + 1) % CIRCULAR_BUF_SIZE;
+    } while (i != mNextInd);
+    result.appendFormat(">\n");
+}
+
+bool SensorService::CircularBuffer::populateLastEvent(sensors_event_t *event) {
+    int lastEventInd = (mNextInd - 1 + CIRCULAR_BUF_SIZE) % CIRCULAR_BUF_SIZE;
+    // Check if the buffer is empty.
+    if (mTrimmedSensorEventArr[lastEventInd]->mTimestamp == -1) {
+        return false;
+    }
+    event->version = sizeof(sensors_event_t);
+    event->type = mSensorType;
+    event->timestamp = mTrimmedSensorEventArr[lastEventInd]->mTimestamp;
+    if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
+          event->u64.step_counter = mTrimmedSensorEventArr[lastEventInd]->mStepCounter;
+    } else {
+        memcpy(event->data, mTrimmedSensorEventArr[lastEventInd]->mData,
+                 sizeof(float) * SensorService::getNumEventsForSensorType(mSensorType));
+    }
+    return true;
+}
+
+SensorService::CircularBuffer::~CircularBuffer() {
+    for (int i = 0; i < CIRCULAR_BUF_SIZE; ++i) {
+        delete mTrimmedSensorEventArr[i];
+    }
+    delete [] mTrimmedSensorEventArr;
+}
+
 // ---------------------------------------------------------------------------
 
 SensorService::SensorEventConnection::SensorEventConnection(
@@ -1709,7 +1800,7 @@
 #endif
            } else if (numBytesRead == sizeof(uint32_t)) {
                uint32_t numAcks = 0;
-               memcpy(&numAcks, buf, sizeof(numBytesRead));
+               memcpy(&numAcks, buf, numBytesRead);
                // Sanity check to ensure  there are no read errors in recv, numAcks is always
                // within the range and not zero. If any of the above don't hold reset
                // mWakeLockRefCount to zero.
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index df04d00..7c466c1 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -53,6 +53,8 @@
 // For older HALs which don't support batching, use a smaller socket buffer size.
 #define SOCKET_BUFFER_SIZE_NON_BATCHED 4 * 1024
 
+#define CIRCULAR_BUF_SIZE 10
+
 struct sensors_poll_device_t;
 struct sensors_module_t;
 
@@ -258,6 +260,53 @@
         SensorEventAckReceiver(const sp<SensorService>& service): mService(service) {}
     };
 
+    // sensor_event_t with only the data and the timestamp.
+    struct TrimmedSensorEvent {
+        union {
+            float *mData;
+            uint64_t mStepCounter;
+        };
+        // Timestamp from the sensor_event.
+        int64_t mTimestamp;
+        // HH:MM:SS local time at which this sensor event is read at SensorService. Useful
+        // for debugging.
+        int32_t mHour, mMin, mSec;
+
+        TrimmedSensorEvent(int numData, int sensorType) {
+            mTimestamp = -1;
+            if (sensorType == SENSOR_TYPE_STEP_COUNTER) {
+                mStepCounter = 0;
+            } else {
+                mData = new float[numData];
+                for (int i = 0; i < numData; ++i) {
+                    mData[i] = -1.0;
+                }
+            }
+            mHour = mMin = mSec = 0;
+        }
+
+        ~TrimmedSensorEvent() {
+            delete [] mData;
+        }
+    };
+
+    // A circular buffer of TrimmedSensorEvents. The size of this buffer is typically 10. The
+    // last N events generated from the sensor are stored in this buffer. The buffer is NOT
+    // cleared when the sensor unregisters and as a result one may see very old data in the
+    // dumpsys output but this is WAI.
+    class CircularBuffer {
+        int mNextInd;
+        int mSensorType;
+        TrimmedSensorEvent ** mTrimmedSensorEventArr;
+    public:
+        CircularBuffer(int sensor_event_type);
+        void addEvent(const sensors_event_t& sensor_event);
+        void printBuffer(String8& buffer) const;
+        bool populateLastEvent(sensors_event_t *event);
+        ~CircularBuffer();
+    };
+
+    static int getNumEventsForSensorType(int sensor_event_type);
     String8 getSensorName(int handle) const;
     bool isVirtualSensor(int handle) const;
     Sensor getSensorFromHandle(int handle) const;
@@ -336,7 +385,7 @@
     Mode mCurrentOperatingMode;
 
     // The size of this vector is constant, only the items are mutable
-    KeyedVector<int32_t, sensors_event_t> mLastEventSeen;
+    KeyedVector<int32_t, CircularBuffer *> mLastEventSeen;
 
 public:
     void cleanupConnection(SensorEventConnection* connection);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index c8b36ec..579b39e 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -461,7 +461,7 @@
 }
 
 uint32_t HWComposer::getFormat(int disp) const {
-    if (uint32_t(disp)>31 || !mAllocatedDisplayIDs.hasBit(disp)) {
+    if (static_cast<uint32_t>(disp) >= MAX_HWC_DISPLAYS || !mAllocatedDisplayIDs.hasBit(disp)) {
         return HAL_PIXEL_FORMAT_RGBA_8888;
     } else {
         return mDisplayData[disp].format;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 9fb94dd..2b733e9 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -80,7 +80,11 @@
         mProtectedByApp(false),
         mHasSurface(false),
         mClientRef(client),
-        mPotentialCursor(false)
+        mPotentialCursor(false),
+        mQueueItemLock(),
+        mQueueItemCondition(),
+        mQueueItems(),
+        mLastFrameNumberReceived(0)
 {
     mCurrentCrop.makeInvalid();
     mFlinger->getRenderEngine().genTextures(1, &mTextureName);
@@ -127,10 +131,6 @@
     mSurfaceFlingerConsumer->setContentsChangedListener(this);
     mSurfaceFlingerConsumer->setName(mName);
 
-    // Set the shadow queue size to 0 to notify the BufferQueue that we are
-    // shadowing it
-    mSurfaceFlingerConsumer->setShadowQueueSize(0);
-
 #ifdef TARGET_DISABLE_TRIPLE_BUFFERING
 #warning "disabling triple buffering"
     mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2);
@@ -167,9 +167,28 @@
     // Add this buffer from our internal queue tracker
     { // Autolock scope
         Mutex::Autolock lock(mQueueItemLock);
+
+        // Reset the frame number tracker when we receive the first buffer after
+        // a frame number reset
+        if (item.mFrameNumber == 1) {
+            mLastFrameNumberReceived = 0;
+        }
+
+        // Ensure that callbacks are handled in order
+        while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
+                    ms2ns(500));
+            if (result != NO_ERROR) {
+                ALOGE("[%s] Timed out waiting on callback", mName.string());
+            }
+        }
+
         mQueueItems.push_back(item);
-        mSurfaceFlingerConsumer->setShadowQueueSize(mQueueItems.size());
         android_atomic_inc(&mQueuedFrames);
+
+        // Wake up any pending callbacks
+        mLastFrameNumberReceived = item.mFrameNumber;
+        mQueueItemCondition.broadcast();
     }
 
     mFlinger->signalLayerUpdate();
@@ -177,11 +196,25 @@
 
 void Layer::onFrameReplaced(const BufferItem& item) {
     Mutex::Autolock lock(mQueueItemLock);
+
+    // Ensure that callbacks are handled in order
+    while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+        status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
+                ms2ns(500));
+        if (result != NO_ERROR) {
+            ALOGE("[%s] Timed out waiting on callback", mName.string());
+        }
+    }
+
     if (mQueueItems.empty()) {
         ALOGE("Can't replace a frame on an empty queue");
         return;
     }
     mQueueItems.editItemAt(0) = item;
+
+    // Wake up any pending callbacks
+    mLastFrameNumberReceived = item.mFrameNumber;
+    mQueueItemCondition.broadcast();
 }
 
 void Layer::onSidebandStreamChanged() {
@@ -1125,6 +1158,10 @@
     if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
         // mSidebandStreamChanged was true
         mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream();
+        if (mSidebandStream != NULL) {
+            setTransactionFlags(eTransactionNeeded);
+            mFlinger->setTransactionFlags(eTraversalNeeded);
+        }
         recomputeVisibleRegions = true;
 
         const State& s(getDrawingState());
@@ -1257,8 +1294,14 @@
         Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
                 getProducerStickyTransform() != 0);
 
+        uint64_t maxFrameNumber = 0;
+        {
+            Mutex::Autolock lock(mQueueItemLock);
+            maxFrameNumber = mLastFrameNumberReceived;
+        }
+
         status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
-                mFlinger->mPrimaryDispSync);
+                mFlinger->mPrimaryDispSync, maxFrameNumber);
         if (updateResult == BufferQueue::PRESENT_LATER) {
             // Producer doesn't want buffer to be displayed yet.  Signal a
             // layer update so we check again at the next opportunity.
@@ -1268,12 +1311,7 @@
             // If the buffer has been rejected, remove it from the shadow queue
             // and return early
             Mutex::Autolock lock(mQueueItemLock);
-
-            // Update the BufferQueue with the new shadow queue size after
-            // dropping this item
             mQueueItems.removeAt(0);
-            mSurfaceFlingerConsumer->setShadowQueueSize(mQueueItems.size());
-
             android_atomic_dec(&mQueuedFrames);
             return outDirtyRegion;
         }
@@ -1290,10 +1328,7 @@
                 android_atomic_dec(&mQueuedFrames);
             }
 
-            // Update the BufferQueue with our new shadow queue size, since we
-            // have removed at least one item
             mQueueItems.removeAt(0);
-            mSurfaceFlingerConsumer->setShadowQueueSize(mQueueItems.size());
         }
 
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 46c17e5..947da85 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -339,9 +339,9 @@
 
 private:
     // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
-    virtual void onFrameAvailable(const BufferItem& item);
-    virtual void onFrameReplaced(const BufferItem& item);
-    virtual void onSidebandStreamChanged();
+    virtual void onFrameAvailable(const BufferItem& item) override;
+    virtual void onFrameReplaced(const BufferItem& item) override;
+    virtual void onSidebandStreamChanged() override;
 
     void commitTransaction();
 
@@ -416,7 +416,9 @@
 
     // Local copy of the queued contents of the incoming BufferQueue
     mutable Mutex mQueueItemLock;
+    Condition mQueueItemCondition;
     Vector<BufferItem> mQueueItems;
+    uint64_t mLastFrameNumberReceived;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index a9a2958..ed1f31b 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -32,7 +32,7 @@
 // ---------------------------------------------------------------------------
 
 status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
-        const DispSync& dispSync)
+        const DispSync& dispSync, uint64_t maxFrameNumber)
 {
     ATRACE_CALL();
     ALOGV("updateTexImage");
@@ -54,7 +54,8 @@
     // Acquire the next buffer.
     // In asynchronous mode the list is guaranteed to be one buffer
     // deep, while in synchronous mode we use the oldest buffer.
-    err = acquireBufferLocked(&item, computeExpectedPresent(dispSync));
+    err = acquireBufferLocked(&item, computeExpectedPresent(dispSync),
+            maxFrameNumber);
     if (err != NO_ERROR) {
         if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
             err = NO_ERROR;
@@ -104,8 +105,9 @@
 }
 
 status_t SurfaceFlingerConsumer::acquireBufferLocked(BufferItem* item,
-        nsecs_t presentWhen) {
-    status_t result = GLConsumer::acquireBufferLocked(item, presentWhen);
+        nsecs_t presentWhen, uint64_t maxFrameNumber) {
+    status_t result = GLConsumer::acquireBufferLocked(item, presentWhen,
+            maxFrameNumber);
     if (result == NO_ERROR) {
         mTransformToDisplayInverse = item->mTransformToDisplayInverse;
         mSurfaceDamage = item->mSurfaceDamage;
@@ -125,10 +127,6 @@
     return mConsumer->getSidebandStream();
 }
 
-void SurfaceFlingerConsumer::setShadowQueueSize(size_t size) {
-    mConsumer->setShadowQueueSize(size);
-}
-
 // We need to determine the time when a buffer acquired now will be
 // displayed.  This can be calculated:
 //   time when previous buffer's actual-present fence was signaled
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index a90a8b9..779e5b7 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -49,13 +49,15 @@
         virtual ~BufferRejecter() { }
     };
 
-    virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen);
+    virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen,
+            uint64_t maxFrameNumber = 0) override;
 
     // This version of updateTexImage() takes a functor that may be used to
     // reject the newly acquired buffer.  Unlike the GLConsumer version,
     // this does not guarantee that the buffer has been bound to the GL
     // texture.
-    status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync);
+    status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync,
+            uint64_t maxFrameNumber = 0);
 
     // See GLConsumer::bindTextureImageLocked().
     status_t bindTextureImage();
@@ -70,9 +72,6 @@
 
     sp<NativeHandle> getSidebandStream() const;
 
-    // See IGraphicBufferConsumer::setShadowQueueSize
-    void setShadowQueueSize(size_t size);
-
     nsecs_t computeExpectedPresent(const DispSync& dispSync);
 
 private: