Merge "Added --skip option to skip services."
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 054db74..22fd2c3 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -368,6 +368,10 @@
 
 /* adds a new entry to the existing zip file. */
 static bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
+    if (!zip_writer) {
+        ALOGD("Not adding zip entry %s from fd because zip_writer is not set", entry_name.c_str());
+        return false;
+    }
     ALOGD("Adding zip entry %s", entry_name.c_str());
     int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(),
             ZipWriter::kCompress, get_mtime(fd, now));
@@ -420,14 +424,21 @@
 
 /* adds all files from a directory to the zipped bugreport file */
 void add_dir(const char *dir, bool recursive) {
-    if (!zip_writer) return;
+    if (!zip_writer) {
+        ALOGD("Not adding dir %s because zip_writer is not set", dir);
+        return;
+    }
     DurationReporter duration_reporter(dir, NULL);
     dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd);
 }
 
 /* adds a text entry entry to the existing zip file. */
 static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) {
-    ALOGD("Adding zip text entry %s (%s)", entry_name.c_str(), content.c_str());
+    if (!zip_writer) {
+        ALOGD("Not adding text zip entry %s because zip_writer is not set", entry_name.c_str());
+        return false;
+    }
+    ALOGD("Adding zip text entry %s", entry_name.c_str());
     int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now);
     if (err) {
         ALOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
@@ -772,7 +783,7 @@
             "  -s: write output to control socket (for init)\n"
             "  -q: disable vibrate\n"
             "  -B: send broadcast when finished (requires -o)\n"
-            "  -P: send broadacast when started and update system properties on progress (requires -o and -B)\n"
+            "  -P: send broadcast when started and update system properties on progress (requires -o and -B)\n"
             "  -R: take bugreport in remote mode (requires -o, -z, -d and -B, shouldn't be used with -P)\n"
             "  -V: sets the bugreport format version (%s or %s)\n",
             VERSION_DEFAULT.c_str(), VERSION_DUMPSYS_SPLIT.c_str());
@@ -794,6 +805,7 @@
     }
     if (!add_text_zip_entry("main_entry.txt", bugreport_name)) {
         ALOGE("Failed to add main_entry.txt to .zip file\n");
+        return false;
     }
 
     int32_t err = zip_writer->Finish();
@@ -1027,6 +1039,7 @@
         if (do_zip_file) {
             ALOGD("Creating initial .zip file");
             path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
+            create_parent_dirs(path.c_str());
             zip_file.reset(fopen(path.c_str(), "wb"));
             if (!zip_file) {
                 ALOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno));
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 8332d22..a6afbf4 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -112,6 +112,9 @@
 /* redirect output to a file */
 void redirect_to_file(FILE *redirect, char *path);
 
+/* create leading directories, if necessary */
+void create_parent_dirs(const char *path);
+
 /* dump Dalvik and native stack traces, return the trace file location (NULL if none) */
 const char *dump_traces();
 
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index ee60f57..0c35430 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -657,23 +657,35 @@
     close(fd);
 }
 
-/* redirect output to a file */
-void redirect_to_file(FILE *redirect, char *path) {
-    char *chp = path;
+void create_parent_dirs(const char *path) {
+    char *chp = (char*) path;
 
     /* skip initial slash */
     if (chp[0] == '/')
         chp++;
 
     /* create leading directories, if necessary */
+    struct stat dir_stat;
     while (chp && chp[0]) {
         chp = strchr(chp, '/');
         if (chp) {
             *chp = 0;
-            mkdir(path, 0770);  /* drwxrwx--- */
+            if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) {
+                ALOGI("Creating directory %s\n", path);
+                if (mkdir(path, 0770)) { /* drwxrwx--- */
+                    ALOGE("Unable to create directory %s: %s\n", path, strerror(errno));
+                } else if (chown(path, AID_SHELL, AID_SHELL)) {
+                    ALOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno));
+                }
+            }
             *chp++ = '/';
         }
     }
