Merge "Fix sensor uuid, retrofit recent event logger" into nyc-dev
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index 1ba339d..aee7bd8 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -11,4 +11,5 @@
     onrestart restart inputflinger
     onrestart restart drm
     onrestart restart cameraserver
+    writepid /dev/cpuset/system-background/tasks
 
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 620cf89..0b7ce17 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -844,30 +844,31 @@
             mCore->mQueue.push_back(item);
             frameAvailableListener = mCore->mConsumerListener;
         } else {
-            // When the queue is not empty, we need to look at the front buffer
-            // state to see if we need to replace it
-            BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
-            if (front->mIsDroppable) {
+            // When the queue is not empty, we need to look at the last buffer
+            // in the queue to see if we need to replace it
+            const BufferItem& last = mCore->mQueue.itemAt(
+                    mCore->mQueue.size() - 1);
+            if (last.mIsDroppable) {
 
-                if (!front->mIsStale) {
-                    mSlots[front->mSlot].mBufferState.freeQueued();
+                if (!last.mIsStale) {
+                    mSlots[last.mSlot].mBufferState.freeQueued();
 
                     // After leaving shared buffer mode, the shared buffer will
                     // still be around. Mark it as no longer shared if this
                     // operation causes it to be free.
                     if (!mCore->mSharedBufferMode &&
-                            mSlots[front->mSlot].mBufferState.isFree()) {
-                        mSlots[front->mSlot].mBufferState.mShared = false;
+                            mSlots[last.mSlot].mBufferState.isFree()) {
+                        mSlots[last.mSlot].mBufferState.mShared = false;
                     }
                     // Don't put the shared buffer on the free list.
-                    if (!mSlots[front->mSlot].mBufferState.isShared()) {
-                        mCore->mActiveBuffers.erase(front->mSlot);
-                        mCore->mFreeBuffers.push_back(front->mSlot);
+                    if (!mSlots[last.mSlot].mBufferState.isShared()) {
+                        mCore->mActiveBuffers.erase(last.mSlot);
+                        mCore->mFreeBuffers.push_back(last.mSlot);
                     }
                 }
 
                 // Overwrite the droppable buffer with the incoming one
-                *front = item;
+                mCore->mQueue.editItemAt(mCore->mQueue.size() - 1) = item;
                 frameReplacedListener = mCore->mConsumerListener;
             } else {
                 mCore->mQueue.push_back(item);
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index df639cd..217c821 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -605,7 +605,6 @@
     EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
     if (result == EGL_TRUE) {
         _s.terminate();
-        dp->removeSurface(surface);
     }
     return result;
 }
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index c368bad..e335a6c 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -90,31 +90,6 @@
     return false;
 }
 
-void egl_display_t::addContext(egl_context_t* context) {
-    Mutex::Autolock _l(lock);
-    contexts.add(context);
-}
-
-void egl_display_t::removeContext(egl_context_t* context) {
-    Mutex::Autolock _l(lock);
-    contexts.remove(context);
-}
-
-void egl_display_t::removeSurface(EGLSurface surface) const {
-    Mutex::Autolock _l(lock);
-    for (size_t i = 0; i < contexts.size(); i++) {
-        egl_context_t* context = contexts[i];
-        if (context->read == surface) {
-            SurfaceRef _r(get_surface(context->read));
-            _r.release();
-        }
-        if (context->draw == surface) {
-            SurfaceRef _d(get_surface(context->draw));
-            _d.release();
-        }
-    }
-}
-
 EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp) {
     if (uintptr_t(disp) >= NUM_DISPLAYS)
         return NULL;
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 0ede705..2d86295 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -68,13 +68,6 @@
     // add reference to this object. returns true if this is a valid object.
     bool getObject(egl_object_t* object) const;
 
-    // add context to this display's list
-    void addContext(egl_context_t* context);
-    // remove context from this display's list
-    void removeContext(egl_context_t* context);
-    // search for surface on all contexts and remove the references
-    void removeSurface(EGLSurface surface) const;
-
     // These notifications allow the display to keep track of how many window
     // surfaces exist, which it uses to decide whether to hibernate the
     // underlying EGL implementation. They can be called by any thread without
@@ -142,7 +135,6 @@
     mutable Mutex                       lock, refLock;
     mutable Condition                   refCond;
             SortedVector<egl_object_t*> objects;
-            SortedVector<egl_context_t*> contexts;
             String8 mVendorString;
             String8 mVersionString;
             String8 mClientApiString;
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index 8859387..918faa8 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -91,12 +91,6 @@
         egl_connection_t const* cnx, int version) :
     egl_object_t(get_display_nowake(dpy)), dpy(dpy), context(context),
             config(config), read(0), draw(0), cnx(cnx), version(version) {
-    get_display_nowake(dpy)->addContext(this);
-}
-
-void egl_context_t::terminate() {
-    display->removeContext(this);
-    egl_object_t::terminate();
 }
 
 void egl_context_t::onLooseCurrent() {
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index 8268900..17a8304 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -40,12 +40,11 @@
 class egl_display_t;
 
 class egl_object_t {
+    egl_display_t *display;
     mutable volatile int32_t count;
 
 protected:
     virtual ~egl_object_t();
-    virtual void terminate();
-    egl_display_t *display;
 
 public:
     egl_object_t(egl_display_t* display);
@@ -56,6 +55,7 @@
     inline egl_display_t* getDisplay() const { return display; }
 
 private:
+    void terminate();
     static bool get(egl_display_t const* display, egl_object_t* object);
 
 public:
@@ -143,7 +143,6 @@
 class egl_context_t: public egl_object_t {
 protected:
     ~egl_context_t() {}
-    void terminate() override;
 public:
     typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref;
 
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6ccd4ff..c640f58 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -251,7 +251,7 @@
             ALOGE("Can't replace a frame on an empty queue");
             return;
         }
-        mQueueItems.editItemAt(0) = item;
+        mQueueItems.editItemAt(mQueueItems.size() - 1) = item;
 
         // Wake up any pending callbacks
         mLastFrameNumberReceived = item.mFrameNumber;
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 17ccc72..b02f5b4 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -480,17 +480,20 @@
         if (hook->type == ProcHook::GLOBAL)
             return hook->proc;
 
+        // v0 layers expect
+        //
+        //   vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateDevice");
+        //
+        // to work.
+        if (strcmp(pName, "vkCreateDevice") == 0)
+            return hook->proc;
+
         ALOGE(
             "Invalid use of vkGetInstanceProcAddr to query %s without an "
             "instance",
             pName);
 
-        // Some naughty layers expect
-        //
-        //   vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateDevice");
-        //
-        // to work.
-        return (strcmp(pName, "vkCreateDevice") == 0) ? hook->proc : nullptr;
+        return nullptr;
     }
 
     PFN_vkVoidFunction proc;
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index 6b53a9a..4cf1c2a 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -43,75 +43,118 @@
 // probably want to intern strings, etc., and will need some custom/manual data
 // structures.
 
-// TODO(jessehall): Currently we have separate lists for instance and device
-// layers. Most layers are both; we should use one entry for each layer name,
-// with a mask saying what kind(s) it is.
-
 namespace vulkan {
 namespace api {
 
 struct Layer {
     VkLayerProperties properties;
     size_t library_idx;
-    std::vector<VkExtensionProperties> extensions;
+
+    bool is_global;
+
+    std::vector<VkExtensionProperties> instance_extensions;
+    std::vector<VkExtensionProperties> device_extensions;
 };
 
 namespace {
 
-std::mutex g_library_mutex;
-struct LayerLibrary {
-    std::string path;
-    void* dlhandle;
-    size_t refcount;
-};
-std::vector<LayerLibrary> g_layer_libraries;
-std::vector<Layer> g_instance_layers;
-std::vector<Layer> g_device_layers;
+class LayerLibrary {
+   public:
+    LayerLibrary(const std::string& path)
+        : path_(path), dlhandle_(nullptr), refcount_(0) {}
 
-void AddLayerLibrary(const std::string& path) {
-    ALOGV("examining layer library '%s'", path.c_str());
-
-    void* dlhandle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
-    if (!dlhandle) {
-        ALOGW("failed to load layer library '%s': %s", path.c_str(), dlerror());
-        return;
+    LayerLibrary(LayerLibrary&& other)
+        : path_(std::move(other.path_)),
+          dlhandle_(other.dlhandle_),
+          refcount_(other.refcount_) {
+        other.dlhandle_ = nullptr;
+        other.refcount_ = 0;
     }
 
+    LayerLibrary(const LayerLibrary&) = delete;
+    LayerLibrary& operator=(const LayerLibrary&) = delete;
+
+    // these are thread-safe
+    bool Open();
+    void Close();
+
+    bool EnumerateLayers(size_t library_idx,
+                         std::vector<Layer>& instance_layers) const;
+
+    void* GetGPA(const Layer& layer,
+                 const char* gpa_name,
+                 size_t gpa_name_len) const;
+
+   private:
+    const std::string path_;
+
+    std::mutex mutex_;
+    void* dlhandle_;
+    size_t refcount_;
+};
+
+bool LayerLibrary::Open() {
+    std::lock_guard<std::mutex> lock(mutex_);
+
+    if (refcount_++ == 0) {
+        dlhandle_ = dlopen(path_.c_str(), RTLD_NOW | RTLD_LOCAL);
+        ALOGV("Opening library %s", path_.c_str());
+        if (!dlhandle_) {
+            ALOGE("failed to load layer library '%s': %s", path_.c_str(),
+                  dlerror());
+            refcount_ = 0;
+            return false;
+        }
+    }
+    ALOGV("Refcount on activate is %zu", refcount_);
+    return true;
+}
+
+void LayerLibrary::Close() {
+    std::lock_guard<std::mutex> lock(mutex_);
+
+    if (--refcount_ == 0) {
+        ALOGV("Closing library %s", path_.c_str());
+        dlclose(dlhandle_);
+        dlhandle_ = nullptr;
+    }
+    ALOGV("Refcount on destruction is %zu", refcount_);
+}
+
+bool LayerLibrary::EnumerateLayers(size_t library_idx,
+                                   std::vector<Layer>& instance_layers) const {
     PFN_vkEnumerateInstanceLayerProperties enumerate_instance_layers =
         reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>(
-            dlsym(dlhandle, "vkEnumerateInstanceLayerProperties"));
+            dlsym(dlhandle_, "vkEnumerateInstanceLayerProperties"));
     PFN_vkEnumerateInstanceExtensionProperties enumerate_instance_extensions =
         reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>(
-            dlsym(dlhandle, "vkEnumerateInstanceExtensionProperties"));
-    PFN_vkEnumerateDeviceLayerProperties enumerate_device_layers =
-        reinterpret_cast<PFN_vkEnumerateDeviceLayerProperties>(
-            dlsym(dlhandle, "vkEnumerateDeviceLayerProperties"));
-    PFN_vkEnumerateDeviceExtensionProperties enumerate_device_extensions =
-        reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>(
-            dlsym(dlhandle, "vkEnumerateDeviceExtensionProperties"));
-    if (!((enumerate_instance_layers && enumerate_instance_extensions) ||
-          (enumerate_device_layers && enumerate_device_extensions))) {
-        ALOGV(
-            "layer library '%s' has neither instance nor device enumeraion "
-            "functions",
-            path.c_str());
-        dlclose(dlhandle);
-        return;
+            dlsym(dlhandle_, "vkEnumerateInstanceExtensionProperties"));
+    if (!enumerate_instance_layers || !enumerate_instance_extensions) {
+        ALOGV("layer library '%s' misses some instance enumeraion functions",
+              path_.c_str());
+        return false;
     }
 
-    VkResult result;
+    // device functions are optional
+    PFN_vkEnumerateDeviceLayerProperties enumerate_device_layers =
+        reinterpret_cast<PFN_vkEnumerateDeviceLayerProperties>(
+            dlsym(dlhandle_, "vkEnumerateDeviceLayerProperties"));
+    PFN_vkEnumerateDeviceExtensionProperties enumerate_device_extensions =
+        reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>(
+            dlsym(dlhandle_, "vkEnumerateDeviceExtensionProperties"));
+
+    // get layer counts
     uint32_t num_instance_layers = 0;
     uint32_t num_device_layers = 0;
-    if (enumerate_instance_layers) {
-        result = enumerate_instance_layers(&num_instance_layers, nullptr);
+    VkResult result = enumerate_instance_layers(&num_instance_layers, nullptr);
+    if (result != VK_SUCCESS || !num_instance_layers) {
         if (result != VK_SUCCESS) {
             ALOGW(
                 "vkEnumerateInstanceLayerProperties failed for library '%s': "
                 "%d",
-                path.c_str(), result);
-            dlclose(dlhandle);
-            return;
+                path_.c_str(), result);
         }
+        return false;
     }
     if (enumerate_device_layers) {
         result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
@@ -119,23 +162,19 @@
         if (result != VK_SUCCESS) {
             ALOGW(
                 "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
-                path.c_str(), result);
-            dlclose(dlhandle);
-            return;
+                path_.c_str(), result);
+            return false;
         }
     }
+
+    // get layer properties
     VkLayerProperties* properties = static_cast<VkLayerProperties*>(alloca(
         (num_instance_layers + num_device_layers) * sizeof(VkLayerProperties)));
-    if (num_instance_layers > 0) {
-        result = enumerate_instance_layers(&num_instance_layers, properties);
-        if (result != VK_SUCCESS) {
-            ALOGW(
-                "vkEnumerateInstanceLayerProperties failed for library '%s': "
-                "%d",
-                path.c_str(), result);
-            dlclose(dlhandle);
-            return;
-        }
+    result = enumerate_instance_layers(&num_instance_layers, properties);
+    if (result != VK_SUCCESS) {
+        ALOGW("vkEnumerateInstanceLayerProperties failed for library '%s': %d",
+              path_.c_str(), result);
+        return false;
     }
     if (num_device_layers > 0) {
         result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
@@ -143,102 +182,121 @@
         if (result != VK_SUCCESS) {
             ALOGW(
                 "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
-                path.c_str(), result);
-            dlclose(dlhandle);
-            return;
+                path_.c_str(), result);
+            return false;
         }
     }
 
-    size_t library_idx = g_layer_libraries.size();
-    size_t prev_num_instance_layers = g_instance_layers.size();
-    size_t prev_num_device_layers = g_device_layers.size();
-    g_instance_layers.reserve(prev_num_instance_layers + num_instance_layers);
-    g_device_layers.reserve(prev_num_device_layers + num_device_layers);
+    // append layers to instance_layers
+    size_t prev_num_instance_layers = instance_layers.size();
+    instance_layers.reserve(prev_num_instance_layers + num_instance_layers);
     for (size_t i = 0; i < num_instance_layers; i++) {
         const VkLayerProperties& props = properties[i];
 
         Layer layer;
         layer.properties = props;
         layer.library_idx = library_idx;
+        layer.is_global = false;
 
-        if (enumerate_instance_extensions) {
-            uint32_t count = 0;
-            result =
-                enumerate_instance_extensions(props.layerName, &count, nullptr);
-            if (result != VK_SUCCESS) {
-                ALOGW(
-                    "vkEnumerateInstanceExtensionProperties(%s) failed for "
-                    "library "
-                    "'%s': %d",
-                    props.layerName, path.c_str(), result);
-                g_instance_layers.resize(prev_num_instance_layers);
-                dlclose(dlhandle);
-                return;
-            }
-            layer.extensions.resize(count);
-            result = enumerate_instance_extensions(props.layerName, &count,
-                                                   layer.extensions.data());
-            if (result != VK_SUCCESS) {
-                ALOGW(
-                    "vkEnumerateInstanceExtensionProperties(%s) failed for "
-                    "library "
-                    "'%s': %d",
-                    props.layerName, path.c_str(), result);
-                g_instance_layers.resize(prev_num_instance_layers);
-                dlclose(dlhandle);
-                return;
+        uint32_t count = 0;
+        result =
+            enumerate_instance_extensions(props.layerName, &count, nullptr);
+        if (result != VK_SUCCESS) {
+            ALOGW(
+                "vkEnumerateInstanceExtensionProperties(%s) failed for library "
+                "'%s': %d",
+                props.layerName, path_.c_str(), result);
+            instance_layers.resize(prev_num_instance_layers);
+            return false;
+        }
+        layer.instance_extensions.resize(count);
+        result = enumerate_instance_extensions(
+            props.layerName, &count, layer.instance_extensions.data());
+        if (result != VK_SUCCESS) {
+            ALOGW(
+                "vkEnumerateInstanceExtensionProperties(%s) failed for library "
+                "'%s': %d",
+                props.layerName, path_.c_str(), result);
+            instance_layers.resize(prev_num_instance_layers);
+            return false;
+        }
+
+        for (size_t j = 0; j < num_device_layers; j++) {
+            const auto& dev_props = properties[num_instance_layers + j];
+            if (memcmp(&props, &dev_props, sizeof(props)) == 0) {
+                layer.is_global = true;
+                break;
             }
         }
 
-        g_instance_layers.push_back(layer);
-        ALOGV("  added instance layer '%s'", props.layerName);
-    }
-    for (size_t i = 0; i < num_device_layers; i++) {
-        const VkLayerProperties& props = properties[num_instance_layers + i];
-
-        Layer layer;
-        layer.properties = props;
-        layer.library_idx = library_idx;
-
-        if (enumerate_device_extensions) {
-            uint32_t count;
+        if (layer.is_global && enumerate_device_extensions) {
             result = enumerate_device_extensions(
                 VK_NULL_HANDLE, props.layerName, &count, nullptr);
             if (result != VK_SUCCESS) {
                 ALOGW(
                     "vkEnumerateDeviceExtensionProperties(%s) failed for "
-                    "library "
-                    "'%s': %d",
-                    props.layerName, path.c_str(), result);
-                g_instance_layers.resize(prev_num_instance_layers);
-                g_device_layers.resize(prev_num_device_layers);
-                dlclose(dlhandle);
-                return;
+                    "library '%s': %d",
+                    props.layerName, path_.c_str(), result);
+                instance_layers.resize(prev_num_instance_layers);
+                return false;
             }
-            layer.extensions.resize(count);
-            result =
-                enumerate_device_extensions(VK_NULL_HANDLE, props.layerName,
-                                            &count, layer.extensions.data());
+            layer.device_extensions.resize(count);
+            result = enumerate_device_extensions(
+                VK_NULL_HANDLE, props.layerName, &count,
+                layer.device_extensions.data());
             if (result != VK_SUCCESS) {
                 ALOGW(
                     "vkEnumerateDeviceExtensionProperties(%s) failed for "
-                    "library "
-                    "'%s': %d",
-                    props.layerName, path.c_str(), result);
-                g_instance_layers.resize(prev_num_instance_layers);
-                g_device_layers.resize(prev_num_device_layers);
-                dlclose(dlhandle);
-                return;
+                    "library '%s': %d",
+                    props.layerName, path_.c_str(), result);
+                instance_layers.resize(prev_num_instance_layers);
+                return false;
             }
         }
 
-        g_device_layers.push_back(layer);
-        ALOGV("  added device layer '%s'", props.layerName);
+        instance_layers.push_back(layer);
+        ALOGV("  added %s layer '%s'",
+              (layer.is_global) ? "global" : "instance", props.layerName);
     }
 
-    dlclose(dlhandle);
+    return true;
+}
 
-    g_layer_libraries.push_back(LayerLibrary{path, nullptr, 0});
+void* LayerLibrary::GetGPA(const Layer& layer,
+                           const char* gpa_name,
+                           size_t gpa_name_len) const {
+    void* gpa;
+    size_t layer_name_len =
+        std::max(size_t{2}, strlen(layer.properties.layerName));
+    char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1));
+    strcpy(name, layer.properties.layerName);
+    strcpy(name + layer_name_len, gpa_name);
+    if (!(gpa = dlsym(dlhandle_, name))) {
+        strcpy(name, "vk");
+        strcpy(name + 2, gpa_name);
+        gpa = dlsym(dlhandle_, name);
+    }
+    return gpa;
+}
+
+std::vector<LayerLibrary> g_layer_libraries;
+std::vector<Layer> g_instance_layers;
+
+void AddLayerLibrary(const std::string& path) {
+    ALOGV("examining layer library '%s'", path.c_str());
+
+    LayerLibrary library(path);
+    if (!library.Open())
+        return;
+
+    if (!library.EnumerateLayers(g_layer_libraries.size(), g_instance_layers)) {
+        library.Close();
+        return;
+    }
+
+    library.Close();
+
+    g_layer_libraries.emplace_back(std::move(library));
 }
 
 void DiscoverLayersInDirectory(const std::string& dir_path) {
@@ -271,71 +329,25 @@
     closedir(directory);
 }
 
+const Layer* FindInstanceLayer(const char* name) {
+    auto layer =
+        std::find_if(g_instance_layers.cbegin(), g_instance_layers.cend(),
+                     [=](const Layer& entry) {
+                         return strcmp(entry.properties.layerName, name) == 0;
+                     });
+    return (layer != g_instance_layers.cend()) ? &*layer : nullptr;
+}
+
+const Layer* FindDeviceLayer(const char* name) {
+    const Layer* layer = FindInstanceLayer(name);
+    return (layer && layer->is_global) ? layer : nullptr;
+}
+
 void* GetLayerGetProcAddr(const Layer& layer,
                           const char* gpa_name,
                           size_t gpa_name_len) {
     const LayerLibrary& library = g_layer_libraries[layer.library_idx];
-    void* gpa;
-    size_t layer_name_len = std::max(size_t{2}, strlen(layer.properties.layerName));
-    char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1));
-    strcpy(name, layer.properties.layerName);
-    strcpy(name + layer_name_len, gpa_name);
-    if (!(gpa = dlsym(library.dlhandle, name))) {
-        strcpy(name, "vk");
-        strcpy(name + 2, gpa_name);
-        gpa = dlsym(library.dlhandle, name);
-    }
-    return gpa;
-}
-
-uint32_t EnumerateLayers(const std::vector<Layer>& layers,
-                         uint32_t count,
-                         VkLayerProperties* properties) {
-    uint32_t n = std::min(count, static_cast<uint32_t>(layers.size()));
-    for (uint32_t i = 0; i < n; i++) {
-        properties[i] = layers[i].properties;
-    }
-    return static_cast<uint32_t>(layers.size());
-}
-
-void GetLayerExtensions(const std::vector<Layer>& layers,
-                        const char* name,
-                        const VkExtensionProperties** properties,
-                        uint32_t* count) {
-    auto layer =
-        std::find_if(layers.cbegin(), layers.cend(), [=](const Layer& entry) {
-            return strcmp(entry.properties.layerName, name) == 0;
-        });
-    if (layer == layers.cend()) {
-        *properties = nullptr;
-        *count = 0;
-    } else {
-        *properties = layer->extensions.data();
-        *count = static_cast<uint32_t>(layer->extensions.size());
-    }
-}
-
-LayerRef GetLayerRef(std::vector<Layer>& layers, const char* name) {
-    for (uint32_t id = 0; id < layers.size(); id++) {
-        if (strcmp(name, layers[id].properties.layerName) == 0) {
-            LayerLibrary& library = g_layer_libraries[layers[id].library_idx];
-            std::lock_guard<std::mutex> lock(g_library_mutex);
-            if (library.refcount++ == 0) {
-                library.dlhandle =
-                    dlopen(library.path.c_str(), RTLD_NOW | RTLD_LOCAL);
-                ALOGV("Opening library %s", library.path.c_str());
-                if (!library.dlhandle) {
-                    ALOGE("failed to load layer library '%s': %s",
-                          library.path.c_str(), dlerror());
-                    library.refcount = 0;
-                    return LayerRef(nullptr);
-                }
-            }
-            ALOGV("Refcount on activate is %zu", library.refcount);
-            return LayerRef(&layers[id]);
-        }
-    }
-    return LayerRef(nullptr);
+    return library.GetGPA(layer, gpa_name, gpa_name_len);
 }
 
 }  // anonymous namespace
@@ -349,45 +361,84 @@
 
 uint32_t EnumerateInstanceLayers(uint32_t count,
                                  VkLayerProperties* properties) {
-    return EnumerateLayers(g_instance_layers, count, properties);
+    uint32_t n =
+        std::min(count, static_cast<uint32_t>(g_instance_layers.size()));
+    for (uint32_t i = 0; i < n; i++)
+        properties[i] = g_instance_layers[i].properties;
+
+    return static_cast<uint32_t>(g_instance_layers.size());
 }
 
 uint32_t EnumerateDeviceLayers(uint32_t count, VkLayerProperties* properties) {
-    return EnumerateLayers(g_device_layers, count, properties);
+    uint32_t n = 0;
+    for (const auto& layer : g_instance_layers) {
+        // ignore non-global layers
+        if (!layer.is_global)
+            continue;
+
+        if (n < count)
+            properties[n] = layer.properties;
+        n++;
+    }
+
+    return n;
 }
 
 void GetInstanceLayerExtensions(const char* name,
                                 const VkExtensionProperties** properties,
                                 uint32_t* count) {
-    GetLayerExtensions(g_instance_layers, name, properties, count);
+    const Layer* layer = FindInstanceLayer(name);
+    if (layer) {
+        *properties = layer->instance_extensions.data();
+        *count = static_cast<uint32_t>(layer->instance_extensions.size());
+    } else {
+        *properties = nullptr;
+        *count = 0;
+    }
 }
 
 void GetDeviceLayerExtensions(const char* name,
                               const VkExtensionProperties** properties,
                               uint32_t* count) {
-    GetLayerExtensions(g_device_layers, name, properties, count);
+    const Layer* layer = FindDeviceLayer(name);
+    if (layer) {
+        *properties = layer->device_extensions.data();
+        *count = static_cast<uint32_t>(layer->device_extensions.size());
+    } else {
+        *properties = nullptr;
+        *count = 0;
+    }
 }
 
 LayerRef GetInstanceLayerRef(const char* name) {
-    return GetLayerRef(g_instance_layers, name);
+    const Layer* layer = FindInstanceLayer(name);
+    if (layer) {
+        LayerLibrary& library = g_layer_libraries[layer->library_idx];
+        if (!library.Open())
+            layer = nullptr;
+    }
+
+    return LayerRef(layer, true);
 }
 
 LayerRef GetDeviceLayerRef(const char* name) {
-    return GetLayerRef(g_device_layers, name);
+    const Layer* layer = FindDeviceLayer(name);
+    if (layer) {
+        LayerLibrary& library = g_layer_libraries[layer->library_idx];
+        if (!library.Open())
+            layer = nullptr;
+    }
+
+    return LayerRef(layer, false);
 }
 
-LayerRef::LayerRef(Layer* layer) : layer_(layer) {}
+LayerRef::LayerRef(const Layer* layer, bool is_instance)
+    : layer_(layer), is_instance_(is_instance) {}
 
 LayerRef::~LayerRef() {
     if (layer_) {
         LayerLibrary& library = g_layer_libraries[layer_->library_idx];
-        std::lock_guard<std::mutex> lock(g_library_mutex);
-        if (--library.refcount == 0) {
-            ALOGV("Closing library %s", library.path.c_str());
-            dlclose(library.dlhandle);
-            library.dlhandle = nullptr;
-        }
-        ALOGV("Refcount on destruction is %zu", library.refcount);
+        library.Close();
     }
 }
 
@@ -395,11 +446,12 @@
     return layer_->properties.layerName;
 }
 
-uint32_t LayerRef::GetSpecVersion() {
+uint32_t LayerRef::GetSpecVersion() const {
     return layer_->properties.specVersion;
 }
 
-LayerRef::LayerRef(LayerRef&& other) : layer_(std::move(other.layer_)) {
+LayerRef::LayerRef(LayerRef&& other)
+    : layer_(other.layer_), is_instance_(other.is_instance_) {
     other.layer_ = nullptr;
 }
 
@@ -416,10 +468,12 @@
 }
 
 bool LayerRef::SupportsExtension(const char* name) const {
-    return std::find_if(layer_->extensions.cbegin(), layer_->extensions.cend(),
+    const auto& extensions = (is_instance_) ? layer_->instance_extensions
+                                            : layer_->device_extensions;
+    return std::find_if(extensions.cbegin(), extensions.cend(),
                         [=](const VkExtensionProperties& ext) {
                             return strcmp(ext.extensionName, name) == 0;
-                        }) != layer_->extensions.cend();
+                        }) != extensions.cend();
 }
 
 }  // namespace api
