Merge "Move libgvr to vendor/unbundled_google/libraries/vr."
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index b323624..e33f099 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1344,7 +1344,8 @@
 
     // TODO: explicity setting Shell's component to allow broadcast to launch it.
     // That might break other components that are listening to the bugreport notifications
-    // (android.intent.action.BUGREPORT_STARTED and android.intent.action.BUGREPORT_STOPED), but
+    // (com.android.internal.intent.action.BUGREPORT_STARTED and
+    // com.android.internal.intent.action.BUGREPORT_STOPED), but
     // those should be just handled by Shell anyways.
     // A more generic alternative would be passing the -f 0x01000000 flag (or whatever
     // value is defined by FLAG_RECEIVER_INCLUDE_BACKGROUND), but that would reset the
@@ -1600,7 +1601,7 @@
                      "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
                 };
                 // clang-format on
-                SendShellBroadcast("android.intent.action.BUGREPORT_STARTED", am_args);
+                SendShellBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
             }
             if (use_control_socket) {
                 dprintf(ds.control_socket_fd_, "BEGIN:%s\n", ds.path_.c_str());
@@ -1825,9 +1826,10 @@
                 am_args.push_back("--es");
                 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
                 am_args.push_back(SHA256_file_hash(ds.path_));
-                SendShellBroadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
+                SendShellBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED",
+                                   am_args);
             } else {
-                SendShellBroadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
+                SendShellBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
             }
         } else {
             MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index aa32d6b..0fb207b 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -854,13 +854,16 @@
     return open(file_name, flags, permissions);
 }
 
-static bool set_permissions_and_ownership(int fd, bool is_public, int uid, const char* path) {
+static bool set_permissions_and_ownership(
+        int fd, bool is_public, int uid, const char* path, bool is_secondary_dex) {
+    // Primary apks are owned by the system. Secondary dex files are owned by the app.
+    int owning_uid = is_secondary_dex ? uid : AID_SYSTEM;
     if (fchmod(fd,
                S_IRUSR|S_IWUSR|S_IRGRP |
                (is_public ? S_IROTH : 0)) < 0) {
         ALOGE("installd cannot chmod '%s' during dexopt\n", path);
         return false;
-    } else if (fchown(fd, AID_SYSTEM, uid) < 0) {
+    } else if (fchown(fd, owning_uid, uid) < 0) {
         ALOGE("installd cannot chown '%s' during dexopt\n", path);
         return false;
     }
@@ -1009,10 +1012,11 @@
 
 // (re)Creates the app image if needed.
 Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path, bool profile_guided,
-        bool is_public, int uid) {
+        bool is_public, int uid, bool is_secondary_dex) {
     // Use app images only if it is enabled (by a set image format) and we are compiling
     // profile-guided (so the app image doesn't conservatively contain all classes).
-    if (!profile_guided) {
+    // Note that we don't create an image for secondary dex files.
+    if (is_secondary_dex || !profile_guided) {
         return Dex2oatFileWrapper();
     }
 
@@ -1043,7 +1047,7 @@
             }
         }
     } else if (!set_permissions_and_ownership(
-                wrapper_fd.get(), is_public, uid, image_path.c_str())) {
+                wrapper_fd.get(), is_public, uid, image_path.c_str(), is_secondary_dex)) {
         ALOGE("installd cannot set owner '%s' for image during dexopt\n", image_path.c_str());
         wrapper_fd.reset(-1);
     }
@@ -1101,7 +1105,7 @@
 // Opens the vdex files and assigns the input fd to in_vdex_wrapper_fd and the output fd to
 // out_vdex_wrapper_fd. Returns true for success or false in case of errors.
 bool open_vdex_files(const char* apk_path, const char* out_oat_path, int dexopt_needed,
-        const char* instruction_set, bool is_public, int uid,
+        const char* instruction_set, bool is_public, int uid, bool is_secondary_dex,
         Dex2oatFileWrapper* in_vdex_wrapper_fd,
         Dex2oatFileWrapper* out_vdex_wrapper_fd) {
     CHECK(in_vdex_wrapper_fd != nullptr);
@@ -1164,7 +1168,7 @@
         }
     }
     if (!set_permissions_and_ownership(out_vdex_wrapper_fd->get(), is_public, uid,
-            out_vdex_path_str.c_str())) {
+            out_vdex_path_str.c_str(), is_secondary_dex)) {
         ALOGE("installd cannot set owner '%s' for vdex during dexopt\n", out_vdex_path_str.c_str());
         return false;
     }
@@ -1187,7 +1191,8 @@
             [out_oat_path_str]() { unlink(out_oat_path_str.c_str()); });
     if (wrapper_fd.get() < 0) {
         PLOG(ERROR) << "installd cannot open output during dexopt" <<  out_oat_path;
-    } else if (!set_permissions_and_ownership(wrapper_fd.get(), is_public, uid, out_oat_path)) {
+    } else if (!set_permissions_and_ownership(
+                wrapper_fd.get(), is_public, uid, out_oat_path, is_secondary_dex)) {
         ALOGE("installd cannot set owner '%s' for output during dexopt\n", out_oat_path);
         wrapper_fd.reset(-1);
     }
@@ -1445,7 +1450,7 @@
     Dex2oatFileWrapper in_vdex_fd;
     Dex2oatFileWrapper out_vdex_fd;
     if (!open_vdex_files(dex_path, out_oat_path, dexopt_needed, instruction_set, is_public, uid,
-            &in_vdex_fd, &out_vdex_fd)) {
+            is_secondary_dex, &in_vdex_fd, &out_vdex_fd)) {
         return -1;
     }
 
@@ -1454,7 +1459,7 @@
 
     // Create the app image file if needed.
     Dex2oatFileWrapper image_fd =