+}
+
+/* redirect output to a file */
+void redirect_to_file(FILE *redirect, char *path) {
+    create_parent_dirs(path);
 
     int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
                                      S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index cfe5a62..e9ec3d3 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -666,6 +666,14 @@
 
     bool generate_debug_info = check_boolean_property("debug.generate-debug-info");
 
+    char app_image_format[kPropertyValueMax];
+    char image_format_arg[strlen("--image-format=") + kPropertyValueMax];
+    bool have_app_image_format =
+            image_fd >= 0 && get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
+    if (have_app_image_format) {
+        sprintf(image_format_arg, "--image-format=%s", app_image_format);
+    }
+
     static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
 
     static const char* RUNTIME_ARG = "--runtime-arg";
@@ -756,6 +764,7 @@
                      + (have_dex2oat_relocation_skip_flag ? 2 : 0)
                      + (generate_debug_info ? 1 : 0)
                      + (debuggable ? 1 : 0)
+                     + (have_app_image_format ? 1 : 0)
                      + dex2oat_flags_count
                      + profile_files_fd.size()
                      + reference_profile_files_fd.size()];
@@ -798,6 +807,9 @@
     if (debuggable) {
         argv[i++] = "--debuggable";
     }
+    if (have_app_image_format) {
+        argv[i++] = image_format_arg;
+    }
     if (dex2oat_flags_count) {
         i += split(dex2oat_flags, argv + i);
     }
@@ -983,13 +995,21 @@
   }
 }
 
