Merge "HardwareAPI: set enum basetypes for MediaImage2" into nyc-dev
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 3abd8f0..e15a0c5 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1279,14 +1279,6 @@
 
     dumpstate(do_early_screenshot ? "": screenshot_path, version);
 
-    /* done */
-    if (vibrator) {
-        for (int i = 0; i < 3; i++) {
-            vibrate(vibrator.get(), 75);
-            usleep((75 + 50) * 1000);
-        }
-    }
-
     /* close output if needed */
     if (is_redirecting) {
         fclose(stdout);
@@ -1335,6 +1327,17 @@
                 do_text_file = true;
             } else {
                 do_text_file = false;
+                // Since zip file is already created, it needs to be renamed.
+                std::string new_path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
+                if (path != new_path) {
+                    MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str());
+                    if (rename(path.c_str(), new_path.c_str())) {
+                        MYLOGE("rename(%s, %s): %s\n", path.c_str(),
+                                new_path.c_str(), strerror(errno));
+                    } else {
+                        path = new_path;
+                    }
+                }
             }
         }
         if (do_text_file) {
@@ -1347,6 +1350,14 @@
         }
     }
 
+    /* vibrate a few but shortly times to let user know it's finished */
+    if (vibrator) {
+        for (int i = 0; i < 3; i++) {
+            vibrate(vibrator.get(), 75);
+            usleep((75 + 50) * 1000);
+        }
+    }
+
     /* tell activity manager we're done */
     if (do_broadcast) {
         if (!path.empty()) {
diff --git a/data/etc/android.hardware.vulkan.level-0.xml b/data/etc/android.hardware.vulkan.level-0.xml
new file mode 100644
index 0000000..39c65ac
--- /dev/null
+++ b/data/etc/android.hardware.vulkan.level-0.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This is the standard feature indicating that the device supports Vulkan
+     hardware level 0. -->
+<permissions>
+    <feature name="android.hardware.vulkan.level" version="0" />
+</permissions>
diff --git a/data/etc/android.hardware.vulkan.level-1.xml b/data/etc/android.hardware.vulkan.level-1.xml
new file mode 100644
index 0000000..c3f5513
--- /dev/null
+++ b/data/etc/android.hardware.vulkan.level-1.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This is the standard feature indicating that the device supports Vulkan
+     hardware level 1. -->
+<permissions>
+    <feature name="android.hardware.vulkan.level" version="1" />
+</permissions>
diff --git a/data/etc/android.hardware.vulkan.version-1_0_3.xml b/data/etc/android.hardware.vulkan.version-1_0_3.xml
new file mode 100644
index 0000000..adc5a5d
--- /dev/null
+++ b/data/etc/android.hardware.vulkan.version-1_0_3.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This is the standard feature indicating that the device has a Vulkan
+     driver that supports API version 1.0.3 (0x00400003) -->
+<permissions>
+    <feature name="android.hardware.vulkan.version" version="4194307" />
+</permissions>
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index d10ba2f..2645d09 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -32,6 +32,7 @@
 
 #include <list>
 #include <set>
+#include <vector>
 
 #define BQ_LOGV(x, ...) ALOGV("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
 #define BQ_LOGD(x, ...) ALOGD("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
@@ -120,8 +121,9 @@
     void freeAllBuffersLocked();
 
     // If delta is positive, makes more slots available. If negative, takes
-    // away slots. Returns false if the request can't be met.
-    bool adjustAvailableSlotsLocked(int delta);
+    // away slots. Returns false if the request can't be met. Any slots that
+    // were freed will be appended to freedSlots.
+    bool adjustAvailableSlotsLocked(int delta, std::vector<int>* freedSlots);
 
     // waitWhileAllocatingLocked blocks until mIsAllocating is false.
     void waitWhileAllocatingLocked() const;
diff --git a/include/gui/IProducerListener.h b/include/gui/IProducerListener.h
index 3848a6c..895da4b 100644
--- a/include/gui/IProducerListener.h
+++ b/include/gui/IProducerListener.h
@@ -41,6 +41,9 @@
     // This is called without any lock held and can be called concurrently by
     // multiple threads.
     virtual void onBufferReleased() = 0; // Asynchronous
+
+    // onSlotFreed is called when the BufferQueue frees a buffer in a slot.
+    virtual void onSlotFreed(int /*slot*/) {}; // Asynchronous
 };
 
 class IProducerListener : public ProducerListener, public IInterface
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index e4d8201..9a061a0 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -28,7 +28,7 @@
 
 static const sp<IBinder>& getToken(const sp<IAppOpsService>& service) {
     pthread_mutex_lock(&gTokenMutex);
-    if (gToken == NULL) {
+    if (gToken == NULL || gToken->pingBinder() != NO_ERROR) {
         gToken = service->getToken(new BBinder());
     }
     pthread_mutex_unlock(&gTokenMutex);
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 4029496..aacbed5 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -277,35 +277,51 @@
     ATRACE_CALL();
     ATRACE_BUFFER_INDEX(slot);
     BQ_LOGV("detachBuffer: slot %d", slot);
-    Mutex::Autolock lock(mCore->mMutex);
 
-    if (mCore->mIsAbandoned) {
-        BQ_LOGE("detachBuffer: BufferQueue has been abandoned");
-        return NO_INIT;
+    sp<IConsumerListener> consumerListener;
+    sp<IProducerListener> producerListener;
+    {
+        Mutex::Autolock lock(mCore->mMutex);
+
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("detachBuffer: BufferQueue has been abandoned");
+            return NO_INIT;
+        }
+
+        if (mCore->mSingleBufferMode || slot == mCore->mSingleBufferSlot) {
+            BQ_LOGE("detachBuffer: detachBuffer not allowed in single buffer"
+                    "mode");
+            return BAD_VALUE;
+        }
+
+        if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
+            BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)",
+                    slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
+            return BAD_VALUE;
+        } else if (!mSlots[slot].mBufferState.isAcquired()) {
+            BQ_LOGE("detachBuffer: slot %d is not owned by the consumer "
+                    "(state = %s)", slot, mSlots[slot].mBufferState.string());
+            return BAD_VALUE;
+        }
+
+        mSlots[slot].mBufferState.detachConsumer();
+        mCore->mActiveBuffers.erase(slot);
+        mCore->mFreeSlots.insert(slot);
+        mCore->clearBufferSlotLocked(slot);
+        mCore->mDequeueCondition.broadcast();
+        VALIDATE_CONSISTENCY();
+        producerListener = mCore->mConnectedProducerListener;
+        consumerListener = mCore->mConsumerListener;
     }
 
-    if (mCore->mSingleBufferMode || slot == mCore->mSingleBufferSlot) {
-        BQ_LOGE("detachBuffer: detachBuffer not allowed in single buffer"
-                "mode");
-        return BAD_VALUE;
+    // Call back without lock held
+    if (producerListener != NULL) {
+        producerListener->onSlotFreed(slot);
+    }
+    if (consumerListener != NULL) {
+        consumerListener->onBuffersReleased();
     }
 
-    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
-        BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)",
-                slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
-        return BAD_VALUE;
-    } else if (!mSlots[slot].mBufferState.isAcquired()) {
-        BQ_LOGE("detachBuffer: slot %d is not owned by the consumer "
-                "(state = %s)", slot, mSlots[slot].mBufferState.string());
-        return BAD_VALUE;
-    }
-
-    mSlots[slot].mBufferState.detachConsumer();
-    mCore->mActiveBuffers.erase(slot);
-    mCore->mFreeSlots.insert(slot);
-    mCore->clearBufferSlotLocked(slot);
-    mCore->mDequeueCondition.broadcast();
-    VALIDATE_CONSISTENCY();
 
     return NO_ERROR;
 }
@@ -576,30 +592,40 @@
         return BAD_VALUE;
     }
 
-    Mutex::Autolock lock(mCore->mMutex);
+    sp<IConsumerListener> listener;
+    {
+        Mutex::Autolock lock(mCore->mMutex);
+        if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
+            BQ_LOGE("setMaxBufferCount: producer is already connected");
+            return INVALID_OPERATION;
+        }
 
-    if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
-        BQ_LOGE("setMaxBufferCount: producer is already connected");
-        return INVALID_OPERATION;
+        if (bufferCount < mCore->mMaxAcquiredBufferCount) {
+            BQ_LOGE("setMaxBufferCount: invalid buffer count (%d) less than"
+                    "mMaxAcquiredBufferCount (%d)", bufferCount,
+                    mCore->mMaxAcquiredBufferCount);
+            return BAD_VALUE;
+        }
+
+        int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode,
+                mCore->mDequeueBufferCannotBlock, bufferCount) -
+                mCore->getMaxBufferCountLocked();
+        if (!mCore->adjustAvailableSlotsLocked(delta, nullptr)) {
+            BQ_LOGE("setMaxBufferCount: BufferQueue failed to adjust the number"
+                    " of available slots. Delta = %d", delta);
+            return BAD_VALUE;
+        }
+
+        mCore->mMaxBufferCount = bufferCount;
+        if (delta < 0) {
+            listener = mCore->mConsumerListener;
+        }
     }
 
