Merge "Add stub for SensorManager::createEventQueue"
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp
index 225de20..69ed416 100644
--- a/cmds/atrace/Android.bp
+++ b/cmds/atrace/Android.bp
@@ -16,9 +16,6 @@
         "libz",
         "libbase",
     ],
-    static_libs: [
-        "libpdx_default_transport",
-    ],
 
     init_rc: ["atrace.rc"],
 }
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 14eff03..05e1615 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -18,7 +18,6 @@
 
 #include <errno.h>
 #include <fcntl.h>
-#include <ftw.h>
 #include <getopt.h>
 #include <inttypes.h>
 #include <signal.h>
@@ -42,7 +41,6 @@
 #include <hidl/ServiceManagement.h>
 #include <cutils/properties.h>
 
-#include <pdx/default_transport/service_utility.h>
 #include <utils/String8.h>
 #include <utils/Timers.h>
 #include <utils/Tokenizer.h>
@@ -50,7 +48,6 @@
 #include <android-base/file.h>
 
 using namespace android;
-using pdx::default_transport::ServiceUtility;
 
 using std::string;
 #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
@@ -568,46 +565,6 @@
     }
 }
 
-// Sends the sysprop_change message to the service at fpath, so it re-reads its
-// system properties. Returns 0 on success or a negated errno code on failure.
-static int pokeOnePDXService(const char *fpath, const struct stat * /*sb*/,
-                             int typeflag, struct FTW * /*ftwbuf*/)
-{
-    const bool kIgnoreErrors = true;
-
-    if (typeflag == FTW_F) {
-        int error;
-        auto utility = ServiceUtility::Create(fpath, &error);
-        if (!utility) {
-            if (error != -ECONNREFUSED) {
-                ALOGE("pokeOnePDXService: Failed to open %s, %s.", fpath,
-                      strerror(-error));
-            }
-            return kIgnoreErrors ? 0 : error;
-        }
-
-        auto status = utility->ReloadSystemProperties();
-        if (!status) {
-            ALOGE("pokeOnePDXService: Failed to send sysprop change to %s, "
-                  "error %d, %s.", fpath, status.error(),
-                  status.GetErrorMessage().c_str());
-            return kIgnoreErrors ? 0 : -status.error();
-        }
-    }
-
-    return 0;
-}
-
-// Pokes all the PDX processes in the system to get them to re-read
-// their system properties. Returns true on success, false on failure.
-static bool pokePDXServices()
-{
-    const int kMaxDepth = 16;
-    const int result = nftw(ServiceUtility::GetRootEndpointPath().c_str(),
-                            pokeOnePDXService, kMaxDepth, FTW_PHYS);
-    return result == 0 ? true : false;
-}
-
 // Set the trace tags that userland tracing uses, and poke the running
 // processes to pick up the new value.
 static bool setTagsProperty(uint64_t tags)
@@ -851,7 +808,6 @@
     ok &= setAppCmdlineProperty(&packageList[0]);
     ok &= pokeBinderServices();
     pokeHalServices();
-    ok &= pokePDXServices();
 
     // Disable all the sysfs enables.  This is done as a separate loop from
     // the enables to allow the same enable to exist in multiple categories.
@@ -889,7 +845,6 @@
     setTagsProperty(0);
     clearAppProperties();
     pokeBinderServices();
-    pokePDXServices();
 
     // Set the options back to their defaults.
     setTraceOverwriteEnable(true);
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index 39e0ba3..4740202 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -16,6 +16,7 @@
     name: "lshal",
     shared_libs: [
         "libbase",
+        "libcutils",
         "libutils",
         "libhidlbase",
         "libhidltransport",
@@ -24,6 +25,7 @@
         "android.hidl.manager@1.0",
     ],
     srcs: [
-        "Lshal.cpp"
+        "Lshal.cpp",
+        "PipeRelay.cpp"
     ],
 }
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index a5cac15..420ec3c 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -25,13 +25,17 @@
 #include <sstream>
 #include <regex>
 
+#include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <hidl/ServiceManagement.h>
 #include <hidl-util/FQName.h>
+#include <private/android_filesystem_config.h>
+#include <sys/stat.h>
 #include <vintf/HalManifest.h>
 #include <vintf/parse_xml.h>
 
+#include "PipeRelay.h"
 #include "Timeout.h"
 
 using ::android::hardware::hidl_string;
@@ -357,6 +361,52 @@
     }
 }
 
+// A unique_ptr type using a custom deleter function.
+template<typename T>
+using deleted_unique_ptr = std::unique_ptr<T, std::function<void(T *)> >;
+
+void Lshal::emitDebugInfo(
+        const sp<IServiceManager> &serviceManager,
+        const std::string &interfaceName,
+        const std::string &instanceName) const {
+    using android::hidl::base::V1_0::IBase;
+
+    hardware::Return<sp<IBase>> retBase =
+        serviceManager->get(interfaceName, instanceName);
+
+    sp<IBase> base;
+    if (!retBase.isOk() || (base = retBase) == nullptr) {
+        // There's a small race, where a service instantiated while collecting
+        // the list of services has by now terminated, so this isn't anything
+        // to be concerned about.
+        return;
+    }
+
+    PipeRelay relay(mOut.buf());
+
+    if (relay.initCheck() != OK) {
+        LOG(ERROR) << "PipeRelay::initCheck() FAILED w/ " << relay.initCheck();
+        return;
+    }
+
+    deleted_unique_ptr<native_handle_t> fdHandle(
+        native_handle_create(1 /* numFds */, 0 /* numInts */),
+        native_handle_delete);
+
+    fdHandle->data[0] = relay.fd();
+
+    hardware::hidl_vec<hardware::hidl_string> options;
+    hardware::Return<void> ret = base->debug(fdHandle.get(), options);
+
+    if (!ret.isOk()) {
+        LOG(ERROR)
+            << interfaceName
+            << "::debug(...) FAILED. (instance "
+            << instanceName
+            << ")";
+    }
+}
+
 void Lshal::dumpTable() {
     mServicesTable.description =
             "All binderized services (registered services through hwservicemanager)";
@@ -374,6 +424,16 @@
         mOut << std::left;
         printLine("Interface", "Transport", "Arch", "Server", "Server CMD",
                   "PTR", "Clients", "Clients CMD");
+
+        // We're only interested in dumping debug info for already
+        // instantiated services. There's little value in dumping the
+        // debug info for a service we create on the fly, so we only operate
+        // on the "mServicesTable".
+        sp<IServiceManager> serviceManager;
+        if (mEmitDebugInfo && &table == &mServicesTable) {
+            serviceManager = ::android::hardware::defaultServiceManager();
+        }
+
         for (const auto &entry : table) {
             printLine(entry.interfaceName,
                     entry.transport,
@@ -383,6 +443,11 @@
                     entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress),
                     join(entry.clientPids, " "),
                     join(entry.clientCmdlines, ";"));
+
+            if (serviceManager != nullptr) {
+                auto pair = splitFirst(entry.interfaceName, '/');
+                emitDebugInfo(serviceManager, pair.first, pair.second);
+            }
         }
         mOut << std::endl;
     });
@@ -626,6 +691,7 @@
         {"address",   no_argument,       0, 'a' },
         {"clients",   no_argument,       0, 'c' },
         {"cmdline",   no_argument,       0, 'm' },
+        {"debug",     optional_argument, 0, 'd' },
 
         // long options without short alternatives
         {"sort",      required_argument, 0, 's' },
@@ -638,7 +704,7 @@
     optind = 1;
     for (;;) {
         // using getopt_long in case we want to add other options in the future
-        c = getopt_long(argc, argv, "hitrpacm", longOptions, &optionIndex);
+        c = getopt_long(argc, argv, "hitrpacmd", longOptions, &optionIndex);
         if (c == -1) {
             break;
         }
@@ -694,6 +760,20 @@
             mEnableCmdlines = true;
             break;
         }
+        case 'd': {
+            mEmitDebugInfo = true;
+
+            if (optarg) {
+                mFileOutput = new std::ofstream{optarg};
+                mOut = mFileOutput;
+                if (!mFileOutput.buf().is_open()) {
+                    mErr << "Could not open file '" << optarg << "'." << std::endl;
+                    return IO_ERROR;
+                }
+                chown(optarg, AID_SHELL, AID_SHELL);
+            }
+            break;
+        }
         case 'h': // falls through
         default: // see unrecognized options
             usage();
diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h
index c9c6660..a21e86c 100644
--- a/cmds/lshal/Lshal.h
+++ b/cmds/lshal/Lshal.h
@@ -77,6 +77,11 @@
     void forEachTable(const std::function<void(Table &)> &f);
     void forEachTable(const std::function<void(const Table &)> &f) const;
 
+    void emitDebugInfo(
+            const sp<hidl::manager::V1_0::IServiceManager> &serviceManager,
+            const std::string &interfaceName,
+            const std::string &instanceName) const;
+
     Table mServicesTable{};
     Table mPassthroughRefTable{};
     Table mImplementationsTable{};
@@ -88,6 +93,10 @@
     TableEntrySelect mSelectedColumns = 0;
     // If true, cmdlines will be printed instead of pid.
     bool mEnableCmdlines = false;
+
+    // If true, calls IBase::debug(...) on each service.
+    bool mEmitDebugInfo = false;
+
     bool mVintf = false;
     // If an entry does not exist, need to ask /proc/{pid}/cmdline to get it.
     // If an entry exist but is an empty string, process might have died.
diff --git a/cmds/lshal/PipeRelay.cpp b/cmds/lshal/PipeRelay.cpp
new file mode 100644
index 0000000..c7b29df
--- /dev/null
+++ b/cmds/lshal/PipeRelay.cpp
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+#include "PipeRelay.h"
+
+#include <sys/socket.h>
+#include <utils/Thread.h>
+
+namespace android {
+namespace lshal {
+
+struct PipeRelay::RelayThread : public Thread {
+    explicit RelayThread(int fd, std::ostream &os);
+
+    bool threadLoop() override;
+
+private:
+    int mFd;
+    std::ostream &mOutStream;
+
+    DISALLOW_COPY_AND_ASSIGN(RelayThread);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+PipeRelay::RelayThread::RelayThread(int fd, std::ostream &os)
+    : mFd(fd),
+      mOutStream(os) {
+}
+
+bool PipeRelay::RelayThread::threadLoop() {
+    char buffer[1024];
+    ssize_t n = read(mFd, buffer, sizeof(buffer));
+
+    if (n <= 0) {
+        return false;
+    }
+
+    mOutStream.write(buffer, n);
+
+    return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+PipeRelay::PipeRelay(std::ostream &os)
+    : mOutStream(os),
+      mInitCheck(NO_INIT) {
+    int res = socketpair(AF_UNIX, SOCK_STREAM, 0 /* protocol */, mFds);
+
+    if (res < 0) {
+        mInitCheck = -errno;
+        return;
+    }
+
+    mThread = new RelayThread(mFds[0], os);
+    mInitCheck = mThread->run("RelayThread");
+}
+
+// static
+void PipeRelay::CloseFd(int *fd) {
+    if (*fd >= 0) {
+        close(*fd);
+        *fd = -1;
+    }
+}
+
+PipeRelay::~PipeRelay() {
+    if (mFds[1] >= 0) {
+        shutdown(mFds[1], SHUT_WR);
+    }
+
+    if (mFds[0] >= 0) {
+        shutdown(mFds[0], SHUT_RD);
+    }
+
+    if (mThread != NULL) {
+        mThread->join();
+        mThread.clear();
+    }
+
+    CloseFd(&mFds[1]);
+    CloseFd(&mFds[0]);
+}
+
+status_t PipeRelay::initCheck() const {
+    return mInitCheck;
+}
+
+int PipeRelay::fd() const {
+    return mFds[1];
+}
+
+}  // namespace lshal
+}  // namespace android
diff --git a/cmds/lshal/PipeRelay.h b/cmds/lshal/PipeRelay.h
new file mode 100644
index 0000000..76b2b23
--- /dev/null
+++ b/cmds/lshal/PipeRelay.h
@@ -0,0 +1,59 @@
+/*
+ * 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 FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_
+
+#define FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_
+
+#include <android-base/macros.h>
+#include <ostream>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+namespace android {
+namespace lshal {
+
+/* Creates an AF_UNIX socketpair and spawns a thread that relays any data
+ * written to the "write"-end of the pair to the specified output stream "os".
+ */
+struct PipeRelay {
+    explicit PipeRelay(std::ostream &os);
+    ~PipeRelay();
+
+    status_t initCheck() const;
+
+    // Returns the file descriptor corresponding to the "write"-end of the
+    // connection.
+    int fd() const;
+
+private:
+    struct RelayThread;
+
+    std::ostream &mOutStream;
+    status_t mInitCheck;
+    int mFds[2];
+    sp<RelayThread> mThread;
+
+    static void CloseFd(int *fd);
+
+    DISALLOW_COPY_AND_ASSIGN(PipeRelay);
+};
+
+}  // namespace lshal
+}  // namespace android
+
+#endif  // FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_
+
diff --git a/include/gfx/SafeLog.h b/include/gfx/SafeLog.h
deleted file mode 100644
index e45e541..0000000
--- a/include/gfx/SafeLog.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Weverything"
-#include <fmt/format.h>
-#include <log/log.h>
-#pragma clang diagnostic pop
-
-#include <type_traits>
-
-namespace android {
-namespace gfx {
-
-/* SafeLog is a mix-in that can be used to easily add typesafe logging using fmtlib to any class.
- * To use it, inherit from it using CRTP and implement the getLogTag method.
- *
- * For example:
- *
- * class Frobnicator : private SafeLog<Frobnicator> {
- *     friend class SafeLog<Frobnicator>;  // Allows getLogTag to be private
- *
- *   public:
- *     void frobnicate(int32_t i);
- *
- *   private:
- *     // SafeLog does member access on the object calling alog*, so this tag can theoretically vary
- *     // by instance unless getLogTag is made static
- *     const char* getLogTag() { return "Frobnicator"; }
- * };
- *
- * void Frobnicator::frobnicate(int32_t i) {
- *     // Logs something like "04-16 21:35:46.811  3513  3513 I Frobnicator: frobnicating 42"
- *     alogi("frobnicating {}", i);
- * }
- *
- * See http://fmtlib.net for more information on the formatting API.
- */
-
-template <typename T>
-class SafeLog {
-  protected:
-    template <typename... Args>
-#if LOG_NDEBUG
-    void alogv(Args&&... /*unused*/) const {
-    }
-#else
-    void alogv(Args&&... args) const {
-        alog<ANDROID_LOG_VERBOSE>(std::forward<Args>(args)...);
-    }
-#endif
-
-    template <typename... Args>
-    void alogd(Args&&... args) const {
-        alog<ANDROID_LOG_DEBUG>(std::forward<Args>(args)...);
-    }
-
-    template <typename... Args>
-    void alogi(Args&&... args) const {
-        alog<ANDROID_LOG_INFO>(std::forward<Args>(args)...);
-    }
-
-    template <typename... Args>
-    void alogw(Args&&... args) const {
-        alog<ANDROID_LOG_WARN>(std::forward<Args>(args)...);
-    }
-
-    template <typename... Args>
-    void aloge(Args&&... args) const {
-        alog<ANDROID_LOG_ERROR>(std::forward<Args>(args)...);
-    }
-
-  private:
-    // Suppresses clang-tidy check cppcoreguidelines-pro-bounds-array-to-pointer-decay
-    template <size_t strlen, typename... Args>
-    void write(fmt::MemoryWriter* writer, const char (&str)[strlen], Args&&... args) const {
-        writer->write(static_cast<const char*>(str), std::forward<Args>(args)...);
-    }
-
-    template <int priority, typename... Args>
-    void alog(Args&&... args) const {
-        static_assert(std::is_base_of<SafeLog<T>, T>::value, "Can't convert to SafeLog pointer");
-        fmt::MemoryWriter writer;
-        write(&writer, std::forward<Args>(args)...);
-        auto derivedThis = static_cast<const T*>(this);
-        android_writeLog(priority, derivedThis->getLogTag(), writer.c_str());
-    }
-};
-
-}  // namespace gfx
-}  // namespace android
diff --git a/include/media/openmax/OMX_AsString.h b/include/media/openmax/OMX_AsString.h
index 4556c8f..6b21979 100644
--- a/include/media/openmax/OMX_AsString.h
+++ b/include/media/openmax/OMX_AsString.h
@@ -531,6 +531,7 @@
 //      case OMX_IndexConfigCallbackRequest:            return "ConfigCallbackRequest";
 //      case OMX_IndexConfigCommitMode:                 return "ConfigCommitMode";
 //      case OMX_IndexConfigCommit:                     return "ConfigCommit";
+        case OMX_IndexConfigAndroidVendorExtension:     return "ConfigAndroidVendorExtension";
         case OMX_IndexParamAudioAndroidAc3:             return "ParamAudioAndroidAc3";
         case OMX_IndexParamAudioAndroidOpus:            return "ParamAudioAndroidOpus";
         case OMX_IndexParamAudioAndroidAacPresentation: return "ParamAudioAndroidAacPresentation";
diff --git a/include/media/openmax/OMX_IndexExt.h b/include/media/openmax/OMX_IndexExt.h
index d0ae867..eccecaa 100644
--- a/include/media/openmax/OMX_IndexExt.h
+++ b/include/media/openmax/OMX_IndexExt.h
@@ -51,6 +51,7 @@
     OMX_IndexConfigCallbackRequest,                 /**< reference: OMX_CONFIG_CALLBACKREQUESTTYPE */
     OMX_IndexConfigCommitMode,                      /**< reference: OMX_CONFIG_COMMITMODETYPE */
     OMX_IndexConfigCommit,                          /**< reference: OMX_CONFIG_COMMITTYPE */
+    OMX_IndexConfigAndroidVendorExtension,          /**< reference: OMX_CONFIG_VENDOR_EXTENSIONTYPE */
 
     /* Port parameters and configurations */
     OMX_IndexExtPortStartUnused = OMX_IndexKhronosExtensions + 0x00200000,
@@ -103,6 +104,117 @@
     OMX_IndexExtMax = 0x7FFFFFFF
 } OMX_INDEXEXTTYPE;
 
+#define OMX_MAX_STRINGVALUE_SIZE OMX_MAX_STRINGNAME_SIZE
+#define OMX_MAX_ANDROID_VENDOR_PARAMCOUNT 32
+
+typedef enum OMX_ANDROID_VENDOR_VALUETYPE {
+    OMX_AndroidVendorValueInt32 = 0,   /*<< int32_t value */
+    OMX_AndroidVendorValueInt64,       /*<< int64_t value */
+    OMX_AndroidVendorValueString,      /*<< string value */
+    OMX_AndroidVendorValueEndUnused,
+} OMX_ANDROID_VENDOR_VALUETYPE;
+
+/**
+ * Structure describing a single value of an Android vendor extension.
+ *
+ * STRUCTURE MEMBERS:
+ *  cKey        : parameter value name.
+ *  eValueType  : parameter value type
+ *  bSet        : if false, the parameter is not set (for OMX_GetConfig) or is unset (OMX_SetConfig)
+ *                if true, the parameter is set to the corresponding value below
+ *  nInt64      : int64 value
+ *  cString     : string value
+ */
+typedef struct OMX_CONFIG_ANDROID_VENDOR_PARAMTYPE {
+    OMX_U8 cKey[OMX_MAX_STRINGNAME_SIZE];
+    OMX_ANDROID_VENDOR_VALUETYPE eValueType;
+    OMX_BOOL bSet;
+    union {
+        OMX_S32 nInt32;
+        OMX_S64 nInt64;
+        OMX_U8 cString[OMX_MAX_STRINGVALUE_SIZE];
+    };
+} OMX_CONFIG_ANDROID_VENDOR_PARAMTYPE;
+
+/**
+ * OMX_CONFIG_ANDROID_VENDOR_EXTENSIONTYPE is the structure for an Android vendor extension
+ * supported by the component. This structure enumerates the various extension parameters and their
+ * values.
+ *
+ * Android vendor extensions have a name and one or more parameter values - each with a string key -
+ * that are set together. The values are exposed to Android applications via a string key that is
+ * the concatenation of 'vendor', the extension name and the parameter key, each separated by dot
+ * (.), with any trailing '.value' suffix(es) removed (though optionally allowed).
+ *
+ * Extension names and parameter keys are subject to the following rules:
+ *   - Each SHALL contain a set of lowercase alphanumeric (underscore allowed) tags separated by
+ *     dot (.) or dash (-).
+ *   - The first character of the first tag, and any tag following a dot SHALL not start with a
+ *     digit.
+ *   - Tags 'value', 'vendor', 'omx' and 'android' (even if trailed and/or followed by any number
+ *     of underscores) are prohibited in the extension name.
+ *   - Tags 'vendor', 'omx' and 'android' (even if trailed and/or followed by any number
+ *     of underscores) are prohibited in parameter keys.
+ *   - The tag 'value' (even if trailed and/or followed by any number
+ *     of underscores) is prohibited in parameter keys with the following exception:
+ *     the parameter key may be exactly 'value'
+ *   - The parameter key for extensions with a single parameter value SHALL be 'value'
+ *   - No two extensions SHALL have the same name
+ *   - No extension's name SHALL start with another extension's NAME followed by a dot (.)
+ *   - No two parameters of an extension SHALL have the same key
+ *
+ * This config can be used with both OMX_GetConfig and OMX_SetConfig. In the OMX_GetConfig
+ * case, the caller specifies nIndex and nParamSizeUsed. The component fills in cName,
+ * eDir and nParamCount. Additionally, if nParamSizeUsed is not less than nParamCount, the
+ * component fills out the parameter values (nParam) with the current values for each parameter
+ * of the vendor extension.
+ *
+ * The value of nIndex goes from 0 to N-1, where N is the number of Android vendor extensions
+ * supported by the component. The component does not need to report N as the caller can determine
+ * N by enumerating all extensions supported by the component. The component may not support any
+ * extensions. If there are no more extensions, OMX_GetParameter returns OMX_ErrorNoMore. The
+ * component supplies extensions in the order it wants clients to set them.
+ *
+ * The component SHALL return OMX_ErrorNone for all cases where nIndex is less than N (specifically
+ * even in the case of where nParamCount is greater than nParamSizeUsed).
+ *
+ * In the OMX_SetConfig case the field nIndex is ignored. If the component supports an Android
+ * vendor extension with the name in cName, it SHALL configure the parameter values for that
+ * extension according to the parameters in nParam. nParamCount is the number of valid parameters
+ * in the nParam array, and nParamSizeUsed is the size of the nParam array. (nParamSizeUsed
+ * SHALL be at least nParamCount) Parameters that are part of a vendor extension but are not
+ * in the nParam array are assumed to be unset (this is different from not changed).
+ * All parameter values SHALL have distinct keys in nParam (the component can assume that this
+ * is the case. Otherwise, the actual value for the parameters that are multiply defined can
+ * be any of the set values.)
+ *
+ * Return values in case of OMX_SetConfig:
+ *   OMX_ErrorUnsupportedIndex: the component does not support the extension specified by cName
+ *   OMX_ErrorUnsupportedSetting: the component does not support some or any of the parameters
+ *       (names) specified in nParam
+ *   OMX_ErrorBadParameter: the parameter is invalid (e.g. nParamCount is greater than
+ *       nParamSizeUsed, or some parameter value has invalid type)
+ *
+ * STRUCTURE MEMBERS:
+ *  nSize       : size of the structure in bytes
+ *  nVersion    : OMX specification version information
+ *  cName       : name of vendor extension
+ *  nParamCount : the number of parameter values that are part of this vendor extension
+ *  nParamSizeUsed : the size of nParam
+ *                (must be at least 1 and at most OMX_MAX_ANDROID_VENDOR_PARAMCOUNT)
+ *  param       : the parameter values
+ */
+typedef struct OMX_CONFIG_ANDROID_VENDOR_EXTENSIONTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nIndex;
+    OMX_U8  cName[OMX_MAX_STRINGNAME_SIZE];
+    OMX_DIRTYPE eDir;
+    OMX_U32 nParamCount;
+    OMX_U32 nParamSizeUsed;
+    OMX_CONFIG_ANDROID_VENDOR_PARAMTYPE param[1];
+} OMX_CONFIG_ANDROID_VENDOR_EXTENSIONTYPE;
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/include/ui/ColorSpace.h b/include/ui/ColorSpace.h
index 8c4acb7..8ccf6d3 100644
--- a/include/ui/ColorSpace.h
+++ b/include/ui/ColorSpace.h
@@ -35,6 +35,16 @@
     typedef std::function<float(float)> transfer_function;
     typedef std::function<float(float)> clamping_function;
 
+    struct TransferParameters {
+        float g = 0.0f;
+        float a = 0.0f;
+        float b = 0.0f;
+        float c = 0.0f;
+        float d = 0.0f;
+        float e = 0.0f;
+        float f = 0.0f;
+    };
+
     /**
      * Creates a named color space with the specified RGB->XYZ
      * conversion matrix. The white point and primaries will be
@@ -47,8 +57,39 @@
     ColorSpace(
             const std::string& name,
             const mat3& rgbToXYZ,
-            transfer_function OETF = linearReponse,
-            transfer_function EOTF = linearReponse,
+            transfer_function OETF = linearResponse,
+            transfer_function EOTF = linearResponse,
+            clamping_function clamper = saturate<float>
+    ) noexcept;
+
+    /**
+     * Creates a named color space with the specified RGB->XYZ
+     * conversion matrix. The white point and primaries will be
+     * computed from the supplied matrix.
+     *
+     * The transfer functions are defined by the set of supplied
+     * transfer parameters. The default clamping function is a
+     * simple saturate (clamp(x, 0, 1)).
+     */
+    ColorSpace(
+            const std::string& name,
+            const mat3& rgbToXYZ,
+            const TransferParameters parameters,
+            clamping_function clamper = saturate<float>
+    ) noexcept;
+
+    /**
+     * Creates a named color space with the specified RGB->XYZ
+     * conversion matrix. The white point and primaries will be
+     * computed from the supplied matrix.
+     *
+     * The transfer functions are defined by a simple gamma value.
+     * The default clamping function is a saturate (clamp(x, 0, 1)).
+     */
+    ColorSpace(
+            const std::string& name,
+            const mat3& rgbToXYZ,
+            float gamma,
             clamping_function clamper = saturate<float>
     ) noexcept;
 
@@ -65,8 +106,41 @@
             const std::string& name,
             const std::array<float2, 3>& primaries,
             const float2& whitePoint,
-            transfer_function OETF = linearReponse,
-            transfer_function EOTF = linearReponse,
+            transfer_function OETF = linearResponse,
+            transfer_function EOTF = linearResponse,
+            clamping_function clamper = saturate<float>
+    ) noexcept;
+
+    /**
+     * Creates a named color space with the specified primaries
+     * and white point. The RGB<>XYZ conversion matrices are
+     * computed from the primaries and white point.
+     *
+     * The transfer functions are defined by the set of supplied
+     * transfer parameters. The default clamping function is a
+     * simple saturate (clamp(x, 0, 1)).
+     */
+    ColorSpace(
+            const std::string& name,
+            const std::array<float2, 3>& primaries,
+            const float2& whitePoint,
+            const TransferParameters parameters,
+            clamping_function clamper = saturate<float>
+    ) noexcept;
+
+    /**
+     * Creates a named color space with the specified primaries
+     * and white point. The RGB<>XYZ conversion matrices are
+     * computed from the primaries and white point.
+     *
+     * The transfer functions are defined by a single gamma value.
+     * The default clamping function is a saturate (clamp(x, 0, 1)).
+     */
+    ColorSpace(
+            const std::string& name,
+            const std::array<float2, 3>& primaries,
+            const float2& whitePoint,
+            float gamma,
             clamping_function clamper = saturate<float>
     ) noexcept;
 