-static int open_with_extension(char* file_name, const char* extension) {
-    if (strlen(file_name) + strlen(extension) + 1 <= PKG_PATH_MAX) {
-        strcat(file_name, extension);
-        unlink(file_name);
-        return open(file_name, O_RDWR | O_CREAT | O_EXCL, 0600);
+static bool add_extension_to_file_name(char* file_name, const char* extension) {
+    if (strlen(file_name) + strlen(extension) + 1 > PKG_PATH_MAX) {
+        return false;
     }
-    return -1;
+    strcat(file_name, extension);
+    return true;
+}
+
+static int open_output_file(char* file_name, bool recreate) {
+    int flags = O_RDWR | O_CREAT;
+    if (recreate) {
+        unlink(file_name);
+        flags |= O_EXCL;
+    }
+    return open(file_name, flags, 0600);
 }
 
 static bool set_permissions_and_ownership(int fd, bool is_public, int uid, const char* path) {
@@ -1103,7 +1123,9 @@
     if (ShouldUseSwapFileForDexopt()) {
         // Make sure there really is enough space.
         strcpy(swap_file_name, out_path);
-        swap_fd = open_with_extension(swap_file_name, ".swap");
+        if (add_extension_to_file_name(swap_file_name, ".swap")) {
+            swap_fd = open_output_file(swap_file_name, /*recreate*/true);
+        }
         if (swap_fd < 0) {
             // Could not create swap file. Optimistically go on and hope that we can compile
             // without it.
@@ -1114,16 +1136,30 @@
         }
     }
 
+    // Avoid generating an app image for extract only since it will not contain any classes.
     strcpy(image_path, out_path);
     trim_extension(image_path);
-    image_fd = open_with_extension(image_path, ".art");
-    if (image_fd < 0) {
-        // Could not create swap file. Optimistically go on and hope that we can compile
-        // without it.
-        ALOGE("installd could not create '%s' for image file during dexopt\n", image_path);
-    } else if (!set_permissions_and_ownership(image_fd, is_public, uid, image_path)) {
-        image_fd = -1;
+    if (add_extension_to_file_name(image_path, ".art")) {
+      char app_image_format[kPropertyValueMax];
+      bool have_app_image_format =
+              get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
+      if (!extract_only && have_app_image_format) {
+          // Recreate is false since we want to avoid deleting the image in case dex2oat decides to
+          // not compile anything.
+          image_fd = open_output_file(image_path, /*recreate*/false);
+          if (image_fd < 0) {
+              // Could not create application image file. Go on since we can compile without it.
+              ALOGE("installd could not create '%s' for image file during dexopt\n", image_path);
+          } else if (!set_permissions_and_ownership(image_fd, is_public, uid, image_path)) {
+              image_fd = -1;
+          }
+      }
+      // If we have a valid image file path but no image fd, erase the image file.
+      if (image_fd < 0) {
+          unlink(image_path);
+      }
     }
+
     ALOGV("DexInv: --- BEGIN '%s' ---\n", input_file);
 
     pid_t pid;
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index 23cd066..e2e73a0 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -126,9 +126,11 @@
     // waitWhileAllocatingLocked blocks until mIsAllocating is false.
     void waitWhileAllocatingLocked() const;
 
+#if DEBUG_ONLY_CODE
     // validateConsistencyLocked ensures that the free lists are in sync with
     // the information stored in mSlots
     void validateConsistencyLocked() const;
+#endif
 
     // mAllocator is the connection to SurfaceFlinger that is used to allocate
     // new GraphicBuffer objects.
diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h
index ebce7fb..e983c16 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/include/gui/IGraphicBufferConsumer.h
@@ -206,17 +206,26 @@
     virtual status_t setMaxBufferCount(int bufferCount) = 0;
 
     // setMaxAcquiredBufferCount sets the maximum number of buffers that can
-    // be acquired by the consumer at one time (default 1).  This call will
-    // fail if a producer is connected to the BufferQueue.
+    // be acquired by the consumer at one time (default 1). If this method
+    // succeeds, any new buffer slots will be both unallocated and owned by the
+    // BufferQueue object (i.e. they are not owned by the producer or consumer).
+    // Calling this may also cause some buffer slots to be emptied.
+    //
+    // This function should not be called with a value of maxAcquiredBuffers
+    // that is less than the number of currently acquired buffer slots. Doing so
+    // will result in a BAD_VALUE error.
     //
     // maxAcquiredBuffers must be (inclusive) between 1 and
     // MAX_MAX_ACQUIRED_BUFFERS. It also cannot cause the maxBufferCount value
     // to be exceeded.
     //
     // Return of a value other than NO_ERROR means an error has occurred:
+    // * NO_INIT - the buffer queue has been abandoned
     // * BAD_VALUE - one of the below conditions occurred:
     //             * maxAcquiredBuffers was out of range (see above).
     //             * failure to adjust the number of available slots.
+    //             * client would have more than the requested number of
+    //               acquired buffers after this call
     // * INVALID_OPERATION - attempting to call this after a producer connected.
     virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0;
 
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 1f4c8ac..265728f 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -82,15 +82,16 @@
     virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) = 0;
 
     // setMaxDequeuedBufferCount sets the maximum number of buffers that can be
-    // dequeued by the producer at one time. If this method succeeds, buffer
-    // slots will be both unallocated and owned by the BufferQueue object (i.e.
-    // they are not owned by the producer or consumer). Calling this will also
-    // cause all buffer slots to be emptied. If the caller is caching the
+    // dequeued by the producer at one time. If this method succeeds, any new
+    // buffer slots will be both unallocated and owned by the BufferQueue object
+    // (i.e. they are not owned by the producer or consumer). Calling this may
+    // also cause some buffer slots to be emptied. If the caller is caching the
     // contents of the buffer slots, it should empty that cache after calling
     // this method.
     //
-    // This function should not be called when there are any currently dequeued
-    // buffer slots. Doing so will result in a BAD_VALUE error.
+    // This function should not be called with a value of maxDequeuedBuffers
+    // that is less than the number of currently dequeued buffer slots. Doing so
+    // will result in a BAD_VALUE error.
     //
     // The buffer count should be at least 1 (inclusive), but at most
     // (NUM_BUFFER_SLOTS - the minimum undequeued buffer count) (exclusive). The
@@ -100,9 +101,10 @@
     // Return of a value other than NO_ERROR means an error has occurred:
     // * NO_INIT - the buffer queue has been abandoned.
     // * BAD_VALUE - one of the below conditions occurred:
-    //     * bufferCount was out of range (see above)
-    //     * client has too many buffers dequeued
-    //     * this call would cause the maxBufferCount value to be exceeded
+    //     * bufferCount was out of range (see above).
+    //     * client would have more than the requested number of dequeued
+    //       buffers after this call.
+    //     * this call would cause the maxBufferCount value to be exceeded.
     //     * failure to adjust the number of available slots.
     virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) = 0;
 
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index 8a965dd..635020e 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -36,6 +36,8 @@
 # Don't warn about struct padding
 LOCAL_CPPFLAGS += -Wno-padded
 
+LOCAL_CPPFLAGS += -DDEBUG_ONLY_CODE=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0)
+
 LOCAL_SRC_FILES := \
 	IGraphicBufferConsumer.cpp \
 	IConsumerListener.cpp \
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index d182f6b..92285e5 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -20,6 +20,12 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 //#define LOG_NDEBUG 0
 
+#if DEBUG_ONLY_CODE
+#define VALIDATE_CONSISTENCY() do { mCore->validateConsistencyLocked(); } while (0)
+#else
+#define VALIDATE_CONSISTENCY()
+#endif
+
 #include <gui/BufferItem.h>
 #include <gui/BufferQueueConsumer.h>
 #include <gui/BufferQueueCore.h>
@@ -252,7 +258,7 @@
 
         ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
 
-        mCore->validateConsistencyLocked();
+        VALIDATE_CONSISTENCY();
     }
 
     if (listener != NULL) {
@@ -296,7 +302,7 @@
     mCore->mFreeSlots.insert(slot);
     mCore->clearBufferSlotLocked(slot);
     mCore->mDequeueCondition.broadcast();
-    mCore->validateConsistencyLocked();
+    VALIDATE_CONSISTENCY();
 
     return NO_ERROR;
 }