diff --git a/vulkan/libvulkan/layers_extensions.h b/vulkan/libvulkan/layers_extensions.h
index 7e7bfd3..e2eb32b 100644
--- a/vulkan/libvulkan/layers_extensions.h
+++ b/vulkan/libvulkan/layers_extensions.h
@@ -25,14 +25,14 @@
 struct Layer;
 class LayerRef {
    public:
-    LayerRef(Layer* layer);
+    LayerRef(const Layer* layer, bool is_instance);
     LayerRef(LayerRef&& other);
     ~LayerRef();
     LayerRef(const LayerRef&) = delete;
     LayerRef& operator=(const LayerRef&) = delete;
 
     const char* GetName() const;
-    uint32_t GetSpecVersion();
+    uint32_t GetSpecVersion() const;
 
     // provides bool-like behavior
     operator const Layer*() const { return layer_; }
@@ -43,7 +43,8 @@
     bool SupportsExtension(const char* name) const;
 
    private:
-    Layer* layer_;
+    const Layer* layer_;
+    bool is_instance_;
 };
 
 void DiscoverLayers();
diff --git a/vulkan/libvulkan/stubhal.cpp b/vulkan/libvulkan/stubhal.cpp
index 89fcebb..a74d370 100644
--- a/vulkan/libvulkan/stubhal.cpp
+++ b/vulkan/libvulkan/stubhal.cpp
@@ -83,7 +83,7 @@
     std::lock_guard<std::mutex> lock(g_instance_mutex);
     ssize_t idx =
         reinterpret_cast<hwvulkan_dispatch_t*>(instance) - &g_instances[0];