-            maybe_open_app_image(out_oat_path, profile_guided, is_public, uid);
+            maybe_open_app_image(out_oat_path, profile_guided, is_public, uid, is_secondary_dex);
 
     // Open the reference profile if needed.
     Dex2oatFileWrapper reference_profile_fd =
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index c380598..5aab35a 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -22,6 +22,6 @@
         "libhidltransport",
     ],
     srcs: [
-        "lshal.cpp"
+        "Lshal.cpp"
     ],
 }
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
new file mode 100644
index 0000000..ce058c8
--- /dev/null
+++ b/cmds/lshal/Lshal.cpp
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Lshal.h"
+
+#include <getopt.h>
+
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <regex>
+
+#include <android-base/parseint.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <hidl/ServiceManagement.h>
+
+#include "Timeout.h"
+
+using ::android::hardware::hidl_string;
+using ::android::hidl::manager::V1_0::IServiceManager;
+
+namespace android {
+namespace lshal {
+
+template <typename A>
+std::string join(const A &components, const std::string &separator) {
+    std::stringstream out;
+    bool first = true;
+    for (const auto &component : components) {
+        if (!first) {
+            out << separator;
+        }
+        out << component;
+
+        first = false;
+    }
+    return out.str();
+}
+
+static std::string toHexString(uint64_t t) {
+    std::ostringstream os;
+    os << std::hex << std::setfill('0') << std::setw(16) << t;
+    return os.str();
+}
+
+static std::pair<hidl_string, hidl_string> split(const hidl_string &s, char c) {
+    const char *pos = strchr(s.c_str(), c);
+    if (pos == nullptr) {
+        return {s, {}};
+    }
+    return {hidl_string(s.c_str(), pos - s.c_str()), hidl_string(pos + 1)};
+}
+
+static std::vector<std::string> split(const std::string &s, char c) {
+    std::vector<std::string> components{};
+    size_t startPos = 0;
+    size_t matchPos;
+    while ((matchPos = s.find(c, startPos)) != std::string::npos) {
+        components.push_back(s.substr(startPos, matchPos - startPos));
+        startPos = matchPos + 1;
+    }
+
+    if (startPos <= s.length()) {
+        components.push_back(s.substr(startPos));
+    }
+    return components;
+}
+
+std::string getCmdline(pid_t pid) {
+    std::ifstream ifs("/proc/" + std::to_string(pid) + "/cmdline");
+    std::string cmdline;
+    if (!ifs.is_open()) {
+        return "";
+    }
+    ifs >> cmdline;
+    return cmdline;
+}
+
+const std::string &Lshal::getCmdline(pid_t pid) {
+    auto pair = mCmdlines.find(pid);
+    if (pair != mCmdlines.end()) {
+        return pair->second;
+    }
+    mCmdlines[pid] = ::android::lshal::getCmdline(pid);
+    return mCmdlines[pid];
+}
+
+void Lshal::removeDeadProcesses(Pids *pids) {
+    static const pid_t myPid = getpid();
+    std::remove_if(pids->begin(), pids->end(), [this](auto pid) {
+        return pid == myPid || this->getCmdline(pid).empty();
+    });
+}
+
+bool Lshal::getReferencedPids(
+        pid_t serverPid, std::map<uint64_t, Pids> *objects) const {
+
+    std::ifstream ifs("/d/binder/proc/" + std::to_string(serverPid));
+    if (!ifs.is_open()) {
+        return false;
+    }
+
+    static const std::regex prefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
+
+    std::string line;
+    std::smatch match;
+    while(getline(ifs, line)) {
+        if (!std::regex_search(line, match, prefix)) {
+            // the line doesn't start with the correct prefix
+            continue;
+        }
+        std::string ptrString = "0x" + match.str(2); // use number after c
+        uint64_t ptr;
+        if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
+            // Should not reach here, but just be tolerant.
+            mErr << "Could not parse number " << ptrString << std::endl;
+            continue;
+        }
+        const std::string proc = " proc ";
+        auto pos = line.rfind(proc);
+        if (pos != std::string::npos) {
+            for (const std::string &pidStr : split(line.substr(pos + proc.size()), ' ')) {
+                int32_t pid;
+                if (!::android::base::ParseInt(pidStr, &pid)) {
+                    mErr << "Could not parse number " << pidStr << std::endl;
+                    continue;
+                }
+                (*objects)[ptr].push_back(pid);
+            }
+        }
+    }
+    return true;
+}
+
+void Lshal::postprocess() {
+    if (mSortColumn) {
+        std::sort(mTable.begin(), mTable.end(), mSortColumn);
+    }
+    for (TableEntry &entry : mTable) {
+        entry.serverCmdline = getCmdline(entry.serverPid);
+        removeDeadProcesses(&entry.clientPids);
+        for (auto pid : entry.clientPids) {
+            entry.clientCmdlines.push_back(this->getCmdline(pid));
+        }
+    }
+}
+
+void Lshal::printLine(
+        const std::string &interfaceName,
+        const std::string &transport, const std::string &server,
+        const std::string &serverCmdline,
+        const std::string &address, const std::string &clients,
+        const std::string &clientCmdlines) const {
+    if (mSelectedColumns & ENABLE_INTERFACE_NAME)
+        mOut << std::setw(80) << interfaceName << "\t";
+    if (mSelectedColumns & ENABLE_TRANSPORT)
+        mOut << std::setw(10) << transport << "\t";
+    if (mSelectedColumns & ENABLE_SERVER_PID) {
+        if (mEnableCmdlines) {
+            mOut << std::setw(15) << serverCmdline << "\t";
+        } else {
+            mOut << std::setw(5)  << server << "\t";
+        }
+    }
+    if (mSelectedColumns & ENABLE_SERVER_ADDR)
+        mOut << std::setw(16) << address << "\t";
+    if (mSelectedColumns & ENABLE_CLIENT_PIDS) {
+        if (mEnableCmdlines) {
+            mOut << std::setw(0)  << clientCmdlines;
+        } else {
+            mOut << std::setw(0)  << clients;
+        }
+    }
+    mOut << std::endl;
+}
+
+void Lshal::dump() const {
+    mOut << "All services:" << std::endl;
+    mOut << std::left;
+    printLine("Interface", "Transport", "Server", "Server CMD", "PTR", "Clients", "Clients CMD");
+    for (const auto &entry : mTable) {
+        printLine(entry.interfaceName,
+                entry.transport,
+                entry.serverPid == NO_PID ? "N/A" : std::to_string(entry.serverPid),
+                entry.serverCmdline,
+                entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress),
+                join(entry.clientPids, " "),
+                join(entry.clientCmdlines, ";"));
+    }
+}
+
+void Lshal::putEntry(TableEntry &&entry) {
+    mTable.push_back(std::forward<TableEntry>(entry));
+}
+
+Status Lshal::fetchAllLibraries(const sp<IServiceManager> &manager) {
+    using namespace ::android::hardware;
+    using namespace ::android::hidl::manager::V1_0;
+    using namespace ::android::hidl::base::V1_0;
+    auto ret = timeoutIPC(manager, &IServiceManager::list, [&] (const auto &fqInstanceNames) {
+        for (const auto &fqInstanceName : fqInstanceNames) {
+            putEntry({
+                .interfaceName = fqInstanceName,
+                .transport = "passthrough",
+                .serverPid = NO_PID,
+                .serverObjectAddress = NO_PTR,
+                .clientPids = {}
+            });
+        }
+    });
+    if (!ret.isOk()) {
+        mErr << "Error: Failed to call list on getPassthroughServiceManager(): "
+             << ret.description() << std::endl;
+        return DUMP_ALL_LIBS_ERROR;
+    }
+    return OK;
+}
+
+Status Lshal::fetchPassthrough(const sp<IServiceManager> &manager) {
+    using namespace ::android::hardware;
+    using namespace ::android::hidl::manager::V1_0;
+    using namespace ::android::hidl::base::V1_0;
+    auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) {
+        for (const auto &info : infos) {
+            putEntry({
+                .interfaceName =
+                        std::string{info.interfaceName.c_str()} + "/" +
+                        std::string{info.instanceName.c_str()},
+                .transport = "passthrough",
+                .serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID,
+                .serverObjectAddress = NO_PTR,
+                .clientPids = info.clientPids
+            });
+        }
+    });
+    if (!ret.isOk()) {
+        mErr << "Error: Failed to call debugDump on defaultServiceManager(): "
+             << ret.description() << std::endl;
+        return DUMP_PASSTHROUGH_ERROR;
+    }
+    return OK;
+}
+
+Status Lshal::fetchBinderized(const sp<IServiceManager> &manager) {
+    using namespace ::std;
+    using namespace ::android::hardware;
+    using namespace ::android::hidl::manager::V1_0;
+    using namespace ::android::hidl::base::V1_0;
+    const std::string mode = "hwbinder";
+    Status status = OK;
+    auto listRet = timeoutIPC(manager, &IServiceManager::list, [&] (const auto &fqInstanceNames) {
+        // server pid, .ptr value of binder object, child pids
+        std::map<std::string, DebugInfo> allDebugInfos;
+        std::map<pid_t, std::map<uint64_t, Pids>> allPids;
+        for (const auto &fqInstanceName : fqInstanceNames) {
+            const auto pair = split(fqInstanceName, '/');
+            const auto &serviceName = pair.first;
+            const auto &instanceName = pair.second;
+            auto getRet = timeoutIPC(manager, &IServiceManager::get, serviceName, instanceName);
+            if (!getRet.isOk()) {
+                mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
+                     << "cannot be fetched from service manager:"
+                     << getRet.description() << std::endl;
+                status |= DUMP_BINDERIZED_ERROR;
+                continue;
+            }
+            sp<IBase> service = getRet;
+            if (service == nullptr) {
+                mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
+                     << "cannot be fetched from service manager (null)";
+                status |= DUMP_BINDERIZED_ERROR;
+                continue;
+            }
+            auto debugRet = timeoutIPC(service, &IBase::getDebugInfo, [&] (const auto &debugInfo) {
+                allDebugInfos[fqInstanceName] = debugInfo;
+                if (debugInfo.pid >= 0) {
+                    allPids[static_cast<pid_t>(debugInfo.pid)].clear();
+                }
+            });
+            if (!debugRet.isOk()) {
+                mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
+                     << "debugging information cannot be retrieved:"
+                     << debugRet.description() << std::endl;
+                status |= DUMP_BINDERIZED_ERROR;
+            }
+        }
+        for (auto &pair : allPids) {
+            pid_t serverPid = pair.first;
+            if (!getReferencedPids(serverPid, &allPids[serverPid])) {
+                mErr << "Warning: no information for PID " << serverPid
+                          << ", are you root?" << std::endl;
+                status |= DUMP_BINDERIZED_ERROR;
+            }
+        }
+        for (const auto &fqInstanceName : fqInstanceNames) {
+            auto it = allDebugInfos.find(fqInstanceName);
+            if (it == allDebugInfos.end()) {
+                putEntry({
+                    .interfaceName = fqInstanceName,
+                    .transport = mode,
+                    .serverPid = NO_PID,
+                    .serverObjectAddress = NO_PTR,
+                    .clientPids = {}
+                });
+                continue;
+            }
+            const DebugInfo &info = it->second;
+            putEntry({
+                .interfaceName = fqInstanceName,
+                .transport = mode,
+                .serverPid = info.pid,
+                .serverObjectAddress = info.ptr,
+                .clientPids = info.pid == NO_PID || info.ptr == NO_PTR
+                        ? Pids{} : allPids[info.pid][info.ptr]
+            });
+        }
+
+    });
+    if (!listRet.isOk()) {
+        mErr << "Error: Failed to list services for " << mode << ": "
+             << listRet.description() << std::endl;
+        status |= DUMP_BINDERIZED_ERROR;
+    }
+    return status;
+}
+
+Status Lshal::fetch() {
+    Status status = OK;
+    auto bManager = ::android::hardware::defaultServiceManager();
+    if (bManager == nullptr) {
+        mErr << "Failed to get defaultServiceManager()!" << std::endl;
+        status |= NO_BINDERIZED_MANAGER;
+    } else {
+        status |= fetchBinderized(bManager);
+        // Passthrough PIDs are registered to the binderized manager as well.
+        status |= fetchPassthrough(bManager);
+    }
+
+    auto pManager = ::android::hardware::getPassthroughServiceManager();
+    if (pManager == nullptr) {
+        mErr << "Failed to get getPassthroughServiceManager()!" << std::endl;
+        status |= NO_PASSTHROUGH_MANAGER;
+    } else {
+        status |= fetchAllLibraries(pManager);
+    }
+    return status;
+}
+
+void Lshal::usage() const {
+    mErr
+        << "usage: lshal" << std::endl
+        << "           Dump all hals with default ordering and columns [-itpc]." << std::endl
+        << "       lshal [--interface|-i] [--transport|-t]" << std::endl
+        << "             [--pid|-p] [--address|-a] [--clients|-c] [--cmdline|-m]" << std::endl
+        << "             [--sort={interface|i|pid|p}]" << std::endl
+        << "           -i, --interface: print the interface name column" << std::endl
+        << "           -n, --instance: print the instance name column" << std::endl
+        << "           -t, --transport: print the transport mode column" << std::endl
+        << "           -p, --pid: print the server PID, or server cmdline if -m is set" << std::endl
+        << "           -a, --address: print the server object address column" << std::endl
+        << "           -c, --clients: print the client PIDs, or client cmdlines if -m is set"
+                                                                              << std::endl
+        << "           -m, --cmdline: print cmdline instead of PIDs" << std::endl
+        << "           --sort=i, --sort=interface: sort by interface name" << std::endl
+        << "           --sort=p, --sort=pid: sort by server pid" << std::endl
+        << "       lshal [-h|--help]" << std::endl
+        << "           -h, --help: show this help information." << std::endl;
+}
+
+Status Lshal::parseArgs(int argc, char **argv) {
+    static struct option longOptions[] = {
+        // long options with short alternatives
+        {"help",      no_argument,       0, 'h' },
+        {"interface", no_argument,       0, 'i' },
+        {"transport", no_argument,       0, 't' },
+        {"pid",       no_argument,       0, 'p' },
+        {"address",   no_argument,       0, 'a' },
+        {"clients",   no_argument,       0, 'c' },
+        {"cmdline",   no_argument,       0, 'm' },
+
+        // long options without short alternatives
+        {"sort",      required_argument, 0, 's' },
+        { 0,          0,                 0,  0  }
+    };
+
+    int optionIndex;
+    int c;
+    optind = 1;
+    for (;;) {
+        // using getopt_long in case we want to add other options in the future
+        c = getopt_long(argc, argv, "hitpacm", longOptions, &optionIndex);
+        if (c == -1) {
+            break;
+        }
+        switch (c) {
+        case 's': {
+            if (strcmp(optarg, "interface") == 0 || strcmp(optarg, "i") == 0) {
+                mSortColumn = TableEntry::sortByInterfaceName;
+            } else if (strcmp(optarg, "pid") == 0 || strcmp(optarg, "p") == 0) {
+                mSortColumn = TableEntry::sortByServerPid;
+            } else {
+                mErr << "Unrecognized sorting column: " << optarg << std::endl;
+                usage();
+                return USAGE;
+            }
+            break;
+        }
+        case 'i': {
+            mSelectedColumns |= ENABLE_INTERFACE_NAME;
+            break;
+        }
+        case 't': {
+            mSelectedColumns |= ENABLE_TRANSPORT;
+            break;
+        }
+        case 'p': {
+            mSelectedColumns |= ENABLE_SERVER_PID;
+            break;
+        }
+        case 'a': {
+            mSelectedColumns |= ENABLE_SERVER_ADDR;
+            break;
+        }
+        case 'c': {
+            mSelectedColumns |= ENABLE_CLIENT_PIDS;
+            break;
+        }
+        case 'm': {
+            mEnableCmdlines = true;
+            break;
+        }
+        case 'h': // falls through
+        default: // see unrecognized options
+            usage();
+            return USAGE;
+        }
+    }
+
+    if (mSelectedColumns == 0) {
+        mSelectedColumns = ENABLE_INTERFACE_NAME
+                | ENABLE_TRANSPORT | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS;
+    }
+    return OK;
+}
+
+int Lshal::main(int argc, char **argv) {
+    Status status = parseArgs(argc, argv);
+    if (status != OK) {
+        return status;
+    }
+    status = fetch();
+    postprocess();
+    dump();
+    return status;
+}
+
+}  // namespace lshal
+}  // namespace android
+
+int main(int argc, char **argv) {
+    return ::android::lshal::Lshal{}.main(argc, argv);
+}
diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h
new file mode 100644
index 0000000..ead99dc
--- /dev/null
+++ b/cmds/lshal/Lshal.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_LSHAL_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_LSHAL_H_
+
+#include <stdint.h>
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <android/hidl/manager/1.0/IServiceManager.h>
+
+#include "TableEntry.h"
+
+namespace android {
+namespace lshal {
+
+enum : unsigned int {
+    OK                                      = 0,
+    USAGE                                   = 1 << 0,
+    NO_BINDERIZED_MANAGER                   = 1 << 1,
+    NO_PASSTHROUGH_MANAGER                  = 1 << 2,
+    DUMP_BINDERIZED_ERROR                   = 1 << 3,
+    DUMP_PASSTHROUGH_ERROR                  = 1 << 4,
+    DUMP_ALL_LIBS_ERROR                     = 1 << 5,
+};
+using Status = unsigned int;
+
+class Lshal {
+public:
+    int main(int argc, char **argv);
+
+private:
+    Status parseArgs(int argc, char **argv);
+    Status fetch();
+    void postprocess();
+    void dump() const;
+    void usage() const;
+    void putEntry(TableEntry &&entry);
+    Status fetchPassthrough(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
+    Status fetchBinderized(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
+    Status fetchAllLibraries(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
+    bool getReferencedPids(
+        pid_t serverPid, std::map<uint64_t, Pids> *objects) const;
+    void printLine(
+            const std::string &interfaceName,
+            const std::string &transport, const std::string &server,
+            const std::string &serverCmdline,
+            const std::string &address, const std::string &clients,
+            const std::string &clientCmdlines) const ;
+    // Return /proc/{pid}/cmdline if it exists, else empty string.
+    const std::string &getCmdline(pid_t pid);
+    // Call getCmdline on all pid in pids. If it returns empty string, the process might
+    // have died, and the pid is removed from pids.
+    void removeDeadProcesses(Pids *pids);
+
+    Table mTable{};
+    std::ostream &mErr = std::cerr;
+    std::ostream &mOut = std::cout;
+    TableEntryCompare mSortColumn = nullptr;
+    TableEntrySelect mSelectedColumns = 0;
+    // If true, cmdlines will be printed instead of pid.
+    bool mEnableCmdlines;
+    // 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.
+    // If an entry exist and not empty, it contains the cached content of /proc/{pid}/cmdline.
+    std::map<pid_t, std::string> mCmdlines;
+};
+
+
+}  // namespace lshal
+}  // namespace android
+
+#endif  // FRAMEWORK_NATIVE_CMDS_LSHAL_LSHAL_H_
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
new file mode 100644
index 0000000..4ec3a0c
--- /dev/null
+++ b/cmds/lshal/TableEntry.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_TABLE_ENTRY_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_TABLE_ENTRY_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+#include <iostream>
+
+namespace android {
+namespace lshal {
+
+using Pids = std::vector<int32_t>;
+
+struct TableEntry {
+    std::string interfaceName;
+    std::string transport;
+    int32_t serverPid;
+    std::string serverCmdline;
+    uint64_t serverObjectAddress;
+    Pids clientPids;
+    std::vector<std::string> clientCmdlines;
+
+    static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) {
+        return a.interfaceName < b.interfaceName;
+    };
+    static bool sortByServerPid(const TableEntry &a, const TableEntry &b) {
+        return a.serverPid < b.serverPid;
+    };
+};
+
+using Table = std::vector<TableEntry>;
+using TableEntryCompare = std::function<bool(const TableEntry &, const TableEntry &)>;
+
+enum : unsigned int {
+    ENABLE_INTERFACE_NAME = 1 << 0,
+    ENABLE_TRANSPORT      = 1 << 1,
+    ENABLE_SERVER_PID     = 1 << 2,
+    ENABLE_SERVER_ADDR    = 1 << 3,
+    ENABLE_CLIENT_PIDS    = 1 << 4
+};
+
+using TableEntrySelect = unsigned int;
+
+enum {
+    NO_PID = -1,
+    NO_PTR = 0
+};
+
+}  // namespace lshal
+}  // namespace android
+
+#endif  // FRAMEWORK_NATIVE_CMDS_LSHAL_TABLE_ENTRY_H_
diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h
new file mode 100644
index 0000000..bf883c0
--- /dev/null
+++ b/cmds/lshal/Timeout.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <condition_variable>
+#include <chrono>
+#include <functional>
+#include <mutex>
+#include <thread>
+
+#include <hidl/Status.h>
+
+namespace android {
+namespace lshal {
+
+static constexpr std::chrono::milliseconds IPC_CALL_WAIT{500};
+
+class BackgroundTaskState {
+public:
+    BackgroundTaskState(){}
+    void notify() {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mFinished = true;
+        lock.unlock();
+        mCondVar.notify_all();
+    }
+    template<class C, class D>
+    bool wait(std::chrono::time_point<C, D> end) {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mCondVar.wait_until(lock, end, [this](){ return this->mFinished; });
+        return mFinished;
+    }
+private:
+    std::mutex mMutex;
+    std::condition_variable mCondVar;
+    bool mFinished = false;
+};
+
+template<class R, class P>
+bool timeout(std::chrono::duration<R, P> delay, const std::function<void(void)> &func) {
+    auto now = std::chrono::system_clock::now();
+    BackgroundTaskState state{};
+    std::thread t([&state, &func] {
+        func();
+        state.notify();
+    });
+    t.detach();
+    bool success = state.wait(now + delay);
+    return success;
+}
+
+template<class Function, class I, class... Args>
+typename std::result_of<Function(I *, Args...)>::type
+timeoutIPC(const sp<I> &interfaceObject, Function &&func, Args &&... args) {
+    using ::android::hardware::Status;
+    typename std::result_of<Function(I *, Args...)>::type ret{Status::ok()};
+    auto boundFunc = std::bind(std::forward<Function>(func),
+            interfaceObject.get(), std::forward<Args>(args)...);
+    bool success = timeout(IPC_CALL_WAIT, [&ret, &boundFunc] {
+        ret = boundFunc();
+    });
+    if (!success) {
+        return Status::fromStatusT(TIMED_OUT);
+    }
+    return ret;
+}
+
+}  // namespace lshal
+}  // namespace android
diff --git a/cmds/lshal/lshal.cpp b/cmds/lshal/lshal.cpp
deleted file mode 100644
index 9998a46..0000000
--- a/cmds/lshal/lshal.cpp
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#include <getopt.h>
-
-#include <map>
-#include <fstream>
-#include <iomanip>
-#include <iostream>
-#include <sstream>
-#include <regex>
-
-#include <android-base/parseint.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
-#include <hidl/ServiceManagement.h>
-
-using ::android::sp;
-using ::android::hardware::hidl_string;
-using ::android::hidl::manager::V1_0::IServiceManager;
-
-template <typename A, typename B, typename C, typename D, typename E, typename F>
-void printColumn(std::stringstream &stream,
-        const A &a, const B &b, const C &c, const D &d, const E &, const F &f) {
-    using namespace ::std;
-    stream << left
-           << setw(70) << a << "\t"
-           << setw(20) << b << "\t"
-           << setw(10) << c << "\t"
-           << setw(5)  << d << "\t"
-           // TODO(b/34984175): enable selecting columns
-           // << setw(16) << e << "\t"
-           << setw(0)  << f
-           << endl;
-}
-
-template <typename A>
-std::string join(const A &components, const std::string &separator) {
-    std::stringstream out;
-    bool first = true;
-    for (const auto &component : components) {
-        if (!first) {
-            out << separator;
-        }
-        out << component;
-
-        first = false;
-    }
-    return out.str();
-}
-
-std::string toHexString(uint64_t t) {
-    std::ostringstream os;
-    os << std::hex << std::setfill('0') << std::setw(16) << t;
-    return os.str();
-}
-
-std::pair<hidl_string, hidl_string> split(const hidl_string &s, char c) {
-    const char *pos = strchr(s.c_str(), c);
-    if (pos == nullptr) {
-        return {s, {}};
-    }
-    return {hidl_string(s.c_str(), pos - s.c_str()), hidl_string(pos + 1)};
-}
-
-bool getReferencedPids(
-        pid_t serverPid, std::map<uint64_t, std::string> *objects) {
-
-    std::ifstream ifs("/d/binder/proc/" + std::to_string(serverPid));
-    if (!ifs.is_open()) {
-        return false;
-    }
-
-    static const std::regex prefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
-
-    std::string line;
-    std::smatch match;
-    while(getline(ifs, line)) {
-        if (!std::regex_search(line, match, prefix)) {
-            // the line doesn't start with the correct prefix
-            continue;
-        }
-        std::string ptrString = "0x" + match.str(2); // use number after c
-        uint64_t ptr;
-        if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
-            // Should not reach here, but just be tolerant.
-            std::cerr << "Could not parse number " << ptrString << std::endl;
-            continue;
-        }
-        const std::string proc = " proc ";
-        auto pos = line.rfind(proc);
-        if (pos != std::string::npos) {
-            (*objects)[ptr] += line.substr(pos + proc.size());
-        }
-    }
-    return true;
-}
-
-void dumpAllLibraries(std::stringstream &stream, const std::string &mode,
-            const sp<IServiceManager> &manager) {
-    using namespace ::std;
-    using namespace ::android::hardware;
-    using namespace ::android::hidl::manager::V1_0;
-    using namespace ::android::hidl::base::V1_0;
-    auto ret = manager->list([&] (const auto &fqInstanceNames) {
-        for (const auto &fqInstanceName : fqInstanceNames) {
-            const auto pair = split(fqInstanceName, '/');
-            const auto &serviceName = pair.first;
-            const auto &instanceName = pair.second;
-            printColumn(stream,
-                serviceName,
-                instanceName,
-                mode,
-                "N/A",
-                "N/A",
-                "N/A");
-        }
-    });
-    if (!ret.isOk()) {
-        cerr << "Error: Failed to call debugDump on defaultServiceManager(): "
-             << ret.description() << endl;
-    }
-}
-
-void dumpPassthrough(std::stringstream &stream, const std::string &mode,
-            const sp<IServiceManager> &manager) {
-    using namespace ::std;
-    using namespace ::android::hardware;
-    using namespace ::android::hidl::manager::V1_0;
-    using namespace ::android::hidl::base::V1_0;
-    auto ret = manager->debugDump([&] (const auto &infos) {
-        for (const auto &info : infos) {
-
-            printColumn(stream,
-                info.interfaceName,
-                info.instanceName,
-                mode,
-                info.clientPids.size() == 1 ? std::to_string(info.clientPids[0]) : "N/A",
-                "N/A",
-                join(info.clientPids, " "));
-        }
-    });
-    if (!ret.isOk()) {
-        cerr << "Error: Failed to call debugDump on defaultServiceManager(): "
-             << ret.description() << endl;
-    }
-}
-
-void dumpBinderized(std::stringstream &stream, const std::string &mode,
-            const sp<IServiceManager> &manager) {
-    using namespace ::std;
-    using namespace ::android::hardware;
-    using namespace ::android::hidl::manager::V1_0;
-    using namespace ::android::hidl::base::V1_0;
-    auto listRet = manager->list([&] (const auto &fqInstanceNames) {
-        // server pid, .ptr value of binder object, child pids
-        std::map<std::string, DebugInfo> allDebugInfos;
-        std::map<pid_t, std::map<uint64_t, std::string>> allPids;
-        for (const auto &fqInstanceName : fqInstanceNames) {
-            const auto pair = split(fqInstanceName, '/');
-            const auto &serviceName = pair.first;
-            const auto &instanceName = pair.second;
-            auto getRet = manager->get(serviceName, instanceName);
-            if (!getRet.isOk()) {
-                cerr << "Warning: Skipping \"" << fqInstanceName << "\": "
-                     << "cannot be fetched from service manager:"
-                     << getRet.description() << endl;
-                continue;
-            }
-            sp<IBase> service = getRet;
-            if (service == nullptr) {
-                cerr << "Warning: Skipping \"" << fqInstanceName << "\": "
-                     << "cannot be fetched from service manager (null)";
-                continue;
-            }
-            auto debugRet = service->getDebugInfo([&] (const auto &debugInfo) {
-                allDebugInfos[fqInstanceName] = debugInfo;
-                if (debugInfo.pid >= 0) {
-                    allPids[static_cast<pid_t>(debugInfo.pid)].clear();
-                }
-            });
-            if (!debugRet.isOk()) {
-                cerr << "Warning: Skipping \"" << fqInstanceName << "\": "
-                     << "debugging information cannot be retrieved:"
-                     << debugRet.description() << endl;
-            }
-        }
-        for (auto &pair : allPids) {
-            pid_t serverPid = pair.first;
-            if (!getReferencedPids(serverPid, &allPids[serverPid])) {
-                std::cerr << "Warning: no information for PID " << serverPid
-                          << ", are you root?" << std::endl;
-            }
-        }
-        for (const auto &fqInstanceName : fqInstanceNames) {
-            const auto pair = split(fqInstanceName, '/');
-            const auto &serviceName = pair.first;
-            const auto &instanceName = pair.second;
-            auto it = allDebugInfos.find(fqInstanceName);
-            if (it == allDebugInfos.end()) {
-                printColumn(stream,
-                    serviceName,
-                    instanceName,
-                    mode,
-                    "N/A",
-                    "N/A",
-                    ""
-                );
-                continue;
-            }
-            const DebugInfo &info = it->second;
-            printColumn(stream,
-                serviceName,
-                instanceName,
-                mode,
-                info.pid < 0 ? "N/A" : std::to_string(info.pid),
-                info.ptr == 0 ? "N/A" : toHexString(info.ptr),
-                info.pid < 0 || info.ptr == 0 ? "" : allPids[info.pid][info.ptr]
-            );
-        }
-
-    });
-    if (!listRet.isOk()) {
-        cerr << "Error: Failed to list services for " << mode << ": "
-             << listRet.description() << endl;
-    }
-}
-
-int dump() {
-    using namespace ::std;
-    using namespace ::android::hardware;
-
-    std::stringstream stream;
-
-    stream << "All services:" << endl;
-    stream << left;
-    printColumn(stream, "Interface", "Instance", "Transport", "Server", "PTR", "Clients");
-
-    auto bManager = defaultServiceManager();
-    if (bManager == nullptr) {
-        cerr << "Failed to get defaultServiceManager()!" << endl;
-    } else {
-        dumpBinderized(stream, "hwbinder", bManager);
-        // Passthrough PIDs are registered to the binderized manager as well.
-        dumpPassthrough(stream, "passthrough", bManager);
-    }
-
-    auto pManager = getPassthroughServiceManager();
-    if (pManager == nullptr) {
-        cerr << "Failed to get getPassthroughServiceManager()!" << endl;
-    } else {
-        dumpAllLibraries(stream, "passthrough", pManager);
-    }
-
-    cout << stream.rdbuf();
-    return 0;
-}
-
-int usage() {
-    using namespace ::std;
-    cerr
-        << "usage: lshal" << endl
-        << "           To dump all hals." << endl
-        << "or:" << endl
-        << "       lshal [-h|--help]" << endl
-        << "           -h, --help: show this help information." << endl;
-    return -1;
-}
-
-int main(int argc, char **argv) {
-    static struct option longOptions[] = {
-        {"help", no_argument, 0, 'h' },
-        { 0,               0, 0,  0  }
-    };
-
-    int optionIndex;
-    int c;
-    optind = 1;
-    for (;;) {
-        // using getopt_long in case we want to add other options in the future
-        c = getopt_long(argc, argv, "h", longOptions, &optionIndex);
-        if (c == -1) {
-            break;
-        }
-        switch (c) {
-        case 'h': // falls through
-        default: // see unrecognized options
-            return usage();
-        }
-    }
-    return dump();
-
-}
diff --git a/include/audiomanager/IPlayer.h b/include/audiomanager/IPlayer.h
index 94afae5..de5c1c7 100644
--- a/include/audiomanager/IPlayer.h
+++ b/include/audiomanager/IPlayer.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <media/VolumeShaper.h>
 #include <utils/RefBase.h>
 #include <utils/Errors.h>
 #include <binder/IInterface.h>
@@ -45,6 +46,9 @@
 
     virtual void setStartDelayMs(int delayMs) = 0;
 
+    virtual void applyVolumeShaper(
+            const sp<VolumeShaper::Configuration>& configuration,
+            const sp<VolumeShaper::Operation>& operation) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h
index 46ca2c2..9e1ae94 100644
--- a/include/gui/FrameTimestamps.h
+++ b/include/gui/FrameTimestamps.h
@@ -95,6 +95,11 @@
     std::shared_ptr<FenceTime> releaseFence{FenceTime::NO_FENCE};
 };
 