-    if (bufferCount < mCore->mMaxAcquiredBufferCount) {
-        BQ_LOGE("setMaxBufferCount: invalid buffer count (%d) less than"
-                "mMaxAcquiredBufferCount (%d)", bufferCount,
-                mCore->mMaxAcquiredBufferCount);
-        return BAD_VALUE;
+    // Call back without lock held
+    if (listener != NULL) {
+        listener->onBuffersReleased();
     }
-
-    int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode,
-            mCore->mDequeueBufferCannotBlock, bufferCount) -
-            mCore->getMaxBufferCountLocked();
-    if (!mCore->adjustAvailableSlotsLocked(delta)) {
-        BQ_LOGE("setMaxBufferCount: BufferQueue failed to adjust the number of "
-                "available slots. Delta = %d", delta);
-        return BAD_VALUE;
-    }
-
-    mCore->mMaxBufferCount = bufferCount;
     return NO_ERROR;
 }
 
@@ -614,7 +640,9 @@
         return BAD_VALUE;
     }
 
-    sp<IConsumerListener> listener;
+    sp<IConsumerListener> consumerListener;
+    sp<IProducerListener> producerListener;
+    std::vector<int> freedSlots;
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
         mCore->waitWhileAllocatingLocked();
@@ -651,7 +679,7 @@
         }
 
         int delta = maxAcquiredBuffers - mCore->mMaxAcquiredBufferCount;
-        if (!mCore->adjustAvailableSlotsLocked(delta)) {
+        if (!mCore->adjustAvailableSlotsLocked(delta, &freedSlots)) {
             return BAD_VALUE;
         }
 
@@ -659,12 +687,19 @@
         mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers;
         VALIDATE_CONSISTENCY();
         if (delta < 0) {
-            listener = mCore->mConsumerListener;
+            consumerListener = mCore->mConsumerListener;
+            producerListener = mCore->mConnectedProducerListener;
         }
     }
+
     // Call back without lock held
-    if (listener != NULL) {
-        listener->onBuffersReleased();
+    if (consumerListener != NULL) {
+        consumerListener->onBuffersReleased();
+    }
+    if (producerListener != NULL) {
+        for (int i : freedSlots) {
+            producerListener->onSlotFreed(i);
+        }
     }
 
     return NO_ERROR;
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index ba07362..fc3ffed 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -226,7 +226,8 @@
     VALIDATE_CONSISTENCY();
 }
 
-bool BufferQueueCore::adjustAvailableSlotsLocked(int delta) {
+bool BufferQueueCore::adjustAvailableSlotsLocked(int delta,
+        std::vector<int>* freedSlots) {
     if (delta >= 0) {
         // If we're going to fail, do so before modifying anything
         if (delta > static_cast<int>(mUnusedSlots.size())) {
@@ -253,11 +254,17 @@
                 clearBufferSlotLocked(*slot);
                 mUnusedSlots.push_back(*slot);
                 mFreeSlots.erase(slot);
+                if (freedSlots) {
+                    freedSlots->push_back(*slot);
+                }
             } else if (!mFreeBuffers.empty()) {
                 int slot = mFreeBuffers.back();
                 clearBufferSlotLocked(slot);
                 mUnusedSlots.push_back(slot);
                 mFreeBuffers.pop_back();
+                if (freedSlots) {
+                    freedSlots->push_back(slot);
+                }
             } else {
                 return false;
             }
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 17d4a2c..cb5d773 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -90,7 +90,9 @@
     BQ_LOGV("setMaxDequeuedBufferCount: maxDequeuedBuffers = %d",
             maxDequeuedBuffers);
 
-    sp<IConsumerListener> listener;
+    sp<IConsumerListener> consumerListener;
+    sp<IProducerListener> producerListener;
+    std::vector<int> freedSlots;
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
         mCore->waitWhileAllocatingLocked();
@@ -142,20 +144,26 @@
         }
 
         int delta = maxDequeuedBuffers - mCore->mMaxDequeuedBufferCount;
-        if (!mCore->adjustAvailableSlotsLocked(delta)) {
+        if (!mCore->adjustAvailableSlotsLocked(delta, &freedSlots)) {
             return BAD_VALUE;
         }
         mCore->mMaxDequeuedBufferCount = maxDequeuedBuffers;
         VALIDATE_CONSISTENCY();
         if (delta < 0) {
-            listener = mCore->mConsumerListener;
+            consumerListener = mCore->mConsumerListener;
+            producerListener = mCore->mConnectedProducerListener;
         }
         mCore->mDequeueCondition.broadcast();
     } // Autolock scope
 
     // Call back without lock held
-    if (listener != NULL) {
-        listener->onBuffersReleased();
+    if (consumerListener != NULL) {
+        consumerListener->onBuffersReleased();
+    }
+    if (producerListener != NULL) {
+        for (int i : freedSlots) {
+            producerListener->onSlotFreed(i);
+        }
     }
 
     return NO_ERROR;
@@ -165,7 +173,9 @@
     ATRACE_CALL();
     BQ_LOGV("setAsyncMode: async = %d", async);
 
-    sp<IConsumerListener> listener;
+    sp<IConsumerListener> consumerListener;
+    sp<IProducerListener> producerListener;
+    std::vector<int> freedSlots;
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
         mCore->waitWhileAllocatingLocked();
@@ -191,7 +201,7 @@
                 mCore->mDequeueBufferCannotBlock, mCore->mMaxBufferCount)
                 - mCore->getMaxBufferCountLocked();
 
-        if (!mCore->adjustAvailableSlotsLocked(delta)) {
+        if (!mCore->adjustAvailableSlotsLocked(delta, &freedSlots)) {
             BQ_LOGE("setAsyncMode: BufferQueue failed to adjust the number of "
                     "available slots. Delta = %d", delta);
             return BAD_VALUE;
@@ -199,12 +209,20 @@
         mCore->mAsyncMode = async;
         VALIDATE_CONSISTENCY();
         mCore->mDequeueCondition.broadcast();
-        listener = mCore->mConsumerListener;
+        if (delta < 0) {
+            consumerListener = mCore->mConsumerListener;
+            producerListener = mCore->mConnectedProducerListener;
+        }
     } // Autolock scope
 
     // Call back without lock held
-    if (listener != NULL) {
-        listener->onBuffersReleased();
+    if (consumerListener != NULL) {
+        consumerListener->onBuffersReleased();
+    }
+    if (producerListener != NULL) {
+        for (int i : freedSlots) {
+            producerListener->onSlotFreed(i);
+        }
     }
     return NO_ERROR;
 }
@@ -361,6 +379,9 @@
     EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
     bool attachedByConsumer = false;
 
+    sp<IConsumerListener> consumerListener;
+    sp<IProducerListener> producerListener;
+    int found = BufferItem::INVALID_BUFFER_SLOT;
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
         mCore->waitWhileAllocatingLocked();
@@ -378,7 +399,6 @@
             height = mCore->mDefaultHeight;
         }
 
-        int found = BufferItem::INVALID_BUFFER_SLOT;
         while (found == BufferItem::INVALID_BUFFER_SLOT) {
             status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue,
                     &found);
@@ -408,6 +428,8 @@
                     mCore->mFreeSlots.insert(found);
                     mCore->clearBufferSlotLocked(found);
                     found = BufferItem::INVALID_BUFFER_SLOT;
+                    consumerListener = mCore->mConsumerListener;
+                    producerListener = mCore->mConnectedProducerListener;
                     continue;
                 }
             }
@@ -444,6 +466,10 @@
         if ((buffer == NULL) ||
                 buffer->needsReallocation(width, height, format, usage))
         {
+            if (buffer != NULL) {
+                consumerListener = mCore->mConsumerListener;
+                producerListener = mCore->mConnectedProducerListener;
+            }
             mSlots[found].mAcquireCalled = false;
             mSlots[found].mGraphicBuffer = NULL;
             mSlots[found].mRequestBufferCalled = false;
@@ -531,6 +557,14 @@
             mSlots[*outSlot].mFrameNumber,
             mSlots[*outSlot].mGraphicBuffer->handle, returnFlags);
 
+    // Call back without lock held
+    if (consumerListener != NULL) {
+        consumerListener->onBuffersReleased();
+    }
+    if (producerListener != NULL) {
+        producerListener->onSlotFreed(found);
+    }
+
     return returnFlags;
 }
 
@@ -538,44 +572,60 @@
     ATRACE_CALL();
     ATRACE_BUFFER_INDEX(slot);
     BQ_LOGV("detachBuffer: slot %d", slot);
-    Mutex::Autolock lock(mCore->mMutex);
 
