Merge "Tie VR mode support to a property"
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index e953ded..7646feb 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 = "64&32";
+    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 a passthrough interface;\n"
+            "PIDs / processes shown below might be inaccurate because the process\n"
+            "might have relinquish 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 the library\n"
+            "and successfully fetch 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(std::string{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/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/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/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index d755ed3..9d761fd 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -21,6 +21,7 @@
 #include <ctype.h>
 
 #include <input/InputDevice.h>
+#include <input/InputEventLabels.h>
 
 namespace android {
 
@@ -87,17 +88,23 @@
         const String8& name, InputDeviceConfigurationFileType type) {
     // Search system repository.
     String8 path;
-    path.setTo(getenv("ANDROID_ROOT"));
-    path.append("/usr/");
-    appendInputDeviceConfigurationFileRelativePath(path, name, type);
+
+    // Treblized input device config files will be located /odm/usr or /vendor/usr.
+    char *rootsForPartition[] {"/odm", "/vendor", getenv("ANDROID_ROOT")};
+    for (size_t i = 0; i < size(rootsForPartition); i++) {
+        path.setTo(rootsForPartition[i]);
+        path.append("/usr/");
+        appendInputDeviceConfigurationFileRelativePath(path, name, type);
 #if DEBUG_PROBE
-    ALOGD("Probing for system provided input device configuration file: path='%s'", path.string());
+        ALOGD("Probing for system provided input device configuration file: path='%s'",
+              path.string());
 #endif
-    if (!access(path.string(), R_OK)) {
+        if (!access(path.string(), R_OK)) {
 #if DEBUG_PROBE
-        ALOGD("Found");
+            ALOGD("Found");
 #endif
-        return path;
+            return path;
+        }
     }
 
     // Search user repository.
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/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 4a281d4..f03491f 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -69,7 +69,8 @@
       mCBContext(),
       mEventHandler(nullptr),
       mVSyncCounts(),
-      mRemainingHwcVirtualDisplays(0)
+      mRemainingHwcVirtualDisplays(0),
+      mDumpMayLockUp(false)
 {
     for (size_t i=0 ; i<HWC_NUM_PHYSICAL_DISPLAY_TYPES ; i++) {
         mLastHwVSync[i] = 0;
@@ -489,6 +490,8 @@
         return NO_ERROR;
     }
 
+    mDumpMayLockUp = true;
+
     uint32_t numTypes = 0;
     uint32_t numRequests = 0;
     auto error = hwcDisplay->validate(&numTypes, &numRequests);
@@ -633,6 +636,9 @@
     auto& displayData = mDisplayData[displayId];
     auto& hwcDisplay = displayData.hwcDisplay;
     auto error = hwcDisplay->present(&displayData.lastPresentFence);
+
+    mDumpMayLockUp = false;
+
     if (error != HWC2::Error::None) {
         ALOGE("presentAndGetReleaseFences: failed for display %d: %s (%d)",
               displayId, to_string(error).c_str(), static_cast<int32_t>(error));
@@ -878,6 +884,11 @@
 }
 
 void HWComposer::dump(String8& result) const {
+    if (mDumpMayLockUp) {
+        result.append("HWComposer dump skipped because present in progress");
+        return;
+    }
+
     // TODO: In order to provide a dump equivalent to HWC1, we need to shadow
     // all the state going into the layers. This is probably better done in
     // Layer itself, but it's going to take a bit of work to get there.
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 0713709..20cca39 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -231,6 +231,9 @@
 
     // thread-safe
     mutable Mutex mVsyncLock;
+
+    // XXX temporary workaround for b/35806047
+    mutable std::atomic<bool> mDumpMayLockUp;
 };
 
 class HWComposerBufferCache {
diff --git a/services/vr/vr_window_manager/Android.mk b/services/vr/vr_window_manager/Android.mk
index e9552bc..706efe5 100644
--- a/services/vr/vr_window_manager/Android.mk
+++ b/services/vr/vr_window_manager/Android.mk
@@ -61,12 +61,12 @@
   libperformance \
   libpdx_default_transport \
   libcutils \
+  libvr_manager \
 
 shared_libs := \
   android.dvr.composer@1.0 \
   android.hardware.graphics.composer@2.1 \
   libvrhwc \
-  libandroid \
   libbase \
   libbinder \
   libinput \
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..6cbd88d 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);
   }
 
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index e105922..b35e534 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -651,7 +651,9 @@
         return VK_ERROR_INITIALIZATION_FAILED;
     }
 
-    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?
@@ -763,13 +765,6 @@
         return VK_ERROR_INITIALIZATION_FAILED;
     }
     uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
-    // The MIN_UNDEQUEUED_BUFFERS query doesn't know whether we'll be using
-    // async mode or not, and assumes not. But in async mode, the BufferQueue
-    // requires an extra undequeued buffer.
-    // 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);
@@ -850,17 +845,6 @@
         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;
-    }
-
     // -- Allocate our Swapchain object --
     // After this point, we must deallocate the swapchain on error.