+struct CompositorTiming {
+    nsecs_t deadline{0};
+    nsecs_t interval{16666667};
+    nsecs_t presentLatency{0};
+};
 
 // A short history of frames that are synchronized between the consumer and
 // producer via deltas.
@@ -111,6 +116,8 @@
 
 protected:
     std::array<FrameEvents, MAX_FRAME_HISTORY> mFrames;
+
+    CompositorTiming mCompositorTiming;
 };
 
 
@@ -119,6 +126,16 @@
 public:
     ~ProducerFrameEventHistory() override;
 
+    // Public for testing.
+    static nsecs_t snapToNextTick(
+            nsecs_t timestamp, nsecs_t tickPhase, nsecs_t tickInterval);
+
+    nsecs_t getNextCompositeDeadline(const nsecs_t now) const;
+    nsecs_t getCompositeInterval() const { return mCompositorTiming.interval; }
+    nsecs_t getCompositeToPresentLatency() const {
+        return mCompositorTiming.presentLatency;
+    }
+
     // virtual for testing.
     virtual void updateAcquireFence(
             uint64_t frameNumber, std::shared_ptr<FenceTime>&& acquire);
@@ -189,12 +206,15 @@
 public:
     ~ConsumerFrameEventHistory() override;
 
+    void initializeCompositorTiming(const CompositorTiming& compositorTiming);
+
     void addQueue(const NewFrameEventsEntry& newEntry);
     void addLatch(uint64_t frameNumber, nsecs_t latchTime);
     void addPreComposition(uint64_t frameNumber, nsecs_t refreshStartTime);
     void addPostComposition(uint64_t frameNumber,
             const std::shared_ptr<FenceTime>& gpuCompositionDone,
-            const std::shared_ptr<FenceTime>& displayPresent);
+            const std::shared_ptr<FenceTime>& displayPresent,
+            const CompositorTiming& compositorTiming);
     void addRetire(uint64_t frameNumber,
             const std::shared_ptr<FenceTime>& displayRetire);
     void addRelease(uint64_t frameNumber, nsecs_t dequeueReadyTime,
@@ -244,7 +264,7 @@
             size_t& count);
 
 private:
-    static size_t minFlattenedSize();
+    static constexpr size_t minFlattenedSize();
 
     size_t mIndex{0};
     uint64_t mFrameNumber{0};
@@ -306,9 +326,10 @@
             size_t& count);
 
 private:
-    static size_t minFlattenedSize();
+    static constexpr size_t minFlattenedSize();
 
     std::vector<FrameEventsDelta> mDeltas;
+    CompositorTiming mCompositorTiming;
 };
 
 
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 966e70d..a3c2bfa 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -135,12 +135,18 @@
     status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence, float outTransformMatrix[16]);
 
+    status_t getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration);
+
     /* Enables or disables frame timestamp tracking. It is disabled by default
      * to avoid overhead during queue and dequeue for applications that don't
      * need the feature. If disabled, calls to getFrameTimestamps will fail.
      */
     void enableFrameTimestamps(bool enable);
 
+    status_t getCompositorTiming(
+            nsecs_t* compositeDeadline, nsecs_t* compositeInterval,
+            nsecs_t* compositeToPresentLatency);
+
     // See IGraphicBufferProducer::getFrameTimestamps
     status_t getFrameTimestamps(uint64_t frameNumber,
             nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
@@ -148,7 +154,6 @@
             nsecs_t* outLastRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
             nsecs_t* outDisplayPresentTime, nsecs_t* outDisplayRetireTime,
             nsecs_t* outDequeueReadyTime, nsecs_t* outReleaseTime);
-    status_t getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration);
 
     status_t getUniqueId(uint64_t* outId) const;
 
@@ -157,6 +162,7 @@
 
     // Virtual for testing.
     virtual sp<ISurfaceComposer> composerService() const;
+    virtual nsecs_t now() const;
 
 private:
     // can't be copied
@@ -204,10 +210,11 @@
     int dispatchSetSurfaceDamage(va_list args);
     int dispatchSetSharedBufferMode(va_list args);
     int dispatchSetAutoRefresh(va_list args);
+    int dispatchGetDisplayRefreshCycleDuration(va_list args);
     int dispatchGetNextFrameId(va_list args);
     int dispatchEnableFrameTimestamps(va_list args);
+    int dispatchGetCompositorTiming(va_list args);
     int dispatchGetFrameTimestamps(va_list args);
-    int dispatchGetDisplayRefreshCycleDuration(va_list args);
 
 protected:
     virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index 73537bf..a6fa38a 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -235,6 +235,23 @@
 
 ProducerFrameEventHistory::~ProducerFrameEventHistory() = default;
 
+nsecs_t ProducerFrameEventHistory::snapToNextTick(
+        nsecs_t timestamp, nsecs_t tickPhase, nsecs_t tickInterval) {
+    nsecs_t tickOffset = (tickPhase - timestamp) % tickInterval;
+    // Integer modulo rounds towards 0 and not -inf before taking the remainder,
+    // so adjust the offset if it is negative.
+    if (tickOffset < 0) {
+        tickOffset += tickInterval;
+    }
+    return timestamp + tickOffset;
+}
+
+nsecs_t ProducerFrameEventHistory::getNextCompositeDeadline(
+        const nsecs_t now) const{
+    return snapToNextTick(
+            now, mCompositorTiming.deadline, mCompositorTiming.interval);
+}
+
 void ProducerFrameEventHistory::updateAcquireFence(
         uint64_t frameNumber, std::shared_ptr<FenceTime>&& acquire) {
     FrameEvents* frame = getFrame(frameNumber, &mAcquireOffset);
@@ -256,6 +273,8 @@
 
 void ProducerFrameEventHistory::applyDelta(
         const FrameEventHistoryDelta& delta) {
+    mCompositorTiming = delta.mCompositorTiming;
+
     for (auto& d : delta.mDeltas) {
         // Avoid out-of-bounds access.
         if (d.mIndex >= mFrames.size()) {
@@ -346,6 +365,11 @@
 
 ConsumerFrameEventHistory::~ConsumerFrameEventHistory() = default;
 
+void ConsumerFrameEventHistory::initializeCompositorTiming(
+        const CompositorTiming& compositorTiming) {
+    mCompositorTiming = compositorTiming;
+}
+
 void ConsumerFrameEventHistory::addQueue(const NewFrameEventsEntry& newEntry) {
     // Overwrite all fields of the frame with default values unless set here.
     FrameEvents newTimestamps;
@@ -393,7 +417,10 @@
 
 void ConsumerFrameEventHistory::addPostComposition(uint64_t frameNumber,
         const std::shared_ptr<FenceTime>& gpuCompositionDone,
-        const std::shared_ptr<FenceTime>& displayPresent) {
+        const std::shared_ptr<FenceTime>& displayPresent,
+        const CompositorTiming& compositorTiming) {
+    mCompositorTiming = compositorTiming;
+
     FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
     if (frame == nullptr) {
         ALOGE_IF(mProducerWantsEvents,
@@ -450,6 +477,8 @@
 
 void ConsumerFrameEventHistory::getAndResetDelta(
         FrameEventHistoryDelta* delta) {
+    delta->mCompositorTiming = mCompositorTiming;
+
     // Write these in order of frame number so that it is easy to
     // add them to a FenceTimeline in the proper order producer side.
     delta->mDeltas.reserve(mFramesDirty.size());
@@ -499,9 +528,8 @@
     }
 }
 
-size_t FrameEventsDelta::minFlattenedSize() {
-    constexpr size_t min =
-            sizeof(FrameEventsDelta::mFrameNumber) +
+constexpr size_t FrameEventsDelta::minFlattenedSize() {
+    return sizeof(FrameEventsDelta::mFrameNumber) +
             sizeof(uint8_t) + // mIndex
             sizeof(uint8_t) + // mAddPostCompositeCalled
             sizeof(uint8_t) + // mAddRetireCalled
@@ -512,7 +540,6 @@
             sizeof(FrameEventsDelta::mFirstRefreshStartTime) +
             sizeof(FrameEventsDelta::mLastRefreshStartTime) +
             sizeof(FrameEventsDelta::mDequeueReadyTime);
-    return min;
 }
 
 // Flattenable implementation
@@ -618,6 +645,8 @@
 
 FrameEventHistoryDelta& FrameEventHistoryDelta::operator=(
         FrameEventHistoryDelta&& src) {
+    mCompositorTiming = src.mCompositorTiming;
+
     if (CC_UNLIKELY(!mDeltas.empty())) {
         ALOGE("FrameEventHistoryDelta: Clobbering history.");
     }
@@ -626,8 +655,9 @@
     return *this;
 }
 
-size_t FrameEventHistoryDelta::minFlattenedSize() {
-    return sizeof(uint32_t);
+constexpr size_t FrameEventHistoryDelta::minFlattenedSize() {
+    return sizeof(uint32_t) + // mDeltas.size()
+            sizeof(mCompositorTiming);
 }
 
 size_t FrameEventHistoryDelta::getFlattenedSize() const {
@@ -654,6 +684,8 @@
         return NO_MEMORY;
     }
 
+    FlattenableUtils::write(buffer, size, mCompositorTiming);
+
     FlattenableUtils::write(
             buffer, size, static_cast<uint32_t>(mDeltas.size()));
     for (auto& d : mDeltas) {
@@ -671,6 +703,8 @@
         return NO_MEMORY;
     }
 
+    FlattenableUtils::read(buffer, size, mCompositorTiming);
+
     uint32_t deltaCount = 0;
     FlattenableUtils::read(buffer, size, deltaCount);
     if (deltaCount > FrameEventHistory::MAX_FRAME_HISTORY) {
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index d1f9f6a..d285ef0 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -100,6 +100,10 @@
     return ComposerService::getComposerService();
 }
 
+nsecs_t Surface::now() const {
+    return systemTime();
+}
+
 sp<IGraphicBufferProducer> Surface::getIGraphicBufferProducer() const {
     return mGraphicBufferProducer;
 }
@@ -142,11 +146,51 @@
             outTransformMatrix);
 }
 
+status_t Surface::getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration) {
+    ATRACE_CALL();
+
+    DisplayStatInfo stats;
+    status_t err = composerService()->getDisplayStats(NULL, &stats);
+
+    *outRefreshDuration = stats.vsyncPeriod;
+
+    return NO_ERROR;
+}
+
 void Surface::enableFrameTimestamps(bool enable) {
     Mutex::Autolock lock(mMutex);
+    // If going from disabled to enabled, get the initial values for
+    // compositor and display timing.
+    if (!mEnableFrameTimestamps && enable) {
+        FrameEventHistoryDelta delta;
+        mGraphicBufferProducer->getFrameTimestamps(&delta);
+        mFrameEventHistory->applyDelta(delta);
+    }
     mEnableFrameTimestamps = enable;
 }
 
+status_t Surface::getCompositorTiming(
+        nsecs_t* compositeDeadline, nsecs_t* compositeInterval,
+        nsecs_t* compositeToPresentLatency) {
+    Mutex::Autolock lock(mMutex);
+    if (!mEnableFrameTimestamps) {
+        return INVALID_OPERATION;
+    }
+
+    if (compositeDeadline != nullptr) {
+        *compositeDeadline =
+                mFrameEventHistory->getNextCompositeDeadline(now());
+    }
+    if (compositeInterval != nullptr) {
+        *compositeInterval = mFrameEventHistory->getCompositeInterval();
+    }
+    if (compositeToPresentLatency != nullptr) {
+        *compositeToPresentLatency =
+                mFrameEventHistory->getCompositeToPresentLatency();
+    }
+    return NO_ERROR;
+}
+
 static bool checkConsumerForUpdates(
         const FrameEvents* e, const uint64_t lastFrameNumber,
         const nsecs_t* outLatchTime,
@@ -260,16 +304,6 @@
 
     return NO_ERROR;
 }
-status_t Surface::getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration) {
-    ATRACE_CALL();
-
-    DisplayStatInfo stats;
-    status_t err = composerService()->getDisplayStats(NULL, &stats);
-
-    *outRefreshDuration = stats.vsyncPeriod;
-
-    return NO_ERROR;
-}
 
 int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) {
     Surface* c = getSelf(window);
@@ -831,18 +865,21 @@
     case NATIVE_WINDOW_SET_AUTO_REFRESH:
         res = dispatchSetAutoRefresh(args);
         break;
+    case NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION:
+        res = dispatchGetDisplayRefreshCycleDuration(args);
+        break;
     case NATIVE_WINDOW_GET_NEXT_FRAME_ID:
         res = dispatchGetNextFrameId(args);
         break;
     case NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS:
         res = dispatchEnableFrameTimestamps(args);
         break;
+    case NATIVE_WINDOW_GET_COMPOSITOR_TIMING:
+        res = dispatchGetCompositorTiming(args);
+        break;
     case NATIVE_WINDOW_GET_FRAME_TIMESTAMPS:
         res = dispatchGetFrameTimestamps(args);
         break;
-    case NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION:
-        res = dispatchGetDisplayRefreshCycleDuration(args);
-        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -963,6 +1000,11 @@
     return setAutoRefresh(autoRefresh);
 }
 
+int Surface::dispatchGetDisplayRefreshCycleDuration(va_list args) {
+    nsecs_t* outRefreshDuration = va_arg(args, int64_t*);
+    return getDisplayRefreshCycleDuration(outRefreshDuration);
+}
+
 int Surface::dispatchGetNextFrameId(va_list args) {
     uint64_t* nextFrameId = va_arg(args, uint64_t*);
     *nextFrameId = getNextFrameNumber();
@@ -975,6 +1017,14 @@
     return NO_ERROR;
 }
 
+int Surface::dispatchGetCompositorTiming(va_list args) {
+    nsecs_t* compositeDeadline = va_arg(args, int64_t*);
+    nsecs_t* compositeInterval = va_arg(args, int64_t*);
+    nsecs_t* compositeToPresentLatency = va_arg(args, int64_t*);
+    return getCompositorTiming(compositeDeadline, compositeInterval,
+            compositeToPresentLatency);
+}
+
 int Surface::dispatchGetFrameTimestamps(va_list args) {
     uint64_t frameId = va_arg(args, uint64_t);
     nsecs_t* outRequestedPresentTime = va_arg(args, int64_t*);
@@ -994,11 +1044,6 @@
             outDisplayRetireTime, outDequeueReadyTime, outReleaseTime);
 }
 
-int Surface::dispatchGetDisplayRefreshCycleDuration(va_list args) {
-    nsecs_t* outRefreshDuration = va_arg(args, int64_t*);
-    return getDisplayRefreshCycleDuration(outRefreshDuration);
-}
-
 int Surface::connect(int api) {
     static sp<IProducerListener> listener = new DummyProducerListener();
     return connect(api, listener);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 3f56665..5298027 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -479,8 +479,17 @@
         return mFakeSurfaceComposer;
     }
 
+    nsecs_t now() const override {
+        return mNow;
+    }
+
+    void setNow(nsecs_t now) {
+        mNow = now;
+    }
+
 public:
     sp<FakeSurfaceComposer> mFakeSurfaceComposer;
+    nsecs_t mNow = 0;
 
     // mFrameEventHistory owns the instance of FakeProducerFrameEventHistory,
     // but this raw pointer gives access to test functionality.
@@ -500,10 +509,12 @@
 
     struct RefreshEvents {
         RefreshEvents(FenceToFenceTimeMap& fenceMap, nsecs_t refreshStart)
-            : mFenceMap(fenceMap),
-              kStartTime(refreshStart + 1),
-              kGpuCompositionDoneTime(refreshStart + 2),
-              kPresentTime(refreshStart + 3) {}
+          : mFenceMap(fenceMap),
+            kCompositorTiming(
+                {refreshStart, refreshStart + 1, refreshStart + 2 }),
+            kStartTime(refreshStart + 3),
+            kGpuCompositionDoneTime(refreshStart + 4),
+            kPresentTime(refreshStart + 5) {}
 
         void signalPostCompositeFences() {
             mFenceMap.signalAllForTest(
@@ -516,6 +527,8 @@
         FenceAndFenceTime mGpuCompositionDone { mFenceMap };
         FenceAndFenceTime mPresent { mFenceMap };
 
+        const CompositorTiming kCompositorTiming;
+
         const nsecs_t kStartTime;
         const nsecs_t kGpuCompositionDoneTime;
         const nsecs_t kPresentTime;
@@ -592,6 +605,12 @@
         native_window_set_buffer_count(mWindow.get(), 4);
     }
 
+    void disableFrameTimestamps() {
+        mFakeConsumer->mGetFrameTimestampsEnabled = false;
+        native_window_enable_frame_timestamps(mWindow.get(), 0);
+        mFrameTimestampsEnabled = false;
+    }
+
     void enableFrameTimestamps() {
         mFakeConsumer->mGetFrameTimestampsEnabled = true;
         native_window_enable_frame_timestamps(mWindow.get(), 1);
@@ -681,7 +700,8 @@
                     oldFrame->mRefreshes[2].mGpuCompositionDone.mFenceTime :
                     FenceTime::NO_FENCE;
             mCfeh->addPostComposition(nOldFrame, gpuDoneFenceTime,
-                    oldFrame->mRefreshes[2].mPresent.mFenceTime);
+                    oldFrame->mRefreshes[2].mPresent.mFenceTime,
+                    oldFrame->mRefreshes[2].kCompositorTiming);
         }
 
         // Latch the new frame.
@@ -698,7 +718,8 @@
                     std::shared_ptr<FenceTime>(oldFrame->mRelease.mFenceTime));
         }
         mCfeh->addPostComposition(nNewFrame, gpuDoneFenceTime,
-                newFrame->mRefreshes[0].mPresent.mFenceTime);
+                newFrame->mRefreshes[0].mPresent.mFenceTime,
+                newFrame->mRefreshes[0].kCompositorTiming);
 
         // Retire the previous buffer just after compositing the new buffer.
         if (oldFrame != nullptr) {
@@ -710,7 +731,8 @@
                 newFrame->mRefreshes[1].mGpuCompositionDone.mFenceTime :
                 FenceTime::NO_FENCE;
         mCfeh->addPostComposition(nNewFrame, gpuDoneFenceTime,
-                newFrame->mRefreshes[1].mPresent.mFenceTime);
+                newFrame->mRefreshes[1].mPresent.mFenceTime,
+                newFrame->mRefreshes[1].kCompositorTiming);
     }
 
     void QueryPresentRetireSupported(
@@ -740,7 +762,8 @@
     int64_t outDequeueReadyTime = -1;
     int64_t outReleaseTime = -1;
 
-    FrameEvents mFrames[2] { { mFenceMap, 1000 }, { mFenceMap, 2000 } };
+    FrameEvents mFrames[3] {
+        { mFenceMap, 1000 }, { mFenceMap, 2000 }, { mFenceMap, 3000 } };
 };
 
 