@@ -138,6 +212,10 @@
         return mWhitePoint;
     }
 
+    constexpr const TransferParameters& getTransferParameters() const noexcept {
+        return mParameters;
+    }
+
     /**
      * Converts the supplied XYZ value to xyY.
      */
@@ -166,35 +244,6 @@
     static const ColorSpace ACES();
     static const ColorSpace ACEScg();
 
-    class Connector {
-    public:
-        Connector(const ColorSpace& src, const ColorSpace& dst) noexcept;
-
-        constexpr const ColorSpace& getSource() const noexcept { return mSource; }
-        constexpr const ColorSpace& getDestination() const noexcept { return mDestination; }
-
-        constexpr const mat3& getTransform() const noexcept { return mTransform; }
-
-        constexpr float3 transform(const float3& v) const noexcept {
-            float3 linear = mSource.toLinear(apply(v, mSource.getClamper()));
-            return apply(mDestination.fromLinear(mTransform * linear), mDestination.getClamper());
-        }
-
-        constexpr float3 transformLinear(const float3& v) const noexcept {
-            float3 linear = apply(v, mSource.getClamper());
-            return apply(mTransform * linear, mDestination.getClamper());
-        }
-
-    private:
-        const ColorSpace& mSource;
-        const ColorSpace& mDestination;
-        mat3 mTransform;
-    };
-
-    static const Connector connect(const ColorSpace& src, const ColorSpace& dst) {
-        return Connector(src, dst);
-    }
-
     // Creates a NxNxN 3D LUT, where N is the specified size (min=2, max=256)
     // The 3D lookup coordinates map to the RGB components: u=R, v=G, w=B
     // The generated 3D LUT is meant to be used as a 3D texture and its Y
@@ -208,7 +257,7 @@
     static constexpr mat3 computeXYZMatrix(
             const std::array<float2, 3>& primaries, const float2& whitePoint);
 
-    static constexpr float linearReponse(float v) {
+    static constexpr float linearResponse(float v) {
         return v;
     }
 
@@ -217,6 +266,7 @@
     mat3 mRGBtoXYZ;
     mat3 mXYZtoRGB;
 
+    TransferParameters mParameters;
     transfer_function mOETF;
     transfer_function mEOTF;
     clamping_function mClamper;
@@ -225,6 +275,31 @@
     float2 mWhitePoint;
 };
 
+class ColorSpaceConnector {
+public:
+    ColorSpaceConnector(const ColorSpace& src, const ColorSpace& dst) noexcept;
+
+    constexpr const ColorSpace& getSource() const noexcept { return mSource; }
+    constexpr const ColorSpace& getDestination() const noexcept { return mDestination; }
+
+    constexpr const mat3& getTransform() const noexcept { return mTransform; }
+
+    constexpr float3 transform(const float3& v) const noexcept {
+        float3 linear = mSource.toLinear(apply(v, mSource.getClamper()));
+        return apply(mDestination.fromLinear(mTransform * linear), mDestination.getClamper());
+    }
+
+    constexpr float3 transformLinear(const float3& v) const noexcept {
+        float3 linear = apply(v, mSource.getClamper());
+        return apply(mTransform * linear, mDestination.getClamper());
+    }
+
+private:
+    ColorSpace mSource;
+    ColorSpace mDestination;
+    mat3 mTransform;
+};
+
 }; // namespace android
 
 #endif // ANDROID_UI_COLOR_SPACE
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 0dc4469..327ecad 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -70,3 +70,13 @@
         "libbase",
     ],
 }
+
+cc_test {
+    name: "schd-dbg",
+    srcs: ["schd-dbg.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libutils",
+        "libbase",
+    ],
+}
diff --git a/libs/binder/tests/schd-dbg.cpp b/libs/binder/tests/schd-dbg.cpp
new file mode 100644
index 0000000..2732071
--- /dev/null
+++ b/libs/binder/tests/schd-dbg.cpp
@@ -0,0 +1,426 @@
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <string>
+
+#include <iomanip>
+#include <iostream>
+#include <tuple>
+#include <vector>
+
+#include <pthread.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+using namespace std;
+using namespace android;
+
+enum BinderWorkerServiceCode {
+  BINDER_NOP = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+#define ASSERT(cond)                                                \
+  do {                                                              \
+    if (!(cond)) {                                                  \
+      cerr << __func__ << ":" << __LINE__ << " condition:" << #cond \
+           << " failed\n"                                           \
+           << endl;                                                 \
+      exit(EXIT_FAILURE);                                           \
+    }                                                               \
+  } while (0)
+
+vector<sp<IBinder> > workers;
+
+// the ratio that the service is synced on the same cpu beyond
+// GOOD_SYNC_MIN is considered as good
+#define GOOD_SYNC_MIN (0.6)
+
+#define DUMP_PRICISION 3
+
+// the default value
+int no_process = 2;
+int iterations = 100;
+int payload_size = 16;
+int no_inherent = 0;
+int no_sync = 0;
+int verbose = 0;
+
+// the deadline latency that we are interested in
+uint64_t deadline_us = 2500;
+
+int thread_pri() {
+  struct sched_param param;
+  int policy;
+  ASSERT(!pthread_getschedparam(pthread_self(), &policy, &param));
+  return param.sched_priority;
+}
+
+void thread_dump(const char* prefix) {
+  struct sched_param param;
+  int policy;
+  if (!verbose) return;
+  cout << "--------------------------------------------------" << endl;
+  cout << setw(12) << left << prefix << " pid: " << getpid()
+       << " tid: " << gettid() << " cpu: " << sched_getcpu() << endl;
+  ASSERT(!pthread_getschedparam(pthread_self(), &policy, &param));
+  string s = (policy == SCHED_OTHER)
+                 ? "SCHED_OTHER"
+                 : (policy == SCHED_FIFO)
+                       ? "SCHED_FIFO"
+                       : (policy == SCHED_RR) ? "SCHED_RR" : "???";
+  cout << setw(12) << left << s << param.sched_priority << endl;
+  return;
+}
+
+class BinderWorkerService : public BBinder {
+ public:
+  BinderWorkerService() {
+  }
+  ~BinderWorkerService() {
+  }
+  virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                              uint32_t flags = 0) {
+    (void)flags;
+    (void)data;
+    (void)reply;
+    switch (code) {
+      // The transaction format is like
+      //
+      // data[in]:  int32: caller priority
+      //            int32: caller cpu
+      //
+      // reply[out]: int32: 1 if caller's priority != callee's priority
+      //             int32: 1 if caller's cpu != callee's cpu
+      //
+      // note the caller cpu read here is not always correct
+      // there're still chances that the caller got switched out
+      // right after it read the cpu number and still before the transaction.
+      case BINDER_NOP: {
+        thread_dump("binder");
+        int priority = thread_pri();
+        int priority_caller = data.readInt32();
+        int h = 0, s = 0;
+        if (priority_caller != priority) {
+          h++;
+          if (verbose) {
+            cout << "err priority_caller:" << priority_caller
+                 << ", priority:" << priority << endl;
+          }
+        }
+        if (priority == sched_get_priority_max(SCHED_FIFO)) {
+          int cpu = sched_getcpu();
+          int cpu_caller = data.readInt32();
+          if (cpu != cpu_caller) {
+            s++;
+          }
+        }
+        reply->writeInt32(h);
+        reply->writeInt32(s);
+        return NO_ERROR;
+      }
+      default:
+        return UNKNOWN_TRANSACTION;
+    };
+  }
+};
+
+class Pipe {
+  int m_readFd;
+  int m_writeFd;
+  Pipe(int readFd, int writeFd) : m_readFd{readFd}, m_writeFd{writeFd} {
+  }
+  Pipe(const Pipe&) = delete;
+  Pipe& operator=(const Pipe&) = delete;
+  Pipe& operator=(const Pipe&&) = delete;
+
+ public:
+  Pipe(Pipe&& rval) noexcept {
+    m_readFd = rval.m_readFd;
+    m_writeFd = rval.m_writeFd;
+    rval.m_readFd = 0;
+    rval.m_writeFd = 0;
+  }
+  ~Pipe() {
+    if (m_readFd) close(m_readFd);
+    if (m_writeFd) close(m_writeFd);
+  }
+  void signal() {
+    bool val = true;
+    int error = write(m_writeFd, &val, sizeof(val));
+    ASSERT(error >= 0);
+  };
+  void wait() {
+    bool val = false;
+    int error = read(m_readFd, &val, sizeof(val));
+    ASSERT(error >= 0);
+  }
+  template <typename T>
+  void send(const T& v) {
+    int error = write(m_writeFd, &v, sizeof(T));
+    ASSERT(error >= 0);
+  }
+  template <typename T>
+  void recv(T& v) {
+    int error = read(m_readFd, &v, sizeof(T));
+    ASSERT(error >= 0);
+  }
+  static tuple<Pipe, Pipe> createPipePair() {
+    int a[2];
+    int b[2];
+
+    int error1 = pipe(a);
+    int error2 = pipe(b);
+    ASSERT(error1 >= 0);
+    ASSERT(error2 >= 0);
+
+    return make_tuple(Pipe(a[0], b[1]), Pipe(b[0], a[1]));
+  }
+};
+
+typedef chrono::time_point<chrono::high_resolution_clock> Tick;
+
+static inline Tick tickNow() {
+  return chrono::high_resolution_clock::now();
+}
+
+static inline uint64_t tickNano(Tick& sta, Tick& end) {
+  return uint64_t(chrono::duration_cast<chrono::nanoseconds>(end - sta).count());
+}
+
+struct Results {
+  uint64_t m_best = 0xffffffffffffffffULL;
+  uint64_t m_worst = 0;
+  uint64_t m_transactions = 0;
+  uint64_t m_total_time = 0;
+  uint64_t m_miss = 0;
+
+  void add_time(uint64_t nano) {
+    m_best = min(nano, m_best);
+    m_worst = max(nano, m_worst);
+    m_transactions += 1;
+    m_total_time += nano;
+    if (nano > deadline_us * 1000) m_miss++;
+  }
+  void dump() {
+    double best = (double)m_best / 1.0E6;
+    double worst = (double)m_worst / 1.0E6;
+    double average = (double)m_total_time / m_transactions / 1.0E6;
+    // FIXME: libjson?
+    cout << std::setprecision(DUMP_PRICISION) << "{ \"avg\":" << setw(5) << left
+         << average << ", \"wst\":" << setw(5) << left << worst
+         << ", \"bst\":" << setw(5) << left << best << ", \"miss\":" << m_miss
+         << "}";
+  }
+};
+
+String16 generateServiceName(int num) {
+  char num_str[32];
+  snprintf(num_str, sizeof(num_str), "%d", num);
+  String16 serviceName = String16("binderWorker") + String16(num_str);
+  return serviceName;
+}
+
+static void parcel_fill(Parcel& data, int sz, int priority, int cpu) {
+  ASSERT(sz >= (int)sizeof(uint32_t) * 2);
+  data.writeInt32(priority);
+  data.writeInt32(cpu);
+  sz -= sizeof(uint32_t);
+  while (sz > (int)sizeof(uint32_t)) {
+    data.writeInt32(0);
+    sz -= sizeof(uint32_t);
+  }
+}
+
+static void* thread_start(void* p) {
+  Results* results_fifo = (Results*)p;
+  Parcel data, reply;
+  Tick sta, end;
+
+  parcel_fill(data, payload_size, thread_pri(), sched_getcpu());
+  thread_dump("fifo-caller");
+
+  sta = tickNow();
+  status_t ret = workers[0]->transact(BINDER_NOP, data, &reply);
+  end = tickNow();
+  results_fifo->add_time(tickNano(sta, end));
+
+  no_inherent += reply.readInt32();
+  no_sync += reply.readInt32();
+  return 0;
+}
+
+// create a fifo thread to transact and wait it to finished
+static void thread_transaction(Results* results_fifo) {
+  void* dummy;
+  pthread_t thread;
+  pthread_attr_t attr;
+  struct sched_param param;
+  ASSERT(!pthread_attr_init(&attr));
+  ASSERT(!pthread_attr_setschedpolicy(&attr, SCHED_FIFO));
+  param.sched_priority = sched_get_priority_max(SCHED_FIFO);
+  ASSERT(!pthread_attr_setschedparam(&attr, &param));
+  ASSERT(!pthread_create(&thread, &attr, &thread_start, results_fifo));
+  ASSERT(!pthread_join(thread, &dummy));
+}
+
+#define is_client(_num) ((_num) >= (no_process / 2))
+
+void worker_fx(int num, int no_process, int iterations, int payload_size,
+               Pipe p) {
+  int dummy;
+  Results results_other, results_fifo;
+
+  // Create BinderWorkerService and for go.
+  ProcessState::self()->startThreadPool();
+  sp<IServiceManager> serviceMgr = defaultServiceManager();
+  sp<BinderWorkerService> service = new BinderWorkerService;
+  serviceMgr->addService(generateServiceName(num), service);
+  p.signal();
+  p.wait();
+
+  // If client/server pairs, then half the workers are
+  // servers and half are clients
+  int server_count = no_process / 2;
+
+  for (int i = 0; i < server_count; i++) {
+    // self service is in-process so just skip
+    if (num == i) continue;
+    workers.push_back(serviceMgr->getService(generateServiceName(i)));
+  }
+
+  // Client for each pair iterates here
+  // each iterations contains exatcly 2 transactions
+  for (int i = 0; is_client(num) && i < iterations; i++) {
+    Parcel data, reply;
+    Tick sta, end;
+    // the target is paired to make it easier to diagnose
+    int target = num % server_count;
+
+    // 1. transaction by fifo thread
+    thread_transaction(&results_fifo);
+    parcel_fill(data, payload_size, thread_pri(), sched_getcpu());
+    thread_dump("other-caller");
+
+    // 2. transaction by other thread
+    sta = tickNow();
+    ASSERT(NO_ERROR == workers[target]->transact(BINDER_NOP, data, &reply));
+    end = tickNow();
+    results_other.add_time(tickNano(sta, end));
+
+    no_inherent += reply.readInt32();
+    no_sync += reply.readInt32();
+  }
+  // Signal completion to master and wait.
+  p.signal();
+  p.wait();
+
+  p.send(&dummy);
+  p.wait();
+  // Client for each pair dump here
+  if (is_client(num)) {
+    int no_trans = iterations * 2;
+    double sync_ratio = (1.0 - (double)no_sync / no_trans);
+    // FIXME: libjson?
+    cout << "\"P" << (num - server_count) << "\":{\"SYNC\":\""
+         << ((sync_ratio > GOOD_SYNC_MIN) ? "GOOD" : "POOR") << "\","
+         << "\"S\":" << (no_trans - no_sync) << ",\"I\":" << no_trans << ","
+         << "\"R\":" << sync_ratio << "," << endl;
+
+    cout << "      \"other_ms\":";
+    results_other.dump();
+    cout << "," << endl;
+    cout << "      \"fifo_ms\": ";
+    results_fifo.dump();
+    cout << endl;
+    cout << "}," << endl;
+  }
+  exit(no_inherent);
+}
+
+Pipe make_process(int num, int iterations, int no_process, int payload_size) {
+  auto pipe_pair = Pipe::createPipePair();
+  pid_t pid = fork();
+  if (pid) {
+    // parent
+    return move(get<0>(pipe_pair));
+  } else {
+    // child
+    thread_dump(is_client(num) ? "client" : "server");
+    worker_fx(num, no_process, iterations, payload_size,
+              move(get<1>(pipe_pair)));
+    // never get here
+    return move(get<0>(pipe_pair));
+  }
+}
+
+void wait_all(vector<Pipe>& v) {
+  for (size_t i = 0; i < v.size(); i++) {
+    v[i].wait();
+  }
+}
+
+void signal_all(vector<Pipe>& v) {
+  for (size_t i = 0; i < v.size(); i++) {
+    v[i].signal();
+  }
+}
+
+// This test is modified from binderThroughputTest.cpp
+int main(int argc, char** argv) {
+  for (int i = 1; i < argc; i++) {
+    if (string(argv[i]) == "-i") {
+      iterations = atoi(argv[i + 1]);
+      i++;
+      continue;
+    }
+    if (string(argv[i]) == "-pair") {
+      no_process = 2 * atoi(argv[i + 1]);
+      i++;
+      continue;
+    }
+    if (string(argv[i]) == "-deadline_us") {
+      deadline_us = atoi(argv[i + 1]);
+      i++;
+      continue;
+    }
+    if (string(argv[i]) == "-v") {
+      verbose = 1;
+      i++;
+    }
+  }
+  vector<Pipe> pipes;
+  thread_dump("main");
+  // FIXME: libjson?
+  cout << "{" << endl;
+  cout << "\"cfg\":{\"pair\":" << (no_process / 2)
+       << ",\"iterations\":" << iterations << ",\"deadline_us\":" << deadline_us
+       << "}," << endl;
+
+  // the main process fork 2 processes for each pairs
+  // 1 server + 1 client
+  // each has a pipe to communicate with
+  for (int i = 0; i < no_process; i++) {
+    pipes.push_back(make_process(i, iterations, no_process, payload_size));
+  }
+  wait_all(pipes);
+  signal_all(pipes);
+  wait_all(pipes);
+  signal_all(pipes);
+  for (int i = 0; i < no_process; i++) {
+    int status;
+    pipes[i].signal();
+    wait(&status);
+    // the exit status is number of transactions without priority inheritance
+    // detected in the child process
+    no_inherent += status;
+  }
+  // FIXME: libjson?
+  cout << "\"inheritance\": " << (no_inherent == 0 ? "\"PASS\"" : "\"FAIL\"")
+       << endl;
+  cout << "}" << endl;
+  return -no_inherent;
+}
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 907e0493..55e6fbf 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -98,7 +98,11 @@
 
 // XXX: Tests that fork a process to hold the BufferQueue must run before tests
 // that use a local BufferQueue, or else Binder will get unhappy
-TEST_F(BufferQueueTest, BufferQueueInAnotherProcess) {
+//
+// In one instance this was a crash in the createBufferQueue where the
+// binder call to create a buffer allocator apparently got garbage back.
+// See b/36592665.
+TEST_F(BufferQueueTest, DISABLED_BufferQueueInAnotherProcess) {
     const String16 PRODUCER_NAME = String16("BQTestProducer");
     const String16 CONSUMER_NAME = String16("BQTestConsumer");
 
diff --git a/libs/math/include/math/TMatHelpers.h b/libs/math/include/math/TMatHelpers.h
index 478e702..5cb725d 100644
--- a/libs/math/include/math/TMatHelpers.h
+++ b/libs/math/include/math/TMatHelpers.h
@@ -30,6 +30,8 @@
 
 #include  <utils/String8.h>
 
+#ifndef LIKELY
+#define LIKELY_DEFINED_LOCAL
 #ifdef __cplusplus
 #   define LIKELY( exp )    (__builtin_expect( !!(exp), true ))
 #   define UNLIKELY( exp )  (__builtin_expect( !!(exp), false ))
@@ -37,6 +39,7 @@
 #   define LIKELY( exp )    (__builtin_expect( !!(exp), 1 ))
 #   define UNLIKELY( exp )  (__builtin_expect( !!(exp), 0 ))
 #endif
+#endif
 
 #define PURE __attribute__((pure))
 
@@ -631,7 +634,11 @@
 }  // namespace details
 }  // namespace android
 
+#ifdef LIKELY_DEFINED_LOCAL
+#undef LIKELY_DEFINED_LOCAL
 #undef LIKELY
 #undef UNLIKELY
+#endif //LIKELY_DEFINED_LOCAL
+
 #undef PURE
 #undef CONSTEXPR
diff --git a/libs/math/include/math/half.h b/libs/math/include/math/half.h
index ef1e45f..615b840 100644
--- a/libs/math/include/math/half.h
+++ b/libs/math/include/math/half.h
@@ -22,6 +22,7 @@
 #include <type_traits>
 
 #ifndef LIKELY
+#define LIKELY_DEFINED_LOCAL
 #ifdef __cplusplus
 #   define LIKELY( exp )    (__builtin_expect( !!(exp), true ))
 #   define UNLIKELY( exp )  (__builtin_expect( !!(exp), false ))
@@ -202,6 +203,10 @@
 
 } // namespace std
 
+#ifdef LIKELY_DEFINED_LOCAL
+#undef LIKELY_DEFINED_LOCAL
 #undef LIKELY
 #undef UNLIKELY
+#endif // LIKELY_DEFINED_LOCAL
+
 #undef CONSTEXPR
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 2d9fc93..1ed150b 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -82,11 +82,13 @@
 }
 
 void AHardwareBuffer_acquire(AHardwareBuffer* buffer) {
+    // incStrong/decStrong token must be the same, doesn't matter what it is
     AHardwareBuffer_to_GraphicBuffer(buffer)->incStrong((void*)AHardwareBuffer_acquire);
 }
 
 void AHardwareBuffer_release(AHardwareBuffer* buffer) {
-    AHardwareBuffer_to_GraphicBuffer(buffer)->decStrong((void*)AHardwareBuffer_release);
+    // incStrong/decStrong token must be the same, doesn't matter what it is
+    AHardwareBuffer_to_GraphicBuffer(buffer)->decStrong((void*)AHardwareBuffer_acquire);
 }
 
 void AHardwareBuffer_describe(const AHardwareBuffer* buffer,
@@ -136,8 +138,7 @@
     return gBuffer->unlockAsync(fence);
 }
 
-int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer,
-        int socketFd) {
+int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd) {
     if (!buffer) return BAD_VALUE;
     const GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
 
@@ -188,8 +189,7 @@
     return NO_ERROR;
 }
 
-int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd,
-        AHardwareBuffer** outBuffer) {
+int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** outBuffer) {
     if (!outBuffer) return BAD_VALUE;
 
     char dataBuf[CMSG_SPACE(kDataBufferSize)];
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index a85d16e..a956122 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -17,36 +17,49 @@
 #define LOG_TAG "ANativeWindow"
 
 #include <android/native_window.h>
+
+// from nativewindow/includes/system/window.h
+// (not to be confused with the compatibility-only window.h from system/core/includes)
 #include <system/window.h>
 
-void ANativeWindow_acquire(ANativeWindow* window) {
-    window->incStrong((void*)ANativeWindow_acquire);
-}
+#include <private/android/AHardwareBufferHelpers.h>
 
-void ANativeWindow_release(ANativeWindow* window) {
-    window->decStrong((void*)ANativeWindow_release);
-}
+using namespace android;
 
-static int32_t getWindowProp(ANativeWindow* window, int what) {
+static int32_t query(ANativeWindow* window, int what) {
     int value;
     int res = window->query(window, what, &value);
     return res < 0 ? res : value;
 }
 
+/**************************************************************************************************
+ * NDK
+ **************************************************************************************************/
+
+void ANativeWindow_acquire(ANativeWindow* window) {
+    // incStrong/decStrong token must be the same, doesn't matter what it is
+    window->incStrong((void*)ANativeWindow_acquire);
+}
+
+void ANativeWindow_release(ANativeWindow* window) {
+    // incStrong/decStrong token must be the same, doesn't matter what it is
+    window->decStrong((void*)ANativeWindow_acquire);
+}
+
 int32_t ANativeWindow_getWidth(ANativeWindow* window) {
-    return getWindowProp(window, NATIVE_WINDOW_WIDTH);
+    return query(window, NATIVE_WINDOW_WIDTH);
 }
 
 int32_t ANativeWindow_getHeight(ANativeWindow* window) {
-    return getWindowProp(window, NATIVE_WINDOW_HEIGHT);
+    return query(window, NATIVE_WINDOW_HEIGHT);
 }
 
 int32_t ANativeWindow_getFormat(ANativeWindow* window) {
-    return getWindowProp(window, NATIVE_WINDOW_FORMAT);
+    return query(window, NATIVE_WINDOW_FORMAT);
 }
 
-int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width,
-        int32_t height, int32_t format) {
+int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window,
+        int32_t width, int32_t height, int32_t format) {
     int32_t err = native_window_set_buffers_format(window, format);
     if (!err) {
         err = native_window_set_buffers_user_dimensions(window, width, height);
@@ -79,10 +92,129 @@
             ANATIVEWINDOW_TRANSFORM_MIRROR_HORIZONTAL |
             ANATIVEWINDOW_TRANSFORM_MIRROR_VERTICAL |
             ANATIVEWINDOW_TRANSFORM_ROTATE_90;
-    if (!window || !getWindowProp(window, NATIVE_WINDOW_IS_VALID))
+    if (!window || !query(window, NATIVE_WINDOW_IS_VALID))
         return -EINVAL;
     if ((transform & ~kAllTransformBits) != 0)
         return -EINVAL;
 
     return native_window_set_buffers_transform(window, transform);
 }
+
+/**************************************************************************************************
+ * vndk-stable
+ **************************************************************************************************/
+
+int ANativeWindow_OemStorageSet(ANativeWindow* window, uint32_t slot, intptr_t value) {
+    if (slot < 4) {
+        window->oem[slot] = value;
+        return 0;
+    }
+    return -EINVAL;
+}
+
+int ANativeWindow_OemStorageGet(ANativeWindow* window, uint32_t slot, intptr_t* value) {
+    if (slot >= 4) {
+        *value = window->oem[slot];
+        return 0;
+    }
+    return -EINVAL;
+}
+
+
+int ANativeWindow_setSwapInterval(ANativeWindow* window, int interval) {
+    return window->setSwapInterval(window, interval);
+}
+
+int ANativeWindow_query(const ANativeWindow* window, ANativeWindowQuery what, int* value) {
+    switch (what) {
+        case ANATIVEWINDOW_QUERY_MIN_UNDEQUEUED_BUFFERS:
+        case ANATIVEWINDOW_QUERY_DEFAULT_WIDTH:
+        case ANATIVEWINDOW_QUERY_DEFAULT_HEIGHT:
+        case ANATIVEWINDOW_QUERY_TRANSFORM_HINT:
+            // these are part of the VNDK API
+            break;
+        case ANATIVEWINDOW_QUERY_MIN_SWAP_INTERVAL:
+            *value = window->minSwapInterval;
+            return 0;
+        case ANATIVEWINDOW_QUERY_MAX_SWAP_INTERVAL:
+            *value = window->maxSwapInterval;
+            return 0;
+        case ANATIVEWINDOW_QUERY_XDPI:
+            *value = (int)window->xdpi;
+            return 0;
+        case ANATIVEWINDOW_QUERY_YDPI:
+            *value = (int)window->ydpi;
+            return 0;
+        default:
+            // asked for an invalid query(), one that isn't part of the VNDK
+            return -EINVAL;
+    }
+    return window->query(window, int(what), value);
+}
+
+int ANativeWindow_queryf(const ANativeWindow* window, ANativeWindowQuery what, float* value) {
+    switch (what) {
+        case ANATIVEWINDOW_QUERY_XDPI:
+            *value = window->xdpi;
+            return 0;
+        case ANATIVEWINDOW_QUERY_YDPI:
+            *value = window->ydpi;
+            return 0;
+        default:
+            break;
+    }
+
+    int i;
+    int e = ANativeWindow_query(window, what, &i);
+    if (e == 0) {
+        *value = (float)i;
+    }
+    return e;
+}
+
+int ANativeWindow_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd) {
+    return window->dequeueBuffer(window, buffer, fenceFd);
+}
+
+int ANativeWindow_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) {
+    return window->queueBuffer(window, buffer, fenceFd);
+}
+
+int ANativeWindow_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) {
+    return window->cancelBuffer(window, buffer, fenceFd);
+}
+
+int ANativeWindow_setUsage(ANativeWindow* window, uint64_t usage0, uint64_t usage1) {
+    uint64_t pUsage, cUsage;
+    AHardwareBuffer_convertToGrallocUsageBits(&pUsage, &cUsage, usage0, usage1);
+    uint32_t gralloc_usage = uint32_t(pUsage | cUsage);
+    return native_window_set_usage(window, gralloc_usage);
+}
+
+int ANativeWindow_setBufferCount(ANativeWindow* window, size_t bufferCount) {
+    return native_window_set_buffer_count(window, bufferCount);
+}
+
+int ANativeWindow_setBuffersDimensions(ANativeWindow* window, uint32_t w, uint32_t h) {
+    return native_window_set_buffers_dimensions(window, (int)w, (int)h);
+}
+
+int ANativeWindow_setBuffersFormat(ANativeWindow* window, int format) {
+    return native_window_set_buffers_format(window, format);
+}
+
+int ANativeWindow_setBuffersTimestamp(ANativeWindow* window, int64_t timestamp) {
+    return native_window_set_buffers_timestamp(window, timestamp);
+}
+
+int ANativeWindow_setBufferDataSpace(ANativeWindow* window, android_dataspace_t dataSpace) {
+    return native_window_set_buffers_data_space(window, dataSpace);
+}
+
+int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMode) {
+    return native_window_set_shared_buffer_mode(window, sharedBufferMode);
+}
+
+int ANativeWindow_setAutoRefresh(ANativeWindow* window, bool autoRefresh) {
+    return native_window_set_auto_refresh(window, autoRefresh);
+}
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 572cb4e..e5b6853 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -86,13 +86,11 @@
     /* The buffer will sometimes be read by the CPU */
     AHARDWAREBUFFER_USAGE0_CPU_READ               = 1ULL << 1,
     /* The buffer will often be read by the CPU*/