-    ALOG_ASSERT(idx >= 0 && idx < g_instance_used.size(),
+    ALOG_ASSERT(idx >= 0 && static_cast<size_t>(idx) < g_instance_used.size(),
                 "DestroyInstance: invalid instance handle");
     g_instance_used[static_cast<size_t>(idx)] = false;
 }
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index e990cf4..69e8e84 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -329,6 +329,17 @@
     int err;
     VkResult result = VK_SUCCESS;
 
+    ALOGV("vkCreateSwapchainKHR: surface=0x%" PRIx64
+          " minImageCount=%u imageFormat=%u imageColorSpace=%u"
+          " imageExtent=%ux%u imageUsage=%#x preTransform=%u presentMode=%u"
+          " oldSwapchain=0x%" PRIx64,
+          reinterpret_cast<uint64_t>(create_info->surface),
+          create_info->minImageCount, create_info->imageFormat,
+          create_info->imageColorSpace, create_info->imageExtent.width,
+          create_info->imageExtent.height, create_info->imageUsage,
+          create_info->preTransform, create_info->presentMode,
+          reinterpret_cast<uint64_t>(create_info->oldSwapchain));
+
     if (!allocator)
         allocator = &GetData(device).allocator;
 
@@ -348,9 +359,32 @@
              "swapchain present mode %d not supported",
              create_info->presentMode);
 