@@ -773,25 +796,55 @@
     int result = getAllFrameTimestamps(fId);
     EXPECT_EQ(INVALID_OPERATION, result);
     EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
+
+    // Verify compositor timing query fails.
+    nsecs_t compositeDeadline = 0;
+    nsecs_t compositeInterval = 0;
+    nsecs_t compositeToPresentLatency = 0;
+    result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(INVALID_OPERATION, result);
 }
 
 // This test verifies that the frame timestamps are retrieved if explicitly
 // enabled via native_window_enable_frame_timestamps.
 TEST_F(GetFrameTimestampsTest, EnabledSimple) {
+    CompositorTiming initialCompositorTiming {
+        1000000000, // 1s deadline
+        16666667, // 16ms interval
+        50000000, // 50ms present latency
+    };
+    mCfeh->initializeCompositorTiming(initialCompositorTiming);
+
     enableFrameTimestamps();
 
+    // Verify the compositor timing query gets the initial compositor values
+    // after timststamps are enabled; even before the first frame is queued
+    // or dequeued.
+    nsecs_t compositeDeadline = 0;
+    nsecs_t compositeInterval = 0;
+    nsecs_t compositeToPresentLatency = 0;
+    mSurface->setNow(initialCompositorTiming.deadline - 1);
+    int result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(initialCompositorTiming.deadline, compositeDeadline);
+    EXPECT_EQ(initialCompositorTiming.interval, compositeInterval);
+    EXPECT_EQ(initialCompositorTiming.presentLatency,
+              compositeToPresentLatency);
+
     int fence;
     ANativeWindowBuffer* buffer;
 
     EXPECT_EQ(0, mFakeConsumer->mAddFrameTimestampsCount);
-    EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(1, mFakeConsumer->mGetFrameTimestampsCount);
 
     const uint64_t fId1 = getNextFrameId();
 
     // Verify getFrameTimestamps is piggybacked on dequeue.
     ASSERT_EQ(NO_ERROR, mWindow->dequeueBuffer(mWindow.get(), &buffer, &fence));
     EXPECT_EQ(0, mFakeConsumer->mAddFrameTimestampsCount);
-    EXPECT_EQ(1, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(2, mFakeConsumer->mGetFrameTimestampsCount);
 
     NewFrameEventsEntry f1;
     f1.frameNumber = 1;
@@ -808,13 +861,13 @@
     ASSERT_EQ(NO_ERROR, mWindow->queueBuffer(mWindow.get(), buffer, fence));
     EXPECT_EQ(1, mFakeConsumer->mAddFrameTimestampsCount);
     EXPECT_EQ(1u, mFakeConsumer->mLastAddedFrameNumber);
-    EXPECT_EQ(2, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(3, mFakeConsumer->mGetFrameTimestampsCount);
 
     // Verify queries for timestamps that the producer doesn't know about
     // triggers a call to see if the consumer has any new timestamps.
-    int result = getAllFrameTimestamps(fId1);
+    result = getAllFrameTimestamps(fId1);
     EXPECT_EQ(NO_ERROR, result);
-    EXPECT_EQ(3, mFakeConsumer->mGetFrameTimestampsCount);
+    EXPECT_EQ(4, mFakeConsumer->mGetFrameTimestampsCount);
 }
 
 void GetFrameTimestampsTest::QueryPresentRetireSupported(
@@ -842,6 +895,234 @@
    QueryPresentRetireSupported(false, true);
 }
 
+TEST_F(GetFrameTimestampsTest, SnapToNextTickBasic) {
+    nsecs_t phase = 4000;
+    nsecs_t interval = 1000;
+
+    // Timestamp in previous interval.
+    nsecs_t timestamp = 3500;
+    EXPECT_EQ(4000, ProducerFrameEventHistory::snapToNextTick(
+            timestamp, phase, interval));
+
+    // Timestamp in next interval.
+    timestamp = 4500;
+    EXPECT_EQ(5000, ProducerFrameEventHistory::snapToNextTick(
+            timestamp, phase, interval));
+
+    // Timestamp multiple intervals before.
+    timestamp = 2500;
+    EXPECT_EQ(3000, ProducerFrameEventHistory::snapToNextTick(
+            timestamp, phase, interval));
+
+    // Timestamp multiple intervals after.
+    timestamp = 6500;
+    EXPECT_EQ(7000, ProducerFrameEventHistory::snapToNextTick(
+            timestamp, phase, interval));
+
+    // Timestamp on previous interval.
+    timestamp = 3000;
+    EXPECT_EQ(3000, ProducerFrameEventHistory::snapToNextTick(
+            timestamp, phase, interval));
+
+    // Timestamp on next interval.
+    timestamp = 5000;
+    EXPECT_EQ(5000, ProducerFrameEventHistory::snapToNextTick(
+            timestamp, phase, interval));
+
+    // Timestamp equal to phase.
+    timestamp = 4000;
+    EXPECT_EQ(4000, ProducerFrameEventHistory::snapToNextTick(
+            timestamp, phase, interval));
+}
+
+// int(big_timestamp / interval) < 0, which can cause a crash or invalid result
+// if the number of intervals elapsed is internally stored in an int.
+TEST_F(GetFrameTimestampsTest, SnapToNextTickOverflow) {
+      nsecs_t phase = 0;
+      nsecs_t interval = 4000;
+      nsecs_t big_timestamp = 8635916564000;
+      int32_t intervals = big_timestamp / interval;
+
+      EXPECT_LT(intervals, 0);
+      EXPECT_EQ(8635916564000, ProducerFrameEventHistory::snapToNextTick(
+            big_timestamp, phase, interval));
+      EXPECT_EQ(8635916564000, ProducerFrameEventHistory::snapToNextTick(
+            big_timestamp, big_timestamp, interval));
+}
+
+// This verifies the compositor timing is updated by refresh events
+// and piggy backed on a queue, dequeue, and enabling of timestamps..
+TEST_F(GetFrameTimestampsTest, CompositorTimingUpdatesBasic) {
+    CompositorTiming initialCompositorTiming {
+        1000000000, // 1s deadline
+        16666667, // 16ms interval
+        50000000, // 50ms present latency
+    };
+    mCfeh->initializeCompositorTiming(initialCompositorTiming);
+
+    enableFrameTimestamps();
+
+    // We get the initial values before any frames are submitted.
+    nsecs_t compositeDeadline = 0;
+    nsecs_t compositeInterval = 0;
+    nsecs_t compositeToPresentLatency = 0;
+    mSurface->setNow(initialCompositorTiming.deadline - 1);
+    int result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(initialCompositorTiming.deadline, compositeDeadline);
+    EXPECT_EQ(initialCompositorTiming.interval, compositeInterval);
+    EXPECT_EQ(initialCompositorTiming.presentLatency,
+              compositeToPresentLatency);
+
+    const uint64_t fId1 = getNextFrameId();
+    dequeueAndQueue(0);
+    addFrameEvents(true, NO_FRAME_INDEX, 0);
+
+    // Still get the initial values because the frame events for frame 0
+    // didn't get a chance to piggyback on a queue or dequeue yet.
+    result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(initialCompositorTiming.deadline, compositeDeadline);
+    EXPECT_EQ(initialCompositorTiming.interval, compositeInterval);
+    EXPECT_EQ(initialCompositorTiming.presentLatency,
+              compositeToPresentLatency);
+
+    const uint64_t fId2 = getNextFrameId();
+    dequeueAndQueue(1);
+    addFrameEvents(true, 0, 1);
+
+    // Now expect the composite values associated with frame 1.
+    mSurface->setNow(mFrames[0].mRefreshes[1].kCompositorTiming.deadline);
+    result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[0].mRefreshes[1].kCompositorTiming.deadline,
+            compositeDeadline);
+    EXPECT_EQ(mFrames[0].mRefreshes[1].kCompositorTiming.interval,
+            compositeInterval);
+    EXPECT_EQ(mFrames[0].mRefreshes[1].kCompositorTiming.presentLatency,
+            compositeToPresentLatency);
+
+    dequeueAndQueue(2);
+    addFrameEvents(true, 1, 2);
+
+    // Now expect the composite values associated with frame 2.
+    mSurface->setNow(mFrames[1].mRefreshes[1].kCompositorTiming.deadline);
+    result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[1].mRefreshes[1].kCompositorTiming.deadline,
+            compositeDeadline);
+    EXPECT_EQ(mFrames[1].mRefreshes[1].kCompositorTiming.interval,
+            compositeInterval);
+    EXPECT_EQ(mFrames[1].mRefreshes[1].kCompositorTiming.presentLatency,
+            compositeToPresentLatency);
+
+    // Re-enabling frame timestamps should get the latest values.
+    disableFrameTimestamps();
+    enableFrameTimestamps();
+
+    // Now expect the composite values associated with frame 3.
+    mSurface->setNow(mFrames[2].mRefreshes[1].kCompositorTiming.deadline);
+    result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(mFrames[2].mRefreshes[1].kCompositorTiming.deadline,
+            compositeDeadline);
+    EXPECT_EQ(mFrames[2].mRefreshes[1].kCompositorTiming.interval,
+            compositeInterval);
+    EXPECT_EQ(mFrames[2].mRefreshes[1].kCompositorTiming.presentLatency,
+            compositeToPresentLatency);
+}
+
+// This verifies the compositor deadline properly snaps to the the next
+// deadline based on the current time.
+TEST_F(GetFrameTimestampsTest, CompositorTimingDeadlineSnaps) {
+    CompositorTiming initialCompositorTiming {
+        1000000000, // 1s deadline
+        16666667, // 16ms interval
+        50000000, // 50ms present latency
+    };
+    mCfeh->initializeCompositorTiming(initialCompositorTiming);
+
+    enableFrameTimestamps();
+
+    nsecs_t compositeDeadline = 0;
+    nsecs_t compositeInterval = 0;
+    nsecs_t compositeToPresentLatency = 0;
+
+    // A "now" just before the deadline snaps to the deadline.
+    mSurface->setNow(initialCompositorTiming.deadline - 1);
+    int result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    EXPECT_EQ(initialCompositorTiming.deadline, compositeDeadline);
+    nsecs_t expectedDeadline = initialCompositorTiming.deadline;
+    EXPECT_EQ(expectedDeadline, compositeDeadline);
+
+    const uint64_t fId1 = getNextFrameId();
+    dequeueAndQueue(0);
+    addFrameEvents(true, NO_FRAME_INDEX, 0);
+
+    // A "now" just after the deadline snaps properly.
+    mSurface->setNow(initialCompositorTiming.deadline + 1);
+    result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    expectedDeadline =
+            initialCompositorTiming.deadline +initialCompositorTiming.interval;
+    EXPECT_EQ(expectedDeadline, compositeDeadline);
+
+    const uint64_t fId2 = getNextFrameId();
+    dequeueAndQueue(1);
+    addFrameEvents(true, 0, 1);
+
+    // A "now" just after the next interval snaps properly.
+    mSurface->setNow(
+            mFrames[0].mRefreshes[1].kCompositorTiming.deadline +
+            mFrames[0].mRefreshes[1].kCompositorTiming.interval + 1);
+    result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    expectedDeadline =
+            mFrames[0].mRefreshes[1].kCompositorTiming.deadline +
+            mFrames[0].mRefreshes[1].kCompositorTiming.interval * 2;
+    EXPECT_EQ(expectedDeadline, compositeDeadline);
+
+    dequeueAndQueue(2);
+    addFrameEvents(true, 1, 2);
+
+    // A "now" over 1 interval before the deadline snaps properly.
+    mSurface->setNow(
+            mFrames[1].mRefreshes[1].kCompositorTiming.deadline -
+            mFrames[1].mRefreshes[1].kCompositorTiming.interval - 1);
+    result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    expectedDeadline =
+            mFrames[1].mRefreshes[1].kCompositorTiming.deadline -
+            mFrames[1].mRefreshes[1].kCompositorTiming.interval;
+    EXPECT_EQ(expectedDeadline, compositeDeadline);
+
+    // Re-enabling frame timestamps should get the latest values.
+    disableFrameTimestamps();
+    enableFrameTimestamps();
+
+    // A "now" over 2 intervals before the deadline snaps properly.
+    mSurface->setNow(
+            mFrames[2].mRefreshes[1].kCompositorTiming.deadline -
+            mFrames[2].mRefreshes[1].kCompositorTiming.interval * 2 - 1);
+    result = native_window_get_compositor_timing(mWindow.get(),
+        &compositeDeadline, &compositeInterval, &compositeToPresentLatency);
+    EXPECT_EQ(NO_ERROR, result);
+    expectedDeadline =
+            mFrames[2].mRefreshes[1].kCompositorTiming.deadline -
+            mFrames[2].mRefreshes[1].kCompositorTiming.interval * 2;
+    EXPECT_EQ(expectedDeadline, compositeDeadline);
+}
+
 // This verifies the timestamps recorded in the consumer's
 // FrameTimestampsHistory are properly retrieved by the producer for the
 // correct frames.
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 6485ae5..6572cab 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -632,24 +632,31 @@
 #ifndef EGL_ANDROID_get_frame_timestamps
 #define EGL_ANDROID_get_frame_timestamps 1
 #define EGL_TIMESTAMPS_ANDROID 0x314D
-#define EGL_REQUESTED_PRESENT_TIME_ANDROID 0x314E
-#define EGL_RENDERING_COMPLETE_TIME_ANDROID 0x314F
-#define EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3150
-#define EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3151
-#define EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3152
-#define EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID 0x3153
-#define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3154
-#define EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3155
-#define EGL_DEQUEUE_READY_TIME_ANDROID 0x3156
-#define EGL_READS_DONE_TIME_ANDROID 0x3157
+#define EGL_COMPOSITE_DEADLINE_ANDROID 0x314E
+#define EGL_COMPOSITE_INTERVAL_ANDROID 0x314F
+#define EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3150
+#define EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3151
+#define EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3152
+#define EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3153
+#define EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3154
+#define EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3155
+#define EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID 0x3156
+#define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3157
+#define EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3158
+#define EGL_DEQUEUE_READY_TIME_ANDROID 0x3159
+#define EGL_READS_DONE_TIME_ANDROID 0x315A
 #ifdef EGL_EGLEXT_PROTOTYPES
 EGLAPI EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId);
+EGLAPI EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values);
+EGLAPI EGLBoolean eglGetCompositorTimingSupportedANDROID(EGLDisplay dpy, EGLSurface surface, EGLint name);
 EGLAPI EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);