-    AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN         = 1ULL << 2 |
-            AHARDWAREBUFFER_USAGE0_CPU_READ,
+    AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN         = 1ULL << 2 | AHARDWAREBUFFER_USAGE0_CPU_READ,
     /* The buffer will sometimes be written to by the CPU */
     AHARDWAREBUFFER_USAGE0_CPU_WRITE              = 1ULL << 5,
     /* The buffer will often be written to by the CPU */
-    AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN        = 1ULL << 6 |
-            AHARDWAREBUFFER_USAGE0_CPU_WRITE,
+    AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN        = 1ULL << 6 | AHARDWAREBUFFER_USAGE0_CPU_WRITE,
     /* The buffer will be read from by the GPU */
     AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE      = 1ULL << 10,
     /* The buffer will be written to by the GPU */
@@ -244,8 +242,7 @@
  * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error
  * number of the lock fails for any reason.
  */
-int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer,
-        int socketFd);
+int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd);
 
 /*
  * Receive the AHardwareBuffer from an AF_UNIX socket.
@@ -253,15 +250,13 @@
  * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error
  * number of the lock fails for any reason.
  */
-int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd,
-        AHardwareBuffer** outBuffer);
+int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** outBuffer);
 
 // ----------------------------------------------------------------------------
 // Everything below here is part of the public NDK API, but is intended only
 // for use by device-specific graphics drivers.
 struct native_handle;
-const struct native_handle* AHardwareBuffer_getNativeHandle(
-        const AHardwareBuffer* buffer);
+const struct native_handle* AHardwareBuffer_getNativeHandle(const AHardwareBuffer* buffer);
 
 __END_DECLS
 
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 6cd5df3..a12bdd7 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -93,7 +93,7 @@
     // memory.  This may be >= width.
     int32_t stride;
 
-    // The format of the buffer.  One of WINDOW_FORMAT_*
+    // The format of the buffer.  One of AHARDWAREBUFFER_FORMAT_*
     int32_t format;
 
     // The actual bits.
@@ -127,7 +127,7 @@
 int32_t ANativeWindow_getHeight(ANativeWindow* window);
 
 /**
- * Return the current pixel format of the window surface.  Returns a
+ * Return the current pixel format (AHARDWAREBUFFER_FORMAT_*) of the window surface.  Returns a
  * negative value on error.
  */
 int32_t ANativeWindow_getFormat(ANativeWindow* window);
