Merge "Double check hidl service at init + meaningful abort when hidl crash"
diff --git a/cmds/bugreportz/readme.md b/cmds/bugreportz/readme.md
index 2697f09..eb0d898 100644
--- a/cmds/bugreportz/readme.md
+++ b/cmds/bugreportz/readme.md
@@ -17,3 +17,4 @@
 
 - `OK:<path_to_bugreport_file>` in case of success.
 - `FAIL:<error message>` in case of failure.
+
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index e953ded..9e60461 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -159,22 +159,37 @@
     return true;
 }
 
+void Lshal::forEachTable(const std::function<void(Table &)> &f) {
+    for (const Table &table : {mServicesTable, mPassthroughRefTable, mImplementationsTable}) {
+        f(const_cast<Table &>(table));
+    }
+}
+void Lshal::forEachTable(const std::function<void(const Table &)> &f) const {
+    for (const Table &table : {mServicesTable, mPassthroughRefTable, mImplementationsTable}) {
+        f(table);
+    }
+}
+
 void Lshal::postprocess() {
-    if (mSortColumn) {
-        std::sort(mTable.begin(), mTable.end(), mSortColumn);
-    }
-    for (TableEntry &entry : mTable) {
-        entry.serverCmdline = getCmdline(entry.serverPid);
-        removeDeadProcesses(&entry.clientPids);
-        for (auto pid : entry.clientPids) {
-            entry.clientCmdlines.push_back(this->getCmdline(pid));
+    forEachTable([this](Table &table) {
+        if (mSortColumn) {
+            std::sort(table.begin(), table.end(), mSortColumn);
         }
-    }
+        for (TableEntry &entry : table) {
+            entry.serverCmdline = getCmdline(entry.serverPid);
+            removeDeadProcesses(&entry.clientPids);
+            for (auto pid : entry.clientPids) {
+                entry.clientCmdlines.push_back(this->getCmdline(pid));
+            }
+        }
+    });
 }
 
 void Lshal::printLine(
         const std::string &interfaceName,
-        const std::string &transport, const std::string &server,
+        const std::string &transport,
+        const std::string &arch,
+        const std::string &server,
         const std::string &serverCmdline,
         const std::string &address, const std::string &clients,
         const std::string &clientCmdlines) const {
@@ -182,6 +197,8 @@
         mOut << std::setw(80) << interfaceName << "\t";
     if (mSelectedColumns & ENABLE_TRANSPORT)
         mOut << std::setw(10) << transport << "\t";
+    if (mSelectedColumns & ENABLE_ARCH)
+        mOut << std::setw(5) << arch << "\t";
     if (mSelectedColumns & ENABLE_SERVER_PID) {
         if (mEnableCmdlines) {
             mOut << std::setw(15) << serverCmdline << "\t";
@@ -203,90 +220,139 @@
 
 void Lshal::dumpVintf() const {
     vintf::HalManifest manifest;
-    for (const TableEntry &entry : mTable) {
+    forEachTable([this, &manifest] (const Table &table) {
+        for (const TableEntry &entry : table) {
 
-        std::string fqInstanceName = entry.interfaceName;
+            std::string fqInstanceName = entry.interfaceName;
 
-        if (entry.source == LIST_DLLIB) {
-            // Quick hack to work around *'s
-            replaceAll(&fqInstanceName, '*', 'D');
-        }
-        auto splittedFqInstanceName = splitFirst(fqInstanceName, '/');
-        FQName fqName(splittedFqInstanceName.first);
-        if (!fqName.isValid()) {
-            mErr << "Warning: '" << splittedFqInstanceName.first
-                 << "' is not a valid FQName." << std::endl;
-            continue;
-        }
-        // Strip out system libs.
-        // TODO(b/34772739): might want to add other framework HAL packages
-        if (fqName.inPackage("android.hidl")) {
-            continue;
-        }
-        std::string interfaceName =
-                entry.source == LIST_DLLIB ? "" : fqName.name();
-        std::string instanceName =
-                entry.source == LIST_DLLIB ? "" : splittedFqInstanceName.second;
-
-        vintf::Transport transport;
-        if (entry.transport == "hwbinder") {
-            transport = vintf::Transport::HWBINDER;
-        } else if (entry.transport == "passthrough") {
-            transport = vintf::Transport::PASSTHROUGH;
-        } else {
-            mErr << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl;
-            continue;
-        }
-
-        vintf::ManifestHal *hal = manifest.getHal(fqName.package());
-        if (hal == nullptr) {
-            if (!manifest.add(vintf::ManifestHal{
-                .format = vintf::HalFormat::HIDL,
-                .name = fqName.package(),
-                .impl = {.implLevel = vintf::ImplLevel::GENERIC, .impl = ""},
-                .transport = transport
-            })) {
-                mErr << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
+            if (&table == &mImplementationsTable) {
+                // Quick hack to work around *'s
+                replaceAll(&fqInstanceName, '*', 'D');
+            }
+            auto splittedFqInstanceName = splitFirst(fqInstanceName, '/');
+            FQName fqName(splittedFqInstanceName.first);
+            if (!fqName.isValid()) {
+                mErr << "Warning: '" << splittedFqInstanceName.first
+                     << "' is not a valid FQName." << std::endl;
                 continue;
             }
-            hal = manifest.getHal(fqName.package());
-        }
-        if (hal == nullptr) {
-            mErr << "Warning: cannot get hal '" << fqInstanceName
-                 << "' after adding it" << std::endl;
-            continue;
-        }
-        vintf::Version version{fqName.getPackageMajorVersion(), fqName.getPackageMinorVersion()};
-        if (std::find(hal->versions.begin(), hal->versions.end(), version) == hal->versions.end()) {
-            hal->versions.push_back(version);
-        }
-        if (entry.source != LIST_DLLIB) {
-            auto it = hal->interfaces.find(interfaceName);
-            if (it == hal->interfaces.end()) {
-                hal->interfaces.insert({interfaceName, {interfaceName, {{instanceName}}}});
+            // Strip out system libs.
+            // TODO(b/34772739): might want to add other framework HAL packages
+            if (fqName.inPackage("android.hidl")) {
+                continue;
+            }
+            std::string interfaceName =
+                    &table == &mImplementationsTable ? "" : fqName.name();
+            std::string instanceName =
+                    &table == &mImplementationsTable ? "" : splittedFqInstanceName.second;
+
+            vintf::Transport transport;
+            if (entry.transport == "hwbinder") {
+                transport = vintf::Transport::HWBINDER;
+            } else if (entry.transport == "passthrough") {
+                transport = vintf::Transport::PASSTHROUGH;
             } else {
-                it->second.instances.insert(instanceName);
+                mErr << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl;
+                continue;
+            }
+
+            vintf::ManifestHal *hal = manifest.getHal(fqName.package());
+            if (hal == nullptr) {
+                if (!manifest.add(vintf::ManifestHal{
+                    .format = vintf::HalFormat::HIDL,
+                    .name = fqName.package(),
+                    .impl = {.implLevel = vintf::ImplLevel::GENERIC, .impl = ""},
+                    .transport = transport
+                })) {
+                    mErr << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
+                    continue;
+                }
+                hal = manifest.getHal(fqName.package());
+            }
+            if (hal == nullptr) {
+                mErr << "Warning: cannot get hal '" << fqInstanceName
+                     << "' after adding it" << std::endl;
+                continue;
+            }
+            vintf::Version version{fqName.getPackageMajorVersion(), fqName.getPackageMinorVersion()};
+            if (std::find(hal->versions.begin(), hal->versions.end(), version) == hal->versions.end()) {
+                hal->versions.push_back(version);
+            }
+            if (&table != &mImplementationsTable) {
+                auto it = hal->interfaces.find(interfaceName);
+                if (it == hal->interfaces.end()) {
+                    hal->interfaces.insert({interfaceName, {interfaceName, {{instanceName}}}});
+                } else {
+                    it->second.instances.insert(instanceName);
+                }
             }
         }
-    }
+    });
     mOut << vintf::gHalManifestConverter(manifest);
 }
 
-void Lshal::dumpTable() const {
-    mOut << "All services:" << std::endl;
-    mOut << std::left;
-    printLine("Interface", "Transport", "Server", "Server CMD", "PTR", "Clients", "Clients CMD");
-    for (const auto &entry : mTable) {
-        printLine(entry.interfaceName,
-                entry.transport,
-                entry.serverPid == NO_PID ? "N/A" : std::to_string(entry.serverPid),
-                entry.serverCmdline,
-                entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress),
-                join(entry.clientPids, " "),
-                join(entry.clientCmdlines, ";"));
+static const std::string &getArchString(Architecture arch) {
+    static const std::string sStr64 = "64";
+    static const std::string sStr32 = "32";
+    static const std::string sStrBoth = "32+64";
+    static const std::string sStrUnknown = "";
+    switch (arch) {
+        case ARCH64:
+            return sStr64;
+        case ARCH32:
+            return sStr32;
+        case ARCH_BOTH:
+            return sStrBoth;
+        case ARCH_UNKNOWN: // fall through
+        default:
+            return sStrUnknown;
     }
 }
 
+static Architecture fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo::Architecture a) {
+    switch (a) {
+        case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_64BIT:
+            return ARCH64;
+        case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_32BIT:
+            return ARCH32;
+        case ::android::hidl::base::V1_0::DebugInfo::Architecture::UNKNOWN: // fallthrough
+        default:
+            return ARCH_UNKNOWN;
+    }
+}
+
+void Lshal::dumpTable() {
+    mServicesTable.description =
+            "All binderized services (registered services through hwservicemanager)";
+    mPassthroughRefTable.description =
+            "All interfaces that getService() has ever return as a passthrough interface;\n"
+            "PIDs / processes shown below might be inaccurate because the process\n"
+            "might have relinquished the interface or might have died.\n"
+            "The Server / Server CMD column can be ignored.\n"
+            "The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
+            "the library and successfully fetched the passthrough implementation.";
+    mImplementationsTable.description =
+            "All available passthrough implementations (all -impl.so files)";
+    forEachTable([this] (const Table &table) {
+        mOut << table.description << std::endl;
+        mOut << std::left;
+        printLine("Interface", "Transport", "Arch", "Server", "Server CMD",
+                  "PTR", "Clients", "Clients CMD");
+        for (const auto &entry : table) {
+            printLine(entry.interfaceName,
+                    entry.transport,
+                    getArchString(entry.arch),
+                    entry.serverPid == NO_PID ? "N/A" : std::to_string(entry.serverPid),
+                    entry.serverCmdline,
+                    entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress),
+                    join(entry.clientPids, " "),
+                    join(entry.clientCmdlines, ";"));
+        }
+        mOut << std::endl;
+    });
+
+}
+
 void Lshal::dump() {
     if (mVintf) {
         dumpVintf();
@@ -301,24 +367,43 @@
     }
 }
 
-void Lshal::putEntry(TableEntry &&entry) {
-    mTable.push_back(std::forward<TableEntry>(entry));
+void Lshal::putEntry(TableEntrySource source, TableEntry &&entry) {
+    Table *table = nullptr;
+    switch (source) {
+        case HWSERVICEMANAGER_LIST :
+            table = &mServicesTable; break;
+        case PTSERVICEMANAGER_REG_CLIENT :
+            table = &mPassthroughRefTable; break;
+        case LIST_DLLIB :
+            table = &mImplementationsTable; break;
+        default:
+            mErr << "Error: Unknown source of entry " << source << std::endl;
+    }
+    if (table) {
+        table->entries.push_back(std::forward<TableEntry>(entry));
+    }
 }
 
 Status Lshal::fetchAllLibraries(const sp<IServiceManager> &manager) {
     using namespace ::android::hardware;
     using namespace ::android::hidl::manager::V1_0;
     using namespace ::android::hidl::base::V1_0;
-    auto ret = timeoutIPC(manager, &IServiceManager::list, [&] (const auto &fqInstanceNames) {
-        for (const auto &fqInstanceName : fqInstanceNames) {
-            putEntry({
-                .interfaceName = fqInstanceName,
+    auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) {
+        std::map<std::string, TableEntry> entries;
+        for (const auto &info : infos) {
+            std::string interfaceName = std::string{info.interfaceName.c_str()} + "/" +
+                    std::string{info.instanceName.c_str()};
+            entries.emplace(interfaceName, TableEntry{
+                .interfaceName = interfaceName,
                 .transport = "passthrough",
                 .serverPid = NO_PID,
                 .serverObjectAddress = NO_PTR,
                 .clientPids = {},
-                .source = LIST_DLLIB
-            });
+                .arch = ARCH_UNKNOWN
+            }).first->second.arch |= fromBaseArchitecture(info.arch);
+        }
+        for (auto &&pair : entries) {
+            putEntry(LIST_DLLIB, std::move(pair.second));
         }
     });
     if (!ret.isOk()) {
@@ -331,11 +416,12 @@
 
 Status Lshal::fetchPassthrough(const sp<IServiceManager> &manager) {
     using namespace ::android::hardware;
+    using namespace ::android::hardware::details;
     using namespace ::android::hidl::manager::V1_0;
     using namespace ::android::hidl::base::V1_0;
     auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) {
         for (const auto &info : infos) {
-            putEntry({
+            putEntry(PTSERVICEMANAGER_REG_CLIENT, {
                 .interfaceName =
                         std::string{info.interfaceName.c_str()} + "/" +
                         std::string{info.instanceName.c_str()},
@@ -343,7 +429,7 @@
                 .serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID,
                 .serverObjectAddress = NO_PTR,
                 .clientPids = info.clientPids,
-                .source = PTSERVICEMANAGER_REG_CLIENT
+                .arch = fromBaseArchitecture(info.arch)
             });
         }
     });
@@ -420,25 +506,25 @@
     for (const auto &fqInstanceName : fqInstanceNames) {
         auto it = allDebugInfos.find(fqInstanceName);
         if (it == allDebugInfos.end()) {
-            putEntry({
+            putEntry(HWSERVICEMANAGER_LIST, {
                 .interfaceName = fqInstanceName,
                 .transport = mode,
                 .serverPid = NO_PID,
                 .serverObjectAddress = NO_PTR,
                 .clientPids = {},
-                .source = HWSERVICEMANAGER_LIST
+                .arch = ARCH_UNKNOWN
             });
             continue;
         }
         const DebugInfo &info = it->second;
-        putEntry({
+        putEntry(HWSERVICEMANAGER_LIST, {
             .interfaceName = fqInstanceName,
             .transport = mode,
             .serverPid = info.pid,
             .serverObjectAddress = info.ptr,
             .clientPids = info.pid == NO_PID || info.ptr == NO_PTR
                     ? Pids{} : allPids[info.pid][info.ptr],
-            .source = HWSERVICEMANAGER_LIST
+            .arch = fromBaseArchitecture(info.arch),
         });
     }
     return status;
@@ -469,13 +555,14 @@
 void Lshal::usage() const {
     mErr
         << "usage: lshal" << std::endl
-        << "           Dump all hals with default ordering and columns [-itpc]." << std::endl
-        << "       lshal [--interface|-i] [--transport|-t]" << std::endl
+        << "           Dump all hals with default ordering and columns [-ipc]." << std::endl
+        << "       lshal [--interface|-i] [--transport|-t] [-r|--arch]" << std::endl
         << "             [--pid|-p] [--address|-a] [--clients|-c] [--cmdline|-m]" << std::endl
         << "             [--sort={interface|i|pid|p}] [--init-vintf[=path]]" << std::endl
         << "           -i, --interface: print the interface name column" << std::endl
         << "           -n, --instance: print the instance name column" << std::endl
         << "           -t, --transport: print the transport mode column" << std::endl
+        << "           -r, --arch: print if the HAL is in 64-bit or 32-bit" << std::endl
         << "           -p, --pid: print the server PID, or server cmdline if -m is set" << std::endl
         << "           -a, --address: print the server object address column" << std::endl
         << "           -c, --clients: print the client PIDs, or client cmdlines if -m is set"
@@ -495,6 +582,7 @@
         {"help",      no_argument,       0, 'h' },
         {"interface", no_argument,       0, 'i' },
         {"transport", no_argument,       0, 't' },
+        {"arch",      no_argument,       0, 'r' },
         {"pid",       no_argument,       0, 'p' },
         {"address",   no_argument,       0, 'a' },
         {"clients",   no_argument,       0, 'c' },
@@ -511,7 +599,7 @@
     optind = 1;
     for (;;) {
         // using getopt_long in case we want to add other options in the future
-        c = getopt_long(argc, argv, "hitpacm", longOptions, &optionIndex);
+        c = getopt_long(argc, argv, "hitrpacm", longOptions, &optionIndex);
         if (c == -1) {
             break;
         }
@@ -547,6 +635,10 @@
             mSelectedColumns |= ENABLE_TRANSPORT;
             break;
         }
+        case 'r': {
+            mSelectedColumns |= ENABLE_ARCH;
+            break;
+        }
         case 'p': {
             mSelectedColumns |= ENABLE_SERVER_PID;
             break;
@@ -571,8 +663,7 @@
     }
 
     if (mSelectedColumns == 0) {
-        mSelectedColumns = ENABLE_INTERFACE_NAME
-                | ENABLE_TRANSPORT | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS;
+        mSelectedColumns = ENABLE_INTERFACE_NAME | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS;
     }
     return OK;
 }
diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h
index 1c30908..c9c6660 100644
--- a/cmds/lshal/Lshal.h
+++ b/cmds/lshal/Lshal.h
@@ -53,17 +53,19 @@
     void postprocess();
     void dump();
     void usage() const;
-    void putEntry(TableEntry &&entry);
+    void putEntry(TableEntrySource source, TableEntry &&entry);
     Status fetchPassthrough(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
     Status fetchBinderized(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
     Status fetchAllLibraries(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
     bool getReferencedPids(
         pid_t serverPid, std::map<uint64_t, Pids> *objects) const;
-    void dumpTable() const;
+    void dumpTable();
     void dumpVintf() const;
     void printLine(
             const std::string &interfaceName,
-            const std::string &transport, const std::string &server,
+            const std::string &transport,
+            const std::string &arch,
+            const std::string &server,
             const std::string &serverCmdline,
             const std::string &address, const std::string &clients,
             const std::string &clientCmdlines) const ;
@@ -72,8 +74,13 @@
     // Call getCmdline on all pid in pids. If it returns empty string, the process might
     // have died, and the pid is removed from pids.
     void removeDeadProcesses(Pids *pids);
+    void forEachTable(const std::function<void(Table &)> &f);
+    void forEachTable(const std::function<void(const Table &)> &f) const;
 
-    Table mTable{};
+    Table mServicesTable{};
+    Table mPassthroughRefTable{};
+    Table mImplementationsTable{};
+
     NullableOStream<std::ostream> mErr = std::cerr;
     NullableOStream<std::ostream> mOut = std::cout;
     NullableOStream<std::ofstream> mFileOutput = nullptr;
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index e55806e..2407b42 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -35,6 +35,14 @@
 };
 using TableEntrySource = unsigned int;
 
+enum : unsigned int {
+    ARCH_UNKNOWN = 0,
+    ARCH64       = 1 << 0,
+    ARCH32       = 1 << 1,
+    ARCH_BOTH    = ARCH32 | ARCH64
+};
+using Architecture = unsigned int;
+
 struct TableEntry {
     std::string interfaceName;
     std::string transport;
@@ -43,7 +51,7 @@
     uint64_t serverObjectAddress;
     Pids clientPids;
     std::vector<std::string> clientCmdlines;
-    TableEntrySource source;
+    Architecture arch;
 
     static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) {
         return a.interfaceName < b.interfaceName;
@@ -53,7 +61,17 @@
     };
 };
 
-using Table = std::vector<TableEntry>;
+struct Table {
+    using Entries = std::vector<TableEntry>;
+    std::string description;
+    Entries entries;
+
+    Entries::iterator begin() { return entries.begin(); }
+    Entries::const_iterator begin() const { return entries.begin(); }
+    Entries::iterator end() { return entries.end(); }
+    Entries::const_iterator end() const { return entries.end(); }
+};
+
 using TableEntryCompare = std::function<bool(const TableEntry &, const TableEntry &)>;
 
 enum : unsigned int {
@@ -61,7 +79,8 @@
     ENABLE_TRANSPORT      = 1 << 1,
     ENABLE_SERVER_PID     = 1 << 2,
     ENABLE_SERVER_ADDR    = 1 << 3,
-    ENABLE_CLIENT_PIDS    = 1 << 4
+    ENABLE_CLIENT_PIDS    = 1 << 4,
+    ENABLE_ARCH           = 1 << 5
 };
 
 using TableEntrySelect = unsigned int;
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index f757fc3..f36c9fd 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -29,6 +29,7 @@
 #include <utils/Errors.h>
 #include <utils/StrongPointer.h>
 
+#include <stdatomic.h>
 #include <condition_variable>
 #include <memory>
 #include <mutex>
diff --git a/include/binder/HalToken.h b/include/binder/HalToken.h
new file mode 100644
index 0000000..ce97c78
--- /dev/null
+++ b/include/binder/HalToken.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2017 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_HALTOKEN_H
+#define ANDROID_HALTOKEN_H
+
+#include <binder/Parcel.h>
+#include <hidl/HidlSupport.h>
+
+/**
+ * Hybrid Interfaces
+ * =================
+ *
+ * A hybrid interface is a binder interface that
+ * 1. is implemented both traditionally and as a wrapper around a hidl
+ *    interface, and allows querying whether the underlying instance comes from
+ *    a hidl interface or not; and
+ * 2. allows efficient calls to a hidl interface (if the underlying instance
+ *    comes from a hidl interface) by automatically creating the wrapper in the
+ *    process that calls it.
+ *
+ * Terminology:
+ * - `HalToken`: The type for a "token" of a hidl interface. This is defined to
+ *   be compatible with `ITokenManager.hal`.
+ * - `HInterface`: The base type for a hidl interface. Currently, it is defined
+ *   as `::android::hidl::base::V1_0::IBase`.
+ * - `HALINTERFACE`: The hidl interface that will be sent through binders.
+ * - `INTERFACE`: The binder interface that will be the wrapper of
+ *   `HALINTERFACE`. `INTERFACE` is supposed to be somewhat similar to
+ *   `HALINTERFACE`.
+ *
+ * To demonstrate how this is done, here is an example. Suppose `INTERFACE` is
+ * `IFoo` and `HALINTERFACE` is `HFoo`. The required steps are:
+ * 1. Use DECLARE_HYBRID_META_INTERFACE instead of DECLARE_META_INTERFACE in the
+ *    definition of `IFoo`. The usage is
+ *        DECLARE_HYBRID_META_INTERFACE(IFoo, HFoo)
+ *    inside the body of `IFoo`.
+ * 2. Create a converter class that derives from
+ *    `H2BConverter<HFoo, IFoo, BnFoo>`. Let us call this `H2BFoo`.
+ * 3. Add the following constructor in `H2BFoo` that call the corresponding
+ *    constructors in `H2BConverter`:
+ *        H2BFoo(const sp<HalInterface>& base) : CBase(base) {}
+ *    Note: `CBase = H2BConverter<HFoo, IFoo, BnFoo>` and `HalInterface = HFoo`
+ *    are member typedefs of `H2BConverter<HFoo, IFoo, BnFoo>`, so the above
+ *    line can be copied into `H2BFoo`.
+ * 4. Implement `IFoo` in `H2BFoo` on top of `HFoo`. `H2BConverter` provides a
+ *    protected `mBase` of type `sp<HFoo>` that can be used to access the `HFoo`
+ *    instance. (There is also a public function named `getHalInterface()` that
+ *    returns `mBase`.)
+ * 5. Create a hardware proxy class that derives from
+ *    `HpInterface<BpFoo, H2BFoo>`. Name this class `HpFoo`. (This name cannot
+ *    deviate. See step 8 below.)
+ * 6. Add the following constructor to `HpFoo`:
+ *        HpFoo(const sp<IBinder>& base): PBase(base) {}
+ *    Note: `PBase` a member typedef of `HpInterface<BpFoo, H2BFoo>` that is
+ *    equal to `HpInterface<BpFoo, H2BFoo>` itself, so the above line can be
+ *    copied verbatim into `HpFoo`.
+ * 7. Delegate all functions in `HpFoo` that come from `IFoo` except
+ *    `getHalInterface` to the protected member `mBase`,
+ *    which is defined in `HpInterface<BpFoo, H2BFoo>` (hence in `HpFoo`) with
+ *    type `IFoo`. (There is also a public function named `getBaseInterface()`
+ *    that returns `mBase`.)
+ * 8. Replace the existing `IMPLEMENT_META_INTERFACE` for INTERFACE by
+ *    `IMPLEMENT_HYBRID_META_INTERFACE`. Note that this macro relies on the
+ *    exact naming of `HpFoo`, where `Foo` comes from the interface name `IFoo`.
+ *    An example usage is
+ *        IMPLEMENT_HYBRID_META_INTERFACE(IFoo, HFoo, "example.interface.foo");
+ *
+ * `GETTOKEN` Template Argument
+ * ============================
+ *
+ * Following the instructions above, `H2BConverter` and `HpInterface` would use
+ * `transact()` to send over tokens, with `code` (the first argument of
+ * `transact()`) equal to a 4-byte value of '_GTK'. If this value clashes with
+ * other values already in use in the `Bp` class, it can be changed by supplying
+ * the last optional template argument to `H2BConverter` and `HpInterface`.
+ *
+ */
+
+namespace android {
+
+typedef uint64_t HalToken;
+typedef ::android::hidl::base::V1_0::IBase HInterface;
+
+sp<HInterface> retrieveHalInterface(const HalToken& token);
+bool createHalToken(const sp<HInterface>& interface, HalToken* token);
+bool deleteHalToken(const HalToken& token);
+
+template <
+        typename HINTERFACE,
+        typename INTERFACE,
+        typename BNINTERFACE,
+        uint32_t GETTOKEN = '_GTK'>
+class H2BConverter : public BNINTERFACE {
+public:
+    typedef H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN> CBase; // Converter Base
+    typedef INTERFACE BaseInterface;
+    typedef HINTERFACE HalInterface;
+    static constexpr uint32_t GET_HAL_TOKEN = GETTOKEN;
+
+    H2BConverter(const sp<HalInterface>& base) : mBase(base) {}
+    virtual status_t onTransact(uint32_t code,
+            const Parcel& data, Parcel* reply, uint32_t flags = 0);
+    sp<HalInterface> getHalInterface() override { return mBase; }
+    HalInterface* getBaseInterface() { return mBase.get(); }
+
+protected:
+    sp<HalInterface> mBase;
+};
+
+template <
+        typename BPINTERFACE,
+        typename CONVERTER,
+        uint32_t GETTOKEN = '_GTK'>
+class HpInterface : public CONVERTER::BaseInterface {
+public:
+    typedef HpInterface<BPINTERFACE, CONVERTER, GETTOKEN> PBase; // Proxy Base
+    typedef typename CONVERTER::BaseInterface BaseInterface;
+    typedef typename CONVERTER::HalInterface HalInterface;
+    static constexpr uint32_t GET_HAL_TOKEN = GETTOKEN;
+
+    explicit HpInterface(const sp<IBinder>& impl);
+    sp<HalInterface> getHalInterface() override { return mHal; }
+    BaseInterface* getBaseInterface() { return mBase.get(); }
+
+protected:
+    sp<IBinder> mImpl;
+    sp<BaseInterface> mBase;
+    sp<HalInterface> mHal;
+    IBinder* onAsBinder() override { return mImpl.get(); }
+};
+
+// ----------------------------------------------------------------------
+
+#define DECLARE_HYBRID_META_INTERFACE(INTERFACE, HAL)                   \
+    static const ::android::String16 descriptor;                        \
+    static ::android::sp<I##INTERFACE> asInterface(                     \
+            const ::android::sp<::android::IBinder>& obj);              \
+    virtual const ::android::String16& getInterfaceDescriptor() const;  \
+    I##INTERFACE();                                                     \
+    virtual ~I##INTERFACE();                                            \
+    virtual sp<HAL> getHalInterface();                                  \
+
+
+#define IMPLEMENT_HYBRID_META_INTERFACE(INTERFACE, HAL, NAME)           \
+    const ::android::String16 I##INTERFACE::descriptor(NAME);           \
+    const ::android::String16&                                          \
+            I##INTERFACE::getInterfaceDescriptor() const {              \
+        return I##INTERFACE::descriptor;                                \
+    }                                                                   \
+    ::android::sp<I##INTERFACE> I##INTERFACE::asInterface(              \
+            const ::android::sp<::android::IBinder>& obj)               \
+    {                                                                   \
+        ::android::sp<I##INTERFACE> intr;                               \
+        if (obj != NULL) {                                              \
+            intr = static_cast<I##INTERFACE*>(                          \
+                obj->queryLocalInterface(                               \
+                        I##INTERFACE::descriptor).get());               \
+            if (intr == NULL) {                                         \
+                intr = new Hp##INTERFACE(obj);                          \
+            }                                                           \
+        }                                                               \
+        return intr;                                                    \
+    }                                                                   \
+    I##INTERFACE::I##INTERFACE() { }                                    \
+    I##INTERFACE::~I##INTERFACE() { }                                   \
+    sp<HAL> I##INTERFACE::getHalInterface() { return nullptr; }         \
+
+// ----------------------------------------------------------------------
+
+template <
+        typename HINTERFACE,
+        typename INTERFACE,
+        typename BNINTERFACE,
+        uint32_t GETTOKEN>
+status_t H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN>::
+        onTransact(
+        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+    if (code == GET_HAL_TOKEN) {
+        HalToken token;
+        bool result;
+        result = createHalToken(mBase, &token);
+        if (!result) {
+            ALOGE("H2BConverter: Failed to create HAL token.");
+        }
+        reply->writeBool(result);
+        reply->writeUint64(token);
+        return NO_ERROR;
+    }
+    return BNINTERFACE::onTransact(code, data, reply, flags);
+}
+
+template <typename BPINTERFACE, typename CONVERTER, uint32_t GETTOKEN>
+HpInterface<BPINTERFACE, CONVERTER, GETTOKEN>::HpInterface(
+        const sp<IBinder>& impl) : mImpl(impl) {
+    Parcel data, reply;
+    data.writeInterfaceToken(BaseInterface::getInterfaceDescriptor());
+    if (impl->transact(GET_HAL_TOKEN, data, &reply) == NO_ERROR) {
+        bool tokenCreated = reply.readBool();
+        HalToken token = reply.readUint64();
+        if (!tokenCreated) {
+            ALOGE("HpInterface: Sender failed to create HAL token.");
+            mBase = new BPINTERFACE(impl);
+        } else {
+            sp<HInterface> hInterface = retrieveHalInterface(token);
+            deleteHalToken(token);
+            if (hInterface != nullptr) {
+                mHal = static_cast<HalInterface*>(hInterface.get());
+                mBase = new CONVERTER(mHal);
+            } else {
+                ALOGE("HpInterface: Cannot retrieve HAL interface from token.");
+                mBase = new BPINTERFACE(impl);
+            }
+        }
+    } else {
+        mBase = new BPINTERFACE(impl);
+    }
+}
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_HALTOKEN_H
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index a3c2bfa..cfc68c6 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -155,6 +155,9 @@
             nsecs_t* outDisplayPresentTime, nsecs_t* outDisplayRetireTime,
             nsecs_t* outDequeueReadyTime, nsecs_t* outReleaseTime);
 
+    status_t getWideColorSupport(bool* supported);
+    status_t getHdrSupport(bool* supported);
+
     status_t getUniqueId(uint64_t* outId) const;
 
 protected:
@@ -215,6 +218,8 @@
     int dispatchEnableFrameTimestamps(va_list args);
     int dispatchGetCompositorTiming(va_list args);
     int dispatchGetFrameTimestamps(va_list args);
+    int dispatchGetWideColorSupport(va_list args);
+    int dispatchGetHdrSupport(va_list args);
 
 protected:
     virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 93b8684..2cb44eb 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -34,6 +34,7 @@
         "IResultReceiver.cpp",
         "IServiceManager.cpp",
         "IShellCallback.cpp",
+        "HalToken.cpp",
         "MemoryBase.cpp",
         "MemoryDealer.cpp",
         "MemoryHeapBase.cpp",
@@ -65,6 +66,8 @@
         "liblog",
         "libcutils",
         "libutils",
+        "libhidlbase",
+        "android.hidl.token@1.0",
     ],
     export_shared_lib_headers: [
         "libbase",
diff --git a/libs/binder/HalToken.cpp b/libs/binder/HalToken.cpp
new file mode 100644
index 0000000..6e71a52
--- /dev/null
+++ b/libs/binder/HalToken.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+#define LOG_TAG "HalToken"
+
+#include <utils/Log.h>
+#include <binder/HalToken.h>
+
+#include <android/hidl/token/1.0/ITokenManager.h>
+
+namespace android {
+
+using ::android::hidl::token::V1_0::ITokenManager;
+
+sp<ITokenManager> gTokenManager = nullptr;
+
+ITokenManager* getTokenManager() {
+    if (gTokenManager != nullptr) {
+        return gTokenManager.get();
+    }
+    gTokenManager = ITokenManager::getService();
+    if (gTokenManager == nullptr) {
+        ALOGE("Cannot retrieve TokenManager.");
+    }
+    return gTokenManager.get();
+}
+
+sp<HInterface> retrieveHalInterface(const HalToken& token) {
+    auto transaction = getTokenManager()->get(token);
+    if (!transaction.isOk()) {
+        ALOGE("getHalInterface: Cannot obtain interface from token.");
+        return nullptr;
+    }
+    return static_cast<sp<HInterface> >(transaction);
+}
+
+bool createHalToken(const sp<HInterface>& interface, HalToken* token) {
+    auto transaction = getTokenManager()->createToken(interface);
+    if (!transaction.isOk()) {
+        ALOGE("createHalToken: Cannot create token from interface.");
+        return false;
+    }
+    *token = static_cast<HalToken>(transaction);
+    return true;
+}
+
+bool deleteHalToken(const HalToken& token) {
+    auto transaction = getTokenManager()->unregister(token);
+    if (!transaction.isOk()) {
+        ALOGE("deleteHalToken: Cannot unregister hal token.");
+        return false;
+    }
+    return true;
+}
+
+}; // namespace android
+
diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp
index 87b295a..50a8b28 100644
--- a/libs/binder/IActivityManager.cpp
+++ b/libs/binder/IActivityManager.cpp
@@ -36,6 +36,7 @@
     virtual int openContentUri(const String16& stringUri)
     {
         Parcel data, reply;
+        data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
         data.writeString16(stringUri);
         status_t ret = remote()->transact(OPEN_CONTENT_URI_TRANSACTION, data, & reply);
         int fd = -1;
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index f4e0a60..5c1a4f4 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -17,6 +17,8 @@
 #define LOG_TAG "IMemory"
 
 #include <atomic>
+#include <stdatomic.h>
+
 #include <fcntl.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -28,6 +30,7 @@
 #include <binder/IMemory.h>
 #include <binder/Parcel.h>
 #include <log/log.h>
+
 #include <utils/CallStack.h>
 #include <utils/KeyedVector.h>
 #include <utils/threads.h>
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 6e6cce2..9e3fecb 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -29,6 +29,7 @@
 #include <inttypes.h>
 
 #include <cutils/properties.h>
+#include <cutils/atomic.h>
 
 #include <gui/BufferItem.h>
 #include <gui/BufferQueueCore.h>
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index c26de66..8acdfed 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -27,6 +27,8 @@
 
 #include <hardware/hardware.h>
 
+#include <cutils/atomic.h>
+
 #include <gui/BufferItem.h>
 #include <gui/IGraphicBufferAlloc.h>
 #include <gui/ISurfaceComposer.h>
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index efb1524..ad1984a 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -26,9 +26,10 @@
 #include <utils/Trace.h>
 #include <utils/NativeHandle.h>
 
-#include <ui/Fence.h>
-#include <ui/Region.h>
 #include <ui/DisplayStatInfo.h>
+#include <ui/Fence.h>
+#include <ui/HdrCapabilities.h>
+#include <ui/Region.h>
 
 #include <gui/BufferItem.h>
 #include <gui/IProducerListener.h>
@@ -305,6 +306,51 @@
     return NO_ERROR;
 }
 
+status_t Surface::getWideColorSupport(bool* supported) {
+    ATRACE_CALL();
+
+    sp<IBinder> display(
+        composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    Vector<android_color_mode_t> colorModes;
+    status_t err =
+        composerService()->getDisplayColorModes(display, &colorModes);
+
+    if (err)
+        return err;
+
+    *supported = false;
+    for (android_color_mode_t colorMode : colorModes) {
+        switch (colorMode) {
+            case HAL_COLOR_MODE_DISPLAY_P3:
+            case HAL_COLOR_MODE_ADOBE_RGB:
+            case HAL_COLOR_MODE_DCI_P3:
+                *supported = true;
+                break;
+            default:
+                break;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+status_t Surface::getHdrSupport(bool* supported) {
+    ATRACE_CALL();
+
+    sp<IBinder> display(
+        composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    HdrCapabilities hdrCapabilities;
+    status_t err =
+        composerService()->getHdrCapabilities(display, &hdrCapabilities);
+
+    if (err)
+        return err;
+
+    *supported = !hdrCapabilities.getSupportedHdrTypes().empty();
+
+    return NO_ERROR;
+}
+
 int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) {
     Surface* c = getSelf(window);
     return c->setSwapInterval(interval);
@@ -880,6 +926,12 @@
     case NATIVE_WINDOW_GET_FRAME_TIMESTAMPS:
         res = dispatchGetFrameTimestamps(args);
         break;
+    case NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT:
+        res = dispatchGetWideColorSupport(args);
+        break;
+    case NATIVE_WINDOW_GET_HDR_SUPPORT:
+        res = dispatchGetHdrSupport(args);
+        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -1044,6 +1096,16 @@
             outDisplayRetireTime, outDequeueReadyTime, outReleaseTime);
 }
 
+int Surface::dispatchGetWideColorSupport(va_list args) {
+    bool* outSupport = va_arg(args, bool*);
+    return getWideColorSupport(outSupport);
+}
+
+int Surface::dispatchGetHdrSupport(va_list args) {
+    bool* outSupport = va_arg(args, bool*);
+    return getHdrSupport(outSupport);
+}
+
 int Surface::connect(int api) {
     static sp<IProducerListener> listener = new DummyProducerListener();
     return connect(api, listener);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 012dbe7..da6f13d 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -19,11 +19,12 @@
 #include <gtest/gtest.h>
 
 #include <binder/ProcessState.h>
+#include <cutils/properties.h>
+#include <gui/BufferItemConsumer.h>
 #include <gui/IDisplayEventConnection.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
-#include <gui/BufferItemConsumer.h>
 #include <private/gui/ComposerService.h>
 #include <ui/Rect.h>
 #include <utils/String8.h>
@@ -252,6 +253,35 @@
     EXPECT_STREQ("TestConsumer", surface->getConsumerName().string());
 }
 
+TEST_F(SurfaceTest, GetWideColorSupport) {
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+
+    sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+    consumer->consumerConnect(dummyConsumer, false);
+    consumer->setConsumerName(String8("TestConsumer"));
+
+    sp<Surface> surface = new Surface(producer);
+    sp<ANativeWindow> window(surface);
+    native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU);
+
+    bool supported;
+    surface->getWideColorSupport(&supported);
+
+    // TODO(courtneygo): How can we know what device we are on to
+    // verify that this is correct?
+    char product[PROPERTY_VALUE_MAX] = "0";
+    property_get("ro.build.product", product, "0");
+    std::cerr << "[          ] product = " << product << std::endl;
+
+    if (strcmp("marlin", product) == 0 || strcmp("sailfish", product) == 0) {
+        ASSERT_EQ(true, supported);
+    } else {
+        ASSERT_EQ(false, supported);
+    }
+}
+
 TEST_F(SurfaceTest, DynamicSetBufferCount) {
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index c4d8f76..9006178 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "GraphicBuffer"
 
+#include <cutils/atomic.h>
+
 #include <ui/GraphicBuffer.h>
 
 #include <cutils/atomic.h>
diff --git a/libs/vr/libsensor/Android.mk b/libs/vr/libsensor/Android.mk
index 89abcb0..8c7ad43 100644
--- a/libs/vr/libsensor/Android.mk
+++ b/libs/vr/libsensor/Android.mk
@@ -32,7 +32,6 @@
 	libhardware \
 	liblog \
 	libutils \
-	libandroid \
 
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(sourceFiles)
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 0ac74db..740ead3 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -623,9 +623,9 @@
 #define EGL_ANDROID_get_native_client_buffer 1
 struct AHardwareBuffer;
 #ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLClientBuffer eglGetNativeClientBufferANDROID (const AHardwareBuffer *buffer);
+EGLAPI EGLClientBuffer eglGetNativeClientBufferANDROID (const struct AHardwareBuffer *buffer);
 #else
-typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETNATIVECLIENTBUFFERANDROID) (const AHardwareBuffer *buffer);
+typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETNATIVECLIENTBUFFERANDROID) (const struct AHardwareBuffer *buffer);
 #endif
 #endif
 
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 3359c64..e52713f 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -126,6 +126,7 @@
         "EGL_EXT_yuv_surface "
         "EGL_EXT_protected_content "
         "EGL_IMG_context_priority "
+        "EGL_KHR_no_config_context "
         ;
 
 // extensions not exposed to applications but used by the ANDROID system
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 24ebac7..c3f8665 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -604,14 +604,15 @@
     // this gives us only the "orientation" component of the transform
     const State& s(getDrawingState());
 #ifdef USE_HWC2
+    auto blendMode = HWC2::BlendMode::None;
     if (!isOpaque(s) || s.alpha != 1.0f) {
-        auto blendMode = mPremultipliedAlpha ?
+        blendMode = mPremultipliedAlpha ?
                 HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage;
-        auto error = hwcLayer->setBlendMode(blendMode);
-        ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set blend mode %s:"
-                " %s (%d)", mName.string(), to_string(blendMode).c_str(),
-                to_string(error).c_str(), static_cast<int32_t>(error));
     }
+    auto error = hwcLayer->setBlendMode(blendMode);
+    ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set blend mode %s:"
+             " %s (%d)", mName.string(), to_string(blendMode).c_str(),
+             to_string(error).c_str(), static_cast<int32_t>(error));
 #else
     if (!isOpaque(s) || s.alpha != 0xFF) {
         layer.setBlending(mPremultipliedAlpha ?
@@ -666,7 +667,7 @@
     }
     const Transform& tr(displayDevice->getTransform());
     Rect transformedFrame = tr.transform(frame);
-    auto error = hwcLayer->setDisplayFrame(transformedFrame);
+    error = hwcLayer->setDisplayFrame(transformedFrame);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)",
                 mName.string(), transformedFrame.left, transformedFrame.top,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4acdb82..daeac27 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -156,6 +156,7 @@
         mVisibleRegionsDirty(false),
         mGeometryInvalid(false),
         mAnimCompositionPending(false),
+        mVrModeSupported(0),
         mDebugRegion(0),
         mDebugDDMS(0),
         mDebugDisableHWC(0),
@@ -185,6 +186,10 @@
     // debugging stuff...
     char value[PROPERTY_VALUE_MAX];
 
+    // TODO (urbanus): remove once b/35319396 is fixed.
+    property_get("ro.boot.vr", value, "0");
+    mVrModeSupported = atoi(value);
+
     property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
     mGpuToCpuSupported = !atoi(value);
 
@@ -1262,8 +1267,11 @@
     ATRACE_CALL();
     switch (what) {
         case MessageQueue::INVALIDATE: {
-            // TODO(eieio): Disabled until SELinux issues are resolved.
-            //updateVrMode();
+            // TODO(eieio): Tied to a conditional until SELinux issues
+            // are resolved.
+            if (mVrModeSupported) {
+                updateVrMode();
+            }
 
             bool frameMissed = !mHadClientComposition &&
                     mPreviousPresentFence != Fence::NO_FENCE &&
@@ -1586,6 +1594,9 @@
                             layer->setHwcLayer(displayDevice->getHwcDisplayId(),
                                     nullptr);
                         }
+                    } else {
+                        layer->setHwcLayer(displayDevice->getHwcDisplayId(),
+                                nullptr);
                     }
                 });
             }
@@ -1640,7 +1651,6 @@
             if (hwcId >= 0) {
                 const Vector<sp<Layer>>& currentLayers(
                         displayDevice->getVisibleLayersSortedByZ());
-                bool foundLayerWithoutHwc = false;
                 for (size_t i = 0; i < currentLayers.size(); i++) {
                     const auto& layer = currentLayers[i];
                     if (!layer->hasHwcLayer(hwcId)) {
@@ -1649,7 +1659,6 @@
                             layer->setHwcLayer(hwcId, std::move(hwcLayer));
                         } else {
                             layer->forceClientComposition(hwcId);
-                            foundLayerWithoutHwc = true;
                             continue;
                         }
                     }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0b3deef..d63c0bb 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -557,6 +557,7 @@
     DefaultKeyedVector< wp<IBinder>, sp<DisplayDevice> > mDisplays;
 
     // don't use a lock for these, we don't care
+    int mVrModeSupported;
     int mDebugRegion;
     int mDebugDDMS;
     int mDebugDisableHWC;
diff --git a/services/vr/virtual_touchpad/Android.mk b/services/vr/virtual_touchpad/Android.mk
index 4224aaa..b78eb99 100644
--- a/services/vr/virtual_touchpad/Android.mk
+++ b/services/vr/virtual_touchpad/Android.mk
@@ -6,13 +6,14 @@
 
 src := \
   EvdevInjector.cpp \
-  VirtualTouchpad.cpp
+  VirtualTouchpadEvdev.cpp
 
 shared_libs := \
   libbase
 
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(src)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 LOCAL_SHARED_LIBRARIES := $(shared_libs)
 LOCAL_CPPFLAGS += -std=c++11
 LOCAL_CFLAGS += -DLOG_TAG=\"VrVirtualTouchpad\"
@@ -29,11 +30,13 @@
 static_libs := \
   libbase \
   libcutils \
+  libutils \
   libvirtualtouchpad
 
 $(foreach file,$(test_src_files), \
     $(eval include $(CLEAR_VARS)) \
     $(eval LOCAL_SRC_FILES := $(file)) \
+    $(eval LOCAL_C_INCLUDES := $(LOCAL_PATH)/include) \
     $(eval LOCAL_STATIC_LIBRARIES := $(static_libs)) \
     $(eval LOCAL_SHARED_LIBRARIES := $(shared_libs)) \
     $(eval LOCAL_CPPFLAGS += -std=c++11) \
@@ -63,6 +66,7 @@
 
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(src)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 LOCAL_STATIC_LIBRARIES := $(static_libs)
 LOCAL_SHARED_LIBRARIES := $(shared_libs)
 LOCAL_CPPFLAGS += -std=c++11
@@ -74,3 +78,27 @@
 LOCAL_MULTILIB := 64
 LOCAL_CXX_STL := libc++_static
 include $(BUILD_EXECUTABLE)
+
+
+# Touchpad client library.
+
+src := \
+  VirtualTouchpadClient.cpp \
+  aidl/android/dvr/VirtualTouchpadService.aidl
+
+shared_libs := \
+  libbase \
+  libbinder \
+  libutils
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(src)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := $(shared_libs)
+LOCAL_CPPFLAGS += -std=c++11
+LOCAL_CFLAGS += -DLOG_TAG=\"VirtualTouchpadClient\"
+LOCAL_LDLIBS := -llog
+LOCAL_MODULE := libvirtualtouchpadclient
+LOCAL_MODULE_TAGS := optional
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+include $(BUILD_STATIC_LIBRARY)
diff --git a/services/vr/virtual_touchpad/VirtualTouchpad.h b/services/vr/virtual_touchpad/VirtualTouchpad.h
deleted file mode 100644
index 17aeb35..0000000
--- a/services/vr/virtual_touchpad/VirtualTouchpad.h
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef ANDROID_DVR_VIRTUAL_TOUCHPAD_H
-#define ANDROID_DVR_VIRTUAL_TOUCHPAD_H
-
-#include <memory>
-
-#include "EvdevInjector.h"
-
-namespace android {
-namespace dvr {
-
-class EvdevInjector;
-
-// Provides a virtual touchpad for injecting events into the input system.
-//
-class VirtualTouchpad {
- public:
-  VirtualTouchpad() {}
-  ~VirtualTouchpad() {}
-
-  // |Intialize()| must be called once on a VirtualTouchpad before
-  // and other public method. Returns zero on success.
-  int Initialize();
-
-  // Generate a simulated touch event.
-  //
-  // @param x Horizontal touch position.
-  // @param y Vertical touch position.
-  //            Values must be in the range [0.0, 1.0).
-  // @param pressure Touch pressure.
-  //            Positive values represent contact; use 1.0f if contact
-  //            is binary. Use 0.0f for no contact.
-  // @returns Zero on success.
-  //
-  int Touch(float x, float y, float pressure);
-
-  // Generate a simulated touchpad button state.
-  //
-  // @param buttons A union of MotionEvent BUTTON_* values.
-  // @returns Zero on success.
-  //
-  // Currently only BUTTON_BACK is supported, as the implementation
-  // restricts itself to operations actually required by VrWindowManager.
-  //
-  int ButtonState(int buttons);
-
- protected:
-  // Must be called only between construction and Initialize().
-  inline void SetEvdevInjectorForTesting(EvdevInjector* injector) {
-    injector_ = injector;
-  }
-
- private:
-  // Except for testing, the |EvdevInjector| used to inject evdev events.
-  std::unique_ptr<EvdevInjector> owned_injector_;
-
-  // Active pointer to |owned_injector_| or to a testing injector.
-  EvdevInjector* injector_ = nullptr;
-
-  // Previous (x, y) position in device space, to suppress redundant events.
-  int32_t last_device_x_ = INT32_MIN;
-  int32_t last_device_y_ = INT32_MIN;
-
-  // Records current touch state (0=up 1=down) in bit 0, and previous state
-  // in bit 1, to track transitions.
-  int touches_ = 0;
-
-  // Previous injected button state, to detect changes.
-  int32_t last_motion_event_buttons_ = 0;
-
-  VirtualTouchpad(const VirtualTouchpad&) = delete;
-  void operator=(const VirtualTouchpad&) = delete;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_VIRTUAL_TOUCHPAD_H
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
new file mode 100644
index 0000000..23a2e31
--- /dev/null
+++ b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
@@ -0,0 +1,52 @@
+#include "VirtualTouchpadClient.h"
+
+#include <android/dvr/IVirtualTouchpadService.h>
+#include <binder/IServiceManager.h>
+
+namespace android {
+namespace dvr {
+
+namespace {
+
+class VirtualTouchpadClientImpl : public VirtualTouchpadClient {
+ public:
+  VirtualTouchpadClientImpl(sp<IVirtualTouchpadService> service)
+      : service_(service) {}
+  ~VirtualTouchpadClientImpl() {}
+
+  status_t Touch(float x, float y, float pressure) override {
+    if (service_ == nullptr) {
+      return NO_INIT;
+    }
+    return service_->touch(x, y, pressure).transactionError();
+  }
+  status_t ButtonState(int buttons) override {
+    if (service_ == nullptr) {
+      return NO_INIT;
+    }
+    return service_->buttonState(buttons).transactionError();
+  }
+
+ private:
+  sp<IVirtualTouchpadService> service_;
+};
+
+}  // anonymous namespace
+
+sp<VirtualTouchpad> VirtualTouchpadClient::Create() {
+  sp<IServiceManager> sm = defaultServiceManager();
+  if (sm == nullptr) {
+    ALOGE("no service manager");
+    return sp<VirtualTouchpad>();
+  }
+  sp<IVirtualTouchpadService> service = interface_cast<IVirtualTouchpadService>(
+      sm->getService(IVirtualTouchpadService::SERVICE_NAME()));
+  if (service == nullptr) {
+    ALOGE("failed to get service");
+    return sp<VirtualTouchpad>();
+  }
+  return new VirtualTouchpadClientImpl(service);
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/virtual_touchpad/VirtualTouchpad.cpp b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
similarity index 87%
rename from services/vr/virtual_touchpad/VirtualTouchpad.cpp
rename to services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
index 4793058..ae31156 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpad.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
@@ -1,4 +1,4 @@
-#include "VirtualTouchpad.h"
+#include "VirtualTouchpadEvdev.h"
 
 #include <android/input.h>
 #include <inttypes.h>
@@ -30,7 +30,17 @@
 
 }  // anonymous namespace
 
-int VirtualTouchpad::Initialize() {
+sp<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
+  VirtualTouchpadEvdev* const touchpad = new VirtualTouchpadEvdev();
+  const status_t status = touchpad->Initialize();
+  if (status) {
+    ALOGE("initialization failed: %d", status);
+    return sp<VirtualTouchpad>();
+  }
+  return sp<VirtualTouchpad>(touchpad);
+}
+
+int VirtualTouchpadEvdev::Initialize() {
   if (!injector_) {
     owned_injector_.reset(new EvdevInjector());
     injector_ = owned_injector_.get();
@@ -46,7 +56,7 @@
   return injector_->GetError();
 }
 
-int VirtualTouchpad::Touch(float x, float y, float pressure) {
+int VirtualTouchpadEvdev::Touch(float x, float y, float pressure) {
   if ((x < 0.0f) || (x >= 1.0f) || (y < 0.0f) || (y >= 1.0f)) {
     return EINVAL;
   }
@@ -91,7 +101,7 @@
   return injector_->GetError();
 }
 
-int VirtualTouchpad::ButtonState(int buttons) {
+int VirtualTouchpadEvdev::ButtonState(int buttons) {
   const int changes = last_motion_event_buttons_ ^ buttons;
   if (!changes) {
     return 0;
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
new file mode 100644
index 0000000..c763529
--- /dev/null
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
@@ -0,0 +1,59 @@
+#ifndef ANDROID_DVR_VIRTUAL_TOUCHPAD_EVDEV_H
+#define ANDROID_DVR_VIRTUAL_TOUCHPAD_EVDEV_H
+
+#include <memory>
+
+#include "VirtualTouchpad.h"
+#include "EvdevInjector.h"
+
+namespace android {
+namespace dvr {
+
+class EvdevInjector;
+
+// VirtualTouchpadEvdev implements a VirtualTouchpad by injecting evdev events.
+//
+class VirtualTouchpadEvdev : public VirtualTouchpad {
+ public:
+  static sp<VirtualTouchpad> Create();
+
+  // VirtualTouchpad implementation:
+  status_t Touch(float x, float y, float pressure) override;
+  status_t ButtonState(int buttons) override;
+
+ protected:
+  VirtualTouchpadEvdev() {}
+  ~VirtualTouchpadEvdev() {}
+  status_t Initialize();
+
+  // Must be called only between construction and Initialize().
+  inline void SetEvdevInjectorForTesting(EvdevInjector* injector) {
+    injector_ = injector;
+  }
+
+ private:
+  // Except for testing, the |EvdevInjector| used to inject evdev events.
+  std::unique_ptr<EvdevInjector> owned_injector_;
+
+  // Active pointer to |owned_injector_| or to a testing injector.
+  EvdevInjector* injector_ = nullptr;
+
+  // Previous (x, y) position in device space, to suppress redundant events.
+  int32_t last_device_x_ = INT32_MIN;
+  int32_t last_device_y_ = INT32_MIN;
+
+  // Records current touch state (0=up 1=down) in bit 0, and previous state
+  // in bit 1, to track transitions.
+  int touches_ = 0;
+
+  // Previous injected button state, to detect changes.
+  int32_t last_motion_event_buttons_ = 0;
+
+  VirtualTouchpadEvdev(const VirtualTouchpadEvdev&) = delete;
+  void operator=(const VirtualTouchpadEvdev&) = delete;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_VIRTUAL_TOUCHPAD_EVDEV_H
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
index 25c1a4f..3fcb8fc 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
@@ -8,19 +8,15 @@
 namespace android {
 namespace dvr {
 
-int VirtualTouchpadService::Initialize() {
-  return touchpad_.Initialize();
-}
-
 binder::Status VirtualTouchpadService::touch(float x, float y, float pressure) {
-  const int error = touchpad_.Touch(x, y, pressure);
-  return error ? binder::Status::fromServiceSpecificError(error)
+  const status_t error = touchpad_->Touch(x, y, pressure);
+  return error ? binder::Status::fromStatusT(error)
                : binder::Status::ok();
 }
 
 binder::Status VirtualTouchpadService::buttonState(int buttons) {
-  const int error = touchpad_.ButtonState(buttons);
-  return error ? binder::Status::fromServiceSpecificError(error)
+  const status_t error = touchpad_->ButtonState(buttons);
+  return error ? binder::Status::fromStatusT(error)
                : binder::Status::ok();
 }
 
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.h b/services/vr/virtual_touchpad/VirtualTouchpadService.h
index e2426e3..b832c8f 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.h
@@ -13,22 +13,16 @@
 //
 class VirtualTouchpadService : public BnVirtualTouchpadService {
  public:
-  VirtualTouchpadService(VirtualTouchpad& touchpad)
+  VirtualTouchpadService(sp<VirtualTouchpad> touchpad)
       : touchpad_(touchpad) {}
 
-  // Must be called before clients can connect.
-  // Returns 0 if initialization is successful.
-  int Initialize();
-
-  static char const* getServiceName() { return "virtual_touchpad"; }
-
  protected:
   // Implements IVirtualTouchpadService.
-  ::android::binder::Status touch(float x, float y, float pressure) override;
-  ::android::binder::Status buttonState(int buttons) override;
+  binder::Status touch(float x, float y, float pressure) override;
+  binder::Status buttonState(int buttons) override;
 
  private:
-  VirtualTouchpad& touchpad_;
+  sp<VirtualTouchpad> touchpad_;
 
   VirtualTouchpadService(const VirtualTouchpadService&) = delete;
   void operator=(const VirtualTouchpadService&) = delete;
diff --git a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
index e048837..c2044da 100644
--- a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
+++ b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
@@ -3,6 +3,8 @@
 /** @hide */
 interface VirtualTouchpadService
 {
+  const String SERVICE_NAME = "virtual_touchpad";
+
   /**
    * Generate a simulated touch event.
    *
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpad.h b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
new file mode 100644
index 0000000..bbaf69b
--- /dev/null
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
@@ -0,0 +1,57 @@
+#ifndef ANDROID_DVR_VIRTUAL_TOUCHPAD_INTERFACE_H
+#define ANDROID_DVR_VIRTUAL_TOUCHPAD_INTERFACE_H
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace dvr {
+
+// Provides a virtual touchpad for injecting events into the input system.
+//
+class VirtualTouchpad : public RefBase {
+ public:
+  // Create a virtual touchpad.
+  // Implementations should provide this, and hide their constructors.
+  // For the user, switching implementations should be as simple as changing
+  // the class whose |Create()| is called.
+  static sp<VirtualTouchpad> Create() {
+    return sp<VirtualTouchpad>();
+  }
+
+  // Generate a simulated touch event.
+  //
+  // @param x Horizontal touch position.
+  // @param y Vertical touch position.
+  //            Values must be in the range [0.0, 1.0).
+  // @param pressure Touch pressure.
+  //            Positive values represent contact; use 1.0f if contact
+  //            is binary. Use 0.0f for no contact.
+  // @returns OK on success.
+  //
+  virtual status_t Touch(float x, float y, float pressure) = 0;
+
+  // Generate a simulated touchpad button state.
+  //
+  // @param buttons A union of MotionEvent BUTTON_* values.
+  // @returns OK on success.
+  //
+  // Currently only BUTTON_BACK is supported, as the implementation
+  // restricts itself to operations actually required by VrWindowManager.
+  //
+  virtual status_t ButtonState(int buttons) = 0;
+
+ protected:
+  VirtualTouchpad() {}
+  virtual ~VirtualTouchpad() {}
+
+ private:
+  VirtualTouchpad(const VirtualTouchpad&) = delete;
+  void operator=(const VirtualTouchpad&) = delete;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_VIRTUAL_TOUCHPAD_INTERFACE_H
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
new file mode 100644
index 0000000..46bec0e
--- /dev/null
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
@@ -0,0 +1,31 @@
+#ifndef ANDROID_DVR_VIRTUAL_TOUCHPAD_CLIENT_H
+#define ANDROID_DVR_VIRTUAL_TOUCHPAD_CLIENT_H
+
+#include "VirtualTouchpad.h"
+
+namespace android {
+namespace dvr {
+
+// VirtualTouchpadClient implements a VirtualTouchpad by connecting to
+// a VirtualTouchpadService over Binder.
+//
+class VirtualTouchpadClient : public VirtualTouchpad {
+ public:
+  // VirtualTouchpad implementation:
+  static sp<VirtualTouchpad> Create();
+  status_t Touch(float x, float y, float pressure) override;
+  status_t ButtonState(int buttons) override;
+
+ protected:
+  VirtualTouchpadClient() {}
+  virtual ~VirtualTouchpadClient() {}
+
+ private:
+  VirtualTouchpadClient(const VirtualTouchpadClient&) = delete;
+  void operator=(const VirtualTouchpadClient&) = delete;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_VIRTUAL_TOUCHPAD_CLIENT_H
diff --git a/services/vr/virtual_touchpad/main.cpp b/services/vr/virtual_touchpad/main.cpp
index 1debe9f..e73f8b9 100644
--- a/services/vr/virtual_touchpad/main.cpp
+++ b/services/vr/virtual_touchpad/main.cpp
@@ -3,17 +3,13 @@
 #include <binder/ProcessState.h>
 #include <log/log.h>
 
+#include "VirtualTouchpadEvdev.h"
 #include "VirtualTouchpadService.h"
 
 int main() {
   ALOGI("Starting");
-  android::dvr::VirtualTouchpad touchpad;
-  android::dvr::VirtualTouchpadService touchpad_service(touchpad);
-  const int touchpad_status = touchpad_service.Initialize();
-  if (touchpad_status) {
-    ALOGE("virtual touchpad initialization failed: %d", touchpad_status);
-    exit(1);
-  }
+  android::dvr::VirtualTouchpadService touchpad_service(
+      android::dvr::VirtualTouchpadEvdev::Create());
 
   signal(SIGPIPE, SIG_IGN);
   android::sp<android::ProcessState> ps(android::ProcessState::self());
@@ -23,7 +19,7 @@
 
   android::sp<android::IServiceManager> sm(android::defaultServiceManager());
   const android::status_t service_status =
-      sm->addService(android::String16(touchpad_service.getServiceName()),
+      sm->addService(android::String16(touchpad_service.SERVICE_NAME()),
                      &touchpad_service, false /*allowIsolated*/);
   if (service_status != android::OK) {
     ALOGE("virtual touchpad service not added: %d",
diff --git a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
index 256c6bc..b448fd1 100644
--- a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
+++ b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
@@ -1,12 +1,12 @@
 #include <android/input.h>
+#include <gtest/gtest.h>
+#include <linux/input.h>
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
-#include <gtest/gtest.h>
-#include <linux/input.h>
 
 #include "EvdevInjector.h"
-#include "VirtualTouchpad.h"
+#include "VirtualTouchpadEvdev.h"
 
 namespace android {
 namespace dvr {
@@ -21,7 +21,7 @@
     event.type = type;
     event.code = code;
     event.value = value;
-    Write(&event, sizeof (event));
+    Write(&event, sizeof(event));
   }
 };
 
@@ -87,16 +87,17 @@
 
 class EvdevInjectorForTesting : public EvdevInjector {
  public:
-  EvdevInjectorForTesting(UInput& uinput) {
-    SetUInputForTesting(&uinput);
-  }
+  EvdevInjectorForTesting(UInput& uinput) { SetUInputForTesting(&uinput); }
   const uinput_user_dev* GetUiDev() const { return GetUiDevForTesting(); }
 };
 
-class VirtualTouchpadForTesting : public VirtualTouchpad {
+class VirtualTouchpadForTesting : public VirtualTouchpadEvdev {
  public:
-  VirtualTouchpadForTesting(EvdevInjector& injector) {
-    SetEvdevInjectorForTesting(&injector);
+  static sp<VirtualTouchpad> Create(EvdevInjectorForTesting& injector) {
+    VirtualTouchpadForTesting* const touchpad = new VirtualTouchpadForTesting();
+    touchpad->SetEvdevInjectorForTesting(&injector);
+    touchpad->Initialize();
+    return sp<VirtualTouchpad>(touchpad);
   }
 };
 
@@ -113,17 +114,13 @@
 
 }  // anonymous namespace
 
-class VirtualTouchpadTest : public testing::Test {
-};
+class VirtualTouchpadTest : public testing::Test {};
 
 TEST_F(VirtualTouchpadTest, Goodness) {
   UInputRecorder expect;
   UInputRecorder record;
   EvdevInjectorForTesting injector(record);
-  VirtualTouchpadForTesting touchpad(injector);
-
-  const int initialization_status = touchpad.Initialize();
-  EXPECT_EQ(0, initialization_status);
+  sp<VirtualTouchpad> touchpad(VirtualTouchpadForTesting::Create(injector));
 
   // Check some aspects of uinput_user_dev.
   const uinput_user_dev* uidev = injector.GetUiDev();
@@ -154,13 +151,13 @@
   expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY);
   expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH);
   // From ConfigureEnd():
-  expect.Write(uidev, sizeof (uinput_user_dev));
+  expect.Write(uidev, sizeof(uinput_user_dev));
   expect.IoctlVoid(UI_DEV_CREATE);
   EXPECT_EQ(expect.GetString(), record.GetString());
 
   expect.Reset();
   record.Reset();
-  int touch_status = touchpad.Touch(0, 0, 0);
+  int touch_status = touchpad->Touch(0, 0, 0);
   EXPECT_EQ(0, touch_status);
   expect.WriteInputEvent(EV_ABS, ABS_MT_SLOT, 0);
   expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
@@ -171,7 +168,7 @@
 
   expect.Reset();
   record.Reset();
-  touch_status = touchpad.Touch(0.25f, 0.75f, 0.5f);
+  touch_status = touchpad->Touch(0.25f, 0.75f, 0.5f);
   EXPECT_EQ(0, touch_status);
   expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
   expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.25f * width);
@@ -182,7 +179,7 @@
 
   expect.Reset();
   record.Reset();
-  touch_status = touchpad.Touch(1.0f, 1.0f, 1.0f);
+  touch_status = touchpad->Touch(1.0f, 1.0f, 1.0f);
   EXPECT_EQ(0, touch_status);
   expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
   expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, width);
@@ -192,7 +189,7 @@
 
   expect.Reset();
   record.Reset();
-  touch_status = touchpad.Touch(0.25f, 0.75f, -0.01f);
+  touch_status = touchpad->Touch(0.25f, 0.75f, -0.01f);
   EXPECT_EQ(0, touch_status);
   expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_RELEASE);
   expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
@@ -201,7 +198,7 @@
 
   expect.Reset();
   record.Reset();
-  touch_status = touchpad.ButtonState(AMOTION_EVENT_BUTTON_BACK);
+  touch_status = touchpad->ButtonState(AMOTION_EVENT_BUTTON_BACK);
   EXPECT_EQ(0, touch_status);
   expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_PRESS);
   expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
@@ -209,13 +206,13 @@
 
   expect.Reset();
   record.Reset();
-  touch_status = touchpad.ButtonState(AMOTION_EVENT_BUTTON_BACK);
+  touch_status = touchpad->ButtonState(AMOTION_EVENT_BUTTON_BACK);
   EXPECT_EQ(0, touch_status);
   EXPECT_EQ(expect.GetString(), record.GetString());
 
   expect.Reset();
   record.Reset();
-  touch_status = touchpad.ButtonState(0);
+  touch_status = touchpad->ButtonState(0);
   EXPECT_EQ(0, touch_status);
   expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_RELEASE);
   expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
@@ -229,56 +226,29 @@
   UInputRecorder expect;
   UInputRecorder record;
   EvdevInjectorForTesting injector(record);
-  VirtualTouchpadForTesting touchpad(injector);
-
-  // Touch before initialization should return an error,
-  // and should not result in any system calls.
-  expect.Reset();
-  record.Reset();
-  int touch_status = touchpad.Touch(0.25f, 0.75f, -0.01f);
-  EXPECT_NE(0, touch_status);
-  EXPECT_EQ(expect.GetString(), record.GetString());
-
-  // Button change before initialization should return an error,
-  // and should not result in any system calls.
-  expect.Reset();
-  record.Reset();
-  touch_status = touchpad.ButtonState(AMOTION_EVENT_BUTTON_BACK);
-  EXPECT_NE(0, touch_status);
-  EXPECT_EQ(expect.GetString(), record.GetString());
-
-  expect.Reset();
-  record.Reset();
-  touchpad.Initialize();
-
-  // Repeated initialization should return an error,
-  // and should not result in any system calls.
-  expect.Reset();
-  record.Reset();
-  const int initialization_status = touchpad.Initialize();
-  EXPECT_NE(0, initialization_status);
-  EXPECT_EQ(expect.GetString(), record.GetString());
+  sp<VirtualTouchpad> touchpad(
+      VirtualTouchpadForTesting::Create(injector));
 
   // Touch off-screen should return an error,
   // and should not result in any system calls.
   expect.Reset();
   record.Reset();
-  touch_status = touchpad.Touch(-0.25f, 0.75f, 1.0f);
-  EXPECT_NE(0, touch_status);
-  touch_status = touchpad.Touch(0.25f, -0.75f, 1.0f);
-  EXPECT_NE(0, touch_status);
-  touch_status = touchpad.Touch(1.25f, 0.75f, 1.0f);
-  EXPECT_NE(0, touch_status);
-  touch_status = touchpad.Touch(0.25f, 1.75f, 1.0f);
-  EXPECT_NE(0, touch_status);
+  status_t touch_status = touchpad->Touch(-0.25f, 0.75f, 1.0f);
+  EXPECT_NE(OK, touch_status);
+  touch_status = touchpad->Touch(0.25f, -0.75f, 1.0f);
+  EXPECT_NE(OK, touch_status);
+  touch_status = touchpad->Touch(1.25f, 0.75f, 1.0f);
+  EXPECT_NE(OK, touch_status);
+  touch_status = touchpad->Touch(0.25f, 1.75f, 1.0f);
+  EXPECT_NE(OK, touch_status);
   EXPECT_EQ(expect.GetString(), record.GetString());
 
   // Unsupported button should return an error,
   // and should not result in any system calls.
   expect.Reset();
   record.Reset();
-  touch_status = touchpad.ButtonState(AMOTION_EVENT_BUTTON_FORWARD);
-  EXPECT_NE(0, touch_status);
+  touch_status = touchpad->ButtonState(AMOTION_EVENT_BUTTON_FORWARD);
+  EXPECT_NE(OK, touch_status);
   EXPECT_EQ(expect.GetString(), record.GetString());
 }
 
diff --git a/services/vr/vr_window_manager/Android.mk b/services/vr/vr_window_manager/Android.mk
index e9552bc..ddb58e9 100644
--- a/services/vr/vr_window_manager/Android.mk
+++ b/services/vr/vr_window_manager/Android.mk
@@ -14,29 +14,6 @@
 
 LOCAL_PATH := $(call my-dir)
 
-binder_src := \
-  vr_window_manager_binder.cpp \
-  aidl/android/service/vr/IVrWindowManager.aidl
-
-static_libs := \
-  libcutils
-
-shared_libs := \
-  libbase \
-  libbinder \
-  libutils
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(binder_src)
-LOCAL_STATIC_LIBRARIES := $(static_libs)
-LOCAL_SHARED_LIBRARIES := $(shared_libs)
-LOCAL_CPPFLAGS += -std=c++11
-LOCAL_CFLAGS += -DLOG_TAG=\"VrWindowManager\"
-LOCAL_LDLIBS := -llog
-LOCAL_MODULE := libvrwm_binder
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_STATIC_LIBRARY)
-
 native_src := \
   application.cpp \
   controller_mesh.cpp \
@@ -47,7 +24,8 @@
   surface_flinger_view.cpp \
   texture.cpp \
   vr_window_manager.cpp \
-  ../virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl \
+  vr_window_manager_binder.cpp \
+  aidl/android/service/vr/IVrWindowManager.aidl
 
 static_libs := \
   libdisplay \
@@ -61,12 +39,13 @@
   libperformance \
   libpdx_default_transport \
   libcutils \
+  libvr_manager \
+  libvirtualtouchpadclient
 
 shared_libs := \
   android.dvr.composer@1.0 \
   android.hardware.graphics.composer@2.1 \
   libvrhwc \
-  libandroid \
   libbase \
   libbinder \
   libinput \
@@ -85,7 +64,7 @@
 
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(native_src)
-LOCAL_STATIC_LIBRARIES := $(static_libs) libvrwm_binder
+LOCAL_STATIC_LIBRARIES := $(static_libs)
 LOCAL_SHARED_LIBRARIES := $(shared_libs)
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES
 LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES
diff --git a/services/vr/vr_window_manager/application.cpp b/services/vr/vr_window_manager/application.cpp
index 467e95e..dba797f 100644
--- a/services/vr/vr_window_manager/application.cpp
+++ b/services/vr/vr_window_manager/application.cpp
@@ -17,9 +17,16 @@
 namespace android {
 namespace dvr {
 
-Application::Application() {}
+Application::Application() {
+  vr_mode_listener_ = new VrModeListener(this);
+}
 
 Application::~Application() {
+  sp<IVrManager> vrManagerService = interface_cast<IVrManager>(
+      defaultServiceManager()->getService(String16("vrmanager")));
+  if (vrManagerService.get()) {
+    vrManagerService->unregisterListener(vr_mode_listener_);
+  }
 }
 
 int Application::Initialize() {
@@ -29,6 +36,11 @@
   elbow_model_.Enable(ElbowModel::kDefaultNeckPosition, is_right_handed);
   last_frame_time_ = std::chrono::system_clock::now();
 
+  sp<IVrManager> vrManagerService = interface_cast<IVrManager>(
+      defaultServiceManager()->getService(String16("vrmanager")));
+  if (vrManagerService.get()) {
+    vrManagerService->registerListener(vr_mode_listener_);
+  }
   return 0;
 }
 
@@ -274,6 +286,11 @@
 }
 
 void Application::SetVisibility(bool visible) {
+  if (visible && !initialized_) {
+    if (AllocateResources())
+      ALOGE("Failed to allocate resources");
+  }
+
   bool changed = is_visible_ != visible;
   if (changed) {
     is_visible_ = visible;
@@ -296,5 +313,10 @@
   wake_up_init_and_render_.notify_one();
 }
 
+void Application::VrModeListener::onVrStateChanged(bool enabled) {
+  if (!enabled)
+    app_->QueueTask(MainThreadTask::ExitingVrMode);
+}
+
 }  // namespace dvr
 }  // namespace android
diff --git a/services/vr/vr_window_manager/application.h b/services/vr/vr_window_manager/application.h
index c7aa4dd..2c60e0a 100644
--- a/services/vr/vr_window_manager/application.h
+++ b/services/vr/vr_window_manager/application.h
@@ -4,6 +4,7 @@
 #include <memory>
 #include <private/dvr/types.h>
 #include <stdint.h>
+#include <vr/vr_manager/vr_manager.h>
 
 #include <chrono>
 #include <mutex>
@@ -43,6 +44,16 @@
     Show,
   };
 
+  class VrModeListener : public BnVrStateCallbacks {
+   public:
+    VrModeListener(Application *app) : app_(app) {}
+    void onVrStateChanged(bool enabled) override;
+
+   private:
+    Application *app_;
+  };
+
+  sp<VrModeListener> vr_mode_listener_;
   virtual void OnDrawFrame() = 0;
   virtual void DrawEye(EyeType eye, const mat4& perspective,
                        const mat4& eye_matrix, const mat4& head_matrix) = 0;
diff --git a/services/vr/vr_window_manager/hwc_callback.h b/services/vr/vr_window_manager/hwc_callback.h
index bcfeb97..be56856 100644
--- a/services/vr/vr_window_manager/hwc_callback.h
+++ b/services/vr/vr_window_manager/hwc_callback.h
@@ -25,7 +25,8 @@
   struct HwcLayer {
     enum LayerType : uint32_t {
       // These are from frameworks/base/core/java/android/view/WindowManager.java
-      kUndefinedWindow = 0,
+      kSurfaceFlingerLayer = 0,
+      kUndefinedWindow = ~0U,
       kFirstApplicationWindow = 1,
       kLastApplicationWindow = 99,
       kFirstSubWindow = 1000,
@@ -42,6 +43,19 @@
         // Always skip the following layer types
       case kNavigationBar:
       case kStatusBar:
+      case kSurfaceFlingerLayer:
+      case kUndefinedWindow:
+        return true;
+      default:
+        return false;
+      }
+    }
+
+    // This is a layer that provides some other functionality, eg dim layer.
+    // We use this to determine the point at which layers are "on top".
+    bool is_extra_layer() const {
+      switch(type) {
+      case kSurfaceFlingerLayer:
       case kUndefinedWindow:
         return true;
       default:
diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp
index 9d0aaad..7321ed0 100644
--- a/services/vr/vr_window_manager/shell_view.cpp
+++ b/services/vr/vr_window_manager/shell_view.cpp
@@ -195,7 +195,8 @@
                                             uint32_t vr_app) {
   auto& layers = frame.layers();
 
-  // We assume the first two layers are the VR app.
+  // We assume the first two layers are the VR app. In the case of a 2D app,
+  // there will be the app + at least one system layer so this is still safe.
   if (layers.size() < kVRAppLayerCount)
     return ViewMode::Hidden;
 
@@ -203,19 +204,23 @@
       layers[1].appid != layers[0].appid) {
     if (layers[1].appid != layers[0].appid && layers[0].appid) {
       // This might be a 2D app.
+      // If a dim layer exists afterwards it is much more likely that this is
+      // actually an app launch artifact.
+      for (size_t i = 2; i < layers.size(); i++) {
+        if (layers[i].is_extra_layer())
+          return ViewMode::Hidden;
+      }
       return ViewMode::App;
     }
     return ViewMode::Hidden;
   }
 
-  // If a non-VR-app, non-skipped layer appears, show.
   size_t index = kVRAppLayerCount;
   // Now, find a dim layer if it exists.
   // If it does, ignore any layers behind it for visibility determination.
   for (size_t i = index; i < layers.size(); i++) {
-    if (layers[i].appid == 0) {
+    if (layers[i].appid == HwcCallback::HwcLayer::kSurfaceFlingerLayer) {
       index = i + 1;
-      break;
     }
   }
 
@@ -419,7 +424,6 @@
   // so give it a kick.
   if (visibility != ViewMode::Hidden &&
       current_frame_.visibility == ViewMode::Hidden) {
-    QueueTask(MainThreadTask::EnteringVrMode);
     QueueTask(MainThreadTask::Show);
   }
 
@@ -699,10 +703,7 @@
 }
 
 bool ShellView::InitializeTouch() {
-  virtual_touchpad_ =
-      android::interface_cast<android::dvr::IVirtualTouchpadService>(
-          android::defaultServiceManager()->getService(
-              android::String16("virtual_touchpad")));
+  virtual_touchpad_ = VirtualTouchpadClient::Create();
   if (!virtual_touchpad_.get()) {
     ALOGE("Failed to connect to virtual touchpad");
     return false;
@@ -719,12 +720,12 @@
     }
   }
 
-  const android::binder::Status status = virtual_touchpad_->touch(
+  const android::status_t status = virtual_touchpad_->Touch(
       hit_location_in_window_coord_.x() / size_.x(),
       hit_location_in_window_coord_.y() / size_.y(),
       is_touching_ ? 1.0f : 0.0f);
-  if (!status.isOk()) {
-    ALOGE("touch failed: %s", status.toString8().string());
+  if (status != OK) {
+    ALOGE("touch failed: %d", status);
   }
 }
 
@@ -746,11 +747,10 @@
     return false;
   }
 
-  const android::binder::Status status =
-      virtual_touchpad_->buttonState(touchpad_buttons_);
-  if (!status.isOk()) {
-    ALOGE("touchpad button failed: %d %s", touchpad_buttons_,
-          status.toString8().string());
+  const android::status_t status =
+      virtual_touchpad_->ButtonState(touchpad_buttons_);
+  if (status != OK) {
+    ALOGE("touchpad button failed: %d %d", touchpad_buttons_, status);
   }
   return true;
 }
diff --git a/services/vr/vr_window_manager/shell_view.h b/services/vr/vr_window_manager/shell_view.h
index 1e061bb..c477669 100644
--- a/services/vr/vr_window_manager/shell_view.h
+++ b/services/vr/vr_window_manager/shell_view.h
@@ -3,10 +3,10 @@
 
 #include <private/dvr/graphics/mesh.h>
 #include <private/dvr/graphics/shader_program.h>
-#include <android/dvr/IVirtualTouchpadService.h>
 
 #include <deque>
 
+#include "VirtualTouchpadClient.h"
 #include "application.h"
 #include "reticle.h"
 #include "shell_view_binder_interface.h"
@@ -90,7 +90,7 @@
 
   std::unique_ptr<SurfaceFlingerView> surface_flinger_view_;
   std::unique_ptr<Reticle> reticle_;
-  sp<IVirtualTouchpadService> virtual_touchpad_;
+  sp<VirtualTouchpad> virtual_touchpad_;
   std::vector<TextureLayer> textures_;
   TextureLayer ime_texture_;
 
diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h
index 45b574a..3c8ee1c 100644
--- a/vulkan/include/vulkan/vulkan.h
+++ b/vulkan/include/vulkan/vulkan.h
@@ -3218,18 +3218,19 @@
 
 typedef enum VkColorSpaceKHR {
     VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0,
-    VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT = 1000104001,
-    VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104002,
-    VK_COLOR_SPACE_SCRGB_LINEAR_EXT = 1000104003,
-    VK_COLOR_SPACE_SCRGB_NONLINEAR_EXT = 1000104004,
-    VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = 1000104005,
-    VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104006,
-    VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104007,
-    VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104008,
-    VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104009,
-    VK_COLOR_SPACE_BT2020_NONLINEAR_EXT = 1000104010,
+    VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001,
+    VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT = 1000104002,
+    VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104003,
+    VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = 1000104004,
+    VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104005,
+    VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104006,
+    VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104007,
+    VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104008,
+    VK_COLOR_SPACE_BT2020_170M_EXT = 1000104009,
+    VK_COLOR_SPACE_BT2020_ST2084_EXT = 1000104010,
     VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011,
     VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012,
+    VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013,
     VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
     VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
     VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1),
@@ -4606,6 +4607,10 @@
     VkPastPresentationTimingGOOGLE*             pPresentationTimings);
 #endif
 
+#define VK_EXT_swapchain_colorspace 1
+#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 1
+#define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace"
+
 #define VK_EXT_hdr_metadata 1
 #define VK_EXT_HDR_METADATA_SPEC_VERSION  0
 #define VK_EXT_HDR_METADATA_EXTENSION_NAME "VK_EXT_hdr_metadata"
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index 4835a56..992c5d1 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -683,12 +683,13 @@
 VK_ANDROID_native_buffer
 VK_EXT_debug_report
 VK_EXT_hdr_metadata
+VK_EXT_swapchain_colorspace
 VK_GOOGLE_display_timing
 VK_KHR_android_surface
 VK_KHR_incremental_present
+VK_KHR_shared_presentable_image
 VK_KHR_surface
 VK_KHR_swapchain
-VK_KHR_shared_presentable_image
 {{end}}
 
 
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 76aa176..351caeb 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -447,6 +447,7 @@
         switch (ext_bit) {
             case ProcHook::KHR_android_surface:
             case ProcHook::KHR_surface:
+            case ProcHook::EXT_swapchain_colorspace:
                 hook_extensions_.set(ext_bit);
                 // return now as these extensions do not require HAL support
                 return;
@@ -673,11 +674,13 @@
     const char* pLayerName,
     uint32_t* pPropertyCount,
     VkExtensionProperties* pProperties) {
-    static const std::array<VkExtensionProperties, 2> loader_extensions = {{
+    static const std::array<VkExtensionProperties, 3> 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},
+        {VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME,
+         VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION},
     }};
     static const VkExtensionProperties loader_debug_report_extension = {
         VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION,
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index c4cb544..fc3f87a 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -365,12 +365,13 @@
     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_EXT_hdr_metadata") == 0) return ProcHook::EXT_hdr_metadata;
+    if (strcmp(name, "VK_EXT_swapchain_colorspace") == 0) return ProcHook::EXT_swapchain_colorspace;
     if (strcmp(name, "VK_GOOGLE_display_timing") == 0) return ProcHook::GOOGLE_display_timing;
     if (strcmp(name, "VK_KHR_android_surface") == 0) return ProcHook::KHR_android_surface;
     if (strcmp(name, "VK_KHR_incremental_present") == 0) return ProcHook::KHR_incremental_present;
+    if (strcmp(name, "VK_KHR_shared_presentable_image") == 0) return ProcHook::KHR_shared_presentable_image;
     if (strcmp(name, "VK_KHR_surface") == 0) return ProcHook::KHR_surface;
     if (strcmp(name, "VK_KHR_swapchain") == 0) return ProcHook::KHR_swapchain;
-    if (strcmp(name, "VK_KHR_shared_presentable_image") == 0) return ProcHook::KHR_shared_presentable_image;
     if (strcmp(name, "VK_KHR_get_physical_device_properties2") == 0) return ProcHook::KHR_get_physical_device_properties2;
     // clang-format on
     return ProcHook::EXTENSION_UNKNOWN;
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index c9dba78..738da5b 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -36,12 +36,13 @@
         ANDROID_native_buffer,
         EXT_debug_report,
         EXT_hdr_metadata,
+        EXT_swapchain_colorspace,
         GOOGLE_display_timing,
         KHR_android_surface,
         KHR_incremental_present,
+        KHR_shared_presentable_image,
         KHR_surface,
         KHR_swapchain,
-        KHR_shared_presentable_image,
         KHR_get_physical_device_properties2,
 
         EXTENSION_CORE,  // valid bit
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index e105922..a0ae1f3 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -380,6 +380,75 @@
     *count = num_copied;
 }
 
+android_pixel_format GetNativePixelFormat(VkFormat format) {
+    android_pixel_format native_format = HAL_PIXEL_FORMAT_RGBA_8888;
+    switch (format) {
+        case VK_FORMAT_R8G8B8A8_UNORM:
+        case VK_FORMAT_R8G8B8A8_SRGB:
+            native_format = HAL_PIXEL_FORMAT_RGBA_8888;
+            break;
+        case VK_FORMAT_R5G6B5_UNORM_PACK16:
+            native_format = HAL_PIXEL_FORMAT_RGB_565;
+            break;
+        case VK_FORMAT_R16G16B16A16_SFLOAT:
+            native_format = HAL_PIXEL_FORMAT_RGBA_FP16;
+            break;
+        case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
+            native_format = HAL_PIXEL_FORMAT_RGBA_1010102;
+            break;
+        default:
+            ALOGV("unsupported swapchain format %d", format);
+            break;
+    }
+    return native_format;
+}
+
+android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace) {
+    switch (colorspace) {
+        case VK_COLOR_SPACE_SRGB_NONLINEAR_KHR:
+            return HAL_DATASPACE_V0_SRGB;
+        case VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT:
+            return HAL_DATASPACE_DISPLAY_P3;
+        case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT:
+            return HAL_DATASPACE_V0_SCRGB_LINEAR;
+        case VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT:
+            return HAL_DATASPACE_V0_SCRGB;
+        case VK_COLOR_SPACE_DCI_P3_LINEAR_EXT:
+            return HAL_DATASPACE_DCI_P3_LINEAR;
+        case VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT:
+            return HAL_DATASPACE_DCI_P3;
+        case VK_COLOR_SPACE_BT709_LINEAR_EXT:
+            return HAL_DATASPACE_V0_SRGB_LINEAR;
+        case VK_COLOR_SPACE_BT709_NONLINEAR_EXT:
+            return HAL_DATASPACE_V0_SRGB;
+        case VK_COLOR_SPACE_BT2020_170M_EXT:
+            return static_cast<android_dataspace>(
+                HAL_DATASPACE_STANDARD_BT2020 |
+                HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_FULL);
+        case VK_COLOR_SPACE_BT2020_ST2084_EXT:
+            return static_cast<android_dataspace>(
+                HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_ST2084 |
+                HAL_DATASPACE_RANGE_FULL);
+        case VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT:
+            return static_cast<android_dataspace>(
+                HAL_DATASPACE_STANDARD_ADOBE_RGB |
+                HAL_DATASPACE_TRANSFER_LINEAR | HAL_DATASPACE_RANGE_FULL);
+        case VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT:
+            return HAL_DATASPACE_ADOBE_RGB;
+
+        // Pass through is intended to allow app to provide data that is passed
+        // to the display system without modification.
+        case VK_COLOR_SPACE_PASS_THROUGH_EXT:
+            return HAL_DATASPACE_ARBITRARY;
+
+        default:
+            // This indicates that we don't know about the
+            // dataspace specified and we should indicate that
+            // it's unsupported
+            return HAL_DATASPACE_UNKNOWN;
+    }
+}
+
 }  // anonymous namespace
 
 VKAPI_ATTR
@@ -410,7 +479,7 @@
               err);
         surface->~Surface();
         allocator->pfnFree(allocator->pUserData, surface);
-        return VK_ERROR_INITIALIZATION_FAILED;
+        return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR;
     }
 
     *out_surface = HandleFromSurface(surface);
@@ -458,13 +527,13 @@
     if (err != 0) {
         ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
               strerror(-err), err);
-        return VK_ERROR_INITIALIZATION_FAILED;
+        return VK_ERROR_SURFACE_LOST_KHR;
     }
     err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
     if (err != 0) {
         ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
               strerror(-err), err);
-        return VK_ERROR_INITIALIZATION_FAILED;
+        return VK_ERROR_SURFACE_LOST_KHR;
     }
 
     int transform_hint;
@@ -472,7 +541,7 @@
     if (err != 0) {
         ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)",
               strerror(-err), err);
-        return VK_ERROR_INITIALIZATION_FAILED;
+        return VK_ERROR_SURFACE_LOST_KHR;
     }
 
     // TODO(jessehall): Figure out what the min/max values should be.
@@ -512,10 +581,12 @@
 }
 
 VKAPI_ATTR
-VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice /*pdev*/,
-                                            VkSurfaceKHR /*surface*/,
+VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev,
+                                            VkSurfaceKHR surface_handle,
                                             uint32_t* count,
                                             VkSurfaceFormatKHR* formats) {
+    const InstanceData& instance_data = GetData(pdev);
+
     // 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
@@ -528,15 +599,51 @@
         {VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
     };
     const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
+    uint32_t total_num_formats = kNumFormats;
+
+    bool wide_color_support = false;
+    Surface& surface = *SurfaceFromHandle(surface_handle);
+    int err = native_window_get_wide_color_support(surface.window.get(),
+                                                   &wide_color_support);
+    if (err) {
+        // Not allowed to return a more sensible error code, so do this
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+    }
+    ALOGV("wide_color_support is: %d", wide_color_support);
+    wide_color_support =
+        wide_color_support &&
+        instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
+
+    const VkSurfaceFormatKHR kWideColorFormats[] = {
+        {VK_FORMAT_R16G16B16A16_SFLOAT,
+         VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT},
+        {VK_FORMAT_A2R10G10B10_UNORM_PACK32,
+         VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
+    };
+    const uint32_t kNumWideColorFormats =
+        sizeof(kWideColorFormats) / sizeof(kWideColorFormats[0]);
+    if (wide_color_support) {
+        total_num_formats += kNumWideColorFormats;
+    }
 
     VkResult result = VK_SUCCESS;
     if (formats) {
-        if (*count < kNumFormats)
+        uint32_t out_count = 0;
+        uint32_t transfer_count = 0;
+        if (*count < total_num_formats)
             result = VK_INCOMPLETE;
-        *count = std::min(*count, kNumFormats);
-        std::copy(kFormats, kFormats + *count, formats);
+        transfer_count = std::min(*count, kNumFormats);
+        std::copy(kFormats, kFormats + transfer_count, formats);
+        out_count += transfer_count;
+        if (wide_color_support) {
+            transfer_count = std::min(*count - out_count, kNumWideColorFormats);
+            std::copy(kWideColorFormats, kWideColorFormats + transfer_count,
+                      formats + out_count);
+            out_count += transfer_count;
+        }
+        *count = out_count;
     } else {
-        *count = kNumFormats;
+        *count = total_num_formats;
     }
     return result;
 }
@@ -594,12 +701,21 @@
     if (!allocator)
         allocator = &GetData(device).allocator;
 
+    android_pixel_format native_pixel_format =
+        GetNativePixelFormat(create_info->imageFormat);
+    android_dataspace native_dataspace =
+        GetNativeDataspace(create_info->imageColorSpace);
+    if (native_dataspace == HAL_DATASPACE_UNKNOWN) {
+        ALOGE(
+            "CreateSwapchainKHR(VkSwapchainCreateInfoKHR.imageColorSpace = %d) "
+            "failed: Unsupported color space",
+            create_info->imageColorSpace);
+        return VK_ERROR_INITIALIZATION_FAILED;
+    }
+
     ALOGV_IF(create_info->imageArrayLayers != 1,
              "swapchain imageArrayLayers=%u not supported",
              create_info->imageArrayLayers);
-    ALOGV_IF(create_info->imageColorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
-             "swapchain imageColorSpace=%u not supported",
-             create_info->imageColorSpace);
     ALOGV_IF((create_info->preTransform & ~kSupportedTransforms) != 0,
              "swapchain preTransform=%#x not supported",
              create_info->preTransform);
@@ -648,65 +764,55 @@
     if (err != 0) {
         ALOGE("native_window_set_buffer_count(0) failed: %s (%d)",
               strerror(-err), err);
-        return VK_ERROR_INITIALIZATION_FAILED;
+        return VK_ERROR_SURFACE_LOST_KHR;
     }
 
-    err = surface.window->setSwapInterval(surface.window.get(), 1);
+    int swap_interval =
+        create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1;
+    err = surface.window->setSwapInterval(surface.window.get(), swap_interval);
     if (err != 0) {
         // TODO(jessehall): Improve error reporting. Can we enumerate possible
         // errors and translate them to valid Vulkan result codes?
         ALOGE("native_window->setSwapInterval(1) failed: %s (%d)",
               strerror(-err), err);
-        return VK_ERROR_INITIALIZATION_FAILED;
+        return VK_ERROR_SURFACE_LOST_KHR;
     }
 
     err = native_window_set_shared_buffer_mode(surface.window.get(), false);
     if (err != 0) {
         ALOGE("native_window_set_shared_buffer_mode(false) failed: %s (%d)",
               strerror(-err), err);
-        return VK_ERROR_INITIALIZATION_FAILED;
+        return VK_ERROR_SURFACE_LOST_KHR;
     }
 
     err = native_window_set_auto_refresh(surface.window.get(), false);
     if (err != 0) {
         ALOGE("native_window_set_auto_refresh(false) failed: %s (%d)",
               strerror(-err), err);
-        return VK_ERROR_INITIALIZATION_FAILED;
+        return VK_ERROR_SURFACE_LOST_KHR;
     }
 
     // -- Configure the native window --
 
     const auto& dispatch = GetData(device).driver;
 
-    int native_format = HAL_PIXEL_FORMAT_RGBA_8888;
-    switch (create_info->imageFormat) {
-        case VK_FORMAT_R8G8B8A8_UNORM:
-        case VK_FORMAT_R8G8B8A8_SRGB:
-            native_format = HAL_PIXEL_FORMAT_RGBA_8888;
-            break;
-        case VK_FORMAT_R5G6B5_UNORM_PACK16:
-            native_format = HAL_PIXEL_FORMAT_RGB_565;
-            break;
-        default:
-            ALOGV("unsupported swapchain format %d", create_info->imageFormat);
-            break;
-    }
-    err = native_window_set_buffers_format(surface.window.get(), native_format);
+    err = native_window_set_buffers_format(surface.window.get(),
+                                           native_pixel_format);
     if (err != 0) {
         // TODO(jessehall): Improve error reporting. Can we enumerate possible
         // errors and translate them to valid Vulkan result codes?
         ALOGE("native_window_set_buffers_format(%d) failed: %s (%d)",
-              native_format, strerror(-err), err);
-        return VK_ERROR_INITIALIZATION_FAILED;
+              native_pixel_format, strerror(-err), err);
+        return VK_ERROR_SURFACE_LOST_KHR;
     }
     err = native_window_set_buffers_data_space(surface.window.get(),
-                                               HAL_DATASPACE_SRGB_LINEAR);
+                                               native_dataspace);
     if (err != 0) {
         // TODO(jessehall): Improve error reporting. Can we enumerate possible
         // errors and translate them to valid Vulkan result codes?
         ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
-              HAL_DATASPACE_SRGB_LINEAR, strerror(-err), err);
-        return VK_ERROR_INITIALIZATION_FAILED;
+              native_dataspace, strerror(-err), err);
+        return VK_ERROR_SURFACE_LOST_KHR;
     }
 
     err = native_window_set_buffers_dimensions(
@@ -718,7 +824,7 @@
         ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
               create_info->imageExtent.width, create_info->imageExtent.height,
               strerror(-err), err);
-        return VK_ERROR_INITIALIZATION_FAILED;
+        return VK_ERROR_SURFACE_LOST_KHR;
     }
 
     // VkSwapchainCreateInfo::preTransform indicates the transformation the app
@@ -738,7 +844,7 @@
         ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
               InvertTransformToNative(create_info->preTransform),
               strerror(-err), err);
-        return VK_ERROR_INITIALIZATION_FAILED;
+        return VK_ERROR_SURFACE_LOST_KHR;
     }
 
     err = native_window_set_scaling_mode(
@@ -748,7 +854,7 @@
         // errors and translate them to valid Vulkan result codes?
         ALOGE("native_window_set_scaling_mode(SCALE_TO_WINDOW) failed: %s (%d)",
               strerror(-err), err);
-        return VK_ERROR_INITIALIZATION_FAILED;
+        return VK_ERROR_SURFACE_LOST_KHR;
     }
 
     int query_value;
@@ -760,16 +866,9 @@
         // errors and translate them to valid Vulkan result codes?
         ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
               query_value);
-        return VK_ERROR_INITIALIZATION_FAILED;
+        return VK_ERROR_SURFACE_LOST_KHR;
     }
     uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
-    // The MIN_UNDEQUEUED_BUFFERS query doesn't know whether we'll be using
-    // async mode or not, and assumes not. But in async mode, the BufferQueue
-    // requires an extra undequeued buffer.
-    // See BufferQueueCore::getMinUndequeuedBufferCountLocked().
-    if (create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR)
-        min_undequeued_buffers += 1;
-
     uint32_t num_images =
         (create_info->minImageCount - 1) + min_undequeued_buffers;
     err = native_window_set_buffer_count(surface.window.get(), num_images);
@@ -778,7 +877,7 @@
         // errors and translate them to valid Vulkan result codes?
         ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images,
               strerror(-err), err);
-        return VK_ERROR_INITIALIZATION_FAILED;
+        return VK_ERROR_SURFACE_LOST_KHR;
     }
 
     VkSwapchainImageUsageFlagsANDROID swapchain_image_usage = 0;
@@ -789,7 +888,7 @@
         err = native_window_set_shared_buffer_mode(surface.window.get(), true);
         if (err != 0) {
             ALOGE("native_window_set_shared_buffer_mode failed: %s (%d)", strerror(-err), err);
-            return VK_ERROR_INITIALIZATION_FAILED;
+            return VK_ERROR_SURFACE_LOST_KHR;
         }
     }
 
@@ -797,7 +896,7 @@
         err = native_window_set_auto_refresh(surface.window.get(), true);
         if (err != 0) {
             ALOGE("native_window_set_auto_refresh failed: %s (%d)", strerror(-err), err);
-            return VK_ERROR_INITIALIZATION_FAILED;
+            return VK_ERROR_SURFACE_LOST_KHR;
         }
     }
 