-EGLAPI EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
+EGLAPI EGLBoolean eglGetFrameTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
 #else
 typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETNEXTFRAMEIDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCOMPOSITORTIMINGANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCOMPOSITORTIMINGSUPPORTEDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint name);
 typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSANDROID) (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYTIMESTAMPSUPPORTEDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSUPPORTEDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
 #endif
 #endif
 
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 2d02b72..4681b89 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -56,8 +56,6 @@
 
 using namespace android;
 
-#define ENABLE_EGL_ANDROID_GET_FRAME_TIMESTAMPS 0
-
 // ----------------------------------------------------------------------------
 
 namespace android {
@@ -88,9 +86,7 @@
         "EGL_KHR_swap_buffers_with_damage "
         "EGL_ANDROID_create_native_client_buffer "
         "EGL_ANDROID_front_buffer_auto_refresh "
-#if ENABLE_EGL_ANDROID_GET_FRAME_TIMESTAMPS
         "EGL_ANDROID_get_frame_timestamps "
-#endif
         ;
 extern char const * const gExtensionString  =
         "EGL_KHR_image "                        // mandatory
@@ -218,10 +214,14 @@
     // EGL_ANDROID_get_frame_timestamps
     { "eglGetNextFrameIdANDROID",
             (__eglMustCastToProperFunctionPointerType)&eglGetNextFrameIdANDROID },
+    { "eglGetCompositorTimingANDROID",
+            (__eglMustCastToProperFunctionPointerType)&eglGetCompositorTimingANDROID },
+    { "eglGetCompositorTimingSupportedANDROID",
+            (__eglMustCastToProperFunctionPointerType)&eglGetCompositorTimingSupportedANDROID },
     { "eglGetFrameTimestampsANDROID",
             (__eglMustCastToProperFunctionPointerType)&eglGetFrameTimestampsANDROID },
-    { "eglQueryTimestampSupportedANDROID",
-            (__eglMustCastToProperFunctionPointerType)&eglQueryTimestampSupportedANDROID },
+    { "eglGetFrameTimestampSupportedANDROID",
+            (__eglMustCastToProperFunctionPointerType)&eglGetFrameTimestampSupportedANDROID },
 };
 
 /*
@@ -1242,7 +1242,6 @@
             setError(EGL_BAD_SURFACE, EGL_FALSE);
     }
 
-#if ENABLE_EGL_ANDROID_GET_FRAME_TIMESTAMPS
     if (attribute == EGL_TIMESTAMPS_ANDROID) {
         if (!s->win.get()) {
             return setError(EGL_BAD_SURFACE, EGL_FALSE);
@@ -1252,7 +1251,6 @@
         return (err == NO_ERROR) ? EGL_TRUE :
             setError(EGL_BAD_SURFACE, EGL_FALSE);
     }
-#endif
 
     if (s->cnx->egl.eglSurfaceAttrib) {
         return s->cnx->egl.eglSurfaceAttrib(
@@ -2084,6 +2082,95 @@
     return EGL_TRUE;
 }
 
+EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface,
+        EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values)
+{
+    clearError();
+
+    const egl_display_ptr dp = validate_display(dpy);
+    if (!dp) {
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    }
+
+    SurfaceRef _s(dp.get(), surface);
+    if (!_s.get()) {
+        return setError(EGL_BAD_SURFACE, EGL_FALSE);
+    }
+
+    egl_surface_t const * const s = get_surface(surface);
+
+    if (!s->win.get()) {
+        return setError(EGL_BAD_SURFACE, EGL_FALSE);
+    }
+
+    nsecs_t* compositeDeadline = nullptr;
+    nsecs_t* compositeInterval = nullptr;
+    nsecs_t* compositeToPresentLatency = nullptr;
+
+    for (int i = 0; i < numTimestamps; i++) {
+        switch (names[i]) {
+            case EGL_COMPOSITE_DEADLINE_ANDROID:
+                compositeDeadline = &values[i];
+                break;
+            case EGL_COMPOSITE_INTERVAL_ANDROID:
+                compositeInterval = &values[i];
+                break;
+            case EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID:
+                compositeToPresentLatency = &values[i];
+                break;
+            default:
+                return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+        }
+    }
+
+    status_t ret = native_window_get_compositor_timing(s->win.get(),
+            compositeDeadline, compositeInterval, compositeToPresentLatency);
+
+    switch (ret) {
+      case NO_ERROR:
+        return EGL_TRUE;
+      case INVALID_OPERATION:
+        return setError(EGL_BAD_SURFACE, EGL_FALSE);
+      default:
+        // This should not happen. Return an error that is not in the spec
+        // so it's obvious something is very wrong.
+        ALOGE("eglGetCompositorTiming: Unexpected error.");
+        return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
+    }
+}
+
+EGLBoolean eglGetCompositorTimingSupportedANDROID(
+        EGLDisplay dpy, EGLSurface surface, EGLint name)
+{
+    clearError();
+
+    const egl_display_ptr dp = validate_display(dpy);
+    if (!dp) {
+        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    }
+
+    SurfaceRef _s(dp.get(), surface);
+    if (!_s.get()) {
+        return setError(EGL_BAD_SURFACE, EGL_FALSE);
+    }
+
+    egl_surface_t const * const s = get_surface(surface);
+
+    ANativeWindow* window = s->win.get();
+    if (!window) {
+        return setError(EGL_BAD_SURFACE, EGL_FALSE);
+    }
+
+    switch (name) {
+        case EGL_COMPOSITE_DEADLINE_ANDROID:
+        case EGL_COMPOSITE_INTERVAL_ANDROID:
+        case EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID:
+            return EGL_TRUE;
+        default:
+            return EGL_FALSE;
+    }
+}
+
 EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface,
         EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps,
         EGLnsecsANDROID *values)
@@ -2176,8 +2263,8 @@
     }
 }
 
-EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface,
-        EGLint timestamp)
+EGLBoolean eglGetFrameTimestampSupportedANDROID(
+        EGLDisplay dpy, EGLSurface surface, EGLint timestamp)
 {
     clearError();
 
@@ -2199,7 +2286,9 @@
     }
 
     switch (timestamp) {
-#if ENABLE_EGL_ANDROID_GET_FRAME_TIMESTAMPS
+        case EGL_COMPOSITE_DEADLINE_ANDROID:
+        case EGL_COMPOSITE_INTERVAL_ANDROID:
+        case EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID:
         case EGL_REQUESTED_PRESENT_TIME_ANDROID:
         case EGL_RENDERING_COMPLETE_TIME_ANDROID:
         case EGL_COMPOSITION_LATCH_TIME_ANDROID:
@@ -2221,7 +2310,6 @@
                     NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_RETIRE, &value);
             return value == 0 ? EGL_FALSE : EGL_TRUE;
         }
-#endif
         default:
             return EGL_FALSE;
     }
diff --git a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
index f24d634..d0ed8e1 100644
--- a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
+++ b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
@@ -8,11 +8,19 @@
 
 Contributors
 
+    Brian Anderson
+    Dan Stoza
     Pablo Ceballos
+    Jesse Hall
+    Fabien Sanglard
 
 Contact
 
+    Brian Anderson, Google Inc. (brianderson 'at' google.com)
+    Dan Stoza, Google Inc. (stoza 'at' google.com)
     Pablo Ceballos, Google Inc. (pceballos 'at' google.com)
+    Jesse Hall, Google Inc. (jessehall 'at' google.com)
+    Fabien Sanglard, Google Inc. (sanglardf 'at' google.com)
 
 Status
 
@@ -20,7 +28,7 @@
 
 Version
 
-    Version 1, May 31, 2016
+    Version 1, January 13, 2017
 
 Number
 
@@ -60,26 +68,33 @@
     EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface,
             EGLuint64KHR *frameId);
 
+    EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy,
+            EGLSurface surface, EGLint numTimestamps,
+            const EGLint *names, EGLnsecsANDROID *values);
+
     EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface,
             EGLuint64KHR frameId, EGLint numTimestamps,
             const EGLint *timestamps, EGLnsecsANDROID *values);
 
-    EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface
-            surface, EGLint timestamp);
+    EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy,
+            EGLSurface surface, EGLint timestamp);
 
 New Tokens
 
     EGL_TIMESTAMPS_ANDROID 0x314D
-    EGL_REQUESTED_PRESENT_TIME_ANDROID 0x314E
-    EGL_RENDERING_COMPLETE_TIME_ANDROID 0x314F
-    EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3150
-    EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3151
-    EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3152
-    EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID 0x3153
-    EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3154
-    EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3155
-    EGL_DEQUEUE_READY_TIME_ANDROID 0x3156
-    EGL_READS_DONE_TIME_ANDROID 0x3157
+    EGL_COMPOSITE_DEADLINE_ANDROID 0x314E
+    EGL_COMPOSITE_INTERVAL_ANDROID 0x314F
+    EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3150
+    EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3151
+    EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3152
+    EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3153
+    EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3154
+    EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3155
+    EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID 0x3156
+    EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3157
+    EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3158
+    EGL_DEQUEUE_READY_TIME_ANDROID 0x3159
+    EGL_READS_DONE_TIME_ANDROID 0x315A
 
 Add to the list of supported tokens for eglSurfaceAttrib in section 3.5.6
 "Surface Attributes", page 43:
@@ -89,7 +104,6 @@
     enables timestamp collection, while a value of EGL_FALSE disables it. The
     initial value is false. If surface is not a window surface this has no
     effect.
-
 Changes to Chapter 3 of the EGL 1.5 Specification (EGL Functions and Errors)
 
     Add a new subsection under Section 3,
@@ -108,6 +122,29 @@
 
     The function
 
+        EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy,
+                EGLSurface surface, EGLint numTimestamps,
+                const EGLint *names, EGLnsecsANDROID *values);
+
+    allows querying anticipated timestamps and durations related to the
+    composition and display of a window surface. The values are not associated
+    with a particular frame and can be retrieved before the first swap.
+
+    The eglGetCompositorTimingANDROID function takes an array of names to
+    query and returns their values in the corresponding indices of the values
+    array. The possible names that can be queried are:
+        - EGL_COMPOSITE_DEADLINE_ANDROID - The timestamp of the next time the
+          compositor will begin composition. This is effectively the deadline
+          for when the compositor must receive a newly queued frame.
+        - EGL_COMPOSITE_INTERVAL_ANDROID - The time delta between subsequent
+          composition events.
+        - EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID - The time delta between
+          the start of composition and the expected present time of that
+          composition. This can be used to estimate the latency of the
+          actual present time.
+
+    The function
+
         EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy,
             EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps,
             const EGLint *timestamps, EGLnsecsANDROID *values);
@@ -124,6 +161,12 @@
     supported will generate an EGL_BAD_PARAMETER error. If any error is
     generated the function will return EGL_FALSE.
 
+    The application can poll for the timestamp of particular events by calling
+    eglGetFrameTimestamps over and over without needing to call any other EGL
+    function between calls. This is true even for the most recently swapped
+    frame. eglGetFrameTimestamps is thread safe and can be called from a
+    different thread than the swapping thread.
+
     The eglGetFrameTimestampsANDROID function takes an array of timestamps to
     query and returns timestamps in the corresponding indices of the values
     array. The possible timestamps that can be queried are:
@@ -162,12 +205,19 @@
           purpose of display/composition were completed for this frame.
 
     Not all implementations may support all of the above timestamp queries. The
-    function
+    functions
 
-        EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface
-            surface, EGLint timestamp);
+        EGLBoolean eglGetCompositorTimingSupportedANDROID(EGLDisplay dpy,
+            EGLSurface surface, EGLint name);
 
-    allows querying which timestamps are supported on the implementation."
+    and
+
+        EGLBoolean eglGetFrameTimestampsSupportedANDROID(EGLDisplay dpy,
+            EGLSurface surface, EGLint timestamp);
+
+    allows querying which values are supported by the implementations of
+    eglGetCompositoTimingANDROID and eglGetFrameTimestampsSupportedANDROID
+    respectively."
 
 Issues
 
@@ -175,17 +225,21 @@
 
 Revision History
 
-#1 (Pablo Ceballos, May 31, 2016)
-    - Initial draft.
+#5 (Brian Anderson, January 13, 2017)
+    - Add eglGetCompositorTimingANDROID.
 
-#2 (Brian Anderson, July 22, 2016)
-    - Replace EGL_QUEUE_TIME_ANDROID with EGL_REQUESTED_PRESENT_TIME_ANDROID.
-    - Add DISPLAY_PRESENT_TIME_ANDROID.
+#4 (Brian Anderson, January 10, 2017)
+    - Use an absolute frameId rather than a relative framesAgo.
 
 #3 (Brian Anderson, November 30, 2016)
     - Add EGL_COMPOSITION_LATCH_TIME_ANDROID,
       EGL_LAST_COMPOSITION_START_TIME_ANDROID, and
       EGL_DEQUEUE_READY_TIME_ANDROID.
 
-#4 (Brian Anderson, January 10, 2017)
-    - Use an absolute frameId rather than a relative framesAgo.
+#2 (Brian Anderson, July 22, 2016)
+    - Replace EGL_QUEUE_TIME_ANDROID with EGL_REQUESTED_PRESENT_TIME_ANDROID.
+    - Add DISPLAY_PRESENT_TIME_ANDROID.
+
+#1 (Pablo Ceballos, May 31, 2016)
+    - Initial draft.
+
diff --git a/opengl/specs/README b/opengl/specs/README
index 1853214..0c49023 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -20,14 +20,17 @@
 0x314B               EGL_IMAGE_CROP_BOTTOM_ANDROID (EGL_ANDROID_image_crop)
 0x314C               EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID (EGL_ANDROID_front_buffer_auto_refresh)
 0x314D               EGL_TIMESTAMPS_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x314E               EGL_REQUESTED_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x314F               EGL_RENDERING_COMPLETE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3150               EGL_COMPOSITION_LATCH_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3151               EGL_FIRST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3152               EGL_LAST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3153               EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3154               EGL_DISPLAY_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3155               EGL_DISPLAY_RETIRE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3156               EGL_DEQUEUE_READY_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3157               EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3158 - 0x315F      (unused)
+0x314E               EGL_COMPOSITE_DEADLINE_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x314F               EGL_COMPOSITE_INTERVAL_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3150               EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3151               EGL_REQUESTED_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3152               EGL_RENDERING_COMPLETE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3153               EGL_COMPOSITION_LATCH_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3154               EGL_FIRST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3155               EGL_LAST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3156               EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3157               EGL_DISPLAY_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3158               EGL_DISPLAY_RETIRE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3159               EGL_DEQUEUE_READY_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x315A               EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x315B - 0x315F      (unused)
diff --git a/services/audiomanager/IPlayer.cpp b/services/audiomanager/IPlayer.cpp
index 47edc4b..e8a9c34 100644
--- a/services/audiomanager/IPlayer.cpp
+++ b/services/audiomanager/IPlayer.cpp
@@ -35,6 +35,7 @@
     SET_VOLUME = IBinder::FIRST_CALL_TRANSACTION + 3,
     SET_PAN    = IBinder::FIRST_CALL_TRANSACTION + 4,
     SET_START_DELAY_MS = IBinder::FIRST_CALL_TRANSACTION + 5,
+    APPLY_VOLUME_SHAPER = IBinder::FIRST_CALL_TRANSACTION + 6,
 };
 
 class BpPlayer : public BpInterface<IPlayer>
@@ -88,6 +89,36 @@
         data.writeInt32(delayMs);
         remote()->transact(SET_START_DELAY_MS, data, &reply);
     }
+
+    virtual void applyVolumeShaper(
+            const sp<VolumeShaper::Configuration>& configuration,
+            const sp<VolumeShaper::Operation>& operation) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
+
+        status_t status = configuration.get() == nullptr
+                ? data.writeInt32(0)
+                :  data.writeInt32(1)
+                    ?: configuration->writeToParcel(&data);
+        if (status != NO_ERROR) {
+            ALOGW("applyVolumeShaper failed configuration parceling: %d", status);
+            return; // ignore error
+        }
+
+        status = operation.get() == nullptr
+                ? status = data.writeInt32(0)
+                : data.writeInt32(1)
+                    ?: operation->writeToParcel(&data);
+        if (status != NO_ERROR) {
+            ALOGW("applyVolumeShaper failed operation parceling: %d", status);
+            return; // ignore error
+        }
+
+        status = remote()->transact(APPLY_VOLUME_SHAPER, data, &reply);
+
+        ALOGW_IF(status != NO_ERROR, "applyVolumeShaper failed transact: %d", status);
+        return; // one way transaction, ignore error
+    }
 };
 
 IMPLEMENT_META_INTERFACE(Player, "android.media.IPlayer");
@@ -128,6 +159,28 @@
             setStartDelayMs(data.readInt32());
             return NO_ERROR;
         } break;
+        case APPLY_VOLUME_SHAPER: {
+            CHECK_INTERFACE(IPlayer, data, reply);
+            sp<VolumeShaper::Configuration> configuration;
+            sp<VolumeShaper::Operation> operation;
+
+            int32_t present;
+            status_t status = data.readInt32(&present);
+            if (status == NO_ERROR && present != 0) {
+                configuration = new VolumeShaper::Configuration();
+                status = configuration->readFromParcel(data);
+            }
+            status = status ?: data.readInt32(&present);
+            if (status == NO_ERROR && present != 0) {
+                operation = new VolumeShaper::Operation();
+                status = operation->readFromParcel(data);
+            }
+            if (status == NO_ERROR) {
+                // one way transaction, no error returned
+                applyVolumeShaper(configuration, operation);
+            }
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index aa8f189..9e81a8c 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -133,6 +133,7 @@
 
 LOCAL_STATIC_LIBRARIES := \
     libhwcomposer-command-buffer \
+    android.hardware.configstore-utils \
     libtrace_proto \
     libvkjson \
     libvr_manager \
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 6c18ef7..9af4402 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -47,6 +47,9 @@
 #include "SurfaceFlinger.h"
 #include "Layer.h"
 
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
+
 // ----------------------------------------------------------------------------
 using namespace android;
 // ----------------------------------------------------------------------------
@@ -57,6 +60,14 @@
 static constexpr bool kEGLAndroidSwapRectangle = false;
 #endif
 
+// retrieve triple buffer setting from configstore
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+
+static bool useTripleFramebuffer = getBool<
+        ISurfaceFlingerConfigs,
+        &ISurfaceFlingerConfigs::useTripleFramebuffer>(false);
+
 #if !defined(EGL_EGLEXT_PROTOTYPES) || !defined(EGL_ANDROID_swap_rectangle)
 // Dummy implementation in case it is missing.
 inline void eglSetSwapRectangleANDROID (EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint) {
@@ -165,9 +176,9 @@
     // initialize the display orientation transform.
     setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
 
-#ifdef NUM_FRAMEBUFFER_SURFACE_BUFFERS
-    surface->allocateBuffers();
-#endif
+    if (useTripleFramebuffer) {
+        surface->allocateBuffers();
+    }
 }
 
 DisplayDevice::~DisplayDevice() {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6e0a489..a854aec 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -155,6 +155,10 @@
             flinger->getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
 #endif
     mFrameTracker.setDisplayRefreshPeriod(displayPeriod);
+
+    CompositorTiming compositorTiming;
+    flinger->getCompositorTiming(&compositorTiming);
+    mFrameEventHistory.initializeCompositorTiming(compositorTiming);
 }
 
 void Layer::onFirstRef() {
@@ -1882,10 +1886,10 @@
     return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
 }
 
-bool Layer::onPostComposition(
-        const std::shared_ptr<FenceTime>& glDoneFence,
+bool Layer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
         const std::shared_ptr<FenceTime>& presentFence,
-        const std::shared_ptr<FenceTime>& retireFence) {
+        const std::shared_ptr<FenceTime>& retireFence,
+        const CompositorTiming& compositorTiming) {
     mAcquireTimeline.updateSignalTimes();
     mReleaseTimeline.updateSignalTimes();
 
@@ -1898,7 +1902,7 @@
     {
         Mutex::Autolock lock(mFrameEventHistoryMutex);
         mFrameEventHistory.addPostComposition(mCurrentFrameNumber,
-                glDoneFence, presentFence);
+                glDoneFence, presentFence, compositorTiming);
         mFrameEventHistory.addRetire(mPreviousFrameNumber,
                 retireFence);
     }
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 12166a8..8227dae 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -296,10 +296,10 @@
      * called after composition.
      * returns true if the layer latched a new buffer this frame.
      */
-    bool onPostComposition(
-            const std::shared_ptr<FenceTime>& glDoneFence,
+    bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
             const std::shared_ptr<FenceTime>& presentFence,
-            const std::shared_ptr<FenceTime>& retireFence);
+            const std::shared_ptr<FenceTime>& retireFence,
+            const CompositorTiming& compositorTiming);
 
 #ifdef USE_HWC2
     // If a buffer was replaced this frame, release the former buffer
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cbc209d..462e5a6 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -87,6 +87,7 @@
 #include <cutils/compiler.h>
 
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
 
 #define DISPLAY_COUNT       1
 
@@ -100,22 +101,9 @@
 
 namespace android {
 
+using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
 
-static sp<ISurfaceFlingerConfigs> getConfigs() {
-    static sp<ISurfaceFlingerConfigs> configs
-            = ISurfaceFlingerConfigs::getService();
-    return configs;
-}
-
-static int64_t getVsyncEventPhaseOffsetNs() {
-    int64_t ret = 1000000; // default value
-    getConfigs()->vsyncEventPhaseOffsetNs([&](OptionalInt64 value) {
-          if (value.specified) ret = value.value;
-    });
-    return ret;
-}
-
 // This is the phase offset in nanoseconds of the software vsync event
 // relative to the vsync event reported by HWComposer.  The software vsync
 // event is when SurfaceFlinger and Choreographer-based applications run each
@@ -136,10 +124,12 @@
 // the latency will end up being an additional vsync period, and animations
 // will hiccup.  Therefore, this latency should be tuned somewhat
 // conservatively (or at least with awareness of the trade-off being made).
-static int64_t vsyncPhaseOffsetNs = getVsyncEventPhaseOffsetNs();
+static int64_t vsyncPhaseOffsetNs = getInt64<
+        ISurfaceFlingerConfigs,
+        &ISurfaceFlingerConfigs::vsyncEventPhaseOffsetNs>(1000000);
 
 // This is the phase offset at which SurfaceFlinger's composition runs.
-static const int64_t sfVsyncPhaseOffsetNs = SF_VSYNC_EVENT_PHASE_OFFSET_NS;
+static constexpr int64_t sfVsyncPhaseOffsetNs = SF_VSYNC_EVENT_PHASE_OFFSET_NS;
 
 // ---------------------------------------------------------------------------
 
@@ -1126,6 +1116,11 @@
     }
 }
 