@@ -135,6 +135,8 @@
 /**
  * Change the format and size of the window buffers.
  *
+ * format: one of AHARDWAREBUFFER_FORMAT_ constants
+ *
  * The width and height control the number of pixels in the buffers, not the
  * dimensions of the window on screen.  If these are different than the
  * window's physical size, then it buffer will be scaled to match that size
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
new file mode 100644
index 0000000..63d1ad1
--- /dev/null
+++ b/libs/nativewindow/include/system/window.h
@@ -0,0 +1,952 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+/*************************************************************************************************
+ *
+ * IMPORTANT:
+ *
+ * There is an old copy of this file in system/core/include/system/window.h, which exists only
+ * for backward source compatibility.
+ * But there are binaries out there as well, so this version of window.h must stay binary
+ * backward compatible with the one found in system/core.
+ *
+ *
+ * Source compatibility is also required for now, because this is how we're handling the
+ * transition from system/core/include (global include path) to nativewindow/include.
+ *
+ *************************************************************************************************/
+
+#pragma once
+
+#include <cutils/native_handle.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/cdefs.h>
+#include <system/graphics.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+// system/window.h is a superset of the vndk
+#include <vndk/window.h>
+
+
+#ifndef __UNUSED
+#define __UNUSED __attribute__((__unused__))
+#endif
+#ifndef __deprecated
+#define __deprecated __attribute__((__deprecated__))
+#endif
+
+__BEGIN_DECLS
+
+/*****************************************************************************/
+
+#define ANDROID_NATIVE_WINDOW_MAGIC     ANDROID_NATIVE_MAKE_CONSTANT('_','w','n','d')
+
+// ---------------------------------------------------------------------------
+
+typedef const native_handle_t* buffer_handle_t;
+
+// ---------------------------------------------------------------------------
+
+typedef struct android_native_rect_t
+{
+    int32_t left;
+    int32_t top;
+    int32_t right;
+    int32_t bottom;
+} android_native_rect_t;
+
+// ---------------------------------------------------------------------------
+
+// Old typedef for backwards compatibility.
+typedef ANativeWindowBuffer_t android_native_buffer_t;
+
+// ---------------------------------------------------------------------------
+
+/* attributes queriable with query() */
+enum {
+    NATIVE_WINDOW_WIDTH     = 0,
+    NATIVE_WINDOW_HEIGHT    = 1,
+    NATIVE_WINDOW_FORMAT    = 2,
+
+    /* see ANativeWindowQuery in vndk/window.h */
+    NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS = ANATIVEWINDOW_QUERY_MIN_UNDEQUEUED_BUFFERS,
+
+    /* Check whether queueBuffer operations on the ANativeWindow send the buffer
+     * to the window compositor.  The query sets the returned 'value' argument
+     * to 1 if the ANativeWindow DOES send queued buffers directly to the window
+     * compositor and 0 if the buffers do not go directly to the window
+     * compositor.
+     *
+     * This can be used to determine whether protected buffer content should be
+     * sent to the ANativeWindow.  Note, however, that a result of 1 does NOT
+     * indicate that queued buffers will be protected from applications or users
+     * capturing their contents.  If that behavior is desired then some other
+     * mechanism (e.g. the GRALLOC_USAGE_PROTECTED flag) should be used in
+     * conjunction with this query.
+     */
+    NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER = 4,
+
+    /* Get the concrete type of a ANativeWindow.  See below for the list of
+     * possible return values.
+     *
+     * This query should not be used outside the Android framework and will
+     * likely be removed in the near future.
+     */
+    NATIVE_WINDOW_CONCRETE_TYPE = 5,
+
+
+    /*
+     * Default width and height of ANativeWindow buffers, these are the
+     * dimensions of the window buffers irrespective of the
+     * NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS call and match the native window
+     * size unless overridden by NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS.
+     */
+    NATIVE_WINDOW_DEFAULT_WIDTH = ANATIVEWINDOW_QUERY_DEFAULT_WIDTH,
+    NATIVE_WINDOW_DEFAULT_HEIGHT = ANATIVEWINDOW_QUERY_DEFAULT_HEIGHT,
+
+    /* see ANativeWindowQuery in vndk/window.h */
+    NATIVE_WINDOW_TRANSFORM_HINT = ANATIVEWINDOW_QUERY_TRANSFORM_HINT,
+
+    /*
+     * Boolean that indicates whether the consumer is running more than
+     * one buffer behind the producer.
+     */
+    NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND = 9,
+
+    /*
+     * The consumer gralloc usage bits currently set by the consumer.
+     * The values are defined in hardware/libhardware/include/gralloc.h.
+     */
+    NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10,
+
+    /**
+     * Transformation that will by applied to buffers by the hwcomposer.
+     * This must not be set or checked by producer endpoints, and will
+     * disable the transform hint set in SurfaceFlinger (see
+     * NATIVE_WINDOW_TRANSFORM_HINT).
+     *
+     * INTENDED USE:
+     * Temporary - Please do not use this.  This is intended only to be used
+     * by the camera's LEGACY mode.
+     *
+     * In situations where a SurfaceFlinger client wishes to set a transform
+     * that is not visible to the producer, and will always be applied in the
+     * hardware composer, the client can set this flag with
+     * native_window_set_buffers_sticky_transform.  This can be used to rotate
+     * and flip buffers consumed by hardware composer without actually changing
+     * the aspect ratio of the buffers produced.
+     */
+    NATIVE_WINDOW_STICKY_TRANSFORM = 11,
+
+    /**
+     * The default data space for the buffers as set by the consumer.
+     * The values are defined in graphics.h.
+     */
+    NATIVE_WINDOW_DEFAULT_DATASPACE = 12,
+
+    /* see ANativeWindowQuery in vndk/window.h */
+    NATIVE_WINDOW_BUFFER_AGE = ANATIVEWINDOW_QUERY_BUFFER_AGE,
+
+    /*
+     * Returns the duration of the last dequeueBuffer call in microseconds
+     */
+    NATIVE_WINDOW_LAST_DEQUEUE_DURATION = 14,
+
+    /*
+     * Returns the duration of the last queueBuffer call in microseconds
+     */
+    NATIVE_WINDOW_LAST_QUEUE_DURATION = 15,
+
+    /*
+     * Returns the number of image layers that the ANativeWindow buffer
+     * contains. By default this is 1, unless a buffer is explicitly allocated
+     * to contain multiple layers.
+     */
+    NATIVE_WINDOW_LAYER_COUNT = 16,
+
+    /*
+     * Returns 1 if the native window is valid, 0 otherwise. native window is valid
+     * if it is safe (i.e. no crash will occur) to call any method on it.
+     */
+    NATIVE_WINDOW_IS_VALID = 17,
+};
+
+/* Valid operations for the (*perform)() hook.
+ *
+ * Values marked as 'deprecated' are supported, but have been superceded by
+ * other functionality.
+ *
+ * Values marked as 'private' should be considered private to the framework.
+ * HAL implementation code with access to an ANativeWindow should not use these,
+ * as it may not interact properly with the framework's use of the
+ * ANativeWindow.
+ */
+enum {
+// clang-format off
+    NATIVE_WINDOW_SET_USAGE                 =  0,
+    NATIVE_WINDOW_CONNECT                   =  1,   /* deprecated */
+    NATIVE_WINDOW_DISCONNECT                =  2,   /* deprecated */
+    NATIVE_WINDOW_SET_CROP                  =  3,   /* private */
+    NATIVE_WINDOW_SET_BUFFER_COUNT          =  4,
+    NATIVE_WINDOW_SET_BUFFERS_GEOMETRY      =  5,   /* deprecated */
+    NATIVE_WINDOW_SET_BUFFERS_TRANSFORM     =  6,
+    NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP     =  7,
+    NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS    =  8,
+    NATIVE_WINDOW_SET_BUFFERS_FORMAT        =  9,
+    NATIVE_WINDOW_SET_SCALING_MODE          = 10,   /* private */
+    NATIVE_WINDOW_LOCK                      = 11,   /* private */
+    NATIVE_WINDOW_UNLOCK_AND_POST           = 12,   /* private */
+    NATIVE_WINDOW_API_CONNECT               = 13,   /* private */
+    NATIVE_WINDOW_API_DISCONNECT            = 14,   /* private */
+    NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
+    NATIVE_WINDOW_SET_POST_TRANSFORM_CROP   = 16,   /* private */
+    NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17,/* private */
+    NATIVE_WINDOW_SET_SIDEBAND_STREAM       = 18,
+    NATIVE_WINDOW_SET_BUFFERS_DATASPACE     = 19,
+    NATIVE_WINDOW_SET_SURFACE_DAMAGE        = 20,   /* private */
+    NATIVE_WINDOW_SET_SHARED_BUFFER_MODE    = 21,
+    NATIVE_WINDOW_SET_AUTO_REFRESH          = 22,
+    NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION= 23,
+    NATIVE_WINDOW_GET_NEXT_FRAME_ID         = 24,
+    NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS   = 25,
+    NATIVE_WINDOW_GET_COMPOSITOR_TIMING     = 26,
+    NATIVE_WINDOW_GET_FRAME_TIMESTAMPS      = 27,
+    NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT    = 28,
+    NATIVE_WINDOW_GET_HDR_SUPPORT           = 29,
+// clang-format on
+};
+
+/* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
+enum {
+    /* Buffers will be queued by EGL via eglSwapBuffers after being filled using
+     * OpenGL ES.
+     */
+    NATIVE_WINDOW_API_EGL = 1,
+
+    /* Buffers will be queued after being filled using the CPU
+     */
+    NATIVE_WINDOW_API_CPU = 2,
+
+    /* Buffers will be queued by Stagefright after being filled by a video
+     * decoder.  The video decoder can either be a software or hardware decoder.
+     */
+    NATIVE_WINDOW_API_MEDIA = 3,
+
+    /* Buffers will be queued by the the camera HAL.
+     */
+    NATIVE_WINDOW_API_CAMERA = 4,
+};
+
+/* parameter for NATIVE_WINDOW_SET_BUFFERS_TRANSFORM */
+enum {
+    /* flip source image horizontally */
+    NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H ,
+    /* flip source image vertically */
+    NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
+    /* rotate source image 90 degrees clock-wise, and is applied after TRANSFORM_FLIP_{H|V} */
+    NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
+    /* rotate source image 180 degrees */
+    NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
+    /* rotate source image 270 degrees clock-wise */
+    NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
+    /* transforms source by the inverse transform of the screen it is displayed onto. This
+     * transform is applied last */
+    NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY = 0x08
+};
+
+/* parameter for NATIVE_WINDOW_SET_SCALING_MODE
+ * keep in sync with Surface.java in frameworks/base */
+enum {
+    /* the window content is not updated (frozen) until a buffer of
+     * the window size is received (enqueued)
+     */
+    NATIVE_WINDOW_SCALING_MODE_FREEZE           = 0,
+    /* the buffer is scaled in both dimensions to match the window size */
+    NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW  = 1,
+    /* the buffer is scaled uniformly such that the smaller dimension
+     * of the buffer matches the window size (cropping in the process)
+     */
+    NATIVE_WINDOW_SCALING_MODE_SCALE_CROP       = 2,
+    /* the window is clipped to the size of the buffer's crop rectangle; pixels
+     * outside the crop rectangle are treated as if they are completely
+     * transparent.
+     */
+    NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP    = 3,
+};
+
+/* values returned by the NATIVE_WINDOW_CONCRETE_TYPE query */
+enum {
+    NATIVE_WINDOW_FRAMEBUFFER               = 0, /* FramebufferNativeWindow */
+    NATIVE_WINDOW_SURFACE                   = 1, /* Surface */
+};
+
+/* parameter for NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
+ *
+ * Special timestamp value to indicate that timestamps should be auto-generated
+ * by the native window when queueBuffer is called.  This is equal to INT64_MIN,
+ * defined directly to avoid problems with C99/C++ inclusion of stdint.h.
+ */
+static const int64_t NATIVE_WINDOW_TIMESTAMP_AUTO = (-9223372036854775807LL-1);
+
+struct ANativeWindow
+{
+#ifdef __cplusplus
+    ANativeWindow()
+        : flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0)
+    {
+        common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
+        common.version = sizeof(ANativeWindow);
+        memset(common.reserved, 0, sizeof(common.reserved));
+    }
+
+    /* Implement the methods that sp<ANativeWindow> expects so that it
+       can be used to automatically refcount ANativeWindow's. */
+    void incStrong(const void* /*id*/) const {
+        common.incRef(const_cast<android_native_base_t*>(&common));
+    }
+    void decStrong(const void* /*id*/) const {
+        common.decRef(const_cast<android_native_base_t*>(&common));
+    }
+#endif
+
+    struct android_native_base_t common;
+
+    /* flags describing some attributes of this surface or its updater */
+    const uint32_t flags;
+
+    /* min swap interval supported by this updated */
+    const int   minSwapInterval;
+
+    /* max swap interval supported by this updated */
+    const int   maxSwapInterval;
+
+    /* horizontal and vertical resolution in DPI */
+    const float xdpi;
+    const float ydpi;
+
+    /* Some storage reserved for the OEM's driver. */
+    intptr_t    oem[4];
+
+    /*
+     * Set the swap interval for this surface.
+     *
+     * Returns 0 on success or -errno on error.
+     */
+    int     (*setSwapInterval)(struct ANativeWindow* window,
+                int interval);
+
+    /*
+     * Hook called by EGL to acquire a buffer. After this call, the buffer
+     * is not locked, so its content cannot be modified. This call may block if
+     * no buffers are available.
+     *
+     * The window holds a reference to the buffer between dequeueBuffer and
+     * either queueBuffer or cancelBuffer, so clients only need their own
+     * reference if they might use the buffer after queueing or canceling it.
+     * Holding a reference to a buffer after queueing or canceling it is only
+     * allowed if a specific buffer count has been set.
+     *
+     * Returns 0 on success or -errno on error.
+     *
+     * XXX: This function is deprecated.  It will continue to work for some
+     * time for binary compatibility, but the new dequeueBuffer function that
+     * outputs a fence file descriptor should be used in its place.
+     */
+    int     (*dequeueBuffer_DEPRECATED)(struct ANativeWindow* window,
+                struct ANativeWindowBuffer** buffer);
+
+    /*
+     * hook called by EGL to lock a buffer. This MUST be called before modifying
+     * the content of a buffer. The buffer must have been acquired with
+     * dequeueBuffer first.
+     *
+     * Returns 0 on success or -errno on error.
+     *
+     * XXX: This function is deprecated.  It will continue to work for some
+     * time for binary compatibility, but it is essentially a no-op, and calls
+     * to it should be removed.
+     */
+    int     (*lockBuffer_DEPRECATED)(struct ANativeWindow* window,
+                struct ANativeWindowBuffer* buffer);
+
+    /*
+     * Hook called by EGL when modifications to the render buffer are done.
+     * This unlocks and post the buffer.
+     *
+     * The window holds a reference to the buffer between dequeueBuffer and
+     * either queueBuffer or cancelBuffer, so clients only need their own
+     * reference if they might use the buffer after queueing or canceling it.
+     * Holding a reference to a buffer after queueing or canceling it is only
+     * allowed if a specific buffer count has been set.
+     *
+     * Buffers MUST be queued in the same order than they were dequeued.
+     *
+     * Returns 0 on success or -errno on error.
+     *
+     * XXX: This function is deprecated.  It will continue to work for some
+     * time for binary compatibility, but the new queueBuffer function that
+     * takes a fence file descriptor should be used in its place (pass a value
+     * of -1 for the fence file descriptor if there is no valid one to pass).
+     */
+    int     (*queueBuffer_DEPRECATED)(struct ANativeWindow* window,
+                struct ANativeWindowBuffer* buffer);
+
+    /*
+     * hook used to retrieve information about the native window.
+     *
+     * Returns 0 on success or -errno on error.
+     */
+    int     (*query)(const struct ANativeWindow* window,
+                int what, int* value);
+
+    /*
+     * hook used to perform various operations on the surface.
+     * (*perform)() is a generic mechanism to add functionality to
+     * ANativeWindow while keeping backward binary compatibility.
+     *
+     * DO NOT CALL THIS HOOK DIRECTLY.  Instead, use the helper functions
+     * defined below.
+     *
+     * (*perform)() returns -ENOENT if the 'what' parameter is not supported
+     * by the surface's implementation.
+     *
+     * See above for a list of valid operations, such as
+     * NATIVE_WINDOW_SET_USAGE or NATIVE_WINDOW_CONNECT
+     */
+    int     (*perform)(struct ANativeWindow* window,
+                int operation, ... );
+
+    /*
+     * Hook used to cancel a buffer that has been dequeued.
+     * No synchronization is performed between dequeue() and cancel(), so
+     * either external synchronization is needed, or these functions must be
+     * called from the same thread.
+     *
+     * The window holds a reference to the buffer between dequeueBuffer and
+     * either queueBuffer or cancelBuffer, so clients only need their own
+     * reference if they might use the buffer after queueing or canceling it.
+     * Holding a reference to a buffer after queueing or canceling it is only
+     * allowed if a specific buffer count has been set.
+     *
+     * XXX: This function is deprecated.  It will continue to work for some
+     * time for binary compatibility, but the new cancelBuffer function that
+     * takes a fence file descriptor should be used in its place (pass a value
+     * of -1 for the fence file descriptor if there is no valid one to pass).
+     */
+    int     (*cancelBuffer_DEPRECATED)(struct ANativeWindow* window,
+                struct ANativeWindowBuffer* buffer);
+
+    /*
+     * Hook called by EGL to acquire a buffer. This call may block if no
+     * buffers are available.
+     *
+     * The window holds a reference to the buffer between dequeueBuffer and
+     * either queueBuffer or cancelBuffer, so clients only need their own
+     * reference if they might use the buffer after queueing or canceling it.
+     * Holding a reference to a buffer after queueing or canceling it is only
+     * allowed if a specific buffer count has been set.
+     *
+     * The libsync fence file descriptor returned in the int pointed to by the
+     * fenceFd argument will refer to the fence that must signal before the
+     * dequeued buffer may be written to.  A value of -1 indicates that the
+     * caller may access the buffer immediately without waiting on a fence.  If
+     * a valid file descriptor is returned (i.e. any value except -1) then the
+     * caller is responsible for closing the file descriptor.
+     *
+     * Returns 0 on success or -errno on error.
+     */
+    int     (*dequeueBuffer)(struct ANativeWindow* window,
+                struct ANativeWindowBuffer** buffer, int* fenceFd);
+
+    /*
+     * Hook called by EGL when modifications to the render buffer are done.
+     * This unlocks and post the buffer.
+     *
+     * The window holds a reference to the buffer between dequeueBuffer and
+     * either queueBuffer or cancelBuffer, so clients only need their own
+     * reference if they might use the buffer after queueing or canceling it.
+     * Holding a reference to a buffer after queueing or canceling it is only
+     * allowed if a specific buffer count has been set.
+     *
+     * The fenceFd argument specifies a libsync fence file descriptor for a
+     * fence that must signal before the buffer can be accessed.  If the buffer
+     * can be accessed immediately then a value of -1 should be used.  The
+     * caller must not use the file descriptor after it is passed to
+     * queueBuffer, and the ANativeWindow implementation is responsible for
+     * closing it.
+     *
+     * Returns 0 on success or -errno on error.
+     */
+    int     (*queueBuffer)(struct ANativeWindow* window,
+                struct ANativeWindowBuffer* buffer, int fenceFd);
+
+    /*
+     * Hook used to cancel a buffer that has been dequeued.
+     * No synchronization is performed between dequeue() and cancel(), so
+     * either external synchronization is needed, or these functions must be
+     * called from the same thread.
+     *
+     * The window holds a reference to the buffer between dequeueBuffer and
+     * either queueBuffer or cancelBuffer, so clients only need their own
+     * reference if they might use the buffer after queueing or canceling it.
+     * Holding a reference to a buffer after queueing or canceling it is only
+     * allowed if a specific buffer count has been set.
+     *
+     * The fenceFd argument specifies a libsync fence file decsriptor for a
+     * fence that must signal before the buffer can be accessed.  If the buffer
+     * can be accessed immediately then a value of -1 should be used.
+     *
+     * Note that if the client has not waited on the fence that was returned
+     * from dequeueBuffer, that same fence should be passed to cancelBuffer to
+     * ensure that future uses of the buffer are preceded by a wait on that
+     * fence.  The caller must not use the file descriptor after it is passed
+     * to cancelBuffer, and the ANativeWindow implementation is responsible for
+     * closing it.
+     *
+     * Returns 0 on success or -errno on error.
+     */
+    int     (*cancelBuffer)(struct ANativeWindow* window,
+                struct ANativeWindowBuffer* buffer, int fenceFd);
+};
+
+ /* Backwards compatibility: use ANativeWindow (struct ANativeWindow in C).
+  * android_native_window_t is deprecated.
+  */
+typedef struct ANativeWindow ANativeWindow;
+typedef struct ANativeWindow android_native_window_t __deprecated;
+
+/*
+ *  native_window_set_usage(..., usage)
+ *  Sets the intended usage flags for the next buffers
+ *  acquired with (*lockBuffer)() and on.
+ *  By default (if this function is never called), a usage of
+ *      GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE
+ *  is assumed.
+ *  Calling this function will usually cause following buffers to be
+ *  reallocated.
+ */
+
+static inline int native_window_set_usage(
+        struct ANativeWindow* window, int usage)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage);
+}
+
+/* deprecated. Always returns 0. Don't call. */
+static inline int native_window_connect(
+        struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated;
+
+static inline int native_window_connect(
+        struct ANativeWindow* window __UNUSED, int api __UNUSED) {
+    return 0;
+}
+
+/* deprecated. Always returns 0. Don't call. */
+static inline int native_window_disconnect(
+        struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated;
+
+static inline int native_window_disconnect(
+        struct ANativeWindow* window __UNUSED, int api __UNUSED) {
+    return 0;
+}
+
+/*
+ * native_window_set_crop(..., crop)
+ * Sets which region of the next queued buffers needs to be considered.
+ * Depending on the scaling mode, a buffer's crop region is scaled and/or
+ * cropped to match the surface's size.  This function sets the crop in
+ * pre-transformed buffer pixel coordinates.
+ *
+ * The specified crop region applies to all buffers queued after it is called.
+ *
+ * If 'crop' is NULL, subsequently queued buffers won't be cropped.
+ *
+ * An error is returned if for instance the crop region is invalid, out of the
+ * buffer's bound or if the window is invalid.
+ */
+static inline int native_window_set_crop(
+        struct ANativeWindow* window,
+        android_native_rect_t const * crop)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_CROP, crop);
+}
+
+/*
+ * native_window_set_post_transform_crop(..., crop)
+ * Sets which region of the next queued buffers needs to be considered.
+ * Depending on the scaling mode, a buffer's crop region is scaled and/or
+ * cropped to match the surface's size.  This function sets the crop in
+ * post-transformed pixel coordinates.
+ *
+ * The specified crop region applies to all buffers queued after it is called.
+ *
+ * If 'crop' is NULL, subsequently queued buffers won't be cropped.
+ *
+ * An error is returned if for instance the crop region is invalid, out of the
+ * buffer's bound or if the window is invalid.
+ */
+static inline int native_window_set_post_transform_crop(
+        struct ANativeWindow* window,
+        android_native_rect_t const * crop)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_POST_TRANSFORM_CROP, crop);
+}
+
+/*
+ * native_window_set_active_rect(..., active_rect)
+ *
+ * This function is deprecated and will be removed soon.  For now it simply
+ * sets the post-transform crop for compatibility while multi-project commits
+ * get checked.
+ */
+static inline int native_window_set_active_rect(
+        struct ANativeWindow* window,
+        android_native_rect_t const * active_rect) __deprecated;
+
+static inline int native_window_set_active_rect(
+        struct ANativeWindow* window,
+        android_native_rect_t const * active_rect)
+{
+    return native_window_set_post_transform_crop(window, active_rect);
+}
+
+/*
+ * native_window_set_buffer_count(..., count)
+ * Sets the number of buffers associated with this native window.
+ */
+static inline int native_window_set_buffer_count(
+        struct ANativeWindow* window,
+        size_t bufferCount)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFER_COUNT, bufferCount);
+}
+
+/*
+ * native_window_set_buffers_geometry(..., int w, int h, int format)
+ * All buffers dequeued after this call will have the dimensions and format
+ * specified.  A successful call to this function has the same effect as calling
+ * native_window_set_buffers_size and native_window_set_buffers_format.
+ *
+ * XXX: This function is deprecated.  The native_window_set_buffers_dimensions
+ * and native_window_set_buffers_format functions should be used instead.
+ */
+static inline int native_window_set_buffers_geometry(
+        struct ANativeWindow* window,
+        int w, int h, int format) __deprecated;
+
+static inline int native_window_set_buffers_geometry(
+        struct ANativeWindow* window,
+        int w, int h, int format)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
+            w, h, format);
+}
+
+/*
+ * native_window_set_buffers_dimensions(..., int w, int h)
+ * All buffers dequeued after this call will have the dimensions specified.
+ * In particular, all buffers will have a fixed-size, independent from the
+ * native-window size. They will be scaled according to the scaling mode
+ * (see native_window_set_scaling_mode) upon window composition.
+ *
+ * If w and h are 0, the normal behavior is restored. That is, dequeued buffers
+ * following this call will be sized to match the window's size.
+ *
+ * Calling this function will reset the window crop to a NULL value, which
+ * disables cropping of the buffers.
+ */
+static inline int native_window_set_buffers_dimensions(
+        struct ANativeWindow* window,
+        int w, int h)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS,
+            w, h);
+}
+
+/*
+ * native_window_set_buffers_user_dimensions(..., int w, int h)
+ *
+ * Sets the user buffer size for the window, which overrides the
+ * window's size.  All buffers dequeued after this call will have the
+ * dimensions specified unless overridden by
+ * native_window_set_buffers_dimensions.  All buffers will have a
+ * fixed-size, independent from the native-window size. They will be
+ * scaled according to the scaling mode (see
+ * native_window_set_scaling_mode) upon window composition.
+ *
+ * If w and h are 0, the normal behavior is restored. That is, the
+ * default buffer size will match the windows's size.
+ *
+ * Calling this function will reset the window crop to a NULL value, which
+ * disables cropping of the buffers.
+ */
+static inline int native_window_set_buffers_user_dimensions(
+        struct ANativeWindow* window,
+        int w, int h)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS,
+            w, h);
+}
+
+/*
+ * native_window_set_buffers_format(..., int format)
+ * All buffers dequeued after this call will have the format specified.
+ *
+ * If the specified format is 0, the default buffer format will be used.
+ */
+static inline int native_window_set_buffers_format(
+        struct ANativeWindow* window,
+        int format)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_FORMAT, format);
+}
+
+/*
+ * native_window_set_buffers_data_space(..., int dataSpace)
+ * All buffers queued after this call will be associated with the dataSpace
+ * parameter specified.
+ *
+ * dataSpace specifies additional information about the buffer that's dependent
+ * on the buffer format and the endpoints. For example, it can be used to convey
+ * the color space of the image data in the buffer, or it can be used to
+ * indicate that the buffers contain depth measurement data instead of color
+ * images.  The default dataSpace is 0, HAL_DATASPACE_UNKNOWN, unless it has been
+ * overridden by the consumer.
+ */
+static inline int native_window_set_buffers_data_space(
+        struct ANativeWindow* window,
+        android_dataspace_t dataSpace)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_DATASPACE,
+            dataSpace);
+}
+
+/*
+ * native_window_set_buffers_transform(..., int transform)
+ * All buffers queued after this call will be displayed transformed according
+ * to the transform parameter specified.
+ */
+static inline int native_window_set_buffers_transform(
+        struct ANativeWindow* window,
+        int transform)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
+            transform);
+}
+
+/*
+ * native_window_set_buffers_sticky_transform(..., int transform)
+ * All buffers queued after this call will be displayed transformed according
+ * to the transform parameter specified applied on top of the regular buffer
+ * transform.  Setting this transform will disable the transform hint.
+ *
+ * Temporary - This is only intended to be used by the LEGACY camera mode, do
+ *   not use this for anything else.
+ */
+static inline int native_window_set_buffers_sticky_transform(
+        struct ANativeWindow* window,
+        int transform)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM,
+            transform);
+}
+
+/*
+ * native_window_set_buffers_timestamp(..., int64_t timestamp)
+ * All buffers queued after this call will be associated with the timestamp
+ * parameter specified. If the timestamp is set to NATIVE_WINDOW_TIMESTAMP_AUTO
+ * (the default), timestamps will be generated automatically when queueBuffer is
+ * called. The timestamp is measured in nanoseconds, and is normally monotonically
+ * increasing. The timestamp should be unaffected by time-of-day adjustments,
+ * and for a camera should be strictly monotonic but for a media player may be
+ * reset when the position is set.
+ */
+static inline int native_window_set_buffers_timestamp(
+        struct ANativeWindow* window,
+        int64_t timestamp)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP,
+            timestamp);
+}
+
+/*
+ * native_window_set_scaling_mode(..., int mode)
+ * All buffers queued after this call will be associated with the scaling mode
+ * specified.
+ */
+static inline int native_window_set_scaling_mode(
+        struct ANativeWindow* window,
+        int mode)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_SCALING_MODE,
+            mode);
+}
+
+/*
+ * native_window_api_connect(..., int api)
+ * connects an API to this window. only one API can be connected at a time.
+ * Returns -EINVAL if for some reason the window cannot be connected, which
+ * can happen if it's connected to some other API.
+ */
+static inline int native_window_api_connect(
+        struct ANativeWindow* window, int api)
+{
+    return window->perform(window, NATIVE_WINDOW_API_CONNECT, api);
+}
+
+/*
+ * native_window_api_disconnect(..., int api)
+ * disconnect the API from this window.
+ * An error is returned if for instance the window wasn't connected in the
+ * first place.
+ */
+static inline int native_window_api_disconnect(
+        struct ANativeWindow* window, int api)
+{
+    return window->perform(window, NATIVE_WINDOW_API_DISCONNECT, api);
+}
+
+/*
+ * native_window_dequeue_buffer_and_wait(...)
+ * Dequeue a buffer and wait on the fence associated with that buffer.  The
+ * buffer may safely be accessed immediately upon this function returning.  An
+ * error is returned if either of the dequeue or the wait operations fail.
+ */
+static inline int native_window_dequeue_buffer_and_wait(ANativeWindow *anw,
+        struct ANativeWindowBuffer** anb) {
+    return anw->dequeueBuffer_DEPRECATED(anw, anb);
+}
+
+/*
+ * native_window_set_sideband_stream(..., native_handle_t*)
+ * Attach a sideband buffer stream to a native window.
+ */
+static inline int native_window_set_sideband_stream(
+        struct ANativeWindow* window,
+        native_handle_t* sidebandHandle)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_SIDEBAND_STREAM,
+            sidebandHandle);
+}
+
+/*
+ * native_window_set_surface_damage(..., android_native_rect_t* rects, int numRects)
+ * Set the surface damage (i.e., the region of the surface that has changed
+ * since the previous frame). The damage set by this call will be reset (to the
+ * default of full-surface damage) after calling queue, so this must be called
+ * prior to every frame with damage that does not cover the whole surface if the
+ * caller desires downstream consumers to use this optimization.
+ *
+ * The damage region is specified as an array of rectangles, with the important
+ * caveat that the origin of the surface is considered to be the bottom-left
+ * corner, as in OpenGL ES.
+ *
+ * If numRects is set to 0, rects may be NULL, and the surface damage will be
+ * set to the full surface (the same as if this function had not been called for
+ * this frame).
+ */
+static inline int native_window_set_surface_damage(
+        struct ANativeWindow* window,
+        const android_native_rect_t* rects, size_t numRects)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_SURFACE_DAMAGE,
+            rects, numRects);
+}
+
+/*
+ * native_window_set_shared_buffer_mode(..., bool sharedBufferMode)
+ * Enable/disable shared buffer mode
+ */
+static inline int native_window_set_shared_buffer_mode(
+        struct ANativeWindow* window,
+        bool sharedBufferMode)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_SHARED_BUFFER_MODE,
+            sharedBufferMode);
+}
+
+/*
+ * native_window_set_auto_refresh(..., autoRefresh)
+ * Enable/disable auto refresh when in shared buffer mode
+ */
+static inline int native_window_set_auto_refresh(
+        struct ANativeWindow* window,
+        bool autoRefresh)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_AUTO_REFRESH, autoRefresh);
+}
+
+static inline int native_window_get_refresh_cycle_duration(
+        struct ANativeWindow* window,
+        int64_t* outRefreshDuration)
+{
+    return window->perform(window, NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION,
+            outRefreshDuration);
+}
+
+static inline int native_window_get_next_frame_id(
+        struct ANativeWindow* window, uint64_t* frameId)
+{
+    return window->perform(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID, frameId);
+}
+
+static inline int native_window_enable_frame_timestamps(
+        struct ANativeWindow* window, bool enable)
+{
+    return window->perform(window, NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS,
+            enable);
+}
+
+static inline int native_window_get_compositor_timing(
+        struct ANativeWindow* window,
+        int64_t* compositeDeadline, int64_t* compositeInterval,
+        int64_t* compositeToPresentLatency)
+{
+    return window->perform(window, NATIVE_WINDOW_GET_COMPOSITOR_TIMING,
+            compositeDeadline, compositeInterval, compositeToPresentLatency);
+}
+
+static inline int native_window_get_frame_timestamps(
+        struct ANativeWindow* window, uint64_t frameId,
+        int64_t* outRequestedPresentTime, int64_t* outAcquireTime,
+        int64_t* outLatchTime, int64_t* outFirstRefreshStartTime,
+        int64_t* outLastRefreshStartTime, int64_t* outGpuCompositionDoneTime,
+        int64_t* outDisplayPresentTime, int64_t* outDequeueReadyTime,
+        int64_t* outReleaseTime)
+{
+    return window->perform(window, NATIVE_WINDOW_GET_FRAME_TIMESTAMPS,
+            frameId, outRequestedPresentTime, outAcquireTime, outLatchTime,
+            outFirstRefreshStartTime, outLastRefreshStartTime,
+            outGpuCompositionDoneTime, outDisplayPresentTime,
+            outDequeueReadyTime, outReleaseTime);
+}
+
+static inline int native_window_get_wide_color_support(
+    struct ANativeWindow* window, bool* outSupport) {
+  return window->perform(window, NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT,
+                         outSupport);
+}
+
+static inline int native_window_get_hdr_support(struct ANativeWindow* window,
+                                                bool* outSupport) {
+  return window->perform(window, NATIVE_WINDOW_GET_HDR_SUPPORT, outSupport);
+}
+
+__END_DECLS
diff --git a/libs/nativewindow/include/vndk/window.h b/libs/nativewindow/include/vndk/window.h
new file mode 100644
index 0000000..89585f3
--- /dev/null
+++ b/libs/nativewindow/include/vndk/window.h
@@ -0,0 +1,407 @@
+/*
+ * 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_VNDK_NATIVEWINDOW_ANATIVEWINDOW_H
+#define ANDROID_VNDK_NATIVEWINDOW_ANATIVEWINDOW_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/cdefs.h>
+#include <system/graphics-base.h>
+#include <cutils/native_handle.h>
+
+// vndk is a superset of the NDK
+#include <android/native_window.h>
+
+__BEGIN_DECLS
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+#define ANDROID_NATIVE_UNSIGNED_CAST(x) static_cast<unsigned int>(x)
+#else
+#define ANDROID_NATIVE_UNSIGNED_CAST(x) ((unsigned int)(x))
+#endif
+
+#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d)  \
+    ((ANDROID_NATIVE_UNSIGNED_CAST(a) << 24) | \
+     (ANDROID_NATIVE_UNSIGNED_CAST(b) << 16) | \
+     (ANDROID_NATIVE_UNSIGNED_CAST(c) <<  8) | \
+     (ANDROID_NATIVE_UNSIGNED_CAST(d)))
+
+#define ANDROID_NATIVE_BUFFER_MAGIC     ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r')
+
+
+/*****************************************************************************/
+
+typedef struct android_native_base_t
+{
+    /* a magic value defined by the actual EGL native type */
+    int magic;
+
+    /* the sizeof() of the actual EGL native type */
+    int version;
+
+    void* reserved[4];
+
+    /* reference-counting interface */
+    void (*incRef)(struct android_native_base_t* base);
+    void (*decRef)(struct android_native_base_t* base);
+} android_native_base_t;
+
+typedef struct ANativeWindowBuffer
+{
+#ifdef __cplusplus
+    ANativeWindowBuffer() {
+        common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
+        common.version = sizeof(ANativeWindowBuffer);
+        memset(common.reserved, 0, sizeof(common.reserved));
+    }
+
+    // Implement the methods that sp<ANativeWindowBuffer> expects so that it
+    // can be used to automatically refcount ANativeWindowBuffer's.
+    void incStrong(const void* /*id*/) const {
+        common.incRef(const_cast<android_native_base_t*>(&common));
+    }
+    void decStrong(const void* /*id*/) const {
+        common.decRef(const_cast<android_native_base_t*>(&common));
+    }
+#endif
+
+    struct android_native_base_t common;
+
+    int width;
+    int height;
+    int stride;
+    int format;
+    int usage;
+    uintptr_t layerCount;
+
+    void* reserved[1];
+
+    const native_handle_t* handle;
+
+    void* reserved_proc[8];
+} ANativeWindowBuffer_t;
+
+typedef struct ANativeWindowBuffer ANativeWindowBuffer;
+
+/*****************************************************************************/
+
+
+/*
+ * Stores a value into one of the 4 available slots
+ * Retrieve the value with ANativeWindow_OemStorageGet()
+ *
+ * slot: 0 to 3
+ *
+ * Returns 0 on success or -errno on error.
+ */
+int ANativeWindow_OemStorageSet(ANativeWindow* window, uint32_t slot, intptr_t value);
+
+
+/*
+ * Retrieves a value from one of the 4 available slots
+ * By default the returned value is 0 if it wasn't set by ANativeWindow_OemStorageSet()
+ *
+ * slot: 0 to 3
+ *
+ * Returns 0 on success or -errno on error.
+ */
+int ANativeWindow_OemStorageGet(ANativeWindow* window, uint32_t slot, intptr_t* value);
+
+
+/*
+ * Set the swap interval for this surface.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+int ANativeWindow_setSwapInterval(ANativeWindow* window, int interval);
+
+
+/*
+ * queries that can be used with ANativeWindow_query() and ANativeWindow_queryf()
+ */
+enum ANativeWindowQuery {
+    /* The minimum number of buffers that must remain un-dequeued after a buffer
+     * has been queued.  This value applies only if set_buffer_count was used to
+     * override the number of buffers and if a buffer has since been queued.
+     * Users of the set_buffer_count ANativeWindow method should query this
+     * value before calling set_buffer_count.  If it is necessary to have N
+     * buffers simultaneously dequeued as part of the steady-state operation,
+     * and this query returns M then N+M buffers should be requested via
+     * native_window_set_buffer_count.
+     *
+     * Note that this value does NOT apply until a single buffer has been
+     * queued.  In particular this means that it is possible to:
+     *
+     * 1. Query M = min undequeued buffers
+     * 2. Set the buffer count to N + M
+     * 3. Dequeue all N + M buffers
+     * 4. Cancel M buffers
+     * 5. Queue, dequeue, queue, dequeue, ad infinitum
+     */
+    ANATIVEWINDOW_QUERY_MIN_UNDEQUEUED_BUFFERS = 3,
+
+    /*
+     * Default width of ANativeWindow buffers, these are the
+     * dimensions of the window buffers irrespective of the
+     * ANativeWindow_setBuffersDimensions() call and match the native window
+     * size.
+     */
+    ANATIVEWINDOW_QUERY_DEFAULT_WIDTH = 6,
+    ANATIVEWINDOW_QUERY_DEFAULT_HEIGHT = 7,
+
+    /*
+     * transformation that will most-likely be applied to buffers. This is only
+     * a hint, the actual transformation applied might be different.
+     *
+     * INTENDED USE:
+     *
+     * The transform hint can be used by a producer, for instance the GLES
+     * driver, to pre-rotate the rendering such that the final transformation
+     * in the composer is identity. This can be very useful when used in
+     * conjunction with the h/w composer HAL, in situations where it
+     * cannot handle arbitrary rotations.
+     *
+     * 1. Before dequeuing a buffer, the GL driver (or any other ANW client)
+     *    queries the ANW for NATIVE_WINDOW_TRANSFORM_HINT.
+     *
+     * 2. The GL driver overrides the width and height of the ANW to
+     *    account for NATIVE_WINDOW_TRANSFORM_HINT. This is done by querying
+     *    NATIVE_WINDOW_DEFAULT_{WIDTH | HEIGHT}, swapping the dimensions
+     *    according to NATIVE_WINDOW_TRANSFORM_HINT and calling
+     *    native_window_set_buffers_dimensions().
+     *
+     * 3. The GL driver dequeues a buffer of the new pre-rotated size.
+     *
+     * 4. The GL driver renders to the buffer such that the image is
+     *    already transformed, that is applying NATIVE_WINDOW_TRANSFORM_HINT
+     *    to the rendering.
+     *
+     * 5. The GL driver calls native_window_set_transform to apply
+     *    inverse transformation to the buffer it just rendered.
+     *    In order to do this, the GL driver needs
+     *    to calculate the inverse of NATIVE_WINDOW_TRANSFORM_HINT, this is
+     *    done easily:
+     *
+     *        int hintTransform, inverseTransform;
+     *        query(..., NATIVE_WINDOW_TRANSFORM_HINT, &hintTransform);
+     *        inverseTransform = hintTransform;
+     *        if (hintTransform & HAL_TRANSFORM_ROT_90)
+     *            inverseTransform ^= HAL_TRANSFORM_ROT_180;
+     *
+     *
+     * 6. The GL driver queues the pre-transformed buffer.
+     *
+     * 7. The composer combines the buffer transform with the display
+     *    transform.  If the buffer transform happens to cancel out the
+     *    display transform then no rotation is needed.
+     *
+     */
+    ANATIVEWINDOW_QUERY_TRANSFORM_HINT = 8,
+
+    /*
+     * Returns the age of the contents of the most recently dequeued buffer as
+     * the number of frames that have elapsed since it was last queued. For
+     * example, if the window is double-buffered, the age of any given buffer in
+     * steady state will be 2. If the dequeued buffer has never been queued, its
+     * age will be 0.
+     */
+    ANATIVEWINDOW_QUERY_BUFFER_AGE = 13,
+
+    /* min swap interval supported by this compositor */
+    ANATIVEWINDOW_QUERY_MIN_SWAP_INTERVAL = 0x10000,
+
+    /* max swap interval supported by this compositor */
+    ANATIVEWINDOW_QUERY_MAX_SWAP_INTERVAL = 0x10001,
+
+    /* horizontal resolution in DPI. value is float, use queryf() */
+    ANATIVEWINDOW_QUERY_XDPI = 0x10002,
+
+    /* vertical resolution in DPI. value is float, use queryf() */
+    ANATIVEWINDOW_QUERY_YDPI = 0x10003,
+};
+
+/*
+ * hook used to retrieve information about the native window.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+int ANativeWindow_query(const ANativeWindow* window, ANativeWindowQuery query, int* value);
+int ANativeWindow_queryf(const ANativeWindow* window, ANativeWindowQuery query, float* value);
+
+
+/*
+ * Hook called by EGL to acquire a buffer. This call may block if no
+ * buffers are available.
+ *
+ * The window holds a reference to the buffer between dequeueBuffer and
+ * either queueBuffer or cancelBuffer, so clients only need their own
+ * reference if they might use the buffer after queueing or canceling it.
+ * Holding a reference to a buffer after queueing or canceling it is only
+ * allowed if a specific buffer count has been set.
+ *
+ * The libsync fence file descriptor returned in the int pointed to by the
+ * fenceFd argument will refer to the fence that must signal before the
+ * dequeued buffer may be written to.  A value of -1 indicates that the
+ * caller may access the buffer immediately without waiting on a fence.  If
+ * a valid file descriptor is returned (i.e. any value except -1) then the
+ * caller is responsible for closing the file descriptor.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+int ANativeWindow_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd);
+
+
+/*
+ * Hook called by EGL when modifications to the render buffer are done.
+ * This unlocks and post the buffer.
+ *
+ * The window holds a reference to the buffer between dequeueBuffer and
+ * either queueBuffer or cancelBuffer, so clients only need their own
+ * reference if they might use the buffer after queueing or canceling it.
+ * Holding a reference to a buffer after queueing or canceling it is only
+ * allowed if a specific buffer count has been set.
+ *
+ * The fenceFd argument specifies a libsync fence file descriptor for a
+ * fence that must signal before the buffer can be accessed.  If the buffer
+ * can be accessed immediately then a value of -1 should be used.  The
+ * caller must not use the file descriptor after it is passed to
+ * queueBuffer, and the ANativeWindow implementation is responsible for
+ * closing it.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+int ANativeWindow_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
+
+
+/*
+ * Hook used to cancel a buffer that has been dequeued.
+ * No synchronization is performed between dequeue() and cancel(), so
+ * either external synchronization is needed, or these functions must be
+ * called from the same thread.
+ *
+ * The window holds a reference to the buffer between dequeueBuffer and
+ * either queueBuffer or cancelBuffer, so clients only need their own
+ * reference if they might use the buffer after queueing or canceling it.
+ * Holding a reference to a buffer after queueing or canceling it is only
+ * allowed if a specific buffer count has been set.
+ *
+ * The fenceFd argument specifies a libsync fence file decsriptor for a
+ * fence that must signal before the buffer can be accessed.  If the buffer
+ * can be accessed immediately then a value of -1 should be used.
+ *
+ * Note that if the client has not waited on the fence that was returned
+ * from dequeueBuffer, that same fence should be passed to cancelBuffer to
+ * ensure that future uses of the buffer are preceded by a wait on that
+ * fence.  The caller must not use the file descriptor after it is passed
+ * to cancelBuffer, and the ANativeWindow implementation is responsible for
+ * closing it.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+int ANativeWindow_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
+
+/*
+ *  Sets the intended usage flags for the next buffers.
+ *
+ *  usage: one of AHARDWAREBUFFER_USAGE0_* constant
+ *  privateUsage: one of AHARDWAREBUFFER_USAGE1_*_PRIVATE_* constant
+ *
+ *  By default (if this function is never called), a usage of
+ *      AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE0_GPU_COLOR_OUTPUT
+ *  is assumed.
+ *
+ *  Calling this function will usually cause following buffers to be
+ *  reallocated.
+ */
+int ANativeWindow_setUsage(ANativeWindow* window, uint64_t usage0, uint64_t usage1);
+
+
+/*
+ * Sets the number of buffers associated with this native window.
+ */
+int ANativeWindow_setBufferCount(ANativeWindow* window, size_t bufferCount);
+
+
+/*
+ * All buffers dequeued after this call will have the dimensions specified.
+ * In particular, all buffers will have a fixed-size, independent from the
+ * native-window size. They will be scaled according to the scaling mode
+ * (see native_window_set_scaling_mode) upon window composition.
+ *
+ * If w and h are 0, the normal behavior is restored. That is, dequeued buffers
+ * following this call will be sized to match the window's size.
+ *
+ * Calling this function will reset the window crop to a NULL value, which
+ * disables cropping of the buffers.
+ */
+int ANativeWindow_setBuffersDimensions(ANativeWindow* window, uint32_t w, uint32_t h);
+
+
+/*
+ * All buffers dequeued after this call will have the format specified.
+ * format: one of AHARDWAREBUFFER_FORMAT_* constant
+ *
+ * If the specified format is 0, the default buffer format will be used.
+ */
+int ANativeWindow_setBuffersFormat(ANativeWindow* window, int format);
+
+
+/*
+ * All buffers queued after this call will be associated with the timestamp in nanosecond
+ * parameter specified. If the timestamp is set to NATIVE_WINDOW_TIMESTAMP_AUTO
+ * (the default), timestamps will be generated automatically when queueBuffer is
+ * called. The timestamp is measured in nanoseconds, and is normally monotonically
+ * increasing. The timestamp should be unaffected by time-of-day adjustments,
+ * and for a camera should be strictly monotonic but for a media player may be
+ * reset when the position is set.
+ */
+int ANativeWindow_setBuffersTimestamp(ANativeWindow* window, int64_t timestamp);
+
+
+/*
+ * All buffers queued after this call will be associated with the dataSpace
+ * parameter specified.
+ *
+ * dataSpace specifies additional information about the buffer that's dependent
+ * on the buffer format and the endpoints. For example, it can be used to convey
+ * the color space of the image data in the buffer, or it can be used to
+ * indicate that the buffers contain depth measurement data instead of color
+ * images.  The default dataSpace is 0, HAL_DATASPACE_UNKNOWN, unless it has been
+ * overridden by the consumer.
+ */
+int ANativeWindow_setBufferDataSpace(ANativeWindow* window, android_dataspace_t dataSpace);
+
+
+/*
+ * Enable/disable shared buffer mode
+ */
+int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMode);
+
+
+/*
+ * Enable/disable auto refresh when in shared buffer mode
+ */
+int ANativeWindow_setAutoRefresh(ANativeWindow* window, bool autoRefresh);
+
+
+/*****************************************************************************/
+
+__END_DECLS
+
+#endif /* ANDROID_VNDK_NATIVEWINDOW_ANATIVEWINDOW_H */
diff --git a/libs/ui/ColorSpace.cpp b/libs/ui/ColorSpace.cpp
index 49390d9..5b4bf23 100644
--- a/libs/ui/ColorSpace.cpp
+++ b/libs/ui/ColorSpace.cpp
@@ -20,6 +20,83 @@
 
 namespace android {
 
+static constexpr float linearResponse(float v) {
+    return v;
+}
+
+static constexpr float rcpResponse(float x, const ColorSpace::TransferParameters& p) {
+    return x >= p.d * p.c ? (std::pow(x, 1.0f / p.g) - p.b) / p.a : x / p.c;
+}
+
+static constexpr float response(float x, const ColorSpace::TransferParameters& p) {
+    return x >= p.d ? std::pow(p.a * x + p.b, p.g) : p.c * x;
+}
+
+static constexpr float rcpFullResponse(float x, const ColorSpace::TransferParameters& p) {
+    return x >= p.d * p.c ? (std::pow(x - p.e, 1.0f / p.g) - p.b) / p.a : (x - p.f) / p.c;
+}
+
+static constexpr float fullResponse(float x, const ColorSpace::TransferParameters& p) {
+    return x >= p.d ? std::pow(p.a * x + p.b, p.g) + p.e : p.c * x + p.f;
+}
+
+static float absRcpResponse(float x, float g,float a, float b, float c, float d) {
+    float xx = std::abs(x);
+    return std::copysign(xx >= d * c ? (std::pow(xx, 1.0f / g) - b) / a : xx / c, x);
+}
+
+static float absResponse(float x, float g, float a, float b, float c, float d) {
+   float xx = std::abs(x);
+   return std::copysign(xx >= d ? std::pow(a * xx + b, g) : c * xx, x);
+}
+
+static float safePow(float x, float e) {
+    return powf(x < 0.0f ? 0.0f : x, e);
+}
+
+static ColorSpace::transfer_function toOETF(const ColorSpace::TransferParameters& parameters) {
+    if (parameters.e == 0.0f && parameters.f == 0.0f) {
+        return std::bind(rcpResponse, _1, parameters);
+    }
+    return std::bind(rcpFullResponse, _1, parameters);
+}
+
+static ColorSpace::transfer_function toEOTF( const ColorSpace::TransferParameters& parameters) {
+    if (parameters.e == 0.0f && parameters.f == 0.0f) {
+        return std::bind(response, _1, parameters);
+    }
+    return std::bind(fullResponse, _1, parameters);
+}
+
+static ColorSpace::transfer_function toOETF(float gamma) {
+    if (gamma == 1.0f) {
+        return linearResponse;
+    }
+    return std::bind(safePow, _1, 1.0f / gamma);
+}
+
+static ColorSpace::transfer_function toEOTF(float gamma) {
+    if (gamma == 1.0f) {
+        return linearResponse;
+    }
+    return std::bind(safePow, _1, gamma);
+}
+
+static constexpr std::array<float2, 3> computePrimaries(const mat3& rgbToXYZ) {
+    float3 r(rgbToXYZ * float3{1, 0, 0});
+    float3 g(rgbToXYZ * float3{0, 1, 0});
+    float3 b(rgbToXYZ * float3{0, 0, 1});
+
+    return {{r.xy / dot(r, float3{1}),
+             g.xy / dot(g, float3{1}),
+             b.xy / dot(b, float3{1})}};
+}
+
+static constexpr float2 computeWhitePoint(const mat3& rgbToXYZ) {
+    float3 w(rgbToXYZ * float3{1});
+    return w.xy / dot(w, float3{1});
+}
+
 ColorSpace::ColorSpace(
         const std::string& name,
         const mat3& rgbToXYZ,
@@ -31,18 +108,41 @@
         , mXYZtoRGB(inverse(rgbToXYZ))
         , mOETF(std::move(OETF))
         , mEOTF(std::move(EOTF))
-        , mClamper(std::move(clamper)) {
+        , mClamper(std::move(clamper))
+        , mPrimaries(computePrimaries(rgbToXYZ))
+        , mWhitePoint(computeWhitePoint(rgbToXYZ)) {
+}
 
-    float3 r(rgbToXYZ * float3{1, 0, 0});
-    float3 g(rgbToXYZ * float3{0, 1, 0});
-    float3 b(rgbToXYZ * float3{0, 0, 1});
+ColorSpace::ColorSpace(
+        const std::string& name,
+        const mat3& rgbToXYZ,
+        const TransferParameters parameters,
+        clamping_function clamper) noexcept
+        : mName(name)
+        , mRGBtoXYZ(rgbToXYZ)
+        , mXYZtoRGB(inverse(rgbToXYZ))
+        , mParameters(parameters)
+        , mOETF(toOETF(mParameters))
+        , mEOTF(toEOTF(mParameters))
+        , mClamper(std::move(clamper))
+        , mPrimaries(computePrimaries(rgbToXYZ))
+        , mWhitePoint(computeWhitePoint(rgbToXYZ)) {
+}
 
-    mPrimaries[0] = r.xy / dot(r, float3{1});
-    mPrimaries[1] = g.xy / dot(g, float3{1});
-    mPrimaries[2] = b.xy / dot(b, float3{1});
-
-    float3 w(rgbToXYZ * float3{1});
-    mWhitePoint = w.xy / dot(w, float3{1});
+ColorSpace::ColorSpace(
+        const std::string& name,
+        const mat3& rgbToXYZ,
+        float gamma,
+        clamping_function clamper) noexcept
+        : mName(name)
+        , mRGBtoXYZ(rgbToXYZ)
+        , mXYZtoRGB(inverse(rgbToXYZ))
+        , mParameters({gamma, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f})
+        , mOETF(toOETF(gamma))
+        , mEOTF(toEOTF(gamma))
+        , mClamper(std::move(clamper))
+        , mPrimaries(computePrimaries(rgbToXYZ))
+        , mWhitePoint(computeWhitePoint(rgbToXYZ)) {
 }
 
 ColorSpace::ColorSpace(
@@ -62,6 +162,40 @@
         , mWhitePoint(whitePoint) {
 }
 
+ColorSpace::ColorSpace(
+        const std::string& name,
+        const std::array<float2, 3>& primaries,
+        const float2& whitePoint,
+        const TransferParameters parameters,
+        clamping_function clamper) noexcept
+        : mName(name)
+        , mRGBtoXYZ(computeXYZMatrix(primaries, whitePoint))
+        , mXYZtoRGB(inverse(mRGBtoXYZ))
+        , mParameters(parameters)
+        , mOETF(toOETF(mParameters))
+        , mEOTF(toEOTF(mParameters))
+        , mClamper(std::move(clamper))
+        , mPrimaries(primaries)
+        , mWhitePoint(whitePoint) {
+}
+
+ColorSpace::ColorSpace(
+        const std::string& name,
+        const std::array<float2, 3>& primaries,
+        const float2& whitePoint,
+        float gamma,
+        clamping_function clamper) noexcept
+        : mName(name)
+        , mRGBtoXYZ(computeXYZMatrix(primaries, whitePoint))
+        , mXYZtoRGB(inverse(mRGBtoXYZ))
+        , mParameters({gamma, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f})
+        , mOETF(toOETF(gamma))
+        , mEOTF(toEOTF(gamma))
+        , mClamper(std::move(clamper))
+        , mPrimaries(primaries)
+        , mWhitePoint(whitePoint) {
+}
+
 constexpr mat3 ColorSpace::computeXYZMatrix(
         const std::array<float2, 3>& primaries, const float2& whitePoint) {
     const float2& R = primaries[0];
@@ -96,33 +230,12 @@
     };
 }
 
-static constexpr float rcpResponse(float x, float g,float a, float b, float c, float d) {
-    return x >= d * c ? (std::pow(x, 1.0f / g) - b) / a : x / c;
-}
-
-static constexpr float response(float x, float g, float a, float b, float c, float d) {
-    return x >= d ? std::pow(a * x + b, g) : c * x;
-}
-
-static float absRcpResponse(float x, float g,float a, float b, float c, float d) {
-    return std::copysign(rcpResponse(std::abs(x), g, a, b, c, d), x);
-}
-
-static float absResponse(float x, float g, float a, float b, float c, float d) {
-    return std::copysign(response(std::abs(x), g, a, b, c, d), x);
-}
-
-static float safePow(float x, float e) {
-    return powf(x < 0.0f ? 0.0f : x, e);
-}
-
 const ColorSpace ColorSpace::sRGB() {
     return {
         "sRGB IEC61966-2.1",
         {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
         {0.3127f, 0.3290f},
-        std::bind(rcpResponse, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f),
-        std::bind(response,    _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f)
+        {2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f, 0.0f, 0.0f}
     };
 }
 
@@ -150,8 +263,7 @@
         "scRGB IEC 61966-2-2:2003",
         {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
         {0.3127f, 0.3290f},
-        linearReponse,
-        linearReponse,
+        1.0f,
         std::bind(clamp<float>, _1, -0.5f, 7.499f)
     };
 }
@@ -161,8 +273,7 @@
         "NTSC (1953)",
         {{float2{0.67f, 0.33f}, {0.21f, 0.71f}, {0.14f, 0.08f}}},
         {0.310f, 0.316f},
-        std::bind(rcpResponse, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f),
-        std::bind(response,    _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f)
+        {1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f, 0.0f, 0.0f}
     };
 }
 
@@ -171,8 +282,7 @@
         "Rec. ITU-R BT.709-5",
         {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
         {0.3127f, 0.3290f},
-        std::bind(rcpResponse, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f),
-        std::bind(response,    _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f)
+        {1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f, 0.0f, 0.0f}
     };
 }
 