@@ -386,7 +392,7 @@
     // for attached buffers.
     mSlots[*outSlot].mAcquireCalled = false;
 
-    mCore->validateConsistencyLocked();
+    VALIDATE_CONSISTENCY();
 
     return NO_ERROR;
 }
@@ -446,7 +452,7 @@
         BQ_LOGV("releaseBuffer: releasing slot %d", slot);
 
         mCore->mDequeueCondition.broadcast();
-        mCore->validateConsistencyLocked();
+        VALIDATE_CONSISTENCY();
     } // Autolock scope
 
     // Call back without lock held
@@ -605,35 +611,59 @@
         return BAD_VALUE;
     }
 
-    Mutex::Autolock lock(mCore->mMutex);
+    sp<IConsumerListener> listener;
+    { // Autolock scope
+        Mutex::Autolock lock(mCore->mMutex);
+        mCore->waitWhileAllocatingLocked();
 
-    if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
-        BQ_LOGE("setMaxAcquiredBufferCount: producer is already connected");
-        return INVALID_OPERATION;
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("setMaxAcquiredBufferCount: consumer is abandoned");
+            return NO_INIT;
+        }
+
+        // The new maxAcquiredBuffers count should not be violated by the number
+        // of currently acquired buffers
+        int acquiredCount = 0;
+        for (int slot : mCore->mActiveBuffers) {
+            if (mSlots[slot].mBufferState.isAcquired()) {
+                acquiredCount++;
+            }
+        }
+        if (acquiredCount > maxAcquiredBuffers) {
+            BQ_LOGE("setMaxAcquiredBufferCount: the requested maxAcquiredBuffer"
+                    "count (%d) exceeds the current acquired buffer count (%d)",
+                    maxAcquiredBuffers, acquiredCount);
+            return BAD_VALUE;
+        }
+
+        if ((maxAcquiredBuffers + mCore->mMaxDequeuedBufferCount +
+                (mCore->mAsyncMode || mCore->mDequeueBufferCannotBlock ? 1 : 0))
+                > mCore->mMaxBufferCount) {
+            BQ_LOGE("setMaxAcquiredBufferCount: %d acquired buffers would "
+                    "exceed the maxBufferCount (%d) (maxDequeued %d async %d)",
+                    maxAcquiredBuffers, mCore->mMaxBufferCount,
+                    mCore->mMaxDequeuedBufferCount, mCore->mAsyncMode ||
+                    mCore->mDequeueBufferCannotBlock);
+            return BAD_VALUE;
+        }
+
+        int delta = maxAcquiredBuffers - mCore->mMaxAcquiredBufferCount;
+        if (!mCore->adjustAvailableSlotsLocked(delta)) {
+            return BAD_VALUE;
+        }
+
+        BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers);
+        mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers;
+        VALIDATE_CONSISTENCY();
+        if (delta < 0) {
+            listener = mCore->mConsumerListener;
+        }
+    }
+    // Call back without lock held
+    if (listener != NULL) {
+        listener->onBuffersReleased();
     }
 