-    if (mCore->mIsAbandoned) {
-        BQ_LOGE("detachBuffer: BufferQueue has been abandoned");
-        return NO_INIT;
+    sp<IConsumerListener> consumerListener;
+    sp<IProducerListener> producerListener;
+    {
+        Mutex::Autolock lock(mCore->mMutex);
+
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("detachBuffer: BufferQueue has been abandoned");
+            return NO_INIT;
+        }
+
+        if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+            BQ_LOGE("detachBuffer: BufferQueue has no connected producer");
+            return NO_INIT;
+        }
+
+        if (mCore->mSingleBufferMode || mCore->mSingleBufferSlot == slot) {
+            BQ_LOGE("detachBuffer: cannot detach a buffer in single buffer "
+                    "mode");
+            return BAD_VALUE;
+        }
+
+        if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
+            BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)",
+                    slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
+            return BAD_VALUE;
+        } else if (!mSlots[slot].mBufferState.isDequeued()) {
+            BQ_LOGE("detachBuffer: slot %d is not owned by the producer "
+                    "(state = %s)", slot, mSlots[slot].mBufferState.string());
+            return BAD_VALUE;
+        } else if (!mSlots[slot].mRequestBufferCalled) {
+            BQ_LOGE("detachBuffer: buffer in slot %d has not been requested",
+                    slot);
+            return BAD_VALUE;
+        }
+
+        mSlots[slot].mBufferState.detachProducer();
+        mCore->mActiveBuffers.erase(slot);
+        mCore->mFreeSlots.insert(slot);
+        mCore->clearBufferSlotLocked(slot);
+        mCore->mDequeueCondition.broadcast();
+        VALIDATE_CONSISTENCY();
+        producerListener = mCore->mConnectedProducerListener;
+        consumerListener = mCore->mConsumerListener;
     }
 
-    if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
-        BQ_LOGE("detachBuffer: BufferQueue has no connected producer");
-        return NO_INIT;
+    // Call back without lock held
+    if (consumerListener != NULL) {
+        consumerListener->onBuffersReleased();
     }
-
-    if (mCore->mSingleBufferMode || mCore->mSingleBufferSlot == slot) {
-        BQ_LOGE("detachBuffer: cannot detach a buffer in single buffer mode");
-        return BAD_VALUE;
+    if (producerListener != NULL) {
+        producerListener->onSlotFreed(slot);
     }
 
-    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
-        BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)",
-                slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
-        return BAD_VALUE;
-    } else if (!mSlots[slot].mBufferState.isDequeued()) {
-        BQ_LOGE("detachBuffer: slot %d is not owned by the producer "
-                "(state = %s)", slot, mSlots[slot].mBufferState.string());
-        return BAD_VALUE;
-    } else if (!mSlots[slot].mRequestBufferCalled) {
-        BQ_LOGE("detachBuffer: buffer in slot %d has not been requested",
-                slot);
-        return BAD_VALUE;
-    }
-
-    mSlots[slot].mBufferState.detachProducer();
-    mCore->mActiveBuffers.erase(slot);
-    mCore->mFreeSlots.insert(slot);
-    mCore->clearBufferSlotLocked(slot);
-    mCore->mDequeueCondition.broadcast();
-    VALIDATE_CONSISTENCY();
-
     return NO_ERROR;
 }
 
@@ -591,41 +641,55 @@
         return BAD_VALUE;
     }
 
-    Mutex::Autolock lock(mCore->mMutex);
+    sp<IConsumerListener> consumerListener;
+    sp<IProducerListener> producerListener;
+    int found = BufferQueueCore::INVALID_BUFFER_SLOT;
+    {
+        Mutex::Autolock lock(mCore->mMutex);
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
+            return NO_INIT;
+        }
 
-    if (mCore->mIsAbandoned) {
-        BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
-        return NO_INIT;
+        if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+            BQ_LOGE("detachNextBuffer: BufferQueue has no connected producer");
+            return NO_INIT;
+        }
+
+        if (mCore->mSingleBufferMode) {
+            BQ_LOGE("detachNextBuffer: cannot detach a buffer in single buffer"
+                    "mode");
+            return BAD_VALUE;
+        }
+
+        mCore->waitWhileAllocatingLocked();
+
+        if (mCore->mFreeBuffers.empty()) {
+            return NO_MEMORY;
+        }
+
+        found = mCore->mFreeBuffers.front();
+        mCore->mFreeBuffers.remove(found);
+        mCore->mFreeSlots.insert(found);
+
+        BQ_LOGV("detachNextBuffer detached slot %d", found);
+
+        *outBuffer = mSlots[found].mGraphicBuffer;
+        *outFence = mSlots[found].mFence;
+        mCore->clearBufferSlotLocked(found);
+        VALIDATE_CONSISTENCY();
+        consumerListener = mCore->mConsumerListener;
+        producerListener = mCore->mConnectedProducerListener;
     }
 
-    if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
-        BQ_LOGE("detachNextBuffer: BufferQueue has no connected producer");
-        return NO_INIT;
+    // Call back without lock held
+    if (consumerListener != NULL) {
+        consumerListener->onBuffersReleased();
     }
-
-    if (mCore->mSingleBufferMode) {
-        BQ_LOGE("detachNextBuffer: cannot detach a buffer in single buffer"
-                "mode");
-        return BAD_VALUE;
+    if (producerListener != NULL) {
+        producerListener->onSlotFreed(found);
     }
 
-    mCore->waitWhileAllocatingLocked();
-
-    if (mCore->mFreeBuffers.empty()) {
-        return NO_MEMORY;
-    }
-
-    int found = mCore->mFreeBuffers.front();
-    mCore->mFreeBuffers.remove(found);
-    mCore->mFreeSlots.insert(found);
-
-    BQ_LOGV("detachNextBuffer detached slot %d", found);
-
-    *outBuffer = mSlots[found].mGraphicBuffer;
-    *outFence = mSlots[found].mFence;
-    mCore->clearBufferSlotLocked(found);
-    VALIDATE_CONSISTENCY();
-
     return NO_ERROR;
 }
 
@@ -1020,82 +1084,102 @@
 status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
         int api, bool producerControlledByApp, QueueBufferOutput *output) {
     ATRACE_CALL();
-    Mutex::Autolock lock(mCore->mMutex);
-    mConsumerName = mCore->mConsumerName;
-    BQ_LOGV("connect: api=%d producerControlledByApp=%s", api,
-            producerControlledByApp ? "true" : "false");
-
-    if (mCore->mIsAbandoned) {
-        BQ_LOGE("connect: BufferQueue has been abandoned");
-        return NO_INIT;
-    }
-
-    if (mCore->mConsumerListener == NULL) {
-        BQ_LOGE("connect: BufferQueue has no consumer");
-        return NO_INIT;
-    }
-
-    if (output == NULL) {
-        BQ_LOGE("connect: output was NULL");
-        return BAD_VALUE;
-    }
-
-    if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
-        BQ_LOGE("connect: already connected (cur=%d req=%d)",
-                mCore->mConnectedApi, api);
-        return BAD_VALUE;
-    }
-
-    int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode,
-            mDequeueTimeout < 0 ?
-            mCore->mConsumerControlledByApp && producerControlledByApp : false,
-            mCore->mMaxBufferCount) -
-            mCore->getMaxBufferCountLocked();
-    if (!mCore->adjustAvailableSlotsLocked(delta)) {
-        BQ_LOGE("connect: BufferQueue failed to adjust the number of available "
-                "slots. Delta = %d", delta);
-        return BAD_VALUE;
-    }
-
     int status = NO_ERROR;
-    switch (api) {
-        case NATIVE_WINDOW_API_EGL:
-        case NATIVE_WINDOW_API_CPU:
-        case NATIVE_WINDOW_API_MEDIA:
-        case NATIVE_WINDOW_API_CAMERA:
-            mCore->mConnectedApi = api;
-            output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight,
-                    mCore->mTransformHint,
-                    static_cast<uint32_t>(mCore->mQueue.size()));
+    sp<IConsumerListener> consumerListener;
+    sp<IProducerListener> producerListener;
+    std::vector<int> freedSlots;
+    {
+        Mutex::Autolock lock(mCore->mMutex);
+        mConsumerName = mCore->mConsumerName;
+        BQ_LOGV("connect: api=%d producerControlledByApp=%s", api,
+                producerControlledByApp ? "true" : "false");
 
-            // Set up a death notification so that we can disconnect
-            // automatically if the remote producer dies
-            if (listener != NULL &&
-                    IInterface::asBinder(listener)->remoteBinder() != NULL) {
-                status = IInterface::asBinder(listener)->linkToDeath(
-                        static_cast<IBinder::DeathRecipient*>(this));
-                if (status != NO_ERROR) {
-                    BQ_LOGE("connect: linkToDeath failed: %s (%d)",
-                            strerror(-status), status);
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("connect: BufferQueue has been abandoned");
+            return NO_INIT;
+        }
+
+        if (mCore->mConsumerListener == NULL) {
+            BQ_LOGE("connect: BufferQueue has no consumer");
+            return NO_INIT;
+        }
+
+        if (output == NULL) {
+            BQ_LOGE("connect: output was NULL");
+            return BAD_VALUE;
+        }
+
+        if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
+            BQ_LOGE("connect: already connected (cur=%d req=%d)",
+                    mCore->mConnectedApi, api);
+            return BAD_VALUE;
+        }
+
+        bool dequeueBufferCannotBlock = mDequeueTimeout < 0 ?
+                mCore->mConsumerControlledByApp && producerControlledByApp :
+                false;
+        int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode,
+                dequeueBufferCannotBlock, mCore->mMaxBufferCount) -
+                mCore->getMaxBufferCountLocked();
+
+        if (!mCore->adjustAvailableSlotsLocked(delta, &freedSlots)) {
+            BQ_LOGE("connect: BufferQueue failed to adjust the number of "
+                    "available slots. Delta = %d", delta);
+            return BAD_VALUE;
+        }
+
+        switch (api) {
+            case NATIVE_WINDOW_API_EGL:
+            case NATIVE_WINDOW_API_CPU:
+            case NATIVE_WINDOW_API_MEDIA:
+            case NATIVE_WINDOW_API_CAMERA:
+                mCore->mConnectedApi = api;
+                output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight,
+                        mCore->mTransformHint,
+                        static_cast<uint32_t>(mCore->mQueue.size()));
+
+                // Set up a death notification so that we can disconnect
+                // automatically if the remote producer dies
+                if (listener != NULL &&
+                        IInterface::asBinder(listener)->remoteBinder() !=
+                        NULL) {
+                    status = IInterface::asBinder(listener)->linkToDeath(
+                            static_cast<IBinder::DeathRecipient*>(this));
+                    if (status != NO_ERROR) {
+                        BQ_LOGE("connect: linkToDeath failed: %s (%d)",
+                                strerror(-status), status);
+                    }
                 }