@@ -826,7 +925,7 @@
         }
         if (result != VK_SUCCESS) {
             ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result);
-            return VK_ERROR_INITIALIZATION_FAILED;
+            return VK_ERROR_SURFACE_LOST_KHR;
         }
         // TODO: This is the same translation done by Gralloc1On0Adapter.
         // Remove it once ANativeWindow has been updated to take gralloc1-style
@@ -839,7 +938,7 @@
             &gralloc_usage);
         if (result != VK_SUCCESS) {
             ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
-            return VK_ERROR_INITIALIZATION_FAILED;
+            return VK_ERROR_SURFACE_LOST_KHR;
         }
     }
     err = native_window_set_usage(surface.window.get(), gralloc_usage);
@@ -847,18 +946,7 @@
         // TODO(jessehall): Improve error reporting. Can we enumerate possible
         // errors and translate them to valid Vulkan result codes?
         ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err);
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    int swap_interval =
-        create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1;
-    err = surface.window->setSwapInterval(surface.window.get(), swap_interval);
-    if (err != 0) {
-        // TODO(jessehall): Improve error reporting. Can we enumerate possible
-        // errors and translate them to valid Vulkan result codes?
-        ALOGE("native_window->setSwapInterval(%d) failed: %s (%d)",
-              swap_interval, strerror(-err), err);
-        return VK_ERROR_INITIALIZATION_FAILED;
+        return VK_ERROR_SURFACE_LOST_KHR;
     }
 
     // -- Allocate our Swapchain object --
@@ -917,7 +1005,7 @@
             // TODO(jessehall): Improve error reporting. Can we enumerate
             // possible errors and translate them to valid Vulkan result codes?
             ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err);
-            result = VK_ERROR_INITIALIZATION_FAILED;
+            result = VK_ERROR_SURFACE_LOST_KHR;
             break;
         }
         img.buffer = buffer;
@@ -1053,7 +1141,7 @@
         // TODO(jessehall): Improve error reporting. Can we enumerate possible
         // errors and translate them to valid Vulkan result codes?
         ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
-        return VK_ERROR_INITIALIZATION_FAILED;
+        return VK_ERROR_SURFACE_LOST_KHR;
     }
 
     uint32_t idx;
diff --git a/vulkan/libvulkan/swapchain.h b/vulkan/libvulkan/swapchain.h
index 4d9f18f..976c995 100644
--- a/vulkan/libvulkan/swapchain.h
+++ b/vulkan/libvulkan/swapchain.h
@@ -27,7 +27,7 @@
 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 GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface_handle, 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);