-    if ((maxAcquiredBuffers + mCore->mMaxDequeuedBufferCount +
-            (mCore->mAsyncMode || mCore->mDequeueBufferCannotBlock ? 1 : 0)) >
-            mCore->mMaxBufferCount) {
-        BQ_LOGE("setMaxAcquiredBufferCount: %d acquired buffers would exceed "
-                "the maxBufferCount (%d) (maxDequeued %d async %d)",
-                maxAcquiredBuffers, mCore->mMaxBufferCount,
-                mCore->mMaxDequeuedBufferCount, mCore->mAsyncMode ||
-                mCore->mDequeueBufferCannotBlock);
-        return BAD_VALUE;
-    }
-
-    if (!mCore->adjustAvailableSlotsLocked(
-            maxAcquiredBuffers - mCore->mMaxAcquiredBufferCount)) {
-        BQ_LOGE("setMaxAcquiredBufferCount: BufferQueue failed to adjust the "
-                "number of available slots. Delta = %d",
-                maxAcquiredBuffers - mCore->mMaxAcquiredBufferCount);
-        return BAD_VALUE;
-    }
-
-    BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers);
-    mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers;
-    mCore->validateConsistencyLocked();
     return NO_ERROR;
 }
 
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index f02ff5f..f785db0 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -20,6 +20,12 @@
 
 #define EGL_EGLEXT_PROTOTYPES
 
+#if DEBUG_ONLY_CODE
+#define VALIDATE_CONSISTENCY() do { validateConsistencyLocked(); } while (0)
+#else
+#define VALIDATE_CONSISTENCY()
+#endif
+
 #include <inttypes.h>
 
 #include <gui/BufferItem.h>
@@ -216,11 +222,15 @@
         b.mIsStale = true;
     }
 
-    validateConsistencyLocked();
+    VALIDATE_CONSISTENCY();
 }
 
 bool BufferQueueCore::adjustAvailableSlotsLocked(int delta) {
     if (delta >= 0) {
+        // If we're going to fail, do so before modifying anything
+        if (delta > static_cast<int>(mUnusedSlots.size())) {
+            return false;
+        }
         while (delta > 0) {
             if (mUnusedSlots.empty()) {
                 return false;
@@ -231,6 +241,11 @@
             delta--;
         }
     } else {
+        // If we're going to fail, do so before modifying anything
+        if (-delta > static_cast<int>(mFreeSlots.size() +
+                mFreeBuffers.size())) {
+            return false;
+        }
         while (delta < 0) {
             if (!mFreeSlots.empty()) {
                 auto slot = mFreeSlots.begin();
@@ -258,6 +273,7 @@
     }
 }
 
+#if DEBUG_ONLY_CODE
 void BufferQueueCore::validateConsistencyLocked() const {
     static const useconds_t PAUSE_TIME = 0;
     int allocatedSlots = 0;
@@ -382,5 +398,6 @@
                 mUnusedSlots.size());
     }
 }
+#endif
 
 } // namespace android
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 22a2d79..9d42464 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -20,6 +20,12 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 //#define LOG_NDEBUG 0
 
+#if DEBUG_ONLY_CODE
+#define VALIDATE_CONSISTENCY() do { mCore->validateConsistencyLocked(); } while (0)
+#else
+#define VALIDATE_CONSISTENCY()
+#endif
+
 #define EGL_EGLEXT_PROTOTYPES
 
 #include <gui/BufferItem.h>
@@ -95,13 +101,20 @@
             return NO_INIT;
         }
 
-        // There must be no dequeued buffers when changing the buffer count.
+        // The new maxDequeuedBuffer count should not be violated by the number
+        // of currently dequeued buffers
+        int dequeuedCount = 0;
         for (int s : mCore->mActiveBuffers) {
             if (mSlots[s].mBufferState.isDequeued()) {
-                BQ_LOGE("setMaxDequeuedBufferCount: buffer owned by producer");
-                return BAD_VALUE;
+                dequeuedCount++;
             }
         }
+        if (dequeuedCount > maxDequeuedBuffers) {
+            BQ_LOGE("setMaxDequeuedBufferCount: the requested maxDequeuedBuffer"
+                    "count (%d) exceeds the current dequeued buffer count (%d)",
+                    maxDequeuedBuffers, dequeuedCount);
+            return BAD_VALUE;
+        }
 
         int bufferCount = mCore->getMinUndequeuedBufferCountLocked();
         bufferCount += maxDequeuedBuffers;