-            }
-            mCore->mConnectedProducerListener = listener;
-            break;
-        default:
-            BQ_LOGE("connect: unknown API %d", api);
-            status = BAD_VALUE;
-            break;
+                mCore->mConnectedProducerListener = listener;
+                break;
+            default:
+                BQ_LOGE("connect: unknown API %d", api);
+                status = BAD_VALUE;
+                break;
+        }
+
+        mCore->mBufferHasBeenQueued = false;
+        mCore->mDequeueBufferCannotBlock = dequeueBufferCannotBlock;
+
+        mCore->mAllowAllocation = true;
+        VALIDATE_CONSISTENCY();
+
+        if (delta < 0) {
+            consumerListener = mCore->mConsumerListener;
+            producerListener = listener;
+        }
     }
 
-    mCore->mBufferHasBeenQueued = false;
-    mCore->mDequeueBufferCannotBlock = false;
-    if (mDequeueTimeout < 0) {
-        mCore->mDequeueBufferCannotBlock =
-                mCore->mConsumerControlledByApp && producerControlledByApp;
+    // Call back without lock held
+    if (consumerListener != NULL) {
+        consumerListener->onBuffersReleased();
+    }
+    if (producerListener != NULL) {
+        for (int i : freedSlots) {
+            producerListener->onSlotFreed(i);
+        }
     }
 
-    mCore->mAllowAllocation = true;
-    VALIDATE_CONSISTENCY();
     return status;
 }
 
@@ -1323,19 +1407,40 @@
     ATRACE_CALL();
     BQ_LOGV("setDequeueTimeout: %" PRId64, timeout);
 
-    Mutex::Autolock lock(mCore->mMutex);
-    int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode, false,
-            mCore->mMaxBufferCount) - mCore->getMaxBufferCountLocked();
-    if (!mCore->adjustAvailableSlotsLocked(delta)) {
-        BQ_LOGE("setDequeueTimeout: BufferQueue failed to adjust the number of "
-                "available slots. Delta = %d", delta);
-        return BAD_VALUE;
+    sp<IConsumerListener> consumerListener;
+    sp<IProducerListener> producerListener;
+    std::vector<int> freedSlots;
+    {
+        Mutex::Autolock lock(mCore->mMutex);
+        int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode, false,
+                mCore->mMaxBufferCount) - mCore->getMaxBufferCountLocked();
+        if (!mCore->adjustAvailableSlotsLocked(delta, &freedSlots)) {
+            BQ_LOGE("setDequeueTimeout: BufferQueue failed to adjust the number"
+                    " of available slots. Delta = %d", delta);
+            return BAD_VALUE;
+        }
+
+        mDequeueTimeout = timeout;
+        mCore->mDequeueBufferCannotBlock = false;
+
+        VALIDATE_CONSISTENCY();
+
+        if (delta < 0) {
+            consumerListener = mCore->mConsumerListener;
+            producerListener = mCore->mConnectedProducerListener;
+        }
     }
 
-    mDequeueTimeout = timeout;
-    mCore->mDequeueBufferCannotBlock = false;
+    // Call back without lock held
+    if (consumerListener != NULL) {
+        consumerListener->onBuffersReleased();
+    }
+    if (producerListener != NULL) {
+        for (int i : freedSlots) {
+            producerListener->onSlotFreed(i);
+        }
+    }
 
-    VALIDATE_CONSISTENCY();
     return NO_ERROR;
 }
 
diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp
index 81adc95..39c1da8 100644
--- a/libs/gui/IProducerListener.cpp
+++ b/libs/gui/IProducerListener.cpp
@@ -22,6 +22,7 @@
 
 enum {
     ON_BUFFER_RELEASED = IBinder::FIRST_CALL_TRANSACTION,
+    ON_SLOT_FREED,
 };
 
 class BpProducerListener : public BpInterface<IProducerListener>
@@ -37,6 +38,17 @@
         data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
         remote()->transact(ON_BUFFER_RELEASED, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    virtual void onSlotFreed(int slot) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
+        data.writeInt32(slot);
+        status_t err = remote()->transact(ON_SLOT_FREED, data, &reply,
+                IBinder::FLAG_ONEWAY);
+        if (err != NO_ERROR) {
+            ALOGE("onSlotFreed failed to transact %d", err);
+        }
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -52,6 +64,12 @@
             CHECK_INTERFACE(IProducerListener, data, reply);
             onBufferReleased();
             return NO_ERROR;
+        case ON_SLOT_FREED: {
+            CHECK_INTERFACE(IProducerListener, data, reply);
+            int slot = data.readInt32();
+            onSlotFreed(slot);
+            return NO_ERROR;
+        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index 45b6463..fad0baa 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -727,4 +727,55 @@
     ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer));
 }
 
+struct TestListener : public BnProducerListener {
+    virtual void onBufferReleased() {}
+    virtual void onSlotFreed(int slot) {
+        ASSERT_EQ(1, slot);
+    }
+};
+
+TEST_F(IGraphicBufferProducerTest, SlotFreedListenerReturnsCorrectSlot) {
+    const ::testing::TestInfo* const testInfo =
+        ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGV("Begin test: %s.%s", testInfo->test_case_name(),
+            testInfo->name());
+
+    BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+
+    sp<DummyConsumer> consumerListener = new DummyConsumer;
+    ASSERT_OK(mConsumer->consumerConnect(consumerListener, false));
+
+    sp<TestListener> producerListener = new TestListener;
+    IGraphicBufferProducer::QueueBufferOutput output;
+    ASSERT_OK(mProducer->connect(producerListener, TEST_API,
+            TEST_CONTROLLED_BY_APP, &output));
+
+    ASSERT_OK(mProducer->setMaxDequeuedBufferCount(2));
+
+    DequeueBufferResult buffer0;
+    sp<GraphicBuffer> buf;
+    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+            dequeueBuffer(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
+            TEST_PRODUCER_USAGE_BITS, &buffer0));
+    ASSERT_OK(mProducer->requestBuffer(buffer0.slot, &buf));
+
+    DequeueBufferResult buffer1;
+    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+            dequeueBuffer(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
+            TEST_PRODUCER_USAGE_BITS, &buffer1));
+
+    IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
+    ASSERT_OK(mProducer->queueBuffer(buffer0.slot, input, &output));
+
+    DequeueBufferResult buffer2;
+    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+            dequeueBuffer(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
+            TEST_PRODUCER_USAGE_BITS, &buffer2));
+
+    ASSERT_OK(mProducer->cancelBuffer(buffer1.slot, Fence::NO_FENCE));
+
+    ASSERT_OK(mProducer->setMaxDequeuedBufferCount(1));
+}
+
+
 } // namespace android
diff --git a/opengl/tools/glgen/specs/gles11/GLES30.spec b/opengl/tools/glgen/specs/gles11/GLES30.spec
index a426eb0..f190fc0 100644
--- a/opengl/tools/glgen/specs/gles11/GLES30.spec
+++ b/opengl/tools/glgen/specs/gles11/GLES30.spec
@@ -108,3 +108,4 @@
 void glTexStorage2D ( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height )
 void glTexStorage3D ( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth )
 void glGetInternalformativ ( GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params )
+void glReadPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint offset )
diff --git a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp
index 47f232d..aa0d2a4 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp
@@ -118,22 +118,35 @@
 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) {
+    jniThrowException(_env, "java/lang/UnsupportedOperationException", "deprecated");
+}
+
+/* void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) */
+static void
+android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2
+  (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jobject name_buf) {
     jintArray _lengthArray = (jintArray) 0;
     jint _lengthBufferOffset = (jint) 0;
     jintArray _sizeArray = (jintArray) 0;
     jint _sizeBufferOffset = (jint) 0;
     jintArray _typeArray = (jintArray) 0;
     jint _typeBufferOffset = (jint) 0;
+    jbyteArray _nameArray = (jbyteArray)0;
+    jint _nameBufferOffset = (jint)0;
     jint _lengthRemaining;
     GLsizei *length = (GLsizei *) 0;
     jint _sizeRemaining;
     GLint *size = (GLint *) 0;
     jint _typeRemaining;
     GLenum *type = (GLenum *) 0;
+    jint _nameRemaining;
+    GLchar* name = (GLchar*)0;
+
 
     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);