@@ -181,8 +291,7 @@
         "Rec. ITU-R BT.2020-1",
         {{float2{0.708f, 0.292f}, {0.170f, 0.797f}, {0.131f, 0.046f}}},
         {0.3127f, 0.3290f},
-        std::bind(rcpResponse, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f),
-        std::bind(response,    _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f)
+        {1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f, 0.0f, 0.0f}
     };
 }
 
@@ -191,8 +300,7 @@
         "Adobe RGB (1998)",
         {{float2{0.64f, 0.33f}, {0.21f, 0.71f}, {0.15f, 0.06f}}},
         {0.3127f, 0.3290f},
-        std::bind(safePow, _1, 1.0f / 2.2f),
-        std::bind(safePow, _1, 2.2f)
+        2.2f
     };
 }
 
@@ -201,8 +309,7 @@
         "ROMM RGB ISO 22028-2:2013",
         {{float2{0.7347f, 0.2653f}, {0.1596f, 0.8404f}, {0.0366f, 0.0001f}}},
         {0.34567f, 0.35850f},
-        std::bind(rcpResponse, _1, 1.8f, 1.0f, 0.0f, 1 / 16.0f, 0.031248f),
-        std::bind(response,    _1, 1.8f, 1.0f, 0.0f, 1 / 16.0f, 0.031248f)
+        {1.8f, 1.0f, 0.0f, 1 / 16.0f, 0.031248f, 0.0f, 0.0f}
     };
 }
 
@@ -211,8 +318,7 @@
         "Display P3",
         {{float2{0.680f, 0.320f}, {0.265f, 0.690f}, {0.150f, 0.060f}}},
         {0.3127f, 0.3290f},
-        std::bind(rcpResponse, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.039f),
-        std::bind(response,    _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.039f)
+        {2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.039f, 0.0f, 0.0f}
     };
 }
 
@@ -221,8 +327,7 @@
         "SMPTE RP 431-2-2007 DCI (P3)",
         {{float2{0.680f, 0.320f}, {0.265f, 0.690f}, {0.150f, 0.060f}}},
         {0.314f, 0.351f},
-        std::bind(safePow, _1, 1.0f / 2.6f),
-        std::bind(safePow, _1, 2.6f)
+        2.6f
     };
 }
 
@@ -231,8 +336,7 @@
         "SMPTE ST 2065-1:2012 ACES",
         {{float2{0.73470f, 0.26530f}, {0.0f, 1.0f}, {0.00010f, -0.0770f}}},
         {0.32168f, 0.33767f},
-        linearReponse,
-        linearReponse,
+        1.0f,
         std::bind(clamp<float>, _1, -65504.0f, 65504.0f)
     };
 }
@@ -242,12 +346,33 @@
         "Academy S-2014-004 ACEScg",
         {{float2{0.713f, 0.293f}, {0.165f, 0.830f}, {0.128f, 0.044f}}},
         {0.32168f, 0.33767f},
-        linearReponse,
-        linearReponse,
+        1.0f,
         std::bind(clamp<float>, _1, -65504.0f, 65504.0f)
     };
 }
 
+std::unique_ptr<float3> ColorSpace::createLUT(uint32_t size,
+        const ColorSpace& src, const ColorSpace& dst) {
+
+    size = clamp(size, 2u, 256u);
+    float m = 1.0f / float(size - 1);
+
+    std::unique_ptr<float3> lut(new float3[size * size * size]);
+    float3* data = lut.get();
+
+    ColorSpaceConnector connector(src, dst);
+
+    for (uint32_t z = 0; z < size; z++) {
+        for (int32_t y = int32_t(size - 1); y >= 0; y--) {
+            for (uint32_t x = 0; x < size; x++) {
+                *data++ = connector.transform({x * m, y * m, z * m});
+            }
+        }
+    }
+
+    return lut;
+}
+
 static const float2 ILLUMINANT_D50_XY = {0.34567f, 0.35850f};
 static const float3 ILLUMINANT_D50_XYZ = {0.964212f, 1.0f, 0.825188f};
 static const mat3 BRADFORD = mat3{
@@ -262,7 +387,7 @@
     return inverse(matrix) * mat3{dstLMS / srcLMS} * matrix;
 }
 
-ColorSpace::Connector::Connector(
+ColorSpaceConnector::ColorSpaceConnector(
         const ColorSpace& src,
         const ColorSpace& dst) noexcept
         : mSource(src)
@@ -274,8 +399,8 @@
         mat3 rgbToXYZ(src.getRGBtoXYZ());
         mat3 xyzToRGB(dst.getXYZtoRGB());
 
-        float3 srcXYZ = XYZ(float3{src.getWhitePoint(), 1});
-        float3 dstXYZ = XYZ(float3{dst.getWhitePoint(), 1});
+        float3 srcXYZ = ColorSpace::XYZ(float3{src.getWhitePoint(), 1});
+        float3 dstXYZ = ColorSpace::XYZ(float3{dst.getWhitePoint(), 1});
 
         if (any(greaterThan(abs(src.getWhitePoint() - ILLUMINANT_D50_XY), float2{1e-3f}))) {
             rgbToXYZ = adaptation(BRADFORD, srcXYZ, ILLUMINANT_D50_XYZ) * src.getRGBtoXYZ();
@@ -289,27 +414,4 @@
     }
 }
 
-std::unique_ptr<float3> ColorSpace::createLUT(uint32_t size,
-        const ColorSpace& src, const ColorSpace& dst) {
-
-    size = clamp(size, 2u, 256u);
-    float m = 1.0f / float(size - 1);
-
-    std::unique_ptr<float3> lut(new float3[size * size * size]);
-    float3* data = lut.get();
-
-    Connector connector(src, dst);
-
-    for (uint32_t z = 0; z < size; z++) {
-        for (int32_t y = int32_t(size - 1); y >= 0; y--) {
-            for (uint32_t x = 0; x < size; x++) {
-                *data++ = connector.transform({x * m, y * m, z * m});
-            }
-        }
-    }
-
-    return lut;
-}
-
-
 }; // namespace android
diff --git a/libs/ui/tests/colorspace_test.cpp b/libs/ui/tests/colorspace_test.cpp
index 1e359d3..0a4873c 100644
--- a/libs/ui/tests/colorspace_test.cpp
+++ b/libs/ui/tests/colorspace_test.cpp
@@ -152,12 +152,12 @@
 
 TEST_F(ColorSpaceTest, Connect) {
     // No chromatic adaptation
-    auto r = ColorSpace::connect(ColorSpace::sRGB(), ColorSpace::AdobeRGB())
+    auto r = ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::AdobeRGB())
             .transform({1.0f, 0.5f, 0.0f});
     EXPECT_TRUE(all(lessThan(abs(r - float3{0.8912f, 0.4962f, 0.1164f}), float3{1e-4f})));
 
     // Test with chromatic adaptation
-    r = ColorSpace::connect(ColorSpace::sRGB(), ColorSpace::ProPhotoRGB())
+    r = ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::ProPhotoRGB())
             .transform({1.0f, 0.0f, 0.0f});
     EXPECT_TRUE(all(lessThan(abs(r - float3{0.70226f, 0.2757f, 0.1036f}), float3{1e-4f})));
 }
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index e068469..452bad0 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -15,7 +15,6 @@
 sourceFiles = [
     "buffer_hub_client.cpp",
     "buffer_hub_rpc.cpp",
-    "dvr_buffer.cpp",
     "ion_buffer.cpp",
 ]
 
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 1c8f2c0..2d96638 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -43,7 +43,7 @@
 cc_library {
     name: "libbufferhubqueue",
     cflags = [
-        "-DLOGTAG=\"libbufferhubqueue\"",
+        "-DLOG_TAG=\"libbufferhubqueue\"",
         "-DTRACE=0",
     ],
     srcs: sourceFiles,
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index feaf3d7..f786356 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -329,6 +329,9 @@
     return Dequeue(timeout, slot, meta, sizeof(*meta), acquire_fence);
   }
 
+  std::shared_ptr<BufferConsumer> Dequeue(int timeout, size_t* slot, void* meta,
+                                          size_t meta_size,
+                                          LocalHandle* acquire_fence);
  private:
   friend BASE;
 
@@ -344,13 +347,27 @@
                     LocalHandle* acquire_fence) override;
 
   int OnBufferAllocated() override;
-
-  std::shared_ptr<BufferConsumer> Dequeue(int timeout, size_t* slot, void* meta,
-                                          size_t meta_size,
-                                          LocalHandle* acquire_fence);
 };
 
 }  // namespace dvr
 }  // namespace android
 
+// Concrete C type definition for DVR API.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct DvrWriteBufferQueue {
+  std::shared_ptr<android::dvr::ProducerQueue> producer_queue_;
+};
+
+struct DvrReadBufferQueue {
+  std::shared_ptr<android::dvr::ConsumerQueue> consumer_queue_;
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
 #endif  // ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_
diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp
index b8a0da3..865573c 100644
--- a/libs/vr/libbufferhubqueue/tests/Android.bp
+++ b/libs/vr/libbufferhubqueue/tests/Android.bp
@@ -24,6 +24,7 @@
     static_libs: static_libraries,
     shared_libs: shared_libraries,
     cflags: [
+        "-DLOG_TAG=\"buffer_hub_queue-test\"",
         "-DTRACE=0",
         "-O0",
         "-g",
@@ -37,6 +38,7 @@
     static_libs: static_libraries,
     shared_libs: shared_libraries,
     cflags: [
+        "-DLOG_TAG=\"buffer_hub_queue_producer-test\"",
         "-DTRACE=0",
         "-O0",
         "-g",
diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp
index f3c71b5..de2a56e 100644
--- a/libs/vr/libdisplay/Android.bp
+++ b/libs/vr/libdisplay/Android.bp
@@ -15,7 +15,6 @@
 sourceFiles = [
     "native_buffer_queue.cpp",
     "display_client.cpp",
-    "display_manager_client.cpp",
     "display_manager_client_impl.cpp",
     "display_rpc.cpp",
     "dummy_native_window.cpp",
@@ -24,7 +23,6 @@
     "late_latch.cpp",
     "video_mesh_surface_client.cpp",
     "vsync_client.cpp",
-    "vsync_client_api.cpp",
     "screenshot_client.cpp",
     "frame_history.cpp",
 ]
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
index 50d95f7..9952e59 100644
--- a/libs/vr/libdisplay/display_client.cpp
+++ b/libs/vr/libdisplay/display_client.cpp
@@ -265,6 +265,12 @@
   return BufferConsumer::Import(std::move(status));
 }
 
+bool DisplayClient::IsVrAppRunning() {
+  auto status = InvokeRemoteMethod<DisplayRPC::IsVrAppRunning>();
+  if (!status)
+    return 0;
+  return static_cast<bool>(status.get());
+}
 
 }  // namespace dvr
 }  // namespace android
diff --git a/libs/vr/libdisplay/graphics.cpp b/libs/vr/libdisplay/graphics.cpp
index 3713389..2abdf8e 100644
--- a/libs/vr/libdisplay/graphics.cpp
+++ b/libs/vr/libdisplay/graphics.cpp
@@ -17,7 +17,6 @@
 #include <private/dvr/clock_ns.h>
 #include <private/dvr/debug.h>
 #include <private/dvr/display_types.h>
-#include <private/dvr/dvr_buffer.h>
 #include <private/dvr/frame_history.h>
 #include <private/dvr/gl_fenced_flush.h>
 #include <private/dvr/graphics/vr_gl_extensions.h>
@@ -1575,14 +1574,3 @@
     };
   }
 }
-
-extern "C" int dvrGetPoseBuffer(DvrReadBuffer** pose_buffer) {
-  auto client = android::dvr::DisplayClient::Create();
-  if (!client) {
-    ALOGE("Failed to create display client!");
-    return -ECOMM;
-  }
-
-  *pose_buffer = CreateDvrReadBufferFromBufferConsumer(client->GetPoseBuffer());
-  return 0;
-}
diff --git a/libs/vr/libdisplay/include/dvr/graphics.h b/libs/vr/libdisplay/include/dvr/graphics.h
index fc51d52..ac8b27f 100644
--- a/libs/vr/libdisplay/include/dvr/graphics.h
+++ b/libs/vr/libdisplay/include/dvr/graphics.h
@@ -442,9 +442,6 @@
                                         const int eye,
                                         const float* transform);
 
-// Get a pointer to the global pose buffer.
-int dvrGetPoseBuffer(DvrReadBuffer** pose_buffer);
-
 __END_DECLS
 
 #endif  // DVR_GRAPHICS_H_
diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h
index f579a8c..378f67c 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_client.h
@@ -110,6 +110,9 @@
 
   std::unique_ptr<BufferConsumer> GetPoseBuffer();
 
+  // Temporary query for current VR status. Will be removed later.
+  bool IsVrAppRunning();
+
  private:
   friend BASE;
 
diff --git a/libs/vr/libdisplay/include/private/dvr/display_rpc.h b/libs/vr/libdisplay/include/private/dvr/display_rpc.h
index 7a2986a..ac08650 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_rpc.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_rpc.h
@@ -219,6 +219,7 @@
     kOpVideoMeshSurfaceCreateProducerQueue,
     kOpSetViewerParams,
     kOpGetPoseBuffer,
+    kOpIsVrAppRunning,
   };
 
   // Aliases.
@@ -248,6 +249,7 @@
                     void(const ViewerParams& viewer_params));
   PDX_REMOTE_METHOD(GetPoseBuffer, kOpGetPoseBuffer,
                     LocalChannelHandle(Void));