+    Surface& surface = *SurfaceFromHandle(create_info->surface);
+
+    // -- Reset the native window --
+    // The native window might have been used previously, and had its properties
+    // changed from defaults. That will affect the answer we get for queries
+    // like MIN_UNDEQUED_BUFFERS. Reset to a known/default state before we
+    // attempt such queries.
+
+    err = native_window_set_buffer_count(surface.window.get(), 0);
+    if (err != 0) {
+        ALOGE("native_window_set_buffer_count(0) failed: %s (%d)",
+              strerror(-err), err);
+        return VK_ERROR_INITIALIZATION_FAILED;
+    }
+
+    err = surface.window->setSwapInterval(surface.window.get(), 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(1) failed: %s (%d)",
+              strerror(-err), err);
+        return VK_ERROR_INITIALIZATION_FAILED;
+    }
+
     // -- Configure the native window --
 
-    Surface& surface = *SurfaceFromHandle(create_info->surface);
     const auto& dispatch = GetData(device).driver;
 
     int native_format = HAL_PIXEL_FORMAT_RGBA_8888;
@@ -451,8 +485,8 @@
     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_buffer_count failed: %s (%d)", strerror(-err),
-              err);
+        ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images,
+              strerror(-err), err);
         return VK_ERROR_INITIALIZATION_FAILED;
     }
 