+    name = (GLchar*)getPointer(_env, name_buf, (jarray*)&_nameArray, &_nameRemaining, &_nameBufferOffset);
     if (length == NULL) {
         char * _lengthBase = (char *)_env->GetIntArrayElements(_lengthArray, (jboolean *) 0);
         length = (GLsizei *) (_lengthBase + _lengthBufferOffset);
@@ -146,6 +159,10 @@
         char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0);
         type = (GLenum *) (_typeBase + _typeBufferOffset);
     }
+    if (name == NULL) {
+        char* _nameBase = (char *)_env->GetByteArrayElements(_nameArray, (jboolean*)0);
+        name = (GLchar *) (_nameBase + _nameBufferOffset);
+    }
     glGetTransformFeedbackVarying(
         (GLuint)program,
         (GLuint)index,
@@ -153,11 +170,7 @@
         (GLsizei *)length,
         (GLint *)size,
         (GLenum *)type,
-        // The cast below is incorrect. The driver will end up writing to the
-        // address specified by name, which will always crash the process since
-        // it is guaranteed to be in low memory. The additional static_cast
-        // suppresses the warning for now. http://b/19478262
-        (char *)static_cast<uintptr_t>(name)
+        (GLchar*)name
     );
     if (_typeArray) {
         releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE);
@@ -168,6 +181,9 @@
     if (_lengthArray) {
         releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _lengthArray, (jint*)length, JNI_TRUE);
     }
+    if (_nameArray) {
+        releaseArrayPointer<jbyteArray, jbyte*, ByteArrayReleaser>(_env, _nameArray, (jbyte*)name, JNI_TRUE);
+    }
 }
 
 /* void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) */
diff --git a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.java b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.java
index f73bbfe..e54359d 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.java
+++ b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.java
@@ -15,7 +15,10 @@
     );
 
     // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
-
+    /**
+     * @deprecated
+     * Use the version that takes a ByteBuffer as the last argument, or the versions that return a String.
+     * */
     public static native void glGetTransformFeedbackVarying(
         int program,
         int index,
@@ -28,6 +31,18 @@
 
     // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
 
+    public static native void glGetTransformFeedbackVarying(
+        int program,
+        int index,
+        int bufsize,
+        java.nio.IntBuffer length,
+        java.nio.IntBuffer size,
+        java.nio.IntBuffer type,
+        java.nio.ByteBuffer name
+    );
+
+    // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
+
     public static native String glGetTransformFeedbackVarying(
         int program,
         int index,
diff --git a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.nativeReg b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.nativeReg
index 412d04c..7f5829b 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.nativeReg
+++ b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.nativeReg
@@ -1,4 +1,5 @@
 {"glGetTransformFeedbackVarying", "(III[II[II[II[BI)V", (void *) android_glGetTransformFeedbackVarying__III_3II_3II_3II_3BI },
 {"glGetTransformFeedbackVarying", "(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;B)V", (void *) android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B },
+{"glGetTransformFeedbackVarying", "(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/ByteBuffer;)V", (void *) android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2 },
 {"glGetTransformFeedbackVarying", "(II[II[II)Ljava/lang/String;", (void *) android_glGetTransformFeedbackVarying1 },
 {"glGetTransformFeedbackVarying", "(IILjava/nio/IntBuffer;Ljava/nio/IntBuffer;)Ljava/lang/String;", (void *) android_glGetTransformFeedbackVarying2 },
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index bdf8f74..e9cbbca 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -82,7 +82,6 @@
       mFlags(),
       mPageFlipCount(),
       mIsSecure(isSecure),
-      mSecureLayerVisible(false),
       mLayerStack(NO_LAYER_STACK),
       mOrientation(),
       mPowerMode(HWC_POWER_MODE_OFF),
@@ -307,24 +306,12 @@
 
 void DisplayDevice::setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers) {
     mVisibleLayersSortedByZ = layers;
-    mSecureLayerVisible = false;
-    size_t count = layers.size();
-    for (size_t i=0 ; i<count ; i++) {
-        const sp<Layer>& layer(layers[i]);
-        if (layer->isSecure()) {
-            mSecureLayerVisible = true;
-        }
-    }
 }
 
 const Vector< sp<Layer> >& DisplayDevice::getVisibleLayersSortedByZ() const {
     return mVisibleLayersSortedByZ;
 }
 
-bool DisplayDevice::getSecureLayerVisible() const {
-    return mSecureLayerVisible;
-}
-
 Region DisplayDevice::getDirtyRegion(bool repaintEverything) const {
     Region dirty;
     if (repaintEverything) {
@@ -506,13 +493,13 @@
     result.appendFormat(
         "+ DisplayDevice: %s\n"
         "   type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p, orient=%2d (type=%08x), "
-        "flips=%u, isSecure=%d, secureVis=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n"
+        "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n"
         "   v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
         "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n",
         mDisplayName.string(), mType, mHwcDisplayId,
         mLayerStack, mDisplayWidth, mDisplayHeight, mNativeWindow.get(),
         mOrientation, tr.getType(), getPageFlipCount(),
-        mIsSecure, mSecureLayerVisible, mPowerMode, mActiveConfig,
+        mIsSecure, mPowerMode, mActiveConfig,
         mVisibleLayersSortedByZ.size(),
         mViewport.left, mViewport.top, mViewport.right, mViewport.bottom,
         mFrame.left, mFrame.top, mFrame.right, mFrame.bottom,
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 8695a44..6d380d1 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -106,7 +106,6 @@
 
     void                    setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers);
     const Vector< sp<Layer> >& getVisibleLayersSortedByZ() const;
-    bool                    getSecureLayerVisible() const;
     Region                  getDirtyRegion(bool repaintEverything) const;
 
     void                    setLayerStack(uint32_t stack);
@@ -202,10 +201,6 @@
     // list of visible layers on that display
     Vector< sp<Layer> > mVisibleLayersSortedByZ;
 
-    // Whether we have a visible secure layer on this display
-    bool mSecureLayerVisible;
-
-
     /*
      * Transaction state
      */
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1e33847..737cc82 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3183,14 +3183,7 @@
     // if we have secure windows on this display, never allow the screen capture
     // unless the producer interface is local (i.e.: we can take a screenshot for
     // ourselves).
-    if (!IInterface::asBinder(producer)->localBinder()) {
-        Mutex::Autolock _l(mStateLock);
-        sp<const DisplayDevice> hw(getDisplayDevice(display));
-        if (hw->getSecureLayerVisible()) {
-            ALOGW("FB is protected: PERMISSION_DENIED");
-            return PERMISSION_DENIED;
-        }
-    }
+    bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder();
 
     // Convert to surfaceflinger's internal rotation type.
     Transform::orientation_flags rotationFlags;
@@ -3223,19 +3216,22 @@
         bool useIdentityTransform;
         Transform::orientation_flags rotation;
         status_t result;
+        bool isLocalScreenshot;
     public:
         MessageCaptureScreen(SurfaceFlinger* flinger,
                 const sp<IBinder>& display,
                 const sp<IGraphicBufferProducer>& producer,
                 Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
                 uint32_t minLayerZ, uint32_t maxLayerZ,
-                bool useIdentityTransform, Transform::orientation_flags rotation)
+                bool useIdentityTransform,
+                Transform::orientation_flags rotation,
+                bool isLocalScreenshot)
             : flinger(flinger), display(display), producer(producer),
               sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight),
               minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
               useIdentityTransform(useIdentityTransform),
-              rotation(rotation),
-              result(PERMISSION_DENIED)
+              rotation(rotation), result(PERMISSION_DENIED),
+              isLocalScreenshot(isLocalScreenshot)
         {
         }
         status_t getResult() const {
@@ -3246,7 +3242,7 @@
             sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
             result = flinger->captureScreenImplLocked(hw, producer,
                     sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
-                    useIdentityTransform, rotation);
+                    useIdentityTransform, rotation, isLocalScreenshot);
             static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
             return true;
         }