@@ -128,21 +141,16 @@
             return BAD_VALUE;
         }
 
-        // Here we are guaranteed that the producer doesn't have any dequeued
-        // buffers and will release all of its buffer references. We don't
-        // clear the queue, however, so that currently queued buffers still
-        // get displayed.
-        if (!mCore->adjustAvailableSlotsLocked(
-                maxDequeuedBuffers - mCore->mMaxDequeuedBufferCount)) {
-            BQ_LOGE("setMaxDequeuedBufferCount: BufferQueue failed to adjust "
-                    "the number of available slots. Delta = %d",
-                    maxDequeuedBuffers - mCore->mMaxDequeuedBufferCount);
+        int delta = maxDequeuedBuffers - mCore->mMaxDequeuedBufferCount;
+        if (!mCore->adjustAvailableSlotsLocked(delta)) {
             return BAD_VALUE;
         }
         mCore->mMaxDequeuedBufferCount = maxDequeuedBuffers;
-        mCore->validateConsistencyLocked();
+        VALIDATE_CONSISTENCY();
+        if (delta < 0) {
+            listener = mCore->mConsumerListener;
+        }
         mCore->mDequeueCondition.broadcast();
-        listener = mCore->mConsumerListener;
     } // Autolock scope
 
     // Call back without lock held
@@ -189,7 +197,7 @@
             return BAD_VALUE;
         }
         mCore->mAsyncMode = async;
-        mCore->validateConsistencyLocked();
+        VALIDATE_CONSISTENCY();
         mCore->mDequeueCondition.broadcast();
         listener = mCore->mConsumerListener;
     } // Autolock scope
@@ -495,7 +503,7 @@
                 return NO_INIT;
             }
 
-            mCore->validateConsistencyLocked();
+            VALIDATE_CONSISTENCY();
         } // Autolock scope
     }
 
@@ -566,7 +574,7 @@
     mCore->mFreeSlots.insert(slot);
     mCore->clearBufferSlotLocked(slot);
     mCore->mDequeueCondition.broadcast();
-    mCore->validateConsistencyLocked();
+    VALIDATE_CONSISTENCY();
 
     return NO_ERROR;
 }
@@ -616,7 +624,7 @@
     *outBuffer = mSlots[found].mGraphicBuffer;
     *outFence = mSlots[found].mFence;
     mCore->clearBufferSlotLocked(found);
-    mCore->validateConsistencyLocked();
+    VALIDATE_CONSISTENCY();
 
     return NO_ERROR;
 }
@@ -684,7 +692,7 @@
     mSlots[*outSlot].mRequestBufferCalled = true;
     mSlots[*outSlot].mAcquireCalled = false;
     mCore->mActiveBuffers.insert(found);
-    mCore->validateConsistencyLocked();
+    VALIDATE_CONSISTENCY();
 
     return returnFlags;
 }
@@ -861,7 +869,7 @@
         // Take a ticket for the callback functions
         callbackTicket = mNextCallbackTicket++;
 
-        mCore->validateConsistencyLocked();
+        VALIDATE_CONSISTENCY();
     } // Autolock scope
 
     // Don't send the GraphicBuffer through the callback, and don't send
@@ -948,7 +956,7 @@
 
     mSlots[slot].mFence = fence;
     mCore->mDequeueCondition.broadcast();
-    mCore->validateConsistencyLocked();
+    VALIDATE_CONSISTENCY();
 
     return NO_ERROR;
 }
@@ -1087,7 +1095,7 @@
     }
 
     mCore->mAllowAllocation = true;
-    mCore->validateConsistencyLocked();
+    VALIDATE_CONSISTENCY();
     return status;
 }
 
@@ -1252,7 +1260,7 @@
 
             mCore->mIsAllocating = false;
             mCore->mIsAllocatingCondition.broadcast();
-            mCore->validateConsistencyLocked();
+            VALIDATE_CONSISTENCY();
         } // Autolock scope
     }
 }
@@ -1316,7 +1324,8 @@
 
     mDequeueTimeout = timeout;
     mCore->mDequeueBufferCannotBlock = false;