@@ -477,14 +511,14 @@
         return VK_ERROR_INITIALIZATION_FAILED;
     }
 
-    err = surface.window->setSwapInterval(
-        surface.window.get(),
-        create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1);
+    int swap_interval =
+        create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1;
+    err = surface.window->setSwapInterval(surface.window.get(), swap_interval);
     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);
+        ALOGE("native_window->setSwapInterval(%d) failed: %s (%d)",
+              swap_interval, strerror(-err), err);
         return VK_ERROR_INITIALIZATION_FAILED;
     }
 
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index 6f57238..f29cb68 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -19,6 +19,7 @@
 #include <algorithm>
 #include <array>
 #include <inttypes.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include <log/log.h>
@@ -186,6 +187,58 @@
         AllocHandle(type, &device->next_handle[type]));
 }
 
+VKAPI_ATTR void* DefaultAllocate(void*,
+                                 size_t size,
+                                 size_t alignment,
+                                 VkSystemAllocationScope) {
+    void* ptr = nullptr;
+    // Vulkan requires 'alignment' to be a power of two, but posix_memalign
+    // additionally requires that it be at least sizeof(void*).
+    int ret = posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size);
+    return ret == 0 ? ptr : nullptr;
+}
+
+VKAPI_ATTR void* DefaultReallocate(void*,
+                                   void* ptr,
+                                   size_t size,
+                                   size_t alignment,
+                                   VkSystemAllocationScope) {
+    if (size == 0) {
+        free(ptr);
+        return nullptr;
+    }
+
+    // TODO(jessehall): Right now we never shrink allocations; if the new
+    // request is smaller than the existing chunk, we just continue using it.
+    // The null driver never reallocs, so this doesn't matter. If that changes,
+    // or if this code is copied into some other project, this should probably
+    // have a heuristic to allocate-copy-free when doing so will save "enough"
+    // space.
+    size_t old_size = ptr ? malloc_usable_size(ptr) : 0;
+    if (size <= old_size)
+        return ptr;
+
+    void* new_ptr = nullptr;
+    if (posix_memalign(&new_ptr, std::max(alignment, sizeof(void*)), size) != 0)
+        return nullptr;
+    if (ptr) {
+        memcpy(new_ptr, ptr, std::min(old_size, size));
+        free(ptr);
+    }
+    return new_ptr;
+}
+
+VKAPI_ATTR void DefaultFree(void*, void* ptr) {
+    free(ptr);
+}
+
+const VkAllocationCallbacks kDefaultAllocCallbacks = {
+    .pUserData = nullptr,
+    .pfnAllocation = DefaultAllocate,
+    .pfnReallocation = DefaultReallocate,
+    .pfnFree = DefaultFree,
+};
+
 }  // namespace
 
 namespace null_driver {
@@ -239,10 +292,8 @@
 VkResult CreateInstance(const VkInstanceCreateInfo* create_info,
                         const VkAllocationCallbacks* allocator,
                         VkInstance* out_instance) {
-    // Assume the loader provided alloc callbacks even if the app didn't.
-    ALOG_ASSERT(
-        allocator,
-        "Missing alloc callbacks, loader or app should have provided them");
+    if (!allocator)
+        allocator = &kDefaultAllocCallbacks;
 
     VkInstance_T* instance =
         static_cast<VkInstance_T*>(allocator->pfnAllocation(
diff --git a/vulkan/tools/vkinfo.cpp b/vulkan/tools/vkinfo.cpp
index e97e5f5..62d8240 100644
--- a/vulkan/tools/vkinfo.cpp
+++ b/vulkan/tools/vkinfo.cpp
@@ -162,8 +162,11 @@
     uint32_t num_extensions = 0;
     for (const auto& desired_ext : kDesiredExtensions) {
         bool available = HasExtension(info.extensions, desired_ext);
-        for (size_t i = 0; !available && i < info.layer_extensions.size(); i++)
-            available = HasExtension(info.layer_extensions[i], desired_ext);
+        if (options.validate) {
+            for (size_t i = 0; !available && i < info.layer_extensions.size();
+                 i++)
+                available = HasExtension(info.layer_extensions[i], desired_ext);
+        }
         if (available)
             extensions[num_extensions++] = desired_ext;
     }
@@ -179,12 +182,11 @@
     // clang-format off
     const char *kValidationLayers[] = {
         "VK_LAYER_GOOGLE_threading",
+        "VK_LAYER_LUNARG_parameter_validation",
         "VK_LAYER_LUNARG_device_limits",
-        "VK_LAYER_LUNARG_draw_state",
-        "VK_LAYER_LUNARG_image",
-        "VK_LAYER_LUNARG_mem_tracker",
         "VK_LAYER_LUNARG_object_tracker",
-        "VK_LAYER_LUNARG_param_checker",
+        "VK_LAYER_LUNARG_image",
+        "VK_LAYER_LUNARG_core_validation",
         "VK_LAYER_LUNARG_swapchain",
         "VK_LAYER_GOOGLE_unique_objects"
     };
@@ -236,8 +238,12 @@
     uint32_t num_extensions = 0;
     for (const auto& desired_ext : kDesiredExtensions) {
         bool available = HasExtension(info->extensions, desired_ext);
-        for (size_t i = 0; !available && i < info->layer_extensions.size(); i++)
-            available = HasExtension(info->layer_extensions[i], desired_ext);
+        if (options.validate) {
+            for (size_t i = 0; !available && i < info->layer_extensions.size();
+                 i++)
+                available =
+                    HasExtension(info->layer_extensions[i], desired_ext);
+        }
         if (available)
             extensions[num_extensions++] = desired_ext;
     }
@@ -245,12 +251,11 @@
     // clang-format off
     const char *kValidationLayers[] = {
         "VK_LAYER_GOOGLE_threading",
+        "VK_LAYER_LUNARG_parameter_validation",
         "VK_LAYER_LUNARG_device_limits",
-        "VK_LAYER_LUNARG_draw_state",
-        "VK_LAYER_LUNARG_image",
-        "VK_LAYER_LUNARG_mem_tracker",
         "VK_LAYER_LUNARG_object_tracker",
-        "VK_LAYER_LUNARG_param_checker",
+        "VK_LAYER_LUNARG_image",
+        "VK_LAYER_LUNARG_core_validation",
         "VK_LAYER_LUNARG_swapchain",
         "VK_LAYER_GOOGLE_unique_objects"
     };