@@ -3269,7 +3265,7 @@
     sp<MessageBase> msg = new MessageCaptureScreen(this,
             display, IGraphicBufferProducer::asInterface( wrapper ),
             sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
-            useIdentityTransform, rotationFlags);
+            useIdentityTransform, rotationFlags, isLocalScreenshot);
 
     status_t res = postMessageAsync(msg);
     if (res == NO_ERROR) {
@@ -3353,7 +3349,8 @@
         const sp<IGraphicBufferProducer>& producer,
         Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
         uint32_t minLayerZ, uint32_t maxLayerZ,
-        bool useIdentityTransform, Transform::orientation_flags rotation)
+        bool useIdentityTransform, Transform::orientation_flags rotation,
+        bool isLocalScreenshot)
 {
     ATRACE_CALL();
 
@@ -3374,6 +3371,24 @@
     reqWidth  = (!reqWidth)  ? hw_w : reqWidth;
     reqHeight = (!reqHeight) ? hw_h : reqHeight;
 
+    bool secureLayerIsVisible = false;
+    const LayerVector& layers(mDrawingState.layersSortedByZ);
+    const size_t count = layers.size();
+    for (size_t i = 0 ; i < count ; ++i) {
+        const sp<Layer>& layer(layers[i]);
+        const Layer::State& state(layer->getDrawingState());
+        if (state.layerStack == hw->getLayerStack() && state.z >= minLayerZ &&
+                state.z <= maxLayerZ && layer->isVisible() &&
+                layer->isSecure()) {
+            secureLayerIsVisible = true;
+        }
+    }
+
+    if (!isLocalScreenshot && secureLayerIsVisible) {
+        ALOGW("FB is protected: PERMISSION_DENIED");
+        return PERMISSION_DENIED;
+    }
+
     // create a surface (because we're a producer, and we need to
     // dequeue/queue a buffer)
     sp<Surface> sur = new Surface(producer, false);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 4e0160a..4101a70 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -329,7 +329,8 @@
             const sp<IGraphicBufferProducer>& producer,
             Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
             uint32_t minLayerZ, uint32_t maxLayerZ,
-            bool useIdentityTransform, Transform::orientation_flags rotation);
+            bool useIdentityTransform, Transform::orientation_flags rotation,
+            bool isLocalScreenshot);
 
     /* ------------------------------------------------------------------------
      * EGL
diff --git a/vulkan/api/templates/vulkan_h.tmpl b/vulkan/api/templates/vulkan_h.tmpl
index b2a77ec..83a5e40 100644
--- a/vulkan/api/templates/vulkan_h.tmpl
+++ b/vulkan/api/templates/vulkan_h.tmpl
@@ -17,7 +17,7 @@
 #endif

 /*
-** Copyright (c) 2015 The Khronos Group Inc.
+** Copyright (c) 2015-2016 The Khronos Group Inc.
 **
 ** Permission is hereby granted, free of charge, to any person obtaining a
 ** copy of this software and/or associated documentation files (the
@@ -47,12 +47,16 @@
 #define VK_VERSION_1_0 1
 #include "vk_platform.h"

-#define VK_MAKE_VERSION(major, minor, patch) ((major << 22) | (minor << 12) | patch)
+#define VK_MAKE_VERSION(major, minor, patch) (((major) << 22) | ((minor) << 12) | (patch))

 // Vulkan API version supported by this file
 #define VK_API_VERSION \
     VK_MAKE_VERSION({{Global "VERSION_MAJOR"}}, {{Global "VERSION_MINOR"}}, {{Global "VERSION_PATCH"}})

+#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22)
+#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
+#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)

 #if defined(__cplusplus) && ((defined(_MSC_VER) && _MSC_VER >= 1800 || __cplusplus >= 201103L)
     #define VK_NULL_HANDLE nullptr
 #else
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index 9b1e684..10565ab 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -28,7 +28,7 @@
 // API version (major.minor.patch)
 define VERSION_MAJOR 1
 define VERSION_MINOR 0
-define VERSION_PATCH 2
+define VERSION_PATCH 3
 
 // API limits
 define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -75,7 +75,7 @@
 @extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_SPEC_VERSION     5
 @extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_NAME             "VK_KHR_win32_surface"
 
-@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION       2
+@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION       1
 @extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_NAME               "VK_EXT_debug_report"
 
 
@@ -1299,9 +1299,9 @@
 type VkFlags VkDebugReportFlagsEXT
 @extension("VK_EXT_debug_report")
 bitfield VkDebugReportFlagBitsEXT {
-    VK_DEBUG_REPORT_INFO_BIT_EXT                            = 0x00000001,
-    VK_DEBUG_REPORT_WARN_BIT_EXT                            = 0x00000002,
-    VK_DEBUG_REPORT_PERF_WARN_BIT_EXT                       = 0x00000004,
+    VK_DEBUG_REPORT_INFORMATION_BIT_EXT                     = 0x00000001,
+    VK_DEBUG_REPORT_WARNING_BIT_EXT                         = 0x00000002,
+    VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT             = 0x00000004,
     VK_DEBUG_REPORT_ERROR_BIT_EXT                           = 0x00000008,
     VK_DEBUG_REPORT_DEBUG_BIT_EXT                           = 0x00000010,
 }
@@ -5130,7 +5130,7 @@
 cmd VkResult vkGetPhysicalDeviceWin32PresentationSupportKHR(
         VkPhysicalDevice                        physicalDevice,
         u32                                     queueFamilyIndex) {
-    physicalDeviceObject := GetPhysicalDevice(physicalDevice)    
+    physicalDeviceObject := GetPhysicalDevice(physicalDevice)
     return ?
 }
 
diff --git a/vulkan/include/vulkan/vk_ext_debug_report.h b/vulkan/include/vulkan/vk_ext_debug_report.h
deleted file mode 100644
index c391033..0000000
--- a/vulkan/include/vulkan/vk_ext_debug_report.h
+++ /dev/null
@@ -1,149 +0,0 @@
-//
-// File: vk_ext_debug_report.h
-//
-/*
- *
- * Copyright (C) 2015 Valve Corporation
- * Copyright (C) 2015 Google Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Author: Cody Northrop <cody@lunarg.com>
- * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
- * Author: Tony Barbour <tony@LunarG.com>
- *
- */
-
-#pragma once
-
-#include "vulkan/vulkan.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif // __cplusplus
-
-/*
-***************************************************************************************************
-*   DebugReport Vulkan Extension API
-***************************************************************************************************
-*/
-#define VK_EXT_debug_report 1
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT)
-
-#define VK_EXT_DEBUG_REPORT_SPEC_VERSION    2
-#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report"
-
-
-typedef enum VkDebugReportObjectTypeEXT {
-    VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0,
-    VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1,
-    VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3,
-    VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4,
-    VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5,
-    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6,
-    VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8,
-    VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9,
-    VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10,
-    VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11,
-    VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12,
-    VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13,
-    VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14,
-    VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15,
-    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16,
-    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17,
-    VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18,
-    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20,
-    VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23,
-    VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24,
-    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25,
-    VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26,
-    VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27,
-    VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = 28,
-} VkDebugReportObjectTypeEXT;
-
-typedef enum VkDebugReportErrorEXT {
-    VK_DEBUG_REPORT_ERROR_NONE_EXT = 0,
-    VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT = 1,
-} VkDebugReportErrorEXT;
-
-typedef enum VkDebugReportFlagBitsEXT {
-    VK_DEBUG_REPORT_INFO_BIT_EXT = 0x00000001,
-    VK_DEBUG_REPORT_WARN_BIT_EXT = 0x00000002,
-    VK_DEBUG_REPORT_PERF_WARN_BIT_EXT = 0x00000004,
-    VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008,
-    VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010,
-} VkDebugReportFlagBitsEXT;
-typedef VkFlags VkDebugReportFlagsEXT;
-
-typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)(
-    VkDebugReportFlagsEXT                       flags,
-    VkDebugReportObjectTypeEXT                  objectType,
-    uint64_t                                    object,
-    size_t                                      location,
-    int32_t                                     messageCode,
-    const char*                                 pLayerPrefix,
-    const char*                                 pMessage,
-    void*                                       pUserData);
-
-
-typedef struct VkDebugReportCallbackCreateInfoEXT {
-    VkStructureType                             sType;
-    const void*                                 pNext;
-    VkDebugReportFlagsEXT                       flags;
-    PFN_vkDebugReportCallbackEXT                pfnCallback;
-    void*                                       pUserData;
-} VkDebugReportCallbackCreateInfoEXT;
-
-typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback);
-typedef void (VKAPI_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator);
-typedef void (VKAPI_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(
-    VkInstance                                  instance,
-    const VkDebugReportCallbackCreateInfoEXT*   pCreateInfo,
-    const VkAllocationCallbacks*                pAllocator,
-    VkDebugReportCallbackEXT*                   pCallback);
-
-VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(
-    VkInstance                                  instance,
-    VkDebugReportCallbackEXT                    callback,
-    const VkAllocationCallbacks*                pAllocator);
-
-VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT(
-    VkInstance                                  instance,
-    VkDebugReportFlagsEXT                       flags,
-    VkDebugReportObjectTypeEXT                  objectType,
-    uint64_t                                    object,
-    size_t                                      location,
-    int32_t                                     messageCode,
-    const char*                                 pLayerPrefix,
-    const char*                                 pMessage);
-#endif
-
-#ifdef __cplusplus
-} // extern "C"
-#endif // __cplusplus
-
diff --git a/vulkan/include/vulkan/vk_layer_interface.h b/vulkan/include/vulkan/vk_layer_interface.h
index 8aef495..5aae51e 100644
--- a/vulkan/include/vulkan/vk_layer_interface.h
+++ b/vulkan/include/vulkan/vk_layer_interface.h
@@ -31,7 +31,6 @@
 #pragma once
 
 #include <vulkan/vulkan.h>
-#include <vulkan/vk_ext_debug_report.h>
 
 // ------------------------------------------------------------------------------------------------
 // CreateInstance and CreateDevice support structures
diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h
index 9940f85..cd6a71a 100644
--- a/vulkan/include/vulkan/vulkan.h
+++ b/vulkan/include/vulkan/vulkan.h
@@ -6,7 +6,7 @@
 #endif
 
 /*
-** Copyright (c) 2015 The Khronos Group Inc.
+** Copyright (c) 2015-2016 The Khronos Group Inc.
 **
 ** Permission is hereby granted, free of charge, to any person obtaining a
 ** copy of this software and/or associated documentation files (the
@@ -38,11 +38,14 @@
 #include "vk_platform.h"
 
 #define VK_MAKE_VERSION(major, minor, patch) \
-    ((major << 22) | (minor << 12) | patch)
+    (((major) << 22) | ((minor) << 12) | (patch))
 
 // Vulkan API version supported by this file
-#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 2)
+#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 3)
 
+#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22)
+#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
+#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
 
 #define VK_NULL_HANDLE 0
         
@@ -3664,6 +3667,107 @@
 #endif
 #endif /* VK_USE_PLATFORM_WIN32_KHR */
 