-    mCore->validateConsistencyLocked();
+
+    VALIDATE_CONSISTENCY();
     return NO_ERROR;
 }
 
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index ac9af07..f4c47ed 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -179,6 +179,14 @@
     sp<DummyConsumer> dc(new DummyConsumer);
     mConsumer->consumerConnect(dc, false);
 
+    EXPECT_EQ(OK, mConsumer->setMaxBufferCount(10));
+    EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(10));
+
+    IGraphicBufferProducer::QueueBufferOutput qbo;
+    mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
+            &qbo);
+    mProducer->setMaxDequeuedBufferCount(3);
+
     int minBufferCount;
     ASSERT_NO_FATAL_FAILURE(GetMinUndequeuedBufferCount(&minBufferCount));
     EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(
@@ -190,8 +198,24 @@
             BufferQueue::MAX_MAX_ACQUIRED_BUFFERS+1));
     EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(100));
 
-    EXPECT_EQ(OK, mConsumer->setMaxBufferCount(5));
-    EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(5));
+    int slot;
+    sp<Fence> fence;
+    sp<GraphicBuffer> buf;
+    IGraphicBufferProducer::QueueBufferInput qbi(0, false,
+            HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+    BufferItem item;
+    EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(3));
+    for (int i = 0; i < 3; i++) {
+        ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+                mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
+                    GRALLOC_USAGE_SW_READ_OFTEN));
+        ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
+        ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
+        ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+    }
+
+    EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(2));
 }
 
 TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) {
@@ -199,12 +223,44 @@
     sp<DummyConsumer> dc(new DummyConsumer);
     mConsumer->consumerConnect(dc, false);
 
+    IGraphicBufferProducer::QueueBufferOutput qbo;
+    mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
+            &qbo);
+    mProducer->setMaxDequeuedBufferCount(2);
+
     int minBufferCount;
     ASSERT_NO_FATAL_FAILURE(GetMinUndequeuedBufferCount(&minBufferCount));
 
     EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1));
     EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(2));
     EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(minBufferCount));
+
+    int slot;
+    sp<Fence> fence;
+    sp<GraphicBuffer> buf;
+    IGraphicBufferProducer::QueueBufferInput qbi(0, false,
+            HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+    BufferItem item;
+
+    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+            mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
+            GRALLOC_USAGE_SW_READ_OFTEN));
+    ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
+    ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
+    ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+
+    EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(3));
+
+    for (int i = 0; i < 2; i++) {
+        ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+                mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
+                GRALLOC_USAGE_SW_READ_OFTEN));
+        ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
+        ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
+        ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+    }
+
     EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(
             BufferQueue::MAX_MAX_ACQUIRED_BUFFERS));
 }
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index 882b14c..45b6463 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -502,31 +502,30 @@
     ASSERT_OK(mProducer->setMaxDequeuedBufferCount(minBuffers))
             << "bufferCount: " << minBuffers;
 
-    std::vector<DequeueBufferResult> dequeueList;
-
     // Should now be able to dequeue up to minBuffers times
+    DequeueBufferResult result;
     for (int i = 0; i < minBuffers; ++i) {
-        DequeueBufferResult result;
 
         EXPECT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
                 (dequeueBuffer(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
                               TEST_PRODUCER_USAGE_BITS, &result)))
                 << "iteration: " << i << ", slot: " << result.slot;
-
-        dequeueList.push_back(result);
-    }
-
-    // Cancel every buffer, so we can set buffer count again
-    for (auto& result : dequeueList) {
-        mProducer->cancelBuffer(result.slot, result.fence);
     }
 
     ASSERT_OK(mProducer->setMaxDequeuedBufferCount(maxBuffers));
 
+    // queue the first buffer to enable max dequeued buffer count checking
+    IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
+    IGraphicBufferProducer::QueueBufferOutput output;
+    sp<GraphicBuffer> buffer;
+    ASSERT_OK(mProducer->requestBuffer(result.slot, &buffer));
+    ASSERT_OK(mProducer->queueBuffer(result.slot, input, &output));
+
+
     // Should now be able to dequeue up to maxBuffers times
+    int dequeuedSlot = -1;
+    sp<Fence> dequeuedFence;
     for (int i = 0; i < maxBuffers; ++i) {
-        int dequeuedSlot = -1;
-        sp<Fence> dequeuedFence;
 
         EXPECT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
                 (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
@@ -535,6 +534,12 @@
                                          TEST_PRODUCER_USAGE_BITS)))
                 << "iteration: " << i << ", slot: " << dequeuedSlot;
     }