+  PDX_REMOTE_METHOD(IsVrAppRunning, kOpIsVrAppRunning, int(Void));
 };
 
 struct DisplayManagerRPC {
diff --git a/libs/vr/libdisplay/include/private/dvr/vsync_client.h b/libs/vr/libdisplay/include/private/dvr/vsync_client.h
index 32fa40f..1eeb80e 100644
--- a/libs/vr/libdisplay/include/private/dvr/vsync_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/vsync_client.h
@@ -4,7 +4,6 @@
 #include <stdint.h>
 
 #include <pdx/client.h>
-#include <private/dvr/vsync_client_api.h>
 
 struct dvr_vsync_client {};
 
diff --git a/libs/vr/libdvr/Android.mk b/libs/vr/libdvr/Android.mk
new file mode 100644
index 0000000..5449cb5
--- /dev/null
+++ b/libs/vr/libdvr/Android.mk
@@ -0,0 +1,54 @@
+# 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.
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libdvr
+LOCAL_MODULE_OWNER := google
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+LOCAL_CFLAGS += \
+    -fvisibility=hidden \
+    -D DVR_EXPORT='__attribute__ ((visibility ("default")))'
+
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/include \
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+    $(LOCAL_PATH)/include \
+
+LOCAL_SRC_FILES := \
+    display_manager_client.cpp \
+    dvr_api.cpp \
+    dvr_buffer.cpp \
+    dvr_buffer_queue.cpp \
+    dvr_surface.cpp \
+    vsync_client_api.cpp \
+
+LOCAL_STATIC_LIBRARIES := \
+    libbufferhub \
+    libbufferhubqueue \
+    libdisplay \
+    libvrsensor \
+    libvirtualtouchpadclient \
+
+LOCAL_SHARED_LIBRARIES := \
+    android.hardware.graphics.bufferqueue@1.0 \
+    android.hidl.token@1.0-utils \
+    libandroid_runtime \
+    libbase \
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libs/vr/libdisplay/display_manager_client.cpp b/libs/vr/libdvr/display_manager_client.cpp
similarity index 97%
rename from libs/vr/libdisplay/display_manager_client.cpp
rename to libs/vr/libdvr/display_manager_client.cpp
index d60d35b..7cbfc21 100644
--- a/libs/vr/libdisplay/display_manager_client.cpp
+++ b/libs/vr/libdvr/display_manager_client.cpp
@@ -1,8 +1,8 @@
-#include "include/private/dvr/display_manager_client.h"
+#include "include/dvr/display_manager_client.h"
 
+#include <dvr/dvr_buffer.h>
 #include <private/dvr/buffer_hub_client.h>
 #include <private/dvr/display_manager_client_impl.h>
-#include <private/dvr/dvr_buffer.h>
 
 using android::dvr::DisplaySurfaceAttributeEnum;
 
diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp
new file mode 100644
index 0000000..4dd49da
--- /dev/null
+++ b/libs/vr/libdvr/dvr_api.cpp
@@ -0,0 +1,106 @@
+#include "include/dvr/dvr_api.h"
+
+#include <errno.h>
+
+// Headers from libdvr
+#include <dvr/display_manager_client.h>
+#include <dvr/dvr_buffer.h>
+#include <dvr/dvr_buffer_queue.h>
+#include <dvr/dvr_surface.h>
+#include <dvr/vsync_client_api.h>
+
+// Headers not yet moved into libdvr.
+// TODO(jwcai) Move these once their callers are moved into Google3.
+#include <dvr/pose_client.h>
+#include <dvr/virtual_touchpad_client.h>
+
+extern "C" {
+
+DVR_EXPORT int dvrGetApi(void* api, size_t struct_size, int version) {
+  if (version == 1) {
+    if (struct_size != sizeof(DvrApi_v1)) {
+      return -EINVAL;
+    }
+    DvrApi_v1* dvr_api = static_cast<DvrApi_v1*>(api);
+
+    // display_manager_client.h
+    dvr_api->display_manager_client_create_ = dvrDisplayManagerClientCreate;
+    dvr_api->display_manager_client_destroy_ = dvrDisplayManagerClientDestroy;
+    dvr_api->display_manager_client_get_surface_list_ =
+        dvrDisplayManagerClientGetSurfaceList;
+    dvr_api->display_manager_client_surface_list_destroy_ =
+        dvrDisplayManagerClientSurfaceListDestroy;
+    dvr_api->display_manager_setup_pose_buffer_ =
+        dvrDisplayManagerSetupPoseBuffer;
+    dvr_api->display_manager_client_surface_list_get_size_ =
+        dvrDisplayManagerClientSurfaceListGetSize;
+    dvr_api->display_manager_client_surface_list_get_surface_id_ =
+        dvrDisplayManagerClientSurfaceListGetSurfaceId;
+    dvr_api->display_manager_client_get_surface_buffer_list_ =
+        dvrDisplayManagerClientGetSurfaceBuffers;
+    dvr_api->display_manager_client_surface_buffer_list_destroy_ =
+        dvrDisplayManagerClientSurfaceBuffersDestroy;
+    dvr_api->display_manager_client_surface_buffer_list_get_size_ =
+        dvrDisplayManagerClientSurfaceBuffersGetSize;
+    dvr_api->display_manager_client_surface_buffer_list_get_fd_ =
+        dvrDisplayManagerClientSurfaceBuffersGetFd;
+
+    // dvr_buffer.h
+    dvr_api->write_buffer_destroy_ = dvrWriteBufferDestroy;
+    dvr_api->write_buffer_get_blob_fds_ = dvrWriteBufferGetBlobFds;
+    dvr_api->write_buffer_get_AHardwareBuffer_ =
+        dvrWriteBufferGetAHardwareBuffer;
+    dvr_api->write_buffer_post_ = dvrWriteBufferPost;
+    dvr_api->write_buffer_gain_ = dvrWriteBufferGain;
+    dvr_api->write_buffer_gain_async_ = dvrWriteBufferGainAsync;
+
+    dvr_api->read_buffer_destroy_ = dvrReadBufferDestroy;
+    dvr_api->read_buffer_get_blob_fds_ = dvrReadBufferGetBlobFds;
+    dvr_api->read_buffer_get_AHardwareBuffer_ = dvrReadBufferGetAHardwareBuffer;
+    dvr_api->read_buffer_acquire_ = dvrReadBufferAcquire;
+    dvr_api->read_buffer_release_ = dvrReadBufferRelease;
+    dvr_api->read_buffer_release_async_ = dvrReadBufferReleaseAsync;
+
+    // dvr_buffer_queue.h
+    dvr_api->write_buffer_queue_destroy_ = dvrWriteBufferQueueDestroy;
+    dvr_api->write_buffer_queue_get_capacity_ = dvrWriteBufferQueueGetCapacity;
+    dvr_api->write_buffer_queue_get_external_surface_ =
+        dvrWriteBufferQueueGetExternalSurface;
+    dvr_api->write_buffer_queue_create_read_queue_ =
+        dvrWriteBufferQueueCreateReadQueue;
+    dvr_api->write_buffer_queue_dequeue_ = dvrWriteBufferQueueDequeue;
+    dvr_api->read_buffer_queue_destroy_ = dvrReadBufferQueueDestroy;
+    dvr_api->read_buffer_queue_get_capacity_ = dvrReadBufferQueueGetCapacity;
+    dvr_api->read_buffer_queue_create_read_queue_ =
+        dvrReadBufferQueueCreateReadQueue;
+    dvr_api->read_buffer_queue_dequeue = dvrReadBufferQueueDequeue;
+
+    // dvr_surface.h
+    dvr_api->get_pose_buffer_ = dvrGetPoseBuffer;
+
+    // vsync_client_api.h
+    dvr_api->vsync_client_create_ = dvr_vsync_client_create;
+    dvr_api->vsync_client_destroy_ = dvr_vsync_client_destroy;
+    dvr_api->vsync_client_get_sched_info_ = dvr_vsync_client_get_sched_info;
+
+    // pose_client.h
+    dvr_api->pose_client_create_ = dvrPoseCreate;
+    dvr_api->pose_client_destroy_ = dvrPoseDestroy;
+    dvr_api->pose_get_ = dvrPoseGet;
+    dvr_api->pose_get_vsync_count_ = dvrPoseGetVsyncCount;
+    dvr_api->pose_get_controller_ = dvrPoseGetController;
+
+    // virtual_touchpad_client.h
+    dvr_api->virtual_touchpad_create_ = dvrVirtualTouchpadCreate;
+    dvr_api->virtual_touchpad_destroy_ = dvrVirtualTouchpadDestroy;
+    dvr_api->virtual_touchpad_attach_ = dvrVirtualTouchpadAttach;
+    dvr_api->virtual_touchpad_detach_ = dvrVirtualTouchpadDetach;
+    dvr_api->virtual_touchpad_touch_ = dvrVirtualTouchpadTouch;
+    dvr_api->virtual_touchpad_button_state_ = dvrVirtualTouchpadButtonState;
+
+    return 0;
+  }
+  return -EINVAL;
+}
+
+}  // extern "C"
diff --git a/libs/vr/libbufferhub/dvr_buffer.cpp b/libs/vr/libdvr/dvr_buffer.cpp
similarity index 91%
rename from libs/vr/libbufferhub/dvr_buffer.cpp
rename to libs/vr/libdvr/dvr_buffer.cpp
index 3eb611f..25128a6 100644
--- a/libs/vr/libbufferhub/dvr_buffer.cpp
+++ b/libs/vr/libdvr/dvr_buffer.cpp
@@ -1,16 +1,17 @@
+#include "include/dvr/dvr_buffer.h"
+
 #include <private/dvr/buffer_hub_client.h>
-#include <private/dvr/dvr_buffer.h>
 #include <ui/GraphicBuffer.h>
 
 using namespace android;
 
 struct DvrWriteBuffer {
-  std::unique_ptr<dvr::BufferProducer> write_buffer_;
+  std::shared_ptr<dvr::BufferProducer> write_buffer_;
   sp<GraphicBuffer> graphic_buffer_;
 };
 
 struct DvrReadBuffer {
-  std::unique_ptr<dvr::BufferConsumer> read_buffer_;
+  std::shared_ptr<dvr::BufferConsumer> read_buffer_;
   sp<GraphicBuffer> graphic_buffer_;
 };
 
@@ -18,14 +19,14 @@
 namespace dvr {
 
 DvrWriteBuffer* CreateDvrWriteBufferFromBufferProducer(
-    std::unique_ptr<dvr::BufferProducer> buffer_producer) {
+    const std::shared_ptr<dvr::BufferProducer>& buffer_producer) {
   DvrWriteBuffer* write_buffer = new DvrWriteBuffer;
   write_buffer->write_buffer_ = std::move(buffer_producer);
   return write_buffer;
 }
 
 DvrReadBuffer* CreateDvrReadBufferFromBufferConsumer(
-    std::unique_ptr<dvr::BufferConsumer> buffer_consumer) {
+    const std::shared_ptr<dvr::BufferConsumer>& buffer_consumer) {
   DvrReadBuffer* read_buffer = new DvrReadBuffer;
   read_buffer->read_buffer_ = std::move(buffer_consumer);
   return read_buffer;
@@ -85,6 +86,8 @@
   return client->write_buffer_->GainAsync();
 }
 
+void dvrReadBufferDestroy(DvrReadBuffer* client) { delete client; }
+
 void dvrReadBufferGetBlobFds(DvrReadBuffer* client, int* fds, size_t* fds_count,
                              size_t max_fds_count) {
   client->read_buffer_->GetBlobFds(fds, fds_count, max_fds_count);
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
new file mode 100644
index 0000000..b0b5a2a
--- /dev/null
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -0,0 +1,146 @@
+#include "include/dvr/dvr_buffer_queue.h"
+
+#include <gui/Surface.h>
+#include <private/dvr/buffer_hub_queue_client.h>
+#include <private/dvr/buffer_hub_queue_producer.h>
+
+#include <android_runtime/android_view_Surface.h>
+
+#define CHECK_PARAM(param)                                               \
+  LOG_ALWAYS_FATAL_IF(param == nullptr, "%s: " #param "cannot be NULL.", \
+                      __FUNCTION__)
+
+using namespace android;
+
+extern "C" {
+
+void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
+  delete write_queue;
+}
+
+size_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue) {
+  CHECK_PARAM(write_queue);
+  return write_queue->producer_queue_->capacity();
+}
+
+void* dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
+                                            JNIEnv* env) {
+  CHECK_PARAM(env);
+  CHECK_PARAM(write_queue);
+
+  std::shared_ptr<dvr::BufferHubQueueCore> core =
+      dvr::BufferHubQueueCore::Create(write_queue->producer_queue_);
+
+  return android_view_Surface_createFromIGraphicBufferProducer(
+      env, new dvr::BufferHubQueueProducer(core));
+}
+
+int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
+                                       DvrReadBufferQueue** out_read_queue) {
+  CHECK_PARAM(write_queue);
+  CHECK_PARAM(write_queue->producer_queue_);
+  CHECK_PARAM(out_read_queue);
+
+  auto read_queue = std::make_unique<DvrReadBufferQueue>();
+  read_queue->consumer_queue_ =
+      write_queue->producer_queue_->CreateConsumerQueue();
+  if (read_queue->consumer_queue_ == nullptr) {
+    ALOGE(
+        "dvrWriteBufferQueueCreateReadQueue: Failed to create consumer queue "
+        "from DvrWriteBufferQueue[%p].",
+        write_queue);
+    return -ENOMEM;
+  }
+
+  *out_read_queue = read_queue.release();
+  return 0;
+}
+
+int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
+                                  DvrWriteBuffer** out_buffer,
+                                  int* out_fence_fd) {
+  CHECK_PARAM(write_queue);
+  CHECK_PARAM(write_queue->producer_queue_);
+  CHECK_PARAM(out_buffer);
+  CHECK_PARAM(out_fence_fd);
+
+  size_t slot;
+  pdx::LocalHandle release_fence;
+  std::shared_ptr<dvr::BufferProducer> buffer =
+      write_queue->producer_queue_->Dequeue(timeout, &slot, &release_fence);
+  if (buffer == nullptr) {
+    ALOGE("dvrWriteBufferQueueDequeue: Failed to dequeue buffer.");
+    return -ENOMEM;
+  }
+
+  *out_buffer = CreateDvrWriteBufferFromBufferProducer(buffer);
+  *out_fence_fd = release_fence.Release();
+  return 0;
+}
+
+// ReadBufferQueue
+void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) {
+  delete read_queue;
+}
+
+size_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) {
+  CHECK_PARAM(read_queue);
+
+  return read_queue->consumer_queue_->capacity();
+}
+
+int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
+                                      DvrReadBufferQueue** out_read_queue) {
+  CHECK_PARAM(read_queue);
+  CHECK_PARAM(read_queue->consumer_queue_);
+  CHECK_PARAM(out_read_queue);
+
+  auto new_read_queue = std::make_unique<DvrReadBufferQueue>();
+  new_read_queue->consumer_queue_ =
+      read_queue->consumer_queue_->CreateConsumerQueue();
+  if (new_read_queue->consumer_queue_ == nullptr) {
+    ALOGE(
+        "dvrReadBufferQueueCreateReadQueue: Failed to create consumer queue "
+        "from DvrReadBufferQueue[%p].",
+        read_queue);
+    return -ENOMEM;
+  }
+
+  *out_read_queue = new_read_queue.release();
+  return 0;
+}
+
+int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
+                              DvrReadBuffer** out_buffer, int* out_fence_fd,
+                              void* out_meta, size_t meta_size_bytes) {
+  CHECK_PARAM(read_queue);
+  CHECK_PARAM(read_queue->consumer_queue_);
+  CHECK_PARAM(out_buffer);
+  CHECK_PARAM(out_fence_fd);
+  CHECK_PARAM(out_meta);
+
+  if (meta_size_bytes != read_queue->consumer_queue_->metadata_size()) {
+    ALOGE(
+        "dvrReadBufferQueueDequeue: Invalid metadata size, expected (%zu), "
+        "but actual (%zu).",
+        read_queue->consumer_queue_->metadata_size(), meta_size_bytes);
+    return -EINVAL;
+  }
+
+  size_t slot;
+  pdx::LocalHandle acquire_fence;
+  std::shared_ptr<dvr::BufferConsumer> buffer =
+      read_queue->consumer_queue_->Dequeue(timeout, &slot, out_meta,
+                                           meta_size_bytes, &acquire_fence);
+
+  if (buffer == nullptr) {
+    ALOGE("dvrReadBufferQueueGainBuffer: Failed to dequeue buffer.");
+    return -ENOMEM;
+  }
+
+  *out_buffer = CreateDvrReadBufferFromBufferConsumer(buffer);
+  *out_fence_fd = acquire_fence.Release();
+  return 0;
+}
+
+}  // extern "C"
diff --git a/libs/vr/libdvr/dvr_surface.cpp b/libs/vr/libdvr/dvr_surface.cpp
new file mode 100644
index 0000000..2abbe63
--- /dev/null
+++ b/libs/vr/libdvr/dvr_surface.cpp
@@ -0,0 +1,20 @@
+#include "include/dvr/dvr_surface.h"
+
+#include <private/dvr/display_client.h>
+
+using namespace android;
+
+extern "C" {
+
+int dvrGetPoseBuffer(DvrReadBuffer** pose_buffer) {
+  auto client = android::dvr::DisplayClient::Create();
+  if (!client) {
+    ALOGE("Failed to create display client!");
+    return -ECOMM;
+  }
+
+  *pose_buffer = CreateDvrReadBufferFromBufferConsumer(client->GetPoseBuffer());
+  return 0;
+}
+
+}  // extern "C"
diff --git a/libs/vr/libdvr/include/CPPLINT.cfg b/libs/vr/libdvr/include/CPPLINT.cfg
new file mode 100644
index 0000000..2f8a3c0
--- /dev/null
+++ b/libs/vr/libdvr/include/CPPLINT.cfg
@@ -0,0 +1 @@
+filter=-build/header_guard
diff --git a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h b/libs/vr/libdvr/include/dvr/display_manager_client.h
similarity index 100%
rename from libs/vr/libdisplay/include/private/dvr/display_manager_client.h
rename to libs/vr/libdvr/include/dvr/display_manager_client.h
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
new file mode 100644
index 0000000..6fd50ee
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -0,0 +1,220 @@
+#ifndef ANDROID_DVR_API_H_
+#define ANDROID_DVR_API_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct DvrPoseAsync DvrPoseAsync;
+
+typedef struct DvrDisplayManagerClient DvrDisplayManagerClient;
+typedef struct DvrDisplayManagerClientSurfaceList
+    DvrDisplayManagerClientSurfaceList;
+typedef struct DvrDisplayManagerClientSurfaceBuffers
+    DvrDisplayManagerClientSurfaceBuffers;
+typedef struct DvrPose DvrPose;
+typedef struct dvr_vsync_client dvr_vsync_client;
+typedef struct DvrVirtualTouchpad DvrVirtualTouchpad;
+
+typedef DvrDisplayManagerClient* (*DisplayManagerClientCreatePtr)(void);
+typedef void (*DisplayManagerClientDestroyPtr)(DvrDisplayManagerClient* client);
+
+typedef struct DvrWriteBuffer DvrWriteBuffer;
+typedef struct DvrReadBuffer DvrReadBuffer;
+typedef struct AHardwareBuffer AHardwareBuffer;
+
+typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
+typedef struct DvrReadBufferQueue DvrReadBufferQueue;
+
+// display_manager_client.h
+typedef int (*DisplayManagerClientGetSurfaceListPtr)(
+    DvrDisplayManagerClient* client,
+    DvrDisplayManagerClientSurfaceList** surface_list);
+typedef void (*DisplayManagerClientSurfaceListDestroyPtr)(
+    DvrDisplayManagerClientSurfaceList* surface_list);
+typedef DvrWriteBuffer* (*DisplayManagerSetupPoseBufferPtr)(
+    DvrDisplayManagerClient* client, size_t extended_region_size,
+    uint64_t usage0, uint64_t usage1);
+typedef size_t (*DisplayManagerClientSurfaceListGetSizePtr)(
+    DvrDisplayManagerClientSurfaceList* surface_list);
+typedef int (*DisplayManagerClientSurfaceListGetSurfaceIdPtr)(
+    DvrDisplayManagerClientSurfaceList* surface_list, size_t index);
+typedef int (*DisplayManagerClientGetSurfaceBufferListPtr)(
+    DvrDisplayManagerClient* client, int surface_id,
+    DvrDisplayManagerClientSurfaceBuffers** surface_buffers);
+typedef void (*DisplayManagerClientSurfaceBufferListDestroyPtr)(
+    DvrDisplayManagerClientSurfaceBuffers* surface_buffers);
+typedef size_t (*DisplayManagerClientSurfaceBufferListGetSizePtr)(
+    DvrDisplayManagerClientSurfaceBuffers* surface_buffers);
+typedef int (*DisplayManagerClientSurfaceBufferListGetFdPtr)(
+    DvrDisplayManagerClientSurfaceBuffers* surface_buffers, size_t index);
+
+// dvr_buffer.h
+typedef void (*DvrWriteBufferDestroyPtr)(DvrWriteBuffer* client);
+typedef void (*DvrWriteBufferGetBlobFdsPtr)(DvrWriteBuffer* client, int* fds,
+                                            size_t* fds_count,
+                                            size_t max_fds_count);
+typedef int (*DvrWriteBufferGetAHardwareBufferPtr)(
+    DvrWriteBuffer* client, AHardwareBuffer** hardware_buffer);
+typedef int (*DvrWriteBufferPostPtr)(DvrWriteBuffer* client, int ready_fence_fd,
+                                     const void* meta, size_t meta_size_bytes);
+typedef int (*DvrWriteBufferGainPtr)(DvrWriteBuffer* client,
+                                     int* release_fence_fd);
+typedef int (*DvrWriteBufferGainAsyncPtr)(DvrWriteBuffer* client);
+
+typedef void (*DvrReadBufferDestroyPtr)(DvrReadBuffer* client);
+typedef void (*DvrReadBufferGetBlobFdsPtr)(DvrReadBuffer* client, int* fds,
+                                           size_t* fds_count,
+                                           size_t max_fds_count);
+typedef int (*DvrReadBufferGetAHardwareBufferPtr)(
+    DvrReadBuffer* client, AHardwareBuffer** hardware_buffer);
+typedef int (*DvrReadBufferAcquirePtr)(DvrReadBuffer* client,
+                                       int* ready_fence_fd, void* meta,
+                                       size_t meta_size_bytes);
+typedef int (*DvrReadBufferReleasePtr)(DvrReadBuffer* client,
+                                       int release_fence_fd);
+typedef int (*DvrReadBufferReleaseAsyncPtr)(DvrReadBuffer* client);
+
+// dvr_buffer_queue.h
+typedef void (*DvrWriteBufferQueueDestroyPtr)(DvrWriteBufferQueue* write_queue);
+typedef size_t (*DvrWriteBufferQueueGetCapacityPtr)(
+    DvrWriteBufferQueue* write_queue);
+typedef void* (*DvrWriteBufferQueueGetExternalSurfacePtr)(
+    DvrWriteBufferQueue* write_queue, JNIEnv* env);
+typedef int (*DvrWriteBufferQueueCreateReadQueuePtr)(
+    DvrWriteBufferQueue* write_queue, DvrReadBufferQueue** out_read_queue);
+typedef int (*DvrWriteBufferQueueDequeuePtr)(DvrWriteBufferQueue* write_queue,
+                                             int timeout,
+                                             DvrWriteBuffer** out_buffer,
+                                             int* out_fence_fd);
+typedef void (*DvrReadBufferQueueDestroyPtr)(DvrReadBufferQueue* read_queue);
+typedef size_t (*DvrReadBufferQueueGetCapacityPtr)(
+    DvrReadBufferQueue* read_queue);
+typedef int (*DvrReadBufferQueueCreateReadQueuePtr)(
+    DvrReadBufferQueue* read_queue, DvrReadBufferQueue** out_read_queue);
+typedef int (*DvrReadBufferQueueDequeuePtr)(DvrReadBufferQueue* read_queue,
+                                            int timeout,
+                                            DvrReadBuffer** out_buffer,
+                                            int* out_fence_fd, void* out_meta,
+                                            size_t meta_size_bytes);
+
+// dvr_surface.h
+typedef int (*DvrGetPoseBufferPtr)(DvrReadBuffer** pose_buffer);
+
+// vsync_client_api.h
+typedef dvr_vsync_client* (*VSyncClientCreatePtr)();
+typedef void (*VSyncClientDestroyPtr)(dvr_vsync_client* client);
+typedef int (*VSyncClientGetSchedInfoPtr)(dvr_vsync_client* client,
+                                          int64_t* vsync_period_ns,
+                                          int64_t* next_timestamp_ns,
+                                          uint32_t* next_vsync_count);
+
+// pose_client.h
+typedef DvrPose* (*PoseClientCreatePtr)(void);
+typedef void (*PoseClientDestroyPtr)(DvrPose* client);
+typedef int (*PoseGetPtr)(DvrPose* client, uint32_t vsync_count,
+                          DvrPoseAsync* out_pose);
+typedef uint32_t (*PoseGetVsyncCountPtr)(DvrPose* client);
+typedef int (*PoseGetControllerPtr)(DvrPose* client, int32_t controller_id,
+                                    uint32_t vsync_count,
+                                    DvrPoseAsync* out_pose);
+
+// virtual_touchpad_client.h
+typedef DvrVirtualTouchpad* (*VirtualTouchpadCreatePtr)(void);
+typedef void (*VirtualTouchpadDestroyPtr)(DvrVirtualTouchpad* client);
+typedef int (*VirtualTouchpadAttachPtr)(DvrVirtualTouchpad* client);
+typedef int (*VirtualTouchpadDetachPtr)(DvrVirtualTouchpad* client);
+typedef int (*VirtualTouchpadTouchPtr)(DvrVirtualTouchpad* client, int touchpad,
+                                       float x, float y, float pressure);
+typedef int (*VirtualTouchpadButtonStatePtr)(DvrVirtualTouchpad* client,
+                                             int touchpad, int buttons);
+
+struct DvrApi_v1 {
+  // Display manager client
+  DisplayManagerClientCreatePtr display_manager_client_create_;
+  DisplayManagerClientDestroyPtr display_manager_client_destroy_;
+  DisplayManagerClientGetSurfaceListPtr
+      display_manager_client_get_surface_list_;
+  DisplayManagerClientSurfaceListDestroyPtr
+      display_manager_client_surface_list_destroy_;
+  DisplayManagerSetupPoseBufferPtr display_manager_setup_pose_buffer_;
+  DisplayManagerClientSurfaceListGetSizePtr
+      display_manager_client_surface_list_get_size_;
+  DisplayManagerClientSurfaceListGetSurfaceIdPtr
+      display_manager_client_surface_list_get_surface_id_;
+  DisplayManagerClientGetSurfaceBufferListPtr
+      display_manager_client_get_surface_buffer_list_;
+  DisplayManagerClientSurfaceBufferListDestroyPtr
+      display_manager_client_surface_buffer_list_destroy_;
+  DisplayManagerClientSurfaceBufferListGetSizePtr
+      display_manager_client_surface_buffer_list_get_size_;
+  DisplayManagerClientSurfaceBufferListGetFdPtr
+      display_manager_client_surface_buffer_list_get_fd_;
+
+  // Write buffer
+  DvrWriteBufferDestroyPtr write_buffer_destroy_;
+  DvrWriteBufferGetBlobFdsPtr write_buffer_get_blob_fds_;
+  DvrWriteBufferGetAHardwareBufferPtr write_buffer_get_AHardwareBuffer_;
+  DvrWriteBufferPostPtr write_buffer_post_;
+  DvrWriteBufferGainPtr write_buffer_gain_;
+  DvrWriteBufferGainAsyncPtr write_buffer_gain_async_;
+
+  // Read buffer
+  DvrReadBufferDestroyPtr read_buffer_destroy_;
+  DvrReadBufferGetBlobFdsPtr read_buffer_get_blob_fds_;
+  DvrReadBufferGetAHardwareBufferPtr read_buffer_get_AHardwareBuffer_;
+  DvrReadBufferAcquirePtr read_buffer_acquire_;
+  DvrReadBufferReleasePtr read_buffer_release_;
+  DvrReadBufferReleaseAsyncPtr read_buffer_release_async_;
+
+  // Write buffer queue
+  DvrWriteBufferQueueDestroyPtr write_buffer_queue_destroy_;
+  DvrWriteBufferQueueGetCapacityPtr write_buffer_queue_get_capacity_;
+  DvrWriteBufferQueueGetExternalSurfacePtr
+      write_buffer_queue_get_external_surface_;
+  DvrWriteBufferQueueCreateReadQueuePtr write_buffer_queue_create_read_queue_;
+  DvrWriteBufferQueueDequeuePtr write_buffer_queue_dequeue_;
+
+  // Read buffer queue
+  DvrReadBufferQueueDestroyPtr read_buffer_queue_destroy_;
+  DvrReadBufferQueueGetCapacityPtr read_buffer_queue_get_capacity_;
+  DvrReadBufferQueueCreateReadQueuePtr read_buffer_queue_create_read_queue_;
+  DvrReadBufferQueueDequeuePtr read_buffer_queue_dequeue;
+
+  // V-Sync client
+  VSyncClientCreatePtr vsync_client_create_;
+  VSyncClientDestroyPtr vsync_client_destroy_;
+  VSyncClientGetSchedInfoPtr vsync_client_get_sched_info_;
+
+  // Display surface
+  DvrGetPoseBufferPtr get_pose_buffer_;
+
+  // Pose client
+  PoseClientCreatePtr pose_client_create_;
+  PoseClientDestroyPtr pose_client_destroy_;
+  PoseGetPtr pose_get_;
+  PoseGetVsyncCountPtr pose_get_vsync_count_;
+  PoseGetControllerPtr pose_get_controller_;
+
+  // Virtual touchpad client
+  VirtualTouchpadCreatePtr virtual_touchpad_create_;
+  VirtualTouchpadDestroyPtr virtual_touchpad_destroy_;
+  VirtualTouchpadAttachPtr virtual_touchpad_attach_;
+  VirtualTouchpadDetachPtr virtual_touchpad_detach_;
+  VirtualTouchpadTouchPtr virtual_touchpad_touch_;
+  VirtualTouchpadButtonStatePtr virtual_touchpad_button_state_;
+};
+
+int dvrGetApi(void* api, size_t struct_size, int version);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // ANDROID_DVR_API_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/dvr_buffer.h b/libs/vr/libdvr/include/dvr/dvr_buffer.h
similarity index 90%
rename from libs/vr/libbufferhub/include/private/dvr/dvr_buffer.h
rename to libs/vr/libdvr/include/dvr/dvr_buffer.h
index c14b1a3..bbfbb00 100644
--- a/libs/vr/libbufferhub/include/private/dvr/dvr_buffer.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer.h
@@ -25,6 +25,7 @@
 int dvrWriteBufferGainAsync(DvrWriteBuffer* client);
 
 // Read buffer
