Merge "Add Surface::waitForNextFrame" into nyc-dev
diff --git a/cmds/bugreport/bugreport.cpp b/cmds/bugreport/bugreport.cpp
index 6892b57..917c813 100644
--- a/cmds/bugreport/bugreport.cpp
+++ b/cmds/bugreport/bugreport.cpp
@@ -28,6 +28,11 @@
 // output. All of the dumpstate output is written to stdout, including
 // any errors encountered while reading/writing the output.
 int main() {
+
+  fprintf(stderr, "=============================================================================\n");
+  fprintf(stderr, "WARNING: flat bugreports are deprecated, use adb bugreport <zip_file> instead\n");
+  fprintf(stderr, "=============================================================================\n\n\n");
+
   // Start the dumpstate service.
   property_set("ctl.start", "dumpstate");
 
diff --git a/cmds/bugreportz/Android.mk b/cmds/bugreportz/Android.mk
new file mode 100644
index 0000000..14ba225
--- /dev/null
+++ b/cmds/bugreportz/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= bugreportz.cpp
+
+LOCAL_MODULE:= bugreportz
+
+LOCAL_CFLAGS := -Wall
+
+LOCAL_SHARED_LIBRARIES := libcutils
+
+include $(BUILD_EXECUTABLE)
diff --git a/cmds/bugreportz/bugreportz.cpp b/cmds/bugreportz/bugreportz.cpp
new file mode 100644
index 0000000..b6856bb
--- /dev/null
+++ b/cmds/bugreportz/bugreportz.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cutils/properties.h>
+#include <cutils/sockets.h>
+
+// TODO: code below was copy-and-pasted from bugreport.cpp (except by the timeout value);
+// should be reused instead.
+int main() {
+
+    // Start the dumpstatez service.
+    property_set("ctl.start", "dumpstatez");
+
+    // Socket will not be available until service starts.
+    int s;
+    for (int i = 0; i < 20; i++) {
+        s = socket_local_client("dumpstate", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
+        if (s >= 0)
+            break;
+        // Try again in 1 second.
+        sleep(1);
+    }
+
+    if (s == -1) {
+        printf("Failed to connect to dumpstatez service: %s\n", strerror(errno));
+        return 1;
+    }
+
+    // Set a timeout so that if nothing is read in 10 minutes, we'll stop
+    // reading and quit. No timeout in dumpstate is longer than 60 seconds,
+    // so this gives lots of leeway in case of unforeseen time outs.
+    struct timeval tv;
+    tv.tv_sec = 10 * 60;
+    tv.tv_usec = 0;
+    if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
+        printf("WARNING: Cannot set socket timeout: %s\n", strerror(errno));
+    }
+
+    while (1) {
+        char buffer[65536];
+        ssize_t bytes_read = TEMP_FAILURE_RETRY(
+                read(s, buffer, sizeof(buffer)));
+        if (bytes_read == 0) {
+            break;
+        } else if (bytes_read == -1) {
+            // EAGAIN really means time out, so change the errno.
+            if (errno == EAGAIN) {
+                errno = ETIMEDOUT;
+            }
+            printf("\nBugreport read terminated abnormally (%s).\n",
+                    strerror(errno));
+            break;
+        }
+
+        ssize_t bytes_to_send = bytes_read;
+        ssize_t bytes_written;
+        do {
+            bytes_written = TEMP_FAILURE_RETRY(
+                    write(STDOUT_FILENO, buffer + bytes_read - bytes_to_send,
+                            bytes_to_send));
+            if (bytes_written == -1) {
+                printf(
+                        "Failed to write data to stdout: read %zd, trying to send %zd (%s)\n",
+                        bytes_read, bytes_to_send, strerror(errno));
+                return 1;
+            }
+            bytes_to_send -= bytes_written;
+        } while (bytes_written != 0 && bytes_to_send > 0);
+    }
+
+    close(s);
+    return 0;
+
+}
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index f486e08..ea14c66 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -63,6 +63,7 @@
 void add_mountinfo();
 static bool add_zip_entry(const std::string& entry_name, const std::string& entry_path);
 static bool add_zip_entry_from_fd(const std::string& entry_name, int fd);
+static int control_socket_fd;
 
 #define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
 
@@ -92,8 +93,7 @@
  * See bugreport-format.txt for more info.
  */
 // TODO: change to "v1" before final N build
-static std::string VERSION_DEFAULT = "v1-dev3";
-static std::string VERSION_BUILD_ON_NAME = "v1-dev4";
+static std::string VERSION_DEFAULT = "v1-dev4";
 
 /* gets the tombstone data, according to the bugreport type: if zipped gets all tombstones,
  * otherwise gets just those modified in the last half an hour. */
@@ -929,20 +929,26 @@
 }
 
 static void usage() {
-    fprintf(stderr, "usage: dumpstate [-b soundfile] [-e soundfile] [-o file [-d] [-p] [-z]] [-s] [-q] [-B] [-P] [-R] [-V version]\n"
-            "  -b: play sound file instead of vibrate, at beginning of job\n"
-            "  -e: play sound file instead of vibrate, at end of job\n"
-            "  -o: write to file (instead of stdout)\n"
-            "  -d: append date to filename (requires -o)\n"
-            "  -p: capture screenshot to filename.png (requires -o)\n"
-            "  -z: generates zipped file (requires -o)\n"
-            "  -s: write output to control socket (for init)\n"
-            "  -q: disable vibrate\n"
-            "  -B: send broadcast when finished (requires -o)\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 (valid values: %s, %s)\n",
-            VERSION_DEFAULT.c_str(), VERSION_BUILD_ON_NAME.c_str());
+  fprintf(stderr,
+          "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] "
+          "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
+          "  -h: display this help message\n"
+          "  -b: play sound file instead of vibrate, at beginning of job\n"
+          "  -e: play sound file instead of vibrate, at end of job\n"
+          "  -o: write to file (instead of stdout)\n"
+          "  -d: append date to filename (requires -o)\n"
+          "  -p: capture screenshot to filename.png (requires -o)\n"
+          "  -z: generate zipped file (requires -o)\n"
+          "  -s: write output to control socket (for init)\n"
+          "  -S: write file location to control socket (for init; requires -o and -z)"
+          "  -q: disable vibrate\n"
+          "  -B: send broadcast when finished (requires -o)\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 (valid values: %s)\n",
+          VERSION_DEFAULT.c_str());
 }
 
 static void sigpipe_handler(int n) {
@@ -1014,6 +1020,7 @@
     int do_vibrate = 1;
     char* use_outfile = 0;
     int use_socket = 0;
+    int use_control_socket = 0;
     int do_fb = 0;
     int do_broadcast = 0;
     int do_early_screenshot = 0;
@@ -1022,15 +1029,6 @@
 
     now = time(NULL);
 
-    if (getuid() != 0) {
-        // Old versions of the adb client would call the
-        // dumpstate command directly. Newer clients
-        // call /system/bin/bugreport instead. If we detect
-        // we're being called incorrectly, then exec the
-        // correct program.
-        return execl("/system/bin/bugreport", "/system/bin/bugreport", NULL);
-    }
-
     MYLOGI("begin\n");
 
     /* gets the sequential id */
@@ -1059,12 +1057,13 @@
     format_args(argc, const_cast<const char **>(argv), &args);
     MYLOGD("Dumpstate command line: %s\n", args.c_str());
     int c;
-    while ((c = getopt(argc, argv, "dho:svqzpPBRV:")) != -1) {
+    while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
         switch (c) {
             case 'd': do_add_date = 1;          break;
             case 'z': do_zip_file = 1;          break;
             case 'o': use_outfile = optarg;     break;
             case 's': use_socket = 1;           break;
+            case 'S': use_control_socket = 1;   break;
             case 'v': break;  // compatibility no-op
             case 'q': do_vibrate = 0;           break;
             case 'p': do_fb = 1;                break;
@@ -1084,6 +1083,11 @@
         exit(1);
     }
 
+    if (use_control_socket && !do_zip_file) {
+        usage();
+        exit(1);
+    }
+
     if (do_update_progress && !do_broadcast) {
         usage();
         exit(1);
@@ -1094,9 +1098,9 @@
         exit(1);
     }
 
-    if (version != VERSION_DEFAULT && version != VERSION_BUILD_ON_NAME) {
-        usage();
-        exit(1);
+    if (version != VERSION_DEFAULT) {
+      usage();
+      exit(1);
     }
 
     MYLOGI("bugreport format version: %s\n", version.c_str());
@@ -1109,6 +1113,11 @@
         redirect_to_socket(stdout, "dumpstate");
     }
 
+    if (use_control_socket) {
+        MYLOGD("Opening control socket\n");
+        control_socket_fd = open_socket("dumpstate");
+    }
+
     /* full path of the directory where the bugreport files will be written */
     std::string bugreport_dir;
 
@@ -1150,11 +1159,9 @@
         } else {
             suffix = "undated";
         }
-        if (version == VERSION_BUILD_ON_NAME) {
-            char build_id[PROPERTY_VALUE_MAX];
-            property_get("ro.build.id", build_id, "UNKNOWN_BUILD");
-            base_name = base_name + "-" + build_id;
-        }
+        char build_id[PROPERTY_VALUE_MAX];
+        property_get("ro.build.id", build_id, "UNKNOWN_BUILD");
+        base_name = base_name + "-" + build_id;
         if (do_fb) {
             // TODO: if dumpstate was an object, the paths could be internal variables and then
             // we could have a function to calculate the derived values, such as:
@@ -1350,6 +1357,14 @@
                 path.clear();
             }
         }
+        if (use_control_socket) {
+            if (do_text_file) {
+                dprintf(control_socket_fd, "FAIL:could not create zip file, check %s "
+                        "for more details\n", log_path.c_str());
+            } else {
+                dprintf(control_socket_fd, "OK:%s\n", path.c_str());
+            }
+        }
     }
 
     /* vibrate a few but shortly times to let user know it's finished */
@@ -1397,5 +1412,10 @@
         fclose(stderr);
     }
 
+    if (use_control_socket && control_socket_fd >= 0) {
+        MYLOGD("Closing control socket\n");
+        close(control_socket_fd);
+    }
+
     return 0;
 }
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index baba0f9..c51c79a 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -130,6 +130,9 @@
 /* prints all the system properties */
 void print_properties();
 
+/** opens a socket and returns its file descriptor */
+int open_socket(const char *service);
+
 /* redirect output to a service control socket */
 void redirect_to_socket(FILE *redirect, const char *service);
 
diff --git a/cmds/dumpstate/dumpstate.rc b/cmds/dumpstate/dumpstate.rc
index 96232c4..1f56d21 100644
--- a/cmds/dumpstate/dumpstate.rc
+++ b/cmds/dumpstate/dumpstate.rc
@@ -9,6 +9,15 @@
     disabled
     oneshot
 
+# dumpstatez generates a zipped bugreport but also uses a socket to print the file location once
+# it is finished.
+service dumpstatez /system/bin/dumpstate -S -d -z \
+        -o /data/user_de/0/com.android.shell/files/bugreports/bugreport
+    socket dumpstate stream 0660 shell log
+    class main
+    disabled
+    oneshot
+
 # bugreportplus is an enhanced version of bugreport that provides a better
 # user interface (like displaying progress and allowing user to enter details).
 # It's typically triggered by the power button or developer settings.
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index d9738bb..da4b5ad 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -909,8 +909,7 @@
     printf("\n");
 }
 
-/* redirect output to a service control socket */
-void redirect_to_socket(FILE *redirect, const char *service) {
+int open_socket(const char *service) {
     int s = android_get_control_socket(service);
     if (s < 0) {
         MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
@@ -930,11 +929,18 @@
         exit(1);
     }
 
+    return fd;
+}
+
+/* redirect output to a service control socket */
+void redirect_to_socket(FILE *redirect, const char *service) {
+    int fd = open_socket(service);
     fflush(redirect);
     dup2(fd, fileno(redirect));
     close(fd);
 }
 
+// TODO: should call is_valid_output_file and/or be merged into it.
 void create_parent_dirs(const char *path) {
     char *chp = const_cast<char *> (path);
 
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index 2bfea63..20ad5f9 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -74,7 +74,7 @@
     uid_t uid = multiuser_get_uid(userid, appid);
     int target_mode = target_sdk_version >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
     if (flags & FLAG_STORAGE_CE) {
-        auto path = create_data_user_package_path(uuid, userid, pkgname);
+        auto path = create_data_user_ce_package_path(uuid, userid, pkgname);
         if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, uid) != 0) {
             PLOG(ERROR) << "Failed to prepare " << path;
             return -1;
@@ -124,7 +124,7 @@
     // consistent location.  This only works on non-FBE devices, since we
     // never want to risk exposing data on a device with real CE/DE storage.
 
-    auto ce_path = create_data_user_package_path(uuid, userid, pkgname);
+    auto ce_path = create_data_user_ce_package_path(uuid, userid, pkgname);
     auto de_path = create_data_user_de_package_path(uuid, userid, pkgname);
 
     // If neither directory is marked as default, assume CE is default
@@ -234,7 +234,8 @@
     return success ? 0 : -1;
 }
 
-int clear_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags) {
+int clear_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
+        ino_t ce_data_inode) {
     std::string suffix = "";
     bool only_cache = false;
     if (flags & FLAG_CLEAR_CACHE_ONLY) {
@@ -247,7 +248,7 @@
 
     int res = 0;
     if (flags & FLAG_STORAGE_CE) {
-        auto path = create_data_user_package_path(uuid, userid, pkgname) + suffix;
+        auto path = create_data_user_ce_package_path(uuid, userid, pkgname, ce_data_inode) + suffix;
         if (access(path.c_str(), F_OK) == 0) {
             res |= delete_dir_contents(path);
         }
@@ -289,11 +290,12 @@
     return result;
 }
 
-int destroy_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags) {
+int destroy_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
+        ino_t ce_data_inode) {
     int res = 0;
     if (flags & FLAG_STORAGE_CE) {
         res |= delete_dir_contents_and_dir(
-                create_data_user_package_path(uuid, userid, pkgname));
+                create_data_user_ce_package_path(uuid, userid, pkgname, ce_data_inode));
     }
     if (flags & FLAG_STORAGE_DE) {
         res |= delete_dir_contents_and_dir(
@@ -346,9 +348,9 @@
     // Copy private data for all known users
     // TODO: handle user_de paths
     for (auto user : users) {
-        std::string from(create_data_user_package_path(from_uuid, user, package_name));
-        std::string to(create_data_user_package_path(to_uuid, user, package_name));
-        std::string to_parent(create_data_user_path(to_uuid, user));
+        std::string from(create_data_user_ce_package_path(from_uuid, user, package_name));
+        std::string to(create_data_user_ce_package_path(to_uuid, user, package_name));
+        std::string to_parent(create_data_user_ce_path(to_uuid, user));
 
         // Data source may not exist for all users; that's okay
         if (access(from.c_str(), F_OK) != 0) {
@@ -356,7 +358,7 @@
             continue;
         }
 
-        std::string user_path(create_data_user_path(to_uuid, user));
+        std::string user_path(create_data_user_ce_path(to_uuid, user));
         if (fs_prepare_dir(user_path.c_str(), 0771, AID_SYSTEM, AID_SYSTEM) != 0) {
             LOG(ERROR) << "Failed to prepare user target " << user_path;
             goto fail;
@@ -409,7 +411,7 @@
         }
     }
     for (auto user : users) {
-        std::string to(create_data_user_package_path(to_uuid, user, package_name));
+        std::string to(create_data_user_ce_package_path(to_uuid, user, package_name));
         if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
             LOG(WARNING) << "Failed to rollback " << to;
         }
@@ -429,7 +431,7 @@
 int delete_user(const char *uuid, userid_t userid) {
     int res = 0;
 
-    std::string data_path(create_data_user_path(uuid, userid));
+    std::string data_path(create_data_user_ce_path(uuid, userid));
     std::string data_de_path(create_data_user_de_path(uuid, userid));
     std::string media_path(create_data_media_path(uuid, userid));
     std::string profiles_path(create_data_user_profiles_path(userid));
@@ -480,7 +482,7 @@
 
     // Special case for owner on internal storage
     if (uuid == nullptr) {
-        std::string _tmpdir(create_data_user_path(nullptr, 0));
+        std::string _tmpdir(create_data_user_ce_path(nullptr, 0));
         add_cache_files(cache, _tmpdir.c_str(), "cache");
     }
 
@@ -567,142 +569,96 @@
     }
 }
 
-int get_app_size(const char *uuid, const char *pkgname, int userid, int flags,
-        const char *apkpath, const char *libdirpath, const char *fwdlock_apkpath,
-        const char *asecpath, const char *instruction_set, int64_t *_codesize, int64_t *_datasize,
-        int64_t *_cachesize, int64_t* _asecsize) {
+static void add_app_data_size(std::string& path, int64_t *codesize, int64_t *datasize,
+        int64_t *cachesize) {
     DIR *d;
     int dfd;
     struct dirent *de;
     struct stat s;
-    char path[PKG_PATH_MAX];
 
-    int64_t codesize = 0;
-    int64_t datasize = 0;
-    int64_t cachesize = 0;
-    int64_t asecsize = 0;
+    d = opendir(path.c_str());
+    if (d == nullptr) {
+        PLOG(WARNING) << "Failed to open " << path;
+        return;
+    }
+    dfd = dirfd(d);
+    while ((de = readdir(d))) {
+        const char *name = de->d_name;
 
-    /* count the source apk as code -- but only if it's not
-     * on the /system partition and its not on the sdcard. */
-    if (validate_system_app_path(apkpath) &&
-            strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) {
-        if (stat(apkpath, &s) == 0) {
-            codesize += stat_size(&s);
-            if (S_ISDIR(s.st_mode)) {
-                d = opendir(apkpath);
-                if (d != NULL) {
-                    dfd = dirfd(d);
-                    codesize += calculate_dir_size(dfd);
-                    closedir(d);
-                }
+        int64_t statsize = 0;
+        if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
+            statsize = stat_size(&s);
+        }
+
+        if (de->d_type == DT_DIR) {
+            int subfd;
+            int64_t dirsize = 0;
+            /* always skip "." and ".." */
+            if (name[0] == '.') {
+                if (name[1] == 0) continue;
+                if ((name[1] == '.') && (name[2] == 0)) continue;
             }
-        }
-    }
-
-    /* count the forward locked apk as code if it is given */
-    if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
-        if (stat(fwdlock_apkpath, &s) == 0) {
-            codesize += stat_size(&s);
-        }
-    }
-
-    /* count the cached dexfile as code */
-    if (create_cache_path(path, apkpath, instruction_set)) {
-        if (stat(path, &s) == 0) {
-            codesize += stat_size(&s);
-        }
-    }
-
-    /* add in size of any libraries */
-    if (libdirpath != NULL && libdirpath[0] != '!') {
-        d = opendir(libdirpath);
-        if (d != NULL) {
-            dfd = dirfd(d);
-            codesize += calculate_dir_size(dfd);
-            closedir(d);
-        }
-    }
-
-    /* compute asec size if it is given */
-    if (asecpath != NULL && asecpath[0] != '!') {
-        if (stat(asecpath, &s) == 0) {
-            asecsize += stat_size(&s);
-        }
-    }
-
-    std::vector<userid_t> users;
-    if (userid == -1) {
-        users = get_known_users(uuid);
-    } else {
-        users.push_back(userid);
-    }
-
-    for (auto user : users) {
-        // TODO: handle user_de directories
-        if (!(flags & FLAG_STORAGE_CE)) continue;
-
-        std::string _pkgdir(create_data_user_package_path(uuid, user, pkgname));
-        const char* pkgdir = _pkgdir.c_str();
-
-        d = opendir(pkgdir);
-        if (d == NULL) {
-            PLOG(WARNING) << "Failed to open " << pkgdir;
-            continue;
-        }
-        dfd = dirfd(d);
-
-        /* most stuff in the pkgdir is data, except for the "cache"
-         * directory and below, which is cache, and the "lib" directory
-         * and below, which is code...
-         */
-        while ((de = readdir(d))) {
-            const char *name = de->d_name;
-
-            if (de->d_type == DT_DIR) {
-                int subfd;
-                int64_t statsize = 0;
-                int64_t dirsize = 0;
-                    /* always skip "." and ".." */
-                if (name[0] == '.') {
-                    if (name[1] == 0) continue;
-                    if ((name[1] == '.') && (name[2] == 0)) continue;
-                }
-                if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
-                    statsize = stat_size(&s);
-                }
-                subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
-                if (subfd >= 0) {
-                    dirsize = calculate_dir_size(subfd);
-                }
-                if(!strcmp(name,"lib")) {
-                    codesize += dirsize + statsize;
-                } else if(!strcmp(name,"cache")) {
-                    cachesize += dirsize + statsize;
-                } else {
-                    datasize += dirsize + statsize;
-                }
-            } else if (de->d_type == DT_LNK && !strcmp(name,"lib")) {
-                // This is the symbolic link to the application's library
-                // code.  We'll count this as code instead of data, since
-                // it is not something that the app creates.
-                if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
-                    codesize += stat_size(&s);
-                }
+            subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
+            if (subfd >= 0) {
+                dirsize = calculate_dir_size(subfd);
+                close(subfd);
+            }
+            // TODO: check xattrs!
+            if (!strcmp(name, "cache") || !strcmp(name, "code_cache")) {
+                *datasize += statsize;
+                *cachesize += dirsize;
             } else {
-                if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
-                    datasize += stat_size(&s);
-                }
+                *datasize += dirsize + statsize;
             }
+        } else if (de->d_type == DT_LNK && !strcmp(name, "lib")) {
+            *codesize += statsize;
+        } else {
+            *datasize += statsize;
         }
+    }
+    closedir(d);
+}
+
+int get_app_size(const char *uuid, const char *pkgname, int userid, int flags, ino_t ce_data_inode,
+        const char *code_path, int64_t *codesize, int64_t *datasize, int64_t *cachesize,
+        int64_t* asecsize) {
+    DIR *d;
+    int dfd;
+
+    d = opendir(code_path);
+    if (d != nullptr) {
+        dfd = dirfd(d);
+        *codesize += calculate_dir_size(dfd);
         closedir(d);
     }
-    *_codesize = codesize;
-    *_datasize = datasize;
-    *_cachesize = cachesize;
-    *_asecsize = asecsize;
+
+    if (flags & FLAG_STORAGE_CE) {
+        auto path = create_data_user_ce_package_path(uuid, userid, pkgname, ce_data_inode);
+        add_app_data_size(path, codesize, datasize, cachesize);
+    }
+    if (flags & FLAG_STORAGE_DE) {
+        auto path = create_data_user_de_package_path(uuid, userid, pkgname);
+        add_app_data_size(path, codesize, datasize, cachesize);
+    }
+
+    *asecsize = 0;
+
     return 0;
 }
 
+int get_app_data_inode(const char *uuid, const char *pkgname, int userid, int flags, ino_t *inode) {
+    struct stat buf;
+    memset(&buf, 0, sizeof(buf));
+    if (flags & FLAG_STORAGE_CE) {
+        auto path = create_data_user_ce_package_path(uuid, userid, pkgname);
+        if (stat(path.c_str(), &buf) == 0) {
+            *inode = buf.st_ino;
+            return 0;
+        }
+    }
+    return -1;
+}
+
 static int split_count(const char *str)
 {
   char *ctx;
@@ -1304,13 +1260,17 @@
     return true;
 }
 
-static int open_output_file(char* file_name, bool recreate) {
+static int open_output_file(char* file_name, bool recreate, int permissions) {
     int flags = O_RDWR | O_CREAT;
     if (recreate) {
-        unlink(file_name);
+        if (unlink(file_name) < 0) {
+            if (errno != ENOENT) {
+                PLOG(ERROR) << "open_output_file: Couldn't unlink " << file_name;
+            }
+        }
         flags |= O_EXCL;
     }
-    return open(file_name, flags, 0600);
+    return open(file_name, flags, permissions);
 }
 
 static bool set_permissions_and_ownership(int fd, bool is_public, int uid, const char* path) {
@@ -1427,8 +1387,7 @@
         return -1;
     }
 
-    unlink(out_path);
-    out_fd = open(out_path, O_RDWR | O_CREAT | O_EXCL, 0644);
+    out_fd = open_output_file(out_path, /*recreate*/true, /*permissions*/0644);
     if (out_fd < 0) {
         ALOGE("installd cannot open '%s' for output during dexopt\n", out_path);
         goto fail;
@@ -1442,7 +1401,7 @@
         // Make sure there really is enough space.
         strcpy(swap_file_name, out_path);
         if (add_extension_to_file_name(swap_file_name, ".swap")) {
-            swap_fd = open_output_file(swap_file_name, /*recreate*/true);
+            swap_fd = open_output_file(swap_file_name, /*recreate*/true, /*permissions*/0600);
         }
         if (swap_fd < 0) {
             // Could not create swap file. Optimistically go on and hope that we can compile
@@ -1450,7 +1409,9 @@
             ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name);
         } else {
             // Immediately unlink. We don't really want to hit flash.
-            unlink(swap_file_name);
+            if (unlink(swap_file_name) < 0) {
+                PLOG(ERROR) << "Couldn't unlink swap file " << swap_file_name;
+            }
         }
     }
 
@@ -1466,7 +1427,7 @@
       if (profile_guided && have_app_image_format) {
           // Recreate is true since we do not want to modify a mapped image. If the app is already
           // running and we modify the image file, it can cause crashes (b/27493510).
-          image_fd = open_output_file(image_path, /*recreate*/true);
+          image_fd = open_output_file(image_path, /*recreate*/true, /*permissions*/0600);
           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);
@@ -1476,7 +1437,11 @@
       }
       // If we have a valid image file path but no image fd, erase the image file.
       if (image_fd < 0) {
-          unlink(image_path);
+          if (unlink(image_path) < 0) {
+              if (errno != ENOENT) {
+                  PLOG(ERROR) << "Couldn't unlink image file " << image_path;
+              }
+          }
       }
     }
 
@@ -1608,7 +1573,7 @@
     struct stat s, libStat;
     int rc = 0;
 
-    std::string _pkgdir(create_data_user_package_path(uuid, userId, pkgname));
+    std::string _pkgdir(create_data_user_ce_package_path(uuid, userId, pkgname));
     std::string _libsymlink(_pkgdir + PKG_LIB_POSTFIX);
 
     const char* pkgdir = _pkgdir.c_str();
@@ -1795,7 +1760,7 @@
 
     uid_t uid = multiuser_get_uid(userid, appid);
     if (flags & FLAG_STORAGE_CE) {
-        auto path = create_data_user_package_path(uuid, userid, pkgName);
+        auto path = create_data_user_ce_package_path(uuid, userid, pkgName);
         if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, seflags) < 0) {
             PLOG(ERROR) << "restorecon failed for " << path;
             res = -1;
diff --git a/cmds/installd/commands.h b/cmds/installd/commands.h
index 13143c5..f13ceea 100644
--- a/cmds/installd/commands.h
+++ b/cmds/installd/commands.h
@@ -33,16 +33,18 @@
 int restorecon_app_data(const char* uuid, const char* pkgName, userid_t userid, int flags,
         appid_t appid, const char* seinfo);
 int migrate_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags);
-int clear_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags);
-int destroy_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags);
+int clear_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
+        ino_t ce_data_inode);
+int destroy_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
+        ino_t ce_data_inode);
 
 int move_complete_app(const char* from_uuid, const char *to_uuid, const char *package_name,
         const char *data_app_name, appid_t appid, const char* seinfo, int target_sdk_version);
 
-int get_app_size(const char *uuid, const char *pkgname, int userid, int flags,
-        const char *apkpath, const char *libdirpath, const char *fwdlock_apkpath,
-        const char *asecpath, const char *instruction_set, int64_t *codesize, int64_t *datasize,
-        int64_t *cachesize, int64_t *asecsize);
+int get_app_size(const char *uuid, const char *pkgname, int userid, int flags, ino_t ce_data_inode,
+        const char* code_path, int64_t *codesize, int64_t *datasize, int64_t *cachesize,
+        int64_t *asecsize);
+int get_app_data_inode(const char *uuid, const char *pkgname, int userid, int flags, ino_t *inode);
 
 int make_user_config(userid_t userid);
 int delete_user(const char *uuid, userid_t userid);
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index de3f54a..5c29eb4 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -207,13 +207,13 @@
 }
 
 static int do_clear_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
-    /* const char *uuid, const char *pkgname, userid_t userid, int flags */
-    return clear_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]));
+    /* const char *uuid, const char *pkgname, userid_t userid, int flags, ino_t ce_data_inode */
+    return clear_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), atol(arg[4]));
 }
 
 static int do_destroy_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
-    /* const char *uuid, const char *pkgname, userid_t userid, int flags */
-    return destroy_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]));
+    /* const char *uuid, const char *pkgname, userid_t userid, int flags, ino_t ce_data_inode */
+    return destroy_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), atol(arg[4]));
 }
 
 // We use otapreopt_chroot to get into the chroot.
@@ -303,11 +303,10 @@
     int64_t asecsize = 0;
     int res = 0;
 
-    /* const char *uuid, const char *pkgname, userid_t userid, int flags,
-            const char *apkpath, const char *libdirpath, const char *fwdlock_apkpath,
-            const char *asecpath, const char *instruction_set */
-    res = get_app_size(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), arg[4], arg[5],
-            arg[6], arg[7], arg[8], &codesize, &datasize, &cachesize, &asecsize);
+    /* const char *uuid, const char *pkgname, int userid, int flags, ino_t ce_data_inode,
+            const char* code_path */
+    res = get_app_size(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), atol(arg[4]),
+            arg[5], &codesize, &datasize, &cachesize, &asecsize);
 
     /*
      * Each int64_t can take up 22 characters printed out. Make sure it
@@ -318,6 +317,17 @@
     return res;
 }
 
+static int do_get_app_data_inode(char **arg, char reply[REPLY_MAX]) {
+    ino_t inode = 0;
+    int res = 0;
+
+    /* const char *uuid, const char *pkgname, int userid, int flags */
+    res = get_app_data_inode(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), &inode);
+
+    snprintf(reply, REPLY_MAX, "%" PRId64, (int64_t) inode);
+    return res;
+}
+
 static int do_move_complete_app(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
     /* const char* from_uuid, const char *to_uuid, const char *package_name,
             const char *data_app_name, appid_t appid, const char* seinfo,
@@ -393,10 +403,11 @@
     { "create_app_data",      7, do_create_app_data },
     { "restorecon_app_data",  6, do_restorecon_app_data },
     { "migrate_app_data",     4, do_migrate_app_data },
-    { "clear_app_data",       4, do_clear_app_data },
-    { "destroy_app_data",     4, do_destroy_app_data },
+    { "clear_app_data",       5, do_clear_app_data },
+    { "destroy_app_data",     5, do_destroy_app_data },
     { "move_complete_app",    7, do_move_complete_app },
-    { "get_app_size",         9, do_get_app_size },
+    { "get_app_size",         6, do_get_app_size },
+    { "get_app_data_inode",   4, do_get_app_data_inode },
 
     { "dexopt",               9, do_dexopt },
     { "markbootcomplete",     1, do_mark_boot_complete },
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index ff69f4b..9b2de88 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -472,13 +472,13 @@
 }
 
 TEST_F(UtilsTest, CreateDataUserPath) {
-    EXPECT_EQ("/data/data", create_data_user_path(nullptr, 0));
-    EXPECT_EQ("/data/user/10", create_data_user_path(nullptr, 10));
+    EXPECT_EQ("/data/data", create_data_user_ce_path(nullptr, 0));
+    EXPECT_EQ("/data/user/10", create_data_user_ce_path(nullptr, 10));
 
     EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/0",
-            create_data_user_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0));
+            create_data_user_ce_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0));
     EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/10",
-            create_data_user_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10));
+            create_data_user_ce_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10));
 }
 
 TEST_F(UtilsTest, CreateDataMediaPath) {
@@ -499,13 +499,13 @@
 }
 
 TEST_F(UtilsTest, CreateDataUserPackagePath) {
-    EXPECT_EQ("/data/data/com.example", create_data_user_package_path(nullptr, 0, "com.example"));
-    EXPECT_EQ("/data/user/10/com.example", create_data_user_package_path(nullptr, 10, "com.example"));
+    EXPECT_EQ("/data/data/com.example", create_data_user_ce_package_path(nullptr, 0, "com.example"));
+    EXPECT_EQ("/data/user/10/com.example", create_data_user_ce_package_path(nullptr, 10, "com.example"));
 
     EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/0/com.example",
-            create_data_user_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example"));
+            create_data_user_ce_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example"));
     EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/10/com.example",
-            create_data_user_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10, "com.example"));
+            create_data_user_ce_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10, "com.example"));
 }
 
 }  // namespace installd
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index d84d9f6..878fb2d 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -81,11 +81,39 @@
  * volume UUID, package name, and user ID. An empty UUID is assumed to be
  * internal storage.
  */
-std::string create_data_user_package_path(const char* volume_uuid,
+std::string create_data_user_ce_package_path(const char* volume_uuid,
         userid_t user, const char* package_name) {
     check_package_name(package_name);
     return StringPrintf("%s/%s",
-            create_data_user_path(volume_uuid, user).c_str(), package_name);
+            create_data_user_ce_path(volume_uuid, user).c_str(), package_name);
+}
+
+std::string create_data_user_ce_package_path(const char* volume_uuid, userid_t user,
+        const char* package_name, ino_t ce_data_inode) {
+    // For testing purposes, rely on the inode when defined; this could be
+    // optimized to use access() in the future.
+    auto fallback = create_data_user_ce_package_path(volume_uuid, user, package_name);
+    if (ce_data_inode != 0) {
+        auto user_path = create_data_user_ce_path(volume_uuid, user);
+        DIR* dir = opendir(user_path.c_str());
+        if (dir == nullptr) {
+            PLOG(ERROR) << "Failed to opendir " << user_path;
+            return fallback;
+        }
+
+        struct dirent* ent;
+        while ((ent = readdir(dir))) {
+            if (ent->d_ino == ce_data_inode) {
+                closedir(dir);
+                return StringPrintf("%s/%s", user_path.c_str(), ent->d_name);
+            }
+        }
+        LOG(WARNING) << "Failed to find inode " << ce_data_inode << " for package " << package_name;
+        closedir(dir);
+        return fallback;
+    } else {
+        return fallback;
+    }
 }
 
 std::string create_data_user_de_package_path(const char* volume_uuid,
@@ -102,7 +130,7 @@
         return -1;
     }
 
-    std::string _tmp(create_data_user_package_path(nullptr, userid, pkgname) + postfix);
+    std::string _tmp(create_data_user_ce_package_path(nullptr, userid, pkgname) + postfix);
     const char* tmp = _tmp.c_str();
     if (strlen(tmp) >= PKG_PATH_MAX) {
         path[0] = '\0';
@@ -132,7 +160,7 @@
 /**
  * Create the path name for user data for a certain userid.
  */
-std::string create_data_user_path(const char* volume_uuid, userid_t userid) {
+std::string create_data_user_ce_path(const char* volume_uuid, userid_t userid) {
     std::string data(create_data_path(volume_uuid));
     if (volume_uuid == nullptr) {
         if (userid == 0) {
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 416a726..9d9a423 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -73,12 +73,13 @@
 
 std::string create_data_app_package_path(const char* volume_uuid, const char* package_name);
 
-// TODO: finish refactoring to "_ce"
-std::string create_data_user_path(const char* volume_uuid, userid_t userid);
+std::string create_data_user_ce_path(const char* volume_uuid, userid_t userid);
 std::string create_data_user_de_path(const char* volume_uuid, userid_t userid);
 
-std::string create_data_user_package_path(const char* volume_uuid,
+std::string create_data_user_ce_package_path(const char* volume_uuid,
         userid_t user, const char* package_name);
+std::string create_data_user_ce_package_path(const char* volume_uuid,
+        userid_t user, const char* package_name, ino_t ce_data_inode);
 std::string create_data_user_de_package_path(const char* volume_uuid,
         userid_t user, const char* package_name);
 
diff --git a/include/batteryservice/BatteryService.h b/include/batteryservice/BatteryService.h
index 912dcf6..b399905 100644
--- a/include/batteryservice/BatteryService.h
+++ b/include/batteryservice/BatteryService.h
@@ -68,6 +68,7 @@
     int batteryCurrent;
     int batteryCycleCount;
     int batteryFullCharge;
+    int batteryChargeCounter;
     String8 batteryTechnology;
 
     status_t writeToParcel(Parcel* parcel) const;
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 8c3d49e..af26721 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -39,6 +39,7 @@
 class DisplayState;
 struct DisplayInfo;
 struct DisplayStatInfo;
+class HdrCapabilities;
 class IDisplayEventConnection;
 class IMemoryHeap;
 class Rect;
@@ -157,6 +158,13 @@
      * Requires the ACCESS_SURFACE_FLINGER permission.
      */
     virtual status_t getAnimationFrameStats(FrameStats* outStats) const = 0;
+
+    /* Gets the supported HDR capabilities of the given display.
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual status_t getHdrCapabilities(const sp<IBinder>& display,
+            HdrCapabilities* outCapabilities) const = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -184,6 +192,7 @@
         GET_ANIMATION_FRAME_STATS,
         SET_POWER_MODE,
         GET_DISPLAY_STATS,
+        GET_HDR_CAPABILITIES,
     };
 
     virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/include/gui/Sensor.h b/include/gui/Sensor.h
index 3792540..353003c 100644
--- a/include/gui/Sensor.h
+++ b/include/gui/Sensor.h
@@ -56,7 +56,7 @@
         uint8_t b[16];
     } uuid_t;
 
-    Sensor();
+    Sensor(const char * name = "");
     Sensor(struct sensor_t const* hwSensor, int halVersion = 0);
     ~Sensor();
 
@@ -80,6 +80,7 @@
     int32_t getMaxDelay() const;
     uint32_t getFlags() const;
     bool isWakeUpSensor() const;
+    bool isDynamicSensor() const;
     int32_t getReportingMode() const;
     const uuid_t& getUuid() const;
 
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index 794fe4c..9161dbb 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -40,6 +40,7 @@
 
 class DisplayInfo;
 class Composer;
+class HdrCapabilities;
 class ISurfaceComposerClient;
 class IGraphicBufferProducer;
 class Region;
@@ -145,6 +146,9 @@
     static status_t clearAnimationFrameStats();
     static status_t getAnimationFrameStats(FrameStats* outStats);
 
+    static status_t getHdrCapabilities(const sp<IBinder>& display,
+            HdrCapabilities* outCapabilities);
+
     static void setDisplaySurface(const sp<IBinder>& token,
             const sp<IGraphicBufferProducer>& bufferProducer);
     static void setDisplayLayerStack(const sp<IBinder>& token,
diff --git a/include/media/openmax/OMX_VideoExt.h b/include/media/openmax/OMX_VideoExt.h
index e11f569..4bb5f9a 100644
--- a/include/media/openmax/OMX_VideoExt.h
+++ b/include/media/openmax/OMX_VideoExt.h
@@ -77,10 +77,13 @@
 
 /** VP9 profiles */
 typedef enum OMX_VIDEO_VP9PROFILETYPE {
-    OMX_VIDEO_VP9Profile0 = 0x0,
-    OMX_VIDEO_VP9Profile1 = 0x1,
-    OMX_VIDEO_VP9Profile2 = 0x2,
-    OMX_VIDEO_VP9Profile3 = 0x3,
+    OMX_VIDEO_VP9Profile0 = 0x1,
+    OMX_VIDEO_VP9Profile1 = 0x2,
+    OMX_VIDEO_VP9Profile2 = 0x4,
+    OMX_VIDEO_VP9Profile3 = 0x8,
+    // HDR profiles also support passing HDR metadata
+    OMX_VIDEO_VP9Profile2HDR = 0x1000,
+    OMX_VIDEO_VP9Profile3HDR = 0x2000,
     OMX_VIDEO_VP9ProfileUnknown = 0x6EFFFFFF,
     OMX_VIDEO_VP9ProfileMax = 0x7FFFFFFF
 } OMX_VIDEO_VP9PROFILETYPE;
diff --git a/include/ui/HdrCapabilities.h b/include/ui/HdrCapabilities.h
new file mode 100644
index 0000000..a7cd5fb
--- /dev/null
+++ b/include/ui/HdrCapabilities.h
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_UI_HDR_CAPABILTIES_H
+#define ANDROID_UI_HDR_CAPABILTIES_H
+
+#include <binder/Parcelable.h>
+
+namespace android {
+
+class HdrCapabilities : public Parcelable
+{
+public:
+    HdrCapabilities(const std::vector<int32_t /*android_hdr_t*/>& types,
+            float maxLuminance, float maxAverageLuminance, float minLuminance)
+      : mSupportedHdrTypes(types),
+        mMaxLuminance(maxLuminance),
+        mMaxAverageLuminance(maxAverageLuminance),
+        mMinLuminance(minLuminance) {}
+
+    // Make this move-constructable and move-assignable
+    HdrCapabilities(HdrCapabilities&& other) = default;
+    HdrCapabilities& operator=(HdrCapabilities&& other) = default;
+
+    HdrCapabilities()
+      : mSupportedHdrTypes(),
+        mMaxLuminance(-1.0f),
+        mMaxAverageLuminance(-1.0f),
+        mMinLuminance(-1.0f) {}
+
+    virtual ~HdrCapabilities() = default;
+
+    const std::vector<int32_t /*android_hdr_t*/>& getSupportedHdrTypes() const {
+        return mSupportedHdrTypes;
+    }
+    float getDesiredMaxLuminance() const { return mMaxLuminance; }
+    float getDesiredMaxAverageLuminance() const { return mMaxAverageLuminance; }
+    float getDesiredMinLuminance() const { return mMinLuminance; }
+
+    // Parcelable interface
+    virtual status_t writeToParcel(Parcel* parcel) const override;
+    virtual status_t readFromParcel(const Parcel* parcel) override;
+
+private:
+    std::vector<int32_t /*android_hdr_t*/> mSupportedHdrTypes;
+    float mMaxLuminance;
+    float mMaxAverageLuminance;
+    float mMinLuminance;
+};
+
+} // namespace android
+
+#endif
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 33fe26c..b221e51 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -40,12 +40,12 @@
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 
 #define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))
 #define DEFAULT_MAX_BINDER_THREADS 15
 
-
-// ---------------------------------------------------------------------------
+// -------------------------------------------------------------------------
 
 namespace android {
 
@@ -278,8 +278,9 @@
 
 String8 ProcessState::makeBinderThreadName() {
     int32_t s = android_atomic_add(1, &mThreadPoolSeq);
+    pid_t pid = getpid();
     String8 name;
-    name.appendFormat("Binder_%X", s);
+    name.appendFormat("Binder:%d_%X", pid, s);
     return name;
 }
 
diff --git a/libs/diskusage/dirsize.c b/libs/diskusage/dirsize.c
index 7576994..5b5ab70 100644
--- a/libs/diskusage/dirsize.c
+++ b/libs/diskusage/dirsize.c
@@ -24,16 +24,7 @@
 
 int64_t stat_size(struct stat *s)
 {
-    int64_t blksize = s->st_blksize;
-    // count actual blocks used instead of nominal file size
-    int64_t size = s->st_blocks * 512;
-
-    if (blksize) {
-        /* round up to filesystem block size */
-        size = (size + blksize - 1) & (~(blksize - 1));
-    }
-
-    return size;
+    return s->st_blocks * 512;
 }
 
 int64_t calculate_dir_size(int dfd)
@@ -51,9 +42,6 @@
 
     while ((de = readdir(d))) {
         const char *name = de->d_name;
-        if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
-            size += stat_size(&s);
-        }
         if (de->d_type == DT_DIR) {
             int subfd;
 
@@ -65,10 +53,17 @@
                     continue;
             }
 
+            if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
+                size += stat_size(&s);
+            }
             subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
             if (subfd >= 0) {
                 size += calculate_dir_size(subfd);
             }
+        } else {
+            if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
+                size += stat_size(&s);
+            }
         }
     }
     closedir(d);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index b4cbf84..a8b4fa8 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -34,6 +34,7 @@
 
 #include <ui/DisplayInfo.h>
 #include <ui/DisplayStatInfo.h>
+#include <ui/HdrCapabilities.h>
 
 #include <utils/Log.h>
 
@@ -282,6 +283,28 @@
         reply.read(*outStats);
         return reply.readInt32();
     }
+
+    virtual status_t getHdrCapabilities(const sp<IBinder>& display,
+            HdrCapabilities* outCapabilities) const {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        status_t result = data.writeStrongBinder(display);
+        if (result != NO_ERROR) {
+            ALOGE("getHdrCapabilities failed to writeStrongBinder: %d", result);
+            return result;
+        }
+        result = remote()->transact(BnSurfaceComposer::GET_HDR_CAPABILITIES,
+                data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("getHdrCapabilities failed to transact: %d", result);
+            return result;
+        }
+        result = reply.readInt32();
+        if (result == NO_ERROR) {
+            result = reply.readParcelable(outCapabilities);
+        }
+        return result;
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -467,6 +490,23 @@
             setPowerMode(display, mode);
             return NO_ERROR;
         }
+        case GET_HDR_CAPABILITIES: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<IBinder> display = nullptr;
+            status_t result = data.readStrongBinder(&display);
+            if (result != NO_ERROR) {
+                ALOGE("getHdrCapabilities failed to readStrongBinder: %d",
+                        result);
+                return result;
+            }
+            HdrCapabilities capabilities;
+            result = getHdrCapabilities(display, &capabilities);
+            reply->writeInt32(result);
+            if (result == NO_ERROR) {
+                reply->writeParcelable(capabilities);
+            }
+            return NO_ERROR;
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index 0b2b942..4b9a2ab 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -35,8 +35,8 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
-Sensor::Sensor()
-    : mHandle(0), mType(0),
+Sensor::Sensor(const char * name)
+    : mName(name), mHandle(0), mType(0),
       mMinValue(0), mMaxValue(0), mResolution(0),
       mPower(0), mMinDelay(0), mVersion(0), mFifoReservedEventCount(0),
       mFifoMaxEventCount(0), mRequiredAppOp(0),
@@ -390,6 +390,10 @@
     return mFlags & SENSOR_FLAG_WAKE_UP;
 }
 
+bool Sensor::isDynamicSensor() const {
+    return mFlags & SENSOR_FLAG_DYNAMIC_SENSOR;
+}
+
 int32_t Sensor::getReportingMode() const {
     return ((mFlags & REPORTING_MODE_MASK) >> REPORTING_MODE_SHIFT);
 }
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 04b5446..418892a 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -722,6 +722,12 @@
     return ComposerService::getComposerService()->getAnimationFrameStats(outStats);
 }
 
+status_t SurfaceComposerClient::getHdrCapabilities(const sp<IBinder>& display,
+        HdrCapabilities* outCapabilities) {
+    return ComposerService::getComposerService()->getHdrCapabilities(display,
+            outCapabilities);
+}
+
 // ----------------------------------------------------------------------------
 
 status_t ScreenshotClient::capture(
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index e4cdcab..ee6c093 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -40,12 +40,14 @@
 	GraphicBuffer.cpp \
 	GraphicBufferAllocator.cpp \
 	GraphicBufferMapper.cpp \
+	HdrCapabilities.cpp \
 	PixelFormat.cpp \
 	Rect.cpp \
 	Region.cpp \
 	UiConfig.cpp
 
 LOCAL_SHARED_LIBRARIES := \
+	libbinder \
 	libcutils \
 	libhardware \
 	libsync \
diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp
new file mode 100644
index 0000000..511f68a
--- /dev/null
+++ b/libs/ui/HdrCapabilities.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#include <ui/HdrCapabilities.h>
+
+#include <binder/Parcel.h>
+
+namespace android {
+
+status_t HdrCapabilities::writeToParcel(Parcel* parcel) const
+{
+    status_t result = parcel->writeInt32Vector(mSupportedHdrTypes);
+    if (result != OK) {
+        return result;
+    }
+    result = parcel->writeFloat(mMaxLuminance);
+    if (result != OK) {
+        return result;
+    }
+    result = parcel->writeFloat(mMaxAverageLuminance);
+    if (result != OK) {
+        return result;
+    }
+    result = parcel->writeFloat(mMinLuminance);
+    return result;
+}
+
+status_t HdrCapabilities::readFromParcel(const Parcel* parcel)
+{
+    status_t result = parcel->readInt32Vector(&mSupportedHdrTypes);
+    if (result != OK) {
+        return result;
+    }
+    result = parcel->readFloat(&mMaxLuminance);
+    if (result != OK) {
+        return result;
+    }
+    result = parcel->readFloat(&mMaxAverageLuminance);
+    if (result != OK) {
+        return result;
+    }
+    result = parcel->readFloat(&mMinLuminance);
+    return result;
+}
+
+} // namespace android
diff --git a/services/batteryservice/BatteryProperties.cpp b/services/batteryservice/BatteryProperties.cpp
index 07cc797..d89d4c9 100644
--- a/services/batteryservice/BatteryProperties.cpp
+++ b/services/batteryservice/BatteryProperties.cpp
@@ -41,6 +41,7 @@
     batteryLevel = p->readInt32();
     batteryVoltage = p->readInt32();
     batteryTemperature = p->readInt32();
+    batteryChargeCounter = p->readInt32();
     batteryTechnology = String8((p->readString16()).string());
     return OK;
 }
@@ -57,6 +58,7 @@
     p->writeInt32(batteryLevel);
     p->writeInt32(batteryVoltage);
     p->writeInt32(batteryTemperature);
+    p->writeInt32(batteryChargeCounter);
     p->writeString16(String16(batteryTechnology));
     return OK;
 }
diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk
index 57c56a6..85e96d6 100644
--- a/services/sensorservice/Android.mk
+++ b/services/sensorservice/Android.mk
@@ -16,6 +16,7 @@
     SensorEventConnection.cpp \
     MostRecentEventLogger.cpp \
     SensorRecord.cpp \
+    SensorList.cpp \
 
 
 LOCAL_CFLAGS:= -DLOG_TAG=\"SensorService\"
diff --git a/services/sensorservice/CorrectedGyroSensor.cpp b/services/sensorservice/CorrectedGyroSensor.cpp
index 7b1f346..788def9 100644
--- a/services/sensorservice/CorrectedGyroSensor.cpp
+++ b/services/sensorservice/CorrectedGyroSensor.cpp
@@ -39,6 +39,18 @@
             break;
         }
     }
+
+    sensor_t hwSensor;
+    hwSensor.name       = "Corrected Gyroscope Sensor";
+    hwSensor.vendor     = "AOSP";
+    hwSensor.version    = 1;
+    hwSensor.handle     = '_cgy';
+    hwSensor.type       = SENSOR_TYPE_GYROSCOPE;
+    hwSensor.maxRange   = mGyro.getMaxValue();
+    hwSensor.resolution = mGyro.getResolution();
+    hwSensor.power      = mSensorFusion.getPowerUsage();
+    hwSensor.minDelay   = mGyro.getMinDelay();
+    mSensor = Sensor(&hwSensor);
 }
 
 bool CorrectedGyroSensor::process(sensors_event_t* outEvent,
@@ -66,19 +78,8 @@
     return mSensorFusion.setDelay(FUSION_9AXIS, ident, ns);
 }
 
-Sensor CorrectedGyroSensor::getSensor() const {
-    sensor_t hwSensor;
-    hwSensor.name       = "Corrected Gyroscope Sensor";
-    hwSensor.vendor     = "AOSP";
-    hwSensor.version    = 1;
-    hwSensor.handle     = '_cgy';
-    hwSensor.type       = SENSOR_TYPE_GYROSCOPE;
-    hwSensor.maxRange   = mGyro.getMaxValue();
-    hwSensor.resolution = mGyro.getResolution();
-    hwSensor.power      = mSensorFusion.getPowerUsage();
-    hwSensor.minDelay   = mGyro.getMinDelay();
-    Sensor sensor(&hwSensor);
-    return sensor;
+const Sensor& CorrectedGyroSensor::getSensor() const {
+    return mSensor;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/CorrectedGyroSensor.h b/services/sensorservice/CorrectedGyroSensor.h
index 3c49c08..3419a8a 100644
--- a/services/sensorservice/CorrectedGyroSensor.h
+++ b/services/sensorservice/CorrectedGyroSensor.h
@@ -35,15 +35,15 @@
     SensorDevice& mSensorDevice;
     SensorFusion& mSensorFusion;
     Sensor mGyro;
+    Sensor mSensor;
 
 public:
     CorrectedGyroSensor(sensor_t const* list, size_t count);
-    virtual bool process(sensors_event_t* outEvent,
-            const sensors_event_t& event);
-    virtual status_t activate(void* ident, bool enabled);
-    virtual status_t setDelay(void* ident, int handle, int64_t ns);
-    virtual Sensor getSensor() const;
-    virtual bool isVirtual() const { return true; }
+    virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) override;
+    virtual status_t activate(void* ident, bool enabled) override;
+    virtual status_t setDelay(void* ident, int handle, int64_t ns) override;
+    virtual const Sensor& getSensor() const override;
+    virtual bool isVirtual() const override { return true; }
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/GravitySensor.cpp b/services/sensorservice/GravitySensor.cpp
index a165a5b..0e80f16 100644
--- a/services/sensorservice/GravitySensor.cpp
+++ b/services/sensorservice/GravitySensor.cpp
@@ -39,6 +39,18 @@
             break;
         }
     }
+
+    sensor_t hwSensor;
+    hwSensor.name       = "Gravity Sensor";
+    hwSensor.vendor     = "AOSP";
+    hwSensor.version    = 3;
+    hwSensor.handle     = '_grv';
+    hwSensor.type       = SENSOR_TYPE_GRAVITY;
+    hwSensor.maxRange   = GRAVITY_EARTH * 2;
+    hwSensor.resolution = mAccelerometer.getResolution();
+    hwSensor.power      = mSensorFusion.getPowerUsage();
+    hwSensor.minDelay   = mSensorFusion.getMinDelay();
+    mSensor = Sensor(&hwSensor);
 }
 
 bool GravitySensor::process(sensors_event_t* outEvent,
@@ -73,19 +85,8 @@
     return mSensorFusion.setDelay(FUSION_NOMAG, ident, ns);
 }
 
-Sensor GravitySensor::getSensor() const {
-    sensor_t hwSensor;
-    hwSensor.name       = "Gravity Sensor";
-    hwSensor.vendor     = "AOSP";
-    hwSensor.version    = 3;
-    hwSensor.handle     = '_grv';
-    hwSensor.type       = SENSOR_TYPE_GRAVITY;
-    hwSensor.maxRange   = GRAVITY_EARTH * 2;
-    hwSensor.resolution = mAccelerometer.getResolution();
-    hwSensor.power      = mSensorFusion.getPowerUsage();
-    hwSensor.minDelay   = mSensorFusion.getMinDelay();
-    Sensor sensor(&hwSensor);
-    return sensor;
+const Sensor& GravitySensor::getSensor() const {
+    return mSensor;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/GravitySensor.h b/services/sensorservice/GravitySensor.h
index ac177c4..f9c0a99 100644
--- a/services/sensorservice/GravitySensor.h
+++ b/services/sensorservice/GravitySensor.h
@@ -35,15 +35,15 @@
     SensorDevice& mSensorDevice;
     SensorFusion& mSensorFusion;
     Sensor mAccelerometer;
+    Sensor mSensor;
 
 public:
     GravitySensor(sensor_t const* list, size_t count);
-    virtual bool process(sensors_event_t* outEvent,
-            const sensors_event_t& event);
-    virtual status_t activate(void* ident, bool enabled);
-    virtual status_t setDelay(void* ident, int handle, int64_t ns);
-    virtual Sensor getSensor() const;
-    virtual bool isVirtual() const { return true; }
+    virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) override;
+    virtual status_t activate(void* ident, bool enabled) override;
+    virtual status_t setDelay(void* ident, int handle, int64_t ns) override;
+    virtual const Sensor& getSensor() const override;
+    virtual bool isVirtual() const override { return true; }
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/LinearAccelerationSensor.cpp b/services/sensorservice/LinearAccelerationSensor.cpp
index d5f20d2..04beced 100644
--- a/services/sensorservice/LinearAccelerationSensor.cpp
+++ b/services/sensorservice/LinearAccelerationSensor.cpp
@@ -33,6 +33,18 @@
     : mSensorDevice(SensorDevice::getInstance()),
       mGravitySensor(list, count)
 {
+    const Sensor &gsensor = mGravitySensor.getSensor();
+    sensor_t hwSensor;
+    hwSensor.name       = "Linear Acceleration Sensor";
+    hwSensor.vendor     = "AOSP";
+    hwSensor.version    = gsensor.getVersion();
+    hwSensor.handle     = '_lin';
+    hwSensor.type       = SENSOR_TYPE_LINEAR_ACCELERATION;
+    hwSensor.maxRange   = gsensor.getMaxValue();
+    hwSensor.resolution = gsensor.getResolution();
+    hwSensor.power      = gsensor.getPowerUsage();
+    hwSensor.minDelay   = gsensor.getMinDelay();
+    mSensor = Sensor(&hwSensor);
 }
 
 bool LinearAccelerationSensor::process(sensors_event_t* outEvent,
@@ -58,20 +70,8 @@
     return mGravitySensor.setDelay(ident, handle, ns);
 }
 
-Sensor LinearAccelerationSensor::getSensor() const {
-    Sensor gsensor(mGravitySensor.getSensor());
-    sensor_t hwSensor;
-    hwSensor.name       = "Linear Acceleration Sensor";
-    hwSensor.vendor     = "AOSP";
-    hwSensor.version    = gsensor.getVersion();
-    hwSensor.handle     = '_lin';
-    hwSensor.type       = SENSOR_TYPE_LINEAR_ACCELERATION;
-    hwSensor.maxRange   = gsensor.getMaxValue();
-    hwSensor.resolution = gsensor.getResolution();
-    hwSensor.power      = gsensor.getPowerUsage();
-    hwSensor.minDelay   = gsensor.getMinDelay();
-    Sensor sensor(&hwSensor);
-    return sensor;
+const Sensor& LinearAccelerationSensor::getSensor() const {
+    return mSensor;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/LinearAccelerationSensor.h b/services/sensorservice/LinearAccelerationSensor.h
index 5deb24f..6b8027b 100644
--- a/services/sensorservice/LinearAccelerationSensor.h
+++ b/services/sensorservice/LinearAccelerationSensor.h
@@ -35,15 +35,16 @@
 class LinearAccelerationSensor : public SensorInterface {
     SensorDevice& mSensorDevice;
     GravitySensor mGravitySensor;
+    Sensor mSensor;
 
     virtual bool process(sensors_event_t* outEvent,
             const sensors_event_t& event);
 public:
     LinearAccelerationSensor(sensor_t const* list, size_t count);
-    virtual status_t activate(void* ident, bool enabled);
-    virtual status_t setDelay(void* ident, int handle, int64_t ns);
-    virtual Sensor getSensor() const;
-    virtual bool isVirtual() const { return true; }
+    virtual status_t activate(void* ident, bool enabled) override;
+    virtual status_t setDelay(void* ident, int handle, int64_t ns) override;
+    virtual const Sensor& getSensor() const override;
+    virtual bool isVirtual() const override { return true; }
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/OrientationSensor.cpp b/services/sensorservice/OrientationSensor.cpp
index d55f336..20b49be 100644
--- a/services/sensorservice/OrientationSensor.cpp
+++ b/services/sensorservice/OrientationSensor.cpp
@@ -36,6 +36,17 @@
     // FIXME: instead of using the SensorFusion code, we should use
     // the SENSOR_TYPE_ROTATION_VECTOR instead. This way we could use the
     // HAL's implementation.
+    sensor_t hwSensor;
+    hwSensor.name       = "Orientation Sensor";
+    hwSensor.vendor     = "AOSP";
+    hwSensor.version    = 1;
+    hwSensor.handle     = '_ypr';
+    hwSensor.type       = SENSOR_TYPE_ORIENTATION;
+    hwSensor.maxRange   = 360.0f;
+    hwSensor.resolution = 1.0f/256.0f; // FIXME: real value here
+    hwSensor.power      = mSensorFusion.getPowerUsage();
+    hwSensor.minDelay   = mSensorFusion.getMinDelay();
+    mSensor = Sensor(&hwSensor);
 }
 
 bool OrientationSensor::process(sensors_event_t* outEvent,
@@ -73,19 +84,8 @@
     return mSensorFusion.setDelay(FUSION_9AXIS, ident, ns);
 }
 
-Sensor OrientationSensor::getSensor() const {
-    sensor_t hwSensor;
-    hwSensor.name       = "Orientation Sensor";
-    hwSensor.vendor     = "AOSP";
-    hwSensor.version    = 1;
-    hwSensor.handle     = '_ypr';
-    hwSensor.type       = SENSOR_TYPE_ORIENTATION;
-    hwSensor.maxRange   = 360.0f;
-    hwSensor.resolution = 1.0f/256.0f; // FIXME: real value here
-    hwSensor.power      = mSensorFusion.getPowerUsage();
-    hwSensor.minDelay   = mSensorFusion.getMinDelay();
-    Sensor sensor(&hwSensor);
-    return sensor;
+const Sensor& OrientationSensor::getSensor() const {
+    return mSensor;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/OrientationSensor.h b/services/sensorservice/OrientationSensor.h
index 855949d..644a774 100644
--- a/services/sensorservice/OrientationSensor.h
+++ b/services/sensorservice/OrientationSensor.h
@@ -34,15 +34,15 @@
 class OrientationSensor : public SensorInterface {
     SensorDevice& mSensorDevice;
     SensorFusion& mSensorFusion;
+    Sensor mSensor;
 
 public:
     OrientationSensor();
-    virtual bool process(sensors_event_t* outEvent,
-            const sensors_event_t& event);
-    virtual status_t activate(void* ident, bool enabled);
-    virtual status_t setDelay(void* ident, int handle, int64_t ns);
-    virtual Sensor getSensor() const;
-    virtual bool isVirtual() const { return true; }
+    virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) override;
+    virtual status_t activate(void* ident, bool enabled) override;
+    virtual status_t setDelay(void* ident, int handle, int64_t ns) override;
+    virtual const Sensor& getSensor() const override;
+    virtual bool isVirtual() const override { return true; }
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/RotationVectorSensor.cpp b/services/sensorservice/RotationVectorSensor.cpp
index 238845b..5a40ef9 100644
--- a/services/sensorservice/RotationVectorSensor.cpp
+++ b/services/sensorservice/RotationVectorSensor.cpp
@@ -32,6 +32,17 @@
       mSensorFusion(SensorFusion::getInstance()),
       mMode(mode)
 {
+    sensor_t hwSensor;
+    hwSensor.name       = getSensorName();
+    hwSensor.vendor     = "AOSP";
+    hwSensor.version    = 3;
+    hwSensor.handle     = getSensorToken();
+    hwSensor.type       = getSensorType();
+    hwSensor.maxRange   = 1;
+    hwSensor.resolution = 1.0f / (1<<24);
+    hwSensor.power      = mSensorFusion.getPowerUsage();
+    hwSensor.minDelay   = mSensorFusion.getMinDelay();
+    mSensor = Sensor(&hwSensor);
 }
 
 bool RotationVectorSensor::process(sensors_event_t* outEvent,
@@ -61,19 +72,8 @@
     return mSensorFusion.setDelay(mMode, ident, ns);
 }
 
-Sensor RotationVectorSensor::getSensor() const {
-    sensor_t hwSensor;
-    hwSensor.name       = getSensorName();
-    hwSensor.vendor     = "AOSP";
-    hwSensor.version    = 3;
-    hwSensor.handle     = getSensorToken();
-    hwSensor.type       = getSensorType();
-    hwSensor.maxRange   = 1;
-    hwSensor.resolution = 1.0f / (1<<24);
-    hwSensor.power      = mSensorFusion.getPowerUsage();
-    hwSensor.minDelay   = mSensorFusion.getMinDelay();
-    Sensor sensor(&hwSensor);
-    return sensor;
+const Sensor& RotationVectorSensor::getSensor() const {
+    return mSensor;
 }
 
 int RotationVectorSensor::getSensorType() const {
@@ -124,6 +124,17 @@
     : mSensorDevice(SensorDevice::getInstance()),
       mSensorFusion(SensorFusion::getInstance())
 {
+    sensor_t hwSensor;
+    hwSensor.name       = "Gyroscope Bias (debug)";
+    hwSensor.vendor     = "AOSP";
+    hwSensor.version    = 1;
+    hwSensor.handle     = '_gbs';
+    hwSensor.type       = SENSOR_TYPE_ACCELEROMETER;
+    hwSensor.maxRange   = 1;
+    hwSensor.resolution = 1.0f / (1<<24);
+    hwSensor.power      = mSensorFusion.getPowerUsage();
+    hwSensor.minDelay   = mSensorFusion.getMinDelay();
+    mSensor = Sensor(&hwSensor);
 }
 
 bool GyroDriftSensor::process(sensors_event_t* outEvent,
@@ -152,19 +163,8 @@
     return mSensorFusion.setDelay(FUSION_9AXIS, ident, ns);
 }
 
-Sensor GyroDriftSensor::getSensor() const {
-    sensor_t hwSensor;
-    hwSensor.name       = "Gyroscope Bias (debug)";
-    hwSensor.vendor     = "AOSP";
-    hwSensor.version    = 1;
-    hwSensor.handle     = '_gbs';
-    hwSensor.type       = SENSOR_TYPE_ACCELEROMETER;
-    hwSensor.maxRange   = 1;
-    hwSensor.resolution = 1.0f / (1<<24);
-    hwSensor.power      = mSensorFusion.getPowerUsage();
-    hwSensor.minDelay   = mSensorFusion.getMinDelay();
-    Sensor sensor(&hwSensor);
-    return sensor;
+const Sensor& GyroDriftSensor::getSensor() const {
+    return mSensor;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/RotationVectorSensor.h b/services/sensorservice/RotationVectorSensor.h
index 1fc316b..5dba0d5 100644
--- a/services/sensorservice/RotationVectorSensor.h
+++ b/services/sensorservice/RotationVectorSensor.h
@@ -36,6 +36,7 @@
     SensorDevice& mSensorDevice;
     SensorFusion& mSensorFusion;
     int mMode;
+    Sensor mSensor;
 
     int getSensorType() const;
     const char* getSensorName() const ;
@@ -43,12 +44,11 @@
 
 public:
     RotationVectorSensor(int mode = FUSION_9AXIS);
-    virtual bool process(sensors_event_t* outEvent,
-            const sensors_event_t& event);
-    virtual status_t activate(void* ident, bool enabled);
-    virtual status_t setDelay(void* ident, int handle, int64_t ns);
-    virtual Sensor getSensor() const;
-    virtual bool isVirtual() const { return true; }
+    virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) override;
+    virtual status_t activate(void* ident, bool enabled) override;
+    virtual status_t setDelay(void* ident, int handle, int64_t ns) override;
+    virtual const Sensor& getSensor() const override;
+    virtual bool isVirtual() const override { return true; }
 };
 
 class GameRotationVectorSensor : public RotationVectorSensor {
@@ -64,15 +64,15 @@
 class GyroDriftSensor : public SensorInterface {
     SensorDevice& mSensorDevice;
     SensorFusion& mSensorFusion;
+    Sensor mSensor;
 
 public:
     GyroDriftSensor();
-    virtual bool process(sensors_event_t* outEvent,
-            const sensors_event_t& event);
-    virtual status_t activate(void* ident, bool enabled);
-    virtual status_t setDelay(void* ident, int handle, int64_t ns);
-    virtual Sensor getSensor() const;
-    virtual bool isVirtual() const { return true; }
+    virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) override;
+    virtual status_t activate(void* ident, bool enabled) override;
+    virtual status_t setDelay(void* ident, int handle, int64_t ns) override;
+    virtual const Sensor& getSensor() const override;
+    virtual bool isVirtual() const override { return true; }
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp
index 970220b..bb2a8a2 100644
--- a/services/sensorservice/SensorInterface.cpp
+++ b/services/sensorservice/SensorInterface.cpp
@@ -65,7 +65,7 @@
     mSensorDevice.autoDisable(ident, handle);
 }
 
-Sensor HardwareSensor::getSensor() const {
+const Sensor& HardwareSensor::getSensor() const {
     return mSensor;
 }
 
diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h
index 3e76377..06cca75 100644
--- a/services/sensorservice/SensorInterface.h
+++ b/services/sensorservice/SensorInterface.h
@@ -33,8 +33,7 @@
 public:
     virtual ~SensorInterface();
 
-    virtual bool process(sensors_event_t* outEvent,
-            const sensors_event_t& event) = 0;
+    virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) = 0;
 
     virtual status_t activate(void* ident, bool enabled) = 0;
     virtual status_t setDelay(void* ident, int handle, int64_t ns) = 0;
@@ -52,7 +51,7 @@
         return -EINVAL;
     }
 
-    virtual Sensor getSensor() const = 0;
+    virtual const Sensor& getSensor() const = 0;
     virtual bool isVirtual() const = 0;
     virtual void autoDisable(void* /*ident*/, int /*handle*/) { }
 };
@@ -72,14 +71,14 @@
     virtual bool process(sensors_event_t* outEvent,
             const sensors_event_t& event);
 
-    virtual status_t activate(void* ident, bool enabled);
+    virtual status_t activate(void* ident, bool enabled) override;
     virtual status_t batch(void* ident, int handle, int flags, int64_t samplingPeriodNs,
-                           int64_t maxBatchReportLatencyNs);
-    virtual status_t setDelay(void* ident, int handle, int64_t ns);
-    virtual status_t flush(void* ident, int handle);
-    virtual Sensor getSensor() const;
-    virtual bool isVirtual() const { return false; }
-    virtual void autoDisable(void *ident, int handle);
+                           int64_t maxBatchReportLatencyNs) override;
+    virtual status_t setDelay(void* ident, int handle, int64_t ns) override;
+    virtual status_t flush(void* ident, int handle) override;
+    virtual const Sensor& getSensor() const override;
+    virtual bool isVirtual() const override { return false; }
+    virtual void autoDisable(void *ident, int handle) override;
 };
 
 
diff --git a/services/sensorservice/SensorList.cpp b/services/sensorservice/SensorList.cpp
new file mode 100644
index 0000000..f28acd2
--- /dev/null
+++ b/services/sensorservice/SensorList.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "SensorList.h"
+
+#include <hardware/sensors.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace SensorServiceUtil {
+
+const Sensor SensorList::mNonSensor = Sensor("unknown");
+
+bool SensorList::add(
+        int handle, SensorInterface* si, bool isForDebug, bool isVirtual) {
+    std::lock_guard<std::mutex> lk(mLock);
+    if (handle == si->getSensor().getHandle() &&
+        mUsedHandle.insert(handle).second) {
+        // will succeed as the mUsedHandle does not have this handle
+        mHandleMap.emplace(handle, Entry(si, isForDebug, isVirtual));
+        return true;
+    }
+    // handle exist already or handle mismatch
+    return false;
+}
+
+bool SensorList::remove(int handle) {
+    std::lock_guard<std::mutex> lk(mLock);
+    auto entry = mHandleMap.find(handle);
+    if (entry != mHandleMap.end()) {
+        mRecycle.push_back(entry->second.si);
+        mHandleMap.erase(entry);
+        return true;
+    }
+    return false;
+}
+
+String8 SensorList::getName(int handle) const {
+    return getOne<String8>(
+            handle, [] (const Entry& e) -> String8 {return e.si->getSensor().getName();},
+            mNonSensor.getName());
+}
+
+const Sensor& SensorList::get(int handle) const {
+    return getOne<const Sensor&>(
+            handle, [] (const Entry& e) -> const Sensor& {return e.si->getSensor();}, mNonSensor);
+}
+
+SensorInterface* SensorList::getInterface(int handle) const {
+    return getOne<SensorInterface *>(
+            handle, [] (const Entry& e) -> SensorInterface* {return e.si;}, nullptr);
+}
+
+
+bool SensorList::isNewHandle(int handle) const {
+    std::lock_guard<std::mutex> lk(mLock);
+    return mUsedHandle.find(handle) == mUsedHandle.end();
+}
+
+const Vector<Sensor> SensorList::getUserSensors() const {
+    // lock in forEachEntry
+    Vector<Sensor> sensors;
+    forEachEntry(
+            [&sensors] (const Entry& e) -> bool {
+                if (!e.isForDebug && !e.si->getSensor().isDynamicSensor()) {
+                    sensors.add(e.si->getSensor());
+                }
+                return true;
+            });
+    return sensors;
+}
+
+const Vector<Sensor> SensorList::getUserDebugSensors() const {
+    // lock in forEachEntry
+    Vector<Sensor> sensors;
+    forEachEntry(
+            [&sensors] (const Entry& e) -> bool {
+                if (!e.si->getSensor().isDynamicSensor()) {
+                    sensors.add(e.si->getSensor());
+                }
+                return true;
+            });
+    return sensors;
+}
+
+const Vector<Sensor> SensorList::getDynamicSensors() const {
+    // lock in forEachEntry
+    Vector<Sensor> sensors;
+    forEachEntry(
+            [&sensors] (const Entry& e) -> bool {
+                if (!e.isForDebug && e.si->getSensor().isDynamicSensor()) {
+                    sensors.add(e.si->getSensor());
+                }
+                return true;
+            });
+    return sensors;
+}
+
+const Vector<Sensor> SensorList::getVirtualSensors() const {
+    // lock in forEachEntry
+    Vector<Sensor> sensors;
+    forEachEntry(
+            [&sensors] (const Entry& e) -> bool {
+                if (e.isVirtual) {
+                    sensors.add(e.si->getSensor());
+                }
+                return true;
+            });
+    return sensors;
+}
+
+std::string SensorList::dump() const {
+    String8 result;
+
+    result.append("Sensor List:\n");
+    forEachSensor([&result] (const Sensor& s) -> bool {
+            result.appendFormat(
+                    "%-15s| %-10s| version=%d |%-20s| 0x%08x | \"%s\" | type=%d |",
+                    s.getName().string(),
+                    s.getVendor().string(),
+                    s.getVersion(),
+                    s.getStringType().string(),
+                    s.getHandle(),
+                    s.getRequiredPermission().string(),
+                    s.getType());
+
+            const int reportingMode = s.getReportingMode();
+            if (reportingMode == AREPORTING_MODE_CONTINUOUS) {
+                result.append(" continuous | ");
+            } else if (reportingMode == AREPORTING_MODE_ON_CHANGE) {
+                result.append(" on-change | ");
+            } else if (reportingMode == AREPORTING_MODE_ONE_SHOT) {
+                result.append(" one-shot | ");
+            } else if (reportingMode == AREPORTING_MODE_SPECIAL_TRIGGER) {
+                result.append(" special-trigger | ");
+            } else {
+                result.append(" unknown-mode | ");
+            }
+
+            if (s.getMaxDelay() > 0) {
+                result.appendFormat("minRate=%.2fHz | ", 1e6f / s.getMaxDelay());
+            } else {
+                result.appendFormat("maxDelay=%dus | ", s.getMaxDelay());
+            }
+
+            if (s.getMinDelay() > 0) {
+                result.appendFormat("maxRate=%.2fHz | ", 1e6f / s.getMinDelay());
+            } else {
+                result.appendFormat("minDelay=%dus | ", s.getMinDelay());
+            }
+
+            if (s.getFifoMaxEventCount() > 0) {
+                result.appendFormat("FifoMax=%d events | ",
+                        s.getFifoMaxEventCount());
+            } else {
+                result.append("no batching | ");
+            }
+
+            if (s.isWakeUpSensor()) {
+                result.appendFormat("wakeUp | ");
+            } else {
+                result.appendFormat("non-wakeUp | ");
+            }
+
+            result.append("\n");
+            return true;
+        });
+    return std::string(result.string());
+}
+
+SensorList::~SensorList() {
+    // from this point on no one should access anything in SensorList
+    mLock.lock();
+    for (auto i : mRecycle) {
+        delete i;
+    }
+    for (auto&& i : mHandleMap) {
+        delete i.second.si;
+    }
+    // the lock will eventually get destructed, there is no guarantee after that.
+}
+
+} // namespace SensorServiceUtil
+} // namespace android
+
diff --git a/services/sensorservice/SensorList.h b/services/sensorservice/SensorList.h
new file mode 100644
index 0000000..3fe73cc
--- /dev/null
+++ b/services/sensorservice/SensorList.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_SENSOR_LIST_H
+#define ANDROID_SENSOR_LIST_H
+
+#include "SensorInterface.h"
+
+#include <gui/Sensor.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include <mutex>
+#include <map>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+namespace android {
+class SensorInterface;
+
+namespace SensorServiceUtil {
+
+class Dumpable {
+public:
+    virtual std::string dump() const;
+    virtual void setFormat(std::string ) {}
+    virtual ~Dumpable() {}
+};
+
+class SensorList : public Dumpable {
+public:
+    // After SensorInterface * is added into SensorList, it can be assumed that SensorList own the
+    // object it pointed to and the object should not be released elsewhere.
+    bool add(int handle, SensorInterface* si, bool isForDebug = false, bool isVirtual = false);
+    bool remove(int handle);
+
+    inline bool hasAnySensor() const { return mHandleMap.size() > 0;}
+
+    //helper functions
+    const Vector<Sensor> getUserSensors() const;
+    const Vector<Sensor> getUserDebugSensors() const;
+    const Vector<Sensor> getDynamicSensors() const;
+    const Vector<Sensor> getVirtualSensors() const;
+
+    String8 getName(int handle) const;
+    const Sensor& get(int handle) const;
+    SensorInterface* getInterface(int handle) const;
+    bool isNewHandle(int handle) const;
+
+    // Iterate through Sensor in sensor list and perform operation f on each Sensor object.
+    //
+    // TF is a function with the signature:
+    //    bool f(const Sensor &);
+    // A return value of 'false' stops the iteration immediately.
+    //
+    // Note: in the function f, it is illegal to make calls to member functions of the same
+    // SensorList object on which forEachSensor is invoked.
+    template <typename TF>
+    void forEachSensor(const TF& f) const;
+
+    const Sensor& getNonSensor() const { return mNonSensor;}
+
+    // Dumpable interface
+    virtual std::string dump() const override;
+
+    virtual ~SensorList();
+private:
+    struct Entry {
+        //TODO: use sp<> here
+        SensorInterface * const si;
+        const bool isForDebug;
+        const bool isVirtual;
+        Entry(SensorInterface* si_, bool debug_, bool virtual_) :
+            si(si_), isForDebug(debug_), isVirtual(virtual_) {
+        }
+    };
+
+    const static Sensor mNonSensor; //.getName() == "unknown",
+
+    // Iterate through Entry in sensor list and perform operation f on each Entry.
+    //
+    // TF is a function with the signature:
+    //    bool f(const Entry &);
+    // A return value of 'false' stops the iteration over entries immediately.
+    //
+    // Note: in the function being passed in, it is illegal to make calls to member functions of the
+    // same SensorList object on which forEachSensor is invoked.
+    template <typename TF>
+    void forEachEntry(const TF& f) const;
+
+    template <typename T, typename TF>
+    T getOne(int handle, const TF& accessor, T def = T()) const;
+
+    mutable std::mutex mLock;
+    std::map<int, Entry> mHandleMap;
+    std::unordered_set<int> mUsedHandle;
+    std::vector<SensorInterface *> mRecycle;
+};
+
+template <typename TF>
+void SensorList::forEachSensor(const TF& f) const {
+    // lock happens in forEachEntry
+    forEachEntry([&f] (const Entry& e) -> bool { return f(e.si->getSensor());});
+}
+
+template <typename TF>
+void SensorList::forEachEntry(const TF& f) const {
+    std::lock_guard<std::mutex> lk(mLock);
+
+    for (auto&& i : mHandleMap) {
+        if (!f(i.second)){
+            break;
+        }
+    }
+}
+
+template <typename T, typename TF>
+T SensorList::getOne(int handle, const TF& accessor, T def) const {
+    std::lock_guard<std::mutex> lk(mLock);
+    auto i = mHandleMap.find(handle);
+    if (i != mHandleMap.end()) {
+        return accessor(i->second);
+    } else {
+        return def;
+    }
+}
+
+} // namespace SensorServiceUtil
+} // namespace android
+
+#endif // ANDROID_SENSOR_LIST_H
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 31ca0e3..f334e29 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -125,78 +125,51 @@
             // registered)
             SensorFusion::getInstance();
 
-            // build the sensor list returned to users
-            mUserSensorList = mSensorList;
-
             if (hasGyro && hasAccel && hasMag) {
                 // Add Android virtual sensors if they're not already
                 // available in the HAL
-                Sensor aSensor;
+                bool needRotationVector =
+                        (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR)) != 0;
 
-                aSensor = registerVirtualSensor( new RotationVectorSensor() );
-                if (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR)) {
-                    mUserSensorList.add(aSensor);
-                }
+                registerSensor(new RotationVectorSensor(), !needRotationVector, true);
+                registerSensor(new OrientationSensor(), !needRotationVector, true);
 
-                aSensor = registerVirtualSensor( new OrientationSensor() );
-                if (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR)) {
-                    // if we are doing our own rotation-vector, also add
-                    // the orientation sensor and remove the HAL provided one.
-                    mUserSensorList.replaceAt(aSensor, orientationIndex);
-                }
+                bool needLinearAcceleration =
+                        (virtualSensorsNeeds & (1<<SENSOR_TYPE_LINEAR_ACCELERATION)) != 0;
 
-                aSensor = registerVirtualSensor(
-                                new LinearAccelerationSensor(list, count) );
-                if (virtualSensorsNeeds &
-                            (1<<SENSOR_TYPE_LINEAR_ACCELERATION)) {
-                    mUserSensorList.add(aSensor);
-                }
+                registerSensor(new LinearAccelerationSensor(list, count),
+                               !needLinearAcceleration, true);
 
-                // virtual debugging sensors are not added to mUserSensorList
-                registerVirtualSensor( new CorrectedGyroSensor(list, count) );
-                registerVirtualSensor( new GyroDriftSensor() );
+                // virtual debugging sensors are not for user
+                registerSensor( new CorrectedGyroSensor(list, count), false, true);
+                registerSensor( new GyroDriftSensor(), false, true);
             }
 
             if (hasAccel && hasGyro) {
-                Sensor aSensor;
+                bool needGravitySensor = (virtualSensorsNeeds & (1<<SENSOR_TYPE_GRAVITY)) != 0;
+                registerSensor(new GravitySensor(list, count), !needGravitySensor, true);
 
-                aSensor = registerVirtualSensor(
-                                new GravitySensor(list, count) );
-                if (virtualSensorsNeeds & (1<<SENSOR_TYPE_GRAVITY)) {
-                    mUserSensorList.add(aSensor);
-                }
-
-                aSensor = registerVirtualSensor(
-                                new GameRotationVectorSensor() );
-                if (virtualSensorsNeeds &
-                            (1<<SENSOR_TYPE_GAME_ROTATION_VECTOR)) {
-                    mUserSensorList.add(aSensor);
-                }
+                bool needGameRotationVector =
+                        (virtualSensorsNeeds & (1<<SENSOR_TYPE_GAME_ROTATION_VECTOR)) != 0;
+                registerSensor(new GameRotationVectorSensor(), !needGameRotationVector, true);
             }
 
             if (hasAccel && hasMag) {
-                Sensor aSensor;
-
-                aSensor = registerVirtualSensor(
-                                new GeoMagRotationVectorSensor() );
-                if (virtualSensorsNeeds &
-                        (1<<SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR)) {
-                    mUserSensorList.add(aSensor);
-                }
+                bool needGeoMagRotationVector =
+                        (virtualSensorsNeeds & (1<<SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR)) != 0;
+                registerSensor(new GeoMagRotationVectorSensor(), !needGeoMagRotationVector, true);
             }
 
-            // debugging sensor list
-            mUserSensorListDebug = mSensorList;
-
             // Check if the device really supports batching by looking at the FIFO event
             // counts for each sensor.
             bool batchingSupported = false;
-            for (size_t i = 0; i < mSensorList.size(); ++i) {
-                if (mSensorList[i].getFifoMaxEventCount() > 0) {
-                    batchingSupported = true;
-                    break;
-                }
-            }
+            mSensors.forEachSensor(
+                    [&batchingSupported] (const Sensor& s) -> bool {
+                        if (s.getFifoMaxEventCount() > 0) {
+                            batchingSupported = true;
+                        }
+                        return !batchingSupported;
+                    });
 
             if (batchingSupported) {
                 // Increase socket buffer size to a max of 100 KB for batching capabilities.
@@ -242,75 +215,35 @@
     }
 }
 
-Sensor SensorService::registerSensor(SensorInterface* s) {
-    const Sensor sensor(s->getSensor());
-
-    // add handle to used handle list
-    mUsedHandleList.add(sensor.getHandle());
-    // add to the sensor list (returned to clients)
-    mSensorList.add(sensor);
-    // add to our handle->SensorInterface mapping
-    mSensorMap.add(sensor.getHandle(), s);
-    // create an entry in the mLastEventSeen array
-    mLastEventSeen.add(sensor.getHandle(), NULL);
-
-    return sensor;
+const Sensor& SensorService::registerSensor(SensorInterface* s, bool isDebug, bool isVirtual) {
+    int handle = s->getSensor().getHandle();
+    if (mSensors.add(handle, s, isDebug, isVirtual)){
+        mLastEventSeen.add(handle, nullptr);
+        return s->getSensor();
+    } else {
+        return mSensors.getNonSensor();
+    }
 }
 
-Sensor SensorService::registerDynamicSensor(SensorInterface* s) {
-    Sensor sensor = registerSensor(s);
-    mDynamicSensorList.add(sensor);
-
-    auto compareSensorHandle = [] (const Sensor* lhs, const Sensor* rhs) {
-        return lhs->getHandle() - rhs->getHandle();
-    };
-    mDynamicSensorList.sort(compareSensorHandle);
-    return sensor;
+const Sensor& SensorService::registerDynamicSensor(SensorInterface* s, bool isDebug) {
+    return registerSensor(s, isDebug);
 }
 
 bool SensorService::unregisterDynamicSensor(int handle) {
-    bool found = false;
-
-    for (size_t i = 0 ; i < mSensorList.size() ; i++) {
-        if (mSensorList[i].getHandle() == handle) {
-            mSensorList.removeAt(i);
-            found = true;
-            break;
-        }
+    bool ret = mSensors.remove(handle);
+    MostRecentEventLogger *buf = mLastEventSeen.valueFor(handle);
+    if (buf) {
+        delete buf;
     }
-
-    if (found) {
-        for (size_t i = 0 ; i < mDynamicSensorList.size() ; i++) {
-            if (mDynamicSensorList[i].getHandle() == handle) {
-                mDynamicSensorList.removeAt(i);
-            }
-        }
-
-        mSensorMap.removeItem(handle);
-        mLastEventSeen.removeItem(handle);
-    }
-    return found;
+    mLastEventSeen.removeItem(handle);
+    return ret;
 }
 
-Sensor SensorService::registerVirtualSensor(SensorInterface* s) {
-    Sensor sensor = registerSensor(s);
-    mVirtualSensorList.add( s );
-    return sensor;
-}
-
-bool SensorService::isNewHandle(int handle) {
-    for (int h : mUsedHandleList) {
-        if (h == handle) {
-            return false;
-        }
-    }
-    return true;
+const Sensor& SensorService::registerVirtualSensor(SensorInterface* s, bool isDebug) {
+    return registerSensor(s, isDebug, true);
 }
 
 SensorService::~SensorService() {
-    for (size_t i=0 ; i<mSensorMap.size() ; i++) {
-        delete mSensorMap.valueAt(i);
-    }
 }
 
 status_t SensorService::dump(int fd, const Vector<String16>& args) {
@@ -374,73 +307,31 @@
                 // Transition to data injection mode supported only from NORMAL mode.
                 return INVALID_OPERATION;
             }
-        } else if (mSensorList.size() == 0) {
+        } else if (!mSensors.hasAnySensor()) {
             result.append("No Sensors on the device\n");
         } else {
             // Default dump the sensor list and debugging information.
-            result.append("Sensor List:\n");
-            for (size_t i=0 ; i<mSensorList.size() ; i++) {
-                const Sensor& s(mSensorList[i]);
-                result.appendFormat(
-                        "%-15s| %-10s| version=%d |%-20s| 0x%08x | \"%s\" | type=%d |",
-                        s.getName().string(),
-                        s.getVendor().string(),
-                        s.getVersion(),
-                        s.getStringType().string(),
-                        s.getHandle(),
-                        s.getRequiredPermission().string(),
-                        s.getType());
+            //
+            result.append(mSensors.dump().c_str());
 
-                const int reportingMode = s.getReportingMode();
-                if (reportingMode == AREPORTING_MODE_CONTINUOUS) {
-                    result.append(" continuous | ");
-                } else if (reportingMode == AREPORTING_MODE_ON_CHANGE) {
-                    result.append(" on-change | ");
-                } else if (reportingMode == AREPORTING_MODE_ONE_SHOT) {
-                    result.append(" one-shot | ");
-                } else {
-                    result.append(" special-trigger | ");
-                }
-
-                if (s.getMaxDelay() > 0) {
-                    result.appendFormat("minRate=%.2fHz | ", 1e6f / s.getMaxDelay());
-                } else {
-                    result.appendFormat("maxDelay=%dus |", s.getMaxDelay());
-                }
-
-                if (s.getMinDelay() > 0) {
-                    result.appendFormat("maxRate=%.2fHz | ", 1e6f / s.getMinDelay());
-                } else {
-                    result.appendFormat("minDelay=%dus |", s.getMinDelay());
-                }
-
-                if (s.getFifoMaxEventCount() > 0) {
-                    result.appendFormat("FifoMax=%d events | ",
-                            s.getFifoMaxEventCount());
-                } else {
-                    result.append("no batching | ");
-                }
-
-                if (s.isWakeUpSensor()) {
-                    result.appendFormat("wakeUp | ");
-                } else {
-                    result.appendFormat("non-wakeUp | ");
-                }
-
-                int bufIndex = mLastEventSeen.indexOfKey(s.getHandle());
-                if (bufIndex >= 0) {
-                    const MostRecentEventLogger* buf = mLastEventSeen.valueAt(bufIndex);
-                    if (buf != NULL && s.getRequiredPermission().isEmpty()) {
-                        buf->printBuffer(result);
-                    } else {
-                        result.append("last=<> \n");
-                    }
-                }
-                result.append("\n");
-            }
             SensorFusion::getInstance().dump(result);
             SensorDevice::getInstance().dump(result);
 
+            result.append("Recent Sensor events:\n");
+            auto& lastEvents = mLastEventSeen;
+            mSensors.forEachSensor([&result, &lastEvents] (const Sensor& s) -> bool {
+                    int bufIndex = lastEvents.indexOfKey(s.getHandle());
+                    if (bufIndex >= 0) {
+                        const MostRecentEventLogger* buf = lastEvents.valueAt(bufIndex);
+                        if (buf != nullptr && s.getRequiredPermission().isEmpty()) {
+                            result.appendFormat("%s (handle:0x%08x): ",
+                                          s.getName().string(), s.getHandle());
+                            buf->printBuffer(result);
+                        }
+                    }
+                    return true;
+                });
+
             result.append("Active sensors:\n");
             for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
                 int handle = mActiveSensors.keyAt(i);
@@ -508,6 +399,7 @@
     return NO_ERROR;
 }
 
+//TODO: move to SensorEventConnection later
 void SensorService::cleanupAutoDisabledSensorLocked(const sp<SensorEventConnection>& connection,
         sensors_event_t const* buffer, const int count) {
     for (int i=0 ; i<count ; i++) {
@@ -516,12 +408,12 @@
             handle = buffer[i].meta_data.sensor;
         }
         if (connection->hasSensor(handle)) {
-            SensorInterface* sensor = getSensorInterfaceFromHandle(handle);
+            SensorInterface* si = mSensors.getInterface(handle);
             // If this buffer has an event from a one_shot sensor and this connection is registered
             // for this particular one_shot sensor, try cleaning up the connection.
-            if (sensor != NULL &&
-                sensor->getSensor().getReportingMode() == AREPORTING_MODE_ONE_SHOT) {
-                sensor->autoDisable(connection.get(), handle);
+            if (si != NULL &&
+                si->getSensor().getReportingMode() == AREPORTING_MODE_ONE_SHOT) {
+                si->autoDisable(connection.get(), handle);
                 cleanupWithoutDisableLocked(connection, handle);
             }
 
@@ -535,11 +427,11 @@
     // each virtual sensor could generate an event per "real" event, that's why we need to size
     // numEventMax much smaller than MAX_RECEIVE_BUFFER_EVENT_COUNT.  in practice, this is too
     // aggressive, but guaranteed to be enough.
+    const size_t vcount = mSensors.getVirtualSensors().size();
     const size_t minBufferSize = SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT;
-    const size_t numEventMax = minBufferSize / (1 + mVirtualSensorList.size());
+    const size_t numEventMax = minBufferSize / (1 + vcount);
 
     SensorDevice& device(SensorDevice::getInstance());
-    const size_t vcount = mVirtualSensorList.size();
 
     const int halVersion = device.getHalDeviceVersion();
     do {
@@ -632,10 +524,10 @@
         }
 
         for (int i = 0; i < count; ++i) {
-            // Map flush_complete_events in the buffer to SensorEventConnections which called flush on
-            // the hardware sensor. mapFlushEventsToConnections[i] will be the SensorEventConnection
-            // mapped to the corresponding flush_complete_event in mSensorEventBuffer[i] if such a
-            // mapping exists (NULL otherwise).
+            // Map flush_complete_events in the buffer to SensorEventConnections which called flush
+            // on the hardware sensor. mapFlushEventsToConnections[i] will be the
+            // SensorEventConnection mapped to the corresponding flush_complete_event in
+            // mSensorEventBuffer[i] if such a mapping exists (NULL otherwise).
             mMapFlushEventsToConnections[i] = NULL;
             if (mSensorEventBuffer[i].type == SENSOR_TYPE_META_DATA) {
                 const int sensor_handle = mSensorEventBuffer[i].meta_data.sensor;
@@ -656,7 +548,7 @@
                     ALOGI("Dynamic sensor handle 0x%x connected, type %d, name %s",
                           handle, dynamicSensor.type, dynamicSensor.name);
 
-                    if (isNewHandle(handle)) {
+                    if (mSensors.isNewHandle(handle)) {
                         sensor_t s = dynamicSensor;
                         // make sure the dynamic sensor flag is set
                         s.flags |= DYNAMIC_SENSOR_MASK;
@@ -664,8 +556,8 @@
                         s.handle = handle;
                         SensorInterface *si = new HardwareSensor(s);
 
-                        // This will release hold on dynamic sensor meta, so it should be called after
-                        // Sensor object is created.
+                        // This will release hold on dynamic sensor meta, so it should be called
+                        // after Sensor object is created.
                         device.handleDynamicSensorConnection(handle, true /*connected*/);
                         registerDynamicSensor(si);
                     } else {
@@ -802,14 +694,7 @@
 }
 
 String8 SensorService::getSensorName(int handle) const {
-    size_t count = mUserSensorList.size();
-    for (size_t i=0 ; i<count ; i++) {
-        const Sensor& sensor(mUserSensorList[i]);
-        if (sensor.getHandle() == handle) {
-            return sensor.getName();
-        }
-    }
-    return String8("unknown");
+    return mSensors.getName(handle);
 }
 
 bool SensorService::isVirtualSensor(int handle) const {
@@ -830,7 +715,7 @@
     char value[PROPERTY_VALUE_MAX];
     property_get("debug.sensors", value, "0");
     const Vector<Sensor>& initialSensorList = (atoi(value)) ?
-            mUserSensorListDebug : mUserSensorList;
+            mSensors.getUserDebugSensors() : mSensors.getUserSensors();
     Vector<Sensor> accessibleSensorList;
     for (size_t i = 0; i < initialSensorList.size(); i++) {
         Sensor sensor = initialSensorList[i];
@@ -848,17 +733,19 @@
 
 Vector<Sensor> SensorService::getDynamicSensorList(const String16& opPackageName) {
     Vector<Sensor> accessibleSensorList;
-    for (size_t i = 0; i < mDynamicSensorList.size(); i++) {
-        Sensor sensor = mDynamicSensorList[i];
-        if (canAccessSensor(sensor, "getDynamicSensorList", opPackageName)) {
-            accessibleSensorList.add(sensor);
-        } else {
-            ALOGI("Skipped sensor %s because it requires permission %s and app op %d",
-                  sensor.getName().string(),
-                  sensor.getRequiredPermission().string(),
-                  sensor.getRequiredAppOp());
-        }
-    }
+    mSensors.forEachSensor(
+            [&opPackageName, &accessibleSensorList] (const Sensor& sensor) -> bool {
+                if (sensor.isDynamicSensor() &&
+                        canAccessSensor(sensor, "getDynamicSensorList", opPackageName)) {
+                    accessibleSensorList.add(sensor);
+                } else {
+                    ALOGI("Skipped sensor %s because it requires permission %s and app op %" PRId32,
+                          sensor.getName().string(),
+                          sensor.getRequiredPermission().string(),
+                          sensor.getRequiredAppOp());
+                }
+                return true;
+            });
     return accessibleSensorList;
 }
 
@@ -950,13 +837,11 @@
 }
 
 SensorInterface* SensorService::getSensorInterfaceFromHandle(int handle) const {
-    ssize_t index = mSensorMap.indexOfKey(handle);
-    return index < 0 ? nullptr : mSensorMap.valueAt(index);
+    return mSensors.getInterface(handle);
 }
 
-Sensor SensorService::getSensorFromHandle(int handle) const {
-    SensorInterface* si = getSensorInterfaceFromHandle(handle);
-    return si ? si->getSensor() : Sensor();
+const Sensor& SensorService::getSensorFromHandle(int handle) const {
+    return mSensors.get(handle);
 }
 
 status_t SensorService::enable(const sp<SensorEventConnection>& connection,
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index da97286..e535339 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -37,6 +37,7 @@
 #include <gui/ISensorEventConnection.h>
 
 #include "SensorInterface.h"
+#include "SensorList.h"
 
 #if __clang__
 // Clang warns about SensorEventConnection::dump hiding BBinder::dump. The cause isn't fixable
@@ -156,18 +157,18 @@
     virtual int isDataInjectionEnabled();
     virtual status_t dump(int fd, const Vector<String16>& args);
 
-
     static int getNumEventsForSensorType(int sensor_event_type);
     String8 getSensorName(int handle) const;
     bool isVirtualSensor(int handle) const;
     SensorInterface* getSensorInterfaceFromHandle(int handle) const;
-    Sensor getSensorFromHandle(int handle) const;
+    const Sensor& getSensorFromHandle(int handle) const;
     bool isWakeUpSensor(int type) const;
     void recordLastValueLocked(sensors_event_t const* buffer, size_t count);
     static void sortEventBuffer(sensors_event_t* buffer, size_t count);
-    Sensor registerSensor(SensorInterface* sensor);
-    Sensor registerVirtualSensor(SensorInterface* sensor);
-    Sensor registerDynamicSensor(SensorInterface* sensor);
+    const Sensor& registerSensor(SensorInterface* sensor,
+                                 bool isDebug = false, bool isVirtual = false);
+    const Sensor& registerVirtualSensor(SensorInterface* sensor, bool isDebug = false);
+    const Sensor& registerDynamicSensor(SensorInterface* sensor, bool isDebug = false);
     bool unregisterDynamicSensor(int handle);
     status_t cleanupWithoutDisable(const sp<SensorEventConnection>& connection, int handle);
     status_t cleanupWithoutDisableLocked(const sp<SensorEventConnection>& connection, int handle);
@@ -182,7 +183,6 @@
     void checkWakeLockStateLocked();
     bool isWakeLockAcquired();
     bool isWakeUpSensorEvent(const sensors_event_t& event) const;
-    bool isNewHandle(int handle);
 
     sp<Looper> getLooper() const;
 
@@ -211,14 +211,7 @@
     status_t resetToNormalMode();
     status_t resetToNormalModeLocked();
 
-    // lists and maps
-    Vector<Sensor> mSensorList;
-    Vector<Sensor> mUserSensorListDebug;
-    Vector<Sensor> mUserSensorList;
-    Vector<Sensor> mDynamicSensorList;
-    DefaultKeyedVector<int, SensorInterface*> mSensorMap;
-    Vector<SensorInterface *> mVirtualSensorList;
-    Vector<int> mUsedHandleList;
+    SensorServiceUtil::SensorList mSensors;
     status_t mInitCheck;
 
     // Socket buffersize used to initialize BitTube. This size depends on whether batching is
@@ -233,6 +226,7 @@
     bool mWakeLockAcquired;
     sensors_event_t *mSensorEventBuffer, *mSensorEventScratch;
     SensorEventConnection const **mMapFlushEventsToConnections;
+    KeyedVector<int32_t, MostRecentEventLogger*> mLastEventSeen;
     Mode mCurrentOperatingMode;
 
     // This packagaName is set when SensorService is in RESTRICTED or DATA_INJECTION mode. Only
@@ -241,9 +235,6 @@
     // sensors.
     String8 mWhiteListedPackage;
 
-    // The size of this vector is constant, only the items are mutable
-    KeyedVector<int32_t, MostRecentEventLogger *> mLastEventSeen;
-
     int mNextSensorRegIndex;
     Vector<SensorRegistrationInfo> mLastNSensorRegistrations;
 };
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index 5ba387d..4cf9370 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -15,6 +15,7 @@
  */
 
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
 
 // This is needed for stdint.h to define INT64_MAX in C++
 #define __STDC_LIMIT_MACROS
@@ -33,12 +34,21 @@
 #include "DispSync.h"
 #include "EventLog/EventLog.h"
 
+#include <algorithm>
+
+using std::max;
+using std::min;
+
 namespace android {
 
 // Setting this to true enables verbose tracing that can be used to debug
 // vsync event model or phase issues.
 static const bool kTraceDetailedInfo = false;
 
+// Setting this to true adds a zero-phase tracer for correlating with hardware
+// vsync events
+static const bool kEnableZeroPhaseTracer = false;
+
 // This is the threshold used to determine when hardware vsync events are
 // needed to re-synchronize the software vsync model with the hardware.  The
 // error metric used is the mean of the squared difference between each
@@ -49,28 +59,36 @@
 // vsync event.
 static const int64_t kPresentTimeOffset = PRESENT_TIME_OFFSET_FROM_VSYNC_NS;
 
+#undef LOG_TAG
+#define LOG_TAG "DispSyncThread"
 class DispSyncThread: public Thread {
 public:
 
-    DispSyncThread():
+    DispSyncThread(const char* name):
+            mName(name),
             mStop(false),
             mPeriod(0),
             mPhase(0),
             mReferenceTime(0),
-            mWakeupLatency(0) {
-    }
+            mWakeupLatency(0),
+            mFrameNumber(0) {}
 
     virtual ~DispSyncThread() {}
 
     void updateModel(nsecs_t period, nsecs_t phase, nsecs_t referenceTime) {
+        if (kTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
         mPeriod = period;
         mPhase = phase;
         mReferenceTime = referenceTime;
+        ALOGV("[%s] updateModel: mPeriod = %" PRId64 ", mPhase = %" PRId64
+                " mReferenceTime = %" PRId64, mName, ns2us(mPeriod),
+                ns2us(mPhase), ns2us(mReferenceTime));
         mCond.signal();
     }
 
     void stop() {
+        if (kTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
         mStop = true;
         mCond.signal();
@@ -89,6 +107,12 @@
             { // Scope for lock
                 Mutex::Autolock lock(mMutex);
 
+                if (kTraceDetailedInfo) {
+                    ATRACE_INT64("DispSync:Frame", mFrameNumber);
+                }
+                ALOGV("[%s] Frame %" PRId64, mName, mFrameNumber);
+                ++mFrameNumber;
+
                 if (mStop) {
                     return false;
                 }
@@ -109,6 +133,9 @@
                 bool isWakeup = false;
 
                 if (now < targetTime) {
+                    ALOGV("[%s] Waiting until %" PRId64, mName,
+                            ns2us(targetTime));
+                    if (kTraceDetailedInfo) ATRACE_NAME("DispSync waiting");
                     err = mCond.waitRelative(mMutex, targetTime - now);
 
                     if (err == TIMED_OUT) {
@@ -122,15 +149,15 @@
 
                 now = systemTime(SYSTEM_TIME_MONOTONIC);
 
+                // Don't correct by more than 1.5 ms
+                static const nsecs_t kMaxWakeupLatency = us2ns(1500);
+
                 if (isWakeup) {
                     mWakeupLatency = ((mWakeupLatency * 63) +
                             (now - targetTime)) / 64;
-                    if (mWakeupLatency > 500000) {
-                        // Don't correct by more than 500 us
-                        mWakeupLatency = 500000;
-                    }
+                    mWakeupLatency = min(mWakeupLatency, kMaxWakeupLatency);
                     if (kTraceDetailedInfo) {
-                        ATRACE_INT64("DispSync:WakeupLat", now - nextEventTime);
+                        ATRACE_INT64("DispSync:WakeupLat", now - targetTime);
                         ATRACE_INT64("DispSync:AvgWakeupLat", mWakeupLatency);
                     }
                 }
@@ -146,7 +173,9 @@
         return false;
     }
 
-    status_t addEventListener(nsecs_t phase, const sp<DispSync::Callback>& callback) {
+    status_t addEventListener(const char* name, nsecs_t phase,
+            const sp<DispSync::Callback>& callback) {
+        if (kTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
 
         for (size_t i = 0; i < mEventListeners.size(); i++) {
@@ -156,15 +185,14 @@
         }
 
         EventListener listener;
+        listener.mName = name;
         listener.mPhase = phase;
         listener.mCallback = callback;
 
         // We want to allow the firstmost future event to fire without
-        // allowing any past events to fire.  Because
-        // computeListenerNextEventTimeLocked filters out events within a half
-        // a period of the last event time, we need to initialize the last
-        // event time to a half a period in the past.
-        listener.mLastEventTime = systemTime(SYSTEM_TIME_MONOTONIC) - mPeriod / 2;
+        // allowing any past events to fire
+        listener.mLastEventTime = systemTime() - mPeriod / 2 + mPhase -
+                mWakeupLatency;
 
         mEventListeners.push(listener);
 
@@ -174,6 +202,7 @@
     }
 
     status_t removeEventListener(const sp<DispSync::Callback>& callback) {
+        if (kTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
 
         for (size_t i = 0; i < mEventListeners.size(); i++) {
@@ -189,6 +218,7 @@
 
     // This method is only here to handle the kIgnorePresentFences case.
     bool hasAnyEventListeners() {
+        if (kTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
         return !mEventListeners.empty();
     }
@@ -196,6 +226,7 @@
 private:
 
     struct EventListener {
+        const char* mName;
         nsecs_t mPhase;
         nsecs_t mLastEventTime;
         sp<DispSync::Callback> mCallback;
@@ -207,6 +238,8 @@
     };
 
     nsecs_t computeNextEventTimeLocked(nsecs_t now) {
+        if (kTraceDetailedInfo) ATRACE_CALL();
+        ALOGV("[%s] computeNextEventTimeLocked", mName);
         nsecs_t nextEventTime = INT64_MAX;
         for (size_t i = 0; i < mEventListeners.size(); i++) {
             nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i],
@@ -217,21 +250,28 @@
             }
         }
 
+        ALOGV("[%s] nextEventTime = %" PRId64, mName, ns2us(nextEventTime));
         return nextEventTime;
     }
 
     Vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) {
+        if (kTraceDetailedInfo) ATRACE_CALL();
+        ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName,
+                ns2us(now));
+
         Vector<CallbackInvocation> callbackInvocations;
-        nsecs_t ref = now - mPeriod;
+        nsecs_t onePeriodAgo = now - mPeriod;
 
         for (size_t i = 0; i < mEventListeners.size(); i++) {
             nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i],
-                    ref);
+                    onePeriodAgo);
 
             if (t < now) {
                 CallbackInvocation ci;
                 ci.mCallback = mEventListeners[i].mCallback;
                 ci.mEventTime = t;
+                ALOGV("[%s] [%s] Preparing to fire", mName,
+                        mEventListeners[i].mName);
                 callbackInvocations.push(ci);
                 mEventListeners.editItemAt(i).mLastEventTime = t;
             }
@@ -241,29 +281,67 @@
     }
 
     nsecs_t computeListenerNextEventTimeLocked(const EventListener& listener,
-            nsecs_t ref) {
+            nsecs_t baseTime) {
+        if (kTraceDetailedInfo) ATRACE_CALL();
+        ALOGV("[%s] [%s] computeListenerNextEventTimeLocked(%" PRId64 ")",
+                mName, listener.mName, ns2us(baseTime));
 
-        nsecs_t lastEventTime = listener.mLastEventTime;
-        if (ref < lastEventTime) {
-            ref = lastEventTime;
+        nsecs_t lastEventTime = listener.mLastEventTime + mWakeupLatency;
+        ALOGV("[%s] lastEventTime: %" PRId64, mName, ns2us(lastEventTime));
+        if (baseTime < lastEventTime) {
+            baseTime = lastEventTime;
+            ALOGV("[%s] Clamping baseTime to lastEventTime -> %" PRId64, mName,
+                    ns2us(baseTime));
         }
 
-        nsecs_t phase = mReferenceTime + mPhase + listener.mPhase;
-        nsecs_t t = (((ref - phase) / mPeriod) + 1) * mPeriod + phase;
+        baseTime -= mReferenceTime;
+        ALOGV("[%s] Relative baseTime = %" PRId64, mName, ns2us(baseTime));
+        nsecs_t phase = mPhase + listener.mPhase;
+        ALOGV("[%s] Phase = %" PRId64, mName, ns2us(phase));
+        baseTime -= phase;
+        ALOGV("[%s] baseTime - phase = %" PRId64, mName, ns2us(baseTime));
 
-        if (t - listener.mLastEventTime < mPeriod / 2) {
+        // If our previous time is before the reference (because the reference
+        // has since been updated), the division by mPeriod will truncate
+        // towards zero instead of computing the floor. Since in all cases
+        // before the reference we want the next time to be effectively now, we
+        // set baseTime to -mPeriod so that numPeriods will be -1.
+        // When we add 1 and the phase, we will be at the correct event time for
+        // this period.
+        if (baseTime < 0) {
+            ALOGV("[%s] Correcting negative baseTime", mName);
+            baseTime = -mPeriod;
+        }
+
+        nsecs_t numPeriods = baseTime / mPeriod;
+        ALOGV("[%s] numPeriods = %" PRId64, mName, numPeriods);
+        nsecs_t t = (numPeriods + 1) * mPeriod + phase;
+        ALOGV("[%s] t = %" PRId64, mName, ns2us(t));
+        t += mReferenceTime;
+        ALOGV("[%s] Absolute t = %" PRId64, mName, ns2us(t));
+
+        // Check that it's been slightly more than half a period since the last
+        // event so that we don't accidentally fall into double-rate vsyncs
+        if (t - listener.mLastEventTime < (3 * mPeriod / 5)) {
             t += mPeriod;
+            ALOGV("[%s] Modifying t -> %" PRId64, mName, ns2us(t));
         }
 
+        t -= mWakeupLatency;
+        ALOGV("[%s] Corrected for wakeup latency -> %" PRId64, mName, ns2us(t));
+
         return t;
     }
 
     void fireCallbackInvocations(const Vector<CallbackInvocation>& callbacks) {
+        if (kTraceDetailedInfo) ATRACE_CALL();
         for (size_t i = 0; i < callbacks.size(); i++) {
             callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime);
         }
     }
 
+    const char* const mName;
+
     bool mStop;
 
     nsecs_t mPeriod;
@@ -271,12 +349,17 @@
     nsecs_t mReferenceTime;
     nsecs_t mWakeupLatency;
 
+    int64_t mFrameNumber;
+
     Vector<EventListener> mEventListeners;
 
     Mutex mMutex;
     Condition mCond;
 };
 
+#undef LOG_TAG
+#define LOG_TAG "DispSync"
+
 class ZeroPhaseTracer : public DispSync::Callback {
 public:
     ZeroPhaseTracer() : mParity(false) {}
@@ -290,9 +373,10 @@
     bool mParity;
 };
 
-DispSync::DispSync() :
+DispSync::DispSync(const char* name) :
+        mName(name),
         mRefreshSkipCount(0),
-        mThread(new DispSyncThread()) {
+        mThread(new DispSyncThread(name)) {
 
     mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
 
@@ -305,8 +389,8 @@
         // Even if we're just ignoring the fences, the zero-phase tracing is
         // not needed because any time there is an event registered we will
         // turn on the HW vsync events.
-        if (!kIgnorePresentFences) {
-            addEventListener(0, new ZeroPhaseTracer());
+        if (!kIgnorePresentFences && kEnableZeroPhaseTracer) {
+            addEventListener("ZeroPhaseTracer", 0, new ZeroPhaseTracer());
         }
     }
 }
@@ -351,7 +435,7 @@
 
 void DispSync::beginResync() {
     Mutex::Autolock lock(mMutex);
-
+    ALOGV("[%s] beginResync", mName);
     mModelUpdated = false;
     mNumResyncSamples = 0;
 }
@@ -359,11 +443,17 @@
 bool DispSync::addResyncSample(nsecs_t timestamp) {
     Mutex::Autolock lock(mMutex);
 
+    ALOGV("[%s] addResyncSample(%" PRId64 ")", mName, ns2us(timestamp));
+
     size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES;
     mResyncSamples[idx] = timestamp;
     if (mNumResyncSamples == 0) {
         mPhase = 0;
         mReferenceTime = timestamp;
+        ALOGV("[%s] First resync sample: mPeriod = %" PRId64 ", mPhase = 0, "
+                "mReferenceTime = %" PRId64, mName, ns2us(mPeriod),
+                ns2us(mReferenceTime));
+        mThread->updateModel(mPeriod, mPhase, mReferenceTime);
     }
 
     if (mNumResyncSamples < MAX_RESYNC_SAMPLES) {
@@ -387,17 +477,21 @@
         return mThread->hasAnyEventListeners();
     }
 
-    return !mModelUpdated || mError > kErrorThreshold;
+    // Check against kErrorThreshold / 2 to add some hysteresis before having to
+    // resync again
+    bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2);
+    ALOGV("[%s] addResyncSample returning %s", mName,
+            modelLocked ? "locked" : "unlocked");
+    return !modelLocked;
 }
 
 void DispSync::endResync() {
 }
 
-status_t DispSync::addEventListener(nsecs_t phase,
+status_t DispSync::addEventListener(const char* name, nsecs_t phase,
         const sp<Callback>& callback) {
-
     Mutex::Autolock lock(mMutex);
-    return mThread->addEventListener(phase, callback);
+    return mThread->addEventListener(name, phase, callback);
 }
 
 void DispSync::setRefreshSkipCount(int count) {
@@ -427,20 +521,32 @@
 }
 
 void DispSync::updateModelLocked() {
+    ALOGV("[%s] updateModelLocked %zu", mName, mNumResyncSamples);
     if (mNumResyncSamples >= MIN_RESYNC_SAMPLES_FOR_UPDATE) {
+        ALOGV("[%s] Computing...", mName);
         nsecs_t durationSum = 0;
+        nsecs_t minDuration = INT64_MAX;
+        nsecs_t maxDuration = 0;
         for (size_t i = 1; i < mNumResyncSamples; i++) {
             size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
             size_t prev = (idx + MAX_RESYNC_SAMPLES - 1) % MAX_RESYNC_SAMPLES;
-            durationSum += mResyncSamples[idx] - mResyncSamples[prev];
+            nsecs_t duration = mResyncSamples[idx] - mResyncSamples[prev];
+            durationSum += duration;
+            minDuration = min(minDuration, duration);
+            maxDuration = max(maxDuration, duration);
         }
 
-        mPeriod = durationSum / (mNumResyncSamples - 1);
+        // Exclude the min and max from the average
+        durationSum -= minDuration + maxDuration;
+        mPeriod = durationSum / (mNumResyncSamples - 3);
+
+        ALOGV("[%s] mPeriod = %" PRId64, mName, ns2us(mPeriod));
 
         double sampleAvgX = 0;
         double sampleAvgY = 0;
         double scale = 2.0 * M_PI / double(mPeriod);
-        for (size_t i = 0; i < mNumResyncSamples; i++) {
+        // Intentionally skip the first sample
+        for (size_t i = 1; i < mNumResyncSamples; i++) {
             size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
             nsecs_t sample = mResyncSamples[idx] - mReferenceTime;
             double samplePhase = double(sample % mPeriod) * scale;
@@ -448,18 +554,21 @@
             sampleAvgY += sin(samplePhase);
         }
 
-        sampleAvgX /= double(mNumResyncSamples);
-        sampleAvgY /= double(mNumResyncSamples);
+        sampleAvgX /= double(mNumResyncSamples - 1);
+        sampleAvgY /= double(mNumResyncSamples - 1);
 
         mPhase = nsecs_t(atan2(sampleAvgY, sampleAvgX) / scale);
 
-        if (mPhase < 0) {
+        ALOGV("[%s] mPhase = %" PRId64, mName, ns2us(mPhase));
+
+        if (mPhase < -(mPeriod / 2)) {
             mPhase += mPeriod;
+            ALOGV("[%s] Adjusting mPhase -> %" PRId64, mName, ns2us(mPhase));
         }
 
         if (kTraceDetailedInfo) {
             ATRACE_INT64("DispSync:Period", mPeriod);
-            ATRACE_INT64("DispSync:Phase", mPhase);
+            ATRACE_INT64("DispSync:Phase", mPhase + mPeriod / 2);
         }
 
         // Artificially inflate the period if requested.
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index a8524b9..537c81b 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -26,11 +26,8 @@
 namespace android {
 
 // Ignore present (retire) fences if the device doesn't have support for the
-// sync framework, or if all phase offsets are zero.  The latter is useful
-// because it allows us to avoid resync bursts on devices that don't need
-// phase-offset VSYNC events.
-#if defined(RUNNING_WITHOUT_SYNC_FRAMEWORK) || \
-        (VSYNC_EVENT_PHASE_OFFSET_NS == 0 && SF_VSYNC_EVENT_PHASE_OFFSET_NS == 0)
+// sync framework
+#if defined(RUNNING_WITHOUT_SYNC_FRAMEWORK)
 static const bool kIgnorePresentFences = true;
 #else
 static const bool kIgnorePresentFences = false;
@@ -64,7 +61,7 @@
         virtual void onDispSyncEvent(nsecs_t when) = 0;
     };
 
-    DispSync();
+    DispSync(const char* name);
     ~DispSync();
 
     // reset clears the resync samples and error value.
@@ -114,7 +111,8 @@
     // given phase offset from the hardware vsync events.  The callback is
     // called from a separate thread and it should return reasonably quickly
     // (i.e. within a few hundred microseconds).
-    status_t addEventListener(nsecs_t phase, const sp<Callback>& callback);
+    status_t addEventListener(const char* name, nsecs_t phase,
+            const sp<Callback>& callback);
 
     // removeEventListener removes an already-registered event callback.  Once
     // this method returns that callback will no longer be called by the
@@ -137,10 +135,12 @@
     void resetErrorLocked();
 
     enum { MAX_RESYNC_SAMPLES = 32 };
-    enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 3 };
+    enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 6 };
     enum { NUM_PRESENT_SAMPLES = 8 };
     enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 };
 
+    const char* const mName;
+
     // mPeriod is the computed period of the modeled vsync events in
     // nanoseconds.
     nsecs_t mPeriod;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 0e97a53..5c78c68 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -74,6 +74,7 @@
 using android::Fence;
 using android::FloatRect;
 using android::GraphicBuffer;
+using android::HdrCapabilities;
 using android::Rect;
 using android::Region;
 using android::sp;
@@ -100,6 +101,7 @@
     mGetDisplayRequests(nullptr),
     mGetDisplayType(nullptr),
     mGetDozeSupport(nullptr),
+    mGetHdrCapabilities(nullptr),
     mGetReleaseFences(nullptr),
     mPresentDisplay(nullptr),
     mSetActiveConfig(nullptr),
@@ -307,82 +309,84 @@
     // loadFunctionPointer specifying which function failed to load
 
     // Display function pointers
-    if(!loadFunctionPointer(FunctionDescriptor::CreateVirtualDisplay,
+    if (!loadFunctionPointer(FunctionDescriptor::CreateVirtualDisplay,
             mCreateVirtualDisplay)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::DestroyVirtualDisplay,
+    if (!loadFunctionPointer(FunctionDescriptor::DestroyVirtualDisplay,
             mDestroyVirtualDisplay)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::Dump, mDump)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetMaxVirtualDisplayCount,
+    if (!loadFunctionPointer(FunctionDescriptor::Dump, mDump)) return;
+    if (!loadFunctionPointer(FunctionDescriptor::GetMaxVirtualDisplayCount,
             mGetMaxVirtualDisplayCount)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::RegisterCallback,
+    if (!loadFunctionPointer(FunctionDescriptor::RegisterCallback,
             mRegisterCallback)) return;
 
     // Device function pointers
-    if(!loadFunctionPointer(FunctionDescriptor::AcceptDisplayChanges,
+    if (!loadFunctionPointer(FunctionDescriptor::AcceptDisplayChanges,
             mAcceptDisplayChanges)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::CreateLayer,
+    if (!loadFunctionPointer(FunctionDescriptor::CreateLayer,
             mCreateLayer)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::DestroyLayer,
+    if (!loadFunctionPointer(FunctionDescriptor::DestroyLayer,
             mDestroyLayer)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetActiveConfig,
+    if (!loadFunctionPointer(FunctionDescriptor::GetActiveConfig,
             mGetActiveConfig)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetChangedCompositionTypes,
+    if (!loadFunctionPointer(FunctionDescriptor::GetChangedCompositionTypes,
             mGetChangedCompositionTypes)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetDisplayAttribute,
+    if (!loadFunctionPointer(FunctionDescriptor::GetDisplayAttribute,
             mGetDisplayAttribute)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetDisplayConfigs,
+    if (!loadFunctionPointer(FunctionDescriptor::GetDisplayConfigs,
             mGetDisplayConfigs)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetDisplayName,
+    if (!loadFunctionPointer(FunctionDescriptor::GetDisplayName,
             mGetDisplayName)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetDisplayRequests,
+    if (!loadFunctionPointer(FunctionDescriptor::GetDisplayRequests,
             mGetDisplayRequests)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetDisplayType,
+    if (!loadFunctionPointer(FunctionDescriptor::GetDisplayType,
             mGetDisplayType)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetDozeSupport,
+    if (!loadFunctionPointer(FunctionDescriptor::GetDozeSupport,
             mGetDozeSupport)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::GetReleaseFences,
+    if (!loadFunctionPointer(FunctionDescriptor::GetHdrCapabilities,
+            mGetHdrCapabilities)) return;
+    if (!loadFunctionPointer(FunctionDescriptor::GetReleaseFences,
             mGetReleaseFences)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::PresentDisplay,
+    if (!loadFunctionPointer(FunctionDescriptor::PresentDisplay,
             mPresentDisplay)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetActiveConfig,
+    if (!loadFunctionPointer(FunctionDescriptor::SetActiveConfig,
             mSetActiveConfig)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetClientTarget,
+    if (!loadFunctionPointer(FunctionDescriptor::SetClientTarget,
             mSetClientTarget)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetOutputBuffer,
+    if (!loadFunctionPointer(FunctionDescriptor::SetOutputBuffer,
             mSetOutputBuffer)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetPowerMode,
+    if (!loadFunctionPointer(FunctionDescriptor::SetPowerMode,
             mSetPowerMode)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetVsyncEnabled,
+    if (!loadFunctionPointer(FunctionDescriptor::SetVsyncEnabled,
             mSetVsyncEnabled)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::ValidateDisplay,
+    if (!loadFunctionPointer(FunctionDescriptor::ValidateDisplay,
             mValidateDisplay)) return;
 
     // Layer function pointers
-    if(!loadFunctionPointer(FunctionDescriptor::SetCursorPosition,
+    if (!loadFunctionPointer(FunctionDescriptor::SetCursorPosition,
             mSetCursorPosition)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerBuffer,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerBuffer,
             mSetLayerBuffer)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerSurfaceDamage,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerSurfaceDamage,
             mSetLayerSurfaceDamage)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerBlendMode,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerBlendMode,
             mSetLayerBlendMode)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerColor,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerColor,
             mSetLayerColor)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerCompositionType,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerCompositionType,
             mSetLayerCompositionType)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerDisplayFrame,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerDisplayFrame,
             mSetLayerDisplayFrame)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerPlaneAlpha,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerPlaneAlpha,
             mSetLayerPlaneAlpha)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerSidebandStream,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerSidebandStream,
             mSetLayerSidebandStream)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerSourceCrop,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerSourceCrop,
             mSetLayerSourceCrop)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerTransform,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerTransform,
             mSetLayerTransform)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerVisibleRegion,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerVisibleRegion,
             mSetLayerVisibleRegion)) return;
-    if(!loadFunctionPointer(FunctionDescriptor::SetLayerZOrder,
+    if (!loadFunctionPointer(FunctionDescriptor::SetLayerZOrder,
             mSetLayerZOrder)) return;
 }
 
@@ -637,6 +641,34 @@
     return Error::None;
 }
 
+Error Display::getHdrCapabilities(
+        std::unique_ptr<HdrCapabilities>* outCapabilities) const
+{
+    uint32_t numTypes = 0;
+    float maxLuminance = -1.0f;
+    float maxAverageLuminance = -1.0f;
+    float minLuminance = -1.0f;
+    int32_t intError = mDevice.mGetHdrCapabilities(mDevice.mHwcDevice, mId,
+            &numTypes, nullptr, &maxLuminance, &maxAverageLuminance,
+            &minLuminance);
+    auto error = static_cast<HWC2::Error>(intError);
+    if (error != Error::None) {
+        return error;
+    }
+
+    std::vector<int32_t> types(numTypes);
+    intError = mDevice.mGetHdrCapabilities(mDevice.mHwcDevice, mId, &numTypes,
+            types.data(), &maxLuminance, &maxAverageLuminance, &minLuminance);
+    error = static_cast<HWC2::Error>(intError);
+    if (error != Error::None) {
+        return error;
+    }
+
+    *outCapabilities = std::make_unique<HdrCapabilities>(std::move(types),
+            maxLuminance, maxAverageLuminance, minLuminance);
+    return Error::None;
+}
+
 Error Display::getReleaseFences(
         std::unordered_map<std::shared_ptr<Layer>, sp<Fence>>* outFences) const
 {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index a7bd28c..7d33a0a 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -23,6 +23,8 @@
 #undef HWC2_INCLUDE_STRINGIFICATION
 #undef HWC2_USE_CPP11
 
+#include <ui/HdrCapabilities.h>
+
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
 #include <utils/Timers.h>
@@ -145,6 +147,7 @@
     HWC2_PFN_GET_DISPLAY_REQUESTS mGetDisplayRequests;
     HWC2_PFN_GET_DISPLAY_TYPE mGetDisplayType;
     HWC2_PFN_GET_DOZE_SUPPORT mGetDozeSupport;
+    HWC2_PFN_GET_HDR_CAPABILITIES mGetHdrCapabilities;
     HWC2_PFN_GET_RELEASE_FENCES mGetReleaseFences;
     HWC2_PFN_PRESENT_DISPLAY mPresentDisplay;
     HWC2_PFN_SET_ACTIVE_CONFIG mSetActiveConfig;
@@ -279,6 +282,8 @@
                     outLayerRequests);
     [[clang::warn_unused_result]] Error getType(DisplayType* outType) const;
     [[clang::warn_unused_result]] Error supportsDoze(bool* outSupport) const;
+    [[clang::warn_unused_result]] Error getHdrCapabilities(
+            std::unique_ptr<android::HdrCapabilities>* outCapabilities) const;
     [[clang::warn_unused_result]] Error getReleaseFences(
             std::unordered_map<std::shared_ptr<Layer>,
                     android::sp<android::Fence>>* outFences) const;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
index dabc77f..6ebcdfe 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
@@ -238,6 +238,11 @@
             return asFP<HWC2_PFN_GET_DOZE_SUPPORT>(
                     displayHook<decltype(&Display::getDozeSupport),
                     &Display::getDozeSupport, int32_t*>);
+        case FunctionDescriptor::GetHdrCapabilities:
+            return asFP<HWC2_PFN_GET_HDR_CAPABILITIES>(
+                    displayHook<decltype(&Display::getHdrCapabilities),
+                    &Display::getHdrCapabilities, uint32_t*, int32_t*, float*,
+                    float*, float*>);
         case FunctionDescriptor::GetReleaseFences:
             return asFP<HWC2_PFN_GET_RELEASE_FENCES>(
                     displayHook<decltype(&Display::getReleaseFences),
@@ -709,6 +714,15 @@
     return Error::None;
 }
 
+Error HWC2On1Adapter::Display::getHdrCapabilities(uint32_t* outNumTypes,
+        int32_t* /*outTypes*/, float* /*outMaxLuminance*/,
+        float* /*outMaxAverageLuminance*/, float* /*outMinLuminance*/)
+{
+    // This isn't supported on HWC1, so per the HWC2 header, return numTypes = 0
+    *outNumTypes = 0;
+    return Error::None;
+}
+
 Error HWC2On1Adapter::Display::getName(uint32_t* outSize, char* outName)
 {
     std::unique_lock<std::recursive_mutex> lock(mStateMutex);
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
index bffeefe..6fdb184 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
@@ -194,6 +194,9 @@
             HWC2::Error getConfigs(uint32_t* outNumConfigs,
                     hwc2_config_t* outConfigIds);
             HWC2::Error getDozeSupport(int32_t* outSupport);
+            HWC2::Error getHdrCapabilities(uint32_t* outNumTypes,
+                    int32_t* outTypes, float* outMaxLuminance,
+                    float* outMaxAverageLuminance, float* outMinLuminance);
             HWC2::Error getName(uint32_t* outSize, char* outName);
             HWC2::Error getReleaseFences(uint32_t* outNumElements,
                     hwc2_layer_t* outLayers, int32_t* outFences);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 26f9519..cd2e05f 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -736,6 +736,26 @@
     mDisplayData[displayId].releaseFences.clear();
 }
 
+std::unique_ptr<HdrCapabilities> HWComposer::getHdrCapabilities(
+        int32_t displayId) {
+    if (!isValidDisplay(displayId)) {
+        ALOGE("getHdrCapabilities: Display %d is not valid", displayId);
+        return nullptr;
+    }
+
+    auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
+    std::unique_ptr<HdrCapabilities> capabilities;
+    auto error = hwcDisplay->getHdrCapabilities(&capabilities);
+    if (error != HWC2::Error::None) {
+        ALOGE("getOutputCapabilities: Failed to get capabilities on display %d:"
+                " %s (%d)", displayId, to_string(error).c_str(),
+                static_cast<int32_t>(error));
+        return nullptr;
+    }
+
+    return capabilities;
+}
+
 // Converts a PixelFormat to a human-readable string.  Max 11 chars.
 // (Could use a table of prefab String8 objects.)
 /*
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 30c8f67..d407877 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -130,6 +130,9 @@
     // it can call this to clear the shared pointers in the release fence map
     void clearReleaseFences(int32_t displayId);
 
+    // Returns the HDR capabilities of the given display
+    std::unique_ptr<HdrCapabilities> getHdrCapabilities(int32_t displayId);
+
     // Events handling ---------------------------------------------------------
 
     void setVsyncEnabled(int32_t disp, HWC2::Vsync enabled);
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index f760200..dd88adb 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -44,8 +44,9 @@
     return;
 }
 
-EventThread::EventThread(const sp<VSyncSource>& src)
+EventThread::EventThread(const sp<VSyncSource>& src, SurfaceFlinger& flinger)
     : mVSyncSource(src),
+      mFlinger(flinger),
       mUseSoftwareVSync(false),
       mVsyncEnabled(false),
       mDebugVsyncEnabled(false),
@@ -126,6 +127,9 @@
 void EventThread::requestNextVsync(
         const sp<EventThread::Connection>& connection) {
     Mutex::Autolock _l(mLock);
+
+    mFlinger.resyncWithRateLimit();
+
     if (connection->count < 0) {
         connection->count = 0;
         mCondition.broadcast();
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 9ba179a..34654fa 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -77,7 +77,7 @@
 
 public:
 
-    EventThread(const sp<VSyncSource>& src);
+    EventThread(const sp<VSyncSource>& src, SurfaceFlinger& flinger);
 
     sp<Connection> createEventConnection() const;
     status_t registerDisplayEventConnection(const sp<Connection>& connection);
@@ -116,6 +116,7 @@
     // constants
     sp<VSyncSource> mVSyncSource;
     PowerHAL mPowerHAL;
+    SurfaceFlinger& mFlinger;
 
     mutable Mutex mLock;
     mutable Condition mCondition;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 40e9ae7..a448639 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -149,6 +149,7 @@
         mLastTransactionTime(0),
         mBootFinished(false),
         mForceFullDamage(false),
+        mPrimaryDispSync("PrimaryDispSync"),
         mPrimaryHWVsyncEnabled(false),
         mHWVsyncAvailable(false),
         mDaltonize(false),
@@ -331,11 +332,12 @@
 class DispSyncSource : public VSyncSource, private DispSync::Callback {
 public:
     DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
-        const char* label) :
+        const char* name) :
+            mName(name),
             mValue(0),
             mTraceVsync(traceVsync),
-            mVsyncOnLabel(String8::format("VsyncOn-%s", label)),
-            mVsyncEventLabel(String8::format("VSYNC-%s", label)),
+            mVsyncOnLabel(String8::format("VsyncOn-%s", name)),
+            mVsyncEventLabel(String8::format("VSYNC-%s", name)),
             mDispSync(dispSync),
             mCallbackMutex(),
             mCallback(),
@@ -348,7 +350,7 @@
     virtual void setVSyncEnabled(bool enable) {
         Mutex::Autolock lock(mVsyncMutex);
         if (enable) {
-            status_t err = mDispSync->addEventListener(mPhaseOffset,
+            status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
                     static_cast<DispSync::Callback*>(this));
             if (err != NO_ERROR) {
                 ALOGE("error registering vsync callback: %s (%d)",
@@ -399,7 +401,7 @@
         }
 
         // Add a listener with the new offset
-        err = mDispSync->addEventListener(mPhaseOffset,
+        err = mDispSync->addEventListener(mName, mPhaseOffset,
                 static_cast<DispSync::Callback*>(this));
         if (err != NO_ERROR) {
             ALOGE("error registering vsync callback: %s (%d)",
@@ -425,6 +427,8 @@
         }
     }
 
+    const char* const mName;
+
     int mValue;
 
     const bool mTraceVsync;
@@ -455,10 +459,10 @@
         // start the EventThread
         sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
                 vsyncPhaseOffsetNs, true, "app");
-        mEventThread = new EventThread(vsyncSrc);
+        mEventThread = new EventThread(vsyncSrc, *this);
         sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
                 sfVsyncPhaseOffsetNs, true, "sf");
-        mSFEventThread = new EventThread(sfVsyncSrc);
+        mSFEventThread = new EventThread(sfVsyncSrc, *this);
         mEventQueue.setEventThread(mSFEventThread);
 
         // Get a RenderEngine for the given display / config (can't fail)
@@ -715,6 +719,27 @@
     return NO_ERROR;
 }
 
+status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& display,
+        HdrCapabilities* outCapabilities) const {
+    Mutex::Autolock _l(mStateLock);
+
+    sp<const DisplayDevice> displayDevice(getDisplayDevice(display));
+    if (displayDevice == nullptr) {
+        ALOGE("getHdrCapabilities: Invalid display %p", displayDevice.get());
+        return BAD_VALUE;
+    }
+
+    std::unique_ptr<HdrCapabilities> capabilities =
+            mHwc->getHdrCapabilities(displayDevice->getHwcDisplayId());
+    if (capabilities) {
+        std::swap(*outCapabilities, *capabilities);
+    } else {
+        return BAD_VALUE;
+    }
+
+    return NO_ERROR;
+}
+
 // ----------------------------------------------------------------------------
 
 sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
@@ -806,6 +831,13 @@
     }
 }
 
+void SurfaceFlinger::resyncWithRateLimit() {
+    static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
+    if (systemTime() - mLastSwapTime > kIgnoreDelay) {
+        resyncToHardwareVsync(true);
+    }
+}
+
 void SurfaceFlinger::onVSyncReceived(int32_t type, nsecs_t timestamp) {
     bool needsHwVsync = false;
 
@@ -2881,6 +2913,7 @@
         case CLEAR_ANIMATION_FRAME_STATS:
         case GET_ANIMATION_FRAME_STATS:
         case SET_POWER_MODE:
+        case GET_HDR_CAPABILITIES:
         {
             // codes that require permission check
             IPCThreadState* ipc = IPCThreadState::self();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 37110b9..633e956 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -222,6 +222,8 @@
     virtual status_t setActiveConfig(const sp<IBinder>& display, int id);
     virtual status_t clearAnimationFrameStats();
     virtual status_t getAnimationFrameStats(FrameStats* outStats) const;
+    virtual status_t getHdrCapabilities(const sp<IBinder>& display,
+            HdrCapabilities* outCapabilities) const;
 
     /* ------------------------------------------------------------------------
      * DeathRecipient interface
@@ -407,8 +409,11 @@
      * VSync
      */
      void enableHardwareVsync();
-     void disableHardwareVsync(bool makeUnavailable);
      void resyncToHardwareVsync(bool makeAvailable);
+     void disableHardwareVsync(bool makeUnavailable);
+public:
+     void resyncWithRateLimit();
+private:
 
     /* ------------------------------------------------------------------------
      * Debugging & dumpsys
@@ -520,7 +525,7 @@
     static const size_t NUM_BUCKETS = 8; // < 1-7, 7+
     nsecs_t mFrameBuckets[NUM_BUCKETS];
     nsecs_t mTotalTime;
-    nsecs_t mLastSwapTime;
+    std::atomic<nsecs_t> mLastSwapTime;
 };
 
 }; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index a63ec50..ea685e7 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -45,6 +45,7 @@
 #include <gui/GraphicBufferAlloc.h>
 
 #include <ui/GraphicBufferAllocator.h>
+#include <ui/HdrCapabilities.h>
 #include <ui/PixelFormat.h>
 #include <ui/UiConfig.h>
 
@@ -147,6 +148,7 @@
         mLastTransactionTime(0),
         mBootFinished(false),
         mForceFullDamage(false),
+        mPrimaryDispSync("PrimaryDispSync"),
         mPrimaryHWVsyncEnabled(false),
         mHWVsyncAvailable(false),
         mDaltonize(false),
@@ -328,11 +330,12 @@
 class DispSyncSource : public VSyncSource, private DispSync::Callback {
 public:
     DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
-        const char* label) :
+        const char* name) :
+            mName(name),
             mValue(0),
             mTraceVsync(traceVsync),
-            mVsyncOnLabel(String8::format("VsyncOn-%s", label)),
-            mVsyncEventLabel(String8::format("VSYNC-%s", label)),
+            mVsyncOnLabel(String8::format("VsyncOn-%s", name)),
+            mVsyncEventLabel(String8::format("VSYNC-%s", name)),
             mDispSync(dispSync),
             mCallbackMutex(),
             mCallback(),
@@ -345,7 +348,7 @@
     virtual void setVSyncEnabled(bool enable) {
         Mutex::Autolock lock(mVsyncMutex);
         if (enable) {
-            status_t err = mDispSync->addEventListener(mPhaseOffset,
+            status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
                     static_cast<DispSync::Callback*>(this));
             if (err != NO_ERROR) {
                 ALOGE("error registering vsync callback: %s (%d)",
@@ -396,7 +399,7 @@
         }
 
         // Add a listener with the new offset
-        err = mDispSync->addEventListener(mPhaseOffset,
+        err = mDispSync->addEventListener(mName, mPhaseOffset,
                 static_cast<DispSync::Callback*>(this));
         if (err != NO_ERROR) {
             ALOGE("error registering vsync callback: %s (%d)",
@@ -422,6 +425,8 @@
         }
     }
 
+    const char* const mName;
+
     int mValue;
 
     const bool mTraceVsync;
@@ -451,10 +456,10 @@
     // start the EventThread
     sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
             vsyncPhaseOffsetNs, true, "app");
-    mEventThread = new EventThread(vsyncSrc);
+    mEventThread = new EventThread(vsyncSrc, *this);
     sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
             sfVsyncPhaseOffsetNs, true, "sf");
-    mSFEventThread = new EventThread(sfVsyncSrc);
+    mSFEventThread = new EventThread(sfVsyncSrc, *this);
     mEventQueue.setEventThread(mSFEventThread);
 
     // Initialize the H/W composer object.  There may or may not be an
@@ -748,6 +753,13 @@
     return NO_ERROR;
 }
 
+status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& /*display*/,
+        HdrCapabilities* outCapabilities) const {
+    // HWC1 does not provide HDR capabilities
+    *outCapabilities = HdrCapabilities();
+    return NO_ERROR;
+}
+
 // ----------------------------------------------------------------------------
 
 sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
@@ -839,6 +851,13 @@
     }
 }
 
+void SurfaceFlinger::resyncWithRateLimit() {
+    static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
+    if (systemTime() - mLastSwapTime > kIgnoreDelay) {
+        resyncToHardwareVsync(true);
+    }
+}
+
 void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
     bool needsHwVsync = false;
 
@@ -2917,6 +2936,7 @@
         case CLEAR_ANIMATION_FRAME_STATS:
         case GET_ANIMATION_FRAME_STATS:
         case SET_POWER_MODE:
+        case GET_HDR_CAPABILITIES:
         {
             // codes that require permission check
             IPCThreadState* ipc = IPCThreadState::self();
diff --git a/vulkan/api/platform.api b/vulkan/api/platform.api
index 980722d..7aa19e7 100644
--- a/vulkan/api/platform.api
+++ b/vulkan/api/platform.api
@@ -43,6 +43,7 @@
 
 // VK_USE_PLATFORM_ANDROID_KHR
 @internal class ANativeWindow {}
+@internal type void* buffer_handle_t
 
 // VK_USE_PLATFORM_WIN32_KHR
 @internal type void* HINSTANCE
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index 10565ab..ae690a3 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -75,6 +75,9 @@
 @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_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION     5
+@extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_NAME             "VK_ANDROID_native_buffer"
+
 @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"
 
@@ -646,6 +649,9 @@
     //@extension("VK_KHR_win32_surface")
     VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR             = 1000009000,
 
+    //@extension("VK_ANDROID_native_buffer")
+    VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID                     = 1000010000,
+
     //@extension("VK_EXT_debug_report")
     VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT              = 1000011000,
 }
@@ -2591,6 +2597,16 @@
     platform.HWND                               hwnd
 }
 
+@extension("VK_ANDROID_native_buffer")
+class VkNativeBufferANDROID {
+    VkStructureType                             sType
+    const void*                                 pNext
+    platform.buffer_handle_t                    handle
+    int                                         stride
+    int                                         format
+    int                                         usage
+}
+
 @extension("VK_EXT_debug_report")
 class VkDebugReportCallbackCreateInfoEXT {
     VkStructureType                             sType
@@ -5134,6 +5150,35 @@
     return ?
 }
 
+@extension("VK_ANDROID_native_buffer")
+cmd VkResult vkGetSwapchainGrallocUsageANDROID(
+        VkDevice                                device,
+        VkFormat                                format,
+        VkImageUsageFlags                       imageUsage,
+        int*                                    grallocUsage) {
+    return ?
+}
+
+@extension("VK_ANDROID_native_buffer")
+cmd VkResult vkAcquireImageANDROID(
+        VkDevice                                device,
+        VkImage                                 image,
+        int                                     nativeFenceFd,
+        VkSemaphore                             semaphore,
+        VkFence                                 fence) {
+    return ?
+}
+
+@extension("VK_ANDROID_native_buffer")
+cmd VkResult vkQueueSignalReleaseImageANDROID(
+        VkQueue                                 queue,
+        u32                                     waitSemaphoreCount,
+        const VkSemaphore*                      pWaitSemaphores,
+        VkImage                                 image,
+        int*                                    pNativeFenceFd) {
+    return ?
+}
+
 @extension("VK_EXT_debug_report")
 @external type void* PFN_vkDebugReportCallbackEXT
 @extension("VK_EXT_debug_report")
diff --git a/vulkan/libvulkan/Android.mk b/vulkan/libvulkan/Android.mk
index e60d74c..7830c26 100644
--- a/vulkan/libvulkan/Android.mk
+++ b/vulkan/libvulkan/Android.mk
@@ -42,9 +42,10 @@
 	api.cpp \
 	api_gen.cpp \
 	debug_report.cpp \
-	dispatch_gen.cpp \
+	driver.cpp \
+	driver_gen.cpp \
 	layers_extensions.cpp \
-	loader.cpp \
+	stubhal.cpp \
 	swapchain.cpp \
 	vulkan_loader_data.cpp
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index 9c5aa3b..4e19af5 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -33,7 +33,7 @@
 #include <vulkan/vk_layer_interface.h>
 #include "api.h"
 #include "driver.h"
-#include "loader.h"
+#include "layers_extensions.h"
 
 namespace vulkan {
 namespace api {
@@ -60,8 +60,8 @@
         allocator_.pfnFree(allocator_.pUserData, implicit_layers_.name_pool);
     }
 
-    VkResult parse(const char* const* names, uint32_t count) {
-        add_implicit_layers();
+    VkResult Parse(const char* const* names, uint32_t count) {
+        AddImplicitLayers();
 
         const auto& arr = implicit_layers_;
         if (arr.result != VK_SUCCESS)
@@ -71,20 +71,20 @@
         if (!arr.count)
             return VK_SUCCESS;
 
-        names_ = allocate_name_array(arr.count + count);
+        names_ = AllocateNameArray(arr.count + count);
         if (!names_)
             return VK_ERROR_OUT_OF_HOST_MEMORY;
 
         // add implicit layer names
         for (uint32_t i = 0; i < arr.count; i++)
-            names_[i] = get_implicit_layer_name(i);
+            names_[i] = GetImplicitLayerName(i);
 
         name_count_ = arr.count;
 
         // add explicit layer names
         for (uint32_t i = 0; i < count; i++) {
             // ignore explicit layers that are also implicit
-            if (is_implicit_layer(names[i]))
+            if (IsImplicitLayer(names[i]))
                 continue;
 
             names_[name_count_++] = names[i];
@@ -93,9 +93,9 @@
         return VK_SUCCESS;
     }
 
-    const char* const* names() const { return names_; }
+    const char* const* Names() const { return names_; }
 
-    uint32_t count() const { return name_count_; }
+    uint32_t Count() const { return name_count_; }
 
    private:
     struct ImplicitLayer {
@@ -115,12 +115,12 @@
         VkResult result;
     };
 
-    void add_implicit_layers() {
+    void AddImplicitLayers() {
         if (!driver::Debuggable())
             return;
 
-        parse_debug_vulkan_layers();
-        property_list(parse_debug_vulkan_layer, this);
+        ParseDebugVulkanLayers();
+        property_list(ParseDebugVulkanLayer, this);
 
         // sort by priorities
         auto& arr = implicit_layers_;
@@ -130,7 +130,7 @@
                   });
     }
 
-    void parse_debug_vulkan_layers() {
+    void ParseDebugVulkanLayers() {
         // debug.vulkan.layers specifies colon-separated layer names
         char prop[PROPERTY_VALUE_MAX];
         if (!property_get("debug.vulkan.layers", prop, ""))
@@ -143,19 +143,19 @@
         const char* delim;
         while ((delim = strchr(p, ':'))) {
             if (delim > p)
-                add_implicit_layer(prio, p, static_cast<size_t>(delim - p));
+                AddImplicitLayer(prio, p, static_cast<size_t>(delim - p));
 
             prio++;
             p = delim + 1;
         }
 
         if (p[0] != '\0')
-            add_implicit_layer(prio, p, strlen(p));
+            AddImplicitLayer(prio, p, strlen(p));
     }
 
-    static void parse_debug_vulkan_layer(const char* key,
-                                         const char* val,
-                                         void* user_data) {
+    static void ParseDebugVulkanLayer(const char* key,
+                                      const char* val,
+                                      void* user_data) {
         static const char prefix[] = "debug.vulkan.layer.";
         const size_t prefix_len = sizeof(prefix) - 1;
 
@@ -176,25 +176,24 @@
 
         OverrideLayerNames& override_layers =
             *reinterpret_cast<OverrideLayerNames*>(user_data);
-        override_layers.add_implicit_layer(priority, val, strlen(val));
+        override_layers.AddImplicitLayer(priority, val, strlen(val));
     }
 
-    void add_implicit_layer(int priority, const char* name, size_t len) {
-        if (!grow_implicit_layer_array(1, 0))
+    void AddImplicitLayer(int priority, const char* name, size_t len) {
+        if (!GrowImplicitLayerArray(1, 0))
             return;
 
         auto& arr = implicit_layers_;
         auto& layer = arr.elements[arr.count++];
 
         layer.priority = priority;
-        layer.name_offset = add_implicit_layer_name(name, len);
+        layer.name_offset = AddImplicitLayerName(name, len);
 
-        ALOGV("Added implicit layer %s",
-              get_implicit_layer_name(arr.count - 1));
+        ALOGV("Added implicit layer %s", GetImplicitLayerName(arr.count - 1));
     }
 
-    size_t add_implicit_layer_name(const char* name, size_t len) {
-        if (!grow_implicit_layer_array(0, len + 1))
+    size_t AddImplicitLayerName(const char* name, size_t len) {
+        if (!GrowImplicitLayerArray(0, len + 1))
             return 0;
 
         // add the name to the pool
@@ -210,7 +209,7 @@
         return offset;
     }
 
-    bool grow_implicit_layer_array(uint32_t layer_count, size_t name_size) {
+    bool GrowImplicitLayerArray(uint32_t layer_count, size_t name_size) {
         const uint32_t initial_max_count = 16;
         const size_t initial_max_pool_size = 512;
 
@@ -265,25 +264,25 @@
         return true;
     }
 
-    const char* get_implicit_layer_name(uint32_t index) const {
+    const char* GetImplicitLayerName(uint32_t index) const {
         const auto& arr = implicit_layers_;
 
         // this may return nullptr when arr.result is not VK_SUCCESS
         return implicit_layers_.name_pool + arr.elements[index].name_offset;
     }
 
-    bool is_implicit_layer(const char* name) const {
+    bool IsImplicitLayer(const char* name) const {
         const auto& arr = implicit_layers_;
 
         for (uint32_t i = 0; i < arr.count; i++) {
-            if (strcmp(name, get_implicit_layer_name(i)) == 0)
+            if (strcmp(name, GetImplicitLayerName(i)) == 0)
                 return true;
         }
 
         return false;
     }
 
-    const char** allocate_name_array(uint32_t count) const {
+    const char** AllocateNameArray(uint32_t count) const {
         return reinterpret_cast<const char**>(allocator_.pfnAllocation(
             allocator_.pUserData, sizeof(const char*) * count,
             alignof(const char*), scope_));
@@ -318,12 +317,12 @@
         allocator_.pfnFree(allocator_.pUserData, names_);
     }
 
-    VkResult parse(const char* const* names, uint32_t count) {
+    VkResult Parse(const char* const* names, uint32_t count) {
         // this is only for debug.vulkan.enable_callback
-        if (!enable_debug_callback())
+        if (!EnableDebugCallback())
             return VK_SUCCESS;
 
-        names_ = allocate_name_array(count + 1);
+        names_ = AllocateNameArray(count + 1);
         if (!names_)
             return VK_ERROR_OUT_OF_HOST_MEMORY;
 
@@ -337,19 +336,19 @@
         return VK_SUCCESS;
     }
 
-    const char* const* names() const { return names_; }
+    const char* const* Names() const { return names_; }
 
-    uint32_t count() const { return name_count_; }
+    uint32_t Count() const { return name_count_; }
 
-    bool install_debug_callback() const { return install_debug_callback_; }
+    bool InstallDebugCallback() const { return install_debug_callback_; }
 
    private:
-    bool enable_debug_callback() const {
+    bool EnableDebugCallback() const {
         return (is_instance_ && driver::Debuggable() &&
                 property_get_bool("debug.vulkan.enable_callback", false));
     }
 
-    const char** allocate_name_array(uint32_t count) const {
+    const char** AllocateNameArray(uint32_t count) const {
         return reinterpret_cast<const char**>(allocator_.pfnAllocation(
             allocator_.pUserData, sizeof(const char*) * count,
             alignof(const char*), scope_));
@@ -368,20 +367,20 @@
 // chaining.
 class LayerChain {
    public:
-    static VkResult create_instance(const VkInstanceCreateInfo* create_info,
-                                    const VkAllocationCallbacks* allocator,
-                                    VkInstance* instance_out);
+    static VkResult CreateInstance(const VkInstanceCreateInfo* create_info,
+                                   const VkAllocationCallbacks* allocator,
+                                   VkInstance* instance_out);
 
-    static VkResult create_device(VkPhysicalDevice physical_dev,
-                                  const VkDeviceCreateInfo* create_info,
-                                  const VkAllocationCallbacks* allocator,
-                                  VkDevice* dev_out);
+    static VkResult CreateDevice(VkPhysicalDevice physical_dev,
+                                 const VkDeviceCreateInfo* create_info,
+                                 const VkAllocationCallbacks* allocator,
+                                 VkDevice* dev_out);
 
-    static void destroy_instance(VkInstance instance,
-                                 const VkAllocationCallbacks* allocator);
+    static void DestroyInstance(VkInstance instance,
+                                const VkAllocationCallbacks* allocator);
 
-    static void destroy_device(VkDevice dev,
-                               const VkAllocationCallbacks* allocator);
+    static void DestroyDevice(VkDevice dev,
+                              const VkAllocationCallbacks* allocator);
 
    private:
     struct ActiveLayer {
@@ -395,43 +394,52 @@
     LayerChain(bool is_instance, const VkAllocationCallbacks& allocator);
     ~LayerChain();
 
-    VkResult activate_layers(const char* const* layer_names,
-                             uint32_t layer_count,
-                             const char* const* extension_names,
-                             uint32_t extension_count);
-    ActiveLayer* allocate_layer_array(uint32_t count) const;
-    VkResult load_layer(ActiveLayer& layer, const char* name);
-    void setup_layer_links();
+    VkResult ActivateLayers(const char* const* layer_names,
+                            uint32_t layer_count,
+                            const char* const* extension_names,
+                            uint32_t extension_count);
+    ActiveLayer* AllocateLayerArray(uint32_t count) const;
+    VkResult LoadLayer(ActiveLayer& layer, const char* name);
+    void SetupLayerLinks();
 
-    bool empty() const;
-    void modify_create_info(VkInstanceCreateInfo& info);
-    void modify_create_info(VkDeviceCreateInfo& info);
+    bool Empty() const;
+    void ModifyCreateInfo(VkInstanceCreateInfo& info);
+    void ModifyCreateInfo(VkDeviceCreateInfo& info);
 
-    VkResult create(const VkInstanceCreateInfo* create_info,
+    VkResult Create(const VkInstanceCreateInfo* create_info,
                     const VkAllocationCallbacks* allocator,
                     VkInstance* instance_out);
 
-    VkResult create(VkPhysicalDevice physical_dev,
+    VkResult Create(VkPhysicalDevice physical_dev,
                     const VkDeviceCreateInfo* create_info,
                     const VkAllocationCallbacks* allocator,
                     VkDevice* dev_out);
 
-    template <typename DataType>
-    void steal_layers(DataType& data);
+    VkResult ValidateExtensions(const char* const* extension_names,
+                                uint32_t extension_count);
+    VkResult ValidateExtensions(VkPhysicalDevice physical_dev,
+                                const char* const* extension_names,
+                                uint32_t extension_count);
+    VkExtensionProperties* AllocateDriverExtensionArray(uint32_t count) const;
+    bool IsLayerExtension(const char* name) const;
+    bool IsDriverExtension(const char* name) const;
 
-    static void destroy_layers(ActiveLayer* layers,
-                               uint32_t count,
-                               const VkAllocationCallbacks& allocator);
+    template <typename DataType>
+    void StealLayers(DataType& data);
+
+    static void DestroyLayers(ActiveLayer* layers,
+                              uint32_t count,
+                              const VkAllocationCallbacks& allocator);
 
     static VKAPI_ATTR VkBool32
-    debug_report_callback(VkDebugReportFlagsEXT flags,
-                          VkDebugReportObjectTypeEXT obj_type,
-                          uint64_t obj,
-                          size_t location,
-                          int32_t msg_code,
-                          const char* layer_prefix,
-                          const char* msg,
-                          void* user_data);
+    DebugReportCallback(VkDebugReportFlagsEXT flags,
+                        VkDebugReportObjectTypeEXT obj_type,
+                        uint64_t obj,
+                        size_t location,
+                        int32_t msg_code,
+                        const char* layer_prefix,
+                        const char* msg,
+                        void* user_data);
 
     const bool is_instance_;
     const VkAllocationCallbacks& allocator_;
@@ -449,6 +457,9 @@
         VkLayerInstanceCreateInfo instance_chain_info_;
         VkLayerDeviceCreateInfo device_chain_info_;
     };
+
+    VkExtensionProperties* driver_extensions_;
+    uint32_t driver_extension_count_;
 };
 
 LayerChain::LayerChain(bool is_instance, const VkAllocationCallbacks& allocator)
@@ -459,27 +470,30 @@
       layers_(nullptr),
       layer_count_(0),
       get_instance_proc_addr_(nullptr),
-      get_device_proc_addr_(nullptr) {}
+      get_device_proc_addr_(nullptr),
+      driver_extensions_(nullptr),
+      driver_extension_count_(0) {}
 
 LayerChain::~LayerChain() {
-    destroy_layers(layers_, layer_count_, allocator_);
+    allocator_.pfnFree(allocator_.pUserData, driver_extensions_);
+    DestroyLayers(layers_, layer_count_, allocator_);
 }
 
-VkResult LayerChain::activate_layers(const char* const* layer_names,
-                                     uint32_t layer_count,
-                                     const char* const* extension_names,
-                                     uint32_t extension_count) {
-    VkResult result = override_layers_.parse(layer_names, layer_count);
+VkResult LayerChain::ActivateLayers(const char* const* layer_names,
+                                    uint32_t layer_count,
+                                    const char* const* extension_names,
+                                    uint32_t extension_count) {
+    VkResult result = override_layers_.Parse(layer_names, layer_count);
     if (result != VK_SUCCESS)
         return result;
 
-    result = override_extensions_.parse(extension_names, extension_count);
+    result = override_extensions_.Parse(extension_names, extension_count);
     if (result != VK_SUCCESS)
         return result;
 
-    if (override_layers_.count()) {
-        layer_names = override_layers_.names();
-        layer_count = override_layers_.count();
+    if (override_layers_.Count()) {
+        layer_names = override_layers_.Names();
+        layer_count = override_layers_.Count();
     }
 
     if (!layer_count) {
@@ -491,13 +505,13 @@
         return VK_SUCCESS;
     }
 
-    layers_ = allocate_layer_array(layer_count);
+    layers_ = AllocateLayerArray(layer_count);
     if (!layers_)
         return VK_ERROR_OUT_OF_HOST_MEMORY;
 
     // load layers
     for (uint32_t i = 0; i < layer_count; i++) {
-        result = load_layer(layers_[i], layer_names[i]);
+        result = LoadLayer(layers_[i], layer_names[i]);
         if (result != VK_SUCCESS)
             return result;
 
@@ -505,13 +519,12 @@
         layer_count_++;
     }
 
-    setup_layer_links();
+    SetupLayerLinks();
 
     return VK_SUCCESS;
 }
 
-LayerChain::ActiveLayer* LayerChain::allocate_layer_array(
-    uint32_t count) const {
+LayerChain::ActiveLayer* LayerChain::AllocateLayerArray(uint32_t count) const {
     VkSystemAllocationScope scope = (is_instance_)
                                         ? VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE
                                         : VK_SYSTEM_ALLOCATION_SCOPE_DEVICE;
@@ -521,7 +534,7 @@
         scope));
 }
 
-VkResult LayerChain::load_layer(ActiveLayer& layer, const char* name) {
+VkResult LayerChain::LoadLayer(ActiveLayer& layer, const char* name) {
     if (is_instance_)
         new (&layer) ActiveLayer{GetInstanceLayerRef(name), {}};
     else
@@ -538,7 +551,7 @@
     return VK_SUCCESS;
 }
 
-void LayerChain::setup_layer_links() {
+void LayerChain::SetupLayerLinks() {
     if (is_instance_) {
         for (uint32_t i = 0; i < layer_count_; i++) {
             ActiveLayer& layer = layers_[i];
@@ -596,12 +609,12 @@
     }
 }
 
-bool LayerChain::empty() const {
-    return (!layer_count_ && !override_layers_.count() &&
-            !override_extensions_.count());
+bool LayerChain::Empty() const {
+    return (!layer_count_ && !override_layers_.Count() &&
+            !override_extensions_.Count());
 }
 
-void LayerChain::modify_create_info(VkInstanceCreateInfo& info) {
+void LayerChain::ModifyCreateInfo(VkInstanceCreateInfo& info) {
     if (layer_count_) {
         const ActiveLayer& layer = layers_[0];
 
@@ -617,18 +630,18 @@
         info.pNext = &instance_chain_info_;
     }
 
-    if (override_layers_.count()) {
-        info.enabledLayerCount = override_layers_.count();
-        info.ppEnabledLayerNames = override_layers_.names();
+    if (override_layers_.Count()) {
+        info.enabledLayerCount = override_layers_.Count();
+        info.ppEnabledLayerNames = override_layers_.Names();
     }
 
-    if (override_extensions_.count()) {
-        info.enabledExtensionCount = override_extensions_.count();
-        info.ppEnabledExtensionNames = override_extensions_.names();
+    if (override_extensions_.Count()) {
+        info.enabledExtensionCount = override_extensions_.Count();
+        info.ppEnabledExtensionNames = override_extensions_.Names();
     }
 }
 
-void LayerChain::modify_create_info(VkDeviceCreateInfo& info) {
+void LayerChain::ModifyCreateInfo(VkDeviceCreateInfo& info) {
     if (layer_count_) {
         const ActiveLayer& layer = layers_[0];
 
@@ -643,26 +656,31 @@
         info.pNext = &device_chain_info_;
     }
 
-    if (override_layers_.count()) {
-        info.enabledLayerCount = override_layers_.count();
-        info.ppEnabledLayerNames = override_layers_.names();
+    if (override_layers_.Count()) {
+        info.enabledLayerCount = override_layers_.Count();
+        info.ppEnabledLayerNames = override_layers_.Names();
     }
 
-    if (override_extensions_.count()) {
-        info.enabledExtensionCount = override_extensions_.count();
-        info.ppEnabledExtensionNames = override_extensions_.names();
+    if (override_extensions_.Count()) {
+        info.enabledExtensionCount = override_extensions_.Count();
+        info.ppEnabledExtensionNames = override_extensions_.Names();
     }
 }
 
-VkResult LayerChain::create(const VkInstanceCreateInfo* create_info,
+VkResult LayerChain::Create(const VkInstanceCreateInfo* create_info,
                             const VkAllocationCallbacks* allocator,
                             VkInstance* instance_out) {
+    VkResult result = ValidateExtensions(create_info->ppEnabledExtensionNames,
+                                         create_info->enabledExtensionCount);
+    if (result != VK_SUCCESS)
+        return result;
+
     // call down the chain
     PFN_vkCreateInstance create_instance =
         reinterpret_cast<PFN_vkCreateInstance>(
             get_instance_proc_addr_(VK_NULL_HANDLE, "vkCreateInstance"));
     VkInstance instance;
-    VkResult result = create_instance(create_info, allocator, &instance);
+    result = create_instance(create_info, allocator, &instance);
     if (result != VK_SUCCESS)
         return result;
 
@@ -680,7 +698,7 @@
     }
 
     // install debug report callback
-    if (override_extensions_.install_debug_callback()) {
+    if (override_extensions_.InstallDebugCallback()) {
         PFN_vkCreateDebugReportCallbackEXT create_debug_report_callback =
             reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(
                 get_instance_proc_addr_(instance,
@@ -700,7 +718,7 @@
             VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
         debug_callback_info.flags =
             VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
-        debug_callback_info.pfnCallback = debug_report_callback;
+        debug_callback_info.pfnCallback = DebugReportCallback;
 
         VkDebugReportCallbackEXT debug_callback;
         result = create_debug_report_callback(instance, &debug_callback_info,
@@ -716,17 +734,23 @@
         ALOGI("Installed debug report callback");
     }
 
-    steal_layers(data);
+    StealLayers(data);
 
     *instance_out = instance;
 
     return VK_SUCCESS;
 }
 
-VkResult LayerChain::create(VkPhysicalDevice physical_dev,
+VkResult LayerChain::Create(VkPhysicalDevice physical_dev,
                             const VkDeviceCreateInfo* create_info,
                             const VkAllocationCallbacks* allocator,
                             VkDevice* dev_out) {
+    VkResult result =
+        ValidateExtensions(physical_dev, create_info->ppEnabledExtensionNames,
+                           create_info->enabledExtensionCount);
+    if (result != VK_SUCCESS)
+        return result;
+
     // call down the chain
     //
     // TODO Instance call chain available at
@@ -736,7 +760,7 @@
     PFN_vkCreateDevice create_device = reinterpret_cast<PFN_vkCreateDevice>(
         get_instance_proc_addr_(instance, "vkCreateDevice"));
     VkDevice dev;
-    VkResult result = create_device(physical_dev, create_info, allocator, &dev);
+    result = create_device(physical_dev, create_info, allocator, &dev);
     if (result != VK_SUCCESS)
         return result;
 
@@ -751,15 +775,105 @@
         return VK_ERROR_INITIALIZATION_FAILED;
     }
 
-    steal_layers(data);
+    StealLayers(data);
 
     *dev_out = dev;
 
     return VK_SUCCESS;
 }
 
+VkResult LayerChain::ValidateExtensions(const char* const* extension_names,
+                                        uint32_t extension_count) {
+    if (!extension_count)
+        return VK_SUCCESS;
+
+    // query driver instance extensions
+    uint32_t count;
+    VkResult result =
+        EnumerateInstanceExtensionProperties(nullptr, &count, nullptr);
+    if (result == VK_SUCCESS && count) {
+        driver_extensions_ = AllocateDriverExtensionArray(count);
+        result = (driver_extensions_) ? EnumerateInstanceExtensionProperties(
+                                            nullptr, &count, driver_extensions_)
+                                      : VK_ERROR_OUT_OF_HOST_MEMORY;
+    }
+    if (result != VK_SUCCESS)
+        return result;
+
+    driver_extension_count_ = count;
+
+    for (uint32_t i = 0; i < extension_count; i++) {
+        const char* name = extension_names[i];
+        if (!IsLayerExtension(name) && !IsDriverExtension(name)) {
+            ALOGE("Failed to enable missing instance extension %s", name);
+            return VK_ERROR_EXTENSION_NOT_PRESENT;
+        }
+    }
+
+    return VK_SUCCESS;
+}
+
+VkResult LayerChain::ValidateExtensions(VkPhysicalDevice physical_dev,
+                                        const char* const* extension_names,
+                                        uint32_t extension_count) {
+    if (!extension_count)
+        return VK_SUCCESS;
+
+    // query driver device extensions
+    uint32_t count;
+    VkResult result = EnumerateDeviceExtensionProperties(physical_dev, nullptr,
+                                                         &count, nullptr);
+    if (result == VK_SUCCESS && count) {
+        driver_extensions_ = AllocateDriverExtensionArray(count);
+        result = (driver_extensions_)
+                     ? EnumerateDeviceExtensionProperties(
+                           physical_dev, nullptr, &count, driver_extensions_)
+                     : VK_ERROR_OUT_OF_HOST_MEMORY;
+    }
+    if (result != VK_SUCCESS)
+        return result;
+
+    driver_extension_count_ = count;
+
+    for (uint32_t i = 0; i < extension_count; i++) {
+        const char* name = extension_names[i];
+        if (!IsLayerExtension(name) && !IsDriverExtension(name)) {
+            ALOGE("Failed to enable missing device extension %s", name);
+            return VK_ERROR_EXTENSION_NOT_PRESENT;
+        }
+    }
+
+    return VK_SUCCESS;
+}
+
+VkExtensionProperties* LayerChain::AllocateDriverExtensionArray(
+    uint32_t count) const {
+    return reinterpret_cast<VkExtensionProperties*>(allocator_.pfnAllocation(
+        allocator_.pUserData, sizeof(VkExtensionProperties) * count,
+        alignof(VkExtensionProperties), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
+}
+
+bool LayerChain::IsLayerExtension(const char* name) const {
+    for (uint32_t i = 0; i < layer_count_; i++) {
+        const ActiveLayer& layer = layers_[i];
+        if (layer.ref.SupportsExtension(name))
+            return true;
+    }
+
+    return false;
+}
+
+bool LayerChain::IsDriverExtension(const char* name) const {
+    for (uint32_t i = 0; i < driver_extension_count_; i++) {
+        if (strcmp(driver_extensions_[i].extensionName, name) == 0)
+            return true;
+    }
+
+    return false;
+}
+
 template <typename DataType>
-void LayerChain::steal_layers(DataType& data) {
+void LayerChain::StealLayers(DataType& data) {
     data.layers = layers_;
     data.layer_count = layer_count_;
 
@@ -767,23 +881,23 @@
     layer_count_ = 0;
 }
 
-void LayerChain::destroy_layers(ActiveLayer* layers,
-                                uint32_t count,
-                                const VkAllocationCallbacks& allocator) {
+void LayerChain::DestroyLayers(ActiveLayer* layers,
+                               uint32_t count,
+                               const VkAllocationCallbacks& allocator) {
     for (uint32_t i = 0; i < count; i++)
         layers[i].ref.~LayerRef();
 
     allocator.pfnFree(allocator.pUserData, layers);
 }
 
-VkBool32 LayerChain::debug_report_callback(VkDebugReportFlagsEXT flags,
-                                           VkDebugReportObjectTypeEXT obj_type,
-                                           uint64_t obj,
-                                           size_t location,
-                                           int32_t msg_code,
-                                           const char* layer_prefix,
-                                           const char* msg,
-                                           void* user_data) {
+VkBool32 LayerChain::DebugReportCallback(VkDebugReportFlagsEXT flags,
+                                         VkDebugReportObjectTypeEXT obj_type,
+                                         uint64_t obj,
+                                         size_t location,
+                                         int32_t msg_code,
+                                         const char* layer_prefix,
+                                         const char* msg,
+                                         void* user_data) {
     int prio;
 
     if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
@@ -808,58 +922,58 @@
     return false;
 }
 
-VkResult LayerChain::create_instance(const VkInstanceCreateInfo* create_info,
-                                     const VkAllocationCallbacks* allocator,
-                                     VkInstance* instance_out) {
+VkResult LayerChain::CreateInstance(const VkInstanceCreateInfo* create_info,
+                                    const VkAllocationCallbacks* allocator,
+                                    VkInstance* instance_out) {
     LayerChain chain(true,
                      (allocator) ? *allocator : driver::GetDefaultAllocator());
 
-    VkResult result = chain.activate_layers(
-        create_info->ppEnabledLayerNames, create_info->enabledLayerCount,
-        create_info->ppEnabledExtensionNames,
-        create_info->enabledExtensionCount);
+    VkResult result = chain.ActivateLayers(create_info->ppEnabledLayerNames,
+                                           create_info->enabledLayerCount,
+                                           create_info->ppEnabledExtensionNames,
+                                           create_info->enabledExtensionCount);
     if (result != VK_SUCCESS)
         return result;
 
     // use a local create info when the chain is not empty
     VkInstanceCreateInfo local_create_info;
-    if (!chain.empty()) {
+    if (!chain.Empty()) {
         local_create_info = *create_info;
-        chain.modify_create_info(local_create_info);
+        chain.ModifyCreateInfo(local_create_info);
         create_info = &local_create_info;
     }
 
-    return chain.create(create_info, allocator, instance_out);
+    return chain.Create(create_info, allocator, instance_out);
 }
 
-VkResult LayerChain::create_device(VkPhysicalDevice physical_dev,
-                                   const VkDeviceCreateInfo* create_info,
-                                   const VkAllocationCallbacks* allocator,
-                                   VkDevice* dev_out) {
+VkResult LayerChain::CreateDevice(VkPhysicalDevice physical_dev,
+                                  const VkDeviceCreateInfo* create_info,
+                                  const VkAllocationCallbacks* allocator,
+                                  VkDevice* dev_out) {
     LayerChain chain(false, (allocator)
                                 ? *allocator
                                 : driver::GetData(physical_dev).allocator);
 
-    VkResult result = chain.activate_layers(
-        create_info->ppEnabledLayerNames, create_info->enabledLayerCount,
-        create_info->ppEnabledExtensionNames,
-        create_info->enabledExtensionCount);
+    VkResult result = chain.ActivateLayers(create_info->ppEnabledLayerNames,
+                                           create_info->enabledLayerCount,
+                                           create_info->ppEnabledExtensionNames,
+                                           create_info->enabledExtensionCount);
     if (result != VK_SUCCESS)
         return result;
 
     // use a local create info when the chain is not empty
     VkDeviceCreateInfo local_create_info;
-    if (!chain.empty()) {
+    if (!chain.Empty()) {
         local_create_info = *create_info;
-        chain.modify_create_info(local_create_info);
+        chain.ModifyCreateInfo(local_create_info);
         create_info = &local_create_info;
     }
 
-    return chain.create(physical_dev, create_info, allocator, dev_out);
+    return chain.Create(physical_dev, create_info, allocator, dev_out);
 }
 
-void LayerChain::destroy_instance(VkInstance instance,
-                                  const VkAllocationCallbacks* allocator) {
+void LayerChain::DestroyInstance(VkInstance instance,
+                                 const VkAllocationCallbacks* allocator) {
     InstanceData& data = GetData(instance);
 
     if (data.debug_callback != VK_NULL_HANDLE)
@@ -875,12 +989,12 @@
     // this also destroys InstanceData
     data.dispatch.DestroyInstance(instance, allocator);
 
-    destroy_layers(layers, layer_count,
-                   (allocator) ? *allocator : local_allocator);
+    DestroyLayers(layers, layer_count,
+                  (allocator) ? *allocator : local_allocator);
 }
 
-void LayerChain::destroy_device(VkDevice device,
-                                const VkAllocationCallbacks* allocator) {
+void LayerChain::DestroyDevice(VkDevice device,
+                               const VkAllocationCallbacks* allocator) {
     DeviceData& data = GetData(device);
 
     ActiveLayer* layers = reinterpret_cast<ActiveLayer*>(data.layers);
@@ -893,8 +1007,8 @@
     // this also destroys DeviceData
     data.dispatch.DestroyDevice(device, allocator);
 
-    destroy_layers(layers, layer_count,
-                   (allocator) ? *allocator : local_allocator);
+    DestroyLayers(layers, layer_count,
+                  (allocator) ? *allocator : local_allocator);
 }
 
 // ----------------------------------------------------------------------------
@@ -921,26 +1035,26 @@
     if (!EnsureInitialized())
         return VK_ERROR_INITIALIZATION_FAILED;
 
-    return LayerChain::create_instance(pCreateInfo, pAllocator, pInstance);
+    return LayerChain::CreateInstance(pCreateInfo, pAllocator, pInstance);
 }
 
 void DestroyInstance(VkInstance instance,
                      const VkAllocationCallbacks* pAllocator) {
     if (instance != VK_NULL_HANDLE)
-        LayerChain::destroy_instance(instance, pAllocator);
+        LayerChain::DestroyInstance(instance, pAllocator);
 }
 
 VkResult CreateDevice(VkPhysicalDevice physicalDevice,
                       const VkDeviceCreateInfo* pCreateInfo,
                       const VkAllocationCallbacks* pAllocator,
                       VkDevice* pDevice) {
-    return LayerChain::create_device(physicalDevice, pCreateInfo, pAllocator,
-                                     pDevice);
+    return LayerChain::CreateDevice(physicalDevice, pCreateInfo, pAllocator,
+                                    pDevice);
 }
 
 void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) {
     if (device != VK_NULL_HANDLE)
-        LayerChain::destroy_device(device, pAllocator);
+        LayerChain::DestroyDevice(device, pAllocator);
 }
 
 VkResult EnumerateInstanceLayerProperties(uint32_t* pPropertyCount,
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index 0c4cd9a..a8cca59 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -272,11 +272,14 @@
         std::binary_search(
             known_non_device_names, known_non_device_names + count, pName,
             [](const char* a, const char* b) { return (strcmp(a, b) < 0); })) {
-        ALOGE("vkGetDeviceProcAddr called with %s", pName);
+        ALOGE("vkGetDeviceProcAddr called with %s", (pName) ? pName : "(null)");
         return nullptr;
     }
     // clang-format off
 
+    if (strcmp(pName, "vkGetDeviceProcAddr") == 0) return reinterpret_cast<PFN_vkVoidFunction>(vkGetDeviceProcAddr);
+    if (strcmp(pName, "vkDestroyDevice") == 0) return reinterpret_cast<PFN_vkVoidFunction>(vulkan::api::DestroyDevice);
+
     return vulkan::api::GetData(device).dispatch.GetDeviceProcAddr(device, pName);
 }
 
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index 7ebe983..7517e91 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -21,6 +21,8 @@
 {{Macro "DefineGlobals" $}}
 {{$ | Macro "api_gen.h"   | Format (Global "clang-format") | Write "api_gen.h"  }}
 {{$ | Macro "api_gen.cpp" | Format (Global "clang-format") | Write "api_gen.cpp"}}
+{{$ | Macro "driver_gen.h" | Format (Global "clang-format") | Write "driver_gen.h"}}
+{{$ | Macro "driver_gen.cpp" | Format (Global "clang-format") | Write "driver_gen.cpp"}}
 
 {{/*
 -------------------------------------------------------------------------------
@@ -44,7 +46,7 @@
   // clang-format off
   {{range $f := AllCommands $}}
     {{if (Macro "api.IsInstanceDispatchTableEntry" $f)}}
-      {{Macro "C++.DeclareDispatchTableEntry" $f}};
+      {{Macro "C++.DeclareTableEntry" $f}};
     {{end}}
   {{end}}
   // clang-format on
@@ -54,7 +56,7 @@
   // clang-format off
   {{range $f := AllCommands $}}
     {{if (Macro "api.IsDeviceDispatchTableEntry" $f)}}
-      {{Macro "C++.DeclareDispatchTableEntry" $f}};
+      {{Macro "C++.DeclareTableEntry" $f}};
     {{end}}
   {{end}}
   // clang-format on
@@ -89,7 +91,9 @@
 namespace vulkan {«
 namespace api {«

-{{Macro "C++.DefineInitProcMacros" "dispatch"}}
+{{Macro "C++.DefineInitProcMacro" "dispatch"}}

+{{Macro "api.C++.DefineInitProcExtMacro"}}

 bool InitDispatchTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc) {
     auto& data = GetData(instance);
@@ -147,11 +151,173 @@
 
 
 {{/*
+-------------------------------------------------------------------------------
+  driver_gen.h
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver_gen.h"}}
+{{Macro "Copyright"}}

+// WARNING: This file is generated. See ../README.md for instructions.

+#ifndef LIBVULKAN_DRIVER_GEN_H
+#define LIBVULKAN_DRIVER_GEN_H

+#include <vulkan/vulkan.h>
+#include <vulkan/vk_android_native_buffer.h>

+namespace vulkan {«
+namespace driver {«

+{{Macro "driver.C++.DefineProcHookType"}}

+struct InstanceDriverTable {
+  // clang-format off
+  {{range $f := AllCommands $}}
+    {{if (Macro "driver.IsInstanceDriverTableEntry" $f)}}
+      {{Macro "C++.DeclareTableEntry" $f}};
+    {{end}}
+  {{end}}
+  // clang-format on
+};

+struct DeviceDriverTable {
+  // clang-format off
+  {{range $f := AllCommands $}}
+    {{if (Macro "driver.IsDeviceDriverTableEntry" $f)}}
+      {{Macro "C++.DeclareTableEntry" $f}};
+    {{end}}
+  {{end}}
+  // clang-format on
+};

+const ProcHook* GetProcHook(const char* name);
+ProcHook::Extension GetProcHookExtension(const char* name);

+bool InitDriverTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc);
+bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc);

+»} // namespace driver
+»} // namespace vulkan

+#endif // LIBVULKAN_DRIVER_TABLE_H
+¶{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  driver_gen.cpp
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver_gen.cpp"}}
+{{Macro "Copyright"}}

+// WARNING: This file is generated. See ../README.md for instructions.

+#include <string.h>
+#include <algorithm>
+#include <log/log.h>

+#include "driver.h"

+namespace vulkan {«
+namespace driver {«

+namespace {«

+// clang-format off

+{{range $f := AllCommands $}}
+  {{Macro "driver.C++.DefineProcHookStubs" $f}}
+{{end}}
+// clang-format on

+const ProcHook g_proc_hooks[] = {
+  // clang-format off
+  {{range $f := SortBy (AllCommands $) "FunctionName"}}
+    {{if (Macro "driver.IsIntercepted" $f)}}
+      {{     if (Macro "IsGloballyDispatched" $f)}}
+        {{Macro "driver.C++.DefineGlobalProcHook" $f}}
+      {{else if (Macro "IsInstanceDispatched" $f)}}
+        {{Macro "driver.C++.DefineInstanceProcHook" $f}}
+      {{else if (Macro "IsDeviceDispatched" $f)}}
+        {{Macro "driver.C++.DefineDeviceProcHook" $f}}
+      {{end}}
+    {{end}}
+  {{end}}
+  // clang-format on
+};

+»} // anonymous

+const ProcHook* GetProcHook(const char* name) {
+    const auto& begin = g_proc_hooks;
+    const auto& end = g_proc_hooks +
+      sizeof(g_proc_hooks) / sizeof(g_proc_hooks[0]);
+    const auto hook = std::lower_bound(begin, end, name,
+        [](const ProcHook& e, const char* n) { return strcmp(e.name, n) < 0; });
+    return (hook <  end && strcmp(hook->name, name) == 0) ? hook : nullptr;
+}

+ProcHook::Extension GetProcHookExtension(const char* name) {
+  {{$exts := Strings (Macro "driver.InterceptedExtensions") | SplitOn "\n"}}
+  // clang-format off
+  {{range $e := $exts}}
+    if (strcmp(name, "{{$e}}") == 0) return ProcHook::{{TrimPrefix "VK_" $e}};
+  {{end}}
+  // clang-format on
+  return ProcHook::EXTENSION_UNKNOWN;
+}

+{{Macro "C++.DefineInitProcMacro" "driver"}}

+{{Macro "driver.C++.DefineInitProcExtMacro"}}

+bool InitDriverTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc)
+{
+    auto& data = GetData(instance);
+    bool success = true;
+    ¶
+    // clang-format off
+    {{range $f := AllCommands $}}
+      {{if (Macro "driver.IsInstanceDriverTableEntry" $f)}}
+        {{Macro "C++.InitProc" $f}}
+      {{end}}
+    {{end}}
+    // clang-format on
+    ¶
+    return success;
+}

+bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc)
+{
+    auto& data = GetData(dev);
+    bool success = true;
+    ¶
+    // clang-format off
+    {{range $f := AllCommands $}}
+      {{if (Macro "driver.IsDeviceDriverTableEntry" $f)}}
+        {{Macro "C++.InitProc" $f}}
+      {{end}}
+    {{end}}
+    // clang-format on
+    ¶
+    return success;
+}

+»} // namespace driver
+»} // namespace vulkan

+// clang-format on
+¶{{end}}
+
+
+{{/*
 ------------------------------------------------------------------------------
-  Emits a declaration of a dispatch table entry.
+  Emits a declaration of a dispatch/driver table entry.
 ------------------------------------------------------------------------------
 */}}
-{{define "C++.DeclareDispatchTableEntry"}}
+{{define "C++.DeclareTableEntry"}}
   {{AssertType $ "Function"}}
 
   {{Macro "FunctionPtrName" $}} {{Macro "BaseName" $}}
@@ -160,10 +326,10 @@
 
 {{/*
 -------------------------------------------------------------------------------
-  Emits macros to help initialize dispatch tables.
+  Emits INIT_PROC macro.
 -------------------------------------------------------------------------------
 */}}
-{{define "C++.DefineInitProcMacros"}}
+{{define "C++.DefineInitProcMacro"}}
   #define UNLIKELY(expr) __builtin_expect((expr), 0)

   #define INIT_PROC(obj, proc) do {                             \
@@ -174,11 +340,6 @@
           success = false;                                      \
       }                                                         \
   } while(0)
-  ¶
-  // TODO do we want to point to a stub or nullptr when ext is not enabled?
-  #define INIT_PROC_EXT(ext, obj, proc) do {                    \
-      INIT_PROC(obj, proc);                                     \
-  } while(0)
 {{end}}
 
 
@@ -262,6 +423,19 @@
 
 
 {{/*
+-------------------------------------------------------------------------------
+  Emits INIT_PROC_EXT macro for vulkan::api.
+-------------------------------------------------------------------------------
+*/}}
+{{define "api.C++.DefineInitProcExtMacro"}}
+  // TODO do we want to point to a stub or nullptr when ext is not enabled?
+  #define INIT_PROC_EXT(ext, obj, proc) do {                    \
+      INIT_PROC(obj, proc);                                     \
+  } while(0)
+{{end}}
+
+
+{{/*
 ------------------------------------------------------------------------------
   Emits code for vkGetInstanceProcAddr for function interception.
 ------------------------------------------------------------------------------
@@ -355,11 +529,25 @@
       std::binary_search(
         known_non_device_names, known_non_device_names + count, pName,
         [](const char* a, const char* b) { return (strcmp(a, b) < 0); })) {
-    ALOGE("vkGetDeviceProcAddr called with %s", pName);
+    ALOGE("vkGetDeviceProcAddr called with %s", (pName) ? pName : "(null)");
     return nullptr;
   }
   // clang-format off

+  {{range $f := AllCommands $}}
+    {{if (Macro "IsDeviceDispatched" $f)}}
+      {{     if (Macro "api.IsIntercepted" $f)}}
+        if (strcmp(pName, "{{$f.Name}}") == 0) return §
+          reinterpret_cast<PFN_vkVoidFunction>(§
+            vulkan::api::{{Macro "BaseName" $f}});
+      {{else if eq $f.Name "vkGetDeviceProcAddr"}}
+        if (strcmp(pName, "{{$f.Name}}") == 0) return §
+          reinterpret_cast<PFN_vkVoidFunction>(§
+            {{$f.Name}});
+      {{end}}
+    {{end}}
+  {{end}}
+  ¶
 {{end}}
 
 
@@ -386,6 +574,348 @@
 
 
 {{/*
+------------------------------------------------------------------------------
+  Emits a list of extensions intercepted by vulkan::driver.
+------------------------------------------------------------------------------
+*/}}
+{{define "driver.InterceptedExtensions"}}
+VK_ANDROID_native_buffer
+VK_EXT_debug_report
+VK_KHR_android_surface
+VK_KHR_surface
+VK_KHR_swapchain
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+  Emits true if an extension is intercepted by vulkan::driver.
+------------------------------------------------------------------------------
+*/}}
+{{define "driver.IsExtensionIntercepted"}}
+  {{$ext_name := index $.Arguments 0}}
+  {{$filters := Strings (Macro "driver.InterceptedExtensions") | SplitOn "\n"}}
+
+  {{range $f := $filters}}
+    {{if eq $ext_name $f}}true{{end}}
+  {{end}}
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+  Emits true if a function is intercepted by vulkan::driver.
+------------------------------------------------------------------------------
+*/}}
+{{define "driver.IsIntercepted"}}
+  {{AssertType $ "Function"}}
+
+  {{if (Macro "IsFunctionSupported" $)}}
+    {{/* Create functions of dispatchable objects */}}
+    {{     if eq $.Name "vkCreateInstance"}}true
+    {{else if eq $.Name "vkCreateDevice"}}true
+    {{else if eq $.Name "vkEnumeratePhysicalDevices"}}true
+    {{else if eq $.Name "vkGetDeviceQueue"}}true
+    {{else if eq $.Name "vkAllocateCommandBuffers"}}true
+
+    {{/* Destroy functions of dispatchable objects */}}
+    {{else if eq $.Name "vkDestroyInstance"}}true
+    {{else if eq $.Name "vkDestroyDevice"}}true
+
+    {{/* Enumeration of extensions */}}
+    {{else if eq $.Name "vkEnumerateInstanceExtensionProperties"}}true
+    {{else if eq $.Name "vkEnumerateDeviceExtensionProperties"}}true
+
+    {{else if eq $.Name "vkGetInstanceProcAddr"}}true
+    {{else if eq $.Name "vkGetDeviceProcAddr"}}true
+
+    {{end}}
+
+    {{$ext := GetAnnotation $ "extension"}}
+    {{if $ext}}
+      {{Macro "driver.IsExtensionIntercepted" $ext}}
+    {{end}}
+
+  {{end}}
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+  Emits true if a function needs ProcHook stubs.
+------------------------------------------------------------------------------
+*/}}
+{{define "driver.NeedProcHookStubs"}}
+  {{AssertType $ "Function"}}
+
+  {{if (Macro "driver.IsIntercepted" $)}}
+    {{$ext := GetAnnotation $ "extension"}}
+    {{if $ext}}
+      {{if not (Macro "IsExtensionInternal" $ext)}}true{{end}}
+    {{end}}
+  {{end}}
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  Emits definition of struct ProcHook.
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver.C++.DefineProcHookType"}}
+  struct ProcHook {
+      enum Type {
+        GLOBAL,
+        INSTANCE,
+        DEVICE,
+      };
+
+      enum Extension {
+        {{$exts := Strings (Macro "driver.InterceptedExtensions") | SplitOn "\n"}}
+        {{range $e := $exts}}
+          {{TrimPrefix "VK_" $e}},
+        {{end}}
+        ¶
+        EXTENSION_CORE, // valid bit
+        EXTENSION_COUNT,
+        EXTENSION_UNKNOWN,
+      };
+      ¶
+      const char* name;
+      Type type;
+      Extension extension;
+      ¶
+      PFN_vkVoidFunction proc;
+      PFN_vkVoidFunction disabled_proc; // nullptr for global hooks
+      PFN_vkVoidFunction checked_proc;  // nullptr for global/instance hooks
+  };
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  Emits INIT_PROC_EXT macro for vulkan::driver.
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver.C++.DefineInitProcExtMacro"}}
+  #define INIT_PROC_EXT(ext, obj, proc) do {                    \
+      if (data.hal_extensions[ProcHook::ext])           \
+        INIT_PROC(obj, proc);                                   \
+  } while(0)
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  Emits definitions of stub functions for ProcHook.
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver.C++.DefineProcHookStubs"}}
+  {{AssertType $ "Function"}}
+
+  {{if (Macro "driver.NeedProcHookStubs" $)}}
+    {{$ext := GetAnnotation $ "extension"}}
+    {{$ext_name := index $ext.Arguments 0}}
+
+    {{$base := (Macro "BaseName" $)}}
+    {{$unnamed_params := (ForEach $.CallParameters "ParameterType" | JoinWith ", ")}}
+
+    VKAPI_ATTR {{Node "Type" $.Return}} disabled{{$base}}({{$unnamed_params}}) {
+      ALOGE("{{$ext_name}} not enabled. {{$.Name}} not executed.");
+      {{if not (IsVoid $.Return.Type)}}return VK_SUCCESS;{{end}}
+    }
+    {{if (Macro "IsDeviceDispatched" $)}}
+      ¶
+      VKAPI_ATTR {{Node "Type" $.Return}} checked{{$base}}({{Macro "Parameters" $}}) {
+        {{if not (IsVoid $.Return.Type)}}return §{{end}}
+
+        {{$p0 := index $.CallParameters 0}}
+        {{$ext_hook := Strings ("ProcHook::") (Macro "BaseName" $ext)}}
+        (GetData({{$p0.Name}}).hook_extensions[{{$ext_hook}}]) ? §
+          {{$base}}({{Macro "Arguments" $}}) : §
+          disabled{{$base}}({{Macro "Arguments" $}});
+      }
+    {{end}}
+    ¶
+  {{end}}
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  Emits definition of a global ProcHook.
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver.C++.DefineGlobalProcHook"}}
+  {{AssertType $ "Function"}}
+
+  {{$base := (Macro "BaseName" $)}}
+
+  {{$ext := GetAnnotation $ "extension"}}
+  {{if $ext}}
+    {{Error "invalid global extension"}}
+  {{end}}
+
+  {
+    "{{$.Name}}",
+    ProcHook::GLOBAL,
+    ProcHook::EXTENSION_CORE,
+    reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
+    nullptr,
+    nullptr,
+  },
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  Emits definition of an instance ProcHook.
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver.C++.DefineInstanceProcHook"}}
+  {{AssertType $ "Function"}}
+
+  {{$base := (Macro "BaseName" $)}}
+
+  {
+    "{{$.Name}}",
+    ProcHook::INSTANCE,
+
+    {{$ext := GetAnnotation $ "extension"}}
+    {{if $ext}}
+      ProcHook::{{Macro "BaseName" $ext}},
+
+      {{if (Macro "IsExtensionInternal" $ext)}}
+        nullptr,
+        nullptr,
+        nullptr,
+      {{else}}
+        reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
+        reinterpret_cast<PFN_vkVoidFunction>(disabled{{$base}}),
+        nullptr,
+      {{end}}
+    {{else}}
+      ProcHook::EXTENSION_CORE,
+      reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
+      nullptr,
+      nullptr,
+    {{end}}
+  },
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  Emits definition of a device ProcHook.
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver.C++.DefineDeviceProcHook"}}
+  {{AssertType $ "Function"}}
+
+  {{$base := (Macro "BaseName" $)}}
+
+  {
+    "{{$.Name}}",
+    ProcHook::DEVICE,
+
+    {{$ext := GetAnnotation $ "extension"}}
+    {{if $ext}}
+      ProcHook::{{Macro "BaseName" $ext}},
+
+      {{if (Macro "IsExtensionInternal" $ext)}}
+        nullptr,
+        nullptr,
+        nullptr,
+      {{else}}
+        reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
+        reinterpret_cast<PFN_vkVoidFunction>(disabled{{$base}}),
+        reinterpret_cast<PFN_vkVoidFunction>(checked{{$base}}),
+      {{end}}
+    {{else}}
+      ProcHook::EXTENSION_CORE,
+      reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
+      nullptr,
+      nullptr,
+    {{end}}
+  },
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  Emits true if a function is needed by vulkan::driver.
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver.IsDriverTableEntry"}}
+  {{AssertType $ "Function"}}
+
+  {{if (Macro "IsFunctionSupported" $)}}
+    {{/* Create functions of dispatchable objects */}}
+    {{     if eq $.Name "vkCreateDevice"}}true
+    {{else if eq $.Name "vkGetDeviceQueue"}}true
+    {{else if eq $.Name "vkAllocateCommandBuffers"}}true
+
+    {{/* Destroy functions of dispatchable objects */}}
+    {{else if eq $.Name "vkDestroyInstance"}}true
+    {{else if eq $.Name "vkDestroyDevice"}}true
+
+    {{else if eq $.Name "vkEnumerateDeviceLayerProperties"}}true
+
+    {{/* Enumeration of extensions */}}
+    {{else if eq $.Name "vkEnumerateDeviceExtensionProperties"}}true
+
+    {{/* We cache physical devices in loader.cpp */}}
+    {{else if eq $.Name "vkEnumeratePhysicalDevices"}}true
+
+    {{else if eq $.Name "vkGetInstanceProcAddr"}}true
+    {{else if eq $.Name "vkGetDeviceProcAddr"}}true
+
+    {{/* VK_KHR_swapchain->VK_ANDROID_native_buffer translation */}}
+    {{else if eq $.Name "vkCreateImage"}}true
+    {{else if eq $.Name "vkDestroyImage"}}true
+
+    {{end}}
+
+    {{$ext := GetAnnotation $ "extension"}}
+    {{if $ext}}
+      {{$ext_name := index $ext.Arguments 0}}
+      {{     if eq $ext_name "VK_ANDROID_native_buffer"}}true
+      {{else if eq $ext_name "VK_EXT_debug_report"}}true
+      {{end}}
+    {{end}}
+  {{end}}
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+  Emits true if an instance-dispatched function is needed by vulkan::driver.
+------------------------------------------------------------------------------
+*/}}
+{{define "driver.IsInstanceDriverTableEntry"}}
+  {{AssertType $ "Function"}}
+
+  {{if and (Macro "driver.IsDriverTableEntry" $) (Macro "IsInstanceDispatched" $)}}
+    true
+  {{end}}
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+  Emits true if a device-dispatched function is needed by vulkan::driver.
+------------------------------------------------------------------------------
+*/}}
+{{define "driver.IsDeviceDriverTableEntry"}}
+  {{AssertType $ "Function"}}
+
+  {{if and (Macro "driver.IsDriverTableEntry" $) (Macro "IsDeviceDispatched" $)}}
+    true
+  {{end}}
+{{end}}
+
+
+{{/*
 -------------------------------------------------------------------------------
   Emits a function/extension name without the "vk"/"VK_" prefix.
 -------------------------------------------------------------------------------
@@ -517,3 +1047,16 @@
   {{else if eq $ext "VK_KHR_android_surface"}}true
   {{end}}
 {{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+  Reports whether an extension is internal to the loader and drivers,
+  so the loader should not enumerate it.
+------------------------------------------------------------------------------
+*/}}
+{{define "IsExtensionInternal"}}
+  {{$ext := index $.Arguments 0}}
+  {{     if eq $ext "VK_ANDROID_native_buffer"}}true
+  {{end}}
+{{end}}
diff --git a/vulkan/libvulkan/debug_report.cpp b/vulkan/libvulkan/debug_report.cpp
index 41b6040..c4a1174 100644
--- a/vulkan/libvulkan/debug_report.cpp
+++ b/vulkan/libvulkan/debug_report.cpp
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-#include "loader.h"
+#include "driver.h"
 
 namespace vulkan {
+namespace driver {
 
 VkResult DebugReportCallbackList::CreateCallback(
     VkInstance instance,
@@ -25,24 +26,22 @@
     VkDebugReportCallbackEXT* callback) {
     VkDebugReportCallbackEXT driver_callback = VK_NULL_HANDLE;
 
-    if (GetDriverDispatch(instance).CreateDebugReportCallbackEXT) {
-        VkResult result =
-            GetDriverDispatch(instance).CreateDebugReportCallbackEXT(
-                GetDriverInstance(instance), create_info, allocator,
-                &driver_callback);
+    if (GetData(instance).driver.CreateDebugReportCallbackEXT) {
+        VkResult result = GetData(instance).driver.CreateDebugReportCallbackEXT(
+            instance, create_info, allocator, &driver_callback);
         if (result != VK_SUCCESS)
             return result;
     }
 
     const VkAllocationCallbacks* alloc =
-        allocator ? allocator : GetAllocator(instance);
+        allocator ? allocator : &GetData(instance).allocator;
     void* mem =
         alloc->pfnAllocation(alloc->pUserData, sizeof(Node), alignof(Node),
                              VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
     if (!mem) {
-        if (GetDriverDispatch(instance).DestroyDebugReportCallbackEXT) {
-            GetDriverDispatch(instance).DestroyDebugReportCallbackEXT(
-                GetDriverInstance(instance), driver_callback, allocator);
+        if (GetData(instance).driver.DestroyDebugReportCallbackEXT) {
+            GetData(instance).driver.DestroyDebugReportCallbackEXT(
+                instance, driver_callback, allocator);
         }
         return VK_ERROR_OUT_OF_HOST_MEMORY;
     }
@@ -68,13 +67,13 @@
     prev->next = node->next;
     lock.unlock();
 
-    if (GetDriverDispatch(instance).DestroyDebugReportCallbackEXT) {
-        GetDriverDispatch(instance).DestroyDebugReportCallbackEXT(
-            GetDriverInstance(instance), node->driver_callback, allocator);
+    if (GetData(instance).driver.DestroyDebugReportCallbackEXT) {
+        GetData(instance).driver.DestroyDebugReportCallbackEXT(
+            instance, node->driver_callback, allocator);
     }
 
     const VkAllocationCallbacks* alloc =
-        allocator ? allocator : GetAllocator(instance);
+        allocator ? allocator : &GetData(instance).allocator;
     alloc->pfnFree(alloc->pUserData, node);
 }
 
@@ -95,40 +94,40 @@
     }
 }
 
-VkResult CreateDebugReportCallbackEXT_Bottom(
+VkResult CreateDebugReportCallbackEXT(
     VkInstance instance,
     const VkDebugReportCallbackCreateInfoEXT* create_info,
     const VkAllocationCallbacks* allocator,
     VkDebugReportCallbackEXT* callback) {
-    return GetDebugReportCallbacks(instance).CreateCallback(
+    return GetData(instance).debug_report_callbacks.CreateCallback(
         instance, create_info, allocator, callback);
 }
 
-void DestroyDebugReportCallbackEXT_Bottom(
-    VkInstance instance,
-    VkDebugReportCallbackEXT callback,
-    const VkAllocationCallbacks* allocator) {
+void DestroyDebugReportCallbackEXT(VkInstance instance,
+                                   VkDebugReportCallbackEXT callback,
+                                   const VkAllocationCallbacks* allocator) {
     if (callback)
-        GetDebugReportCallbacks(instance).DestroyCallback(instance, callback,
-                                                          allocator);
+        GetData(instance).debug_report_callbacks.DestroyCallback(
+            instance, callback, allocator);
 }
 
-void DebugReportMessageEXT_Bottom(VkInstance instance,
-                                  VkDebugReportFlagsEXT flags,
-                                  VkDebugReportObjectTypeEXT object_type,
-                                  uint64_t object,
-                                  size_t location,
-                                  int32_t message_code,
-                                  const char* layer_prefix,
-                                  const char* message) {
-    if (GetDriverDispatch(instance).DebugReportMessageEXT) {
-        GetDriverDispatch(instance).DebugReportMessageEXT(
-            GetDriverInstance(instance), flags, object_type, object, location,
-            message_code, layer_prefix, message);
+void DebugReportMessageEXT(VkInstance instance,
+                           VkDebugReportFlagsEXT flags,
+                           VkDebugReportObjectTypeEXT object_type,
+                           uint64_t object,
+                           size_t location,
+                           int32_t message_code,
+                           const char* layer_prefix,
+                           const char* message) {
+    if (GetData(instance).driver.DebugReportMessageEXT) {
+        GetData(instance).driver.DebugReportMessageEXT(
+            instance, flags, object_type, object, location, message_code,
+            layer_prefix, message);
     }
-    GetDebugReportCallbacks(instance).Message(flags, object_type, object,
-                                              location, message_code,
-                                              layer_prefix, message);
+    GetData(instance).debug_report_callbacks.Message(flags, object_type, object,
+                                                     location, message_code,
+                                                     layer_prefix, message);
 }
 
+}  // namespace driver
 }  // namespace vulkan
diff --git a/vulkan/libvulkan/debug_report.h b/vulkan/libvulkan/debug_report.h
index c6f7570..72b1887 100644
--- a/vulkan/libvulkan/debug_report.h
+++ b/vulkan/libvulkan/debug_report.h
@@ -17,14 +17,16 @@
 #ifndef LIBVULKAN_DEBUG_REPORT_H
 #define LIBVULKAN_DEBUG_REPORT_H 1
 
+#include <vulkan/vulkan.h>
 #include <shared_mutex>
 
 namespace vulkan {
+namespace driver {
 
 // clang-format off
-VKAPI_ATTR VkResult CreateDebugReportCallbackEXT_Bottom(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback);
-VKAPI_ATTR void DestroyDebugReportCallbackEXT_Bottom(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator);
-VKAPI_ATTR void DebugReportMessageEXT_Bottom(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage);
+VKAPI_ATTR VkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback);
+VKAPI_ATTR void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator);
+VKAPI_ATTR void DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage);
 // clang-format on
 
 class DebugReportCallbackList {
@@ -65,6 +67,7 @@
     Node head_;
 };
 
+}  // namespace driver
 }  // namespace vulkan
 
 #endif  // LIBVULKAN_DEBUG_REPORT_H
diff --git a/vulkan/libvulkan/dispatch.tmpl b/vulkan/libvulkan/dispatch.tmpl
deleted file mode 100644
index 67ead4a..0000000
--- a/vulkan/libvulkan/dispatch.tmpl
+++ /dev/null
@@ -1,365 +0,0 @@
-{{/*
- * Copyright 2015 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.
- */}}
-
-{{Include "../api/templates/vulkan_common.tmpl"}}
-{{Global "clang-format" (Strings "clang-format" "-style=file")}}
-{{Macro "DefineGlobals" $}}
-{{$ | Macro "dispatch_gen.h"   | Format (Global "clang-format") | Write "dispatch_gen.h"  }}
-{{$ | Macro "dispatch_gen.cpp" | Format (Global "clang-format") | Write "dispatch_gen.cpp"}}
-
-{{/*
--------------------------------------------------------------------------------
-  dispatch_gen.h
--------------------------------------------------------------------------------
-*/}}
-{{define "dispatch_gen.h"}}
-/*
-•* Copyright 2015 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.
-•*/

-// WARNING: This file is generated. See ../README.md for instructions.

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

-namespace vulkan {

-struct DriverDispatchTable {«
-  // clang-format off
-  {{range $f := AllCommands $}}
-    {{if (Macro "IsInstanceDispatched" $f)}}
-      {{if not (Macro "IsLoaderFunction" $f)}}
-        {{Macro "FunctionPtrName" $f}} {{Macro "BaseName" $f}};
-      {{end}}
-    {{end}}
-  {{end}}
-
-    PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
-
-    PFN_vkDestroyDevice DestroyDevice;
-    PFN_vkGetDeviceQueue GetDeviceQueue;
-    PFN_vkAllocateCommandBuffers AllocateCommandBuffers;
-
-    {{/* TODO(jessehall): Needed by swapchain code. Figure out a better way of
-         handling this that avoids the special case. Probably should rework
-         things so the driver dispatch table has all driver functions. Probably
-         need separate instance- and device-level copies, fill in all device-
-         dispatched functions in the device-level copies only, and change
-         GetDeviceProcAddr_Bottom to look in the already-loaded driver
-         dispatch table rather than forwarding to the driver's
-         vkGetDeviceProcAddr. */}}
-    PFN_vkCreateImage CreateImage;
-    PFN_vkDestroyImage DestroyImage;
-
-    PFN_vkGetSwapchainGrallocUsageANDROID GetSwapchainGrallocUsageANDROID;
-    PFN_vkAcquireImageANDROID AcquireImageANDROID;
-    PFN_vkQueueSignalReleaseImageANDROID QueueSignalReleaseImageANDROID;
-  // clang-format on
-»};

-} // namespace vulkan
-¶{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
-  dispatch_gen.cpp
--------------------------------------------------------------------------------
-*/}}
-{{define "dispatch_gen.cpp"}}
-/*
-•* Copyright 2015 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.
-•*/

-// WARNING: This file is generated. See ../README.md for instructions.

-#include <log/log.h>
-#include <algorithm>
-#include "loader.h"

-#define UNLIKELY(expr) __builtin_expect((expr), 0)

-using namespace vulkan;

-namespace {

-struct NameProc {
-    const char* name;
-    PFN_vkVoidFunction proc;
-};

-PFN_vkVoidFunction Lookup(const char* name, const NameProc* begin, const NameProc* end) {
-    const auto& entry = std::lower_bound(
-        begin, end, name,
-        [](const NameProc& e, const char* n) { return strcmp(e.name, n) < 0; });
-    if (entry == end || strcmp(entry->name, name) != 0)
-        return nullptr;
-    return entry->proc;
-}

-template <size_t N>
-PFN_vkVoidFunction Lookup(const char* name, const NameProc (&procs)[N]) {
-    return Lookup(name, procs, procs + N);
-}

-const NameProc kLoaderBottomProcs[] = {«
-    // clang-format off
-  {{range $f := SortBy (AllCommands $) "FunctionName"}}
-    {{if (Macro "HasLoaderBottomImpl" $f)}}
-    {"{{$f.Name}}", reinterpret_cast<PFN_vkVoidFunction>(§
-        static_cast<{{Macro "FunctionPtrName" $f}}>(§
-            {{Macro "BaseName" $f}}_Bottom))},
-    {{end}}
-  {{end}}
-    // clang-format on
-»};

-} // anonymous namespace

-namespace vulkan {

-PFN_vkVoidFunction GetLoaderBottomProcAddr(const char* name) {
-    return Lookup(name, kLoaderBottomProcs);
-}

-bool LoadDriverDispatchTable(VkInstance instance,
-                             PFN_vkGetInstanceProcAddr get_proc_addr,
-                             const InstanceExtensionSet& extensions,
-                             DriverDispatchTable& dispatch) {«
-    bool success = true;
-    // clang-format off
-  {{range $f := AllCommands $}}
-    {{if (Macro "IsInstanceDispatched" $f)}}
-      {{if not (Macro "IsLoaderFunction" $f)}}
-        {{$ext := GetAnnotation $f "extension"}}
-          {{if $ext}}
-    if (extensions[{{Macro "ExtensionConstant" $ext}}]) {
-          {{end}}
-        dispatch.{{Macro "BaseName" $f}} = §
-            reinterpret_cast<{{Macro "FunctionPtrName" $f}}>(§
-                get_proc_addr(instance, "{{$f.Name}}"));
-        if (UNLIKELY(!dispatch.{{Macro "BaseName" $f}})) {
-            ALOGE("missing driver proc: %s", "{{$f.Name}}");
-            success = false;
-        }
-        {{if $ext}}
-    }
-        {{end}}
-      {{end}}
-    {{end}}
-  {{end}}
-    dispatch.GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(get_proc_addr(instance, "vkGetDeviceProcAddr"));
-    if (UNLIKELY(!dispatch.GetDeviceProcAddr)) {
-        ALOGE("missing driver proc: %s", "vkGetDeviceProcAddr");
-        success = false;
-    }
-    dispatch.DestroyDevice = reinterpret_cast<PFN_vkDestroyDevice>(get_proc_addr(instance, "vkDestroyDevice"));
-    if (UNLIKELY(!dispatch.DestroyDevice)) {
-        ALOGE("missing driver proc: %s", "vkDestroyDevice");
-        success = false;
-    }
-    dispatch.GetDeviceQueue = reinterpret_cast<PFN_vkGetDeviceQueue>(get_proc_addr(instance, "vkGetDeviceQueue"));
-    if (UNLIKELY(!dispatch.GetDeviceQueue)) {
-        ALOGE("missing driver proc: %s", "vkGetDeviceQueue");
-        success = false;
-    }
-    dispatch.AllocateCommandBuffers = reinterpret_cast<PFN_vkAllocateCommandBuffers>(get_proc_addr(instance, "vkAllocateCommandBuffers"));
-    if (UNLIKELY(!dispatch.AllocateCommandBuffers)) {
-        ALOGE("missing driver proc: %s", "vkAllocateCommandBuffers");
-        success = false;
-    }
-    dispatch.CreateImage = reinterpret_cast<PFN_vkCreateImage>(get_proc_addr(instance, "vkCreateImage"));
-    if (UNLIKELY(!dispatch.CreateImage)) {
-        ALOGE("missing driver proc: %s", "vkCreateImage");
-        success = false;
-    }
-    dispatch.DestroyImage = reinterpret_cast<PFN_vkDestroyImage>(get_proc_addr(instance, "vkDestroyImage"));
-    if (UNLIKELY(!dispatch.DestroyImage)) {
-        ALOGE("missing driver proc: %s", "vkDestroyImage");
-        success = false;
-    }
-    dispatch.GetSwapchainGrallocUsageANDROID = reinterpret_cast<PFN_vkGetSwapchainGrallocUsageANDROID>(get_proc_addr(instance, "vkGetSwapchainGrallocUsageANDROID"));
-    if (UNLIKELY(!dispatch.GetSwapchainGrallocUsageANDROID)) {
-        ALOGE("missing driver proc: %s", "vkGetSwapchainGrallocUsageANDROID");
-        success = false;
-    }
-    dispatch.AcquireImageANDROID = reinterpret_cast<PFN_vkAcquireImageANDROID>(get_proc_addr(instance, "vkAcquireImageANDROID"));
-    if (UNLIKELY(!dispatch.AcquireImageANDROID)) {
-        ALOGE("missing driver proc: %s", "vkAcquireImageANDROID");
-        success = false;
-    }
-    dispatch.QueueSignalReleaseImageANDROID = reinterpret_cast<PFN_vkQueueSignalReleaseImageANDROID>(get_proc_addr(instance, "vkQueueSignalReleaseImageANDROID"));
-    if (UNLIKELY(!dispatch.QueueSignalReleaseImageANDROID)) {
-        ALOGE("missing driver proc: %s", "vkQueueSignalReleaseImageANDROID");
-        success = false;
-    }
-    // clang-format on
-    return success;
-»}

-} // namespace vulkan
-¶{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
-  Map an extension name to InstanceExtension or DeviceExtension enum value
--------------------------------------------------------------------------------
-*/}}
-{{define "ExtensionConstant"}}
-  {{$name := index $.Arguments 0}}
-  {{     if (eq $name "VK_KHR_surface")}}kKHR_surface
-  {{else if (eq $name "VK_KHR_android_surface")}}kKHR_android_surface
-  {{else if (eq $name "VK_EXT_debug_report")}}kEXT_debug_report
-  {{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
-  Emits a function name without the "vk" prefix.
--------------------------------------------------------------------------------
-*/}}
-{{define "BaseName"}}
-  {{AssertType $ "Function"}}
-  {{TrimPrefix "vk" $.Name}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
-  Emit "true" for supported functions that undergo table dispatch. Only global
-  functions and functions handled in the loader top without calling into
-  lower layers are not dispatched.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsInstanceDispatched"}}
-  {{AssertType $ "Function"}}
-  {{if and (Macro "IsFunctionSupported" $) (eq (Macro "Vtbl" $) "Instance")}}
-    {{if and (ne $.Name "vkEnumerateDeviceLayerProperties") (ne $.Name "vkGetInstanceProcAddr")}}true{{end}}
-  {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
-  Emit "true" if a function is core or from a supportable extension.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsFunctionSupported"}}
-  {{AssertType $ "Function"}}
-  {{if not (GetAnnotation $ "pfn")}}
-    {{$ext := GetAnnotation $ "extension"}}
-    {{if not $ext}}true
-    {{else if not (Macro "IsExtensionBlacklisted" $ext)}}true
-    {{end}}
-  {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
-  Reports whether an extension function is implemented entirely by the loader,
-  and not implemented by drivers.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsLoaderFunction"}}
-  {{AssertType $ "Function"}}
-
-  {{$ext := GetAnnotation $ "extension"}}
-  {{if $ext}}
-    {{Macro "IsLoaderExtension" $ext}}
-  {{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
-  Emit "true" if the loader has a bottom-level implementation for the function
-  which terminates the dispatch chain.
--------------------------------------------------------------------------------
-*/}}
-{{define "HasLoaderBottomImpl"}}
-  {{AssertType $ "Function"}}
-
-  {{if (Macro "IsFunctionSupported" $)}}
-    {{     if (eq (Macro "Vtbl" $) "Instance")}}true
-    {{else if (Macro "IsLoaderFunction" $)}}true
-    {{else if (eq $.Name "vkCreateInstance")}}true
-    {{else if (eq $.Name "vkGetDeviceProcAddr")}}true
-    {{else if (eq $.Name "vkDestroyDevice")}}true
-    {{else if (eq $.Name "vkGetDeviceQueue")}}true
-    {{else if (eq $.Name "vkAllocateCommandBuffers")}}true
-    {{end}}
-  {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
-  Emit "true" if an extension is unsupportable on Android.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsExtensionBlacklisted"}}
-  {{$ext := index $.Arguments 0}}
-  {{     if eq $ext "VK_KHR_display"}}true
-  {{else if eq $ext "VK_KHR_display_swapchain"}}true
-  {{else if eq $ext "VK_KHR_xlib_surface"}}true
-  {{else if eq $ext "VK_KHR_xcb_surface"}}true
-  {{else if eq $ext "VK_KHR_wayland_surface"}}true
-  {{else if eq $ext "VK_KHR_mir_surface"}}true
-  {{else if eq $ext "VK_KHR_win32_surface"}}true
-  {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
-  Reports whether an extension is implemented entirely by the loader,
-  so drivers should not enumerate it.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsLoaderExtension"}}
-  {{$ext := index $.Arguments 0}}
-  {{     if eq $ext "VK_KHR_surface"}}true
-  {{else if eq $ext "VK_KHR_swapchain"}}true
-  {{else if eq $ext "VK_KHR_android_surface"}}true
-  {{end}}
-{{end}}
diff --git a/vulkan/libvulkan/dispatch_gen.cpp b/vulkan/libvulkan/dispatch_gen.cpp
deleted file mode 100644
index eacf1a1..0000000
--- a/vulkan/libvulkan/dispatch_gen.cpp
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright 2015 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.
- */
-
-// WARNING: This file is generated. See ../README.md for instructions.
-
-#include <log/log.h>
-#include <algorithm>
-#include "loader.h"
-
-#define UNLIKELY(expr) __builtin_expect((expr), 0)
-
-using namespace vulkan;
-
-namespace {
-
-struct NameProc {
-    const char* name;
-    PFN_vkVoidFunction proc;
-};
-
-PFN_vkVoidFunction Lookup(const char* name,
-                          const NameProc* begin,
-                          const NameProc* end) {
-    const auto& entry = std::lower_bound(
-        begin, end, name,
-        [](const NameProc& e, const char* n) { return strcmp(e.name, n) < 0; });
-    if (entry == end || strcmp(entry->name, name) != 0)
-        return nullptr;
-    return entry->proc;
-}
-
-template <size_t N>
-PFN_vkVoidFunction Lookup(const char* name, const NameProc (&procs)[N]) {
-    return Lookup(name, procs, procs + N);
-}
-
-const NameProc kLoaderBottomProcs[] = {
-    // clang-format off
-    {"vkAcquireNextImageKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkAcquireNextImageKHR>(AcquireNextImageKHR_Bottom))},
-    {"vkAllocateCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkAllocateCommandBuffers>(AllocateCommandBuffers_Bottom))},
-    {"vkCreateAndroidSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateAndroidSurfaceKHR>(CreateAndroidSurfaceKHR_Bottom))},
-    {"vkCreateDebugReportCallbackEXT", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDebugReportCallbackEXT>(CreateDebugReportCallbackEXT_Bottom))},
-    {"vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDevice>(CreateDevice_Bottom))},
-    {"vkCreateInstance", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateInstance>(CreateInstance_Bottom))},
-    {"vkCreateSwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSwapchainKHR>(CreateSwapchainKHR_Bottom))},
-    {"vkDebugReportMessageEXT", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDebugReportMessageEXT>(DebugReportMessageEXT_Bottom))},
-    {"vkDestroyDebugReportCallbackEXT", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDebugReportCallbackEXT>(DestroyDebugReportCallbackEXT_Bottom))},
-    {"vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDevice>(DestroyDevice_Bottom))},
-    {"vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyInstance>(DestroyInstance_Bottom))},
-    {"vkDestroySurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroySurfaceKHR>(DestroySurfaceKHR_Bottom))},
-    {"vkDestroySwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroySwapchainKHR>(DestroySwapchainKHR_Bottom))},
-    {"vkEnumerateDeviceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateDeviceExtensionProperties>(EnumerateDeviceExtensionProperties_Bottom))},
-    {"vkEnumerateDeviceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateDeviceLayerProperties>(EnumerateDeviceLayerProperties_Bottom))},
-    {"vkEnumeratePhysicalDevices", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumeratePhysicalDevices>(EnumeratePhysicalDevices_Bottom))},
-    {"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceProcAddr>(GetDeviceProcAddr_Bottom))},
-    {"vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceQueue>(GetDeviceQueue_Bottom))},
-    {"vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetInstanceProcAddr>(GetInstanceProcAddr_Bottom))},
-    {"vkGetPhysicalDeviceFeatures", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFeatures>(GetPhysicalDeviceFeatures_Bottom))},
-    {"vkGetPhysicalDeviceFormatProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFormatProperties>(GetPhysicalDeviceFormatProperties_Bottom))},
-    {"vkGetPhysicalDeviceImageFormatProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceImageFormatProperties>(GetPhysicalDeviceImageFormatProperties_Bottom))},
-    {"vkGetPhysicalDeviceMemoryProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceMemoryProperties>(GetPhysicalDeviceMemoryProperties_Bottom))},
-    {"vkGetPhysicalDeviceProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceProperties>(GetPhysicalDeviceProperties_Bottom))},
-    {"vkGetPhysicalDeviceQueueFamilyProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties>(GetPhysicalDeviceQueueFamilyProperties_Bottom))},
-    {"vkGetPhysicalDeviceSparseImageFormatProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties>(GetPhysicalDeviceSparseImageFormatProperties_Bottom))},
-    {"vkGetPhysicalDeviceSurfaceCapabilitiesKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(GetPhysicalDeviceSurfaceCapabilitiesKHR_Bottom))},
-    {"vkGetPhysicalDeviceSurfaceFormatsKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(GetPhysicalDeviceSurfaceFormatsKHR_Bottom))},
-    {"vkGetPhysicalDeviceSurfacePresentModesKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(GetPhysicalDeviceSurfacePresentModesKHR_Bottom))},
-    {"vkGetPhysicalDeviceSurfaceSupportKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceSurfaceSupportKHR>(GetPhysicalDeviceSurfaceSupportKHR_Bottom))},
-    {"vkGetSwapchainImagesKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainImagesKHR>(GetSwapchainImagesKHR_Bottom))},
-    {"vkQueuePresentKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkQueuePresentKHR>(QueuePresentKHR_Bottom))},
-    // clang-format on
-};
-
-}  // anonymous namespace
-
-namespace vulkan {
-
-PFN_vkVoidFunction GetLoaderBottomProcAddr(const char* name) {
-    return Lookup(name, kLoaderBottomProcs);
-}
-
-bool LoadDriverDispatchTable(VkInstance instance,
-                             PFN_vkGetInstanceProcAddr get_proc_addr,
-                             const InstanceExtensionSet& extensions,
-                             DriverDispatchTable& dispatch) {
-    bool success = true;
-    // clang-format off
-    dispatch.DestroyInstance = reinterpret_cast<PFN_vkDestroyInstance>(get_proc_addr(instance, "vkDestroyInstance"));
-    if (UNLIKELY(!dispatch.DestroyInstance)) {
-        ALOGE("missing driver proc: %s", "vkDestroyInstance");
-        success = false;
-    }
-    dispatch.EnumeratePhysicalDevices = reinterpret_cast<PFN_vkEnumeratePhysicalDevices>(get_proc_addr(instance, "vkEnumeratePhysicalDevices"));
-    if (UNLIKELY(!dispatch.EnumeratePhysicalDevices)) {
-        ALOGE("missing driver proc: %s", "vkEnumeratePhysicalDevices");
-        success = false;
-    }
-    dispatch.GetPhysicalDeviceProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>(get_proc_addr(instance, "vkGetPhysicalDeviceProperties"));
-    if (UNLIKELY(!dispatch.GetPhysicalDeviceProperties)) {
-        ALOGE("missing driver proc: %s", "vkGetPhysicalDeviceProperties");
-        success = false;
-    }
-    dispatch.GetPhysicalDeviceQueueFamilyProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties>(get_proc_addr(instance, "vkGetPhysicalDeviceQueueFamilyProperties"));
-    if (UNLIKELY(!dispatch.GetPhysicalDeviceQueueFamilyProperties)) {
-        ALOGE("missing driver proc: %s", "vkGetPhysicalDeviceQueueFamilyProperties");
-        success = false;
-    }
-    dispatch.GetPhysicalDeviceMemoryProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceMemoryProperties>(get_proc_addr(instance, "vkGetPhysicalDeviceMemoryProperties"));
-    if (UNLIKELY(!dispatch.GetPhysicalDeviceMemoryProperties)) {
-        ALOGE("missing driver proc: %s", "vkGetPhysicalDeviceMemoryProperties");
-        success = false;
-    }
-    dispatch.GetPhysicalDeviceFeatures = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures>(get_proc_addr(instance, "vkGetPhysicalDeviceFeatures"));
-    if (UNLIKELY(!dispatch.GetPhysicalDeviceFeatures)) {
-        ALOGE("missing driver proc: %s", "vkGetPhysicalDeviceFeatures");
-        success = false;
-    }
-    dispatch.GetPhysicalDeviceFormatProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties>(get_proc_addr(instance, "vkGetPhysicalDeviceFormatProperties"));
-    if (UNLIKELY(!dispatch.GetPhysicalDeviceFormatProperties)) {
-        ALOGE("missing driver proc: %s", "vkGetPhysicalDeviceFormatProperties");
-        success = false;
-    }
-    dispatch.GetPhysicalDeviceImageFormatProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceImageFormatProperties>(get_proc_addr(instance, "vkGetPhysicalDeviceImageFormatProperties"));
-    if (UNLIKELY(!dispatch.GetPhysicalDeviceImageFormatProperties)) {
-        ALOGE("missing driver proc: %s", "vkGetPhysicalDeviceImageFormatProperties");
-        success = false;
-    }
-    dispatch.CreateDevice = reinterpret_cast<PFN_vkCreateDevice>(get_proc_addr(instance, "vkCreateDevice"));
-    if (UNLIKELY(!dispatch.CreateDevice)) {
-        ALOGE("missing driver proc: %s", "vkCreateDevice");
-        success = false;
-    }
-    dispatch.EnumerateDeviceExtensionProperties = reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>(get_proc_addr(instance, "vkEnumerateDeviceExtensionProperties"));
-    if (UNLIKELY(!dispatch.EnumerateDeviceExtensionProperties)) {
-        ALOGE("missing driver proc: %s", "vkEnumerateDeviceExtensionProperties");
-        success = false;
-    }
-    dispatch.GetPhysicalDeviceSparseImageFormatProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties>(get_proc_addr(instance, "vkGetPhysicalDeviceSparseImageFormatProperties"));
-    if (UNLIKELY(!dispatch.GetPhysicalDeviceSparseImageFormatProperties)) {
-        ALOGE("missing driver proc: %s", "vkGetPhysicalDeviceSparseImageFormatProperties");
-        success = false;
-    }
-    if (extensions[kEXT_debug_report]) {
-        dispatch.CreateDebugReportCallbackEXT = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(get_proc_addr(instance, "vkCreateDebugReportCallbackEXT"));
-        if (UNLIKELY(!dispatch.CreateDebugReportCallbackEXT)) {
-            ALOGE("missing driver proc: %s", "vkCreateDebugReportCallbackEXT");
-            success = false;
-        }
-    }
-    if (extensions[kEXT_debug_report]) {
-        dispatch.DestroyDebugReportCallbackEXT = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(get_proc_addr(instance, "vkDestroyDebugReportCallbackEXT"));
-        if (UNLIKELY(!dispatch.DestroyDebugReportCallbackEXT)) {
-            ALOGE("missing driver proc: %s", "vkDestroyDebugReportCallbackEXT");
-            success = false;
-        }
-    }
-    if (extensions[kEXT_debug_report]) {
-        dispatch.DebugReportMessageEXT = reinterpret_cast<PFN_vkDebugReportMessageEXT>(get_proc_addr(instance, "vkDebugReportMessageEXT"));
-        if (UNLIKELY(!dispatch.DebugReportMessageEXT)) {
-            ALOGE("missing driver proc: %s", "vkDebugReportMessageEXT");
-            success = false;
-        }
-    }
-    dispatch.GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(get_proc_addr(instance, "vkGetDeviceProcAddr"));
-    if (UNLIKELY(!dispatch.GetDeviceProcAddr)) {
-        ALOGE("missing driver proc: %s", "vkGetDeviceProcAddr");
-        success = false;
-    }
-    dispatch.DestroyDevice = reinterpret_cast<PFN_vkDestroyDevice>(get_proc_addr(instance, "vkDestroyDevice"));
-    if (UNLIKELY(!dispatch.DestroyDevice)) {
-        ALOGE("missing driver proc: %s", "vkDestroyDevice");
-        success = false;
-    }
-    dispatch.GetDeviceQueue = reinterpret_cast<PFN_vkGetDeviceQueue>(get_proc_addr(instance, "vkGetDeviceQueue"));
-    if (UNLIKELY(!dispatch.GetDeviceQueue)) {
-        ALOGE("missing driver proc: %s", "vkGetDeviceQueue");
-        success = false;
-    }
-    dispatch.AllocateCommandBuffers = reinterpret_cast<PFN_vkAllocateCommandBuffers>(get_proc_addr(instance, "vkAllocateCommandBuffers"));
-    if (UNLIKELY(!dispatch.AllocateCommandBuffers)) {
-        ALOGE("missing driver proc: %s", "vkAllocateCommandBuffers");
-        success = false;
-    }
-    dispatch.CreateImage = reinterpret_cast<PFN_vkCreateImage>(get_proc_addr(instance, "vkCreateImage"));
-    if (UNLIKELY(!dispatch.CreateImage)) {
-        ALOGE("missing driver proc: %s", "vkCreateImage");
-        success = false;
-    }
-    dispatch.DestroyImage = reinterpret_cast<PFN_vkDestroyImage>(get_proc_addr(instance, "vkDestroyImage"));
-    if (UNLIKELY(!dispatch.DestroyImage)) {
-        ALOGE("missing driver proc: %s", "vkDestroyImage");
-        success = false;
-    }
-    dispatch.GetSwapchainGrallocUsageANDROID = reinterpret_cast<PFN_vkGetSwapchainGrallocUsageANDROID>(get_proc_addr(instance, "vkGetSwapchainGrallocUsageANDROID"));
-    if (UNLIKELY(!dispatch.GetSwapchainGrallocUsageANDROID)) {
-        ALOGE("missing driver proc: %s", "vkGetSwapchainGrallocUsageANDROID");
-        success = false;
-    }
-    dispatch.AcquireImageANDROID = reinterpret_cast<PFN_vkAcquireImageANDROID>(get_proc_addr(instance, "vkAcquireImageANDROID"));
-    if (UNLIKELY(!dispatch.AcquireImageANDROID)) {
-        ALOGE("missing driver proc: %s", "vkAcquireImageANDROID");
-        success = false;
-    }
-    dispatch.QueueSignalReleaseImageANDROID = reinterpret_cast<PFN_vkQueueSignalReleaseImageANDROID>(get_proc_addr(instance, "vkQueueSignalReleaseImageANDROID"));
-    if (UNLIKELY(!dispatch.QueueSignalReleaseImageANDROID)) {
-        ALOGE("missing driver proc: %s", "vkQueueSignalReleaseImageANDROID");
-        success = false;
-    }
-    // clang-format on
-    return success;
-}
-
-}  // namespace vulkan
diff --git a/vulkan/libvulkan/dispatch_gen.h b/vulkan/libvulkan/dispatch_gen.h
deleted file mode 100644
index ca31caf..0000000
--- a/vulkan/libvulkan/dispatch_gen.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2015 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.
- */
-
-// WARNING: This file is generated. See ../README.md for instructions.
-
-#include <vulkan/vk_android_native_buffer.h>
-#include <vulkan/vulkan.h>
-
-namespace vulkan {
-
-struct DriverDispatchTable {
-    // clang-format off
-    PFN_vkDestroyInstance DestroyInstance;
-    PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices;
-    PFN_vkGetPhysicalDeviceProperties GetPhysicalDeviceProperties;
-    PFN_vkGetPhysicalDeviceQueueFamilyProperties GetPhysicalDeviceQueueFamilyProperties;
-    PFN_vkGetPhysicalDeviceMemoryProperties GetPhysicalDeviceMemoryProperties;
-    PFN_vkGetPhysicalDeviceFeatures GetPhysicalDeviceFeatures;
-    PFN_vkGetPhysicalDeviceFormatProperties GetPhysicalDeviceFormatProperties;
-    PFN_vkGetPhysicalDeviceImageFormatProperties GetPhysicalDeviceImageFormatProperties;
-    PFN_vkCreateDevice CreateDevice;
-    PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;
-    PFN_vkGetPhysicalDeviceSparseImageFormatProperties GetPhysicalDeviceSparseImageFormatProperties;
-    PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
-    PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
-    PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
-    PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
-    PFN_vkDestroyDevice DestroyDevice;
-    PFN_vkGetDeviceQueue GetDeviceQueue;
-    PFN_vkAllocateCommandBuffers AllocateCommandBuffers;
-    PFN_vkCreateImage CreateImage;
-    PFN_vkDestroyImage DestroyImage;
-    PFN_vkGetSwapchainGrallocUsageANDROID GetSwapchainGrallocUsageANDROID;
-    PFN_vkAcquireImageANDROID AcquireImageANDROID;
-    PFN_vkQueueSignalReleaseImageANDROID QueueSignalReleaseImageANDROID;
-    // clang-format on
-};
-
-}  // namespace vulkan
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
new file mode 100644
index 0000000..c5ea20b
--- /dev/null
+++ b/vulkan/libvulkan/driver.cpp
@@ -0,0 +1,775 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <algorithm>
+#include <array>
+#include <new>
+#include <malloc.h>
+#include <sys/prctl.h>
+
+#include "driver.h"
+#include "stubhal.h"
+
+// #define ENABLE_ALLOC_CALLSTACKS 1
+#if ENABLE_ALLOC_CALLSTACKS
+#include <utils/CallStack.h>
+#define ALOGD_CALLSTACK(...)                             \
+    do {                                                 \
+        ALOGD(__VA_ARGS__);                              \
+        android::CallStack callstack;                    \
+        callstack.update();                              \
+        callstack.log(LOG_TAG, ANDROID_LOG_DEBUG, "  "); \
+    } while (false)
+#else
+#define ALOGD_CALLSTACK(...) \
+    do {                     \
+    } while (false)
+#endif
+
+namespace vulkan {
+namespace driver {
+
+namespace {
+
+class CreateInfoWrapper {
+   public:
+    CreateInfoWrapper(const hwvulkan_device_t* hw_dev,
+                      const VkInstanceCreateInfo& create_info,
+                      const VkAllocationCallbacks& allocator);
+    CreateInfoWrapper(VkPhysicalDevice physical_dev,
+                      const VkDeviceCreateInfo& create_info,
+                      const VkAllocationCallbacks& allocator);
+    ~CreateInfoWrapper();
+
+    VkResult Validate();
+
+    const std::bitset<ProcHook::EXTENSION_COUNT>& GetHookExtensions() const;
+    const std::bitset<ProcHook::EXTENSION_COUNT>& GetHalExtensions() const;
+
+    explicit operator const VkInstanceCreateInfo*() const;
+    explicit operator const VkDeviceCreateInfo*() const;
+
+   private:
+    struct ExtensionFilter {
+        VkExtensionProperties* exts;
+        uint32_t ext_count;
+
+        const char** names;
+        uint32_t name_count;
+    };
+
+    VkResult SanitizePNext();
+
+    VkResult SanitizeLayers();
+    VkResult SanitizeExtensions();
+
+    VkResult QueryExtensionCount(uint32_t& count) const;
+    VkResult EnumerateExtensions(uint32_t& count,
+                                 VkExtensionProperties* props) const;
+    VkResult InitExtensionFilter();
+    void FilterExtension(const char* name);
+
+    const bool is_instance_;
+    const VkAllocationCallbacks& allocator_;
+
+    union {
+        const hwvulkan_device_t* hw_dev_;
+        VkPhysicalDevice physical_dev_;
+    };
+
+    union {
+        VkInstanceCreateInfo instance_info_;
+        VkDeviceCreateInfo dev_info_;
+    };
+
+    ExtensionFilter extension_filter_;
+
+    std::bitset<ProcHook::EXTENSION_COUNT> hook_extensions_;
+    std::bitset<ProcHook::EXTENSION_COUNT> hal_extensions_;
+};
+
+CreateInfoWrapper::CreateInfoWrapper(const hwvulkan_device_t* hw_dev,
+                                     const VkInstanceCreateInfo& create_info,
+                                     const VkAllocationCallbacks& allocator)
+    : is_instance_(true),
+      allocator_(allocator),
+      hw_dev_(hw_dev),
+      instance_info_(create_info),
+      extension_filter_() {
+    hook_extensions_.set(ProcHook::EXTENSION_CORE);
+    hal_extensions_.set(ProcHook::EXTENSION_CORE);
+}
+
+CreateInfoWrapper::CreateInfoWrapper(VkPhysicalDevice physical_dev,
+                                     const VkDeviceCreateInfo& create_info,
+                                     const VkAllocationCallbacks& allocator)
+    : is_instance_(false),
+      allocator_(allocator),
+      physical_dev_(physical_dev),
+      dev_info_(create_info),
+      extension_filter_() {
+    hook_extensions_.set(ProcHook::EXTENSION_CORE);
+    hal_extensions_.set(ProcHook::EXTENSION_CORE);
+}
+
+CreateInfoWrapper::~CreateInfoWrapper() {
+    allocator_.pfnFree(allocator_.pUserData, extension_filter_.exts);
+    allocator_.pfnFree(allocator_.pUserData, extension_filter_.names);
+}
+
+VkResult CreateInfoWrapper::Validate() {
+    VkResult result = SanitizePNext();
+    if (result == VK_SUCCESS)
+        result = SanitizeLayers();
+    if (result == VK_SUCCESS)
+        result = SanitizeExtensions();
+
+    return result;
+}
+
+const std::bitset<ProcHook::EXTENSION_COUNT>&
+CreateInfoWrapper::GetHookExtensions() const {
+    return hook_extensions_;
+}
+
+const std::bitset<ProcHook::EXTENSION_COUNT>&
+CreateInfoWrapper::GetHalExtensions() const {
+    return hal_extensions_;
+}
+
+CreateInfoWrapper::operator const VkInstanceCreateInfo*() const {
+    return &instance_info_;
+}
+
+CreateInfoWrapper::operator const VkDeviceCreateInfo*() const {
+    return &dev_info_;
+}
+
+VkResult CreateInfoWrapper::SanitizePNext() {
+    const struct StructHeader {
+        VkStructureType type;
+        const void* next;
+    } * header;
+
+    if (is_instance_) {
+        header = reinterpret_cast<const StructHeader*>(instance_info_.pNext);
+
+        // skip leading VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFOs
+        while (header &&
+               header->type == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO)
+            header = reinterpret_cast<const StructHeader*>(header->next);
+
+        instance_info_.pNext = header;
+    } else {
+        header = reinterpret_cast<const StructHeader*>(dev_info_.pNext);
+
+        // skip leading VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFOs
+        while (header &&
+               header->type == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO)
+            header = reinterpret_cast<const StructHeader*>(header->next);
+
+        dev_info_.pNext = header;
+    }
+
+    return VK_SUCCESS;
+}
+
+VkResult CreateInfoWrapper::SanitizeLayers() {
+    auto& layer_names = (is_instance_) ? instance_info_.ppEnabledLayerNames
+                                       : dev_info_.ppEnabledLayerNames;
+    auto& layer_count = (is_instance_) ? instance_info_.enabledLayerCount
+                                       : dev_info_.enabledLayerCount;
+
+    // remove all layers
+    layer_names = nullptr;
+    layer_count = 0;
+
+    return VK_SUCCESS;
+}
+
+VkResult CreateInfoWrapper::SanitizeExtensions() {
+    auto& ext_names = (is_instance_) ? instance_info_.ppEnabledExtensionNames
+                                     : dev_info_.ppEnabledExtensionNames;
+    auto& ext_count = (is_instance_) ? instance_info_.enabledExtensionCount
+                                     : dev_info_.enabledExtensionCount;
+    if (!ext_count)
+        return VK_SUCCESS;
+
+    VkResult result = InitExtensionFilter();
+    if (result != VK_SUCCESS)
+        return result;
+
+    for (uint32_t i = 0; i < ext_count; i++)
+        FilterExtension(ext_names[i]);
+
+    ext_names = extension_filter_.names;
+    ext_count = extension_filter_.name_count;
+
+    return VK_SUCCESS;
+}
+
+VkResult CreateInfoWrapper::QueryExtensionCount(uint32_t& count) const {
+    if (is_instance_) {
+        return hw_dev_->EnumerateInstanceExtensionProperties(nullptr, &count,
+                                                             nullptr);
+    } else {
+        const auto& driver = GetData(physical_dev_).driver;
+        return driver.EnumerateDeviceExtensionProperties(physical_dev_, nullptr,
+                                                         &count, nullptr);
+    }
+}
+
+VkResult CreateInfoWrapper::EnumerateExtensions(
+    uint32_t& count,
+    VkExtensionProperties* props) const {
+    if (is_instance_) {
+        return hw_dev_->EnumerateInstanceExtensionProperties(nullptr, &count,
+                                                             props);
+    } else {
+        const auto& driver = GetData(physical_dev_).driver;
+        return driver.EnumerateDeviceExtensionProperties(physical_dev_, nullptr,
+                                                         &count, props);
+    }
+}
+
+VkResult CreateInfoWrapper::InitExtensionFilter() {
+    // query extension count
+    uint32_t count;
+    VkResult result = QueryExtensionCount(count);
+    if (result != VK_SUCCESS || count == 0)
+        return result;
+
+    auto& filter = extension_filter_;
+    filter.exts =
+        reinterpret_cast<VkExtensionProperties*>(allocator_.pfnAllocation(
+            allocator_.pUserData, sizeof(VkExtensionProperties) * count,
+            alignof(VkExtensionProperties),
+            VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
+    if (!filter.exts)
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+    // enumerate extensions
+    result = EnumerateExtensions(count, filter.exts);
+    if (result != VK_SUCCESS && result != VK_INCOMPLETE)
+        return result;
+
+    if (!count)
+        return VK_SUCCESS;
+
+    filter.ext_count = count;
+
+    // allocate name array
+    uint32_t enabled_ext_count = (is_instance_)
+                                     ? instance_info_.enabledExtensionCount
+                                     : dev_info_.enabledExtensionCount;
+    count = std::min(filter.ext_count, enabled_ext_count);
+    filter.names = reinterpret_cast<const char**>(allocator_.pfnAllocation(
+        allocator_.pUserData, sizeof(const char*) * count, alignof(const char*),
+        VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
+    if (!filter.names)
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+    return VK_SUCCESS;
+}
+
+void CreateInfoWrapper::FilterExtension(const char* name) {
+    auto& filter = extension_filter_;
+
+    ProcHook::Extension ext_bit = GetProcHookExtension(name);
+    if (is_instance_) {
+        switch (ext_bit) {
+            case ProcHook::KHR_android_surface:
+            case ProcHook::KHR_surface:
+                hook_extensions_.set(ext_bit);
+                // return now as these extensions do not require HAL support
+                return;
+            case ProcHook::EXT_debug_report:
+                // both we and HAL can take part in
+                hook_extensions_.set(ext_bit);
+                break;
+            case ProcHook::EXTENSION_UNKNOWN:
+                // HAL's extensions
+                break;
+            default:
+                ALOGW("Ignored invalid instance extension %s", name);
+                return;
+        }
+    } else {
+        switch (ext_bit) {
+            case ProcHook::KHR_swapchain:
+                // map VK_KHR_swapchain to VK_ANDROID_native_buffer
+                name = VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME;
+                ext_bit = ProcHook::ANDROID_native_buffer;
+                break;
+            case ProcHook::EXTENSION_UNKNOWN:
+                // HAL's extensions
+                break;
+            default:
+                ALOGW("Ignored invalid device extension %s", name);
+                return;
+        }
+    }
+
+    for (uint32_t i = 0; i < filter.ext_count; i++) {
+        const VkExtensionProperties& props = filter.exts[i];
+        // ignore unknown extensions
+        if (strcmp(name, props.extensionName) != 0)
+            continue;
+
+        filter.names[filter.name_count++] = name;
+        if (ext_bit != ProcHook::EXTENSION_UNKNOWN) {
+            if (ext_bit == ProcHook::ANDROID_native_buffer)
+                hook_extensions_.set(ProcHook::KHR_swapchain);
+
+            hal_extensions_.set(ext_bit);
+        }
+
+        break;
+    }
+}
+
+const hwvulkan_device_t* g_hwdevice = nullptr;
+
+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);
+    ALOGD_CALLSTACK("Allocate: size=%zu align=%zu => (%d) %p", size, alignment,
+                    ret, ptr);
+    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.
+    // Right now the loader 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) {
+    ALOGD_CALLSTACK("Free: %p", ptr);
+    free(ptr);
+}
+
+InstanceData* AllocateInstanceData(const VkAllocationCallbacks& allocator) {
+    void* data_mem = allocator.pfnAllocation(
+        allocator.pUserData, sizeof(InstanceData), alignof(InstanceData),
+        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+    if (!data_mem)
+        return nullptr;
+
+    return new (data_mem) InstanceData(allocator);
+}
+
+void FreeInstanceData(InstanceData* data,
+                      const VkAllocationCallbacks& allocator) {
+    data->~InstanceData();
+    allocator.pfnFree(allocator.pUserData, data);
+}
+
+DeviceData* AllocateDeviceData(const VkAllocationCallbacks& allocator) {
+    void* data_mem = allocator.pfnAllocation(
+        allocator.pUserData, sizeof(DeviceData), alignof(DeviceData),
+        VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
+    if (!data_mem)
+        return nullptr;
+
+    return new (data_mem) DeviceData(allocator);
+}
+
+void FreeDeviceData(DeviceData* data, const VkAllocationCallbacks& allocator) {
+    data->~DeviceData();
+    allocator.pfnFree(allocator.pUserData, data);
+}
+
+}  // anonymous namespace
+
+bool Debuggable() {
+    return (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) >= 0);
+}
+
+bool OpenHAL() {
+    ALOG_ASSERT(!g_hwdevice, "OpenHAL called more than once");
+
+    // Use a stub device unless we successfully open a real HAL device.
+    g_hwdevice = &stubhal::kDevice;
+
+    const hwvulkan_module_t* module;
+    int result =
+        hw_get_module("vulkan", reinterpret_cast<const hw_module_t**>(&module));
+    if (result != 0) {
+        ALOGV("no Vulkan HAL present, using stub HAL");
+        return true;
+    }
+
+    hwvulkan_device_t* device;
+    result =
+        module->common.methods->open(&module->common, HWVULKAN_DEVICE_0,
+                                     reinterpret_cast<hw_device_t**>(&device));
+    if (result != 0) {
+        // Any device with a Vulkan HAL should be able to open the device.
+        ALOGE("failed to open Vulkan HAL device: %s (%d)", strerror(-result),
+              result);
+        return false;
+    }
+
+    g_hwdevice = device;
+
+    return true;
+}
+
+const VkAllocationCallbacks& GetDefaultAllocator() {
+    static const VkAllocationCallbacks kDefaultAllocCallbacks = {
+        .pUserData = nullptr,
+        .pfnAllocation = DefaultAllocate,
+        .pfnReallocation = DefaultReallocate,
+        .pfnFree = DefaultFree,
+    };
+
+    return kDefaultAllocCallbacks;
+}
+
+PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName) {
+    const ProcHook* hook = GetProcHook(pName);
+    if (!hook)
+        return g_hwdevice->GetInstanceProcAddr(instance, pName);
+
+    if (!instance) {
+        if (hook->type == ProcHook::GLOBAL)
+            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;
+    }
+
+    PFN_vkVoidFunction proc;
+
+    switch (hook->type) {
+        case ProcHook::INSTANCE:
+            proc = (GetData(instance).hook_extensions[hook->extension])
+                       ? hook->proc
+                       : hook->disabled_proc;
+            break;
+        case ProcHook::DEVICE:
+            proc = (hook->extension == ProcHook::EXTENSION_CORE)
+                       ? hook->proc
+                       : hook->checked_proc;
+            break;
+        default:
+            ALOGE(
+                "Invalid use of vkGetInstanceProcAddr to query %s with an "
+                "instance",
+                pName);
+            proc = nullptr;
+            break;
+    }
+
+    return proc;
+}
+
+PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName) {
+    const ProcHook* hook = GetProcHook(pName);
+    if (!hook)
+        return GetData(device).driver.GetDeviceProcAddr(device, pName);
+
+    if (hook->type != ProcHook::DEVICE) {
+        ALOGE("Invalid use of vkGetDeviceProcAddr to query %s", pName);
+        return nullptr;
+    }
+
+    return (GetData(device).hook_extensions[hook->extension])
+               ? hook->proc
+               : hook->disabled_proc;
+}
+
+VkResult EnumerateInstanceExtensionProperties(
+    const char* pLayerName,
+    uint32_t* pPropertyCount,
+    VkExtensionProperties* pProperties) {
+    static const std::array<VkExtensionProperties, 2> loader_extensions = {{
+        // WSI extensions
+        {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_SPEC_VERSION},
+        {VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
+         VK_KHR_ANDROID_SURFACE_SPEC_VERSION},
+    }};
+
+    // enumerate our extensions first
+    if (!pLayerName && pProperties) {
+        uint32_t count = std::min(
+            *pPropertyCount, static_cast<uint32_t>(loader_extensions.size()));
+
+        std::copy_n(loader_extensions.begin(), count, pProperties);
+
+        if (count < loader_extensions.size()) {
+            *pPropertyCount = count;
+            return VK_INCOMPLETE;
+        }
+
+        pProperties += count;
+        *pPropertyCount -= count;
+    }
+
+    VkResult result = g_hwdevice->EnumerateInstanceExtensionProperties(
+        pLayerName, pPropertyCount, pProperties);
+
+    if (!pLayerName && (result == VK_SUCCESS || result == VK_INCOMPLETE))
+        *pPropertyCount += loader_extensions.size();
+
+    return result;
+}
+
+VkResult EnumerateDeviceExtensionProperties(
+    VkPhysicalDevice physicalDevice,
+    const char* pLayerName,
+    uint32_t* pPropertyCount,
+    VkExtensionProperties* pProperties) {
+    const InstanceData& data = GetData(physicalDevice);
+
+    VkResult result = data.driver.EnumerateDeviceExtensionProperties(
+        physicalDevice, pLayerName, pPropertyCount, pProperties);
+    if (result != VK_SUCCESS && result != VK_INCOMPLETE)
+        return result;
+
+    if (!pProperties)
+        return result;
+
+    // map VK_ANDROID_native_buffer to VK_KHR_swapchain
+    for (uint32_t i = 0; i < *pPropertyCount; i++) {
+        auto& prop = pProperties[i];
+
+        if (strcmp(prop.extensionName,
+                   VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME) != 0)
+            continue;
+
+        memcpy(prop.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME,
+               sizeof(VK_KHR_SWAPCHAIN_EXTENSION_NAME));
+        prop.specVersion = VK_KHR_SWAPCHAIN_SPEC_VERSION;
+    }
+
+    return result;
+}
+
+VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo,
+                        const VkAllocationCallbacks* pAllocator,
+                        VkInstance* pInstance) {
+    const VkAllocationCallbacks& data_allocator =
+        (pAllocator) ? *pAllocator : GetDefaultAllocator();
+
+    CreateInfoWrapper wrapper(g_hwdevice, *pCreateInfo, data_allocator);
+    VkResult result = wrapper.Validate();
+    if (result != VK_SUCCESS)
+        return result;
+
+    InstanceData* data = AllocateInstanceData(data_allocator);
+    if (!data)
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+    data->hook_extensions |= wrapper.GetHookExtensions();
+    data->hal_extensions |= wrapper.GetHalExtensions();
+
+    // call into the driver
+    VkInstance instance;
+    result = g_hwdevice->CreateInstance(
+        static_cast<const VkInstanceCreateInfo*>(wrapper), pAllocator,
+        &instance);
+    if (result != VK_SUCCESS) {
+        FreeInstanceData(data, data_allocator);
+        return result;
+    }
+
+    // initialize InstanceDriverTable
+    if (!SetData(instance, *data) ||
+        !InitDriverTable(instance, g_hwdevice->GetInstanceProcAddr)) {
+        data->driver.DestroyInstance = reinterpret_cast<PFN_vkDestroyInstance>(
+            g_hwdevice->GetInstanceProcAddr(instance, "vkDestroyInstance"));
+        if (data->driver.DestroyInstance)
+            data->driver.DestroyInstance(instance, pAllocator);
+
+        FreeInstanceData(data, data_allocator);
+
+        return VK_ERROR_INCOMPATIBLE_DRIVER;
+    }
+
+    data->get_device_proc_addr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
+        g_hwdevice->GetInstanceProcAddr(instance, "vkGetDeviceProcAddr"));
+    if (!data->get_device_proc_addr) {
+        data->driver.DestroyInstance(instance, pAllocator);
+        FreeInstanceData(data, data_allocator);
+
+        return VK_ERROR_INCOMPATIBLE_DRIVER;
+    }
+
+    *pInstance = instance;
+
+    return VK_SUCCESS;
+}
+
+void DestroyInstance(VkInstance instance,
+                     const VkAllocationCallbacks* pAllocator) {
+    InstanceData& data = GetData(instance);
+    data.driver.DestroyInstance(instance, pAllocator);
+
+    VkAllocationCallbacks local_allocator;
+    if (!pAllocator) {
+        local_allocator = data.allocator;
+        pAllocator = &local_allocator;
+    }
+
+    FreeInstanceData(&data, *pAllocator);
+}
+
+VkResult CreateDevice(VkPhysicalDevice physicalDevice,
+                      const VkDeviceCreateInfo* pCreateInfo,
+                      const VkAllocationCallbacks* pAllocator,
+                      VkDevice* pDevice) {
+    const InstanceData& instance_data = GetData(physicalDevice);
+    const VkAllocationCallbacks& data_allocator =
+        (pAllocator) ? *pAllocator : instance_data.allocator;
+
+    CreateInfoWrapper wrapper(physicalDevice, *pCreateInfo, data_allocator);
+    VkResult result = wrapper.Validate();
+    if (result != VK_SUCCESS)
+        return result;
+
+    DeviceData* data = AllocateDeviceData(data_allocator);
+    if (!data)
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+    data->hook_extensions |= wrapper.GetHookExtensions();
+    data->hal_extensions |= wrapper.GetHalExtensions();
+
+    // call into the driver
+    VkDevice dev;
+    result = instance_data.driver.CreateDevice(
+        physicalDevice, static_cast<const VkDeviceCreateInfo*>(wrapper),
+        pAllocator, &dev);
+    if (result != VK_SUCCESS) {
+        FreeDeviceData(data, data_allocator);
+        return result;
+    }
+
+    // initialize DeviceDriverTable
+    if (!SetData(dev, *data) ||
+        !InitDriverTable(dev, instance_data.get_device_proc_addr)) {
+        data->driver.DestroyDevice = reinterpret_cast<PFN_vkDestroyDevice>(
+            instance_data.get_device_proc_addr(dev, "vkDestroyDevice"));
+        if (data->driver.DestroyDevice)
+            data->driver.DestroyDevice(dev, pAllocator);
+
+        FreeDeviceData(data, data_allocator);
+
+        return VK_ERROR_INCOMPATIBLE_DRIVER;
+    }
+
+    *pDevice = dev;
+
+    return VK_SUCCESS;
+}
+
+void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) {
+    DeviceData& data = GetData(device);
+    data.driver.DestroyDevice(device, pAllocator);
+
+    VkAllocationCallbacks local_allocator;
+    if (!pAllocator) {
+        local_allocator = data.allocator;
+        pAllocator = &local_allocator;
+    }
+
+    FreeDeviceData(&data, *pAllocator);
+}
+
+VkResult EnumeratePhysicalDevices(VkInstance instance,
+                                  uint32_t* pPhysicalDeviceCount,
+                                  VkPhysicalDevice* pPhysicalDevices) {
+    const auto& data = GetData(instance);
+
+    VkResult result = data.driver.EnumeratePhysicalDevices(
+        instance, pPhysicalDeviceCount, pPhysicalDevices);
+    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pPhysicalDevices) {
+        for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++)
+            SetData(pPhysicalDevices[i], data);
+    }
+
+    return result;
+}
+
+void GetDeviceQueue(VkDevice device,
+                    uint32_t queueFamilyIndex,
+                    uint32_t queueIndex,
+                    VkQueue* pQueue) {
+    const auto& data = GetData(device);
+
+    data.driver.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
+    SetData(*pQueue, data);
+}
+
+VKAPI_ATTR VkResult
+AllocateCommandBuffers(VkDevice device,
+                       const VkCommandBufferAllocateInfo* pAllocateInfo,
+                       VkCommandBuffer* pCommandBuffers) {
+    const auto& data = GetData(device);
+
+    VkResult result = data.driver.AllocateCommandBuffers(device, pAllocateInfo,
+                                                         pCommandBuffers);
+    if (result == VK_SUCCESS) {
+        for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; i++)
+            SetData(pCommandBuffers[i], data);
+    }
+
+    return result;
+}
+
+}  // namespace driver
+}  // namespace vulkan
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index de9d1c6..22db93f 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -18,6 +18,7 @@
 #define LIBVULKAN_DRIVER_H 1
 
 #include <inttypes.h>
+#include <bitset>
 #include <type_traits>
 #include <log/log.h>
 
@@ -25,6 +26,9 @@
 #include <hardware/hwvulkan.h>
 
 #include "api_gen.h"
+#include "driver_gen.h"
+#include "debug_report.h"
+#include "swapchain.h"
 
 namespace vulkan {
 
@@ -61,15 +65,43 @@
 namespace driver {
 
 struct InstanceData {
+    InstanceData(const VkAllocationCallbacks& alloc)
+        : opaque_api_data(),
+          allocator(alloc),
+          driver(),
+          get_device_proc_addr(nullptr) {
+        hook_extensions.set(ProcHook::EXTENSION_CORE);
+        hal_extensions.set(ProcHook::EXTENSION_CORE);
+    }
+
     api::InstanceData opaque_api_data;
 
     const VkAllocationCallbacks allocator;
+
+    std::bitset<ProcHook::EXTENSION_COUNT> hook_extensions;
+    std::bitset<ProcHook::EXTENSION_COUNT> hal_extensions;
+
+    InstanceDriverTable driver;
+    PFN_vkGetDeviceProcAddr get_device_proc_addr;
+
+    DebugReportCallbackList debug_report_callbacks;
 };
 
 struct DeviceData {
+    DeviceData(const VkAllocationCallbacks& alloc)
+        : opaque_api_data(), allocator(alloc), driver() {
+        hook_extensions.set(ProcHook::EXTENSION_CORE);
+        hal_extensions.set(ProcHook::EXTENSION_CORE);
+    }
+
     api::DeviceData opaque_api_data;
 
     const VkAllocationCallbacks allocator;
+
+    std::bitset<ProcHook::EXTENSION_COUNT> hook_extensions;
+    std::bitset<ProcHook::EXTENSION_COUNT> hal_extensions;
+
+    DeviceDriverTable driver;
 };
 
 bool Debuggable();
@@ -80,6 +112,17 @@
 VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName);
 VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName);
 VKAPI_ATTR VkResult EnumerateInstanceExtensionProperties(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties);
+
+VKAPI_ATTR VkResult EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties);
+
+VKAPI_ATTR VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance);
+VKAPI_ATTR void DestroyInstance(VkInstance instance, const VkAllocationCallbacks* pAllocator);
+VKAPI_ATTR VkResult CreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice);
+VKAPI_ATTR void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator);
+
+VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices);
+VKAPI_ATTR void GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue);
+VKAPI_ATTR VkResult AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers);
 // clang-format on
 
 template <typename DispatchableType>
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
new file mode 100644
index 0000000..8b816ba
--- /dev/null
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -0,0 +1,431 @@
+/*
+ * 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.
+ */
+
+// WARNING: This file is generated. See ../README.md for instructions.
+
+#include <string.h>
+#include <algorithm>
+#include <log/log.h>
+
+#include "driver.h"
+
+namespace vulkan {
+namespace driver {
+
+namespace {
+
+// clang-format off
+
+VKAPI_ATTR void disabledDestroySurfaceKHR(VkInstance, VkSurfaceKHR, const VkAllocationCallbacks*) {
+    ALOGE("VK_KHR_surface not enabled. vkDestroySurfaceKHR not executed.");
+}
+
+VKAPI_ATTR VkResult disabledGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice, uint32_t, VkSurfaceKHR, VkBool32*) {
+    ALOGE("VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfaceSupportKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult disabledGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice, VkSurfaceKHR, VkSurfaceCapabilitiesKHR*) {
+    ALOGE("VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfaceCapabilitiesKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult disabledGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice, VkSurfaceKHR, uint32_t*, VkSurfaceFormatKHR*) {
+    ALOGE("VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfaceFormatsKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult disabledGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice, VkSurfaceKHR, uint32_t*, VkPresentModeKHR*) {
+    ALOGE("VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfacePresentModesKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult disabledCreateSwapchainKHR(VkDevice, const VkSwapchainCreateInfoKHR*, const VkAllocationCallbacks*, VkSwapchainKHR*) {
+    ALOGE("VK_KHR_swapchain not enabled. vkCreateSwapchainKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult checkedCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain) {
+    return (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) ? CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain) : disabledCreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
+}
+
+VKAPI_ATTR void disabledDestroySwapchainKHR(VkDevice, VkSwapchainKHR, const VkAllocationCallbacks*) {
+    ALOGE("VK_KHR_swapchain not enabled. vkDestroySwapchainKHR not executed.");
+}
+
+VKAPI_ATTR void checkedDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator) {
+    (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) ? DestroySwapchainKHR(device, swapchain, pAllocator) : disabledDestroySwapchainKHR(device, swapchain, pAllocator);
+}
+
+VKAPI_ATTR VkResult disabledGetSwapchainImagesKHR(VkDevice, VkSwapchainKHR, uint32_t*, VkImage*) {
+    ALOGE("VK_KHR_swapchain not enabled. vkGetSwapchainImagesKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult checkedGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages) {
+    return (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) ? GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages) : disabledGetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages);
+}
+
+VKAPI_ATTR VkResult disabledAcquireNextImageKHR(VkDevice, VkSwapchainKHR, uint64_t, VkSemaphore, VkFence, uint32_t*) {
+    ALOGE("VK_KHR_swapchain not enabled. vkAcquireNextImageKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult checkedAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex) {
+    return (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) ? AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex) : disabledAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex);
+}
+
+VKAPI_ATTR VkResult disabledQueuePresentKHR(VkQueue, const VkPresentInfoKHR*) {
+    ALOGE("VK_KHR_swapchain not enabled. vkQueuePresentKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult checkedQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo) {
+    return (GetData(queue).hook_extensions[ProcHook::KHR_swapchain]) ? QueuePresentKHR(queue, pPresentInfo) : disabledQueuePresentKHR(queue, pPresentInfo);
+}
+
+VKAPI_ATTR VkResult disabledCreateAndroidSurfaceKHR(VkInstance, const VkAndroidSurfaceCreateInfoKHR*, const VkAllocationCallbacks*, VkSurfaceKHR*) {
+    ALOGE("VK_KHR_android_surface not enabled. vkCreateAndroidSurfaceKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult disabledCreateDebugReportCallbackEXT(VkInstance, const VkDebugReportCallbackCreateInfoEXT*, const VkAllocationCallbacks*, VkDebugReportCallbackEXT*) {
+    ALOGE("VK_EXT_debug_report not enabled. vkCreateDebugReportCallbackEXT not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR void disabledDestroyDebugReportCallbackEXT(VkInstance, VkDebugReportCallbackEXT, const VkAllocationCallbacks*) {
+    ALOGE("VK_EXT_debug_report not enabled. vkDestroyDebugReportCallbackEXT not executed.");
+}
+
+VKAPI_ATTR void disabledDebugReportMessageEXT(VkInstance, VkDebugReportFlagsEXT, VkDebugReportObjectTypeEXT, uint64_t, size_t, int32_t, const char*, const char*) {
+    ALOGE("VK_EXT_debug_report not enabled. vkDebugReportMessageEXT not executed.");
+}
+
+// clang-format on
+
+const ProcHook g_proc_hooks[] = {
+    // clang-format off
+    {
+        "vkAcquireImageANDROID",
+        ProcHook::DEVICE,
+        ProcHook::ANDROID_native_buffer,
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkAcquireNextImageKHR",
+        ProcHook::DEVICE,
+        ProcHook::KHR_swapchain,
+        reinterpret_cast<PFN_vkVoidFunction>(AcquireNextImageKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledAcquireNextImageKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(checkedAcquireNextImageKHR),
+    },
+    {
+        "vkAllocateCommandBuffers",
+        ProcHook::DEVICE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(AllocateCommandBuffers),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkCreateAndroidSurfaceKHR",
+        ProcHook::INSTANCE,
+        ProcHook::KHR_android_surface,
+        reinterpret_cast<PFN_vkVoidFunction>(CreateAndroidSurfaceKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledCreateAndroidSurfaceKHR),
+        nullptr,
+    },
+    {
+        "vkCreateDebugReportCallbackEXT",
+        ProcHook::INSTANCE,
+        ProcHook::EXT_debug_report,
+        reinterpret_cast<PFN_vkVoidFunction>(CreateDebugReportCallbackEXT),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledCreateDebugReportCallbackEXT),
+        nullptr,
+    },
+    {
+        "vkCreateDevice",
+        ProcHook::INSTANCE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(CreateDevice),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkCreateInstance",
+        ProcHook::GLOBAL,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(CreateInstance),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkCreateSwapchainKHR",
+        ProcHook::DEVICE,
+        ProcHook::KHR_swapchain,
+        reinterpret_cast<PFN_vkVoidFunction>(CreateSwapchainKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledCreateSwapchainKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(checkedCreateSwapchainKHR),
+    },
+    {
+        "vkDebugReportMessageEXT",
+        ProcHook::INSTANCE,
+        ProcHook::EXT_debug_report,
+        reinterpret_cast<PFN_vkVoidFunction>(DebugReportMessageEXT),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledDebugReportMessageEXT),
+        nullptr,
+    },
+    {
+        "vkDestroyDebugReportCallbackEXT",
+        ProcHook::INSTANCE,
+        ProcHook::EXT_debug_report,
+        reinterpret_cast<PFN_vkVoidFunction>(DestroyDebugReportCallbackEXT),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledDestroyDebugReportCallbackEXT),
+        nullptr,
+    },
+    {
+        "vkDestroyDevice",
+        ProcHook::DEVICE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkDestroyInstance",
+        ProcHook::INSTANCE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkDestroySurfaceKHR",
+        ProcHook::INSTANCE,
+        ProcHook::KHR_surface,
+        reinterpret_cast<PFN_vkVoidFunction>(DestroySurfaceKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledDestroySurfaceKHR),
+        nullptr,
+    },
+    {
+        "vkDestroySwapchainKHR",
+        ProcHook::DEVICE,
+        ProcHook::KHR_swapchain,
+        reinterpret_cast<PFN_vkVoidFunction>(DestroySwapchainKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledDestroySwapchainKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(checkedDestroySwapchainKHR),
+    },
+    {
+        "vkEnumerateDeviceExtensionProperties",
+        ProcHook::INSTANCE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceExtensionProperties),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkEnumerateInstanceExtensionProperties",
+        ProcHook::GLOBAL,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkEnumeratePhysicalDevices",
+        ProcHook::INSTANCE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkGetDeviceProcAddr",
+        ProcHook::DEVICE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkGetDeviceQueue",
+        ProcHook::DEVICE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkGetInstanceProcAddr",
+        ProcHook::INSTANCE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkGetPhysicalDeviceSurfaceCapabilitiesKHR",
+        ProcHook::INSTANCE,
+        ProcHook::KHR_surface,
+        reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceCapabilitiesKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledGetPhysicalDeviceSurfaceCapabilitiesKHR),
+        nullptr,
+    },
+    {
+        "vkGetPhysicalDeviceSurfaceFormatsKHR",
+        ProcHook::INSTANCE,
+        ProcHook::KHR_surface,
+        reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceFormatsKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledGetPhysicalDeviceSurfaceFormatsKHR),
+        nullptr,
+    },
+    {
+        "vkGetPhysicalDeviceSurfacePresentModesKHR",
+        ProcHook::INSTANCE,
+        ProcHook::KHR_surface,
+        reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfacePresentModesKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledGetPhysicalDeviceSurfacePresentModesKHR),
+        nullptr,
+    },
+    {
+        "vkGetPhysicalDeviceSurfaceSupportKHR",
+        ProcHook::INSTANCE,
+        ProcHook::KHR_surface,
+        reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceSupportKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledGetPhysicalDeviceSurfaceSupportKHR),
+        nullptr,
+    },
+    {
+        "vkGetSwapchainGrallocUsageANDROID",
+        ProcHook::DEVICE,
+        ProcHook::ANDROID_native_buffer,
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkGetSwapchainImagesKHR",
+        ProcHook::DEVICE,
+        ProcHook::KHR_swapchain,
+        reinterpret_cast<PFN_vkVoidFunction>(GetSwapchainImagesKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledGetSwapchainImagesKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(checkedGetSwapchainImagesKHR),
+    },
+    {
+        "vkQueuePresentKHR",
+        ProcHook::DEVICE,
+        ProcHook::KHR_swapchain,
+        reinterpret_cast<PFN_vkVoidFunction>(QueuePresentKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledQueuePresentKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(checkedQueuePresentKHR),
+    },
+    {
+        "vkQueueSignalReleaseImageANDROID",
+        ProcHook::DEVICE,
+        ProcHook::ANDROID_native_buffer,
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    // clang-format on
+};
+
+}  // anonymous
+
+const ProcHook* GetProcHook(const char* name) {
+    const auto& begin = g_proc_hooks;
+    const auto& end =
+        g_proc_hooks + sizeof(g_proc_hooks) / sizeof(g_proc_hooks[0]);
+    const auto hook = std::lower_bound(
+        begin, end, name,
+        [](const ProcHook& e, const char* n) { return strcmp(e.name, n) < 0; });
+    return (hook < end && strcmp(hook->name, name) == 0) ? hook : nullptr;
+}
+
+ProcHook::Extension GetProcHookExtension(const char* name) {
+    // clang-format off
+    if (strcmp(name, "VK_ANDROID_native_buffer") == 0) return ProcHook::ANDROID_native_buffer;
+    if (strcmp(name, "VK_EXT_debug_report") == 0) return ProcHook::EXT_debug_report;
+    if (strcmp(name, "VK_KHR_android_surface") == 0) return ProcHook::KHR_android_surface;
+    if (strcmp(name, "VK_KHR_surface") == 0) return ProcHook::KHR_surface;
+    if (strcmp(name, "VK_KHR_swapchain") == 0) return ProcHook::KHR_swapchain;
+    // clang-format on
+    return ProcHook::EXTENSION_UNKNOWN;
+}
+
+#define UNLIKELY(expr) __builtin_expect((expr), 0)
+
+#define INIT_PROC(obj, proc)                                           \
+    do {                                                               \
+        data.driver.proc =                                             \
+            reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \
+        if (UNLIKELY(!data.driver.proc)) {                             \
+            ALOGE("missing " #obj " proc: vk" #proc);                  \
+            success = false;                                           \
+        }                                                              \
+    } while (0)
+
+#define INIT_PROC_EXT(ext, obj, proc)           \
+    do {                                        \
+        if (data.hal_extensions[ProcHook::ext]) \
+            INIT_PROC(obj, proc);               \
+    } while (0)
+
+bool InitDriverTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc) {
+    auto& data = GetData(instance);
+    bool success = true;
+
+    // clang-format off
+    INIT_PROC(instance, DestroyInstance);
+    INIT_PROC(instance, EnumeratePhysicalDevices);
+    INIT_PROC(instance, GetInstanceProcAddr);
+    INIT_PROC(instance, CreateDevice);
+    INIT_PROC(instance, EnumerateDeviceLayerProperties);
+    INIT_PROC(instance, EnumerateDeviceExtensionProperties);
+    INIT_PROC_EXT(EXT_debug_report, instance, CreateDebugReportCallbackEXT);
+    INIT_PROC_EXT(EXT_debug_report, instance, DestroyDebugReportCallbackEXT);
+    INIT_PROC_EXT(EXT_debug_report, instance, DebugReportMessageEXT);
+    // clang-format on
+
+    return success;
+}
+
+bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc) {
+    auto& data = GetData(dev);
+    bool success = true;
+
+    // clang-format off
+    INIT_PROC(dev, GetDeviceProcAddr);
+    INIT_PROC(dev, DestroyDevice);
+    INIT_PROC(dev, GetDeviceQueue);
+    INIT_PROC(dev, CreateImage);
+    INIT_PROC(dev, DestroyImage);
+    INIT_PROC(dev, AllocateCommandBuffers);
+    INIT_PROC_EXT(ANDROID_native_buffer, dev, GetSwapchainGrallocUsageANDROID);
+    INIT_PROC_EXT(ANDROID_native_buffer, dev, AcquireImageANDROID);
+    INIT_PROC_EXT(ANDROID_native_buffer, dev, QueueSignalReleaseImageANDROID);
+    // clang-format on
+
+    return success;
+}
+
+}  // namespace driver
+}  // namespace vulkan
+
+// clang-format on
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
new file mode 100644
index 0000000..1eb7d79
--- /dev/null
+++ b/vulkan/libvulkan/driver_gen.h
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+// WARNING: This file is generated. See ../README.md for instructions.
+
+#ifndef LIBVULKAN_DRIVER_GEN_H
+#define LIBVULKAN_DRIVER_GEN_H
+
+#include <vulkan/vulkan.h>
+#include <vulkan/vk_android_native_buffer.h>
+
+namespace vulkan {
+namespace driver {
+
+struct ProcHook {
+    enum Type {
+        GLOBAL,
+        INSTANCE,
+        DEVICE,
+    };
+    enum Extension {
+        ANDROID_native_buffer,
+        EXT_debug_report,
+        KHR_android_surface,
+        KHR_surface,
+        KHR_swapchain,
+
+        EXTENSION_CORE,  // valid bit
+        EXTENSION_COUNT,
+        EXTENSION_UNKNOWN,
+    };
+
+    const char* name;
+    Type type;
+    Extension extension;
+
+    PFN_vkVoidFunction proc;
+    PFN_vkVoidFunction disabled_proc;  // nullptr for global hooks
+    PFN_vkVoidFunction checked_proc;   // nullptr for global/instance hooks
+};
+
+struct InstanceDriverTable {
+    // clang-format off
+    PFN_vkDestroyInstance DestroyInstance;
+    PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices;
+    PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
+    PFN_vkCreateDevice CreateDevice;
+    PFN_vkEnumerateDeviceLayerProperties EnumerateDeviceLayerProperties;
+    PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;
+    PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
+    PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
+    PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
+    // clang-format on
+};
+
+struct DeviceDriverTable {
+    // clang-format off
+    PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
+    PFN_vkDestroyDevice DestroyDevice;
+    PFN_vkGetDeviceQueue GetDeviceQueue;
+    PFN_vkCreateImage CreateImage;
+    PFN_vkDestroyImage DestroyImage;
+    PFN_vkAllocateCommandBuffers AllocateCommandBuffers;
+    PFN_vkGetSwapchainGrallocUsageANDROID GetSwapchainGrallocUsageANDROID;
+    PFN_vkAcquireImageANDROID AcquireImageANDROID;
+    PFN_vkQueueSignalReleaseImageANDROID QueueSignalReleaseImageANDROID;
+    // clang-format on
+};
+
+const ProcHook* GetProcHook(const char* name);
+ProcHook::Extension GetProcHookExtension(const char* name);
+
+bool InitDriverTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc);
+bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc);
+
+}  // namespace driver
+}  // namespace vulkan
+
+#endif  // LIBVULKAN_DRIVER_TABLE_H
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index aec0fd0..6b53a9a 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -16,7 +16,7 @@
 
 // #define LOG_NDEBUG 0
 
-#include "loader.h"
+#include "layers_extensions.h"
 #include <alloca.h>
 #include <dirent.h>
 #include <dlfcn.h>
@@ -28,8 +28,6 @@
 #include <log/log.h>
 #include <vulkan/vulkan_loader_data.h>
 
-using namespace vulkan;
-
 // TODO(jessehall): The whole way we deal with extensions is pretty hokey, and
 // not a good long-term solution. Having a hard-coded enum of extensions is
 // bad, of course. Representing sets of extensions (requested, supported, etc.)
@@ -50,12 +48,13 @@
 // 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;
 };
-}  // namespace vulkan
 
 namespace {
 
@@ -341,8 +340,6 @@
 
 }  // anonymous namespace
 
-namespace vulkan {
-
 void DiscoverLayers() {
     if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0))
         DiscoverLayersInDirectory("/data/local/debug/vulkan");
@@ -425,22 +422,5 @@
                         }) != layer_->extensions.cend();
 }
 
-InstanceExtension InstanceExtensionFromName(const char* name) {
-    if (strcmp(name, VK_KHR_SURFACE_EXTENSION_NAME) == 0)
-        return kKHR_surface;
-    if (strcmp(name, VK_KHR_ANDROID_SURFACE_EXTENSION_NAME) == 0)
-        return kKHR_android_surface;
-    if (strcmp(name, VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0)
-        return kEXT_debug_report;
-    return kInstanceExtensionCount;
-}
-
-DeviceExtension DeviceExtensionFromName(const char* name) {
-    if (strcmp(name, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0)
-        return kKHR_swapchain;
-    if (strcmp(name, VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME) == 0)
-        return kANDROID_native_buffer;
-    return kDeviceExtensionCount;
-}
-
+}  // namespace api
 }  // namespace vulkan
diff --git a/vulkan/libvulkan/layers_extensions.h b/vulkan/libvulkan/layers_extensions.h
new file mode 100644
index 0000000..7e7bfd3
--- /dev/null
+++ b/vulkan/libvulkan/layers_extensions.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015 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.
+ */
+
+#ifndef LIBVULKAN_LAYERS_EXTENSIONS_H
+#define LIBVULKAN_LAYERS_EXTENSIONS_H 1
+
+#include <vulkan/vulkan.h>
+
+namespace vulkan {
+namespace api {
+
+struct Layer;
+class LayerRef {
+   public:
+    LayerRef(Layer* layer);
+    LayerRef(LayerRef&& other);
+    ~LayerRef();
+    LayerRef(const LayerRef&) = delete;
+    LayerRef& operator=(const LayerRef&) = delete;
+
+    const char* GetName() const;
+    uint32_t GetSpecVersion();
+
+    // provides bool-like behavior
+    operator const Layer*() const { return layer_; }
+
+    PFN_vkGetInstanceProcAddr GetGetInstanceProcAddr() const;
+    PFN_vkGetDeviceProcAddr GetGetDeviceProcAddr() const;
+
+    bool SupportsExtension(const char* name) const;
+
+   private:
+    Layer* layer_;
+};
+
+void DiscoverLayers();
+uint32_t EnumerateInstanceLayers(uint32_t count, VkLayerProperties* properties);
+uint32_t EnumerateDeviceLayers(uint32_t count, VkLayerProperties* properties);
+void GetInstanceLayerExtensions(const char* name,
+                                const VkExtensionProperties** properties,
+                                uint32_t* count);
+void GetDeviceLayerExtensions(const char* name,
+                              const VkExtensionProperties** properties,
+                              uint32_t* count);
+LayerRef GetInstanceLayerRef(const char* name);
+LayerRef GetDeviceLayerRef(const char* name);
+
+}  // namespace api
+}  // namespace vulkan
+
+#endif  // LIBVULKAN_LAYERS_EXTENSIONS_H
diff --git a/vulkan/libvulkan/loader.cpp b/vulkan/libvulkan/loader.cpp
deleted file mode 100644
index 65b09db..0000000
--- a/vulkan/libvulkan/loader.cpp
+++ /dev/null
@@ -1,1045 +0,0 @@
-/*
- * Copyright 2015 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.
- */
-
-// module header
-#include "loader.h"
-#include "driver.h"
-// standard C headers
-#include <dirent.h>
-#include <dlfcn.h>
-#include <inttypes.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/prctl.h>
-// standard C++ headers
-#include <algorithm>
-#include <mutex>
-#include <sstream>
-#include <string>
-#include <unordered_map>
-#include <vector>
-// platform/library headers
-#include <cutils/properties.h>
-#include <hardware/hwvulkan.h>
-#include <log/log.h>
-#include <vulkan/vulkan_loader_data.h>
-#include <vulkan/vk_layer_interface.h>
-
-// #define ENABLE_ALLOC_CALLSTACKS 1
-#if ENABLE_ALLOC_CALLSTACKS
-#include <utils/CallStack.h>
-#define ALOGD_CALLSTACK(...)                             \
-    do {                                                 \
-        ALOGD(__VA_ARGS__);                              \
-        android::CallStack callstack;                    \
-        callstack.update();                              \
-        callstack.log(LOG_TAG, ANDROID_LOG_DEBUG, "  "); \
-    } while (false)
-#else
-#define ALOGD_CALLSTACK(...) \
-    do {                     \
-    } while (false)
-#endif
-
-using namespace vulkan;
-
-static const uint32_t kMaxPhysicalDevices = 4;
-
-namespace {
-
-// ----------------------------------------------------------------------------
-
-// Standard-library allocator that delegates to VkAllocationCallbacks.
-//
-// TODO(jessehall): This class currently always uses
-// VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE. The scope to use could be a template
-// parameter or a constructor parameter. The former would help catch bugs
-// where we use the wrong scope, e.g. adding a command-scope string to an
-// instance-scope vector. But that might also be pretty annoying to deal with.
-template <class T>
-class CallbackAllocator {
-   public:
-    typedef T value_type;
-
-    CallbackAllocator(const VkAllocationCallbacks* alloc_input)
-        : alloc(alloc_input) {}
-
-    template <class T2>
-    CallbackAllocator(const CallbackAllocator<T2>& other)
-        : alloc(other.alloc) {}
-
-    T* allocate(std::size_t n) {
-        void* mem =
-            alloc->pfnAllocation(alloc->pUserData, n * sizeof(T), alignof(T),
-                                 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
-        if (!mem)
-            throw std::bad_alloc();
-        return static_cast<T*>(mem);
-    }
-
-    void deallocate(T* array, std::size_t /*n*/) noexcept {
-        alloc->pfnFree(alloc->pUserData, array);
-    }
-
-    const VkAllocationCallbacks* alloc;
-};
-// These are needed in order to move Strings
-template <class T>
-bool operator==(const CallbackAllocator<T>& alloc1,
-                const CallbackAllocator<T>& alloc2) {
-    return alloc1.alloc == alloc2.alloc;
-}
-template <class T>
-bool operator!=(const CallbackAllocator<T>& alloc1,
-                const CallbackAllocator<T>& alloc2) {
-    return !(alloc1 == alloc2);
-}
-
-template <class T>
-using Vector = std::vector<T, CallbackAllocator<T>>;
-
-typedef std::basic_string<char, std::char_traits<char>, CallbackAllocator<char>>
-    String;
-
-// ----------------------------------------------------------------------------
-
-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);
-    ALOGD_CALLSTACK("Allocate: size=%zu align=%zu => (%d) %p", size, alignment,
-                    ret, ptr);
-    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.
-    // Right now the loader 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) {
-    ALOGD_CALLSTACK("Free: %p", ptr);
-    free(ptr);
-}
-
-const VkAllocationCallbacks kDefaultAllocCallbacks = {
-    .pUserData = nullptr,
-    .pfnAllocation = DefaultAllocate,
-    .pfnReallocation = DefaultReallocate,
-    .pfnFree = DefaultFree,
-};
-
-// ----------------------------------------------------------------------------
-// Global Data and Initialization
-
-hwvulkan_device_t* g_hwdevice = nullptr;
-InstanceExtensionSet g_driver_instance_extensions;
-
-void LoadVulkanHAL() {
-    static const hwvulkan_module_t* module;
-    int result =
-        hw_get_module("vulkan", reinterpret_cast<const hw_module_t**>(&module));
-    if (result != 0) {
-        ALOGE("failed to load vulkan hal: %s (%d)", strerror(-result), result);
-        return;
-    }
-    result = module->common.methods->open(
-        &module->common, HWVULKAN_DEVICE_0,
-        reinterpret_cast<hw_device_t**>(&g_hwdevice));
-    if (result != 0) {
-        ALOGE("failed to open vulkan driver: %s (%d)", strerror(-result),
-              result);
-        module = nullptr;
-        return;
-    }
-
-    VkResult vkresult;
-    uint32_t count;
-    if ((vkresult = g_hwdevice->EnumerateInstanceExtensionProperties(
-             nullptr, &count, nullptr)) != VK_SUCCESS) {
-        ALOGE("driver EnumerateInstanceExtensionProperties failed: %d",
-              vkresult);
-        g_hwdevice->common.close(&g_hwdevice->common);
-        g_hwdevice = nullptr;
-        module = nullptr;
-        return;
-    }
-    VkExtensionProperties* extensions = static_cast<VkExtensionProperties*>(
-        alloca(count * sizeof(VkExtensionProperties)));
-    if ((vkresult = g_hwdevice->EnumerateInstanceExtensionProperties(
-             nullptr, &count, extensions)) != VK_SUCCESS) {
-        ALOGE("driver EnumerateInstanceExtensionProperties failed: %d",
-              vkresult);
-        g_hwdevice->common.close(&g_hwdevice->common);
-        g_hwdevice = nullptr;
-        module = nullptr;
-        return;
-    }
-    ALOGV_IF(count > 0, "Driver-supported instance extensions:");
-    for (uint32_t i = 0; i < count; i++) {
-        ALOGV("  %s (v%u)", extensions[i].extensionName,
-              extensions[i].specVersion);
-        InstanceExtension id =
-            InstanceExtensionFromName(extensions[i].extensionName);
-        if (id != kInstanceExtensionCount)
-            g_driver_instance_extensions.set(id);
-    }
-    // Ignore driver attempts to support loader extensions
-    g_driver_instance_extensions.reset(kKHR_surface);
-    g_driver_instance_extensions.reset(kKHR_android_surface);
-}
-
-// -----------------------------------------------------------------------------
-
-struct Instance {
-    Instance(const VkAllocationCallbacks* alloc_callbacks)
-        : base{{}, *alloc_callbacks},
-          alloc(&base.allocator),
-          num_physical_devices(0) {
-        memset(physical_devices, 0, sizeof(physical_devices));
-        enabled_extensions.reset();
-        memset(&drv.dispatch, 0, sizeof(drv.dispatch));
-    }
-
-    ~Instance() {}
-
-    driver::InstanceData base;
-
-    const VkAllocationCallbacks* alloc;
-    uint32_t num_physical_devices;
-    VkPhysicalDevice physical_devices_top[kMaxPhysicalDevices];
-    VkPhysicalDevice physical_devices[kMaxPhysicalDevices];
-    DeviceExtensionSet physical_device_driver_extensions[kMaxPhysicalDevices];
-
-    DebugReportCallbackList debug_report_callbacks;
-    InstanceExtensionSet enabled_extensions;
-
-    struct {
-        DriverDispatchTable dispatch;
-    } drv;  // may eventually be an array
-};
-
-struct Device {
-    Device(Instance* instance_)
-        : base{{}, *instance_->alloc}, instance(instance_) {
-        enabled_extensions.reset();
-    }
-
-    driver::DeviceData base;
-
-    Instance* instance;
-    PFN_vkGetDeviceProcAddr get_device_proc_addr;
-    DeviceExtensionSet enabled_extensions;
-};
-
-template <typename THandle>
-struct HandleTraits {};
-template <>
-struct HandleTraits<VkInstance> {
-    typedef Instance LoaderObjectType;
-};
-template <>
-struct HandleTraits<VkPhysicalDevice> {
-    typedef Instance LoaderObjectType;
-};
-template <>
-struct HandleTraits<VkDevice> {
-    typedef Device LoaderObjectType;
-};
-template <>
-struct HandleTraits<VkQueue> {
-    typedef Device LoaderObjectType;
-};
-template <>
-struct HandleTraits<VkCommandBuffer> {
-    typedef Device LoaderObjectType;
-};
-
-template <typename THandle>
-typename HandleTraits<THandle>::LoaderObjectType& GetDispatchParent(
-    THandle handle) {
-    // TODO(jessehall): Make Instance and Device POD types (by removing the
-    // non-default constructors), so that offsetof is actually legal to use.
-    // The specific case we're using here is safe in gcc/clang (and probably
-    // most other C++ compilers), but isn't guaranteed by C++.
-    typedef typename HandleTraits<THandle>::LoaderObjectType ObjectType;
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Winvalid-offsetof"
-    const size_t kBaseOffset = offsetof(ObjectType, base);
-#pragma clang diagnostic pop
-
-    const auto& base = driver::GetData(handle);
-    uintptr_t base_addr = reinterpret_cast<uintptr_t>(&base);
-    uintptr_t object_addr = base_addr - kBaseOffset;
-    return *reinterpret_cast<ObjectType*>(object_addr);
-}
-
-// -----------------------------------------------------------------------------
-
-void DestroyDevice(Device* device, VkDevice vkdevice) {
-    const auto& instance = *device->instance;
-
-    if (vkdevice != VK_NULL_HANDLE)
-        instance.drv.dispatch.DestroyDevice(vkdevice, instance.alloc);
-
-    device->~Device();
-    instance.alloc->pfnFree(instance.alloc->pUserData, device);
-}
-
-/*
- * This function will return the pNext pointer of any
- * CreateInfo extensions that are not loader extensions.
- * This is used to skip past the loader extensions prepended
- * to the list during CreateInstance and CreateDevice.
- */
-void* StripCreateExtensions(const void* pNext) {
-    VkLayerInstanceCreateInfo* create_info =
-        const_cast<VkLayerInstanceCreateInfo*>(
-            static_cast<const VkLayerInstanceCreateInfo*>(pNext));
-
-    while (
-        create_info &&
-        (create_info->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO ||
-         create_info->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO)) {
-        create_info = const_cast<VkLayerInstanceCreateInfo*>(
-            static_cast<const VkLayerInstanceCreateInfo*>(create_info->pNext));
-    }
-
-    return create_info;
-}
-
-// Clean up and deallocate an Instance; called from both the failure paths in
-// CreateInstance_Top as well as from DestroyInstance_Top. This function does
-// not call down the dispatch chain; that should be done before calling this
-// function, iff the lower vkCreateInstance call has been made and returned
-// successfully.
-void DestroyInstance(Instance* instance,
-                     const VkAllocationCallbacks* allocator,
-                     VkInstance vkinstance) {
-    if (vkinstance != VK_NULL_HANDLE && instance->drv.dispatch.DestroyInstance)
-        instance->drv.dispatch.DestroyInstance(vkinstance, allocator);
-
-    instance->~Instance();
-    allocator->pfnFree(allocator->pUserData, instance);
-}
-
-}  // anonymous namespace
-
-namespace vulkan {
-
-// -----------------------------------------------------------------------------
-// "Bottom" functions. These are called at the end of the instance dispatch
-// chain.
-
-VkResult CreateInstance_Bottom(const VkInstanceCreateInfo* create_info,
-                               const VkAllocationCallbacks* allocator,
-                               VkInstance* vkinstance) {
-    VkResult result;
-
-    if (!allocator)
-        allocator = &kDefaultAllocCallbacks;
-
-    void* instance_mem = allocator->pfnAllocation(
-        allocator->pUserData, sizeof(Instance), alignof(Instance),
-        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
-    if (!instance_mem)
-        return VK_ERROR_OUT_OF_HOST_MEMORY;
-    Instance& instance = *new (instance_mem) Instance(allocator);
-
-    // Check that all enabled extensions are supported
-    uint32_t num_driver_extensions = 0;
-    for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) {
-        const char* name = create_info->ppEnabledExtensionNames[i];
-        InstanceExtension id = InstanceExtensionFromName(name);
-        if (id != kInstanceExtensionCount) {
-            if (g_driver_instance_extensions[id]) {
-                num_driver_extensions++;
-                instance.enabled_extensions.set(id);
-                continue;
-            }
-            if (id == kKHR_surface || id == kKHR_android_surface) {
-                instance.enabled_extensions.set(id);
-                continue;
-            }
-            // The loader natively supports debug report.
-            if (id == kEXT_debug_report) {
-                continue;
-            }
-        }
-    }
-
-    VkInstanceCreateInfo driver_create_info = *create_info;
-    driver_create_info.pNext = StripCreateExtensions(create_info->pNext);
-    driver_create_info.enabledLayerCount = 0;
-    driver_create_info.ppEnabledLayerNames = nullptr;
-    driver_create_info.enabledExtensionCount = 0;
-    driver_create_info.ppEnabledExtensionNames = nullptr;
-    if (num_driver_extensions > 0) {
-        const char** names = static_cast<const char**>(
-            alloca(num_driver_extensions * sizeof(char*)));
-        for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) {
-            const char* name = create_info->ppEnabledExtensionNames[i];
-            InstanceExtension id = InstanceExtensionFromName(name);
-            if (id != kInstanceExtensionCount) {
-                if (g_driver_instance_extensions[id]) {
-                    names[driver_create_info.enabledExtensionCount++] = name;
-                    continue;
-                }
-            }
-        }
-        driver_create_info.ppEnabledExtensionNames = names;
-        ALOG_ASSERT(
-            driver_create_info.enabledExtensionCount == num_driver_extensions,
-            "counted enabled driver instance extensions twice and got "
-            "different answers!");
-    }
-
-    VkInstance drv_instance;
-    result = g_hwdevice->CreateInstance(&driver_create_info, instance.alloc,
-                                        &drv_instance);
-    if (result != VK_SUCCESS) {
-        DestroyInstance(&instance, allocator, VK_NULL_HANDLE);
-        return result;
-    }
-
-    if (!driver::SetData(drv_instance, instance.base)) {
-        DestroyInstance(&instance, allocator, drv_instance);
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    if (!LoadDriverDispatchTable(drv_instance, g_hwdevice->GetInstanceProcAddr,
-                                 instance.enabled_extensions,
-                                 instance.drv.dispatch)) {
-        DestroyInstance(&instance, allocator, drv_instance);
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    uint32_t num_physical_devices = 0;
-    result = instance.drv.dispatch.EnumeratePhysicalDevices(
-        drv_instance, &num_physical_devices, nullptr);
-    if (result != VK_SUCCESS) {
-        DestroyInstance(&instance, allocator, drv_instance);
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-    num_physical_devices = std::min(num_physical_devices, kMaxPhysicalDevices);
-    result = instance.drv.dispatch.EnumeratePhysicalDevices(
-        drv_instance, &num_physical_devices, instance.physical_devices);
-    if (result != VK_SUCCESS) {
-        DestroyInstance(&instance, allocator, drv_instance);
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    Vector<VkExtensionProperties> extensions(
-        Vector<VkExtensionProperties>::allocator_type(instance.alloc));
-    for (uint32_t i = 0; i < num_physical_devices; i++) {
-        if (!driver::SetData(instance.physical_devices[i], instance.base)) {
-            DestroyInstance(&instance, allocator, drv_instance);
-            return VK_ERROR_INITIALIZATION_FAILED;
-        }
-
-        uint32_t count;
-        if ((result = instance.drv.dispatch.EnumerateDeviceExtensionProperties(
-                 instance.physical_devices[i], nullptr, &count, nullptr)) !=
-            VK_SUCCESS) {
-            ALOGW("driver EnumerateDeviceExtensionProperties(%u) failed: %d", i,
-                  result);
-            continue;
-        }
-        try {
-            extensions.resize(count);
-        } catch (std::bad_alloc&) {
-            ALOGE("instance creation failed: out of memory");
-            DestroyInstance(&instance, allocator, drv_instance);
-            return VK_ERROR_OUT_OF_HOST_MEMORY;
-        }
-        if ((result = instance.drv.dispatch.EnumerateDeviceExtensionProperties(
-                 instance.physical_devices[i], nullptr, &count,
-                 extensions.data())) != VK_SUCCESS) {
-            ALOGW("driver EnumerateDeviceExtensionProperties(%u) failed: %d", i,
-                  result);
-            continue;
-        }
-        ALOGV_IF(count > 0, "driver gpu[%u] supports extensions:", i);
-        for (const auto& extension : extensions) {
-            ALOGV("  %s (v%u)", extension.extensionName, extension.specVersion);
-            DeviceExtension id =
-                DeviceExtensionFromName(extension.extensionName);
-            if (id == kDeviceExtensionCount) {
-                ALOGW("driver gpu[%u] extension '%s' unknown to loader", i,
-                      extension.extensionName);
-            } else {
-                instance.physical_device_driver_extensions[i].set(id);
-            }
-        }
-        // Ignore driver attempts to support loader extensions
-        instance.physical_device_driver_extensions[i].reset(kKHR_swapchain);
-    }
-    instance.num_physical_devices = num_physical_devices;
-
-    *vkinstance = drv_instance;
-
-    return VK_SUCCESS;
-}
-
-VkResult CreateAndroidSurfaceKHR_Disabled(VkInstance,
-                                          const VkAndroidSurfaceCreateInfoKHR*,
-                                          const VkAllocationCallbacks*,
-                                          VkSurfaceKHR*) {
-    ALOGE(
-        "VK_KHR_android_surface not enabled. vkCreateAndroidSurfaceKHR not "
-        "executed.");
-
-    return VK_SUCCESS;
-}
-
-void DestroySurfaceKHR_Disabled(VkInstance,
-                                VkSurfaceKHR,
-                                const VkAllocationCallbacks*) {
-    ALOGE("VK_KHR_surface not enabled. vkDestroySurfaceKHR not executed.");
-}
-
-VkResult GetPhysicalDeviceSurfaceSupportKHR_Disabled(VkPhysicalDevice,
-                                                     uint32_t,
-                                                     VkSurfaceKHR,
-                                                     VkBool32*) {
-    ALOGE(
-        "VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfaceSupportKHR not "
-        "executed.");
-
-    return VK_SUCCESS;
-}
-
-VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR_Disabled(
-    VkPhysicalDevice,
-    VkSurfaceKHR,
-    VkSurfaceCapabilitiesKHR*) {
-    ALOGE(
-        "VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfaceapabilitiesKHR "
-        "not executed.");
-
-    return VK_SUCCESS;
-}
-
-VkResult GetPhysicalDeviceSurfaceFormatsKHR_Disabled(VkPhysicalDevice,
-                                                     VkSurfaceKHR,
-                                                     uint32_t*,
-                                                     VkSurfaceFormatKHR*) {
-    ALOGE(
-        "VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfaceFormatsKHR not "
-        "executed.");
-
-    return VK_SUCCESS;
-}
-
-VkResult GetPhysicalDeviceSurfacePresentModesKHR_Disabled(VkPhysicalDevice,
-                                                          VkSurfaceKHR,
-                                                          uint32_t*,
-                                                          VkPresentModeKHR*) {
-    ALOGE(
-        "VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfacePresentModesKHR "
-        "not executed.");
-
-    return VK_SUCCESS;
-}
-
-PFN_vkVoidFunction GetInstanceProcAddr_Bottom(VkInstance vkinstance,
-                                              const char* name) {
-    PFN_vkVoidFunction pfn;
-
-    if (vkinstance) {
-        Instance& instance = GetDispatchParent(vkinstance);
-        if (!instance.enabled_extensions[kKHR_android_surface]) {
-            // KHR_android_surface is not enabled, use error stubs instead
-            if (strcmp(name, "vkCreateAndroidSurfaceKHR") == 0) {
-                return reinterpret_cast<PFN_vkVoidFunction>(
-                    CreateAndroidSurfaceKHR_Disabled);
-            }
-        }
-        if (!instance.enabled_extensions[kKHR_surface]) {
-            // KHR_surface is not enabled, use error stubs instead
-            if (strcmp(name, "vkDestroySurfaceKHR") == 0) {
-                return reinterpret_cast<PFN_vkVoidFunction>(
-                    DestroySurfaceKHR_Disabled);
-            }
-            if (strcmp(name, "vkGetPhysicalDeviceSurfaceSupportKHR") == 0) {
-                return reinterpret_cast<PFN_vkVoidFunction>(
-                    GetPhysicalDeviceSurfaceSupportKHR_Disabled);
-            }
-            if (strcmp(name, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR") ==
-                0) {
-                return reinterpret_cast<PFN_vkVoidFunction>(
-                    GetPhysicalDeviceSurfaceCapabilitiesKHR_Disabled);
-            }
-            if (strcmp(name, "vkGetPhysicalDeviceSurfaceFormatsKHR") == 0) {
-                return reinterpret_cast<PFN_vkVoidFunction>(
-                    GetPhysicalDeviceSurfaceFormatsKHR_Disabled);
-            }
-            if (strcmp(name, "vkGetPhysicalDeviceSurfacePresentModesKHR") ==
-                0) {
-                return reinterpret_cast<PFN_vkVoidFunction>(
-                    GetPhysicalDeviceSurfacePresentModesKHR_Disabled);
-            }
-        }
-    }
-    if ((pfn = GetLoaderBottomProcAddr(name)))
-        return pfn;
-    return g_hwdevice->GetInstanceProcAddr(vkinstance, name);
-}
-
-VkResult EnumeratePhysicalDevices_Bottom(VkInstance vkinstance,
-                                         uint32_t* pdev_count,
-                                         VkPhysicalDevice* pdevs) {
-    Instance& instance = GetDispatchParent(vkinstance);
-    uint32_t count = instance.num_physical_devices;
-    if (pdevs) {
-        count = std::min(count, *pdev_count);
-        std::copy(instance.physical_devices, instance.physical_devices + count,
-                  pdevs);
-    }
-    *pdev_count = count;
-    return VK_SUCCESS;
-}
-
-void GetPhysicalDeviceProperties_Bottom(
-    VkPhysicalDevice pdev,
-    VkPhysicalDeviceProperties* properties) {
-    GetDispatchParent(pdev).drv.dispatch.GetPhysicalDeviceProperties(
-        pdev, properties);
-}
-
-void GetPhysicalDeviceFeatures_Bottom(VkPhysicalDevice pdev,
-                                      VkPhysicalDeviceFeatures* features) {
-    GetDispatchParent(pdev).drv.dispatch.GetPhysicalDeviceFeatures(pdev,
-                                                                   features);
-}
-
-void GetPhysicalDeviceMemoryProperties_Bottom(
-    VkPhysicalDevice pdev,
-    VkPhysicalDeviceMemoryProperties* properties) {
-    GetDispatchParent(pdev).drv.dispatch.GetPhysicalDeviceMemoryProperties(
-        pdev, properties);
-}
-
-void GetPhysicalDeviceQueueFamilyProperties_Bottom(
-    VkPhysicalDevice pdev,
-    uint32_t* pCount,
-    VkQueueFamilyProperties* properties) {
-    GetDispatchParent(pdev).drv.dispatch.GetPhysicalDeviceQueueFamilyProperties(
-        pdev, pCount, properties);
-}
-
-void GetPhysicalDeviceFormatProperties_Bottom(VkPhysicalDevice pdev,
-                                              VkFormat format,
-                                              VkFormatProperties* properties) {
-    GetDispatchParent(pdev).drv.dispatch.GetPhysicalDeviceFormatProperties(
-        pdev, format, properties);
-}
-
-VkResult GetPhysicalDeviceImageFormatProperties_Bottom(
-    VkPhysicalDevice pdev,
-    VkFormat format,
-    VkImageType type,
-    VkImageTiling tiling,
-    VkImageUsageFlags usage,
-    VkImageCreateFlags flags,
-    VkImageFormatProperties* properties) {
-    return GetDispatchParent(pdev)
-        .drv.dispatch.GetPhysicalDeviceImageFormatProperties(
-            pdev, format, type, tiling, usage, flags, properties);
-}
-
-void GetPhysicalDeviceSparseImageFormatProperties_Bottom(
-    VkPhysicalDevice pdev,
-    VkFormat format,
-    VkImageType type,
-    VkSampleCountFlagBits samples,
-    VkImageUsageFlags usage,
-    VkImageTiling tiling,
-    uint32_t* properties_count,
-    VkSparseImageFormatProperties* properties) {
-    GetDispatchParent(pdev)
-        .drv.dispatch.GetPhysicalDeviceSparseImageFormatProperties(
-            pdev, format, type, samples, usage, tiling, properties_count,
-            properties);
-}
-
-VKAPI_ATTR
-VkResult EnumerateDeviceExtensionProperties_Bottom(
-    VkPhysicalDevice pdev,
-    const char* layer_name,
-    uint32_t* properties_count,
-    VkExtensionProperties* properties) {
-    (void)layer_name;
-
-    Instance& instance = GetDispatchParent(pdev);
-
-    size_t gpu_idx = 0;
-    while (instance.physical_devices[gpu_idx] != pdev)
-        gpu_idx++;
-    const DeviceExtensionSet driver_extensions =
-        instance.physical_device_driver_extensions[gpu_idx];
-
-    // We only support VK_KHR_swapchain if the GPU supports
-    // VK_ANDROID_native_buffer
-    VkExtensionProperties* available = static_cast<VkExtensionProperties*>(
-        alloca(kDeviceExtensionCount * sizeof(VkExtensionProperties)));
-    uint32_t num_extensions = 0;
-    if (driver_extensions[kANDROID_native_buffer]) {
-        available[num_extensions++] = VkExtensionProperties{
-            VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_SWAPCHAIN_SPEC_VERSION};
-    }
-
-    if (!properties || *properties_count > num_extensions)
-        *properties_count = num_extensions;
-    if (properties)
-        std::copy(available, available + *properties_count, properties);
-
-    return *properties_count < num_extensions ? VK_INCOMPLETE : VK_SUCCESS;
-}
-
-// This is a no-op, the Top function returns the aggregate layer property
-// data. This is to keep the dispatch generator happy.
-VKAPI_ATTR
-VkResult EnumerateDeviceLayerProperties_Bottom(
-    VkPhysicalDevice /*pdev*/,
-    uint32_t* /*properties_count*/,
-    VkLayerProperties* /*properties*/) {
-    return VK_SUCCESS;
-}
-
-VKAPI_ATTR
-VkResult CreateDevice_Bottom(VkPhysicalDevice gpu,
-                             const VkDeviceCreateInfo* create_info,
-                             const VkAllocationCallbacks* allocator,
-                             VkDevice* device_out) {
-    Instance& instance = GetDispatchParent(gpu);
-
-    // FIXME(jessehall): We don't have good conventions or infrastructure yet to
-    // do better than just using the instance allocator and scope for
-    // everything. See b/26732122.
-    if (true /*!allocator*/)
-        allocator = instance.alloc;
-
-    void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Device),
-                                         alignof(Device),
-                                         VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
-    if (!mem)
-        return VK_ERROR_OUT_OF_HOST_MEMORY;
-    Device* device = new (mem) Device(&instance);
-
-    size_t gpu_idx = 0;
-    while (instance.physical_devices[gpu_idx] != gpu)
-        gpu_idx++;
-
-    VkDeviceCreateInfo driver_create_info = *create_info;
-    driver_create_info.pNext = StripCreateExtensions(create_info->pNext);
-    driver_create_info.enabledLayerCount = 0;
-    driver_create_info.ppEnabledLayerNames = nullptr;
-
-    uint32_t num_driver_extensions = 0;
-    const char** driver_extensions = static_cast<const char**>(
-        alloca(create_info->enabledExtensionCount * sizeof(const char*)));
-    for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) {
-        const char* name = create_info->ppEnabledExtensionNames[i];
-        DeviceExtension id = DeviceExtensionFromName(name);
-        if (id != kDeviceExtensionCount) {
-            if (instance.physical_device_driver_extensions[gpu_idx][id]) {
-                driver_extensions[num_driver_extensions++] = name;
-                device->enabled_extensions.set(id);
-                continue;
-            }
-            // Add the VK_ANDROID_native_buffer extension to the list iff
-            // the VK_KHR_swapchain extension was requested
-            if (id == kKHR_swapchain &&
-                instance.physical_device_driver_extensions
-                    [gpu_idx][kANDROID_native_buffer]) {
-                driver_extensions[num_driver_extensions++] =
-                    VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME;
-                device->enabled_extensions.set(id);
-                continue;
-            }
-        }
-    }
-
-    driver_create_info.enabledExtensionCount = num_driver_extensions;
-    driver_create_info.ppEnabledExtensionNames = driver_extensions;
-    VkDevice drv_device;
-    VkResult result = instance.drv.dispatch.CreateDevice(
-        gpu, &driver_create_info, allocator, &drv_device);
-    if (result != VK_SUCCESS) {
-        DestroyDevice(device, VK_NULL_HANDLE);
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    if (!driver::SetData(drv_device, device->base)) {
-        DestroyDevice(device, drv_device);
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    device->get_device_proc_addr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
-        instance.drv.dispatch.GetDeviceProcAddr(drv_device,
-                                                "vkGetDeviceProcAddr"));
-    *device_out = drv_device;
-    return VK_SUCCESS;
-}
-
-void DestroyInstance_Bottom(VkInstance vkinstance,
-                            const VkAllocationCallbacks* allocator) {
-    Instance& instance = GetDispatchParent(vkinstance);
-
-    VkAllocationCallbacks local_allocator;
-    if (!allocator) {
-        local_allocator = *instance.alloc;
-        allocator = &local_allocator;
-    }
-
-    DestroyInstance(&instance, allocator, vkinstance);
-}
-
-VkResult CreateSwapchainKHR_Disabled(VkDevice,
-                                     const VkSwapchainCreateInfoKHR*,
-                                     const VkAllocationCallbacks*,
-                                     VkSwapchainKHR*) {
-    ALOGE("VK_KHR_swapchain not enabled. vkCreateSwapchainKHR not executed.");
-
-    return VK_SUCCESS;
-}
-
-void DestroySwapchainKHR_Disabled(VkDevice,
-                                  VkSwapchainKHR,
-                                  const VkAllocationCallbacks*) {
-    ALOGE("VK_KHR_swapchain not enabled. vkDestroySwapchainKHR not executed.");
-}
-
-VkResult GetSwapchainImagesKHR_Disabled(VkDevice,
-                                        VkSwapchainKHR,
-                                        uint32_t*,
-                                        VkImage*) {
-    ALOGE(
-        "VK_KHR_swapchain not enabled. vkGetSwapchainImagesKHR not executed.");
-
-    return VK_SUCCESS;
-}
-
-VkResult AcquireNextImageKHR_Disabled(VkDevice,
-                                      VkSwapchainKHR,
-                                      uint64_t,
-                                      VkSemaphore,
-                                      VkFence,
-                                      uint32_t*) {
-    ALOGE("VK_KHR_swapchain not enabled. vkAcquireNextImageKHR not executed.");
-
-    return VK_SUCCESS;
-}
-
-VkResult QueuePresentKHR_Disabled(VkQueue, const VkPresentInfoKHR*) {
-    ALOGE("VK_KHR_swapchain not enabled. vkQueuePresentKHR not executed.");
-
-    return VK_SUCCESS;
-}
-
-PFN_vkVoidFunction GetDeviceProcAddr_Bottom(VkDevice vkdevice,
-                                            const char* name) {
-    if (strcmp(name, "vkCreateDevice") == 0) {
-        return reinterpret_cast<PFN_vkVoidFunction>(CreateDevice_Bottom);
-    }
-
-    Device& device = GetDispatchParent(vkdevice);
-    if (!device.enabled_extensions[kKHR_swapchain]) {
-        if (strcmp(name, "vkCreateSwapchainKHR") == 0) {
-            return reinterpret_cast<PFN_vkVoidFunction>(
-                CreateSwapchainKHR_Disabled);
-        }
-        if (strcmp(name, "vkDestroySwapchainKHR") == 0) {
-            return reinterpret_cast<PFN_vkVoidFunction>(
-                DestroySwapchainKHR_Disabled);
-        }
-        if (strcmp(name, "vkGetSwapchainImagesKHR") == 0) {
-            return reinterpret_cast<PFN_vkVoidFunction>(
-                GetSwapchainImagesKHR_Disabled);
-        }
-        if (strcmp(name, "vkAcquireNextSwapchainImageKHR") == 0) {
-            return reinterpret_cast<PFN_vkVoidFunction>(
-                AcquireNextImageKHR_Disabled);
-        }
-        if (strcmp(name, "vkQueuePresentKHR") == 0) {
-            return reinterpret_cast<PFN_vkVoidFunction>(
-                QueuePresentKHR_Disabled);
-        }
-    }
-
-    // VK_ANDROID_native_buffer should be hidden from applications and layers.
-    // TODO(jessehall): Generate this as part of GetLoaderBottomProcAddr.
-    PFN_vkVoidFunction pfn;
-    if (strcmp(name, "vkGetSwapchainGrallocUsageANDROID") == 0 ||
-        strcmp(name, "vkAcquireImageANDROID") == 0 ||
-        strcmp(name, "vkQueueSignalReleaseImageANDROID") == 0) {
-        return nullptr;
-    }
-    if ((pfn = GetLoaderBottomProcAddr(name)))
-        return pfn;
-    return GetDispatchParent(vkdevice).get_device_proc_addr(vkdevice, name);
-}
-
-void DestroyDevice_Bottom(VkDevice vkdevice, const VkAllocationCallbacks*) {
-    DestroyDevice(&GetDispatchParent(vkdevice), vkdevice);
-}
-
-void GetDeviceQueue_Bottom(VkDevice vkdevice,
-                           uint32_t family,
-                           uint32_t index,
-                           VkQueue* queue_out) {
-    const auto& device = GetDispatchParent(vkdevice);
-    const auto& instance = *device.instance;
-
-    instance.drv.dispatch.GetDeviceQueue(vkdevice, family, index, queue_out);
-    driver::SetData(*queue_out, device.base);
-}
-
-VkResult AllocateCommandBuffers_Bottom(
-    VkDevice vkdevice,
-    const VkCommandBufferAllocateInfo* alloc_info,
-    VkCommandBuffer* cmdbufs) {
-    const auto& device = GetDispatchParent(vkdevice);
-    const auto& instance = *device.instance;
-
-    VkResult result = instance.drv.dispatch.AllocateCommandBuffers(
-        vkdevice, alloc_info, cmdbufs);
-    if (result == VK_SUCCESS) {
-        for (uint32_t i = 0; i < alloc_info->commandBufferCount; i++)
-            driver::SetData(cmdbufs[i], device.base);
-    }
-
-    return result;
-}
-
-// -----------------------------------------------------------------------------
-
-const VkAllocationCallbacks* GetAllocator(VkInstance vkinstance) {
-    return GetDispatchParent(vkinstance).alloc;
-}
-
-const VkAllocationCallbacks* GetAllocator(VkDevice vkdevice) {
-    return GetDispatchParent(vkdevice).instance->alloc;
-}
-
-VkInstance GetDriverInstance(VkInstance instance) {
-    return instance;
-}
-
-const DriverDispatchTable& GetDriverDispatch(VkInstance instance) {
-    return GetDispatchParent(instance).drv.dispatch;
-}
-
-const DriverDispatchTable& GetDriverDispatch(VkDevice device) {
-    return GetDispatchParent(device).instance->drv.dispatch;
-}
-
-const DriverDispatchTable& GetDriverDispatch(VkQueue queue) {
-    return GetDispatchParent(queue).instance->drv.dispatch;
-}
-
-DebugReportCallbackList& GetDebugReportCallbacks(VkInstance instance) {
-    return GetDispatchParent(instance).debug_report_callbacks;
-}
-
-namespace driver {
-
-bool Debuggable() {
-    return (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) >= 0);
-}
-
-bool OpenHAL() {
-    if (!g_hwdevice)
-        LoadVulkanHAL();
-
-    return (g_hwdevice != nullptr);
-}
-
-const VkAllocationCallbacks& GetDefaultAllocator() {
-    return kDefaultAllocCallbacks;
-}
-
-PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName) {
-    return GetInstanceProcAddr_Bottom(instance, pName);
-}
-
-PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName) {
-    return GetDeviceProcAddr_Bottom(device, pName);
-}
-
-VkResult EnumerateInstanceExtensionProperties(
-    const char* pLayerName,
-    uint32_t* pPropertyCount,
-    VkExtensionProperties* pProperties) {
-    (void)pLayerName;
-
-    VkExtensionProperties* available = static_cast<VkExtensionProperties*>(
-        alloca(kInstanceExtensionCount * sizeof(VkExtensionProperties)));
-    uint32_t num_extensions = 0;
-
-    available[num_extensions++] = VkExtensionProperties{
-        VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_SPEC_VERSION};
-    available[num_extensions++] =
-        VkExtensionProperties{VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
-                              VK_KHR_ANDROID_SURFACE_SPEC_VERSION};
-    if (g_driver_instance_extensions[kEXT_debug_report]) {
-        available[num_extensions++] =
-            VkExtensionProperties{VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
-                                  VK_EXT_DEBUG_REPORT_SPEC_VERSION};
-    }
-
-    if (!pProperties || *pPropertyCount > num_extensions)
-        *pPropertyCount = num_extensions;
-    if (pProperties)
-        std::copy(available, available + *pPropertyCount, pProperties);
-
-    return *pPropertyCount < num_extensions ? VK_INCOMPLETE : VK_SUCCESS;
-}
-
-}  // namespace driver
-
-}  // namespace vulkan
diff --git a/vulkan/libvulkan/loader.h b/vulkan/libvulkan/loader.h
deleted file mode 100644
index 0ec08b2..0000000
--- a/vulkan/libvulkan/loader.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright 2015 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.
- */
-
-#ifndef LIBVULKAN_LOADER_H
-#define LIBVULKAN_LOADER_H 1
-
-#include <bitset>
-#include "dispatch_gen.h"
-#include "debug_report.h"
-
-namespace vulkan {
-
-enum InstanceExtension {
-    kKHR_surface,
-    kKHR_android_surface,
-    kEXT_debug_report,
-    kInstanceExtensionCount
-};
-typedef std::bitset<kInstanceExtensionCount> InstanceExtensionSet;
-
-enum DeviceExtension {
-    kKHR_swapchain,
-    kANDROID_native_buffer,
-    kDeviceExtensionCount
-};
-typedef std::bitset<kDeviceExtensionCount> DeviceExtensionSet;
-
-// -----------------------------------------------------------------------------
-// dispatch_gen.cpp
-
-PFN_vkVoidFunction GetLoaderBottomProcAddr(const char* name);
-bool LoadDriverDispatchTable(VkInstance instance,
-                             PFN_vkGetInstanceProcAddr get_proc_addr,
-                             const InstanceExtensionSet& extensions,
-                             DriverDispatchTable& dispatch);
-
-// -----------------------------------------------------------------------------
-// loader.cpp
-
-// clang-format off
-VKAPI_ATTR VkResult CreateInstance_Bottom(const VkInstanceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkInstance* vkinstance);
-VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr_Bottom(VkInstance, const char* name);
-VKAPI_ATTR VkResult EnumeratePhysicalDevices_Bottom(VkInstance vkinstance, uint32_t* pdev_count, VkPhysicalDevice* pdevs);
-VKAPI_ATTR void GetPhysicalDeviceProperties_Bottom(VkPhysicalDevice pdev, VkPhysicalDeviceProperties* properties);
-VKAPI_ATTR void GetPhysicalDeviceFeatures_Bottom(VkPhysicalDevice pdev, VkPhysicalDeviceFeatures* features);
-VKAPI_ATTR void GetPhysicalDeviceMemoryProperties_Bottom(VkPhysicalDevice pdev, VkPhysicalDeviceMemoryProperties* properties);
-VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties_Bottom(VkPhysicalDevice pdev, uint32_t* properties_count, VkQueueFamilyProperties* properties);
-VKAPI_ATTR void GetPhysicalDeviceFormatProperties_Bottom(VkPhysicalDevice pdev, VkFormat format, VkFormatProperties* properties);
-VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties_Bottom(VkPhysicalDevice pdev, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* properties);
-VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties_Bottom(VkPhysicalDevice pdev, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* properties_count, VkSparseImageFormatProperties* properties);
-VKAPI_ATTR VkResult EnumerateDeviceExtensionProperties_Bottom(VkPhysicalDevice pdev, const char* layer_name, uint32_t* properties_count, VkExtensionProperties* properties);
-VKAPI_ATTR VkResult EnumerateDeviceLayerProperties_Bottom(VkPhysicalDevice pdev, uint32_t* properties_count, VkLayerProperties* properties);
-VKAPI_ATTR VkResult CreateDevice_Bottom(VkPhysicalDevice pdev, const VkDeviceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkDevice* device_out);
-VKAPI_ATTR void DestroyInstance_Bottom(VkInstance vkinstance, const VkAllocationCallbacks* allocator);
-VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr_Bottom(VkDevice vkdevice, const char* name);
-VKAPI_ATTR void DestroyDevice_Bottom(VkDevice device, const VkAllocationCallbacks* pAllocator);
-VKAPI_ATTR void GetDeviceQueue_Bottom(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue);
-VKAPI_ATTR VkResult AllocateCommandBuffers_Bottom(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers);
-// clang-format on
-
-const VkAllocationCallbacks* GetAllocator(VkInstance instance);
-const VkAllocationCallbacks* GetAllocator(VkDevice device);
-VkInstance GetDriverInstance(VkInstance instance);
-const DriverDispatchTable& GetDriverDispatch(VkInstance instance);
-const DriverDispatchTable& GetDriverDispatch(VkDevice device);
-const DriverDispatchTable& GetDriverDispatch(VkQueue queue);
-DebugReportCallbackList& GetDebugReportCallbacks(VkInstance instance);
-
-// -----------------------------------------------------------------------------
-// swapchain.cpp
-
-// clang-format off
-VKAPI_ATTR VkResult CreateAndroidSurfaceKHR_Bottom(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
-VKAPI_ATTR void DestroySurfaceKHR_Bottom(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* allocator);
-VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR_Bottom(VkPhysicalDevice pdev, uint32_t queue_family, VkSurfaceKHR surface, VkBool32* pSupported);
-VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR_Bottom(VkPhysicalDevice pdev, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* capabilities);
-VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormatsKHR_Bottom(VkPhysicalDevice pdev, VkSurfaceKHR surface, uint32_t* count, VkSurfaceFormatKHR* formats);
-VKAPI_ATTR VkResult GetPhysicalDeviceSurfacePresentModesKHR_Bottom(VkPhysicalDevice pdev, VkSurfaceKHR surface, uint32_t* count, VkPresentModeKHR* modes);
-VKAPI_ATTR VkResult CreateSwapchainKHR_Bottom(VkDevice device, const VkSwapchainCreateInfoKHR* create_info, const VkAllocationCallbacks* allocator, VkSwapchainKHR* swapchain_handle);
-VKAPI_ATTR void DestroySwapchainKHR_Bottom(VkDevice device, VkSwapchainKHR swapchain_handle, const VkAllocationCallbacks* allocator);
-VKAPI_ATTR VkResult GetSwapchainImagesKHR_Bottom(VkDevice device, VkSwapchainKHR swapchain_handle, uint32_t* count, VkImage* images);
-VKAPI_ATTR VkResult AcquireNextImageKHR_Bottom(VkDevice device, VkSwapchainKHR swapchain_handle, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* image_index);
-VKAPI_ATTR VkResult QueuePresentKHR_Bottom(VkQueue queue, const VkPresentInfoKHR* present_info);
-
-VKAPI_ATTR VkResult CreateAndroidSurfaceKHR_Disabled(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
-VKAPI_ATTR void DestroySurfaceKHR_Disabled(VkInstance, VkSurfaceKHR, const VkAllocationCallbacks*);
-VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR_Disabled(VkPhysicalDevice, uint32_t, VkSurfaceKHR, VkBool32*);
-VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR_Disabled(VkPhysicalDevice, VkSurfaceKHR, VkSurfaceCapabilitiesKHR*);
-VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormatsKHR_Disabled(VkPhysicalDevice, VkSurfaceKHR, uint32_t*, VkSurfaceFormatKHR*);
-VKAPI_ATTR VkResult GetPhysicalDeviceSurfacePresentModesKHR_Disabled(VkPhysicalDevice, VkSurfaceKHR, uint32_t*, VkPresentModeKHR*);
-VKAPI_ATTR VkResult CreateSwapchainKHR_Disabled(VkDevice device, const VkSwapchainCreateInfoKHR* create_info, const VkAllocationCallbacks* allocator, VkSwapchainKHR* swapchain_handle);
-VKAPI_ATTR void DestroySwapchainKHR_Disabled(VkDevice device, VkSwapchainKHR swapchain_handle, const VkAllocationCallbacks* allocator);
-VKAPI_ATTR VkResult GetSwapchainImagesKHR_Disabled(VkDevice device, VkSwapchainKHR swapchain_handle, uint32_t* count, VkImage* images);
-VKAPI_ATTR VkResult AcquireNextImageKHR_Disabled(VkDevice device, VkSwapchainKHR swapchain_handle, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* image_index);
-VKAPI_ATTR VkResult QueuePresentKHR_Disabled(VkQueue queue, const VkPresentInfoKHR* present_info);
-// clang-format on
-
-// -----------------------------------------------------------------------------
-// layers_extensions.cpp
-
-struct Layer;
-class LayerRef {
-   public:
-    LayerRef(Layer* layer);
-    LayerRef(LayerRef&& other);
-    ~LayerRef();
-    LayerRef(const LayerRef&) = delete;
-    LayerRef& operator=(const LayerRef&) = delete;
-
-    const char* GetName() const;
-    uint32_t GetSpecVersion();
-
-    // provides bool-like behavior
-    operator const Layer*() const { return layer_; }
-
-    PFN_vkGetInstanceProcAddr GetGetInstanceProcAddr() const;
-    PFN_vkGetDeviceProcAddr GetGetDeviceProcAddr() const;
-
-    bool SupportsExtension(const char* name) const;
-
-   private:
-    Layer* layer_;
-};
-
-void DiscoverLayers();
-uint32_t EnumerateInstanceLayers(uint32_t count, VkLayerProperties* properties);
-uint32_t EnumerateDeviceLayers(uint32_t count, VkLayerProperties* properties);
-void GetInstanceLayerExtensions(const char* name,
-                                const VkExtensionProperties** properties,
-                                uint32_t* count);
-void GetDeviceLayerExtensions(const char* name,
-                              const VkExtensionProperties** properties,
-                              uint32_t* count);
-LayerRef GetInstanceLayerRef(const char* name);
-LayerRef GetDeviceLayerRef(const char* name);
-
-InstanceExtension InstanceExtensionFromName(const char* name);
-DeviceExtension DeviceExtensionFromName(const char* name);
-
-}  // namespace vulkan
-
-#endif  // LIBVULKAN_LOADER_H
diff --git a/vulkan/libvulkan/stubhal.cpp b/vulkan/libvulkan/stubhal.cpp
new file mode 100644
index 0000000..89fcebb
--- /dev/null
+++ b/vulkan/libvulkan/stubhal.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+/* NOTE:
+ * This stub HAL is only used internally by the loader when a real HAL
+ * implementation is not present, in order to avoid needing "null HAL" checks
+ * throughout the loader. It does not enumerate any physical devices, and is
+ * only as conformant to the Vulkan and Android HAL interfaces as the loader
+ * needs it to be. Do not use it as an example of a correct implementation; the
+ * code in ../null_driver is better for that.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "vkstub"
+
+#include <array>
+#include <bitset>
+#include <mutex>
+#include <hardware/hwvulkan.h>
+#include <log/log.h>
+#include "stubhal.h"
+
+namespace vulkan {
+namespace stubhal {
+
+namespace {
+
+const size_t kMaxInstances = 32;
+static std::mutex g_instance_mutex;
+static std::bitset<kMaxInstances> g_instance_used(false);
+static std::array<hwvulkan_dispatch_t, kMaxInstances> g_instances;
+
+[[noreturn]] void NoOp() {
+    LOG_ALWAYS_FATAL("invalid stub function called");
+}
+
+VKAPI_ATTR VkResult
+EnumerateInstanceExtensionProperties(const char* /*layer_name*/,
+                                     uint32_t* count,
+                                     VkExtensionProperties* /*properties*/) {
+    *count = 0;
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult
+EnumerateInstanceLayerProperties(uint32_t* count,
+                                 VkLayerProperties* /*properties*/) {
+    *count = 0;
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult CreateInstance(const VkInstanceCreateInfo* /*create_info*/,
+                                   const VkAllocationCallbacks* /*allocator*/,
+                                   VkInstance* instance) {
+    std::lock_guard<std::mutex> lock(g_instance_mutex);
+    for (size_t i = 0; i < kMaxInstances; i++) {
+        if (!g_instance_used[i]) {
+            g_instance_used[i] = true;
+            g_instances[i].magic = HWVULKAN_DISPATCH_MAGIC;
+            *instance = reinterpret_cast<VkInstance>(&g_instances[i]);
+            return VK_SUCCESS;
+        }
+    }
+    ALOGE("no more instances available (max=%zu)", kMaxInstances);
+    return VK_ERROR_INITIALIZATION_FAILED;
+}
+
+VKAPI_ATTR void DestroyInstance(VkInstance instance,
+                                const VkAllocationCallbacks* /*allocator*/) {
+    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(),
+                "DestroyInstance: invalid instance handle");
+    g_instance_used[static_cast<size_t>(idx)] = false;
+}
+
+VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance /*instance*/,
+                                             uint32_t* count,
+                                             VkPhysicalDevice* /*gpus*/) {
+    *count = 0;
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance /*instance*/,
+                                                  const char* name) {
+    if (strcmp(name, "vkCreateInstance") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(CreateInstance);
+    if (strcmp(name, "vkDestroyInstance") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance);
+    if (strcmp(name, "vkEnumerateInstanceExtensionProperties") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(
+            EnumerateInstanceExtensionProperties);
+    if (strcmp(name, "vkEnumeratePhysicalDevices") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices);
+    if (strcmp(name, "vkGetInstanceProcAddr") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr);
+
+    // None of the other Vulkan functions should ever be called, as they all
+    // take a VkPhysicalDevice or other object obtained from a physical device.
+    return reinterpret_cast<PFN_vkVoidFunction>(NoOp);
+}
+
+}  // anonymous namespace
+
+const hwvulkan_device_t kDevice = {
+    .common =
+        {
+            .tag = HARDWARE_DEVICE_TAG,
+            .version = HWVULKAN_DEVICE_API_VERSION_0_1,
+            .module = nullptr,
+            .close = nullptr,
+        },
+    .EnumerateInstanceExtensionProperties =
+        EnumerateInstanceExtensionProperties,
+    .CreateInstance = CreateInstance,
+    .GetInstanceProcAddr = GetInstanceProcAddr,
+};
+
+}  // namespace stubhal
+}  // namespace vulkan
diff --git a/vulkan/libvulkan/stubhal.h b/vulkan/libvulkan/stubhal.h
new file mode 100644
index 0000000..9ba7d04
--- /dev/null
+++ b/vulkan/libvulkan/stubhal.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#ifndef LIBVULKAN_STUBHAL_H
+#define LIBVULKAN_STUBHAL_H 1
+
+struct hwvulkan_device_t;
+
+namespace vulkan {
+namespace stubhal {
+
+extern const hwvulkan_device_t kDevice;
+
+}  // namespace stubhal
+}  // namespace vulkan
+
+#endif  // LIBVULKAN_STUBHAL_H
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 7f944cf..320a2ac 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -21,14 +21,14 @@
 #include <log/log.h>
 #include <sync/sync.h>
 
-#include "loader.h"
-
-using namespace vulkan;
+#include "driver.h"
 
 // TODO(jessehall): Currently we don't have a good error code for when a native
 // window operation fails. Just returning INITIALIZATION_FAILED for now. Later
 // versions (post SDK 0.9) of the API/extension have a better error code.
 // When updating to that version, audit all error returns.
+namespace vulkan {
+namespace driver {
 
 namespace {
 
@@ -98,11 +98,10 @@
 std::shared_ptr<T> InitSharedPtr(Host host, T* obj) {
     try {
         obj->common.incRef(&obj->common);
-        return std::shared_ptr<T>(
-            obj, NativeBaseDeleter<T>(),
-            VulkanAllocator<T>(*GetAllocator(host), AllocScope<Host>::kScope));
+        return std::shared_ptr<T>(obj, NativeBaseDeleter<T>(),
+                                  VulkanAllocator<T>(GetData(host).allocator,
+                                                     AllocScope<Host>::kScope));
     } catch (std::bad_alloc&) {
-        obj->common.decRef(&obj->common);
         return nullptr;
     }
 }
@@ -224,16 +223,14 @@
 
 }  // anonymous namespace
 
-namespace vulkan {
-
 VKAPI_ATTR
-VkResult CreateAndroidSurfaceKHR_Bottom(
+VkResult CreateAndroidSurfaceKHR(
     VkInstance instance,
     const VkAndroidSurfaceCreateInfoKHR* pCreateInfo,
     const VkAllocationCallbacks* allocator,
     VkSurfaceKHR* out_surface) {
     if (!allocator)
-        allocator = GetAllocator(instance);
+        allocator = &GetData(instance).allocator;
     void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Surface),
                                          alignof(Surface),
                                          VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
@@ -267,30 +264,30 @@
 }
 
 VKAPI_ATTR
-void DestroySurfaceKHR_Bottom(VkInstance instance,
-                              VkSurfaceKHR surface_handle,
-                              const VkAllocationCallbacks* allocator) {
+void DestroySurfaceKHR(VkInstance instance,
+                       VkSurfaceKHR surface_handle,
+                       const VkAllocationCallbacks* allocator) {
     Surface* surface = SurfaceFromHandle(surface_handle);
     if (!surface)
         return;
     native_window_api_disconnect(surface->window.get(), NATIVE_WINDOW_API_EGL);
     surface->~Surface();
     if (!allocator)
-        allocator = GetAllocator(instance);
+        allocator = &GetData(instance).allocator;
     allocator->pfnFree(allocator->pUserData, surface);
 }
 
 VKAPI_ATTR
-VkResult GetPhysicalDeviceSurfaceSupportKHR_Bottom(VkPhysicalDevice /*pdev*/,
-                                                   uint32_t /*queue_family*/,
-                                                   VkSurfaceKHR /*surface*/,
-                                                   VkBool32* supported) {
+VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice /*pdev*/,
+                                            uint32_t /*queue_family*/,
+                                            VkSurfaceKHR /*surface*/,
+                                            VkBool32* supported) {
     *supported = VK_TRUE;
     return VK_SUCCESS;
 }
 
 VKAPI_ATTR
-VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR_Bottom(
+VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(
     VkPhysicalDevice /*pdev*/,
     VkSurfaceKHR surface,
     VkSurfaceCapabilitiesKHR* capabilities) {
@@ -357,11 +354,10 @@
 }
 
 VKAPI_ATTR
-VkResult GetPhysicalDeviceSurfaceFormatsKHR_Bottom(
-    VkPhysicalDevice /*pdev*/,
-    VkSurfaceKHR /*surface*/,
-    uint32_t* count,
-    VkSurfaceFormatKHR* formats) {
+VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice /*pdev*/,
+                                            VkSurfaceKHR /*surface*/,
+                                            uint32_t* count,
+                                            VkSurfaceFormatKHR* formats) {
     // TODO(jessehall): Fill out the set of supported formats. Longer term, add
     // a new gralloc method to query whether a (format, usage) pair is
     // supported, and check that for each gralloc format that corresponds to a
@@ -386,11 +382,10 @@
 }
 
 VKAPI_ATTR
-VkResult GetPhysicalDeviceSurfacePresentModesKHR_Bottom(
-    VkPhysicalDevice /*pdev*/,
-    VkSurfaceKHR /*surface*/,
-    uint32_t* count,
-    VkPresentModeKHR* modes) {
+VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice /*pdev*/,
+                                                 VkSurfaceKHR /*surface*/,
+                                                 uint32_t* count,
+                                                 VkPresentModeKHR* modes) {
     const VkPresentModeKHR kModes[] = {
         VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR,
     };
@@ -407,15 +402,15 @@
 }
 
 VKAPI_ATTR
-VkResult CreateSwapchainKHR_Bottom(VkDevice device,
-                                   const VkSwapchainCreateInfoKHR* create_info,
-                                   const VkAllocationCallbacks* allocator,
-                                   VkSwapchainKHR* swapchain_handle) {
+VkResult CreateSwapchainKHR(VkDevice device,
+                            const VkSwapchainCreateInfoKHR* create_info,
+                            const VkAllocationCallbacks* allocator,
+                            VkSwapchainKHR* swapchain_handle) {
     int err;
     VkResult result = VK_SUCCESS;
 
     if (!allocator)
-        allocator = GetAllocator(device);
+        allocator = &GetData(device).allocator;
 
     ALOGV_IF(create_info->imageArrayLayers != 1,
              "Swapchain imageArrayLayers (%u) != 1 not supported",
@@ -436,7 +431,7 @@
     // -- Configure the native window --
 
     Surface& surface = *SurfaceFromHandle(create_info->surface);
-    const DriverDispatchTable& dispatch = GetDriverDispatch(device);
+    const auto& dispatch = GetData(device).driver;
 
     int native_format = HAL_PIXEL_FORMAT_RGBA_8888;
     switch (create_info->imageFormat) {
@@ -681,10 +676,10 @@
 }
 
 VKAPI_ATTR
-void DestroySwapchainKHR_Bottom(VkDevice device,
-                                VkSwapchainKHR swapchain_handle,
-                                const VkAllocationCallbacks* allocator) {
-    const DriverDispatchTable& dispatch = GetDriverDispatch(device);
+void DestroySwapchainKHR(VkDevice device,
+                         VkSwapchainKHR swapchain_handle,
+                         const VkAllocationCallbacks* allocator) {
+    const auto& dispatch = GetData(device).driver;
     Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
     const std::shared_ptr<ANativeWindow>& window = swapchain->surface.window;
 
@@ -702,16 +697,16 @@
     }
 
     if (!allocator)
-        allocator = GetAllocator(device);
+        allocator = &GetData(device).allocator;
     swapchain->~Swapchain();
     allocator->pfnFree(allocator->pUserData, swapchain);
 }
 
 VKAPI_ATTR
-VkResult GetSwapchainImagesKHR_Bottom(VkDevice,
-                                      VkSwapchainKHR swapchain_handle,
-                                      uint32_t* count,
-                                      VkImage* images) {
+VkResult GetSwapchainImagesKHR(VkDevice,
+                               VkSwapchainKHR swapchain_handle,
+                               uint32_t* count,
+                               VkImage* images) {
     Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
     VkResult result = VK_SUCCESS;
     if (images) {
@@ -728,12 +723,12 @@
 }
 
 VKAPI_ATTR
-VkResult AcquireNextImageKHR_Bottom(VkDevice device,
-                                    VkSwapchainKHR swapchain_handle,
-                                    uint64_t timeout,
-                                    VkSemaphore semaphore,
-                                    VkFence vk_fence,
-                                    uint32_t* image_index) {
+VkResult AcquireNextImageKHR(VkDevice device,
+                             VkSwapchainKHR swapchain_handle,
+                             uint64_t timeout,
+                             VkSemaphore semaphore,
+                             VkFence vk_fence,
+                             uint32_t* image_index) {
     Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
     ANativeWindow* window = swapchain.surface.window.get();
     VkResult result;
@@ -777,7 +772,7 @@
         }
     }
 
-    result = GetDriverDispatch(device).AcquireImageANDROID(
+    result = GetData(device).driver.AcquireImageANDROID(
         device, swapchain.images[idx].image, fence_clone, semaphore, vk_fence);
     if (result != VK_SUCCESS) {
         // NOTE: we're relying on AcquireImageANDROID to close fence_clone,
@@ -798,14 +793,13 @@
 }
 
 VKAPI_ATTR
-VkResult QueuePresentKHR_Bottom(VkQueue queue,
-                                const VkPresentInfoKHR* present_info) {
+VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) {
     ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
              "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d",
              present_info->sType);
     ALOGV_IF(present_info->pNext, "VkPresentInfo::pNext != NULL");
 
-    const DriverDispatchTable& dispatch = GetDriverDispatch(queue);
+    const auto& dispatch = GetData(queue).driver;
     VkResult final_result = VK_SUCCESS;
     for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) {
         Swapchain& swapchain =
@@ -858,4 +852,5 @@
     return final_result;
 }
 
+}  // namespace driver
 }  // namespace vulkan
diff --git a/vulkan/libvulkan/swapchain.h b/vulkan/libvulkan/swapchain.h
new file mode 100644
index 0000000..2c60c49
--- /dev/null
+++ b/vulkan/libvulkan/swapchain.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015 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.
+ */
+
+#ifndef LIBVULKAN_SWAPCHAIN_H
+#define LIBVULKAN_SWAPCHAIN_H 1
+
+#include <vulkan/vulkan.h>
+
+namespace vulkan {
+namespace driver {
+
+// clang-format off
+VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
+VKAPI_ATTR void DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* allocator);
+VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice pdev, uint32_t queue_family, VkSurfaceKHR surface, VkBool32* pSupported);
+VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* capabilities);
+VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface, uint32_t* count, VkSurfaceFormatKHR* formats);
+VKAPI_ATTR VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface, uint32_t* count, VkPresentModeKHR* modes);
+VKAPI_ATTR VkResult CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* create_info, const VkAllocationCallbacks* allocator, VkSwapchainKHR* swapchain_handle);
+VKAPI_ATTR void DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain_handle, const VkAllocationCallbacks* allocator);
+VKAPI_ATTR VkResult GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain_handle, uint32_t* count, VkImage* images);
+VKAPI_ATTR VkResult AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain_handle, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* image_index);
+VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info);
+// clang-format on
+
+}  // namespace driver
+}  // namespace vulkan
+
+#endif  // LIBVULKAN_SWAPCHAIN_H