+
+    // Cancel a buffer, so we can decrease the buffer count
+    ASSERT_OK(mProducer->cancelBuffer(dequeuedSlot, dequeuedFence));
+
+    // Should now be able to decrease the max dequeued count by 1
+    ASSERT_OK(mProducer->setMaxDequeuedBufferCount(maxBuffers-1));
 }
 
 TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) {
@@ -553,11 +558,12 @@
     EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(maxBuffers + 1))
             << "bufferCount: " << maxBuffers + 1;
 
-    // Prerequisite to fail out a valid setBufferCount call
-    {
-        int dequeuedSlot = -1;
-        sp<Fence> dequeuedFence;
-
+    // Set max dequeue count to 2
+    ASSERT_OK(mProducer->setMaxDequeuedBufferCount(2));
+    // Dequeue 2 buffers
+    int dequeuedSlot = -1;
+    sp<Fence> dequeuedFence;
+    for (int i = 0; i < 2; i++) {
         ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
                 (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
                                          DEFAULT_WIDTH, DEFAULT_HEIGHT,
@@ -566,8 +572,8 @@
                 << "slot: " << dequeuedSlot;
     }
 
-    // Client has one or more buffers dequeued
-    EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(minBuffers))
+    // Client has too many buffers dequeued
+    EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(1))
             << "bufferCount: " << minBuffers;
 
     // Abandon buffer queue
diff --git a/vulkan/libvulkan/loader.cpp b/vulkan/libvulkan/loader.cpp
index bc1c3b8..939f3b9 100644
--- a/vulkan/libvulkan/loader.cpp
+++ b/vulkan/libvulkan/loader.cpp
@@ -600,13 +600,6 @@
         return result;
     }
 
-    if (!LoadDriverDispatchTable(instance.drv.instance,
-                                 g_hwdevice->GetInstanceProcAddr,
-                                 enabled_extensions, instance.drv.dispatch)) {
-        DestroyInstance_Bottom(instance.handle, allocator);
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
     hwvulkan_dispatch_t* drv_dispatch =
         reinterpret_cast<hwvulkan_dispatch_t*>(instance.drv.instance);
     if (drv_dispatch->magic == HWVULKAN_DISPATCH_MAGIC) {
@@ -619,6 +612,13 @@
         return VK_ERROR_INITIALIZATION_FAILED;
     }
 
+    if (!LoadDriverDispatchTable(instance.drv.instance,
+                                 g_hwdevice->GetInstanceProcAddr,
+                                 enabled_extensions, instance.drv.dispatch)) {
+        DestroyInstance_Bottom(instance.handle, allocator);
+        return VK_ERROR_INITIALIZATION_FAILED;
+    }
+
     uint32_t num_physical_devices = 0;
     result = instance.drv.dispatch.EnumeratePhysicalDevices(
         instance.drv.instance, &num_physical_devices, nullptr);
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 2392b5c..bab5a59 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -346,10 +346,8 @@
              "swapchain re-creation not yet implemented");
     ALOGE_IF(create_info->preTransform != VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
              "swapchain preTransform not yet implemented");
-    ALOGW_IF((create_info->presentMode != VK_PRESENT_MODE_FIFO_KHR ||
-              create_info->presentMode != VK_PRESENT_MODE_MAILBOX_KHR),
-             "swapchain present mode %d not supported",
-             create_info->presentMode);
+    ALOGE_IF(create_info->presentMode != VK_PRESENT_MODE_FIFO_KHR,
+             "present modes other than FIFO are not yet implemented");
 
     // -- Configure the native window --
 
@@ -420,17 +418,6 @@
         return VK_ERROR_INITIALIZATION_FAILED;
     }
 
-    err = surface.window->setSwapInterval(
-        surface.window.get(),
-        create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1);
-    if (err != 0) {
-        // TODO(jessehall): Improve error reporting. Can we enumerate possible
-        // errors and translate them to valid Vulkan result codes?
-        ALOGE("native_window->setSwapInterval failed: %s (%d)", strerror(-err),
-              err);
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
     // -- Allocate our Swapchain object --
     // After this point, we must deallocate the swapchain on error.