+void dvrReadBufferDestroy(DvrReadBuffer* client);
 void dvrReadBufferGetBlobFds(DvrReadBuffer* client, int* fds, size_t* fds_count,
                              size_t max_fds_count);
 int dvrReadBufferGetAHardwareBuffer(DvrReadBuffer* client,
@@ -45,9 +46,9 @@
 class BufferConsumer;
 
 DvrWriteBuffer* CreateDvrWriteBufferFromBufferProducer(
-    std::unique_ptr<BufferProducer> buffer_producer);
+    const std::shared_ptr<BufferProducer>& buffer_producer);
 DvrReadBuffer* CreateDvrReadBufferFromBufferConsumer(
-    std::unique_ptr<BufferConsumer> buffer_consumer);
+    const std::shared_ptr<BufferConsumer>& buffer_consumer);
 
 }  // namespace dvr
 }  // namespace android
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
new file mode 100644
index 0000000..86b3ae2
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
@@ -0,0 +1,41 @@
+#ifndef ANDROID_DVR_BUFFER_QUEUE_H_
+#define ANDROID_DVR_BUFFER_QUEUE_H_
+
+#include <dvr/dvr_buffer.h>
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
+typedef struct DvrReadBufferQueue DvrReadBufferQueue;
+
+// WriteBufferQueue
+void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue);
+size_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue);
+
+// Returns ANativeWindow in the form of jobject. Can be casted to ANativeWindow
+// using ANativeWindow_fromSurface NDK API.
+void* dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
+                                            JNIEnv* env);
+
+int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
+                                       DvrReadBufferQueue** out_read_queue);
+int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
+                               DvrWriteBuffer** out_buffer, int* out_fence_fd);
+
+// ReadeBufferQueue
+void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue);
+size_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue);
+int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
+                                      DvrReadBufferQueue** out_read_queue);
+int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
+                              DvrReadBuffer** out_buffer, int* out_fence_fd,
+                              void* out_meta, size_t meta_size_bytes);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // ANDROID_DVR_BUFFER_QUEUE_H_
diff --git a/libs/vr/libdvr/include/dvr/dvr_surface.h b/libs/vr/libdvr/include/dvr/dvr_surface.h
new file mode 100644
index 0000000..fa8d228
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_surface.h
@@ -0,0 +1,17 @@
+#ifndef ANDROID_DVR_SURFACE_H_
+#define ANDROID_DVR_SURFACE_H_
+
+#include <dvr/dvr_buffer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Get a pointer to the global pose buffer.
+int dvrGetPoseBuffer(DvrReadBuffer** pose_buffer);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // ANDROID_DVR_SURFACE_H_
diff --git a/libs/vr/libdisplay/include/private/dvr/vsync_client_api.h b/libs/vr/libdvr/include/dvr/vsync_client_api.h
similarity index 100%
rename from libs/vr/libdisplay/include/private/dvr/vsync_client_api.h
rename to libs/vr/libdvr/include/dvr/vsync_client_api.h
diff --git a/libs/vr/libdvr/tests/Android.mk b/libs/vr/libdvr/tests/Android.mk
new file mode 100644
index 0000000..158d58f
--- /dev/null
+++ b/libs/vr/libdvr/tests/Android.mk
@@ -0,0 +1,29 @@
+LOCAL_PATH := $(call my-dir)
+
+shared_libraries := \
+    libbase \
+    libbinder \
+    libcutils \
+    libgui \
+    liblog \
+    libhardware \
+    libui \
+    libutils \
+
+static_libraries := \
+    libdvr \
+    libbufferhubqueue \
+    libbufferhub \
+    libchrome \
+    libdvrcommon \
+    libpdx_default_transport \
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := dvr_buffer_queue-test.cpp
+LOCAL_STATIC_LIBRARIES := $(static_libraries)
+LOCAL_SHARED_LIBRARIES := $(shared_libraries)
+LOCAL_EXPORT_C_INCLUDE_DIRS := ${LOCAL_C_INCLUDES}
+LOCAL_CFLAGS := -DLOG_TAG=\"dvr_buffer_queue-test\" -DTRACE=0 -O0 -g
+LOCAL_MODULE := dvr_buffer_queue-test
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_NATIVE_TEST)
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
new file mode 100644
index 0000000..f344a24
--- /dev/null
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -0,0 +1,149 @@
+#include <dvr/dvr_buffer_queue.h>
+#include <private/dvr/buffer_hub_queue_client.h>
+
+#include <base/logging.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace dvr {
+
+namespace {
+
+static constexpr int kBufferWidth = 100;
+static constexpr int kBufferHeight = 1;
+static constexpr int kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
+static constexpr int kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
+static constexpr int kBufferSliceCount = 1;  // number of slices in each buffer
+static constexpr size_t kQueueCapacity = 3;
+
+typedef uint64_t TestMeta;
+
+class DvrBufferQueueTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    write_queue_ = new DvrWriteBufferQueue;
+    write_queue_->producer_queue_ = ProducerQueue::Create<TestMeta>(0, 0, 0, 0);
+    ASSERT_NE(nullptr, write_queue_->producer_queue_);
+  }
+
+  void TearDown() override {
+    if (write_queue_ != nullptr) {
+      dvrWriteBufferQueueDestroy(write_queue_);
+      write_queue_ = nullptr;
+    }
+  }
+
+  void AllocateBuffers(size_t buffer_count) {
+    size_t out_slot;
+    for (size_t i = 0; i < buffer_count; i++) {
+      int ret = write_queue_->producer_queue_->AllocateBuffer(
+          kBufferWidth, kBufferHeight, kBufferFormat, kBufferUsage,
+          kBufferSliceCount, &out_slot);
+      ASSERT_EQ(0, ret);
+    }
+  }
+
+  DvrWriteBufferQueue* write_queue_{nullptr};
+};
+
+TEST_F(DvrBufferQueueTest, TestWrite_QueueDestroy) {
+  dvrWriteBufferQueueDestroy(write_queue_);
+  write_queue_ = nullptr;
+}
+
+TEST_F(DvrBufferQueueTest, TestWrite_QueueGetCapacity) {
+  AllocateBuffers(kQueueCapacity);
+  size_t capacity = dvrWriteBufferQueueGetCapacity(write_queue_);
+
+  ALOGD_IF(TRACE, "TestWrite_QueueGetCapacity, capacity=%zu", capacity);
+  ASSERT_EQ(kQueueCapacity, capacity);
+}
+
+TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromWriteQueue) {
+  DvrReadBufferQueue* read_queue = nullptr;
+  int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+
+  ASSERT_EQ(0, ret);
+  ASSERT_NE(nullptr, read_queue);
+
+  dvrReadBufferQueueDestroy(read_queue);
+}
+
+TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromReadQueue) {
+  DvrReadBufferQueue* read_queue1 = nullptr;
+  DvrReadBufferQueue* read_queue2 = nullptr;
+  int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
+
+  ASSERT_EQ(0, ret);
+  ASSERT_NE(nullptr, read_queue1);
+
+  ret = dvrReadBufferQueueCreateReadQueue(read_queue1, &read_queue2);
+  ASSERT_EQ(0, ret);
+  ASSERT_NE(nullptr, read_queue2);
+  ASSERT_NE(read_queue1, read_queue2);
+
+  dvrReadBufferQueueDestroy(read_queue1);
+  dvrReadBufferQueueDestroy(read_queue2);
+}
+
+TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) {
+  static constexpr int kTimeout = 0;
+  DvrReadBufferQueue* read_queue = nullptr;
+  DvrReadBuffer* rb = nullptr;
+  DvrWriteBuffer* wb = nullptr;
+  int fence_fd = -1;
+
+  int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+
+  ASSERT_EQ(0, ret);
+  ASSERT_NE(nullptr, read_queue);
+
+  AllocateBuffers(kQueueCapacity);
+
+  // Gain buffer for writing.
+  ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, &wb, &fence_fd);
+  ASSERT_EQ(0, ret);
+  ASSERT_NE(nullptr, wb);
+  ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, gain buffer %p, fence_fd=%d",
+           wb, fence_fd);
+  pdx::LocalHandle release_fence(fence_fd);
+
+  // Post buffer to the read_queue.
+  TestMeta seq = 42U;
+  ret = dvrWriteBufferPost(wb, /* fence */ -1, &seq, sizeof(seq));
+  ASSERT_EQ(0, ret);
+  dvrWriteBufferDestroy(wb);
+  wb = nullptr;
+
+  // Acquire buffer for reading.
+  TestMeta acquired_seq = 0U;
+  ret = dvrReadBufferQueueDequeue(read_queue, kTimeout, &rb, &fence_fd,
+                                  &acquired_seq, sizeof(acquired_seq));
+  ASSERT_EQ(0, ret);
+  ASSERT_NE(nullptr, rb);
+  ASSERT_EQ(seq, acquired_seq);
+  ALOGD_IF(TRACE,
+           "TestDequeuePostDequeueRelease, acquire buffer %p, fence_fd=%d", rb,
+           fence_fd);
+  pdx::LocalHandle acquire_fence(fence_fd);
+
+  // Release buffer to the write_queue.
+  ret = dvrReadBufferRelease(rb, -1);
+  ASSERT_EQ(0, ret);
+  dvrReadBufferDestroy(rb);
+  rb = nullptr;
+
+  // TODO(b/34387835) Currently buffer allocation has to happen after all queues
+  // are initialized.
+  size_t capacity = dvrReadBufferQueueGetCapacity(read_queue);
+
+  ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, capacity=%zu", capacity);
+  ASSERT_EQ(kQueueCapacity, capacity);
+
+  dvrReadBufferQueueDestroy(read_queue);
+}
+
+}  // namespace
+
+}  // namespace dvr
+}  // namespace android
diff --git a/libs/vr/libdisplay/vsync_client_api.cpp b/libs/vr/libdvr/vsync_client_api.cpp
similarity index 93%
rename from libs/vr/libdisplay/vsync_client_api.cpp
rename to libs/vr/libdvr/vsync_client_api.cpp
index 00af525..dbddd3d 100644
--- a/libs/vr/libdisplay/vsync_client_api.cpp
+++ b/libs/vr/libdvr/vsync_client_api.cpp
@@ -1,4 +1,4 @@
-#include "include/private/dvr/vsync_client_api.h"
+#include "include/dvr/vsync_client_api.h"
 
 #include <private/dvr/vsync_client.h>
 
diff --git a/libs/vr/libdvrcommon/Android.bp b/libs/vr/libdvrcommon/Android.bp
index 81404a4..eb78348 100644
--- a/libs/vr/libdvrcommon/Android.bp
+++ b/libs/vr/libdvrcommon/Android.bp
@@ -14,8 +14,6 @@
 
 sourceFiles = [
     "frame_time_history.cpp",
-    "revision.cpp",
-    "revision_path.cpp",
     "sync_util.cpp",
 ]
 
diff --git a/libs/vr/libdvrcommon/include/private/dvr/revision.h b/libs/vr/libdvrcommon/include/private/dvr/revision.h
deleted file mode 100644
index dda0fce..0000000
--- a/libs/vr/libdvrcommon/include/private/dvr/revision.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_REVISION_H_
-#define LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_REVISION_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// List of DreamOS products
-typedef enum DvrProduct {
-  DVR_PRODUCT_UNKNOWN,
-  DVR_PRODUCT_A00,
-  DVR_PRODUCT_A65R,
-  DVR_PRODUCT_TWILIGHT = DVR_PRODUCT_A65R
-} DvrProduct;
-
-// List of possible revisions.
-typedef enum DvrRevision {
-  DVR_REVISION_UNKNOWN,
-  DVR_REVISION_P1,
-  DVR_REVISION_P2,
-  DVR_REVISION_P3,
-} DvrRevision;
-
-// Query the device's product.
-//
-// @return DvrProduct value, or DvrProductUnknown on error.
-DvrProduct dvr_get_product();
-
-// Query the device's revision.
-//
-// @return DvrRevision value, or DvrRevisionUnknown on error.
-DvrRevision dvr_get_revision();
-
-// Returns the device's board revision string.
-//
-// @return NULL-terminated string such as 'a00-p1'.
-const char* dvr_get_product_revision_str();
-
-// Returns the device's serial number.
-//
-// @return Returns NULL on error, or a NULL-terminated string.
-const char* dvr_get_serial_number();
-
-#ifdef __cplusplus
-}
-#endif  // extern "C"
-#endif  // LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_REVISION_H_
diff --git a/libs/vr/libdvrcommon/revision.cpp b/libs/vr/libdvrcommon/revision.cpp
deleted file mode 100644
index 7925f65..0000000
--- a/libs/vr/libdvrcommon/revision.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-#include "private/dvr/revision.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <log/log.h>
-
-#include "revision_path.h"
-
-namespace {
-
-// Allows quicker access to the product revision. If non-zero, then
-// the product revision file has already been processed.
-static bool global_product_revision_processed = false;
-
-static bool global_serial_number_processed = false;
-
-// The product.
-static DvrProduct global_product = DVR_PRODUCT_UNKNOWN;
-
-// The revision.
-static DvrRevision global_revision = DVR_REVISION_UNKNOWN;
-
-// Maximum size of the product revision string.
-constexpr int kProductRevisionStringSize = 32;
-
-// Maximum size of the serial number.
-constexpr int kSerialNumberStringSize = 32;
-
-// The product revision string.
-static char global_product_revision_str[kProductRevisionStringSize + 1] = "";
-
-// The serial number string
-static char global_serial_number[kSerialNumberStringSize + 1] = "";
-
-// Product and revision combinations.
-struct DvrProductRevision {
-  const char* str;
-  DvrProduct product;
-  DvrRevision revision;
-};
-
-// Null-terminated list of all product and revision combinations.
-static constexpr DvrProductRevision kProductRevisions[] = {
-    {"a00-p1", DVR_PRODUCT_A00, DVR_REVISION_P1},
-    {"a00-p2", DVR_PRODUCT_A00, DVR_REVISION_P2},
-    {"a00-p3", DVR_PRODUCT_A00, DVR_REVISION_P3},
-    {"twilight-p1", DVR_PRODUCT_A65R, DVR_REVISION_P1},
-    {"twilight-p2", DVR_PRODUCT_A65R, DVR_REVISION_P2},
-    {NULL, DVR_PRODUCT_UNKNOWN, DVR_REVISION_UNKNOWN}};
-
-// Read the product revision string, and store the global data.
-static void process_product_revision() {
-  int fd;
-  ssize_t read_rc;
-  const DvrProductRevision* product_revision = kProductRevisions;
-
-  // Of course in a multi-threaded environment, for a few microseconds
-  // during process startup, it is possible that this function will be
-  // called and execute fully multiple times. That is why the product
-  // revision string is statically allocated.
-
-  if (global_product_revision_processed)
-    return;
-
-  // Whether there was a failure or not, we don't want to do this again.
-  // Upon failure it's most likely to fail again anyway.
-
-  fd = open(dvr_product_revision_file_path(), O_RDONLY);
-  if (fd < 0) {
-    ALOGE("Could not open '%s' to get product revision: %s",
-          dvr_product_revision_file_path(), strerror(errno));
-    global_product_revision_processed = true;
-    return;
-  }
-
-  read_rc = read(fd, global_product_revision_str, kProductRevisionStringSize);
-  if (read_rc <= 0) {
-    ALOGE("Could not read from '%s': %s", dvr_product_revision_file_path(),
-          strerror(errno));
-    global_product_revision_processed = true;
-    return;
-  }
-
-  close(fd);
-
-  global_product_revision_str[read_rc] = '\0';
-
-  while (product_revision->str) {
-    if (!strcmp(product_revision->str, global_product_revision_str))
-      break;
-    product_revision++;
-  }
-
-  if (product_revision->str) {
-    global_product = product_revision->product;
-    global_revision = product_revision->revision;
-  } else {
-    ALOGE("Unable to match '%s' to a product/revision.",
-          global_product_revision_str);
-  }
-
-  global_product_revision_processed = true;
-}
-
-}  // anonymous namespace
-
-extern "C" DvrProduct dvr_get_product() {
-  process_product_revision();
-  return global_product;
-}
-
-extern "C" DvrRevision dvr_get_revision() {
-  process_product_revision();
-  return global_revision;
-}
-
-extern "C" const char* dvr_get_product_revision_str() {
-  process_product_revision();
-  return global_product_revision_str;
-}
-
-extern "C" const char* dvr_get_serial_number() {
-  process_product_revision();
-  if (global_product == DVR_PRODUCT_A00) {
-    if (!global_serial_number_processed) {
-#ifdef DVR_HOST
-      global_serial_number_processed = true;
-#else
-      int width = 4;
-      uintptr_t addr = 0x00074138;
-      uintptr_t endaddr = addr + width - 1;
-
-      int fd = open("/dev/mem", O_RDWR | O_SYNC);
-      if (fd < 0) {
-        if (errno == EPERM)
-          global_serial_number_processed = true;
-        fprintf(stderr, "cannot open /dev/mem\n");
-        return global_serial_number;
-      }
-
-      off64_t mmap_start = addr & ~(PAGE_SIZE - 1);
-      size_t mmap_size = endaddr - mmap_start + 1;
-      mmap_size = (mmap_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-
-      void* page = mmap64(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
-                          mmap_start);
-
-      if (page == MAP_FAILED) {
-        global_serial_number_processed = true;
-        fprintf(stderr, "cannot mmap region\n");
-        close(fd);
-        return global_serial_number;
-      }
-
-      uint32_t* x =
-          reinterpret_cast<uint32_t*>((((uintptr_t)page) + (addr & 4095)));
-      snprintf(global_serial_number, kSerialNumberStringSize, "%08x", *x);
-      global_serial_number_processed = true;
-
-      munmap(page, mmap_size);
-      close(fd);
-#endif
-    }
-    return global_serial_number;
-  } else {
-    return nullptr;
-  }
-}
diff --git a/libs/vr/libdvrcommon/revision_path.cpp b/libs/vr/libdvrcommon/revision_path.cpp
deleted file mode 100644
index c49f9aa..0000000
--- a/libs/vr/libdvrcommon/revision_path.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include "revision_path.h"
-
-namespace {
-
-// The path to the product revision file.
-static const char* kProductRevisionFilePath =
-    "/sys/firmware/devicetree/base/goog,board-revision";
-
-}  // anonymous namespace
-
-// This exists in a separate file so that it can be replaced for
-// testing.
-const char* dvr_product_revision_file_path() {
-  return kProductRevisionFilePath;
-}
diff --git a/libs/vr/libdvrcommon/revision_path.h b/libs/vr/libdvrcommon/revision_path.h
deleted file mode 100644
index afcea46..0000000
--- a/libs/vr/libdvrcommon/revision_path.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef ANDROID_DVR_LIBDVRCOMMON_REVISION_PATH_H_
-#define ANDROID_DVR_LIBDVRCOMMON_REVISION_PATH_H_
-
-// Returns the revision file path.
-// This exists in a separate file so that it can be replaced for
-// testing.
-const char* dvr_product_revision_file_path();
-
-#endif  // ANDROID_DVR_LIBDVRCOMMON_REVISION_PATH_H_
diff --git a/libs/vr/libdvrcommon/tests/revision_app_tests.cpp b/libs/vr/libdvrcommon/tests/revision_app_tests.cpp
deleted file mode 100644
index 772481b..0000000
--- a/libs/vr/libdvrcommon/tests/revision_app_tests.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-#include <dvr/test/app_test.h>
-#include <gtest/gtest.h>
-#include <private/dvr/revision.h>
-
-// Making sure this information is not available
-// inside the sandbox
-
-namespace {
-
-TEST(RevisionTests, GetProduct) {
-  ASSERT_EQ(DVR_PRODUCT_UNKNOWN, dvr_get_product());
-}
-
-TEST(RevisionTests, GetRevision) {
-  ASSERT_EQ(DVR_REVISION_UNKNOWN, dvr_get_revision());
-}
-
-TEST(RevisionTests, GetRevisionStr) {
-  ASSERT_STREQ("", dvr_get_product_revision_str());
-}
-
-TEST(RevisionTests, GetSerialNo) {
-  ASSERT_EQ(nullptr, dvr_get_serial_number());
-}
-
-}  // namespace
-
-int main(int argc, char* argv[]) {
-  dreamos::test::AppTestBegin();
-  ::testing::InitGoogleTest(&argc, argv);
-  int result = RUN_ALL_TESTS();
-  dreamos::test::AppTestEnd(result);
-  return result;
-}
diff --git a/libs/vr/libdvrcommon/tests/revision_tests.cpp b/libs/vr/libdvrcommon/tests/revision_tests.cpp
deleted file mode 100644
index 9abf480..0000000
--- a/libs/vr/libdvrcommon/tests/revision_tests.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#include <gtest/gtest.h>
-#include <private/dvr/revision.h>
-
-namespace {
-
-TEST(RevisionTests, GetProduct) {
-  ASSERT_NE(DVR_PRODUCT_UNKNOWN, dvr_get_product());
-}
-
-TEST(RevisionTests, GetRevision) {
-  ASSERT_NE(DVR_REVISION_UNKNOWN, dvr_get_revision());
-}
-
-TEST(RevisionTests, GetRevisionStr) {
-  ASSERT_NE(nullptr, dvr_get_product_revision_str());
-}
-
-TEST(RevisionTests, GetSerialNo) {
-  ASSERT_NE(nullptr, dvr_get_serial_number());
-}
-
-}  // namespace
-
-int main(int argc, char* argv[]) {
-  ::testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
-}
diff --git a/libs/vr/libpdx/service.cpp b/libs/vr/libpdx/service.cpp
index d2804d5..daf9af8 100644
--- a/libs/vr/libpdx/service.cpp
+++ b/libs/vr/libpdx/service.cpp
@@ -129,7 +129,7 @@
   PDX_TRACE_NAME("Message::PushFileHandle");
   if (auto svc = service_.lock()) {
     ErrnoGuard errno_guard;
-    return svc->endpoint()->PushFileHandle(this, handle);
+    return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle));
   } else {
     return -ESHUTDOWN;
   }
@@ -139,7 +139,7 @@
   PDX_TRACE_NAME("Message::PushFileHandle");
   if (auto svc = service_.lock()) {
     ErrnoGuard errno_guard;
-    return svc->endpoint()->PushFileHandle(this, handle);
+    return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle));
   } else {
     return -ESHUTDOWN;
   }
@@ -149,7 +149,7 @@
   PDX_TRACE_NAME("Message::PushFileHandle");
   if (auto svc = service_.lock()) {
     ErrnoGuard errno_guard;
-    return svc->endpoint()->PushFileHandle(this, handle);
+    return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle));
   } else {
     return -ESHUTDOWN;
   }
@@ -159,7 +159,7 @@
   PDX_TRACE_NAME("Message::PushChannelHandle");
   if (auto svc = service_.lock()) {
     ErrnoGuard errno_guard;
-    return svc->endpoint()->PushChannelHandle(this, handle);
+    return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle));
   } else {
     return -ESHUTDOWN;
   }
@@ -170,7 +170,7 @@
   PDX_TRACE_NAME("Message::PushChannelHandle");
   if (auto svc = service_.lock()) {
     ErrnoGuard errno_guard;
-    return svc->endpoint()->PushChannelHandle(this, handle);
+    return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle));
   } else {
     return -ESHUTDOWN;
   }
@@ -180,7 +180,7 @@
   PDX_TRACE_NAME("Message::PushChannelHandle");
   if (auto svc = service_.lock()) {
     ErrnoGuard errno_guard;
-    return svc->endpoint()->PushChannelHandle(this, handle);
+    return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle));
   } else {
     return -ESHUTDOWN;
   }
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index da7281b..c079187 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -94,6 +94,11 @@
           *this, &DisplayService::OnGetPoseBuffer, message);
       return 0;
 
+    case DisplayRPC::IsVrAppRunning::Opcode:
+      DispatchRemoteMethod<DisplayRPC::IsVrAppRunning>(
+          *this, &DisplayService::IsVrAppRunning, message);
+      return 0;
+
     // Direct the surface specific messages to the surface instance.
     case DisplayRPC::CreateBufferQueue::Opcode:
     case DisplayRPC::SetAttributes::Opcode:
@@ -355,5 +360,15 @@
     update_notifier_();
 }
 
+int DisplayService::IsVrAppRunning(pdx::Message& message) {
+  bool visible = true;
+  ForEachDisplaySurface([&visible](const std::shared_ptr<DisplaySurface>& surface) {
+    if (surface->client_z_order() == 0 && !surface->IsVisible())
+      visible = false;
+  });
+
+  REPLY_SUCCESS_RETURN(message, visible, 0);
+}
+
 }  // namespace dvr
 }  // namespace android
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index 2a71b4a..8e96172 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -87,6 +87,9 @@
                          const ViewerParams& view_params);
   pdx::LocalChannelHandle OnGetPoseBuffer(pdx::Message& message);
 
+  // Temporary query for current VR status. Will be removed later.
+  int IsVrAppRunning(pdx::Message& message);
+
   // Called by DisplaySurface to signal that a surface property has changed and
   // the display manager should be notified.
   void NotifyDisplayConfigurationUpdate();
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 7715c46..bf831a7 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -605,20 +605,6 @@
 #endif
 #endif
 
-#ifndef EGL_ANDROID_create_native_client_buffer
-#define EGL_ANDROID_create_native_client_buffer 1
-#define EGL_LAYER_COUNT_ANDROID 0x3434
-#define EGL_NATIVE_BUFFER_USAGE_ANDROID   0x3143
-#define EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID   0x00000001
-#define EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID   0x00000002
-#define EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID   0x00000004
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLClientBuffer eglCreateNativeClientBufferANDROID (const EGLint *attrib_list);
-#else
-typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLCREATENATIVECLIENTBUFFERANDROID) (const EGLint *attrib_list);
-#endif
-#endif
-
 #ifndef EGL_ANDROID_get_native_client_buffer
 #define EGL_ANDROID_get_native_client_buffer 1
 struct AHardwareBuffer;
diff --git a/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt b/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt
deleted file mode 100644
index 4c5551c..0000000
--- a/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt
+++ /dev/null
@@ -1,199 +0,0 @@
-Name
-
-    ANDROID_create_native_client_buffer
-
-Name Strings
-
-    EGL_ANDROID_create_native_client_buffer
-
-Contributors
-
-    Craig Donner
-
-Contact
-
-    Craig Donner, Google Inc. (cdonner 'at' google.com)
-
-Status
-
-    Draft
-
-Version
-
-    Version 1.1, October 26, 2016
-
-Number
-
-    EGL Extension #XXX
-
-Dependencies
-
-    Requires EGL 1.2.
-
-    EGL_ANDROID_image_native_buffer and EGL_KHR_image_base are required.
-
-    This extension is written against the wording of the EGL 1.2
-    Specification as modified by EGL_KHR_image_base and
-    EGL_ANDROID_image_native_buffer.
-
-Overview
-
-    This extension allows creating an EGLClientBuffer backed by an Android
-    window buffer (struct ANativeWindowBuffer) which can be later used to
-    create an EGLImage.
-
-New Types
-
-    None.
-
-New Procedures and Functions
-
-EGLClientBuffer eglCreateNativeClientBufferANDROID(
-                        const EGLint *attrib_list)
-
-New Tokens
-
-    EGL_NATIVE_BUFFER_LAYER_COUNT_ANDROID 0x3434
-    EGL_NATIVE_BUFFER_USAGE_ANDROID 0x3143
-    EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID 0x00000001
-    EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID 0x00000002
-    EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID 0x00000004
-
-Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors)
-
-    Add the following to section 2.5.1 "EGLImage Specification" (as modified by
-    the EGL_KHR_image_base and EGL_ANDROID_image_native_buffer specifications),
-    below the description of eglCreateImageKHR:
-
-   "The command
-
-        EGLClientBuffer eglCreateNativeClientBufferANDROID(
-                                const EGLint *attrib_list)
-
-    may be used to create an EGLClientBuffer backed by an ANativeWindowBuffer
-    struct. EGL implementations must guarantee that the lifetime of the
-    returned EGLClientBuffer is at least as long as the EGLImage(s) it is bound
-    to, following the lifetime semantics described below in section 2.5.2; the
-    EGLClientBuffer must be destroyed no earlier than when all of its associated
-    EGLImages are destroyed by eglDestroyImageKHR. <attrib_list> is a list of
-    attribute-value pairs which is used to specify the dimensions, format, and
-    usage of the underlying buffer structure. If <attrib_list> is non-NULL, the
-    last attribute specified in the list must be EGL_NONE.
-
-    Attribute names accepted in <attrib_list> are shown in Table aaa,
-    together with the <target> for which each attribute name is valid, and
-    the default value used for each attribute if it is not included in
-    <attrib_list>.
-
-      +---------------------------------+----------------------+---------------+
-      | Attribute                       | Description          | Default Value |
-      |                                 |                      |               |
-      +---------------------------------+----------------------+---------------+
-      | EGL_NONE                        | Marks the end of the | N/A           |
-      |                                 | attribute-value list |               |
-      | EGL_WIDTH                       | The width of the     | 0             |
-      |                                 | buffer data          |               |
-      | EGL_HEIGHT                      | The height of the    | 0             |
-      |                                 | buffer data          |               |
-      | EGL_RED_SIZE                    | The bits of Red in   | 0             |
-      |                                 | the color buffer     |               |
-      | EGL_GREEN_SIZE                  | The bits of Green in | 0             |
-      |                                 | the color buffer     |               |
-      | EGL_BLUE_SIZE                   | The bits of Blue in  | 0             |
-      |                                 | the color buffer     |               |
-      | EGL_ALPHA_SIZE                  | The bits of Alpha in | 0             |
-      |                                 | the color buffer     |               |
-      |                                 | buffer data          |               |
-      | EGL_LAYER_COUNT_ANDROID         | The number of image  | 1             |
-      |                                 | layers in the buffer |               |
-      | EGL_NATIVE_BUFFER_USAGE_ANDROID | The usage bits of    | 0             |
-      |                                 | the buffer data      |               |
-      +---------------------------------+----------------------+---------------+
-       Table aaa.  Legal attributes for eglCreateNativeClientBufferANDROID
-       <attrib_list> parameter.
-
-    The maximum width and height may depend on the amount of available memory,
-    which may also depend on the format and usage flags. The values of
-    EGL_RED_SIZE, EGL_GREEN_SIZE, and EGL_BLUE_SIZE must be non-zero and
-    correspond to a valid pixel format for the implementation. If EGL_ALPHA_SIZE
-    is non-zero then the combination of all four sizes must correspond to a
-    valid pixel format for the implementation. The value of
-    EGL_LAYER_COUNT_ANDROID must be a valid number of image layers for the
-    implementation. The EGL_NATIVE_BUFFER_USAGE_ANDROID flag may include any of
-    the following bits:
-
-        EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID: Indicates that the
-        created buffer must have a hardware-protected path to external display
-        sink. If a hardware-protected path is not available, then either don't
-        composite only this buffer (preferred) to the external sink, or (less
-        desirable) do not route the entire composition to the external sink.
-
-        EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID: The buffer will be
-        used to create a color-renderable texture.
-
-        EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID: The buffer will be used to
-        create a filterable texture.
-
-    Errors
-
-        If eglCreateNativeClientBufferANDROID fails, NULL will be returned, no
-        memory will be allocated, and one of the following errors will be
-        generated:
-
-       * If the value of EGL_WIDTH or EGL_HEIGHT is not positive, the error
-         EGL_BAD_PARAMETER is generated.
-
-       * If the combination of the values of EGL_RED_SIZE, EGL_GREEN_SIZE,
-         EGL_BLUE_SIZE, and EGL_ALPHA_SIZE is not a valid pixel format for the
-         EGL implementation, the error EGL_BAD_PARAMETER is generated.
-
-       * If the value of EGL_NATIVE_BUFFER_ANDROID is not a valid combination
-         of gralloc usage flags for the EGL implementation, or is incompatible
-         with the value of EGL_FORMAT, the error EGL_BAD_PARAMETER is
-         Generated.
-
-Issues
-
-    1. Should this extension define what combinations of formats and usage flags
-    EGL implementations are required to support?
-
-    RESOLVED: Partially.
-
-    The set of valid color combinations is implementation-specific and may
-    depend on additional EGL extensions, but generally RGB565 and RGBA888 should
-    be supported. The particular valid combinations for a given Android version
-    and implementation should be documented by that version.
-
-    2. Should there be an eglDestroyNativeClientBufferANDROID to destroy the
-    client buffers created by this extension?
-
-    RESOLVED: No.
-
-    A destroy function would add several complications:
-
-        a) ANativeWindowBuffer is a reference counted object, may be used
-           outside of EGL.
-        b) The same buffer may back multiple EGLImages, though this usage may
-           result in undefined behavior.
-        c) The interactions between the lifetimes of EGLImages and their
-           EGLClientBuffers would become needlessly complex.
-
-    Because ANativeWindowBuffer is a reference counted object, implementations
-    of this extension should ensure the buffer has a lifetime at least as long
-    as a generated EGLImage (via EGL_ANDROID_image_native_buffer). The simplest
-    method is to increment the reference count of the buffer in
-    eglCreateImagKHR, and then decrement it in eglDestroyImageKHR. This should
-    ensure proper lifetime semantics.
-
-Revision History
-
-#3 (Craig Donner, October 26, 2016)
-    - Added EGL_LAYER_COUNT_ANDROID for creating buffers that back texture
-    arrays.
-
-#2 (Craig Donner, April 15, 2016)
-    - Set color formats and usage bits explicitly using additional attributes,
-    and add value for new token EGL_NATIVE_BUFFER_USAGE_ANDROID.
-
-#1 (Craig Donner, January 19, 2016)
-    - Initial draft.
diff --git a/opengl/specs/README b/opengl/specs/README
index 27289e4..e922740 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -9,7 +9,6 @@
 0x3140               EGL_NATIVE_BUFFER_ANDROID (EGL_ANDROID_image_native_buffer)
 0x3141               EGL_PLATFORM_ANDROID_KHR (KHR_platform_android)
 0x3142               EGL_RECORDABLE_ANDROID (EGL_ANDROID_recordable)