+#define VK_EXT_debug_report 1
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT)
+
+#define VK_EXT_DEBUG_REPORT_SPEC_VERSION  1
+#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report"
+
+
+typedef enum VkDebugReportObjectTypeEXT {
+    VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0,
+    VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1,
+    VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2,
+    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3,
+    VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4,
+    VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5,
+    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6,
+    VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7,
+    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8,
+    VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9,
+    VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10,
+    VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11,
+    VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12,
+    VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13,
+    VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14,
+    VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15,
+    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16,
+    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17,
+    VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18,
+    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19,
+    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20,
+    VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21,
+    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22,
+    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23,
+    VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24,
+    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25,
+    VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26,
+    VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27,
+    VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = 28,
+} VkDebugReportObjectTypeEXT;
+
+typedef enum VkDebugReportErrorEXT {
+    VK_DEBUG_REPORT_ERROR_NONE_EXT = 0,
+    VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT = 1,
+} VkDebugReportErrorEXT;
+
+
+typedef enum VkDebugReportFlagBitsEXT {
+    VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001,
+    VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002,
+    VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004,
+    VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008,
+    VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010,
+} VkDebugReportFlagBitsEXT;
+typedef VkFlags VkDebugReportFlagsEXT;
+
+typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)(
+    VkDebugReportFlagsEXT                       flags,
+    VkDebugReportObjectTypeEXT                  objectType,
+    uint64_t                                    object,
+    size_t                                      location,
+    int32_t                                     messageCode,
+    const char*                                 pLayerPrefix,
+    const char*                                 pMessage,
+    void*                                       pUserData);
+
+
+typedef struct VkDebugReportCallbackCreateInfoEXT {
+    VkStructureType                 sType;
+    const void*                     pNext;
+    VkDebugReportFlagsEXT           flags;
+    PFN_vkDebugReportCallbackEXT    pfnCallback;
+    void*                           pUserData;
+} VkDebugReportCallbackCreateInfoEXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback);
+typedef void (VKAPI_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator);
+typedef void (VKAPI_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(
+    VkInstance                                  instance,
+    const VkDebugReportCallbackCreateInfoEXT*   pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkDebugReportCallbackEXT*                   pCallback);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(
+    VkInstance                                  instance,
+    VkDebugReportCallbackEXT                    callback,
+    const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT(
+    VkInstance                                  instance,
+    VkDebugReportFlagsEXT                       flags,
+    VkDebugReportObjectTypeEXT                  objectType,
+    uint64_t                                    object,
+    size_t                                      location,
+    int32_t                                     messageCode,
+    const char*                                 pLayerPrefix,
+    const char*                                 pMessage);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/vulkan/libvulkan/Android.mk b/vulkan/libvulkan/Android.mk
index 779fedf..85b8ab2 100644
--- a/vulkan/libvulkan/Android.mk
+++ b/vulkan/libvulkan/Android.mk
@@ -16,6 +16,8 @@
 include $(CLEAR_VARS)
 
 LOCAL_CLANG := true
+LOCAL_SANITIZE := integer
+
 LOCAL_CFLAGS := -DLOG_TAG=\"vulkan\" \
 	-std=c99 -fvisibility=hidden -fstrict-aliasing \
 	-Weverything -Werror \
diff --git a/vulkan/libvulkan/debug_report.h b/vulkan/libvulkan/debug_report.h
index 5bce240..c6f7570 100644
--- a/vulkan/libvulkan/debug_report.h
+++ b/vulkan/libvulkan/debug_report.h
@@ -18,7 +18,6 @@
 #define LIBVULKAN_DEBUG_REPORT_H 1
 
 #include <shared_mutex>
-#include <vulkan/vk_ext_debug_report.h>
 
 namespace vulkan {
 
diff --git a/vulkan/libvulkan/dispatch.tmpl b/vulkan/libvulkan/dispatch.tmpl
index 306aae4..0a0338e 100644
--- a/vulkan/libvulkan/dispatch.tmpl
+++ b/vulkan/libvulkan/dispatch.tmpl
@@ -46,7 +46,6 @@

 #define VK_USE_PLATFORM_ANDROID_KHR
 #include <vulkan/vk_android_native_buffer.h>
-#include <vulkan/vk_ext_debug_report.h>
 #include <vulkan/vulkan.h>

 namespace vulkan {
diff --git a/vulkan/libvulkan/dispatch_gen.h b/vulkan/libvulkan/dispatch_gen.h
index 7bab6ca..cef4ccf 100644
--- a/vulkan/libvulkan/dispatch_gen.h
+++ b/vulkan/libvulkan/dispatch_gen.h
@@ -18,7 +18,6 @@
 
 #define VK_USE_PLATFORM_ANDROID_KHR
 #include <vulkan/vk_android_native_buffer.h>
-#include <vulkan/vk_ext_debug_report.h>
 #include <vulkan/vulkan.h>
 
 namespace vulkan {
diff --git a/vulkan/libvulkan/loader.cpp b/vulkan/libvulkan/loader.cpp
index 1a57c22..fc60f35 100644
--- a/vulkan/libvulkan/loader.cpp
+++ b/vulkan/libvulkan/loader.cpp
@@ -496,7 +496,7 @@
                                  void* /*user_data*/) {
     if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
         ALOGE("[%s] Code %d : %s", layer_prefix, message_code, message);
-    } else if (flags & VK_DEBUG_REPORT_WARN_BIT_EXT) {
+    } else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
         ALOGW("[%s] Code %d : %s", layer_prefix, message_code, message);
     }
     return false;
@@ -1205,7 +1205,7 @@
         const VkDebugReportCallbackCreateInfoEXT callback_create_info = {
             .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT,
             .flags =
-                VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARN_BIT_EXT,
+                VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT,
             .pfnCallback = LogDebugMessageCallback,
         };
         PFN_vkCreateDebugReportCallbackEXT create_debug_report_callback =
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index f8de675..7f944cf 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -107,6 +107,79 @@
     }
 }
 
+const VkSurfaceTransformFlagsKHR kSupportedTransforms =
+    VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR |
+    VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR |
+    VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR |
+    VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR |
+    // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform.
+    // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR |
+    // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR |
+    // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR |
+    // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR |
+    VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR;
+
+VkSurfaceTransformFlagBitsKHR TranslateNativeToVulkanTransform(int native) {
+    // Native and Vulkan transforms are isomorphic, but are represented
+    // differently. Vulkan transforms are built up of an optional horizontal
+    // mirror, followed by a clockwise 0/90/180/270-degree rotation. Native
+    // transforms are built up from a horizontal flip, vertical flip, and
+    // 90-degree rotation, all optional but always in that order.
+
+    // TODO(jessehall): For now, only support pure rotations, not
+    // flip or flip-and-rotate, until I have more time to test them and build
+    // sample code. As far as I know we never actually use anything besides
+    // pure rotations anyway.
+
+    switch (native) {
+        case 0:  // 0x0
+            return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+        // case NATIVE_WINDOW_TRANSFORM_FLIP_H:  // 0x1
+        //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR;
+        // case NATIVE_WINDOW_TRANSFORM_FLIP_V:  // 0x2
+        //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR;
+        case NATIVE_WINDOW_TRANSFORM_ROT_180:  // FLIP_H | FLIP_V
+            return VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR;
+        case NATIVE_WINDOW_TRANSFORM_ROT_90:  // 0x4
+            return VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR;
+        // case NATIVE_WINDOW_TRANSFORM_FLIP_H | NATIVE_WINDOW_TRANSFORM_ROT_90:
+        //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR;
+        // case NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_ROT_90:
+        //     return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR;
+        case NATIVE_WINDOW_TRANSFORM_ROT_270:  // FLIP_H | FLIP_V | ROT_90
+            return VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR;
+        case NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY:
+        default:
+            return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+    }
+}
+
+int InvertTransformToNative(VkSurfaceTransformFlagBitsKHR transform) {
+    switch (transform) {
+        case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
+            return NATIVE_WINDOW_TRANSFORM_ROT_270;
+        case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
+            return NATIVE_WINDOW_TRANSFORM_ROT_180;
+        case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
+            return NATIVE_WINDOW_TRANSFORM_ROT_90;
+        // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform.
+        // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR:
+        //     return NATIVE_WINDOW_TRANSFORM_FLIP_H;
+        // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR:
+        //     return NATIVE_WINDOW_TRANSFORM_FLIP_H |
+        //            NATIVE_WINDOW_TRANSFORM_ROT_90;
+        // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR:
+        //     return NATIVE_WINDOW_TRANSFORM_FLIP_V;
+        // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR:
+        //     return NATIVE_WINDOW_TRANSFORM_FLIP_V |
+        //            NATIVE_WINDOW_TRANSFORM_ROT_90;
+        case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
+        case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR:
+        default:
+            return 0;
+    }
+}
+
 // ----------------------------------------------------------------------------
 
 struct Surface {
@@ -238,6 +311,14 @@
         return VK_ERROR_INITIALIZATION_FAILED;
     }
 
+    int transform_hint;
+    err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint);
+    if (err != 0) {
+        ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)",
+              strerror(-err), err);
+        return VK_ERROR_INITIALIZATION_FAILED;
+    }
+
     // TODO(jessehall): Figure out what the min/max values should be.
     capabilities->minImageCount = 2;
     capabilities->maxImageCount = 3;