+void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) {
+    std::lock_guard<std::mutex> lock(mCompositeTimingLock);
+    *compositorTiming = mCompositorTiming;
+}
+
 void SurfaceFlinger::onHotplugReceived(int32_t disp, bool connected) {
     ALOGV("onHotplugReceived(%d, %s)", disp, connected ? "true" : "false");
     if (disp == DisplayDevice::DISPLAY_PRIMARY) {
@@ -1261,11 +1256,13 @@
     ATRACE_CALL();
     switch (what) {
         case MessageQueue::INVALIDATE: {
-            updateVrMode();
+            // TODO(eieio): Disabled until SELinux issues are resolved.
+            //updateVrMode();
 
             bool frameMissed = !mHadClientComposition &&
                     mPreviousPresentFence != Fence::NO_FENCE &&
-                    mPreviousPresentFence->getSignalTime() == INT64_MAX;
+                    (mPreviousPresentFence->getSignalTime() ==
+                            Fence::SIGNAL_TIME_PENDING);
             ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
             if (mPropagateBackpressure && frameMissed) {
                 signalLayerUpdate();
@@ -1314,7 +1311,7 @@
     setUpHWComposer();
     doDebugFlashRegions();
     doComposition();
-    postComposition();
+    postComposition(refreshStartTime);
 
     mPreviousPresentFence = mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
 
@@ -1389,7 +1386,61 @@
     }
 }
 
-void SurfaceFlinger::postComposition()
+void SurfaceFlinger::updateCompositorTiming(
+        nsecs_t vsyncPhase, nsecs_t vsyncInterval, nsecs_t compositeTime,
+        std::shared_ptr<FenceTime>& presentFenceTime) {
+    // Update queue of past composite+present times and determine the
+    // most recently known composite to present latency.
+    mCompositePresentTimes.push({compositeTime, presentFenceTime});
+    nsecs_t compositeToPresentLatency = -1;
+    while (!mCompositePresentTimes.empty()) {
+        CompositePresentTime& cpt = mCompositePresentTimes.front();
+        // Cached values should have been updated before calling this method,
+        // which helps avoid duplicate syscalls.
+        nsecs_t displayTime = cpt.display->getCachedSignalTime();
+        if (displayTime == Fence::SIGNAL_TIME_PENDING) {
+            break;
+        }
+        compositeToPresentLatency = displayTime - cpt.composite;
+        mCompositePresentTimes.pop();
+    }
+
+    // Don't let mCompositePresentTimes grow unbounded, just in case.
+    while (mCompositePresentTimes.size() > 16) {
+        mCompositePresentTimes.pop();
+    }
+
+    // Integer division and modulo round toward 0 not -inf, so we need to
+    // treat negative and positive offsets differently.
+    nsecs_t idealLatency = (sfVsyncPhaseOffsetNs >= 0) ?
+            (vsyncInterval - (sfVsyncPhaseOffsetNs % vsyncInterval)) :
+            ((-sfVsyncPhaseOffsetNs) % vsyncInterval);
+
+    // Snap the latency to a value that removes scheduling jitter from the
+    // composition and present times, which often have >1ms of jitter.
+    // Reducing jitter is important if an app attempts to extrapolate
+    // something (such as user input) to an accurate diasplay time.
+    // Snapping also allows an app to precisely calculate sfVsyncPhaseOffsetNs
+    // with (presentLatency % interval).
+    nsecs_t snappedCompositeToPresentLatency = -1;
+    if (compositeToPresentLatency >= 0) {
+        nsecs_t bias = vsyncInterval / 2;
+        int64_t extraVsyncs =
+                (compositeToPresentLatency - idealLatency + bias) /
+                vsyncInterval;
+        nsecs_t extraLatency = extraVsyncs * vsyncInterval;
+        snappedCompositeToPresentLatency = idealLatency + extraLatency;
+    }
+
+    std::lock_guard<std::mutex> lock(mCompositeTimingLock);
+    mCompositorTiming.deadline = vsyncPhase - idealLatency;
+    mCompositorTiming.interval = vsyncInterval;
+    if (snappedCompositeToPresentLatency >= 0) {
+        mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
+    }
+}
+
+void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
 {
     ATRACE_CALL();
     ALOGV("postComposition");
@@ -1424,9 +1475,19 @@
     } else {
         retireFenceTime = &displayFenceTime;
     }
+
+    nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
+    nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
+
+    // We use the refreshStartTime which might be sampled a little later than
+    // when we started doing work for this frame, but that should be okay
+    // since updateCompositorTiming has snapping logic.
+    updateCompositorTiming(
+        vsyncPhase, vsyncInterval, refreshStartTime, displayFenceTime);
+
     mDrawingState.traverseInZOrder([&](Layer* layer) {
         bool frameLatched = layer->onPostComposition(glCompositionDoneFenceTime,
-                *presentFenceTime, *retireFenceTime);
+                *presentFenceTime, *retireFenceTime, mCompositorTiming);
         if (frameLatched) {
             recordBufferingStats(layer->getName().string(),
                     layer->getOccupancyHistory(false));
@@ -1471,9 +1532,8 @@
     if (mHasPoweredOff) {
         mHasPoweredOff = false;
     } else {
-        nsecs_t period = mPrimaryDispSync.getPeriod();
         nsecs_t elapsedTime = currentTime - mLastSwapTime;
-        size_t numPeriods = static_cast<size_t>(elapsedTime / period);
+        size_t numPeriods = static_cast<size_t>(elapsedTime / vsyncInterval);
         if (numPeriods < NUM_BUCKETS - 1) {
             mFrameBuckets[numPeriods] += elapsedTime;
         } else {
@@ -2876,6 +2936,11 @@
     const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
     const nsecs_t period = activeConfig->getVsyncPeriod();
     mAnimFrameTracker.setDisplayRefreshPeriod(period);
+
+    {
+        std::lock_guard<std::mutex> lock(mCompositeTimingLock);
+        mCompositorTiming.interval = period;
+    }
 }
 
 void SurfaceFlinger::initializeDisplays() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 02e4a0c..f52bd2d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -42,6 +42,7 @@
 #include <ui/PixelFormat.h>
 #include <ui/mat4.h>
 
+#include <gui/FrameTimestamps.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
 #include <gui/OccupancyTracker.h>
@@ -65,7 +66,10 @@
 #include "Effects/Daltonizer.h"
 
 #include <map>
+#include <mutex>
+#include <queue>
 #include <string>
+#include <utility>
 
 namespace android {
 
@@ -413,7 +417,10 @@
             Region& dirtyRegion, Region& opaqueRegion);
 
     void preComposition(nsecs_t refreshStartTime);
-    void postComposition();
+    void postComposition(nsecs_t refreshStartTime);
+    void updateCompositorTiming(
+            nsecs_t vsyncPhase, nsecs_t vsyncInterval, nsecs_t compositeTime,
+            std::shared_ptr<FenceTime>& presentFenceTime);
     void rebuildLayerStacks();
     void setUpHWComposer();
     void doComposition();
@@ -434,12 +441,13 @@
     /* ------------------------------------------------------------------------
      * VSync
      */
-     void enableHardwareVsync();
-     void resyncToHardwareVsync(bool makeAvailable);
-     void disableHardwareVsync(bool makeUnavailable);
+    void enableHardwareVsync();
+    void resyncToHardwareVsync(bool makeAvailable);
+    void disableHardwareVsync(bool makeUnavailable);
 
 public:
-     void resyncWithRateLimit();
+    void resyncWithRateLimit();
+    void getCompositorTiming(CompositorTiming* compositorTiming);
 private:
 
     /* ------------------------------------------------------------------------
@@ -581,6 +589,17 @@
     bool mPrimaryHWVsyncEnabled;
     bool mHWVsyncAvailable;
 
+    // protected by mCompositorTimingLock;
+    mutable std::mutex mCompositeTimingLock;
+    CompositorTiming mCompositorTiming;
+
+    // Only accessed from the main thread.
+    struct CompositePresentTime {
+        nsecs_t composite { -1 };
+        std::shared_ptr<FenceTime> display { FenceTime::NO_FENCE };
+    };
+    std::queue<CompositePresentTime> mCompositePresentTimes;
+
     /* ------------------------------------------------------------------------
      * Feature prototyping
      */
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 40a27e8..477eb27 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -1036,6 +1036,11 @@
     }
 }
 
+void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) {
+    std::lock_guard<std::mutex> lock(mCompositeTimingLock);
+    *compositorTiming = mCompositorTiming;
+}
+
 void SurfaceFlinger::onHotplugReceived(int type, bool connected) {
     if (mEventThread == NULL) {
         // This is a temporary workaround for b/7145521.  A non-null pointer
@@ -1114,7 +1119,7 @@
     setUpHWComposer();
     doDebugFlashRegions();
     doComposition();
-    postComposition();
+    postComposition(refreshStartTime);
 }
 
 void SurfaceFlinger::doDebugFlashRegions()
@@ -1171,7 +1176,61 @@
     }
 }
 
-void SurfaceFlinger::postComposition()
+void SurfaceFlinger::updateCompositorTiming(
+        nsecs_t vsyncPhase, nsecs_t vsyncInterval, nsecs_t compositeTime,
+        std::shared_ptr<FenceTime>& presentFenceTime) {
+    // Update queue of past composite+present times and determine the
+    // most recently known composite to present latency.
+    mCompositePresentTimes.push({compositeTime, presentFenceTime});
+    nsecs_t compositeToPresentLatency = -1;
+    while (!mCompositePresentTimes.empty()) {
+        CompositePresentTime& cpt = mCompositePresentTimes.front();
+        // Cached values should have been updated before calling this method,
+        // which helps avoid duplicate syscalls.
+        nsecs_t displayTime = cpt.display->getCachedSignalTime();
+        if (displayTime == Fence::SIGNAL_TIME_PENDING) {
+            break;
+        }
+        compositeToPresentLatency = displayTime - cpt.composite;
+        mCompositePresentTimes.pop();
+    }
+
+    // Don't let mCompositePresentTimes grow unbounded, just in case.
+    while (mCompositePresentTimes.size() > 16) {
+        mCompositePresentTimes.pop();
+    }
+
+    // Integer division and modulo round toward 0 not -inf, so we need to
+    // treat negative and positive offsets differently.
+    nsecs_t idealLatency = (sfVsyncPhaseOffsetNs >= 0) ?
+            (vsyncInterval - (sfVsyncPhaseOffsetNs % vsyncInterval)) :
+            ((-sfVsyncPhaseOffsetNs) % vsyncInterval);
+
+    // Snap the latency to a value that removes scheduling jitter from the
+    // composition and present times, which often have >1ms of jitter.
+    // Reducing jitter is important if an app attempts to extrapolate
+    // something (such as user input) to an accurate diasplay time.
+    // Snapping also allows an app to precisely calculate sfVsyncPhaseOffsetNs
+    // with (presentLatency % interval).
+    nsecs_t snappedCompositeToPresentLatency = -1;
+    if (compositeToPresentLatency >= 0) {
+        nsecs_t bias = vsyncInterval / 2;
+        int64_t extraVsyncs =
+                (compositeToPresentLatency - idealLatency + bias) /
+                vsyncInterval;
+        nsecs_t extraLatency = extraVsyncs * vsyncInterval;
+        snappedCompositeToPresentLatency = idealLatency + extraLatency;
+    }
+
+    std::lock_guard<std::mutex> lock(mCompositeTimingLock);
+    mCompositorTiming.deadline = vsyncPhase - idealLatency;
+    mCompositorTiming.interval = vsyncInterval;
+    if (snappedCompositeToPresentLatency >= 0) {
+        mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
+    }
+}
+
+void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
 {
     const HWComposer& hwc = getHwComposer();
     const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
@@ -1192,10 +1251,18 @@
     mDisplayTimeline.push(retireFenceTime);
     mDisplayTimeline.updateSignalTimes();
 
+    nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
+    nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
+
+    // We use the refreshStartTime which might be sampled a little later than
+    // when we started doing work for this frame, but that should be okay
+    // since updateCompositorTiming has snapping logic.
+    updateCompositorTiming(
+        vsyncPhase, vsyncInterval, refreshStartTime, retireFenceTime);
+
     mDrawingState.traverseInZOrder([&](Layer* layer) {
         bool frameLatched = layer->onPostComposition(glCompositionDoneFenceTime,
-                presentFenceTime, retireFenceTime);
-
+                presentFenceTime, retireFenceTime, mCompositorTiming);
         if (frameLatched) {
             recordBufferingStats(layer->getName().string(),
                     layer->getOccupancyHistory(false));
diff --git a/services/vr/sensord/sensord.rc b/services/vr/sensord/sensord.rc
index 0311474..d868a7e 100644
--- a/services/vr/sensord/sensord.rc
+++ b/services/vr/sensord/sensord.rc
@@ -1,3 +1,7 @@
+on init
+  mkdir /dev/socket/pdx/system/vr/pose 0775 system system
+  mkdir /dev/socket/pdx/system/vr/sensors 0775 system system
+
 service sensord /system/bin/sensord
   class core
   user system
diff --git a/services/vr/vr_window_manager/Android.mk b/services/vr/vr_window_manager/Android.mk
index 85f8e1f..e9552bc 100644
--- a/services/vr/vr_window_manager/Android.mk
+++ b/services/vr/vr_window_manager/Android.mk
@@ -37,33 +37,18 @@
 LOCAL_MODULE_TAGS := optional
 include $(BUILD_STATIC_LIBRARY)
 
-
 native_src := \
   application.cpp \
   controller_mesh.cpp \
   elbow_model.cpp \
   hwc_callback.cpp \
   reticle.cpp \
-  render_thread.cpp \
   shell_view.cpp \
   surface_flinger_view.cpp \
   texture.cpp \
   vr_window_manager.cpp \
   ../virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl \
 
-src := \
-  vr_window_manager_jni.cpp \
-  application.cpp \
-  controller_mesh.cpp \
-  elbow_model.cpp \
-  hwc_callback.cpp \
-  reticle.cpp \
-  render_thread.cpp \
-  shell_view.cpp \
-  surface_flinger_view.cpp \
-  texture.cpp \
-  ../virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl \
-
 static_libs := \
   libdisplay \
   libbufferhub \
@@ -86,6 +71,7 @@
   libbinder \
   libinput \
   libhardware \
+  libhwbinder \
   libsync \
   libutils \
   libgui \
@@ -97,62 +83,19 @@
   libhidlbase \
   libhidltransport
 
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(src)
-LOCAL_STATIC_LIBRARIES := $(static_libs)
-LOCAL_SHARED_LIBRARIES := $(shared_libs)
-LOCAL_SHARED_LIBRARIES += libgvr
-LOCAL_STATIC_LIBRARIES += libgvr_ext
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES
-LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES
-LOCAL_CFLAGS += -DLOG_TAG=\"VrWindowManager\"
-LOCAL_LDLIBS := -llog
-LOCAL_MODULE := libvr_window_manager_jni
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64
-LOCAL_MULTILIB := 64
-LOCAL_CXX_STL := libc++_static
-include $(BUILD_SHARED_LIBRARY)
-
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(native_src)
 LOCAL_STATIC_LIBRARIES := $(static_libs) libvrwm_binder
 LOCAL_SHARED_LIBRARIES := $(shared_libs)
-LOCAL_SHARED_LIBRARIES += libgvr
-LOCAL_STATIC_LIBRARIES += libgvr_ext
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES
 LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES
 LOCAL_CFLAGS += -DLOG_TAG=\"VrWindowManager\"
 LOCAL_LDLIBS := -llog
 LOCAL_MODULE := vr_wm
 LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64
 LOCAL_INIT_RC := vr_wm.rc
 include $(BUILD_EXECUTABLE)
 
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := VrWindowManager
-
-# We need to be priveleged to run as the system user, which is necessary for
-# getting hmd input events and doing input injection.
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := $(call all-java-files-under, java)
-LOCAL_JNI_SHARED_LIBRARIES := libvr_window_manager_jni
-LOCAL_STATIC_JAVA_AAR_LIBRARIES := gvr_common_library_aar
-# gvr_common_library_aar depends on nano version of libprotobuf
-LOCAL_STATIC_JAVA_LIBRARIES := libprotobuf-java-nano
-# Make sure that libgvr's resources are loaded
-LOCAL_AAPT_FLAGS += --auto-add-overlay
-LOCAL_AAPT_FLAGS += --extra-packages com.google.vr.cardboard
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64
-include $(BUILD_PACKAGE)
-
-
 cmd_src := \
   vr_wm_ctl.cpp \
   aidl/android/service/vr/IVrWindowManager.aidl
diff --git a/services/vr/vr_window_manager/AndroidManifest.xml b/services/vr/vr_window_manager/AndroidManifest.xml
deleted file mode 100644
index d5008a3..0000000
--- a/services/vr/vr_window_manager/AndroidManifest.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.google.vr.windowmanager"
-          coreApp="true"
-          android:sharedUserId="android.uid.system"
-          android:versionCode="1"
-          android:versionName="1.0" >
-
-  <!-- The GVR SDK requires API 19+ and OpenGL ES 2+. -->
-  <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="24" />
-  <uses-feature android:glEsVersion="0x00020000" android:required="true" />
-
-  <!-- We need the DIAGNOSTIC permission to read HMD button events. DIAGNOSTIC
-       ensures our process runs with the "input" group, so we can access
-       /dev/input. See frameworks/base/data/etc/platform.xml for the permission
-       to group mappings.
-
-       TODO(steventhomas): We shouldn't use this DIAGNOSTIC permission. Figure
-       out the correct way to get access to the HMD buttons.
-       Bug: b/33253485. -->
-  <uses-permission android:name="android.permission.DIAGNOSTIC"/>
-  <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
-
-  <application
-      android:label="vr_window_manager"
-      android:theme="@style/AppStyle">
-    <service android:name=".VrWindowManagerService" />
-    <receiver android:name="com.google.vr.windowmanager.BootCompletedReceiver">
-      <intent-filter>
-        <!-- action android:name="android.intent.action.BOOT_COMPLETED" / -->
-      </intent-filter>
-    </receiver>
-  </application>
-</manifest>
diff --git a/services/vr/vr_window_manager/application.cpp b/services/vr/vr_window_manager/application.cpp
index 895f25f..33cd499 100644
--- a/services/vr/vr_window_manager/application.cpp
+++ b/services/vr/vr_window_manager/application.cpp
@@ -16,25 +16,18 @@
 namespace android {
 namespace dvr {
 
-Application::Application()
-    : controller_api_status_logged_(false),
-      controller_connection_state_logged_(false) {}
+Application::Application() {}
 
 Application::~Application() {
 }
 
-int Application::Initialize(JNIEnv* env, jobject app_context,
-                            jobject class_loader) {
+int Application::Initialize() {
   dvrSetCpuPartition(0, "/application/performance");
 
   bool is_right_handed = true;  // TODO: retrieve setting from system
   elbow_model_.Enable(ElbowModel::kDefaultNeckPosition, is_right_handed);
   last_frame_time_ = std::chrono::system_clock::now();
 
-  java_env_ = env;
-  app_context_ = app_context;
-  class_loader_ = class_loader;
-
   return 0;
 }
 
@@ -100,42 +93,10 @@
   fov_[1] = FieldOfView(lens_info.right_fov[0], lens_info.right_fov[1],
                         lens_info.right_fov[2], lens_info.right_fov[3]);
 
-  if (java_env_) {
-    int ret = InitializeController();
-    if (ret)
-      return ret;
-  }
-
-  return 0;
-}
-
-int Application::InitializeController() {
-  gvr_context_ = gvr::GvrApi::Create(java_env_, app_context_, class_loader_);
-  if (gvr_context_ == nullptr) {
-    ALOGE("Gvr context creation failed");
-    return 1;
-  }
-
-  int32_t options = gvr_controller_get_default_options();
-  options |= GVR_CONTROLLER_ENABLE_GYRO | GVR_CONTROLLER_ENABLE_ACCEL;
-
-  controller_.reset(new gvr::ControllerApi);
-  if (!controller_->Init(java_env_, app_context_, class_loader_, options,
-                         gvr_context_->cobj())) {
-    ALOGE("Gvr controller init failed");
-    return 1;
-  }
-
-  controller_state_.reset(new gvr::ControllerState);
-
   return 0;
 }
 
 void Application::DeallocateResources() {
-  gvr_context_.reset();
-  controller_.reset();
-  controller_state_.reset();
-
   if (graphics_context_)
     dvrGraphicsContextDestroy(graphics_context_);
 
@@ -162,8 +123,8 @@
         break;
       case MainThreadTask::EnteringVrMode:
         if (!initialized_) {
-          if (AllocateResources())
-            ALOGE("Failed to allocate resources");
+          LOG_ALWAYS_FATAL_IF(AllocateResources(),
+                              "Failed to allocate resources");
         }
         break;
       case MainThreadTask::ExitingVrMode:
@@ -309,47 +270,6 @@
       return;
     }
   }
-
-  if (!controller_)
-    return;
-
-  controller_state_->Update(*controller_);
-  gvr::ControllerApiStatus new_api_status = controller_state_->GetApiStatus();
-  gvr::ControllerConnectionState new_connection_state =
-      controller_state_->GetConnectionState();
-
-  if (!controller_api_status_logged_) {
-    controller_api_status_logged_ = true;
-    ALOGI("Controller api status: %s",
-          gvr::ControllerApi::ToString(new_api_status));
-  } else if (new_api_status != controller_api_status_) {
-    ALOGI("Controller api status changed: %s --> %s",
-          gvr::ControllerApi::ToString(controller_api_status_),
-          gvr::ControllerApi::ToString(new_api_status));
-  }
-
-  if (new_api_status == gvr::kControllerApiOk) {
-    if (!controller_connection_state_logged_) {
-      controller_connection_state_logged_ = true;
-      ALOGI("Controller connection state: %s",
-            gvr::ControllerApi::ToString(new_connection_state));
-    } else if (new_connection_state != controller_connection_state_) {
-      ALOGI("Controller connection state changed: %s --> %s",
-            gvr::ControllerApi::ToString(controller_connection_state_),
-            gvr::ControllerApi::ToString(new_connection_state));
-    }
-  } else {
-    controller_connection_state_logged_ = false;
-  }
-
-  if (new_api_status == gvr::kControllerApiOk) {
-    gvr_quatf orientation = controller_state_->GetOrientation();
-    controller_orientation_ =
-        quat(orientation.qw, orientation.qx, orientation.qy, orientation.qz);
-  }
-
-  controller_api_status_ = new_api_status;
-  controller_connection_state_ = new_connection_state;
 }
 
 void Application::SetVisibility(bool visible) {
@@ -357,12 +277,6 @@
   if (changed) {
     is_visible_ = visible;
     dvrGraphicsSurfaceSetVisible(graphics_context_, is_visible_);
-    if (controller_) {
-      if (is_visible_)
-        controller_->Resume();
-      else
-        controller_->Pause();
-    }
     OnVisibilityChanged(is_visible_);
   }
 }
diff --git a/services/vr/vr_window_manager/application.h b/services/vr/vr_window_manager/application.h
index 0c6385f..c7aa4dd 100644
--- a/services/vr/vr_window_manager/application.h
+++ b/services/vr/vr_window_manager/application.h
@@ -1,15 +1,13 @@
 #ifndef VR_WINDOW_MANAGER_APPLICATION_H_
 #define VR_WINDOW_MANAGER_APPLICATION_H_
 
-#include <jni.h>
 #include <memory>
 #include <private/dvr/types.h>
 #include <stdint.h>
-#include <vr/gvr/capi/include/gvr.h>
-#include <vr/gvr/capi/include/gvr_controller.h>
 
 #include <chrono>
 #include <mutex>
+#include <vector>
 
 #include "controller_data_provider.h"
 #include "elbow_model.h"
@@ -25,8 +23,7 @@
   Application();
   virtual ~Application();
 
-  virtual int Initialize(JNIEnv* env, jobject app_context,
-                         jobject class_loader);
+  virtual int Initialize();
 
   virtual int AllocateResources();
   virtual void DeallocateResources();
@@ -59,8 +56,6 @@
 
   void QueueTask(MainThreadTask task);
 
-  int InitializeController();
-
   DvrGraphicsContext* graphics_context_ = nullptr;
   DvrPose* pose_client_ = nullptr;
 
@@ -69,15 +64,8 @@
   FieldOfView fov_[2];
   Posef last_pose_;
 
-  std::unique_ptr<gvr::GvrApi> gvr_context_;
-  std::unique_ptr<gvr::ControllerApi> controller_;
-  std::unique_ptr<gvr::ControllerState> controller_state_;
-  gvr::ControllerApiStatus controller_api_status_;
-  gvr::ControllerConnectionState controller_connection_state_;
   quat controller_orientation_;
   bool shmem_controller_active_ = false;
-  bool controller_api_status_logged_;
-  bool controller_connection_state_logged_;
   uint64_t shmem_controller_buttons_;
 
   bool is_visible_ = false;
@@ -95,11 +83,6 @@
   bool initialized_ = false;
   std::vector<MainThreadTask> main_thread_tasks_;
 
-  // Java Resources.
-  JNIEnv* java_env_;
-  jobject app_context_;
-  jobject class_loader_;
-
   // Controller data provider from shared memory buffer.
   ControllerDataProvider* controller_data_provider_ = nullptr;
 
diff --git a/services/vr/vr_window_manager/composer/impl/vr_composer_view.cpp b/services/vr/vr_window_manager/composer/impl/vr_composer_view.cpp
index 5f8168d..1096a37 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_composer_view.cpp
+++ b/services/vr/vr_window_manager/composer/impl/vr_composer_view.cpp
@@ -3,7 +3,9 @@
 namespace android {
 namespace dvr {
 
-VrComposerView::VrComposerView() : composer_view_(nullptr) {}
+VrComposerView::VrComposerView(
+    std::unique_ptr<VrComposerView::Callback> callback)
+    : composer_view_(nullptr), callback_(std::move(callback)) {}
 
 VrComposerView::~VrComposerView() {
   composer_view_->UnregisterObserver(this);
@@ -14,66 +16,19 @@
   composer_view_->RegisterObserver(this);
 }
 
-Return<void> VrComposerView::registerCallback(
-    const sp<IVrComposerCallback>& callback) {
-  callback_ = callback;
-  return Void();
-}
-
-Return<void> VrComposerView::releaseFrame() {
+void VrComposerView::ReleaseFrame() {
+  LOG_ALWAYS_FATAL_IF(!composer_view_, "VrComposerView not initialized");
   composer_view_->ReleaseFrame();
-  return Void();
 }
 
 void VrComposerView::OnNewFrame(const ComposerView::Frame& frame) {
+  std::lock_guard<std::mutex> guard(mutex_);
   if (!callback_.get()) {
-    releaseFrame();
+    ReleaseFrame();
     return;
   }
 
-  std::vector<IVrComposerCallback::Layer> layers;
-  std::vector<native_handle_t*> fences;
-  for (size_t i = 0; i < frame.size(); ++i) {
-    native_handle_t* fence;
-    if (frame[i].fence->isValid()) {
-      fence = native_handle_create(1, 0);
-      fence->data[0] = frame[i].fence->dup();
-    } else {
-      fence = native_handle_create(0, 0);
-    }
-    fences.push_back(fence);
-
-    layers.push_back(IVrComposerCallback::Layer{
-      .buffer = hidl_handle(frame[i].buffer->getNativeBuffer()->handle),
-      .fence = hidl_handle(fence),
-      .display_frame = frame[i].display_frame,
-      .crop = frame[i].crop,
-      .blend_mode= frame[i].blend_mode,
-      .alpha = frame[i].alpha,
-      .type = frame[i].type,
-      .app_id = frame[i].app_id,
-    });
-  }
-
-  auto status =
-      callback_->onNewFrame(hidl_vec<IVrComposerCallback::Layer>(layers));
-  if (!status.isOk()) {
-    ALOGE("Failed to send onNewFrame: %s", status.description().c_str());
-    releaseFrame();
-  }
-
-  for (size_t i = 0; i < fences.size(); ++i) {
-    native_handle_close(fences[i]);
-    native_handle_delete(fences[i]);
-  }
-}
-
-VrComposerView* GetVrComposerViewFromIVrComposerView(IVrComposerView* view) {
-  return static_cast<VrComposerView*>(view);
-}
-
-IVrComposerView* HIDL_FETCH_IVrComposerView(const char* name) {
-  return new VrComposerView();
+  callback_->OnNewFrame(frame);
 }
 
 }  // namespace dvr
diff --git a/services/vr/vr_window_manager/composer/impl/vr_composer_view.h b/services/vr/vr_window_manager/composer/impl/vr_composer_view.h
index 133bbc8..5a938e9 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_composer_view.h
+++ b/services/vr/vr_window_manager/composer/impl/vr_composer_view.h
@@ -1,41 +1,37 @@
 #ifndef VR_WINDOW_MANAGER_COMPOSER_IMPL_VR_COMPOSER_VIEW_H_
 #define VR_WINDOW_MANAGER_COMPOSER_IMPL_VR_COMPOSER_VIEW_H_
 
-#include <android/dvr/composer/1.0/IVrComposerCallback.h>
-#include <android/dvr/composer/1.0/IVrComposerView.h>
+#include <memory>
 
 #include "vr_hwc.h"
 
 namespace android {
 namespace dvr {
 
-using composer::V1_0::IVrComposerView;
-using composer::V1_0::IVrComposerCallback;
-
-class VrComposerView : public IVrComposerView, public ComposerView::Observer {
+class VrComposerView : public ComposerView::Observer {
  public:
-  VrComposerView();
+  class Callback {
+   public:
+    virtual ~Callback() = default;
+    virtual void OnNewFrame(const ComposerView::Frame& frame) = 0;
+  };
+
+  VrComposerView(std::unique_ptr<Callback> callback);
   ~VrComposerView() override;
 
   void Initialize(ComposerView* composer_view);
 
-  // IVrComposerView
-  Return<void> registerCallback(const sp<IVrComposerCallback>& callback)
-      override;
-  Return<void> releaseFrame() override;
+  void ReleaseFrame();
 
   // ComposerView::Observer
   void OnNewFrame(const ComposerView::Frame& frame) override;
 
  private:
   ComposerView* composer_view_;
-  sp<IVrComposerCallback> callback_;
+  std::unique_ptr<Callback> callback_;
+  std::mutex mutex_;
 };
 
-VrComposerView* GetVrComposerViewFromIVrComposerView(IVrComposerView* view);
-
-IVrComposerView* HIDL_FETCH_IVrComposerView(const char* name);
-
 }  // namespace dvr
 }  // namespace android
 
diff --git a/services/vr/vr_window_manager/hwc_callback.cpp b/services/vr/vr_window_manager/hwc_callback.cpp
index 12a76d8..b29d175 100644
--- a/services/vr/vr_window_manager/hwc_callback.cpp
+++ b/services/vr/vr_window_manager/hwc_callback.cpp
@@ -12,11 +12,16 @@
 namespace {
 
 sp<GraphicBuffer> GetBufferFromHandle(const native_handle_t* handle) {
+  GraphicBufferMapper& mapper = GraphicBufferMapper::get();
+  if (mapper.registerBuffer(handle) != OK) {
+    ALOGE("Failed to register buffer");
+    return nullptr;
+  }
+
   uint32_t width = 0, height = 0, stride = 0, layer_count = 1;
   uint64_t producer_usage = 0, consumer_usage = 0;
   int32_t format = 0;
 
-  GraphicBufferMapper& mapper = GraphicBufferMapper::get();
   if (mapper.getDimensions(handle, &width, &height) ||
       mapper.getStride(handle, &stride) ||
       mapper.getFormat(handle, &format) ||
@@ -33,10 +38,6 @@
   sp<GraphicBuffer> buffer = new GraphicBuffer(
       width, height, format, layer_count, producer_usage, consumer_usage,
       stride, native_handle_clone(handle), true);
-  if (mapper.registerBuffer(buffer.get()) != OK) {
-    ALOGE("Failed to register buffer");
-    return nullptr;
-  }
 
   return buffer;
 }
@@ -62,27 +63,18 @@
 
 }  // namespace
 
-HwcCallback::HwcCallback(IVrComposerView* composer_view, Client* client)
-    : composer_view_(composer_view),
-      client_(client) {
-  composer_view_->registerCallback(this);
+HwcCallback::HwcCallback(Client* client) : client_(client) {
 }
 
 HwcCallback::~HwcCallback() {
-  composer_view_->registerCallback(nullptr);
 }
 
-Return<void> HwcCallback::onNewFrame(
-    const hidl_vec<IVrComposerCallback::Layer>& frame) {
-
+void HwcCallback::OnNewFrame(const ComposerView::Frame& frame) {
   std::vector<HwcLayer> hwc_frame(frame.size());
   for (size_t i = 0; i < frame.size(); ++i) {
-    int fence = frame[i].fence.getNativeHandle()->numFds ?
-        dup(frame[i].fence.getNativeHandle()->data[0]) : -1;
-
     hwc_frame[i] = HwcLayer{
-      .fence = new Fence(fence),
-      .buffer = GetBufferFromHandle(frame[i].buffer.getNativeHandle()),
+      .fence = frame[i].fence,
+      .buffer = frame[i].buffer,
       .crop = frame[i].crop,
       .display_frame = frame[i].display_frame,
       .blending = static_cast<int32_t>(frame[i].blend_mode),
@@ -92,10 +84,7 @@
     };
   }
 
-  std::lock_guard<std::mutex> guard(mutex_);
   client_->OnFrame(std::make_unique<Frame>(std::move(hwc_frame)));
-
-  return Void();
 }
 
 HwcCallback::Frame::Frame(std::vector<HwcLayer>&& layers)
diff --git a/services/vr/vr_window_manager/hwc_callback.h b/services/vr/vr_window_manager/hwc_callback.h
index 05a889b..d4d6e66 100644
--- a/services/vr/vr_window_manager/hwc_callback.h
+++ b/services/vr/vr_window_manager/hwc_callback.h
@@ -6,8 +6,7 @@
 #include <mutex>
 #include <vector>
 
-#include <android/dvr/composer/1.0/IVrComposerCallback.h>
-#include <android/dvr/composer/1.0/IVrComposerView.h>
+#include <impl/vr_composer_view.h>
 #include <impl/vr_hwc.h>
 
 namespace android {
@@ -20,10 +19,7 @@
 using Recti = ComposerView::ComposerLayer::Recti;
 using Rectf = ComposerView::ComposerLayer::Rectf;
 
-using composer::V1_0::IVrComposerCallback;
-using composer::V1_0::IVrComposerView;
-
-class HwcCallback : public IVrComposerCallback {
+class HwcCallback : public VrComposerView::Callback {
  public:
   struct HwcLayer {
     enum LayerType : uint32_t {
@@ -86,19 +82,12 @@
     virtual void OnFrame(std::unique_ptr<Frame>) = 0;
   };
 
-  explicit HwcCallback(IVrComposerView* composer_view, Client* client);
+  explicit HwcCallback(Client* client);
   ~HwcCallback() override;
 
  private:
-  // This is the only method called on the binder thread. Everything else is
-  // called on the render thread.
-  Return<void> onNewFrame(const hidl_vec<IVrComposerCallback::Layer>& frame)
-      override;
-
-  IVrComposerView* composer_view_;
+  void OnNewFrame(const ComposerView::Frame& frame) override;
   Client *client_;
-  std::mutex mutex_;
-
 
   HwcCallback(const HwcCallback&) = delete;
   void operator=(const HwcCallback&) = delete;
diff --git a/services/vr/vr_window_manager/java/com/google/vr/windowmanager/BootCompletedReceiver.java b/services/vr/vr_window_manager/java/com/google/vr/windowmanager/BootCompletedReceiver.java
deleted file mode 100644
index 01d1bdb..0000000
--- a/services/vr/vr_window_manager/java/com/google/vr/windowmanager/BootCompletedReceiver.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.google.vr.windowmanager;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-
-public class BootCompletedReceiver extends BroadcastReceiver {
-  private static final String TAG = BootCompletedReceiver.class.getSimpleName();
-
-  @Override
-  public void onReceive(Context context, Intent intent) {
-    Log.i(TAG, "Starting VRWindowManager");
-    Intent vrWindowManagerIntent = new Intent(context, VrWindowManagerService.class);
-    context.startService(vrWindowManagerIntent);
-  }
-}
diff --git a/services/vr/vr_window_manager/java/com/google/vr/windowmanager/VrWindowManagerService.java b/services/vr/vr_window_manager/java/com/google/vr/windowmanager/VrWindowManagerService.java
deleted file mode 100644
index 1d815ca..0000000
--- a/services/vr/vr_window_manager/java/com/google/vr/windowmanager/VrWindowManagerService.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package com.google.vr.windowmanager;
-
-import android.app.Service;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Handler;
-import android.os.IBinder;
-import android.util.Log;
-
-public class VrWindowManagerService extends Service {
-  private static final String TAG = VrWindowManagerService.class.getSimpleName();
-  private long nativeVrWindowManager;
-
-  // This is a temporary debugging tool for development only.
-  // It allows us to show VrWindowManager in debug mode via command line.
-  private final BroadcastReceiver debugReceiver = new BroadcastReceiver() {
-    @Override
-    public void onReceive(Context context, Intent intent) {
-      String action = intent.getAction();
-      if (action.equals("com.google.vr.windowmanager.intent.SHOW")) {
-        nativeEnableDebug(nativeVrWindowManager);
-      } else if (action.equals("com.google.vr.windowmanager.intent.HIDE")) {
-        nativeDisableDebug(nativeVrWindowManager);
-      } else if (action.equals("com.google.vr.windowmanager.intent.ENTER_VR")) {
-        nativeEnterVrMode(nativeVrWindowManager);
-      } else if (action.equals("com.google.vr.windowmanager.intent.EXIT_VR")) {
-        nativeExitVrMode(nativeVrWindowManager);
-      }
-    }
-  };
-
-  static {
-    System.loadLibrary("vr_window_manager_jni");
-  }
-
-  @Override
-  public void onCreate() {
-    super.onCreate();
-    destroyRenderer();
-    nativeVrWindowManager = nativeCreate(getClass().getClassLoader(), getApplicationContext());
-    if (nativeVrWindowManager == 0) {
-      Log.e(TAG, "Failed to create native renderer");
-    }
-
-    // For development, testing and debugging.
-    IntentFilter filter = new IntentFilter();
-    filter.addAction("com.google.vr.windowmanager.intent.SHOW");
-    filter.addAction("com.google.vr.windowmanager.intent.HIDE");
-    filter.addAction("com.google.vr.windowmanager.intent.ENTER_VR");
-    filter.addAction("com.google.vr.windowmanager.intent.EXIT_VR");
-    registerReceiver(debugReceiver, filter);
-  }
-
-  @Override
-  public int onStartCommand(Intent intent, int flags, int startId) {
-    return START_STICKY;
-  }
-
-  @Override
-  public IBinder onBind(Intent intent) {
-    Log.i(TAG, "Ignoring bind request");
-    return null;
-  }
-
-  @Override
-  public void onDestroy() {
-    super.onDestroy();
-    unregisterReceiver(debugReceiver);
-    destroyRenderer();
-  }
-
-  private void destroyRenderer() {
-    if (nativeVrWindowManager != 0) {
-      nativeDestroy(nativeVrWindowManager);
-      nativeVrWindowManager = 0;
-    }
-  }
-
-  private native long nativeCreate(ClassLoader appClassLoader, Context context);
-  private native void nativeDestroy(long nativeVrWindowManager);
-  private native void nativeEnableDebug(long nativeVrWindowManager);
-  private native void nativeDisableDebug(long nativeVrWindowManager);
-  private native void nativeEnterVrMode(long nativeVrWindowManager);
-  private native void nativeExitVrMode(long nativeVrWindowManager);
-}
diff --git a/services/vr/vr_window_manager/render_thread.cpp b/services/vr/vr_window_manager/render_thread.cpp
deleted file mode 100644
index b67a051..0000000
--- a/services/vr/vr_window_manager/render_thread.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-#include <jni.h>
-#include <log/log.h>
-#include <future>
-
-#include "render_thread.h"
-#include "shell_view.h"
-
-namespace android {
-namespace dvr {
-
-RenderThread::RenderThread(JNIEnv* env, jobject class_loader,
-                           jobject android_context)
-    : jvm_(nullptr),
-      class_loader_global_ref_(0),
-      android_context_global_ref_(0),
-      quit_(false) {
-  env->GetJavaVM(&jvm_);
-
-  // Create global references so we can access these objects on the render
-  // thread
-  class_loader_global_ref_ = env->NewGlobalRef(class_loader);
-  android_context_global_ref_ = env->NewGlobalRef(android_context);
-
-  std::promise<int> render_thread_init_result_promise;
-  thread_ = std::thread([this, &render_thread_init_result_promise] {
-    JNIEnv* render_thread_jni_env = nullptr;
-    jvm_->AttachCurrentThread(&render_thread_jni_env, nullptr);
-    RunRenderLoop(&render_thread_init_result_promise);
-    jvm_->DetachCurrentThread();
-  });
-
-  // Wait to see if the render thread started successfully. If not bail.
-  int render_thread_init_result =
-      render_thread_init_result_promise.get_future().get();
-  LOG_ALWAYS_FATAL_IF(render_thread_init_result != 0,
-                      "Failed initializing render thread. result=%d",
-                      render_thread_init_result);
-}
-
-RenderThread::~RenderThread() { Quit(); }
-
-void RenderThread::Quit() {
-  if (thread_.joinable()) {
-    quit_ = true;
-    thread_.join();
-  }
-
-  JNIEnv* env = GetJniEnv();
-  if (class_loader_global_ref_ != 0) {
-    env->DeleteGlobalRef(class_loader_global_ref_);
-    class_loader_global_ref_ = 0;
-  }
-  if (android_context_global_ref_ != 0) {
-    env->DeleteGlobalRef(android_context_global_ref_);
-    android_context_global_ref_ = 0;
-  }
-}
-
-void RenderThread::EnableDebug(bool debug) { shell_view_.EnableDebug(debug); }
-
-void RenderThread::VrMode(bool mode) { shell_view_.VrMode(mode); }
-
-JNIEnv* RenderThread::GetJniEnv() {
-  JNIEnv* env;
-  jvm_->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
-  return env;
-}
-
-void RenderThread::RunRenderLoop(
-    std::promise<int>* init_result_promise) {
-  // TODO(steventhomas): Create local refs to work around b/33251144. Remove
-  // once that bug is fixed.
-  JNIEnv* env = GetJniEnv();
-  jobject class_loader = env->NewLocalRef(class_loader_global_ref_);
-  jobject android_context = env->NewLocalRef(android_context_global_ref_);
-
-  int init_result = shell_view_.Initialize(env, android_context, class_loader);
-  init_result_promise->set_value(init_result);
-  if (init_result == 0) {
-    while (!quit_)
-      shell_view_.DrawFrame();
-  } else {
-    ALOGE("Failed to initialize ShellView");
-  }
-
-  env->DeleteLocalRef(class_loader);
-  env->DeleteLocalRef(android_context);
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/services/vr/vr_window_manager/render_thread.h b/services/vr/vr_window_manager/render_thread.h
deleted file mode 100644
index e193643..0000000
--- a/services/vr/vr_window_manager/render_thread.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef VR_WINDOW_MANAGER_RENDER_THREAD_H_
-#define VR_WINDOW_MANAGER_RENDER_THREAD_H_
-
-#include <atomic>
-#include <future>
-#include <jni.h>
-#include <thread>
-
-#include "shell_view.h"
-
-namespace android {
-namespace dvr {
-
-class RenderThread {
- public:
-  RenderThread(JNIEnv* env, jobject class_loader, jobject android_context);
-  ~RenderThread();
-  void Quit();
-  void EnableDebug(bool debug);
-  void VrMode(bool mode);
-
-  RenderThread(const RenderThread&) = delete;
-  void operator=(const RenderThread&) = delete;
-
- private:
-  // Called by both the main thread and render thread. Will return the correct
-  // JNIEnv for the current thread.
-  JNIEnv* GetJniEnv();
-
-  void RunRenderLoop(std::promise<int>* init_result_promise);
-
-  // Accessed only by the main thread.
-  std::thread thread_;
-
-  // The vars below are accessed by both the main thread and the render thread.
-  JavaVM* jvm_;
-  jobject class_loader_global_ref_;
-  jobject android_context_global_ref_;
-  std::atomic_bool quit_;
-
-  ShellView shell_view_;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // VR_WINDOW_MANAGER_RENDER_THREAD_H_
diff --git a/services/vr/vr_window_manager/res/drawable-nodpi/vr_icon.png b/services/vr/vr_window_manager/res/drawable-nodpi/vr_icon.png
deleted file mode 100644
index 06f896d..0000000
--- a/services/vr/vr_window_manager/res/drawable-nodpi/vr_icon.png
+++ /dev/null
Binary files differ
diff --git a/services/vr/vr_window_manager/res/drawable-nodpi/vr_icon_background.png b/services/vr/vr_window_manager/res/drawable-nodpi/vr_icon_background.png
deleted file mode 100644
index d336da3..0000000
--- a/services/vr/vr_window_manager/res/drawable-nodpi/vr_icon_background.png
+++ /dev/null
Binary files differ
diff --git a/services/vr/vr_window_manager/res/values/styles.xml b/services/vr/vr_window_manager/res/values/styles.xml
deleted file mode 100644
index 8a1a74b..0000000
--- a/services/vr/vr_window_manager/res/values/styles.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-<add-resource type="style" name="AppStyle"></add-resource>
-<style name="AppStyle"
-    parent="@android:style/Theme.Holo.NoActionBar.Fullscreen">
-  <item name="android:windowDisablePreview">true</item>
-</style>
-</resources>
diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp
index 29ade64..84b8467 100644
--- a/services/vr/vr_window_manager/shell_view.cpp
+++ b/services/vr/vr_window_manager/shell_view.cpp
@@ -238,9 +238,8 @@
 
 ShellView::~ShellView() {}
 
-int ShellView::Initialize(JNIEnv* env, jobject app_context,
-                          jobject class_loader) {
-  int ret = Application::Initialize(env, app_context, class_loader);
+int ShellView::Initialize() {
+  int ret = Application::Initialize();
   if (ret)
     return ret;
 
@@ -604,10 +603,7 @@
   vec3 pointer_location = last_pose_.GetPosition();
   quat view_quaternion = last_pose_.GetRotation();
 
-  bool gvr_api_active =
-      controller_ && controller_api_status_ == gvr::kControllerApiOk;
-
-  if (gvr_api_active || shmem_controller_active_) {
+  if (shmem_controller_active_) {
     view_quaternion = controller_orientation_;
     vec4 controller_location = controller_translate_ * vec4(0, 0, 0, 1);
     pointer_location = vec3(controller_location.x(), controller_location.y(),
@@ -635,18 +631,6 @@
         }
         buttons >>= 4;
       }
-    } else if (controller_) {
-      if (controller_state_->GetButtonDown(gvr::kControllerButtonClick))
-        OnClick(true);
-
-      if (controller_state_->GetButtonUp(gvr::kControllerButtonClick))
-        OnClick(false);
-
-      if (controller_state_->GetButtonDown(gvr::kControllerButtonApp))
-        OnTouchpadButton(true, AMOTION_EVENT_BUTTON_BACK);
-
-      if (controller_state_->GetButtonUp(gvr::kControllerButtonApp))
-        OnTouchpadButton(false, AMOTION_EVENT_BUTTON_BACK);
     }
   }
 
@@ -676,7 +660,7 @@
 
 void ShellView::DrawController(const mat4& perspective, const mat4& eye_matrix,
                                const mat4& head_matrix) {
-  if (!controller_ && !shmem_controller_active_)
+  if (!shmem_controller_active_)
     return;
 
   controller_program_->Use();
diff --git a/services/vr/vr_window_manager/shell_view.h b/services/vr/vr_window_manager/shell_view.h
index 14ad0f3..39b5451 100644
--- a/services/vr/vr_window_manager/shell_view.h
+++ b/services/vr/vr_window_manager/shell_view.h
@@ -28,8 +28,7 @@
   ShellView();
   virtual ~ShellView();
 
-  int Initialize(JNIEnv* env, jobject app_context,
-                 jobject class_loader) override;
+  int Initialize() override;
 
   int AllocateResources() override;
   void DeallocateResources() override;
diff --git a/services/vr/vr_window_manager/surface_flinger_view.cpp b/services/vr/vr_window_manager/surface_flinger_view.cpp
index b15d262..7b17420 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.cpp
+++ b/services/vr/vr_window_manager/surface_flinger_view.cpp
@@ -1,6 +1,5 @@
 #include "surface_flinger_view.h"
 
-#include <binder/IServiceManager.h>
 #include <impl/vr_composer_view.h>
 #include <private/dvr/native_buffer.h>
 
@@ -15,23 +14,20 @@
 SurfaceFlingerView::~SurfaceFlingerView() {}
 
 bool SurfaceFlingerView::Initialize(HwcCallback::Client *client) {
-  const char instance[] = "DaydreamDisplay";
-  composer_service_ = IVrComposerView::getService(instance);
-  if (composer_service_ == nullptr) {
-    ALOGE("Failed to initialize composer service");
+  sp<IComposer> vr_hwcomposer = IComposer::getService("vr_hwcomposer");
+  if (!vr_hwcomposer.get()) {
+    ALOGE("vr_hwcomposer not registered as service");
     return false;
   }
 
-  if (!composer_service_->isRemote()) {
-    ALOGE("Composer service is not remote");
-    return false;
-  }
+  vr_composer_view_ =
+      std::make_unique<VrComposerView>(std::make_unique<HwcCallback>(client));
+  vr_composer_view_->Initialize(GetComposerViewFromIComposer(
+      vr_hwcomposer.get()));
 
   // TODO(dnicoara): Query this from the composer service.
   width_ = 1920;
   height_ = 1080;
-
-  composer_observer_.reset(new HwcCallback(composer_service_.get(), client));
   return true;
 }
 
@@ -76,7 +72,7 @@
 }
 
 void SurfaceFlingerView::ReleaseFrame() {
-  composer_service_->releaseFrame();
+  vr_composer_view_->ReleaseFrame();
 }
 
 }  // namespace dvr
diff --git a/services/vr/vr_window_manager/surface_flinger_view.h b/services/vr/vr_window_manager/surface_flinger_view.h
index 2e36ec1..8d9b44e 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.h
+++ b/services/vr/vr_window_manager/surface_flinger_view.h
@@ -1,10 +1,10 @@
 #ifndef APPLICATIONS_EXPERIMENTS_SURFACE_FLINGER_DEMO_SURFACE_FLINGER_VIEW_H_
 #define APPLICATIONS_EXPERIMENTS_SURFACE_FLINGER_DEMO_SURFACE_FLINGER_VIEW_H_
 
-#include <utils/StrongPointer.h>
-
 #include <memory>
 
+#include <impl/vr_composer_view.h>
+
 #include "hwc_callback.h"
 
 namespace android {
@@ -39,9 +39,7 @@
   void ReleaseFrame();
 
  private:
-  sp<IVrComposerView> composer_service_;
-  std::unique_ptr<HwcCallback> composer_observer_;
-
+  std::unique_ptr<VrComposerView> vr_composer_view_;
   int width_ = 0;
   int height_ = 0;
 
diff --git a/services/vr/vr_window_manager/vr_window_manager.cpp b/services/vr/vr_window_manager/vr_window_manager.cpp
index c51ddee..5e9215c 100644
--- a/services/vr/vr_window_manager/vr_window_manager.cpp
+++ b/services/vr/vr_window_manager/vr_window_manager.cpp
@@ -1,33 +1,60 @@
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
+#include <hwbinder/IPCThreadState.h>
+#include <impl/vr_composer_view.h>
+#include <impl/vr_hwc.h>
 
 #include "shell_view.h"
 #include "vr_window_manager_binder.h"
 
+using namespace android;
+using namespace android::dvr;
+
 int main(int /* argc */, char** /* argv */) {
-  android::dvr::ShellView app;
-  const int app_status = app.Initialize(nullptr, nullptr, nullptr);
-  LOG_ALWAYS_FATAL_IF(app_status != 0, "failed to initialize: %d", app_status);
-
-  android::service::vr::VrWindowManagerBinder service(app);
-  const int status = service.Initialize();
-  LOG_ALWAYS_FATAL_IF(status != 0, "initialization failed: %d", status);
-
   android::ProcessState::self()->startThreadPool();
 
+  // Create vr_hwcomposer.
+  const char vr_hwcomposer_name[] = "vr_hwcomposer";
+  sp<IComposer> vr_hwcomposer = HIDL_FETCH_IComposer(vr_hwcomposer_name);
+  LOG_ALWAYS_FATAL_IF(!vr_hwcomposer.get(), "Failed to get vr_hwcomposer");
+  LOG_ALWAYS_FATAL_IF(vr_hwcomposer->isRemote(),
+                      "vr_hwcomposer service is remote");
+
+  const android::status_t vr_hwcomposer_status =
+      vr_hwcomposer->registerAsService(vr_hwcomposer_name);
+  LOG_ALWAYS_FATAL_IF(vr_hwcomposer_status != ::android::OK,
+                      "Failed to register vr_hwcomposer service");
+
+  // ShellView needs to be created after vr_hwcomposer.
+  android::dvr::ShellView app;
+  const int app_status = app.Initialize();
+  LOG_ALWAYS_FATAL_IF(app_status != 0, "failed to initialize: %d", app_status);
+
+  // Create vr_wm_binder.
+  android::service::vr::VrWindowManagerBinder vr_wm_binder(app);
+  const int status = vr_wm_binder.Initialize();
+  LOG_ALWAYS_FATAL_IF(status != 0, "initialization failed: %d", status);
+
   android::sp<android::IServiceManager> sm(android::defaultServiceManager());
-  const android::status_t service_status = sm->addService(
-      android::service::vr::VrWindowManagerBinder::SERVICE_NAME(), &service,
-      false /*allowIsolated*/);
-  LOG_ALWAYS_FATAL_IF(service_status != android::OK, "service not added: %d",
-                      static_cast<int>(service_status));
+  const android::status_t vr_wm_binder_status =
+      sm->addService(
+          android::service::vr::VrWindowManagerBinder::SERVICE_NAME(),
+          &vr_wm_binder, false /*allowIsolated*/);
+  LOG_ALWAYS_FATAL_IF(vr_wm_binder_status != android::OK,
+                      "vr_wm_binder service not added: %d",
+                      static_cast<int>(vr_wm_binder_status));
 
-  app.SetControllerDataProvider(&service);
+  app.SetControllerDataProvider(&vr_wm_binder);
 
-  while (true)
+  android::hardware::ProcessState::self()->startThreadPool();
+
+  while (true) {
     app.DrawFrame();
+  }
 
+  android::hardware::IPCThreadState::self()->joinThreadPool();
   android::IPCThreadState::self()->joinThreadPool();
+
   return 0;
 }
diff --git a/services/vr/vr_window_manager/vr_window_manager_jni.cpp b/services/vr/vr_window_manager/vr_window_manager_jni.cpp
deleted file mode 100644
index 49eaba1..0000000
--- a/services/vr/vr_window_manager/vr_window_manager_jni.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-#include <jni.h>
-#include <log/log.h>
-
-#include <memory>
-
-#include "render_thread.h"
-
-#define JNI_METHOD(return_type, method_name) \
-  JNIEXPORT return_type JNICALL              \
-      Java_com_google_vr_windowmanager_VrWindowManagerService_##method_name
-
-namespace {
-
-inline jlong jptr(android::dvr::RenderThread* native_vr_window_manager) {
-  return reinterpret_cast<intptr_t>(native_vr_window_manager);
-}
-
-inline android::dvr::RenderThread* native(jlong ptr) {
-  return reinterpret_cast<android::dvr::RenderThread*>(ptr);
-}
-
-}  // namespace
-
-extern "C" {
-
-JNI_METHOD(jlong, nativeCreate)(JNIEnv* env, jclass /*clazz*/,
-                                jobject class_loader,
-                                jobject android_context) {
-  return jptr(new android::dvr::RenderThread(
-      env, class_loader, android_context));
-}
-
-JNI_METHOD(void, nativeDestroy)
-(JNIEnv* /*env*/, jclass /*clazz*/, jlong native_render_thread) {
-  delete native(native_render_thread);
-}
-
-JNI_METHOD(void, nativeEnableDebug)
-(JNIEnv* /*env*/, jclass /*clazz*/, jlong native_render_thread) {
-  native(native_render_thread)->EnableDebug(true);
-}
-
-JNI_METHOD(void, nativeDisableDebug)
-(JNIEnv* /*env*/, jclass /*clazz*/, jlong native_render_thread) {
-  native(native_render_thread)->EnableDebug(false);
-}
-
-JNI_METHOD(void, nativeEnterVrMode)
-(JNIEnv* /*env*/, jclass /*clazz*/, jlong native_render_thread) {
-  native(native_render_thread)->VrMode(true);
-}
-
-JNI_METHOD(void, nativeExitVrMode)
-(JNIEnv* /*env*/, jclass /*clazz*/, jlong native_render_thread) {
-  native(native_render_thread)->VrMode(false);
-}
-
-}  // extern "C"
diff --git a/services/vr/vr_window_manager/vr_wm.rc b/services/vr/vr_window_manager/vr_wm.rc
index 143b916..951515b 100644
--- a/services/vr/vr_window_manager/vr_wm.rc
+++ b/services/vr/vr_window_manager/vr_wm.rc
@@ -3,7 +3,3 @@
   user system
   group system graphics input
   cpuset /system
-  disabled
-
-on property:persist.daydream.vr_wm=1
-  enable vr_wm
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index a23056c..32f777d 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -739,10 +739,8 @@
     const InstanceData& data = GetData(physicalDevice);
     static const std::array<VkExtensionProperties, 2> loader_extensions = {{
         // WSI extensions
-#if 0 // Remove this "#if 0" once the VK_KHR_incremental_present extension is ratified
         {VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME,
          VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION},
-#endif
         {VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME,
          VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION},
     }};