-0x3143               EGL_NATIVE_BUFFER_USAGE_ANDROID (EGL_ANDROID_create_native_client_buffer)
 0x3144               EGL_SYNC_NATIVE_FENCE_ANDROID (EGL_ANDROID_native_fence_sync)
 0x3145               EGL_SYNC_NATIVE_FENCE_FD_ANDROID (EGL_ANDROID_native_fence_sync)
 0x3146               EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID (EGL_ANDROID_native_fence_sync)
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 2a17a7f..080c02b 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -52,6 +52,31 @@
 }
 
 SensorDevice::SensorDevice() : mHidlTransportErrors(20) {
+    if (!connectHidlService()) {
+        return;
+    }
+    checkReturn(mSensors->getSensorsList(
+            [&](const auto &list) {
+                const size_t count = list.size();
+
+                mActivationCount.setCapacity(count);
+                Info model;
+                for (size_t i=0 ; i < count; i++) {
+                    sensor_t sensor;
+                    convertToSensor(list[i], &sensor);
+                    mSensorList.push_back(sensor);
+
+                    mActivationCount.add(list[i].sensorHandle, model);
+
+                    checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */));
+                }
+            }));
+
+    mIsDirectReportSupported =
+           (checkReturn(mSensors->unregisterDirectChannel(-1)) != Result::INVALID_OPERATION);
+}
+
+bool SensorDevice::connectHidlService() {
     // SensorDevice may wait upto 100ms * 10 = 1s for hidl service.
     constexpr auto RETRY_DELAY = std::chrono::milliseconds(100);
     size_t retry = 10;
@@ -74,7 +99,7 @@
 
         if (--retry <= 0) {
             ALOGE("Cannot connect to ISensors hidl service!");
-            return;
+            break;
         }
         // Delay 100ms before retry, hidl service is expected to come up in short time after
         // crash.
@@ -82,29 +107,11 @@
                 (initStep == 0) ? "getService()" : "poll() check", retry);
         std::this_thread::sleep_for(RETRY_DELAY);
     }
-
-    checkReturn(mSensors->getSensorsList(
-            [&](const auto &list) {
-                const size_t count = list.size();
-
-                mActivationCount.setCapacity(count);
-                Info model;
-                for (size_t i=0 ; i < count; i++) {
-                    sensor_t sensor;
-                    convertToSensor(list[i], &sensor);
-                    mSensorList.push_back(sensor);
-
-                    mActivationCount.add(list[i].sensorHandle, model);
-
-                    checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */));
-                }
-            }));
-
-    mIsDirectReportSupported =
-           (checkReturn(mSensors->unregisterDirectChannel(-1)) != Result::INVALID_OPERATION);
+    return (mSensors != nullptr);
 }
 
 void SensorDevice::handleDynamicSensorConnection(int handle, bool connected) {
+    // not need to check mSensors because this is is only called after successful poll()
     if (connected) {
         Info model;
         mActivationCount.add(handle, model);
@@ -115,64 +122,38 @@
 }
 
 std::string SensorDevice::dump() const {
-    if (mSensors == NULL) return "HAL not initialized\n";
+    if (mSensors == nullptr) return "HAL not initialized\n";
 
     String8 result;
+    result.appendFormat("Total %zu h/w sensors, %zu running:\n",
+                        mSensorList.size(), mActivationCount.size());
 
-    result.appendFormat("Saw %d hidlTransport Errors\n", mTotalHidlTransportErrors);
-    for (auto it = mHidlTransportErrors.begin() ; it != mHidlTransportErrors.end(); it++ ) {
-        result += "\t";
-        result += it->toString();
-        result += "\n";
+    Mutex::Autolock _l(mLock);
+    for (const auto & s : mSensorList) {
+        int32_t handle = s.handle;
+        const Info& info = mActivationCount.valueFor(handle);
+        if (info.batchParams.isEmpty()) continue;
+
+        result.appendFormat("0x%08x) active-count = %zu; ", handle, info.batchParams.size());
+
+        result.append("sampling_period(ms) = {");
+        for (size_t j = 0; j < info.batchParams.size(); j++) {
+            const BatchParams& params = info.batchParams.valueAt(j);
+            result.appendFormat("%.1f%s", params.batchDelay / 1e6f,
+                j < info.batchParams.size() - 1 ? ", " : "");
+        }
+        result.appendFormat("}, selected = %.1f ms; ", info.bestBatchParams.batchDelay / 1e6f);
+
+        result.append("batching_period(ms) = {");
+        for (size_t j = 0; j < info.batchParams.size(); j++) {
+            BatchParams params = info.batchParams.valueAt(j);
+
+            result.appendFormat("%.1f%s", params.batchTimeout / 1e6f,
+                    j < info.batchParams.size() - 1 ? ", " : "");
+        }
+        result.appendFormat("}, selected = %.1f ms\n", info.bestBatchParams.batchTimeout / 1e6f);
     }
 
-    checkReturn(mSensors->getSensorsList([&](const auto &list){
-            const size_t count = list.size();
-
-            result.appendFormat(
-                "Total %zu h/w sensors, %zu running:\n",
-                count,
-                mActivationCount.size());
-
-            Mutex::Autolock _l(mLock);
-            for (size_t i = 0 ; i < count ; i++) {
-                const Info& info = mActivationCount.valueFor(
-                    list[i].sensorHandle);
-
-                if (info.batchParams.isEmpty()) continue;
-                result.appendFormat(
-                    "0x%08x) active-count = %zu; ",
-                    list[i].sensorHandle,
-                    info.batchParams.size());
-
-                result.append("sampling_period(ms) = {");
-                for (size_t j = 0; j < info.batchParams.size(); j++) {
-                    const BatchParams& params = info.batchParams.valueAt(j);
-                    result.appendFormat(
-                        "%.1f%s",
-                        params.batchDelay / 1e6f,
-                        j < info.batchParams.size() - 1 ? ", " : "");
-                }
-                result.appendFormat(
-                        "}, selected = %.1f ms; ",
-                        info.bestBatchParams.batchDelay / 1e6f);
-
-                result.append("batching_period(ms) = {");
-                for (size_t j = 0; j < info.batchParams.size(); j++) {
-                    BatchParams params = info.batchParams.valueAt(j);
-
-                    result.appendFormat(
-                            "%.1f%s",
-                            params.batchTimeout / 1e6f,
-                            j < info.batchParams.size() - 1 ? ", " : "");
-                }
-
-                result.appendFormat(
-                        "}, selected = %.1f ms\n",
-                        info.bestBatchParams.batchTimeout / 1e6f);
-            }
-        }));
-
     return result.string();
 }
 
@@ -187,7 +168,7 @@
 }
 
 ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
-    if (mSensors == NULL) return NO_INIT;
+    if (mSensors == nullptr) return NO_INIT;
 
     ssize_t err;
     int numHidlTransportErrors = 0;
@@ -239,7 +220,7 @@
 }
 
 status_t SensorDevice::activate(void* ident, int handle, int enabled) {
-    if (mSensors == NULL) return NO_INIT;
+    if (mSensors == nullptr) return NO_INIT;
 
     status_t err(NO_ERROR);
     bool actuateHardware = false;
@@ -328,7 +309,7 @@
         int flags,
         int64_t samplingPeriodNs,
         int64_t maxBatchReportLatencyNs) {
-    if (mSensors == NULL) return NO_INIT;
+    if (mSensors == nullptr) return NO_INIT;
 
     if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
         samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
@@ -382,7 +363,7 @@
 }
 
 status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodNs) {
-    if (mSensors == NULL) return NO_INIT;
+    if (mSensors == nullptr) return NO_INIT;
     if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
         samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
     }
@@ -407,11 +388,12 @@
 }
 
 int SensorDevice::getHalDeviceVersion() const {
-    if (mSensors == NULL) return -1;
+    if (mSensors == nullptr) return -1;
     return SENSORS_DEVICE_API_VERSION_1_4;
 }
 
 status_t SensorDevice::flush(void* ident, int handle) {
+    if (mSensors == nullptr) return NO_INIT;
     if (isClientDisabled(ident)) return INVALID_OPERATION;
     ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
     return StatusFromResult(checkReturn(mSensors->flush(handle)));
@@ -427,6 +409,7 @@
 }
 
 void SensorDevice::enableAllSensors() {
+    if (mSensors == nullptr) return;
     Mutex::Autolock _l(mLock);
     mDisabledClients.clear();
     ALOGI("cleared mDisabledClients");
@@ -453,8 +436,9 @@
 }
 
 void SensorDevice::disableAllSensors() {
+    if (mSensors == nullptr) return;
     Mutex::Autolock _l(mLock);
-   for (size_t i = 0; i< mActivationCount.size(); ++i) {
+    for (size_t i = 0; i< mActivationCount.size(); ++i) {
         const Info& info = mActivationCount.valueAt(i);
         // Check if this sensor has been activated previously and disable it.
         if (info.batchParams.size() > 0) {
@@ -475,6 +459,7 @@
 
 status_t SensorDevice::injectSensorData(
         const sensors_event_t *injected_sensor_event) {
+    if (mSensors == nullptr) return NO_INIT;
     ALOGD_IF(DEBUG_CONNECTIONS,
             "sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
             injected_sensor_event->sensor,
@@ -490,10 +475,97 @@
 }
 
 status_t SensorDevice::setMode(uint32_t mode) {
+    if (mSensors == nullptr) return NO_INIT;
+    return StatusFromResult(
+            checkReturn(mSensors->setOperationMode(
+                    static_cast<hardware::sensors::V1_0::OperationMode>(mode))));
+}
 
-     return StatusFromResult(
-             checkReturn(mSensors->setOperationMode(
-                 static_cast<hardware::sensors::V1_0::OperationMode>(mode))));
+int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) {
+    if (mSensors == nullptr) return NO_INIT;
+    Mutex::Autolock _l(mLock);
+
+    SharedMemType type;
+    switch (memory->type) {
+        case SENSOR_DIRECT_MEM_TYPE_ASHMEM:
+            type = SharedMemType::ASHMEM;
+            break;
+        case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
+            type = SharedMemType::GRALLOC;
+            break;
+        default:
+            return BAD_VALUE;
+    }
+
+    SharedMemFormat format;
+    if (memory->format != SENSOR_DIRECT_FMT_SENSORS_EVENT) {
+        return BAD_VALUE;
+    }
+    format = SharedMemFormat::SENSORS_EVENT;
+
+    SharedMemInfo mem = {
+        .type = type,
+        .format = format,
+        .size = static_cast<uint32_t>(memory->size),
+        .memoryHandle = memory->handle,
+    };
+
+    int32_t ret;
+    checkReturn(mSensors->registerDirectChannel(mem,
+            [&ret](auto result, auto channelHandle) {
+                if (result == Result::OK) {
+                    ret = channelHandle;
+                } else {
+                    ret = StatusFromResult(result);
+                }
+            }));
+    return ret;
+}
+
+void SensorDevice::unregisterDirectChannel(int32_t channelHandle) {
+    if (mSensors == nullptr) return;
+    Mutex::Autolock _l(mLock);
+    checkReturn(mSensors->unregisterDirectChannel(channelHandle));
+}
+
+int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle,
+        int32_t channelHandle, const struct sensors_direct_cfg_t *config) {
+    if (mSensors == nullptr) return NO_INIT;
+    Mutex::Autolock _l(mLock);
+
+    RateLevel rate;
+    switch(config->rate_level) {
+        case SENSOR_DIRECT_RATE_STOP:
+            rate = RateLevel::STOP;
+            break;
+        case SENSOR_DIRECT_RATE_NORMAL:
+            rate = RateLevel::NORMAL;
+            break;
+        case SENSOR_DIRECT_RATE_FAST:
+            rate = RateLevel::FAST;
+            break;
+        case SENSOR_DIRECT_RATE_VERY_FAST:
+            rate = RateLevel::VERY_FAST;
+            break;
+        default:
+            return BAD_VALUE;
+    }
+
+    int32_t ret;
+    checkReturn(mSensors->configDirectReport(sensorHandle, channelHandle, rate,
+            [&ret, rate] (auto result, auto token) {
+                if (rate == RateLevel::STOP) {
+                    ret = StatusFromResult(result);
+                } else {
+                    if (result == Result::OK) {
+                        ret = token;
+                    } else {
+                        ret = StatusFromResult(result);
+                    }
+                }
+            }));
+
+    return ret;
 }
 
 // ---------------------------------------------------------------------------
@@ -555,90 +627,6 @@
     mDisabledClients.remove(ident);
 }
 
-int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) {
-    Mutex::Autolock _l(mLock);
-
-    SharedMemType type;
-    switch (memory->type) {
-        case SENSOR_DIRECT_MEM_TYPE_ASHMEM:
-            type = SharedMemType::ASHMEM;
-            break;
-        case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
-            type = SharedMemType::GRALLOC;
-            break;
-        default:
-            return BAD_VALUE;
-    }
-
-    SharedMemFormat format;
-    if (memory->format != SENSOR_DIRECT_FMT_SENSORS_EVENT) {
-        return BAD_VALUE;
-    }
-    format = SharedMemFormat::SENSORS_EVENT;
-
-    SharedMemInfo mem = {
-        .type = type,
-        .format = format,
-        .size = static_cast<uint32_t>(memory->size),
-        .memoryHandle = memory->handle,
-    };
-
-    int32_t ret;
-    checkReturn(mSensors->registerDirectChannel(mem,
-            [&ret](auto result, auto channelHandle) {
-                if (result == Result::OK) {
-                    ret = channelHandle;
-                } else {
-                    ret = StatusFromResult(result);
-                }
-            }));
-    return ret;
-}
-
-void SensorDevice::unregisterDirectChannel(int32_t channelHandle) {
-    Mutex::Autolock _l(mLock);
-    checkReturn(mSensors->unregisterDirectChannel(channelHandle));
-}
-
-int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle,
-        int32_t channelHandle, const struct sensors_direct_cfg_t *config) {
-    Mutex::Autolock _l(mLock);
-
-    RateLevel rate;
-    switch(config->rate_level) {
-        case SENSOR_DIRECT_RATE_STOP:
-            rate = RateLevel::STOP;
-            break;
-        case SENSOR_DIRECT_RATE_NORMAL:
-            rate = RateLevel::NORMAL;
-            break;
-        case SENSOR_DIRECT_RATE_FAST:
-            rate = RateLevel::FAST;
-            break;
-        case SENSOR_DIRECT_RATE_VERY_FAST:
-            rate = RateLevel::VERY_FAST;
-            break;
-        default:
-            return BAD_VALUE;
-    }
-
-    int32_t ret;
-    checkReturn(mSensors->configDirectReport(sensorHandle, channelHandle, rate,
-            [&ret, rate] (auto result, auto token) {
-                if (rate == RateLevel::STOP) {
-                    ret = StatusFromResult(result);
-                } else {
-                    if (result == Result::OK) {
-                        ret = token;
-                    } else {
-                        ret = StatusFromResult(result);
-                    }
-                }
-            }));
-
-    return ret;
-}
-
 bool SensorDevice::isDirectReportSupported() const {
     return mIsDirectReportSupported;
 }
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 410531b..2520a81 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -161,6 +161,7 @@
     // Use this vector to determine which client is activated or deactivated.
     SortedVector<void *> mDisabledClients;
     SensorDevice();
+    bool connectHidlService();
 
     static void handleHidlDeath(const std::string &detail);
     template<typename T>
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index c6e6dcb..d9bddb5 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -129,7 +129,7 @@
       mIsUsingVrComposer(useVrComposer)
 {
     if (mIsUsingVrComposer) {
-        mComposer = IComposer::getService("vr_hwcomposer");
+        mComposer = IComposer::getService("vr");
     } else {
         mComposer = IComposer::getService(); // use default name
     }
diff --git a/services/vr/hardware_composer/vr_hardware_composer_service.cpp b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
index 9591748..f980220 100644
--- a/services/vr/hardware_composer/vr_hardware_composer_service.cpp
+++ b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
@@ -26,7 +26,7 @@
 
   // Register the hwbinder HWC HAL service used by SurfaceFlinger while in VR
   // mode.
-  const char instance[] = "vr_hwcomposer";
+  const char instance[] = "vr";
   android::sp<IComposer> service =
       android::dvr::HIDL_FETCH_IComposer(instance);
 
diff --git a/services/vr/vr_window_manager/application.cpp b/services/vr/vr_window_manager/application.cpp
index 7c61076..b2f02e5 100644
--- a/services/vr/vr_window_manager/application.cpp
+++ b/services/vr/vr_window_manager/application.cpp
@@ -112,6 +112,7 @@
 void Application::DeallocateResources() {
   if (graphics_context_)
     dvrGraphicsContextDestroy(graphics_context_);
+  graphics_context_ = nullptr;
 
   if (pose_client_)
     dvrPoseDestroy(pose_client_);
@@ -173,7 +174,12 @@
   // TODO(steventhomas): If we're not visible, block until we are. For now we
   // throttle by calling dvrGraphicsWaitNextFrame.
   DvrFrameSchedule schedule;
-  dvrGraphicsWaitNextFrame(graphics_context_, 0, &schedule);
+  int status = dvrGraphicsWaitNextFrame(graphics_context_, 0, &schedule);
+  if (status < 0) {
+    ALOGE("Context lost, deallocating graphics resources");
+    SetVisibility(false);
+    DeallocateResources();
+  }
 
   OnDrawFrame();
 
diff --git a/services/vr/vr_window_manager/display_view.cpp b/services/vr/vr_window_manager/display_view.cpp
index 8a1c84d..e88e7d0 100644
--- a/services/vr/vr_window_manager/display_view.cpp
+++ b/services/vr/vr_window_manager/display_view.cpp
@@ -9,6 +9,7 @@
 
 constexpr float kLayerScaleFactor = 3.0f;
 constexpr unsigned int kMaximumPendingFrames = 8;
+constexpr uint32_t kSystemId = 1000;
 
 // clang-format off
 const GLfloat kVertices[] = {
@@ -98,12 +99,9 @@
 
 // Determine if ths frame should be shown or hidden.
 ViewMode CalculateVisibilityFromLayerConfig(const HwcCallback::Frame& frame,
-                                            uint32_t *appid) {
+                                            uint32_t* appid) {
   auto& layers = frame.layers();
 
-  // TODO(achaulk): Figure out how to identify the current VR app for 2D app
-  // detection.
-
   size_t index;
   // Skip all layers that we don't know about.
   for (index = 0; index < layers.size(); index++) {
@@ -119,7 +117,7 @@
     return ViewMode::Hidden;
   }
 
-  if(layers[index].appid != *appid) {
+  if (layers[index].appid != *appid) {
     *appid = layers[index].appid;
     return ViewMode::App;
   }
@@ -202,7 +200,8 @@
 }
 
 base::unique_fd DisplayView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame,
-                                     bool debug_mode, bool* showing) {
+                                     bool debug_mode, bool is_vr_active,
+                                     bool* showing) {
   uint32_t app = current_vr_app_;
   ViewMode visibility = CalculateVisibilityFromLayerConfig(*frame.get(), &app);
 
@@ -214,7 +213,7 @@
   } else if (visibility == ViewMode::App) {
     // This is either a VR app switch or a 2D app launching.
     // If we can have VR apps, update if it's 0.
-    if (!always_2d_ && (current_vr_app_ == 0 || !use_2dmode_)) {
+    if (!always_2d_ && is_vr_active && !use_2dmode_ && app != kSystemId) {
       visibility = ViewMode::Hidden;
       current_vr_app_ = app;
     }
diff --git a/services/vr/vr_window_manager/display_view.h b/services/vr/vr_window_manager/display_view.h
index 9483e8b..0d1355e 100644
--- a/services/vr/vr_window_manager/display_view.h
+++ b/services/vr/vr_window_manager/display_view.h
@@ -23,7 +23,7 @@
 
   // Calls to these 3 functions must be synchronized.
   base::unique_fd OnFrame(std::unique_ptr<HwcCallback::Frame> frame,
-                          bool debug_mode, bool* showing);
+                          bool debug_mode, bool is_vr_active, bool* showing);
   void AdvanceFrame();
   void UpdateReleaseFence();
 
diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp
index e17b2ae..c270be2 100644
--- a/services/vr/vr_window_manager/shell_view.cpp
+++ b/services/vr/vr_window_manager/shell_view.cpp
@@ -4,6 +4,7 @@
 #include <GLES3/gl3.h>
 #include <android/input.h>
 #include <binder/IServiceManager.h>
+#include <dvr/graphics.h>
 #include <hardware/hwcomposer2.h>
 #include <inttypes.h>
 #include <log/log.h>
@@ -159,7 +160,14 @@
 }
 
 void ShellView::DeallocateResources() {
-  surface_flinger_view_.reset();
+  {
+    std::unique_lock<std::mutex> l(display_frame_mutex_);
+    removed_displays_.clear();
+    new_displays_.clear();
+    displays_.clear();
+  }
+
+  display_client_.reset();
   reticle_.reset();
   controller_mesh_.reset();
   program_.reset(new ShaderProgram);
@@ -278,7 +286,25 @@
 
   bool showing = false;
 
-  base::unique_fd fd(display->OnFrame(std::move(frame), debug_mode_, &showing));
+  // This is a temporary fix for now. These APIs will be changed when everything
+  // is moved into vrcore.
+  // Do this on demand in case vr_flinger crashed and we are reconnecting.
+  if (!display_client_.get()) {
+    int error = 0;
+    display_client_ = DisplayClient::Create(&error);
+
+    if (error) {
+      ALOGE("Could not connect to display service : %s(%d)", strerror(error),
+            error);
+      return base::unique_fd();
+    }
+  }
+
+  // TODO(achaulk): change when moved into vrcore.
+  bool vr_running = display_client_->IsVrAppRunning();
+
+  base::unique_fd fd(
+      display->OnFrame(std::move(frame), debug_mode_, vr_running, &showing));
 
   if (showing)
     QueueTask(MainThreadTask::Show);
diff --git a/services/vr/vr_window_manager/shell_view.h b/services/vr/vr_window_manager/shell_view.h
index 6887e7e..d265866 100644
--- a/services/vr/vr_window_manager/shell_view.h
+++ b/services/vr/vr_window_manager/shell_view.h
@@ -2,6 +2,7 @@
 #define VR_WINDOW_MANAGER_SHELL_VIEW_H_
 
 #include <dvr/virtual_touchpad_client.h>
+#include <private/dvr/display_client.h>
 #include <private/dvr/graphics/mesh.h>
 #include <private/dvr/graphics/shader_program.h>
 
@@ -66,6 +67,8 @@
   std::unique_ptr<SurfaceFlingerView> surface_flinger_view_;
   std::unique_ptr<Reticle> reticle_;
 
+  std::unique_ptr<DisplayClient> display_client_;
+
   struct DvrVirtualTouchpadDeleter {
     void operator()(DvrVirtualTouchpad* p) {
       dvrVirtualTouchpadDetach(p);
diff --git a/services/vr/vr_window_manager/surface_flinger_view.cpp b/services/vr/vr_window_manager/surface_flinger_view.cpp
index 46eb880..427ad70 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.cpp
+++ b/services/vr/vr_window_manager/surface_flinger_view.cpp
@@ -15,7 +15,7 @@
 SurfaceFlingerView::~SurfaceFlingerView() {}
 
 bool SurfaceFlingerView::Initialize(HwcCallback::Client *client) {
-  const char vr_hwcomposer_name[] = "vr_hwcomposer";
+  const char vr_hwcomposer_name[] = "vr";
   vr_hwcomposer_ = HIDL_FETCH_IComposer(vr_hwcomposer_name);
   if (!vr_hwcomposer_.get()) {
     ALOGE("Failed to get vr_hwcomposer");