@@ -252,12 +333,9 @@
 
     capabilities->maxImageArrayLayers = 1;
 
-    // TODO(jessehall): We can support all transforms, fix this once
-    // implemented.
-    capabilities->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
-
-    // TODO(jessehall): Implement based on NATIVE_WINDOW_TRANSFORM_HINT.
-    capabilities->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+    capabilities->supportedTransforms = kSupportedTransforms;
+    capabilities->currentTransform =
+        TranslateNativeToVulkanTransform(transform_hint);
 
     // On Android, window composition is a WindowManager property, not something
     // associated with the bufferqueue. It can't be changed from here.
@@ -347,8 +425,9 @@
              "color spaces other than SRGB_NONLINEAR not yet implemented");
     ALOGE_IF(create_info->oldSwapchain,
              "swapchain re-creation not yet implemented");
-    ALOGE_IF(create_info->preTransform != VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
-             "swapchain preTransform not yet implemented");
+    ALOGE_IF((create_info->preTransform & ~kSupportedTransforms) != 0,
+             "swapchain preTransform %d not supported",
+             create_info->preTransform);
     ALOGW_IF(!(create_info->presentMode == VK_PRESENT_MODE_FIFO_KHR ||
                create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR),
              "swapchain present mode %d not supported",
@@ -402,6 +481,26 @@
         return VK_ERROR_INITIALIZATION_FAILED;
     }
 
+    // VkSwapchainCreateInfo::preTransform indicates the transformation the app
+    // applied during rendering. native_window_set_transform() expects the
+    // inverse: the transform the app is requesting that the compositor perform
+    // during composition. With native windows, pre-transform works by rendering
+    // with the same transform the compositor is applying (as in Vulkan), but
+    // then requesting the inverse transform, so that when the compositor does
+    // it's job the two transforms cancel each other out and the compositor ends
+    // up applying an identity transform to the app's buffer.
+    err = native_window_set_buffers_transform(
+        surface.window.get(),
+        InvertTransformToNative(create_info->preTransform));
+    if (err != 0) {
+        // TODO(jessehall): Improve error reporting. Can we enumerate possible
+        // errors and translate them to valid Vulkan result codes?
+        ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
+              InvertTransformToNative(create_info->preTransform),
+              strerror(-err), err);
+        return VK_ERROR_INITIALIZATION_FAILED;
+    }
+
     err = native_window_set_scaling_mode(
         surface.window.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
     if (err != 0) {
@@ -412,16 +511,18 @@
         return VK_ERROR_INITIALIZATION_FAILED;
     }
 
-    uint32_t min_undequeued_buffers;
-    err = surface.window->query(
-        surface.window.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
-        reinterpret_cast<int*>(&min_undequeued_buffers));
-    if (err != 0) {
+    int query_value;
+    err = surface.window->query(surface.window.get(),
+                                NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+                                &query_value);
+    if (err != 0 || query_value < 0) {
         // TODO(jessehall): Improve error reporting. Can we enumerate possible
         // errors and translate them to valid Vulkan result codes?
-        ALOGE("window->query failed: %s (%d)", strerror(-err), err);
+        ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
+              query_value);
         return VK_ERROR_INITIALIZATION_FAILED;
     }
+    uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
     // The MIN_UNDEQUEUED_BUFFERS query doesn't know whether we'll be using
     // async mode or not, and assumes not. But in async mode, the BufferQueue
     // requires an extra undequeued buffer.
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index cd61e86..6f57238 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -15,7 +15,6 @@
  */
 
 #include <hardware/hwvulkan.h>
-#include <vulkan/vk_ext_debug_report.h>
 
 #include <algorithm>
 #include <array>
diff --git a/vulkan/nulldrv/null_driver.tmpl b/vulkan/nulldrv/null_driver.tmpl
index 7488692..3a84971 100644
--- a/vulkan/nulldrv/null_driver.tmpl
+++ b/vulkan/nulldrv/null_driver.tmpl
@@ -49,7 +49,6 @@
 #define NULLDRV_NULL_DRIVER_H 1

 #include <vulkan/vk_android_native_buffer.h>
-#include <vulkan/vk_ext_debug_report.h>
 #include <vulkan/vulkan.h>

 namespace null_driver {«
diff --git a/vulkan/nulldrv/null_driver_gen.h b/vulkan/nulldrv/null_driver_gen.h
index 87ff681..98952b8 100644
--- a/vulkan/nulldrv/null_driver_gen.h
+++ b/vulkan/nulldrv/null_driver_gen.h
@@ -20,7 +20,6 @@
 #define NULLDRV_NULL_DRIVER_H 1
 
 #include <vulkan/vk_android_native_buffer.h>
-#include <vulkan/vk_ext_debug_report.h>
 #include <vulkan/vulkan.h>
 
 namespace null_driver {
diff --git a/vulkan/tools/Android.mk b/vulkan/tools/Android.mk
index 31d6089..337e683 100644
--- a/vulkan/tools/Android.mk
+++ b/vulkan/tools/Android.mk
@@ -21,7 +21,8 @@
 LOCAL_CFLAGS += -Weverything -Werror -Wno-padded -Wno-undef -Wno-switch-enum
 LOCAL_CPPFLAGS := -std=c++1y \
 	-Wno-c++98-compat-pedantic \
-	-Wno-c99-extensions
+	-Wno-c99-extensions \
+	-Wno-old-style-cast
 
 LOCAL_C_INCLUDES := \
 	frameworks/native/vulkan/include
diff --git a/vulkan/tools/vkinfo.cpp b/vulkan/tools/vkinfo.cpp
index e650a27..e97e5f5 100644
--- a/vulkan/tools/vkinfo.cpp
+++ b/vulkan/tools/vkinfo.cpp
@@ -22,7 +22,6 @@
 #include <vector>
 
 #include <vulkan/vulkan.h>
-#include <vulkan/vk_ext_debug_report.h>
 
 #define LOG_TAG "vkinfo"
 #include <log/log.h>
@@ -258,8 +257,17 @@
     // clang-format on
     uint32_t num_layers = sizeof(kValidationLayers) / sizeof(char*);
 
+    const VkApplicationInfo application_info = {
+        .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
+        .pApplicationName = "vkinfo",
+        .applicationVersion = 0,
+        .pEngineName = "vkinfo",
+        .engineVersion = 0,
+        .apiVersion = VK_API_VERSION,
+    };
     const VkInstanceCreateInfo create_info = {
         .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+        .pApplicationInfo = &application_info,
         .enabledExtensionCount = num_extensions,
         .ppEnabledExtensionNames = extensions,
         .enabledLayerCount = (options.validate) ? num_layers : 0,
@@ -305,16 +313,6 @@
            (kIndent.size() - (kIndentSize * std::min(n, kMaxIndent) + 1));
 }
 
-uint32_t ExtractMajorVersion(uint32_t version) {
-    return (version >> 22) & 0x3FF;
-}
-uint32_t ExtractMinorVersion(uint32_t version) {
-    return (version >> 12) & 0x3FF;
-}
-uint32_t ExtractPatchVersion(uint32_t version) {
-    return (version >> 0) & 0xFFF;
-}
-
 const char* VkPhysicalDeviceTypeStr(VkPhysicalDeviceType type) {
     switch (type) {
         case VK_PHYSICAL_DEVICE_TYPE_OTHER:
@@ -346,9 +344,9 @@
     size_t indent) {
     for (size_t i = 0; i < layers.size(); i++) {
         printf("%s%s %u.%u.%u/%u\n", Indent(indent), layers[i].layerName,
-               ExtractMajorVersion(layers[i].specVersion),
-               ExtractMinorVersion(layers[i].specVersion),
-               ExtractPatchVersion(layers[i].specVersion),
+               VK_VERSION_MAJOR(layers[i].specVersion),
+               VK_VERSION_MINOR(layers[i].specVersion),
+               VK_VERSION_PATCH(layers[i].specVersion),
                layers[i].implementationVersion);
         if (options.layer_description)
             printf("%s%s\n", Indent(indent + 1), layers[i].description);
@@ -491,9 +489,9 @@
     printf("%s\"%s\" (%s) %u.%u.%u/%#x [%04x:%04x]\n", Indent(indent),
            info.properties.deviceName,
            VkPhysicalDeviceTypeStr(info.properties.deviceType),
-           ExtractMajorVersion(info.properties.apiVersion),
-           ExtractMinorVersion(info.properties.apiVersion),
-           ExtractPatchVersion(info.properties.apiVersion),
+           VK_VERSION_MAJOR(info.properties.apiVersion),
+           VK_VERSION_MINOR(info.properties.apiVersion),
+           VK_VERSION_PATCH(info.properties.apiVersion),
            info.properties.driverVersion, info.properties.vendorID,
            info.properties.deviceID);