Merge "Revert "Quick fix to correctly handle empty file/channel handles.""
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp
index 225de20..69ed416 100644
--- a/cmds/atrace/Android.bp
+++ b/cmds/atrace/Android.bp
@@ -16,9 +16,6 @@
         "libz",
         "libbase",
     ],
-    static_libs: [
-        "libpdx_default_transport",
-    ],
 
     init_rc: ["atrace.rc"],
 }
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 14eff03..05e1615 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -18,7 +18,6 @@
 
 #include <errno.h>
 #include <fcntl.h>
-#include <ftw.h>
 #include <getopt.h>
 #include <inttypes.h>
 #include <signal.h>
@@ -42,7 +41,6 @@
 #include <hidl/ServiceManagement.h>
 #include <cutils/properties.h>
 
-#include <pdx/default_transport/service_utility.h>
 #include <utils/String8.h>
 #include <utils/Timers.h>
 #include <utils/Tokenizer.h>
@@ -50,7 +48,6 @@
 #include <android-base/file.h>
 
 using namespace android;
-using pdx::default_transport::ServiceUtility;
 
 using std::string;
 #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
@@ -568,46 +565,6 @@
     }
 }
 
-// Sends the sysprop_change message to the service at fpath, so it re-reads its
-// system properties. Returns 0 on success or a negated errno code on failure.
-static int pokeOnePDXService(const char *fpath, const struct stat * /*sb*/,
-                             int typeflag, struct FTW * /*ftwbuf*/)
-{
-    const bool kIgnoreErrors = true;
-
-    if (typeflag == FTW_F) {
-        int error;
-        auto utility = ServiceUtility::Create(fpath, &error);
-        if (!utility) {
-            if (error != -ECONNREFUSED) {
-                ALOGE("pokeOnePDXService: Failed to open %s, %s.", fpath,
-                      strerror(-error));
-            }
-            return kIgnoreErrors ? 0 : error;
-        }
-
-        auto status = utility->ReloadSystemProperties();
-        if (!status) {
-            ALOGE("pokeOnePDXService: Failed to send sysprop change to %s, "
-                  "error %d, %s.", fpath, status.error(),
-                  status.GetErrorMessage().c_str());
-            return kIgnoreErrors ? 0 : -status.error();
-        }
-    }
-
-    return 0;
-}
-
-// Pokes all the PDX processes in the system to get them to re-read
-// their system properties. Returns true on success, false on failure.
-static bool pokePDXServices()
-{
-    const int kMaxDepth = 16;
-    const int result = nftw(ServiceUtility::GetRootEndpointPath().c_str(),
-                            pokeOnePDXService, kMaxDepth, FTW_PHYS);
-    return result == 0 ? true : false;
-}
-
 // Set the trace tags that userland tracing uses, and poke the running
 // processes to pick up the new value.
 static bool setTagsProperty(uint64_t tags)
@@ -851,7 +808,6 @@
     ok &= setAppCmdlineProperty(&packageList[0]);
     ok &= pokeBinderServices();
     pokeHalServices();
-    ok &= pokePDXServices();
 
     // Disable all the sysfs enables.  This is done as a separate loop from
     // the enables to allow the same enable to exist in multiple categories.
@@ -889,7 +845,6 @@
     setTagsProperty(0);
     clearAppProperties();
     pokeBinderServices();
-    pokePDXServices();
 
     // Set the options back to their defaults.
     setTraceOverwriteEnable(true);
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index d1e94ed..a407ea2 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -16,6 +16,7 @@
         utils.cpp
 COMMON_SHARED_LIBRARIES := \
         android.hardware.dumpstate@1.0 \
+        android.hidl.manager@1.0 \
         libhidlbase \
         libbase \
         libbinder \
@@ -93,10 +94,6 @@
 # ==========#
 include $(CLEAR_VARS)
 
-ifdef BOARD_WLAN_DEVICE
-LOCAL_CFLAGS := -DFWDUMP_$(BOARD_WLAN_DEVICE)
-endif
-
 LOCAL_SRC_FILES := $(COMMON_SRC_FILES) \
         DumpstateService.cpp \
         dumpstate.cpp
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 5430956..efe0466 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -97,6 +97,8 @@
     dprintf(fd, "now: %ld\n", ds_.now_);
     dprintf(fd, "is_zipping: %s\n", ds_.IsZipping() ? "true" : "false");
     dprintf(fd, "listener: %s\n", ds_.listener_name_.c_str());
+    dprintf(fd, "notification title: %s\n", ds_.notification_title.c_str());
+    dprintf(fd, "notification description: %s\n", ds_.notification_description.c_str());
 
     return NO_ERROR;
 }
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 9434d56..f898b90 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -116,6 +116,8 @@
 static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
 static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
 static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
+static constexpr char PROPERTY_EXTRA_TITLE[] = "dumpstate.options.title";
+static constexpr char PROPERTY_EXTRA_DESCRIPTION[] = "dumpstate.options.description";
 
 static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
 
@@ -1037,26 +1039,11 @@
     RunCommand("WIFI NETWORKS", {"wpa_cli", "IFNAME=wlan0", "list_networks"},
                CommandOptions::WithTimeout(20).Build());
 
-#ifdef FWDUMP_bcmdhd
-    RunCommand("ND OFFLOAD TABLE", {WLUTIL, "nd_hostip"}, CommandOptions::AS_ROOT);
-
-    RunCommand("DUMP WIFI INTERNAL COUNTERS (1)", {WLUTIL, "counters"}, AS_ROOT_20);
-
-    RunCommand("ND OFFLOAD STATUS (1)", {WLUTIL, "nd_status"}, CommandOptions::AS_ROOT);
-
-#endif
     DumpFile("INTERRUPTS (1)", "/proc/interrupts");
 
     RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
                CommandOptions::WithTimeout(10).Build());
 
-#ifdef FWDUMP_bcmdhd
-    RunCommand("DUMP WIFI STATUS", {"dhdutil", "-i", "wlan0", "dump"}, AS_ROOT_20);
-
-    RunCommand("DUMP WIFI INTERNAL COUNTERS (2)", {WLUTIL, "counters"}, AS_ROOT_20);
-
-    RunCommand("ND OFFLOAD STATUS (2)", {WLUTIL, "nd_status"}, CommandOptions::AS_ROOT);
-#endif
     DumpFile("INTERRUPTS (2)", "/proc/interrupts");
 
     RunCommand("SYSTEM PROPERTIES", {"getprop"});
@@ -1452,6 +1439,20 @@
         android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
     }
 
+    ds.notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
+    if (!ds.notification_title.empty()) {
+        // Reset the property
+        android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
+
+        ds.notification_description = android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
+        if (!ds.notification_description.empty()) {
+            // Reset the property
+            android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
+        }
+        MYLOGD("notification (title:  %s, description: %s)\n",
+               ds.notification_title.c_str(), ds.notification_description.c_str());
+    }
+
     if ((do_zip_file || do_add_date || ds.update_progress_ || do_broadcast) && !use_outfile) {
         ExitOnInvalidArgs();
     }
@@ -1814,6 +1815,16 @@
                 am_args.push_back("android.intent.extra.SCREENSHOT");
                 am_args.push_back(ds.screenshot_path_);
             }
+            if (!ds.notification_title.empty()) {
+                am_args.push_back("--es");
+                am_args.push_back("android.intent.extra.TITLE");
+                am_args.push_back(ds.notification_title);
+                if (!ds.notification_description.empty()) {
+                    am_args.push_back("--es");
+                    am_args.push_back("android.intent.extra.DESCRIPTION");
+                    am_args.push_back(ds.notification_description);
+                }
+            }
             if (is_remote_mode) {
                 am_args.push_back("--es");
                 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 7fcb980..f02303b 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -333,6 +333,10 @@
     android::sp<android::os::IDumpstateListener> listener_;
     std::string listener_name_;
 
+    // Notification title and description
+    std::string notification_title;
+    std::string notification_description;
+
   private:
     // Used by GetInstance() only.
     Dumpstate(const std::string& version = VERSION_CURRENT);
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 3ba177e..cc4144a 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -38,6 +38,7 @@
 #include <time.h>
 #include <unistd.h>
 
+#include <set>
 #include <string>
 #include <vector>
 
@@ -45,6 +46,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
 #include <cutils/properties.h>
 #include <cutils/sockets.h>
 #include <debuggerd/client.h>
@@ -87,6 +89,16 @@
         NULL,
 };
 
+/* list of hal interface to dump containing process during native dumps */
+static const char* hal_interfaces_to_dump[] {
+        "android.hardware.audio@2.0::IDevicesFactory",
+        "android.hardware.bluetooth@1.0::IBluetoothHci",
+        "android.hardware.camera.provider@2.4::ICameraProvider",
+        "android.hardware.vr@1.0::IVr",
+        "android.hardware.media.omx@1.0::IOmx",
+        NULL,
+};
+
 // Reasonable value for max stats.
 static const int STATS_MAX_N_RUNS = 1000;
 static const long STATS_MAX_AVERAGE = 100000;
@@ -792,6 +804,15 @@
     _redirect_to_file(redirect, path, O_APPEND);
 }
 
+static bool should_dump_hal_interface(const char* interface) {
+    for (const char** i = hal_interfaces_to_dump; *i; i++) {
+        if (!strcmp(*i, interface)) {
+            return true;
+        }
+    }
+    return false;
+}
+
 static bool should_dump_native_traces(const char* path) {
     for (const char** p = native_processes_to_dump; *p; p++) {
         if (!strcmp(*p, path)) {
@@ -801,6 +822,35 @@
     return false;
 }
 
+std::set<int> get_interesting_hal_pids() {
+    using android::hidl::manager::V1_0::IServiceManager;
+    using android::sp;
+    using android::hardware::Return;
+
+    sp<IServiceManager> manager = IServiceManager::getService();
+    std::set<int> pids;
+
+    Return<void> ret = manager->debugDump([&](auto& hals) {
+        for (const auto &info : hals) {
+            if (info.pid == static_cast<int>(IServiceManager::PidConstant::NO_PID)) {
+                continue;
+            }
+
+            if (!should_dump_hal_interface(info.interfaceName)) {
+                continue;
+            }
+
+            pids.insert(info.pid);
+        }
+    });
+
+    if (!ret.isOk()) {
+        MYLOGE("Could not get list of HAL PIDs: %s\n", ret.description().c_str());
+    }
+
+    return pids; // whether it was okay or not
+}
+
 /* dump Dalvik and native stack traces, return the trace file location (NULL if none) */
 const char *dump_traces() {
     DurationReporter duration_reporter("DUMP TRACES");
@@ -835,6 +885,7 @@
     /* Variables below must be initialized before 'goto' statements */
     int dalvik_found = 0;
     int ifd, wfd = -1;
+    std::set<int> hal_pids = get_interesting_hal_pids();
 
     /* walk /proc and kill -QUIT all Dalvik processes */
     DIR *proc = opendir("/proc");
@@ -909,7 +960,8 @@
                 dprintf(fd, "[dump dalvik stack %d: %.3fs elapsed]\n", pid,
                         (float)(Nanotime() - start) / NANOS_PER_SEC);
             }
-        } else if (should_dump_native_traces(data)) {
+        } else if (should_dump_native_traces(data) ||
+                   hal_pids.find(pid) != hal_pids.end()) {
             /* dump native process if appropriate */
             if (lseek(fd, 0, SEEK_END) < 0) {
                 MYLOGE("lseek: %s\n", strerror(errno));
diff --git a/cmds/installd/CacheItem.cpp b/cmds/installd/CacheItem.cpp
index 0349b0f..17eb7ff 100644
--- a/cmds/installd/CacheItem.cpp
+++ b/cmds/installd/CacheItem.cpp
@@ -38,12 +38,12 @@
 
     mParent = static_cast<CacheItem*>(p->fts_parent->fts_pointer);
     if (mParent) {
-        atomic = mParent->atomic;
+        group = mParent->group;
         tombstone = mParent->tombstone;
         mName = p->fts_name;
         mName.insert(0, "/");
     } else {
-        atomic = false;
+        group = false;
         tombstone = false;
         mName = p->fts_path;
     }
diff --git a/cmds/installd/CacheItem.h b/cmds/installd/CacheItem.h
index afbb15d..84b77aa 100644
--- a/cmds/installd/CacheItem.h
+++ b/cmds/installd/CacheItem.h
@@ -31,8 +31,8 @@
 
 /**
  * Single cache item that can be purged to free up space. This may be an
- * isolated file, or an entire directory tree that should be atomically
- * deleted.
+ * isolated file, or an entire directory tree that should be deleted as a
+ * group.
  */
 class CacheItem {
 public:
@@ -46,7 +46,7 @@
 
     short level;
     bool directory;
-    bool atomic;
+    bool group;
     bool tombstone;
     int64_t size;
     time_t modified;
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
index fada699..4bfc834 100644
--- a/cmds/installd/CacheTracker.cpp
+++ b/cmds/installd/CacheTracker.cpp
@@ -106,11 +106,11 @@
         switch (p->fts_info) {
         case FTS_D: {
             auto item = static_cast<CacheItem*>(p->fts_pointer);
-            item->atomic |= (getxattr(p->fts_path, kXattrCacheAtomic, nullptr, 0) >= 0);
+            item->group |= (getxattr(p->fts_path, kXattrCacheGroup, nullptr, 0) >= 0);
             item->tombstone |= (getxattr(p->fts_path, kXattrCacheTombstone, nullptr, 0) >= 0);
 
-            // When atomic, immediately collect all files under tree
-            if (item->atomic) {
+            // When group, immediately collect all files under tree
+            if (item->group) {
                 while ((p = fts_read(fts)) != nullptr) {
                     if (p->fts_info == FTS_DP && p->fts_level == item->level) break;
                     switch (p->fts_info) {
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 9006330..ca4be0a 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -768,15 +768,17 @@
     auto noop = (flags & FLAG_FREE_CACHE_NOOP);
 
     int64_t free = data_disk_free(data_path);
-    int64_t needed = freeStorageSize - free;
     if (free < 0) {
         return error("Failed to determine free space for " + data_path);
-    } else if (free >= freeStorageSize) {
-        return ok();
     }
 
-    LOG(DEBUG) << "Found " << data_path << " with " << free << " free; caller requested "
-            << freeStorageSize;
+    int64_t needed = freeStorageSize - free;
+    LOG(DEBUG) << "Device " << data_path << " has " << free << " free; requested "
+            << freeStorageSize << "; needed " << needed;
+
+    if (free >= freeStorageSize) {
+        return ok();
+    }
 
     if (flags & FLAG_FREE_CACHE_V2) {
         // This new cache strategy fairly removes files from UIDs by deleting
@@ -811,7 +813,9 @@
                             tracker->cacheQuota = mCacheQuotas[uid];
                         }
                         if (tracker->cacheQuota == 0) {
+#if MEASURE_DEBUG
                             LOG(WARNING) << "UID " << uid << " has no cache quota; assuming 64MB";
+#endif
                             tracker->cacheQuota = 67108864;
                         }
                         trackers[uid] = tracker;
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index 50a47d2..360f71a 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -101,6 +101,7 @@
     if (!statvfs("/data/local/tmp", &buf)) {
         return buf.f_bavail * buf.f_bsize;
     } else {
+        PLOG(ERROR) << "Failed to statvfs";
         return -1;
     }
 }
@@ -132,6 +133,8 @@
 };
 
 TEST_F(CacheTest, FreeCache_All) {
+    LOG(INFO) << "FreeCache_All";
+
     mkdir("com.example");
     touch("com.example/normal", 1 * kMbInBytes, 60);
     mkdir("com.example/cache");
@@ -152,6 +155,8 @@
 }
 
 TEST_F(CacheTest, FreeCache_Age) {
+    LOG(INFO) << "FreeCache_Age";
+
     mkdir("com.example");
     mkdir("com.example/cache");
     mkdir("com.example/cache/foo");
@@ -172,6 +177,8 @@
 }
 
 TEST_F(CacheTest, FreeCache_Tombstone) {
+    LOG(INFO) << "FreeCache_Tombstone";
+
     mkdir("com.example");
     mkdir("com.example/cache");
     mkdir("com.example/cache/foo");
@@ -201,14 +208,16 @@
     EXPECT_EQ(0, size("com.example/cache/bar/bar2"));
 }
 
-TEST_F(CacheTest, FreeCache_Atomic) {
+TEST_F(CacheTest, FreeCache_Group) {
+    LOG(INFO) << "FreeCache_Group";
+
     mkdir("com.example");
     mkdir("com.example/cache");
     mkdir("com.example/cache/foo");
     touch("com.example/cache/foo/foo1", 1 * kMbInBytes, 60);
     touch("com.example/cache/foo/foo2", 1 * kMbInBytes, 120);
 
-    setxattr("com.example/cache/foo", "user.cache_atomic");
+    setxattr("com.example/cache/foo", "user.cache_group");
 
     service->freeCache(testUuid, free() + kKbInBytes,
             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
@@ -217,25 +226,25 @@
     EXPECT_EQ(-1, exists("com.example/cache/foo/foo2"));
 }
 
-TEST_F(CacheTest, FreeCache_AtomicTombstone) {
-    LOG(INFO) << "FreeCache_AtomicTombstone";
+TEST_F(CacheTest, FreeCache_GroupTombstone) {
+    LOG(INFO) << "FreeCache_GroupTombstone";
 
     mkdir("com.example");
     mkdir("com.example/cache");
 
     // this dir must look really old for some reason?
-    mkdir("com.example/cache/atomic");
-    touch("com.example/cache/atomic/file1", kMbInBytes, 120);
-    touch("com.example/cache/atomic/file2", kMbInBytes, 120);
-    mkdir("com.example/cache/atomic/dir");
-    touch("com.example/cache/atomic/dir/file1", kMbInBytes, 120);
-    touch("com.example/cache/atomic/dir/file2", kMbInBytes, 120);
-    mkdir("com.example/cache/atomic/tomb");
-    touch("com.example/cache/atomic/tomb/file1", kMbInBytes, 120);
-    touch("com.example/cache/atomic/tomb/file2", kMbInBytes, 120);
-    mkdir("com.example/cache/atomic/tomb/dir");
-    touch("com.example/cache/atomic/tomb/dir/file1", kMbInBytes, 120);
-    touch("com.example/cache/atomic/tomb/dir/file2", kMbInBytes, 120);
+    mkdir("com.example/cache/group");
+    touch("com.example/cache/group/file1", kMbInBytes, 120);
+    touch("com.example/cache/group/file2", kMbInBytes, 120);
+    mkdir("com.example/cache/group/dir");
+    touch("com.example/cache/group/dir/file1", kMbInBytes, 120);
+    touch("com.example/cache/group/dir/file2", kMbInBytes, 120);
+    mkdir("com.example/cache/group/tomb");
+    touch("com.example/cache/group/tomb/file1", kMbInBytes, 120);
+    touch("com.example/cache/group/tomb/file2", kMbInBytes, 120);
+    mkdir("com.example/cache/group/tomb/dir");
+    touch("com.example/cache/group/tomb/dir/file1", kMbInBytes, 120);
+    touch("com.example/cache/group/tomb/dir/file2", kMbInBytes, 120);
 
     mkdir("com.example/cache/tomb");
     touch("com.example/cache/tomb/file1", kMbInBytes, 240);
@@ -243,80 +252,80 @@
     mkdir("com.example/cache/tomb/dir");
     touch("com.example/cache/tomb/dir/file1", kMbInBytes, 240);
     touch("com.example/cache/tomb/dir/file2", kMbInBytes, 240);
-    mkdir("com.example/cache/tomb/atomic");
-    touch("com.example/cache/tomb/atomic/file1", kMbInBytes, 60);
-    touch("com.example/cache/tomb/atomic/file2", kMbInBytes, 60);
-    mkdir("com.example/cache/tomb/atomic/dir");
-    touch("com.example/cache/tomb/atomic/dir/file1", kMbInBytes, 60);
-    touch("com.example/cache/tomb/atomic/dir/file2", kMbInBytes, 60);
+    mkdir("com.example/cache/tomb/group");
+    touch("com.example/cache/tomb/group/file1", kMbInBytes, 60);
+    touch("com.example/cache/tomb/group/file2", kMbInBytes, 60);
+    mkdir("com.example/cache/tomb/group/dir");
+    touch("com.example/cache/tomb/group/dir/file1", kMbInBytes, 60);
+    touch("com.example/cache/tomb/group/dir/file2", kMbInBytes, 60);
 
-    setxattr("com.example/cache/atomic", "user.cache_atomic");
-    setxattr("com.example/cache/atomic/tomb", "user.cache_tombstone");
+    setxattr("com.example/cache/group", "user.cache_group");
+    setxattr("com.example/cache/group/tomb", "user.cache_tombstone");
     setxattr("com.example/cache/tomb", "user.cache_tombstone");
-    setxattr("com.example/cache/tomb/atomic", "user.cache_atomic");
+    setxattr("com.example/cache/tomb/group", "user.cache_group");
 
     service->freeCache(testUuid, free() + kKbInBytes,
             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
 
-    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/file1"));
-    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/file2"));
-    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/dir/file1"));
-    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/dir/file2"));
-    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/file1"));
-    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/file2"));
-    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/dir/file1"));
-    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/dir/file2"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/file2"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/dir/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/dir/file2"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/file2"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/dir/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/dir/file2"));
 
     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file1"));
     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file2"));
     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file1"));
     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file2"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file1"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file2"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file1"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
 
     service->freeCache(testUuid, free() + kKbInBytes,
             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
 
-    EXPECT_EQ(-1, size("com.example/cache/atomic/file1"));
-    EXPECT_EQ(-1, size("com.example/cache/atomic/file2"));
-    EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file1"));
-    EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file2"));
-    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file1"));
-    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file2"));
-    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file1"));
-    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file2"));
+    EXPECT_EQ(-1, size("com.example/cache/group/file1"));
+    EXPECT_EQ(-1, size("com.example/cache/group/file2"));
+    EXPECT_EQ(-1, size("com.example/cache/group/dir/file1"));
+    EXPECT_EQ(-1, size("com.example/cache/group/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/file1"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/file2"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file2"));
 
     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file1"));
     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file2"));
     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file1"));
     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file2"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file1"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file2"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file1"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
 
     service->freeCache(testUuid, kTbInBytes,
             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
 
-    EXPECT_EQ(-1, size("com.example/cache/atomic/file1"));
-    EXPECT_EQ(-1, size("com.example/cache/atomic/file2"));
-    EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file1"));
-    EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file2"));
-    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file1"));
-    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file2"));
-    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file1"));
-    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file2"));
+    EXPECT_EQ(-1, size("com.example/cache/group/file1"));
+    EXPECT_EQ(-1, size("com.example/cache/group/file2"));
+    EXPECT_EQ(-1, size("com.example/cache/group/dir/file1"));
+    EXPECT_EQ(-1, size("com.example/cache/group/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/file1"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/file2"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file2"));
 
     EXPECT_EQ(0, size("com.example/cache/tomb/file1"));
     EXPECT_EQ(0, size("com.example/cache/tomb/file2"));
     EXPECT_EQ(0, size("com.example/cache/tomb/dir/file1"));
     EXPECT_EQ(0, size("com.example/cache/tomb/dir/file2"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file1"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file2"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file1"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
 }
 
 }  // namespace installd
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 97298e5..03ee23f 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -23,12 +23,7 @@
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <sys/xattr.h>
-
-#if defined(__APPLE__)
-#include <sys/mount.h>
-#else
-#include <sys/statfs.h>
-#endif
+#include <sys/statvfs.h>
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
@@ -637,11 +632,11 @@
 
 int64_t data_disk_free(const std::string& data_path)
 {
-    struct statfs sfs;
-    if (statfs(data_path.c_str(), &sfs) == 0) {
+    struct statvfs sfs;
+    if (statvfs(data_path.c_str(), &sfs) == 0) {
         return sfs.f_bavail * sfs.f_bsize;
     } else {
-        PLOG(ERROR) << "Couldn't statfs " << data_path;
+        PLOG(ERROR) << "Couldn't statvfs " << data_path;
         return -1;
     }
 }
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index abe6830..a4eb1f6 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -66,7 +66,7 @@
 
 constexpr const char* kXattrInodeCache = "user.inode_cache";
 constexpr const char* kXattrInodeCodeCache = "user.inode_code_cache";
-constexpr const char* kXattrCacheAtomic = "user.cache_atomic";
+constexpr const char* kXattrCacheGroup = "user.cache_group";
 constexpr const char* kXattrCacheTombstone = "user.cache_tombstone";
 
 int create_pkg_path(char path[PKG_PATH_MAX],
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index 51a8682..a5cac15 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -257,8 +257,9 @@
                 continue;
             }
             // Strip out system libs.
-            // TODO(b/34772739): might want to add other framework HAL packages
-            if (fqName.inPackage("android.hidl")) {
+            if (fqName.inPackage("android.hidl") ||
+                fqName.inPackage("android.frameworks") ||
+                fqName.inPackage("android.system")) {
                 continue;
             }
             std::string interfaceName =
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index dc8e675..5431233 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -34,3 +34,15 @@
     shared_libs: ["libcutils", "libselinux"],
     init_rc: ["servicemanager.rc"],
 }
+
+cc_binary {
+    name: "vndservicemanager",
+    defaults: ["servicemanager_flags"],
+    proprietary: true,
+    srcs: [
+        "service_manager.c",
+        "binder.c",
+    ],
+    shared_libs: ["libcutils", "libselinux"],
+    init_rc: ["vndservicemanager.rc"],
+}
diff --git a/cmds/servicemanager/bctest.c b/cmds/servicemanager/bctest.c
index 6466654..354df67 100644
--- a/cmds/servicemanager/bctest.c
+++ b/cmds/servicemanager/bctest.c
@@ -62,7 +62,7 @@
     uint32_t svcmgr = BINDER_SERVICE_MANAGER;
     uint32_t handle;
 
-    bs = binder_open(128*1024);
+    bs = binder_open("/dev/binder", 128*1024);
     if (!bs) {
         fprintf(stderr, "failed to open binder driver\n");
         return -1;
diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c
index 753aeb5..93a18fc 100644
--- a/cmds/servicemanager/binder.c
+++ b/cmds/servicemanager/binder.c
@@ -94,7 +94,7 @@
     size_t mapsize;
 };
 
-struct binder_state *binder_open(size_t mapsize)
+struct binder_state *binder_open(const char* driver, size_t mapsize)
 {
     struct binder_state *bs;
     struct binder_version vers;
@@ -105,10 +105,10 @@
         return NULL;
     }
 
-    bs->fd = open("/dev/binder", O_RDWR | O_CLOEXEC);
+    bs->fd = open(driver, O_RDWR | O_CLOEXEC);
     if (bs->fd < 0) {
-        fprintf(stderr,"binder: cannot open device (%s)\n",
-                strerror(errno));
+        fprintf(stderr,"binder: cannot open %s (%s)\n",
+                driver, strerror(errno));
         goto fail_open;
     }
 
diff --git a/cmds/servicemanager/binder.h b/cmds/servicemanager/binder.h
index 881ab07..c95b33f 100644
--- a/cmds/servicemanager/binder.h
+++ b/cmds/servicemanager/binder.h
@@ -46,7 +46,7 @@
                               struct binder_io *msg,
                               struct binder_io *reply);
 
-struct binder_state *binder_open(size_t mapsize);
+struct binder_state *binder_open(const char* driver, size_t mapsize);
 void binder_close(struct binder_state *bs);
 
 /* initiate a blocking binder call
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 43c4c8b..5d44e87 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -360,14 +360,21 @@
     return 0;
 }
 
-int main()
+int main(int argc, char** argv)
 {
     struct binder_state *bs;
     union selinux_callback cb;
+    char *driver;
 
-    bs = binder_open(128*1024);
+    if (argc > 1) {
+        driver = argv[1];
+    } else {
+        driver = "/dev/binder";
+    }
+
+    bs = binder_open(driver, 128*1024);
     if (!bs) {
-        ALOGE("failed to open binder driver\n");
+        ALOGE("failed to open binder driver %s\n", driver);
         return -1;
     }
 
diff --git a/cmds/servicemanager/vndservicemanager.rc b/cmds/servicemanager/vndservicemanager.rc
new file mode 100644
index 0000000..d5ddaaf
--- /dev/null
+++ b/cmds/servicemanager/vndservicemanager.rc
@@ -0,0 +1,6 @@
+service vndservicemanager /vendor/bin/vndservicemanager /dev/vndbinder
+    class core
+    user system
+    group system readproc
+    writepid /dev/cpuset/system-background/tasks
+
diff --git a/include/batteryservice/IBatteryPropertiesRegistrar.h b/include/batteryservice/IBatteryPropertiesRegistrar.h
index b5c3a4d..a7dbea6 100644
--- a/include/batteryservice/IBatteryPropertiesRegistrar.h
+++ b/include/batteryservice/IBatteryPropertiesRegistrar.h
@@ -27,6 +27,7 @@
     REGISTER_LISTENER = IBinder::FIRST_CALL_TRANSACTION,
     UNREGISTER_LISTENER,
     GET_PROPERTY,
+    SCHEDULE_UPDATE,
 };
 
 class IBatteryPropertiesRegistrar : public IInterface {
@@ -36,6 +37,7 @@
     virtual void registerListener(const sp<IBatteryPropertiesListener>& listener) = 0;
     virtual void unregisterListener(const sp<IBatteryPropertiesListener>& listener) = 0;
     virtual status_t getProperty(int id, struct BatteryProperty *val) = 0;
+    virtual void scheduleUpdate() = 0;
 };
 
 class BnBatteryPropertiesRegistrar : public BnInterface<IBatteryPropertiesRegistrar> {
diff --git a/include/binder/ProcessState.h b/include/binder/ProcessState.h
index 64cf72e..05e9d09 100644
--- a/include/binder/ProcessState.h
+++ b/include/binder/ProcessState.h
@@ -35,6 +35,11 @@
 {
 public:
     static  sp<ProcessState>    self();
+    /* initWithDriver() can be used to configure libbinder to use
+     * a different binder driver dev node. It must be called *before*
+     * any call to ProcessState::self(). /dev/binder remains the default.
+     */
+    static  sp<ProcessState>    initWithDriver(const char *driver);
 
             void                setContextObject(const sp<IBinder>& object);
             sp<IBinder>         getContextObject(const sp<IBinder>& caller);
@@ -67,7 +72,7 @@
 private:
     friend class IPCThreadState;
     
-                                ProcessState();
+                                ProcessState(const char* driver);
                                 ~ProcessState();
 
                                 ProcessState(const ProcessState& o);
diff --git a/include/media/openmax/OMX_AsString.h b/include/media/openmax/OMX_AsString.h
index 4556c8f..6b21979 100644
--- a/include/media/openmax/OMX_AsString.h
+++ b/include/media/openmax/OMX_AsString.h
@@ -531,6 +531,7 @@
 //      case OMX_IndexConfigCallbackRequest:            return "ConfigCallbackRequest";
 //      case OMX_IndexConfigCommitMode:                 return "ConfigCommitMode";
 //      case OMX_IndexConfigCommit:                     return "ConfigCommit";
+        case OMX_IndexConfigAndroidVendorExtension:     return "ConfigAndroidVendorExtension";
         case OMX_IndexParamAudioAndroidAc3:             return "ParamAudioAndroidAc3";
         case OMX_IndexParamAudioAndroidOpus:            return "ParamAudioAndroidOpus";
         case OMX_IndexParamAudioAndroidAacPresentation: return "ParamAudioAndroidAacPresentation";
diff --git a/include/media/openmax/OMX_IndexExt.h b/include/media/openmax/OMX_IndexExt.h
index d0ae867..eccecaa 100644
--- a/include/media/openmax/OMX_IndexExt.h
+++ b/include/media/openmax/OMX_IndexExt.h
@@ -51,6 +51,7 @@
     OMX_IndexConfigCallbackRequest,                 /**< reference: OMX_CONFIG_CALLBACKREQUESTTYPE */
     OMX_IndexConfigCommitMode,                      /**< reference: OMX_CONFIG_COMMITMODETYPE */
     OMX_IndexConfigCommit,                          /**< reference: OMX_CONFIG_COMMITTYPE */
+    OMX_IndexConfigAndroidVendorExtension,          /**< reference: OMX_CONFIG_VENDOR_EXTENSIONTYPE */
 
     /* Port parameters and configurations */
     OMX_IndexExtPortStartUnused = OMX_IndexKhronosExtensions + 0x00200000,
@@ -103,6 +104,117 @@
     OMX_IndexExtMax = 0x7FFFFFFF
 } OMX_INDEXEXTTYPE;
 
+#define OMX_MAX_STRINGVALUE_SIZE OMX_MAX_STRINGNAME_SIZE
+#define OMX_MAX_ANDROID_VENDOR_PARAMCOUNT 32
+
+typedef enum OMX_ANDROID_VENDOR_VALUETYPE {
+    OMX_AndroidVendorValueInt32 = 0,   /*<< int32_t value */
+    OMX_AndroidVendorValueInt64,       /*<< int64_t value */
+    OMX_AndroidVendorValueString,      /*<< string value */
+    OMX_AndroidVendorValueEndUnused,
+} OMX_ANDROID_VENDOR_VALUETYPE;
+
+/**
+ * Structure describing a single value of an Android vendor extension.
+ *
+ * STRUCTURE MEMBERS:
+ *  cKey        : parameter value name.
+ *  eValueType  : parameter value type
+ *  bSet        : if false, the parameter is not set (for OMX_GetConfig) or is unset (OMX_SetConfig)
+ *                if true, the parameter is set to the corresponding value below
+ *  nInt64      : int64 value
+ *  cString     : string value
+ */
+typedef struct OMX_CONFIG_ANDROID_VENDOR_PARAMTYPE {
+    OMX_U8 cKey[OMX_MAX_STRINGNAME_SIZE];
+    OMX_ANDROID_VENDOR_VALUETYPE eValueType;
+    OMX_BOOL bSet;
+    union {
+        OMX_S32 nInt32;
+        OMX_S64 nInt64;
+        OMX_U8 cString[OMX_MAX_STRINGVALUE_SIZE];
+    };
+} OMX_CONFIG_ANDROID_VENDOR_PARAMTYPE;
+
+/**
+ * OMX_CONFIG_ANDROID_VENDOR_EXTENSIONTYPE is the structure for an Android vendor extension
+ * supported by the component. This structure enumerates the various extension parameters and their
+ * values.
+ *
+ * Android vendor extensions have a name and one or more parameter values - each with a string key -
+ * that are set together. The values are exposed to Android applications via a string key that is
+ * the concatenation of 'vendor', the extension name and the parameter key, each separated by dot
+ * (.), with any trailing '.value' suffix(es) removed (though optionally allowed).
+ *
+ * Extension names and parameter keys are subject to the following rules:
+ *   - Each SHALL contain a set of lowercase alphanumeric (underscore allowed) tags separated by
+ *     dot (.) or dash (-).
+ *   - The first character of the first tag, and any tag following a dot SHALL not start with a
+ *     digit.
+ *   - Tags 'value', 'vendor', 'omx' and 'android' (even if trailed and/or followed by any number
+ *     of underscores) are prohibited in the extension name.
+ *   - Tags 'vendor', 'omx' and 'android' (even if trailed and/or followed by any number
+ *     of underscores) are prohibited in parameter keys.
+ *   - The tag 'value' (even if trailed and/or followed by any number
+ *     of underscores) is prohibited in parameter keys with the following exception:
+ *     the parameter key may be exactly 'value'
+ *   - The parameter key for extensions with a single parameter value SHALL be 'value'
+ *   - No two extensions SHALL have the same name
+ *   - No extension's name SHALL start with another extension's NAME followed by a dot (.)
+ *   - No two parameters of an extension SHALL have the same key
+ *
+ * This config can be used with both OMX_GetConfig and OMX_SetConfig. In the OMX_GetConfig
+ * case, the caller specifies nIndex and nParamSizeUsed. The component fills in cName,
+ * eDir and nParamCount. Additionally, if nParamSizeUsed is not less than nParamCount, the
+ * component fills out the parameter values (nParam) with the current values for each parameter
+ * of the vendor extension.
+ *
+ * The value of nIndex goes from 0 to N-1, where N is the number of Android vendor extensions
+ * supported by the component. The component does not need to report N as the caller can determine
+ * N by enumerating all extensions supported by the component. The component may not support any
+ * extensions. If there are no more extensions, OMX_GetParameter returns OMX_ErrorNoMore. The
+ * component supplies extensions in the order it wants clients to set them.
+ *
+ * The component SHALL return OMX_ErrorNone for all cases where nIndex is less than N (specifically
+ * even in the case of where nParamCount is greater than nParamSizeUsed).
+ *
+ * In the OMX_SetConfig case the field nIndex is ignored. If the component supports an Android
+ * vendor extension with the name in cName, it SHALL configure the parameter values for that
+ * extension according to the parameters in nParam. nParamCount is the number of valid parameters
+ * in the nParam array, and nParamSizeUsed is the size of the nParam array. (nParamSizeUsed
+ * SHALL be at least nParamCount) Parameters that are part of a vendor extension but are not
+ * in the nParam array are assumed to be unset (this is different from not changed).
+ * All parameter values SHALL have distinct keys in nParam (the component can assume that this
+ * is the case. Otherwise, the actual value for the parameters that are multiply defined can
+ * be any of the set values.)
+ *
+ * Return values in case of OMX_SetConfig:
+ *   OMX_ErrorUnsupportedIndex: the component does not support the extension specified by cName
+ *   OMX_ErrorUnsupportedSetting: the component does not support some or any of the parameters
+ *       (names) specified in nParam
+ *   OMX_ErrorBadParameter: the parameter is invalid (e.g. nParamCount is greater than
+ *       nParamSizeUsed, or some parameter value has invalid type)
+ *
+ * STRUCTURE MEMBERS:
+ *  nSize       : size of the structure in bytes
+ *  nVersion    : OMX specification version information
+ *  cName       : name of vendor extension
+ *  nParamCount : the number of parameter values that are part of this vendor extension
+ *  nParamSizeUsed : the size of nParam
+ *                (must be at least 1 and at most OMX_MAX_ANDROID_VENDOR_PARAMCOUNT)
+ *  param       : the parameter values
+ */
+typedef struct OMX_CONFIG_ANDROID_VENDOR_EXTENSIONTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nIndex;
+    OMX_U8  cName[OMX_MAX_STRINGNAME_SIZE];
+    OMX_DIRTYPE eDir;
+    OMX_U32 nParamCount;
+    OMX_U32 nParamSizeUsed;
+    OMX_CONFIG_ANDROID_VENDOR_PARAMTYPE param[1];
+} OMX_CONFIG_ANDROID_VENDOR_EXTENSIONTYPE;
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 98107c5..5c4cfe2 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -71,7 +71,17 @@
     if (gProcess != NULL) {
         return gProcess;
     }
-    gProcess = new ProcessState;
+    gProcess = new ProcessState("/dev/binder");
+    return gProcess;
+}
+
+sp<ProcessState> ProcessState::initWithDriver(const char* driver)
+{
+    Mutex::Autolock _l(gProcessMutex);
+    if (gProcess != NULL) {
+        LOG_ALWAYS_FATAL("ProcessState was already initialized.");
+    }
+    gProcess = new ProcessState(driver);
     return gProcess;
 }
 
@@ -307,9 +317,9 @@
     androidSetThreadName( makeBinderThreadName().string() );
 }
 
-static int open_driver()
+static int open_driver(const char *driver)
 {
-    int fd = open("/dev/binder", O_RDWR | O_CLOEXEC);
+    int fd = open(driver, O_RDWR | O_CLOEXEC);
     if (fd >= 0) {
         int vers = 0;
         status_t result = ioctl(fd, BINDER_VERSION, &vers);
@@ -330,13 +340,13 @@
             ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
         }
     } else {
-        ALOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
+        ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
     }
     return fd;
 }
 
-ProcessState::ProcessState()
-    : mDriverFD(open_driver())
+ProcessState::ProcessState(const char *driver)
+    : mDriverFD(open_driver(driver))
     , mVMStart(MAP_FAILED)
     , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
     , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 5f5fb91..5fc6abe 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -112,9 +112,11 @@
         "libnativewindow",
         "liblog",
         "libhidlbase",
+        "libhidltransport",
         "android.hidl.base@1.0",
         "android.hidl.token@1.0-utils",
         "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.configstore@1.0",
     ],
 
     export_shared_lib_headers: [
@@ -123,6 +125,8 @@
         "android.hidl.token@1.0-utils",
         "android.hardware.graphics.bufferqueue@1.0",
     ],
+
+    header_libs: ["android.hardware.configstore-utils"],
 }
 
 subdirs = ["tests"]
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 9e3fecb..d653db8 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -261,6 +261,13 @@
 
     for (auto& b : mQueue) {
         b.mIsStale = true;
+
+        // We set this to false to force the BufferQueue to resend the buffer
+        // handle upon acquire, since if we're here due to a producer
+        // disconnect, the consumer will have been told to purge its cache of
+        // slot-to-buffer-handle mappings and will not be able to otherwise
+        // obtain a valid buffer handle.
+        b.mAcquireCalled = false;
     }
 
     VALIDATE_CONSISTENCY();
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 429e837..06fc31d 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -37,6 +37,9 @@
 #include <gui/ISurfaceComposer.h>
 #include <private/gui/ComposerService.h>
 
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
+
 namespace android {
 
 Surface::Surface(
@@ -289,6 +292,9 @@
     return NO_ERROR;
 }
 
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+
 status_t Surface::getWideColorSupport(bool* supported) {
     ATRACE_CALL();
 
@@ -301,13 +307,19 @@
     if (err)
         return err;
 
+    bool wideColorBoardConfig =
+        getBool<ISurfaceFlingerConfigs,
+                &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
+
     *supported = false;
     for (android_color_mode_t colorMode : colorModes) {
         switch (colorMode) {
             case HAL_COLOR_MODE_DISPLAY_P3:
             case HAL_COLOR_MODE_ADOBE_RGB:
             case HAL_COLOR_MODE_DCI_P3:
-                *supported = true;
+                if (wideColorBoardConfig) {
+                    *supported = true;
+                }
                 break;
             default:
                 break;
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 91ce531..907e0493 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -1117,4 +1117,64 @@
     ASSERT_EQ(true, output.bufferReplaced);
 }
 
+TEST_F(BufferQueueTest, TestStaleBufferHandleSentAfterDisconnect) {
+    createBufferQueue();
+    sp<DummyConsumer> dc(new DummyConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+    IGraphicBufferProducer::QueueBufferOutput output;
+    sp<IProducerListener> dummyListener(new DummyProducerListener);
+    ASSERT_EQ(OK, mProducer->connect(dummyListener, NATIVE_WINDOW_API_CPU,
+            true, &output));
+
+    int slot = BufferQueue::INVALID_BUFFER_SLOT;
+    sp<Fence> fence = Fence::NO_FENCE;
+    sp<GraphicBuffer> buffer = nullptr;
+    IGraphicBufferProducer::QueueBufferInput input(0ull, true,
+            HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT,
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+
+    // Dequeue, request, and queue one buffer
+    status_t result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0,
+            nullptr);
+    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
+    ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
+    ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+
+    // Acquire and release the buffer. Upon acquiring, the buffer handle should
+    // be non-null since this is the first time we've acquired this slot.
+    BufferItem item;
+    ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+    ASSERT_EQ(slot, item.mSlot);
+    ASSERT_NE(nullptr, item.mGraphicBuffer.get());
+    ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
+            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
+
+    // Dequeue and queue the buffer again
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+
+    // Acquire and release the buffer again. Upon acquiring, the buffer handle
+    // should be null since this is not the first time we've acquired this slot.
+    ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+    ASSERT_EQ(slot, item.mSlot);
+    ASSERT_EQ(nullptr, item.mGraphicBuffer.get());
+    ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
+            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
+
+    // Dequeue and queue the buffer again
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+
+    // Disconnect the producer end. This should clear all of the slots and mark
+    // the buffer in the queue as stale.
+    ASSERT_EQ(OK, mProducer->disconnect(NATIVE_WINDOW_API_CPU));
+
+    // Acquire the buffer again. Upon acquiring, the buffer handle should not be
+    // null since the queued buffer should have been marked as stale, which
+    // should trigger the BufferQueue to resend the buffer handle.
+    ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+    ASSERT_EQ(slot, item.mSlot);
+    ASSERT_NE(nullptr, item.mGraphicBuffer.get());
+}
+
 } // namespace android
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
index 50d95f7..9952e59 100644
--- a/libs/vr/libdisplay/display_client.cpp
+++ b/libs/vr/libdisplay/display_client.cpp
@@ -265,6 +265,12 @@
   return BufferConsumer::Import(std::move(status));
 }
 
+bool DisplayClient::IsVrAppRunning() {
+  auto status = InvokeRemoteMethod<DisplayRPC::IsVrAppRunning>();
+  if (!status)
+    return 0;
+  return static_cast<bool>(status.get());
+}
 
 }  // namespace dvr
 }  // namespace android
diff --git a/libs/vr/libdisplay/graphics.cpp b/libs/vr/libdisplay/graphics.cpp
index c2fbb8b..3713389 100644
--- a/libs/vr/libdisplay/graphics.cpp
+++ b/libs/vr/libdisplay/graphics.cpp
@@ -27,6 +27,7 @@
 #include <private/dvr/sensor_constants.h>
 #include <private/dvr/video_mesh_surface_client.h>
 #include <private/dvr/vsync_client.h>
+#include <private/dvr/platform_defines.h>
 
 #include <android/native_window.h>
 
@@ -43,8 +44,10 @@
 
 namespace {
 
+// TODO(urbanus): revisit once we have per-platform usage config in place.
 constexpr int kDefaultDisplaySurfaceUsage =
-    GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+    GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE |
+    GRALLOC_USAGE_QCOM_FRAMEBUFFER_COMPRESSION;
 constexpr int kDefaultDisplaySurfaceFormat = HAL_PIXEL_FORMAT_RGBA_8888;
 // TODO(alexst): revisit this count when HW encode is available for casting.
 constexpr int kDefaultBufferCount = 4;
diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h
index f579a8c..378f67c 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_client.h
@@ -110,6 +110,9 @@
 
   std::unique_ptr<BufferConsumer> GetPoseBuffer();
 
+  // Temporary query for current VR status. Will be removed later.
+  bool IsVrAppRunning();
+
  private:
   friend BASE;
 
diff --git a/libs/vr/libdisplay/include/private/dvr/display_rpc.h b/libs/vr/libdisplay/include/private/dvr/display_rpc.h
index 7a2986a..ac08650 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_rpc.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_rpc.h
@@ -219,6 +219,7 @@
     kOpVideoMeshSurfaceCreateProducerQueue,
     kOpSetViewerParams,
     kOpGetPoseBuffer,
+    kOpIsVrAppRunning,
   };
 
   // Aliases.
@@ -248,6 +249,7 @@
                     void(const ViewerParams& viewer_params));
   PDX_REMOTE_METHOD(GetPoseBuffer, kOpGetPoseBuffer,
                     LocalChannelHandle(Void));
+  PDX_REMOTE_METHOD(IsVrAppRunning, kOpIsVrAppRunning, int(Void));
 };
 
 struct DisplayManagerRPC {
diff --git a/libs/vr/libdvrcommon/include/private/dvr/platform_defines.h b/libs/vr/libdvrcommon/include/private/dvr/platform_defines.h
index 71d4c8c..2176903 100644
--- a/libs/vr/libdvrcommon/include/private/dvr/platform_defines.h
+++ b/libs/vr/libdvrcommon/include/private/dvr/platform_defines.h
@@ -1,10 +1,11 @@
 #ifndef ANDROID_DVR_PLATFORM_DEFINES_H_
 #define ANDROID_DVR_PLATFORM_DEFINES_H_
 
+#include <hardware/gralloc1.h>
 // Platform-specific macros and defines.
 
-// QCOM's GRALLOC_USAGE_PRIVATE_ALLOC_UBWC usage bit.
-#define GRALLOC_USAGE_QCOM_FRAMEBUFFER_COMPRESSION GRALLOC_USAGE_PRIVATE_1
+// QCOM's GRALLOC_USAGE_PRIVATE_ALLOC_UBWC usage bits.
+#define GRALLOC_USAGE_QCOM_FRAMEBUFFER_COMPRESSION GRALLOC_USAGE_PRIVATE_1 | GRALLOC1_PRODUCER_USAGE_PRIVATE_0
 
 // QCOM bit to use the ADSP heap. This carveout heap is accessible to Linux,
 // Hexagon DSPs, and the GPU.
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index da7281b..c079187 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -94,6 +94,11 @@
           *this, &DisplayService::OnGetPoseBuffer, message);
       return 0;
 
+    case DisplayRPC::IsVrAppRunning::Opcode:
+      DispatchRemoteMethod<DisplayRPC::IsVrAppRunning>(
+          *this, &DisplayService::IsVrAppRunning, message);
+      return 0;
+
     // Direct the surface specific messages to the surface instance.
     case DisplayRPC::CreateBufferQueue::Opcode:
     case DisplayRPC::SetAttributes::Opcode:
@@ -355,5 +360,15 @@
     update_notifier_();
 }
 
+int DisplayService::IsVrAppRunning(pdx::Message& message) {
+  bool visible = true;
+  ForEachDisplaySurface([&visible](const std::shared_ptr<DisplaySurface>& surface) {
+    if (surface->client_z_order() == 0 && !surface->IsVisible())
+      visible = false;
+  });
+
+  REPLY_SUCCESS_RETURN(message, visible, 0);
+}
+
 }  // namespace dvr
 }  // namespace android
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index 2a71b4a..8e96172 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -87,6 +87,9 @@
                          const ViewerParams& view_params);
   pdx::LocalChannelHandle OnGetPoseBuffer(pdx::Message& message);
 
+  // Temporary query for current VR status. Will be removed later.
+  int IsVrAppRunning(pdx::Message& message);
+
   // Called by DisplaySurface to signal that a surface property has changed and
   // the display manager should be notified.
   void NotifyDisplayConfigurationUpdate();
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index 66808ca..66e9925 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -40,7 +40,8 @@
       manager_visible_(false),
       manager_z_order_(0),
       manager_blur_(0.0f),
-      layer_order_(0) {}
+      layer_order_(0),
+      allocated_buffer_index_(0) {}
 
 DisplaySurface::~DisplaySurface() {
   ALOGD_IF(LOCAL_TRACE,
@@ -104,6 +105,14 @@
       return;
     }
 
+    // Save buffer index, associated with the buffer id so that it can be looked
+    // up later.
+    int buffer_id = buffer_consumer->id();
+    if (buffer_id_to_index_.find(buffer_id) == buffer_id_to_index_.end()) {
+      buffer_id_to_index_[buffer_id] = allocated_buffer_index_;
+      ++allocated_buffer_index_;
+    }
+
     if (!IsVisible()) {
       ATRACE_NAME("DropFrameOnInvisibleSurface");
       ALOGD_IF(TRACE,
@@ -171,6 +180,17 @@
   return buffer;
 }
 
+uint32_t DisplaySurface::GetRenderBufferIndex(int buffer_id) {
+  std::lock_guard<std::mutex> autolock(lock_);
+
+  if (buffer_id_to_index_.find(buffer_id) == buffer_id_to_index_.end()) {
+    ALOGW("DisplaySurface::GetRenderBufferIndex: unknown buffer_id %d.",
+          buffer_id);
+    return 0;
+  }
+  return buffer_id_to_index_[buffer_id];
+}
+
 bool DisplaySurface::IsBufferAvailable() {
   std::lock_guard<std::mutex> autolock(lock_);
   DequeueBuffersLocked();
diff --git a/libs/vr/libvrflinger/display_surface.h b/libs/vr/libvrflinger/display_surface.h
index feb173e..d31a3a9 100644
--- a/libs/vr/libvrflinger/display_surface.h
+++ b/libs/vr/libvrflinger/display_surface.h
@@ -60,10 +60,7 @@
     }
   }
 
-  uint32_t GetRenderBufferIndex(int buffer_id) {
-    return buffer_id_to_index_[buffer_id];
-  }
-
+  uint32_t GetRenderBufferIndex(int buffer_id);
   bool IsBufferAvailable();
   bool IsBufferPosted();
   AcquiredBuffer AcquireCurrentBuffer();
@@ -172,6 +169,8 @@
   float manager_blur_;
   int layer_order_;
 
+  // The monotonically increasing index for allocated buffers in this surface.
+  uint32_t allocated_buffer_index_;
   // Maps from the buffer id to the corresponding allocated buffer index.
   std::unordered_map<int, uint32_t> buffer_id_to_index_;
 };
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index da45859..542bbd9 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -518,10 +518,13 @@
     post_thread_cond_var_.notify_all();
 }
 
-int HardwareComposer::PostThreadPollInterruptible(int event_fd) {
+int HardwareComposer::PostThreadPollInterruptible(int event_fd,
+                                                  int requested_events) {
   pollfd pfd[2] = {
       {
-          .fd = event_fd, .events = POLLPRI | POLLIN, .revents = 0,
+          .fd = event_fd,
+          .events = static_cast<short>(requested_events),
+          .revents = 0,
       },
       {
           .fd = post_thread_interrupt_event_fd_.Get(),
@@ -645,7 +648,9 @@
 // TODO(eieio): This is pretty driver specific, this should be moved to a
 // separate class eventually.
 int HardwareComposer::BlockUntilVSync() {
-  return PostThreadPollInterruptible(primary_display_vsync_event_fd_.Get());
+  return PostThreadPollInterruptible(primary_display_vsync_event_fd_.Get(),
+                                     // There will be a POLLPRI event on vsync
+                                     POLLPRI);
 }
 
 // Waits for the next vsync and returns the timestamp of the vsync event. If
@@ -718,7 +723,7 @@
     return -error;
   }
 
-  return PostThreadPollInterruptible(timer_fd);
+  return PostThreadPollInterruptible(timer_fd, POLLIN);
 }
 
 void HardwareComposer::PostThread() {
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 2d3d78b..e570cb6 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -281,7 +281,7 @@
   // Blocks until either event_fd becomes readable, or we're interrupted by a
   // control thread. Any errors are returned as negative errno values. If we're
   // interrupted, kPostThreadInterrupted will be returned.
-  int PostThreadPollInterruptible(int event_fd);
+  int PostThreadPollInterruptible(int event_fd, int requested_events);
 
   // BlockUntilVSync, WaitForVSync, and SleepUntil are all blocking calls made
   // on the post thread that can be interrupted by a control thread. If
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 7715c46..bf831a7 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -605,20 +605,6 @@
 #endif
 #endif
 
-#ifndef EGL_ANDROID_create_native_client_buffer
-#define EGL_ANDROID_create_native_client_buffer 1
-#define EGL_LAYER_COUNT_ANDROID 0x3434
-#define EGL_NATIVE_BUFFER_USAGE_ANDROID   0x3143
-#define EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID   0x00000001
-#define EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID   0x00000002
-#define EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID   0x00000004
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLClientBuffer eglCreateNativeClientBufferANDROID (const EGLint *attrib_list);
-#else
-typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLCREATENATIVECLIENTBUFFERANDROID) (const EGLint *attrib_list);
-#endif
-#endif
-
 #ifndef EGL_ANDROID_get_native_client_buffer
 #define EGL_ANDROID_get_native_client_buffer 1
 struct AHardwareBuffer;
diff --git a/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt b/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt
deleted file mode 100644
index 4c5551c..0000000
--- a/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt
+++ /dev/null
@@ -1,199 +0,0 @@
-Name
-
-    ANDROID_create_native_client_buffer
-
-Name Strings
-
-    EGL_ANDROID_create_native_client_buffer
-
-Contributors
-
-    Craig Donner
-
-Contact
-
-    Craig Donner, Google Inc. (cdonner 'at' google.com)
-
-Status
-
-    Draft
-
-Version
-
-    Version 1.1, October 26, 2016
-
-Number
-
-    EGL Extension #XXX
-
-Dependencies
-
-    Requires EGL 1.2.
-
-    EGL_ANDROID_image_native_buffer and EGL_KHR_image_base are required.
-
-    This extension is written against the wording of the EGL 1.2
-    Specification as modified by EGL_KHR_image_base and
-    EGL_ANDROID_image_native_buffer.
-
-Overview
-
-    This extension allows creating an EGLClientBuffer backed by an Android
-    window buffer (struct ANativeWindowBuffer) which can be later used to
-    create an EGLImage.
-
-New Types
-
-    None.
-
-New Procedures and Functions
-
-EGLClientBuffer eglCreateNativeClientBufferANDROID(
-                        const EGLint *attrib_list)
-
-New Tokens
-
-    EGL_NATIVE_BUFFER_LAYER_COUNT_ANDROID 0x3434
-    EGL_NATIVE_BUFFER_USAGE_ANDROID 0x3143
-    EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID 0x00000001
-    EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID 0x00000002
-    EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID 0x00000004
-
-Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors)
-
-    Add the following to section 2.5.1 "EGLImage Specification" (as modified by
-    the EGL_KHR_image_base and EGL_ANDROID_image_native_buffer specifications),
-    below the description of eglCreateImageKHR:
-
-   "The command
-
-        EGLClientBuffer eglCreateNativeClientBufferANDROID(
-                                const EGLint *attrib_list)
-
-    may be used to create an EGLClientBuffer backed by an ANativeWindowBuffer
-    struct. EGL implementations must guarantee that the lifetime of the
-    returned EGLClientBuffer is at least as long as the EGLImage(s) it is bound
-    to, following the lifetime semantics described below in section 2.5.2; the
-    EGLClientBuffer must be destroyed no earlier than when all of its associated
-    EGLImages are destroyed by eglDestroyImageKHR. <attrib_list> is a list of
-    attribute-value pairs which is used to specify the dimensions, format, and
-    usage of the underlying buffer structure. If <attrib_list> is non-NULL, the
-    last attribute specified in the list must be EGL_NONE.
-
-    Attribute names accepted in <attrib_list> are shown in Table aaa,
-    together with the <target> for which each attribute name is valid, and
-    the default value used for each attribute if it is not included in
-    <attrib_list>.
-
-      +---------------------------------+----------------------+---------------+
-      | Attribute                       | Description          | Default Value |
-      |                                 |                      |               |
-      +---------------------------------+----------------------+---------------+
-      | EGL_NONE                        | Marks the end of the | N/A           |
-      |                                 | attribute-value list |               |
-      | EGL_WIDTH                       | The width of the     | 0             |
-      |                                 | buffer data          |               |
-      | EGL_HEIGHT                      | The height of the    | 0             |
-      |                                 | buffer data          |               |
-      | EGL_RED_SIZE                    | The bits of Red in   | 0             |
-      |                                 | the color buffer     |               |
-      | EGL_GREEN_SIZE                  | The bits of Green in | 0             |
-      |                                 | the color buffer     |               |
-      | EGL_BLUE_SIZE                   | The bits of Blue in  | 0             |
-      |                                 | the color buffer     |               |
-      | EGL_ALPHA_SIZE                  | The bits of Alpha in | 0             |
-      |                                 | the color buffer     |               |
-      |                                 | buffer data          |               |
-      | EGL_LAYER_COUNT_ANDROID         | The number of image  | 1             |
-      |                                 | layers in the buffer |               |
-      | EGL_NATIVE_BUFFER_USAGE_ANDROID | The usage bits of    | 0             |
-      |                                 | the buffer data      |               |
-      +---------------------------------+----------------------+---------------+
-       Table aaa.  Legal attributes for eglCreateNativeClientBufferANDROID
-       <attrib_list> parameter.
-
-    The maximum width and height may depend on the amount of available memory,
-    which may also depend on the format and usage flags. The values of
-    EGL_RED_SIZE, EGL_GREEN_SIZE, and EGL_BLUE_SIZE must be non-zero and
-    correspond to a valid pixel format for the implementation. If EGL_ALPHA_SIZE
-    is non-zero then the combination of all four sizes must correspond to a
-    valid pixel format for the implementation. The value of
-    EGL_LAYER_COUNT_ANDROID must be a valid number of image layers for the
-    implementation. The EGL_NATIVE_BUFFER_USAGE_ANDROID flag may include any of
-    the following bits:
-
-        EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID: Indicates that the
-        created buffer must have a hardware-protected path to external display
-        sink. If a hardware-protected path is not available, then either don't
-        composite only this buffer (preferred) to the external sink, or (less
-        desirable) do not route the entire composition to the external sink.
-
-        EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID: The buffer will be
-        used to create a color-renderable texture.
-
-        EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID: The buffer will be used to
-        create a filterable texture.
-
-    Errors
-
-        If eglCreateNativeClientBufferANDROID fails, NULL will be returned, no
-        memory will be allocated, and one of the following errors will be
-        generated:
-
-       * If the value of EGL_WIDTH or EGL_HEIGHT is not positive, the error
-         EGL_BAD_PARAMETER is generated.
-
-       * If the combination of the values of EGL_RED_SIZE, EGL_GREEN_SIZE,
-         EGL_BLUE_SIZE, and EGL_ALPHA_SIZE is not a valid pixel format for the
-         EGL implementation, the error EGL_BAD_PARAMETER is generated.
-
-       * If the value of EGL_NATIVE_BUFFER_ANDROID is not a valid combination
-         of gralloc usage flags for the EGL implementation, or is incompatible
-         with the value of EGL_FORMAT, the error EGL_BAD_PARAMETER is
-         Generated.
-
-Issues
-
-    1. Should this extension define what combinations of formats and usage flags
-    EGL implementations are required to support?
-
-    RESOLVED: Partially.
-
-    The set of valid color combinations is implementation-specific and may
-    depend on additional EGL extensions, but generally RGB565 and RGBA888 should
-    be supported. The particular valid combinations for a given Android version
-    and implementation should be documented by that version.
-
-    2. Should there be an eglDestroyNativeClientBufferANDROID to destroy the
-    client buffers created by this extension?
-
-    RESOLVED: No.
-
-    A destroy function would add several complications:
-
-        a) ANativeWindowBuffer is a reference counted object, may be used
-           outside of EGL.
-        b) The same buffer may back multiple EGLImages, though this usage may
-           result in undefined behavior.
-        c) The interactions between the lifetimes of EGLImages and their
-           EGLClientBuffers would become needlessly complex.
-
-    Because ANativeWindowBuffer is a reference counted object, implementations
-    of this extension should ensure the buffer has a lifetime at least as long
-    as a generated EGLImage (via EGL_ANDROID_image_native_buffer). The simplest
-    method is to increment the reference count of the buffer in
-    eglCreateImagKHR, and then decrement it in eglDestroyImageKHR. This should
-    ensure proper lifetime semantics.
-
-Revision History
-
-#3 (Craig Donner, October 26, 2016)
-    - Added EGL_LAYER_COUNT_ANDROID for creating buffers that back texture
-    arrays.
-
-#2 (Craig Donner, April 15, 2016)
-    - Set color formats and usage bits explicitly using additional attributes,
-    and add value for new token EGL_NATIVE_BUFFER_USAGE_ANDROID.
-
-#1 (Craig Donner, January 19, 2016)
-    - Initial draft.
diff --git a/opengl/specs/README b/opengl/specs/README
index 27289e4..e922740 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -9,7 +9,6 @@
 0x3140               EGL_NATIVE_BUFFER_ANDROID (EGL_ANDROID_image_native_buffer)
 0x3141               EGL_PLATFORM_ANDROID_KHR (KHR_platform_android)
 0x3142               EGL_RECORDABLE_ANDROID (EGL_ANDROID_recordable)
-0x3143               EGL_NATIVE_BUFFER_USAGE_ANDROID (EGL_ANDROID_create_native_client_buffer)
 0x3144               EGL_SYNC_NATIVE_FENCE_ANDROID (EGL_ANDROID_native_fence_sync)
 0x3145               EGL_SYNC_NATIVE_FENCE_FD_ANDROID (EGL_ANDROID_native_fence_sync)
 0x3146               EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID (EGL_ANDROID_native_fence_sync)
diff --git a/services/batteryservice/IBatteryPropertiesRegistrar.cpp b/services/batteryservice/IBatteryPropertiesRegistrar.cpp
index 1fdda43..01a65ae 100644
--- a/services/batteryservice/IBatteryPropertiesRegistrar.cpp
+++ b/services/batteryservice/IBatteryPropertiesRegistrar.cpp
@@ -60,6 +60,12 @@
                 val->readFromParcel(&reply);
             return ret;
         }
+
+        void scheduleUpdate() {
+            Parcel data;
+            data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor());
+            remote()->transact(SCHEDULE_UPDATE, data, NULL);
+        }
 };
 
 IMPLEMENT_META_INTERFACE(BatteryPropertiesRegistrar, "android.os.IBatteryPropertiesRegistrar");
@@ -97,6 +103,12 @@
             val.writeToParcel(reply);
             return OK;
         }
+
+        case SCHEDULE_UPDATE: {
+            CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply);
+            scheduleUpdate();
+            return OK;
+        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 };
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index b8ca812..22a4616 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -2416,7 +2416,7 @@
             struct KeyReplacement replacement = {keyCode, args->deviceId};
             mReplacedKeys.add(replacement, newKeyCode);
             keyCode = newKeyCode;
-            metaState &= ~AMETA_META_ON;
+            metaState &= ~(AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
         }
     } else if (args->action == AKEY_EVENT_ACTION_UP) {
         // In order to maintain a consistent stream of up and down events, check to see if the key
@@ -2428,7 +2428,7 @@
         if (index >= 0) {
             keyCode = mReplacedKeys.valueAt(index);
             mReplacedKeys.removeItemsAt(index);
-            metaState &= ~AMETA_META_ON;
+            metaState &= ~(AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
         }
     }
 
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index c87a8d9..647a4c0 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -64,10 +64,6 @@
         DisplayHardware/HWComposer_hwc1.cpp
 endif
 
-ifneq ($(NUM_FRAMEBUFFER_SURFACE_BUFFERS),)
-    LOCAL_CFLAGS += -DNUM_FRAMEBUFFER_SURFACE_BUFFERS=$(NUM_FRAMEBUFFER_SURFACE_BUFFERS)
-endif
-
 LOCAL_CFLAGS += -fvisibility=hidden -Werror=format
 
 LOCAL_HEADER_LIBRARIES := \
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 11df4e2..c3b48ca 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -64,9 +64,8 @@
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
 
-static bool useTripleFramebuffer = getBool<
-        ISurfaceFlingerConfigs,
-        &ISurfaceFlingerConfigs::useTripleFramebuffer>(false);
+static bool useTripleFramebuffer = getInt64< ISurfaceFlingerConfigs,
+        &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2) == 3;
 
 #if !defined(EGL_EGLEXT_PROTOTYPES) || !defined(EGL_ANDROID_swap_rectangle)
 // Dummy implementation in case it is missing.
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 9a0e94e..1b598f8 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -40,10 +40,7 @@
 
 #include "FramebufferSurface.h"
 #include "HWComposer.h"
-
-#ifndef NUM_FRAMEBUFFER_SURFACE_BUFFERS
-#define NUM_FRAMEBUFFER_SURFACE_BUFFERS (2)
-#endif
+#include "../SurfaceFlinger.h"
 
 // ----------------------------------------------------------------------------
 namespace android {
@@ -88,7 +85,8 @@
     mConsumer->setDefaultBufferFormat(mHwc.getFormat(disp));
     mConsumer->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp));
 #endif
-    mConsumer->setMaxAcquiredBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS - 1);
+    mConsumer->setMaxAcquiredBufferCount(
+            SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1);
 }
 
 status_t FramebufferSurface::beginFrame(bool /*mustRecompose*/) {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 2755206..ac7e083 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -595,7 +595,7 @@
     const State& s(getDrawingState());
 #ifdef USE_HWC2
     auto blendMode = HWC2::BlendMode::None;
-    if (!isOpaque(s) || s.alpha != 1.0f) {
+    if (!isOpaque(s) || getAlpha() != 1.0f) {
         blendMode = mPremultipliedAlpha ?
                 HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage;
     }
@@ -604,7 +604,7 @@
              " %s (%d)", mName.string(), to_string(blendMode).c_str(),
              to_string(error).c_str(), static_cast<int32_t>(error));
 #else
-    if (!isOpaque(s) || s.alpha != 0xFF) {
+    if (!isOpaque(s) || getAlpha() != 0xFF) {
         layer.setBlending(mPremultipliedAlpha ?
                 HWC_BLENDING_PREMULT :
                 HWC_BLENDING_COVERAGE);
@@ -678,9 +678,10 @@
         hwcInfo.sourceCrop = sourceCrop;
     }
 
-    error = hwcLayer->setPlaneAlpha(s.alpha);
+    float alpha = getAlpha();
+    error = hwcLayer->setPlaneAlpha(alpha);
     ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set plane alpha %.3f: "
-            "%s (%d)", mName.string(), s.alpha, to_string(error).c_str(),
+            "%s (%d)", mName.string(), alpha, to_string(error).c_str(),
             static_cast<int32_t>(error));
 
     error = hwcLayer->setZOrder(z);
@@ -698,7 +699,7 @@
     const Transform& tr(hw->getTransform());
     layer.setFrame(tr.transform(frame));
     layer.setCrop(computeCrop(hw));
-    layer.setPlaneAlpha(s.alpha);
+    layer.setPlaneAlpha(getAlpha());
 #endif
 
     /*
@@ -1147,7 +1148,7 @@
     texCoords[3] = vec2(right, 1.0f - top);
 
     RenderEngine& engine(mFlinger->getRenderEngine());
-    engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), s.alpha);
+    engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), getAlpha());
     engine.drawMesh(mMesh);
     engine.disableBlending();
 }
@@ -1753,11 +1754,15 @@
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
-bool Layer::setFinalCrop(const Rect& crop) {
+
+bool Layer::setFinalCrop(const Rect& crop, bool immediate) {
     if (mCurrentState.finalCrop == crop)
         return false;
     mCurrentState.sequence++;
-    mCurrentState.finalCrop = crop;
+    mCurrentState.requestedFinalCrop = crop;
+    if (immediate) {
+        mCurrentState.finalCrop = crop;
+    }
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
@@ -1957,12 +1962,11 @@
 }
 
 bool Layer::isVisible() const {
-    const Layer::State& s(mDrawingState);
 #ifdef USE_HWC2
-    return !(isHiddenByPolicy()) && s.alpha > 0.0f
+    return !(isHiddenByPolicy()) && getAlpha() > 0.0f
             && (mActiveBuffer != NULL || mSidebandStream != NULL);
 #else
-    return !(isHiddenByPolicy()) && s.alpha
+    return !(isHiddenByPolicy()) && getAlpha()
             && (mActiveBuffer != NULL || mSidebandStream != NULL);
 #endif
 }
@@ -2519,6 +2523,24 @@
     return t * getDrawingState().active.transform;
 }
 
+#ifdef USE_HWC2
+float Layer::getAlpha() const {
+    const auto& p = getParent();
+
+    float parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0;
+    return parentAlpha * getDrawingState().alpha;
+}
+#else
+uint8_t Layer::getAlpha() const {
+    const auto& p = getParent();
+
+    float parentAlpha = (p != nullptr) ? (p->getAlpha() / 255.0f) : 1.0;
+    float drawingAlpha = getDrawingState().alpha / 255.0f;
+    drawingAlpha = drawingAlpha * parentAlpha;
+    return static_cast<uint8_t>(std::round(drawingAlpha * 255));
+}
+#endif
+
 void Layer::commitChildList() {
     for (size_t i = 0; i < mCurrentChildren.size(); i++) {
         const auto& child = mCurrentChildren[i];
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index cee9e3c..e21be8b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -135,6 +135,7 @@
 
         // finalCrop is expressed in display space coordinate.
         Rect finalCrop;
+        Rect requestedFinalCrop;
 
         // If set, defers this state update until the identified Layer
         // receives a frame with the given frameNumber
@@ -163,7 +164,14 @@
     status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
 
     // modify current state
+
+    // These members of state (position, crop, and finalCrop)
+    // may be updated immediately or have the update delayed
+    // until a pending surface resize completes (if applicable).
     bool setPosition(float x, float y, bool immediate);
+    bool setCrop(const Rect& crop, bool immediate);
+    bool setFinalCrop(const Rect& crop, bool immediate);
+
     bool setLayer(int32_t z);
     bool setSize(uint32_t w, uint32_t h);
 #ifdef USE_HWC2
@@ -174,8 +182,6 @@
     bool setMatrix(const layer_state_t::matrix22_t& matrix);
     bool setTransparentRegionHint(const Region& transparent);
     bool setFlags(uint8_t flags, uint8_t mask);
-    bool setCrop(const Rect& crop, bool immediate);
-    bool setFinalCrop(const Rect& crop);
     bool setLayerStack(uint32_t layerStack);
     bool setDataSpace(android_dataspace dataSpace);
     uint32_t getLayerStack() const;
@@ -453,6 +459,15 @@
 
     Transform getTransform() const;
 
+    // Returns the Alpha of the Surface, accounting for the Alpha
+    // of parent Surfaces in the hierarchy (alpha's will be multiplied
+    // down the hierarchy).
+#ifdef USE_HWC2
+    float getAlpha() const;
+#else
+    uint8_t getAlpha() const;
+#endif
+
     void traverseInReverseZOrder(const std::function<void(Layer*)>& exec);
     void traverseInZOrder(const std::function<void(Layer*)>& exec);
 
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index 5ca7d39..0b302eb 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -120,6 +120,11 @@
         mCurrent.crop = mFront.requestedCrop;
         mRecomputeVisibleRegions = true;
     }
+    if (mFront.finalCrop != mFront.requestedFinalCrop) {
+        mFront.finalCrop = mFront.requestedFinalCrop;
+        mCurrent.finalCrop = mFront.requestedFinalCrop;
+        mRecomputeVisibleRegions = true;
+    }
     mFreezePositionUpdates = false;
 
     return false;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9df49f6..f82b363 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -118,6 +118,7 @@
 uint64_t SurfaceFlinger::maxVirtualDisplaySize;
 bool SurfaceFlinger::hasSyncFramework;
 bool SurfaceFlinger::useVrFlinger;
+int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
 
 SurfaceFlinger::SurfaceFlinger()
     :   BnSurfaceComposer(),
@@ -185,6 +186,9 @@
     useVrFlinger = getBool< ISurfaceFlingerConfigs,
             &ISurfaceFlingerConfigs::useVrFlinger>(false);
 
+    maxFrameBufferAcquiredBuffers = getInt64< ISurfaceFlingerConfigs,
+            &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2);
+
     // debugging stuff...
     char value[PROPERTY_VALUE_MAX];
 
@@ -2762,7 +2766,7 @@
                 flags |= eTraversalNeeded;
         }
         if (what & layer_state_t::eFinalCropChanged) {
-            if (layer->setFinalCrop(s.finalCrop))
+            if (layer->setFinalCrop(s.finalCrop, !geometryAppliesWithResize))
                 flags |= eTraversalNeeded;
         }
         if (what & layer_state_t::eLayerStackChanged) {
@@ -3226,6 +3230,8 @@
     result.appendFormat(" FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv);
     result.appendFormat(" MAX_VIRT_DISPLAY_DIM=%" PRIu64, maxVirtualDisplaySize);
     result.appendFormat(" RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !hasSyncFramework);
+    result.appendFormat(" NUM_FRAMEBUFFER_SURFACE_BUFFERS=%" PRId64,
+                        maxFrameBufferAcquiredBuffers);
     result.append("]");
 }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 2a24cb2..581bbfd 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -147,6 +147,10 @@
     // Equal to min(max_height, max_width).
     static uint64_t maxVirtualDisplaySize;
 
+    // Controls the number of buffers SurfaceFlinger will allocate for use in
+    // FramebufferSurface
+    static int64_t maxFrameBufferAcquiredBuffers;
+
     static char const* getServiceName() ANDROID_API {
         return "SurfaceFlinger";
     }
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 0ff9f54..c26847f 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -116,6 +116,7 @@
 bool SurfaceFlinger::useHwcForRgbToYuv;
 uint64_t SurfaceFlinger::maxVirtualDisplaySize;
 bool SurfaceFlinger::hasSyncFramework;
+int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
 
 SurfaceFlinger::SurfaceFlinger()
     :   BnSurfaceComposer(),
@@ -175,6 +176,9 @@
     useHwcForRgbToYuv = getBool< ISurfaceFlingerConfigs,
             &ISurfaceFlingerConfigs::useHwcForRGBtoYUV>(false);
 
+    maxFrameBufferAcquiredBuffers = getInt64< ISurfaceFlingerConfigs,
+            &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2);
+
     char value[PROPERTY_VALUE_MAX];
 
     property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
@@ -2560,7 +2564,7 @@
                 flags |= eTraversalNeeded;
         }
         if (what & layer_state_t::eFinalCropChanged) {
-            if (layer->setFinalCrop(s.finalCrop))
+            if (layer->setFinalCrop(s.finalCrop, !geometryAppliesWithResize))
                 flags |= eTraversalNeeded;
         }
         if (what & layer_state_t::eLayerStackChanged) {
@@ -3024,6 +3028,8 @@
     result.appendFormat(" FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv);
     result.appendFormat(" MAX_VIRT_DISPLAY_DIM=%" PRIu64, maxVirtualDisplaySize);
     result.appendFormat(" RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !hasSyncFramework);
+    result.appendFormat(" NUM_FRAMEBUFFER_SURFACE_BUFFERS=%" PRId64,
+                        maxFrameBufferAcquiredBuffers);
     result.append("]");
 }
 
diff --git a/services/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk
index f46ce8a..16041da 100644
--- a/services/surfaceflinger/tests/Android.mk
+++ b/services/surfaceflinger/tests/Android.mk
@@ -28,6 +28,8 @@
 
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
+LOCAL_TEST_DATA = SurfaceFlinger_test.filter
+
 # Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
 # to integrate with auto-test framework.
 include $(BUILD_NATIVE_TEST)
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
new file mode 100644
index 0000000..915b5cd
--- /dev/null
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -0,0 +1,5 @@
+{
+        "presubmit": {
+            "filter": "LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*" 
+        }
+}
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index aeb557a..a46ba48 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -470,6 +470,141 @@
     }
 }
 
+class GeometryLatchingTest : public LayerUpdateTest {
+protected:
+    void EXPECT_INITIAL_STATE(const char * trace) {
+        SCOPED_TRACE(trace);
+        ScreenCapture::captureScreen(&sc);
+        // We find the leading edge of the FG surface.
+        sc->expectFGColor(127, 127);
+        sc->expectBGColor(128, 128);
+    }
+    void completeFGResize() {
+        fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+        waitForPostedBuffers();
+    }
+    void restoreInitialState() {
+        SurfaceComposerClient::openGlobalTransaction();
+        mFGSurfaceControl->setSize(64, 64);
+        mFGSurfaceControl->setPosition(64, 64);
+        mFGSurfaceControl->setCrop(Rect(0, 0, 64, 64));
+        mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1));
+        SurfaceComposerClient::closeGlobalTransaction(true);
+
+        EXPECT_INITIAL_STATE("After restoring initial state");
+    }
+    sp<ScreenCapture> sc;
+};
+
+TEST_F(GeometryLatchingTest, SurfacePositionLatching) {
+    EXPECT_INITIAL_STATE("before anything");
+
+    // By default position can be updated even while
+    // a resize is pending.
+    SurfaceComposerClient::openGlobalTransaction();
+    mFGSurfaceControl->setSize(32, 32);
+    mFGSurfaceControl->setPosition(100, 100);
+    SurfaceComposerClient::closeGlobalTransaction(true);
+
+    {
+        SCOPED_TRACE("After moving surface");
+        ScreenCapture::captureScreen(&sc);
+        // If we moved, the FG Surface should cover up what was previously BG
+        // however if we didn't move the FG wouldn't be large enough now.
+        sc->expectFGColor(163, 163);
+    }
+
+    restoreInitialState();
+
+    // Now we repeat with setGeometryAppliesWithResize
+    // and verify the position DOESN'T latch.
+    SurfaceComposerClient::openGlobalTransaction();
+    mFGSurfaceControl->setGeometryAppliesWithResize();
+    mFGSurfaceControl->setSize(32, 32);
+    mFGSurfaceControl->setPosition(100, 100);
+    SurfaceComposerClient::closeGlobalTransaction(true);
+
+    {
+        SCOPED_TRACE("While resize is pending");
+        ScreenCapture::captureScreen(&sc);
+        // This time we shouldn't have moved, so the BG color
+        // should still be visible.
+        sc->expectBGColor(128, 128);
+    }
+
+    completeFGResize();
+
+    {
+        SCOPED_TRACE("After the resize");
+        ScreenCapture::captureScreen(&sc);
+        // But after the resize completes, we should move
+        // and the FG should be visible here.
+        sc->expectFGColor(128, 128);
+    }
+}
+
+class CropLatchingTest : public GeometryLatchingTest {
+protected:
+    void EXPECT_CROPPED_STATE(const char* trace) {
+        SCOPED_TRACE(trace);
+        ScreenCapture::captureScreen(&sc);
+        // The edge should be moved back one pixel by our crop.
+        sc->expectFGColor(126, 126);
+        sc->expectBGColor(127, 127);
+        sc->expectBGColor(128, 128);
+    }
+};
+
+TEST_F(CropLatchingTest, CropLatching) {
+    EXPECT_INITIAL_STATE("before anything");
+    // Normally the crop applies immediately even while a resize is pending.
+    SurfaceComposerClient::openGlobalTransaction();
+    mFGSurfaceControl->setSize(128, 128);
+    mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+
+    EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)");
+
+    restoreInitialState();
+
+    SurfaceComposerClient::openGlobalTransaction();
+    mFGSurfaceControl->setSize(128, 128);
+    mFGSurfaceControl->setGeometryAppliesWithResize();
+    mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+
+    EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)");
+
+    completeFGResize();
+
+    EXPECT_CROPPED_STATE("after the resize finishes");
+}
+
+TEST_F(CropLatchingTest, FinalCropLatching) {
+    EXPECT_INITIAL_STATE("before anything");
+    // Normally the crop applies immediately even while a resize is pending.
+    SurfaceComposerClient::openGlobalTransaction();
+    mFGSurfaceControl->setSize(128, 128);
+    mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+
+    EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)");
+
+    restoreInitialState();
+
+    SurfaceComposerClient::openGlobalTransaction();
+    mFGSurfaceControl->setSize(128, 128);
+    mFGSurfaceControl->setGeometryAppliesWithResize();
+    mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+
+    EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)");
+
+    completeFGResize();
+
+    EXPECT_CROPPED_STATE("after the resize finishes");
+}
+
 TEST_F(LayerUpdateTest, DeferredTransactionTest) {
     sp<ScreenCapture> sc;
     {
@@ -629,6 +764,45 @@
     }
 }
 
+TEST_F(ChildLayerTest, ChildLayerAlpha) {
+    fillSurfaceRGBA8(mBGSurfaceControl, 0, 0, 254);
+    fillSurfaceRGBA8(mFGSurfaceControl, 254, 0, 0);
+    fillSurfaceRGBA8(mChild, 0, 254, 0);
+    waitForPostedBuffers();
+
+    SurfaceComposerClient::openGlobalTransaction();
+    mChild->show();
+    mChild->setPosition(0, 0);
+    mFGSurfaceControl->setPosition(0, 0);
+    SurfaceComposerClient::closeGlobalTransaction(true);
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // Unblended child color
+        mCapture->checkPixel(0, 0, 0, 254, 0);
+    }
+
+    SurfaceComposerClient::openGlobalTransaction();
+    ASSERT_EQ(NO_ERROR, mChild->setAlpha(0.5));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // Child and BG blended.
+        mCapture->checkPixel(0, 0, 127, 127, 0);
+    }
+
+    SurfaceComposerClient::openGlobalTransaction();
+    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.5));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // Child and BG blended.
+        mCapture->checkPixel(0, 0, 95, 64, 95);
+    }
+}
+
 TEST_F(ChildLayerTest, ReparentChildren) {
     SurfaceComposerClient::openGlobalTransaction();
     mChild->show();
@@ -677,11 +851,11 @@
 
     SurfaceComposerClient::openGlobalTransaction();
     mFGSurfaceControl->detachChildren();
-    SurfaceComposerClient::closeGlobalTransaction();
+    SurfaceComposerClient::closeGlobalTransaction(true);
 
     SurfaceComposerClient::openGlobalTransaction();
     mChild->hide();
-    SurfaceComposerClient::closeGlobalTransaction();
+    SurfaceComposerClient::closeGlobalTransaction(true);
 
     // Nothing should have changed.
     {
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
new file mode 100644
index 0000000..1601c7f
--- /dev/null
+++ b/services/vr/hardware_composer/Android.bp
@@ -0,0 +1,121 @@
+cc_library_static {
+  name: "libvr_hwc-binder",
+  srcs: [
+    "aidl/android/dvr/IVrComposer.aidl",
+    "aidl/android/dvr/IVrComposerCallback.aidl",
+    "aidl/android/dvr/parcelable_composer_frame.cpp",
+    "aidl/android/dvr/parcelable_composer_layer.cpp",
+    "aidl/android/dvr/parcelable_unique_fd.cpp",
+  ],
+  aidl: {
+    include_dirs: ["frameworks/native/services/vr/hardware_composer/aidl"],
+    export_aidl_headers: true,
+  },
+  export_include_dirs: ["aidl"],
+  shared_libs: [
+    "libbinder",
+    "libui",
+    "libutils",
+    "libvrhwc",
+  ],
+}
+
+cc_library_static {
+  name: "libvr_hwc-impl",
+  srcs: [
+    "vr_composer.cpp",
+  ],
+  static_libs: [
+    "libvr_hwc-binder",
+  ],
+  shared_libs: [
+    "libbase",
+    "libbinder",
+    "liblog",
+    "libui",
+    "libutils",
+    "libvrhwc",
+  ],
+  export_shared_lib_headers: [
+    "libvrhwc",
+  ],
+  cflags: [
+    "-DLOG_TAG=\"vr_hwc\"",
+  ],
+}
+
+cc_binary {
+  name: "vr_hwc",
+  srcs: [
+    "vr_hardware_composer_service.cpp"
+  ],
+  static_libs: [
+    "libvr_hwc-impl",
+    // NOTE: This needs to be included after the *-impl lib otherwise the
+    // symbols in the *-binder library get optimized out.
+    "libvr_hwc-binder",
+  ],
+  shared_libs: [
+    "android.dvr.composer@1.0",
+    "android.hardware.graphics.composer@2.1",
+    "libbase",
+    "libbinder",
+    "liblog",
+    "libhardware",
+    "libhwbinder",
+    "libui",
+    "libutils",
+    "libvrhwc",
+  ],
+  cflags: [
+    "-DLOG_TAG=\"vr_hwc\"",
+  ],
+  init_rc: [
+    "vr_hwc.rc",
+  ],
+}
+
+cc_library_static {
+  name: "libdvr_hwc",
+  srcs: [
+    "dvr_hardware_composer_client.cpp",
+  ],
+  static_libs: [
+    "libvr_hwc-impl",
+    // NOTE: This needs to be included after the *-impl lib otherwise the
+    // symbols in the *-binder library get optimized out.
+    "libvr_hwc-binder",
+  ],
+  shared_libs: [
+    "libbase",
+    "libbinder",
+    "liblog",
+    "libnativewindow",
+    "libui",
+    "libutils",
+  ],
+  export_include_dirs: ["private"],
+  export_shared_lib_headers: [
+    "libnativewindow",
+  ],
+}
+
+cc_test {
+  name: "vr_hwc_test",
+  gtest: true,
+  srcs: ["tests/vr_composer_test.cpp"],
+  static_libs: [
+    "libgtest",
+    "libvr_hwc-impl",
+    // NOTE: This needs to be included after the *-impl lib otherwise the
+    // symbols in the *-binder library get optimized out.
+    "libvr_hwc-binder",
+  ],
+  shared_libs: [
+    "libbase",
+    "libbinder",
+    "liblog",
+    "libui",
+    "libutils",
+  ],
+}
diff --git a/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl b/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
new file mode 100644
index 0000000..5fd5c36
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
@@ -0,0 +1,20 @@
+package android.dvr;
+
+import android.dvr.IVrComposerCallback;
+
+/**
+ * Service interface exposed by VR HWC exposed to system apps which allows one
+ * system app to connect to get SurfaceFlinger's outputs (all displays). This
+ * is active when SurfaceFlinger is in VR mode, where all 2D output is
+ * redirected to VR HWC.
+ *
+ * @hide */
+interface IVrComposer
+{
+  const String SERVICE_NAME = "vr_hwc";
+
+  /**
+   * Registers a callback used to receive frame notifications.
+   */
+  void registerObserver(in IVrComposerCallback callback);
+}
diff --git a/services/vr/hardware_composer/aidl/android/dvr/IVrComposerCallback.aidl b/services/vr/hardware_composer/aidl/android/dvr/IVrComposerCallback.aidl
new file mode 100644
index 0000000..aa70de1
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/IVrComposerCallback.aidl
@@ -0,0 +1,22 @@
+package android.dvr;
+
+import android.dvr.ParcelableComposerFrame;
+import android.dvr.ParcelableUniqueFd;
+
+/**
+ * A system app will implement and register this callback with VRComposer
+ * to receive the layers SurfaceFlinger presented when in VR mode.
+ *
+ * @hide */
+interface IVrComposerCallback {
+  /**
+   * Called by the VR HWC service when a new frame is ready to be presented.
+   *
+   * @param frame The new frame VR HWC wants to present.
+   * @return A fence FD used to signal when the previous frame is no longer
+   * used by the client. This may be an invalid fence (-1) if the client is not
+   * using the previous frame, in which case the previous frame may be re-used
+   * at any point in time.
+   */
+  ParcelableUniqueFd onNewFrame(in ParcelableComposerFrame frame);
+}
diff --git a/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerFrame.aidl b/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerFrame.aidl
new file mode 100644
index 0000000..84abc19
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerFrame.aidl
@@ -0,0 +1,3 @@
+package android.dvr;
+
+parcelable ParcelableComposerFrame cpp_header "android/dvr/parcelable_composer_frame.h";
diff --git a/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerLayer.aidl b/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerLayer.aidl
new file mode 100644
index 0000000..a200345
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerLayer.aidl
@@ -0,0 +1,3 @@
+package android.dvr;
+
+parcelable ParcelableComposerLayer cpp_header "android/dvr/parcelable_composer_layer.h";
diff --git a/services/vr/hardware_composer/aidl/android/dvr/ParcelableUniqueFd.aidl b/services/vr/hardware_composer/aidl/android/dvr/ParcelableUniqueFd.aidl
new file mode 100644
index 0000000..eee9d13
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/ParcelableUniqueFd.aidl
@@ -0,0 +1,3 @@
+package android.dvr;
+
+parcelable ParcelableUniqueFd cpp_header "android/dvr/parcelable_unique_fd.h";
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
new file mode 100644
index 0000000..cb3e49d
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
@@ -0,0 +1,53 @@
+#include "aidl/android/dvr/parcelable_composer_frame.h"
+
+#include <binder/Parcel.h>
+
+#include "aidl/android/dvr/parcelable_composer_layer.h"
+
+namespace android {
+namespace dvr {
+
+ParcelableComposerFrame::ParcelableComposerFrame() {}
+
+ParcelableComposerFrame::ParcelableComposerFrame(
+    const ComposerView::Frame& frame)
+    : frame_(frame) {}
+
+ParcelableComposerFrame::~ParcelableComposerFrame() {}
+
+status_t ParcelableComposerFrame::writeToParcel(Parcel* parcel) const {
+  status_t ret = parcel->writeUint64(frame_.display_id);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeBool(frame_.removed);
+  if (ret != OK) return ret;
+
+  std::vector<ParcelableComposerLayer> layers;
+  for (size_t i = 0; i < frame_.layers.size(); ++i)
+    layers.push_back(ParcelableComposerLayer(frame_.layers[i]));
+
+  ret = parcel->writeParcelableVector(layers);
+
+  return ret;
+}
+
+status_t ParcelableComposerFrame::readFromParcel(const Parcel* parcel) {
+  status_t ret = parcel->readUint64(&frame_.display_id);
+  if (ret != OK) return ret;
+
+  ret = parcel->readBool(&frame_.removed);
+  if (ret != OK) return ret;
+
+  std::vector<ParcelableComposerLayer> layers;
+  ret = parcel->readParcelableVector(&layers);
+  if (ret != OK) return ret;
+
+  frame_.layers.clear();
+  for (size_t i = 0; i < layers.size(); ++i)
+    frame_.layers.push_back(layers[i].layer());
+
+  return ret;
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h
new file mode 100644
index 0000000..b478bb5
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h
@@ -0,0 +1,28 @@
+#ifndef ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_FRAME_H
+#define ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_FRAME_H
+
+#include <binder/Parcelable.h>
+#include <impl/vr_hwc.h>
+
+namespace android {
+namespace dvr {
+
+class ParcelableComposerFrame : public Parcelable {
+ public:
+  ParcelableComposerFrame();
+  ParcelableComposerFrame(const ComposerView::Frame& frame);
+  ~ParcelableComposerFrame() override;
+
+  ComposerView::Frame frame() const { return frame_; }
+
+  status_t writeToParcel(Parcel* parcel) const override;
+  status_t readFromParcel(const Parcel* parcel) override;
+
+ private:
+  ComposerView::Frame frame_;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_FRAME_H
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp
new file mode 100644
index 0000000..34e2b7e
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp
@@ -0,0 +1,166 @@
+#include "aidl/android/dvr/parcelable_composer_layer.h"
+
+#include <binder/Parcel.h>
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferMapper.h>
+
+namespace android {
+namespace dvr {
+namespace {
+
+sp<GraphicBuffer> GetBufferFromHandle(native_handle_t* handle) {
+  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();
+  // Need to register |handle| otherwise we can't read its properties.
+  if (mapper.registerBuffer(handle) != OK) {
+    ALOGE("Failed to register buffer");
+    return nullptr;
+  }
+
+  if (mapper.getDimensions(handle, &width, &height) ||
+      mapper.getStride(handle, &stride) ||
+      mapper.getFormat(handle, &format) ||
+      mapper.getProducerUsage(handle, &producer_usage) ||
+      mapper.getConsumerUsage(handle, &consumer_usage)) {
+    ALOGE("Failed to read handle properties");
+    return nullptr;
+  }
+
+  // This will only succeed if gralloc has GRALLOC1_CAPABILITY_LAYERED_BUFFERS
+  // capability. Otherwise assume a count of 1.
+  mapper.getLayerCount(handle, &layer_count);
+
+  sp<GraphicBuffer> buffer = new GraphicBuffer(
+      width, height, format, layer_count, producer_usage, consumer_usage,
+      stride, handle, true);
+
+  return buffer;
+}
+
+}  // namespace
+
+ParcelableComposerLayer::ParcelableComposerLayer() {}
+
+ParcelableComposerLayer::ParcelableComposerLayer(
+    const ComposerView::ComposerLayer& layer) : layer_(layer) {}
+
+ParcelableComposerLayer::~ParcelableComposerLayer() {}
+
+status_t ParcelableComposerLayer::writeToParcel(Parcel* parcel) const {
+  status_t ret = parcel->writeUint64(layer_.id);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeNativeHandle(layer_.buffer->getNativeBuffer()->handle);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeBool(layer_.fence->isValid());
+  if (ret != OK) return ret;
+
+  if (layer_.fence->isValid()) {
+    ret = parcel->writeFileDescriptor(layer_.fence->dup(), true);
+    if (ret != OK) return ret;
+  }
+
+  ret = parcel->writeInt32(layer_.display_frame.left);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeInt32(layer_.display_frame.top);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeInt32(layer_.display_frame.right);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeInt32(layer_.display_frame.bottom);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeFloat(layer_.crop.left);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeFloat(layer_.crop.top);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeFloat(layer_.crop.right);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeFloat(layer_.crop.bottom);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeInt32(static_cast<int32_t>(layer_.blend_mode));
+  if (ret != OK) return ret;
+
+  ret = parcel->writeFloat(layer_.alpha);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeUint32(layer_.type);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeUint32(layer_.app_id);
+  if (ret != OK) return ret;
+
+  return OK;
+}
+
+status_t ParcelableComposerLayer::readFromParcel(const Parcel* parcel) {
+  status_t ret = parcel->readUint64(&layer_.id);
+  if (ret != OK) return ret;
+
+  native_handle* handle = parcel->readNativeHandle();
+  if (!handle) return BAD_VALUE;
+
+  layer_.buffer = GetBufferFromHandle(handle);
+  if (!layer_.buffer.get()) return BAD_VALUE;
+
+  bool has_fence = 0;
+  ret = parcel->readBool(&has_fence);
+  if (ret != OK) return ret;
+
+  if (has_fence)
+    layer_.fence = new Fence(dup(parcel->readFileDescriptor()));
+  else
+    layer_.fence = new Fence();
+
+  ret = parcel->readInt32(&layer_.display_frame.left);
+  if (ret != OK) return ret;
+
+  ret = parcel->readInt32(&layer_.display_frame.top);
+  if (ret != OK) return ret;
+
+  ret = parcel->readInt32(&layer_.display_frame.right);
+  if (ret != OK) return ret;
+
+  ret = parcel->readInt32(&layer_.display_frame.bottom);
+  if (ret != OK) return ret;
+
+  ret = parcel->readFloat(&layer_.crop.left);
+  if (ret != OK) return ret;
+
+  ret = parcel->readFloat(&layer_.crop.top);
+  if (ret != OK) return ret;
+
+  ret = parcel->readFloat(&layer_.crop.right);
+  if (ret != OK) return ret;
+
+  ret = parcel->readFloat(&layer_.crop.bottom);
+  if (ret != OK) return ret;
+
+  ret = parcel->readInt32(reinterpret_cast<int32_t*>(&layer_.blend_mode));
+  if (ret != OK) return ret;
+
+  ret = parcel->readFloat(&layer_.alpha);
+  if (ret != OK) return ret;
+
+  ret = parcel->readUint32(&layer_.type);
+  if (ret != OK) return ret;
+
+  ret = parcel->readUint32(&layer_.app_id);
+  if (ret != OK) return ret;
+
+  return OK;
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h
new file mode 100644
index 0000000..4cf48f1
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h
@@ -0,0 +1,30 @@
+#ifndef ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_LAYER_H
+#define ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_LAYER_H
+
+#include <binder/Parcelable.h>
+#include <impl/vr_hwc.h>
+
+#include <memory>
+
+namespace android {
+namespace dvr {
+
+class ParcelableComposerLayer : public Parcelable {
+ public:
+  ParcelableComposerLayer();
+  ParcelableComposerLayer(const ComposerView::ComposerLayer& layer);
+  ~ParcelableComposerLayer() override;
+
+  ComposerView::ComposerLayer layer() const { return layer_; }
+
+  status_t writeToParcel(Parcel* parcel) const override;
+  status_t readFromParcel(const Parcel* parcel) override;
+
+ private:
+  ComposerView::ComposerLayer layer_;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_LAYER_H
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.cpp
new file mode 100644
index 0000000..9486f3c
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.cpp
@@ -0,0 +1,37 @@
+#include "android/dvr/parcelable_unique_fd.h"
+
+#include <binder/Parcel.h>
+
+namespace android {
+namespace dvr {
+
+ParcelableUniqueFd::ParcelableUniqueFd() {}
+
+ParcelableUniqueFd::ParcelableUniqueFd(const base::unique_fd& fence)
+    : fence_(dup(fence.get())) {}
+
+ParcelableUniqueFd::~ParcelableUniqueFd() {}
+
+status_t ParcelableUniqueFd::writeToParcel(Parcel* parcel) const {
+  status_t ret = parcel->writeBool(fence_.get() >= 0);
+  if (ret != OK) return ret;
+
+  if (fence_.get() >= 0)
+    ret = parcel->writeUniqueFileDescriptor(fence_);
+
+  return ret;
+}
+
+status_t ParcelableUniqueFd::readFromParcel(const Parcel* parcel) {
+  bool has_fence = 0;
+  status_t ret = parcel->readBool(&has_fence);
+  if (ret != OK) return ret;
+
+  if (has_fence)
+    ret = parcel->readUniqueFileDescriptor(&fence_);
+
+  return ret;
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h
new file mode 100644
index 0000000..daf9e6d
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h
@@ -0,0 +1,34 @@
+#ifndef ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_UNIQUE_FD_H
+#define ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_UNIQUE_FD_H
+
+#include <android-base/unique_fd.h>
+#include <binder/Parcelable.h>
+
+namespace android {
+namespace dvr {
+
+// Provide a wrapper to serialized base::unique_fd. The wrapper also handles the
+// case where the FD is invalid (-1), unlike FileDescriptor which expects a
+// valid FD.
+class ParcelableUniqueFd : public Parcelable {
+ public:
+  ParcelableUniqueFd();
+  ParcelableUniqueFd(const base::unique_fd& fence);
+  ~ParcelableUniqueFd() override;
+
+  void set_fence(const base::unique_fd& fence) {
+    fence_.reset(dup(fence.get()));
+  }
+  base::unique_fd fence() const { return base::unique_fd(dup(fence_.get())); }
+
+  status_t writeToParcel(Parcel* parcel) const override;
+  status_t readFromParcel(const Parcel* parcel) override;
+
+ private:
+  base::unique_fd fence_;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_UNIQUE_FD_H
diff --git a/services/vr/hardware_composer/dvr_hardware_composer_client.cpp b/services/vr/hardware_composer/dvr_hardware_composer_client.cpp
new file mode 100644
index 0000000..39fa9fc
--- /dev/null
+++ b/services/vr/hardware_composer/dvr_hardware_composer_client.cpp
@@ -0,0 +1,136 @@
+#include "private/android/dvr_hardware_composer_client.h"
+
+#include <android/dvr/IVrComposer.h>
+#include <android/dvr/BnVrComposerCallback.h>
+#include <binder/IServiceManager.h>
+#include <private/android/AHardwareBufferHelpers.h>
+
+#include <memory>
+
+struct DvrHwcFrame {
+  android::dvr::ComposerView::Frame frame;
+};
+
+namespace {
+
+class HwcCallback : public android::dvr::BnVrComposerCallback {
+ public:
+  explicit HwcCallback(DvrHwcOnFrameCallback callback);
+  ~HwcCallback() override;
+
+  std::unique_ptr<DvrHwcFrame> DequeueFrame();
+
+ private:
+  // android::dvr::BnVrComposerCallback:
+  android::binder::Status onNewFrame(
+      const android::dvr::ParcelableComposerFrame& frame,
+      android::dvr::ParcelableUniqueFd* fence) override;
+
+  DvrHwcOnFrameCallback callback_;
+
+  HwcCallback(const HwcCallback&) = delete;
+  void operator=(const HwcCallback&) = delete;
+};
+
+HwcCallback::HwcCallback(DvrHwcOnFrameCallback callback)
+    : callback_(callback) {}
+
+HwcCallback::~HwcCallback() {}
+
+android::binder::Status HwcCallback::onNewFrame(
+    const android::dvr::ParcelableComposerFrame& frame,
+    android::dvr::ParcelableUniqueFd* fence) {
+  std::unique_ptr<DvrHwcFrame> dvr_frame(new DvrHwcFrame());
+  dvr_frame->frame = frame.frame();
+
+  fence->set_fence(android::base::unique_fd(callback_(dvr_frame.release())));
+  return android::binder::Status::ok();
+}
+
+}  // namespace
+
+struct DvrHwcClient {
+  android::sp<android::dvr::IVrComposer> composer;
+  android::sp<HwcCallback> callback;
+};
+
+DvrHwcClient* dvrHwcCreateClient(DvrHwcOnFrameCallback callback) {
+  std::unique_ptr<DvrHwcClient> client(new DvrHwcClient());
+
+  android::sp<android::IServiceManager> sm(android::defaultServiceManager());
+  client->composer = android::interface_cast<android::dvr::IVrComposer>(
+      sm->getService(android::dvr::IVrComposer::SERVICE_NAME()));
+  if (!client->composer.get())
+    return nullptr;
+
+  client->callback = new HwcCallback(callback);
+  android::binder::Status status = client->composer->registerObserver(
+      client->callback);
+  if (!status.isOk())
+    return nullptr;
+
+  return client.release();
+}
+
+void dvrHwcFrameDestroy(DvrHwcFrame* frame) {
+  delete frame;
+}
+
+Display dvrHwcFrameGetDisplayId(DvrHwcFrame* frame) {
+  return frame->frame.display_id;
+}
+
+size_t dvrHwcFrameGetLayerCount(DvrHwcFrame* frame) {
+  return frame->frame.layers.size();
+}
+
+Layer dvrHwcFrameGetLayerId(DvrHwcFrame* frame, size_t layer_index) {
+  return frame->frame.layers[layer_index].id;
+}
+
+AHardwareBuffer* dvrHwcFrameGetLayerBuffer(DvrHwcFrame* frame,
+                                           size_t layer_index) {
+  AHardwareBuffer* buffer = android::AHardwareBuffer_from_GraphicBuffer(
+      frame->frame.layers[layer_index].buffer.get());
+  AHardwareBuffer_acquire(buffer);
+  return buffer;
+}
+
+int dvrHwcFrameGetLayerFence(DvrHwcFrame* frame, size_t layer_index) {
+  return frame->frame.layers[layer_index].fence->dup();
+}
+
+Recti dvrHwcFrameGetLayerDisplayFrame(DvrHwcFrame* frame, size_t layer_index) {
+  return Recti{
+    frame->frame.layers[layer_index].display_frame.left,
+    frame->frame.layers[layer_index].display_frame.top,
+    frame->frame.layers[layer_index].display_frame.right,
+    frame->frame.layers[layer_index].display_frame.bottom,
+  };
+}
+
+Rectf dvrHwcFrameGetLayerCrop(DvrHwcFrame* frame, size_t layer_index) {
+  return Rectf{
+    frame->frame.layers[layer_index].crop.left,
+    frame->frame.layers[layer_index].crop.top,
+    frame->frame.layers[layer_index].crop.right,
+    frame->frame.layers[layer_index].crop.bottom,
+  };
+}
+
+BlendMode dvrHwcFrameGetLayerBlendMode(DvrHwcFrame* frame, size_t layer_index) {
+  return static_cast<BlendMode>(frame->frame.layers[layer_index].blend_mode);
+}
+
+float dvrHwcFrameGetLayerAlpha(DvrHwcFrame* frame, size_t layer_index) {
+  return frame->frame.layers[layer_index].alpha;
+}
+
+uint32_t dvrHwcFrameGetLayerType(DvrHwcFrame* frame, size_t layer_index) {
+  return frame->frame.layers[layer_index].type;
+}
+
+uint32_t dvrHwcFrameGetLayerApplicationId(DvrHwcFrame* frame,
+                                          size_t layer_index) {
+  return frame->frame.layers[layer_index].app_id;
+}
diff --git a/services/vr/hardware_composer/private/android/dvr_hardware_composer_client.h b/services/vr/hardware_composer/private/android/dvr_hardware_composer_client.h
new file mode 100644
index 0000000..063c16d
--- /dev/null
+++ b/services/vr/hardware_composer/private/android/dvr_hardware_composer_client.h
@@ -0,0 +1,62 @@
+#ifndef VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
+#define VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
+
+#include <android/dvr_hardware_composer_defs.h>
+#include <android/hardware_buffer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct DvrHwcClient DvrHwcClient;
+typedef struct DvrHwcFrame DvrHwcFrame;
+
+// Called when a new frame has arrived.
+//
+// @param frame New frame. Owned by the client.
+// @return fence FD for the release of the last frame.
+typedef int(*DvrHwcOnFrameCallback)(DvrHwcFrame* frame);
+
+DvrHwcClient* dvrHwcCreateClient(DvrHwcOnFrameCallback callback);
+
+// Called to free the frame information.
+void dvrHwcFrameDestroy(DvrHwcFrame* frame);
+
+Display dvrHwcFrameGetDisplayId(DvrHwcFrame* frame);
+
+// @return Number of layers in the frame.
+size_t dvrHwcFrameGetLayerCount(DvrHwcFrame* frame);
+
+Layer dvrHwcFrameGetLayerId(DvrHwcFrame* frame, size_t layer_index);
+
+// Return the graphic buffer associated with the layer at |layer_index| in
+// |frame|.
+//
+// @return Graphic buffer. Caller owns the buffer and is responsible for freeing
+// it. (see AHardwareBuffer_release())
+AHardwareBuffer* dvrHwcFrameGetLayerBuffer(DvrHwcFrame* frame,
+                                           size_t layer_index);
+
+// Returns the fence FD for the layer at index |layer_index| in |frame|.
+//
+// @return Fence FD. Caller owns the FD and is responsible for closing it.
+int dvrHwcFrameGetLayerFence(DvrHwcFrame* frame, size_t layer_index);
+
+Recti dvrHwcFrameGetLayerDisplayFrame(DvrHwcFrame* frame, size_t layer_index);
+
+Rectf dvrHwcFrameGetLayerCrop(DvrHwcFrame* frame, size_t layer_index);
+
+BlendMode dvrHwcFrameGetLayerBlendMode(DvrHwcFrame* frame, size_t layer_index);
+
+float dvrHwcFrameGetLayerAlpha(DvrHwcFrame* frame, size_t layer_index);
+
+uint32_t dvrHwcFrameGetLayerType(DvrHwcFrame* frame, size_t layer_index);
+
+uint32_t dvrHwcFrameGetLayerApplicationId(DvrHwcFrame* frame,
+                                          size_t layer_index);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
diff --git a/services/vr/hardware_composer/private/android/dvr_hardware_composer_defs.h b/services/vr/hardware_composer/private/android/dvr_hardware_composer_defs.h
new file mode 100644
index 0000000..3186f82
--- /dev/null
+++ b/services/vr/hardware_composer/private/android/dvr_hardware_composer_defs.h
@@ -0,0 +1,50 @@
+#ifndef VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_VR_HARDWARE_COMPOSER_DEFS_H
+#define VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_VR_HARDWARE_COMPOSER_DEFS_H
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// NOTE: These definitions must match the ones in
+// //hardware/libhardware/include/hardware/hwcomposer2.h. They are used by the
+// client side which does not have access to hwc2 headers.
+enum BlendMode {
+  BLEND_MODE_INVALID = 0,
+  BLEND_MODE_NONE = 1,
+  BLEND_MODE_PREMULTIPLIED = 2,
+  BLEND_MODE_COVERAGE = 3,
+};
+
+enum Composition {
+  COMPOSITION_INVALID = 0,
+  COMPOSITION_CLIENT = 1,
+  COMPOSITION_DEVICE = 2,
+  COMPOSITION_SOLID_COLOR = 3,
+  COMPOSITION_CURSOR = 4,
+  COMPOSITION_SIDEBAND = 5,
+};
+
+typedef uint64_t Display;
+typedef uint64_t Layer;
+
+struct Recti {
+  int32_t left;
+  int32_t top;
+  int32_t right;
+  int32_t bottom;
+};
+
+struct Rectf {
+  float left;
+  float top;
+  float right;
+  float bottom;
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_DEFS_H
diff --git a/services/vr/hardware_composer/tests/vr_composer_test.cpp b/services/vr/hardware_composer/tests/vr_composer_test.cpp
new file mode 100644
index 0000000..cfc2708
--- /dev/null
+++ b/services/vr/hardware_composer/tests/vr_composer_test.cpp
@@ -0,0 +1,147 @@
+#include <android/dvr/BnVrComposerCallback.h>
+#include <binder/IServiceManager.h>
+#include <gtest/gtest.h>
+#include <sys/eventfd.h>
+#include <vr_composer.h>
+
+namespace android {
+namespace dvr {
+namespace {
+
+const char kVrDisplayName[] = "VrDisplay_Test";
+
+class TestComposerCallback : public BnVrComposerCallback {
+ public:
+  TestComposerCallback() {}
+  ~TestComposerCallback() override = default;
+
+  ComposerView::Frame last_frame() const { return last_frame_; }
+
+  binder::Status onNewFrame(
+      const ParcelableComposerFrame& frame,
+      ParcelableUniqueFd* /* fence */) override {
+    last_frame_ = frame.frame();
+    return binder::Status::ok();
+  }
+
+ private:
+  ComposerView::Frame last_frame_;
+
+  TestComposerCallback(const TestComposerCallback&) = delete;
+  void operator=(const TestComposerCallback&) = delete;
+};
+
+class TestComposerCallbackWithFence : public TestComposerCallback {
+ public:
+  ~TestComposerCallbackWithFence() override = default;
+
+  binder::Status onNewFrame(
+      const ParcelableComposerFrame& frame,
+      ParcelableUniqueFd* fence) override {
+    binder::Status status = TestComposerCallback::onNewFrame(frame, fence);
+
+    base::unique_fd fd(eventfd(0, 0));
+    EXPECT_LE(0, fd.get());
+    fence->set_fence(fd);
+
+    return status;
+  }
+};
+
+sp<GraphicBuffer> CreateBuffer() {
+  return new GraphicBuffer(600, 400, PIXEL_FORMAT_RGBA_8888,
+                           GraphicBuffer::USAGE_HW_TEXTURE);
+}
+
+}  // namespace
+
+class VrComposerTest : public testing::Test {
+ public:
+  VrComposerTest() : composer_(new VrComposer()) {}
+  ~VrComposerTest() override = default;
+
+  sp<IVrComposer> GetComposerProxy() const {
+    sp<IServiceManager> sm(defaultServiceManager());
+    return interface_cast<IVrComposer>(sm->getService(String16(kVrDisplayName)));
+  }
+
+  void SetUp() override {
+    sp<IServiceManager> sm(defaultServiceManager());
+    EXPECT_EQ(OK,
+              sm->addService(String16(kVrDisplayName), composer_, false));
+  }
+
+ protected:
+  sp<VrComposer> composer_;
+
+  VrComposerTest(const VrComposerTest&) = delete;
+  void operator=(const VrComposerTest&) = delete;
+};
+
+TEST_F(VrComposerTest, TestWithoutObserver) {
+  sp<IVrComposer> composer = GetComposerProxy();
+  ComposerView::Frame frame;
+
+  base::unique_fd fence = composer_->OnNewFrame(frame);
+  ASSERT_EQ(-1, fence.get());
+}
+
+TEST_F(VrComposerTest, TestWithObserver) {
+  sp<IVrComposer> composer = GetComposerProxy();
+  sp<TestComposerCallback> callback = new TestComposerCallback();
+  ASSERT_TRUE(composer->registerObserver(callback).isOk());
+
+  ComposerView::Frame frame;
+  base::unique_fd fence = composer_->OnNewFrame(frame);
+  ASSERT_EQ(-1, fence.get());
+}
+
+TEST_F(VrComposerTest, TestWithOneLayer) {
+  sp<IVrComposer> composer = GetComposerProxy();
+  sp<TestComposerCallback> callback = new TestComposerCallbackWithFence();
+  ASSERT_TRUE(composer->registerObserver(callback).isOk());
+
+  ComposerView::Frame frame;
+  frame.display_id = 1;
+  frame.removed = false;
+  frame.layers.push_back(ComposerView::ComposerLayer{
+    .id = 1,
+    .buffer = CreateBuffer(),
+    .fence = new Fence(eventfd(0, 0)),
+    .display_frame = {0, 0, 600, 400},
+    .crop = {0.0f, 0.0f, 600.0f, 400.0f},
+    .blend_mode = IComposerClient::BlendMode::NONE,
+    .alpha = 1.0f,
+    .type = 1,
+    .app_id = 1,
+  });
+  base::unique_fd fence = composer_->OnNewFrame(frame);
+  ASSERT_LE(0, fence.get());
+
+  ComposerView::Frame received_frame = callback->last_frame();
+  ASSERT_EQ(frame.display_id, received_frame.display_id);
+  ASSERT_EQ(frame.removed, received_frame.removed);
+  ASSERT_EQ(1u, received_frame.layers.size());
+  ASSERT_EQ(frame.layers[0].id, received_frame.layers[0].id);
+  ASSERT_NE(nullptr, received_frame.layers[0].buffer.get());
+  ASSERT_TRUE(received_frame.layers[0].fence->isValid());
+  ASSERT_EQ(frame.layers[0].display_frame.left,
+            received_frame.layers[0].display_frame.left);
+  ASSERT_EQ(frame.layers[0].display_frame.top,
+            received_frame.layers[0].display_frame.top);
+  ASSERT_EQ(frame.layers[0].display_frame.right,
+            received_frame.layers[0].display_frame.right);
+  ASSERT_EQ(frame.layers[0].display_frame.bottom,
+            received_frame.layers[0].display_frame.bottom);
+  ASSERT_EQ(frame.layers[0].crop.left, received_frame.layers[0].crop.left);
+  ASSERT_EQ(frame.layers[0].crop.top, received_frame.layers[0].crop.top);
+  ASSERT_EQ(frame.layers[0].crop.right, received_frame.layers[0].crop.right);
+  ASSERT_EQ(frame.layers[0].crop.bottom, received_frame.layers[0].crop.bottom);
+  ASSERT_EQ(frame.layers[0].blend_mode, received_frame.layers[0].blend_mode);
+  ASSERT_EQ(frame.layers[0].alpha, received_frame.layers[0].alpha);
+  ASSERT_EQ(frame.layers[0].type, received_frame.layers[0].type);
+  ASSERT_EQ(frame.layers[0].app_id, received_frame.layers[0].app_id);
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/hardware_composer/vr_composer.cpp b/services/vr/hardware_composer/vr_composer.cpp
new file mode 100644
index 0000000..c15f8fd
--- /dev/null
+++ b/services/vr/hardware_composer/vr_composer.cpp
@@ -0,0 +1,46 @@
+#include "vr_composer.h"
+
+namespace android {
+namespace dvr {
+
+VrComposer::VrComposer() {}
+
+VrComposer::~VrComposer() {}
+
+binder::Status VrComposer::registerObserver(
+    const sp<IVrComposerCallback>& callback) {
+  std::lock_guard<std::mutex> guard(mutex_);
+
+  if (callback_.get()) {
+    ALOGE("Failed to register callback, already registered");
+    return binder::Status::fromStatusT(ALREADY_EXISTS);
+  }
+
+  callback_ = callback;
+  IInterface::asBinder(callback_)->linkToDeath(this);
+  return binder::Status::ok();
+}
+
+base::unique_fd VrComposer::OnNewFrame(const ComposerView::Frame& frame) {
+  std::lock_guard<std::mutex> guard(mutex_);
+
+  if (!callback_.get())
+    return base::unique_fd();
+
+  ParcelableComposerFrame parcelable_frame(frame);
+  ParcelableUniqueFd fence;
+  binder::Status ret = callback_->onNewFrame(parcelable_frame, &fence);
+  if (!ret.isOk())
+    ALOGE("Failed to send new frame: %s", ret.toString8().string());
+
+  return fence.fence();
+}
+
+void VrComposer::binderDied(const wp<IBinder>& /* who */) {
+  std::lock_guard<std::mutex> guard(mutex_);
+
+  callback_ = nullptr;
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/hardware_composer/vr_composer.h b/services/vr/hardware_composer/vr_composer.h
new file mode 100644
index 0000000..93d1f2b
--- /dev/null
+++ b/services/vr/hardware_composer/vr_composer.h
@@ -0,0 +1,48 @@
+#ifndef ANDROID_DVR_HARDWARE_COMPOSER_VR_COMPOSER_H
+#define ANDROID_DVR_HARDWARE_COMPOSER_VR_COMPOSER_H
+
+#include <android/dvr/BnVrComposer.h>
+#include <impl/vr_hwc.h>
+
+namespace android {
+namespace dvr {
+
+class VrComposerCallback;
+
+// Implementation of the IVrComposer service used to notify VR Window Manager
+// when SurfaceFlinger presents 2D UI changes.
+//
+// VR HWC updates the presented frame via the ComposerView::Observer interface.
+// On notification |callback_| is called to update VR Window Manager.
+// NOTE: If VR Window Manager isn't connected, the notification is a no-op.
+class VrComposer
+    : public BnVrComposer,
+      public ComposerView::Observer,
+      public IBinder::DeathRecipient {
+ public:
+  VrComposer();
+  ~VrComposer() override;
+
+  // BnVrComposer:
+  binder::Status registerObserver(
+      const sp<IVrComposerCallback>& callback) override;
+
+  // ComposerView::Observer:
+  base::unique_fd OnNewFrame(const ComposerView::Frame& frame) override;
+
+ private:
+  // IBinder::DeathRecipient:
+  void binderDied(const wp<IBinder>& who) override;
+
+  std::mutex mutex_;
+
+  sp<IVrComposerCallback> callback_;
+
+  VrComposer(const VrComposer&) = delete;
+  void operator=(const VrComposer&) = delete;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  //  ANDROID_DVR_HARDWARE_COMPOSER_VR_COMPOSER_H
diff --git a/services/vr/hardware_composer/vr_hardware_composer_service.cpp b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
new file mode 100644
index 0000000..9591748
--- /dev/null
+++ b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <hwbinder/IPCThreadState.h>
+#include <impl/vr_hwc.h>
+#include <inttypes.h>
+
+#include "vr_composer.h"
+
+int main() {
+  android::ProcessState::self()->startThreadPool();
+
+  // Register the hwbinder HWC HAL service used by SurfaceFlinger while in VR
+  // mode.
+  const char instance[] = "vr_hwcomposer";
+  android::sp<IComposer> service =
+      android::dvr::HIDL_FETCH_IComposer(instance);
+
+  LOG_ALWAYS_FATAL_IF(!service.get(), "Failed to get service");
+  LOG_ALWAYS_FATAL_IF(service->isRemote(), "Service is remote");
+
+  LOG_ALWAYS_FATAL_IF(service->registerAsService(instance) != android::OK,
+                      "Failed to register service");
+
+  android::sp<android::dvr::VrComposer> composer =
+      new android::dvr::VrComposer();
+
+  android::dvr::ComposerView* composer_view =
+      android::dvr::GetComposerViewFromIComposer(service.get());
+  composer_view->RegisterObserver(composer.get());
+
+  android::sp<android::IServiceManager> sm(android::defaultServiceManager());
+
+  // Register the binder service used by VR Window Manager service to receive
+  // frame information from VR HWC HAL.
+  android::status_t status = sm->addService(
+      android::dvr::VrComposer::SERVICE_NAME(), composer.get(),
+      false /* allowIsolated */);
+  LOG_ALWAYS_FATAL_IF(status != android::OK,
+                      "VrDisplay service failed to start: %" PRId32, status);
+
+  android::hardware::ProcessState::self()->startThreadPool();
+  android::hardware::IPCThreadState::self()->joinThreadPool();
+
+  composer_view->UnregisterObserver(composer.get());
+
+  return 0;
+}
diff --git a/services/vr/hardware_composer/vr_hwc.rc b/services/vr/hardware_composer/vr_hwc.rc
new file mode 100644
index 0000000..5d3c4f7
--- /dev/null
+++ b/services/vr/hardware_composer/vr_hwc.rc
@@ -0,0 +1,6 @@
+service vr_hwc /system/bin/vr_hwc
+  class hal
+  user system
+  group system graphics
+  onrestart restart surfaceflinger
+  disabled
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
index 2e2f622..191bcfb 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
@@ -45,6 +45,8 @@
     // reported when the previous client performs any touchpad action.
     ALOGE("pid=%ld replaces %ld", static_cast<long>(pid),
           static_cast<long>(client_pid_));
+    client_pid_ = pid;
+    return binder::Status::ok();
   }
   client_pid_ = pid;
   if (const status_t error = touchpad_->Attach()) {
diff --git a/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl b/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl
index b5dbb8b..67fd927 100644
--- a/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl
+++ b/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl
@@ -24,5 +24,6 @@
     void enterVrMode() = 2;
     void exitVrMode() = 3;
     void setDebugMode(int mode) = 4;
+    void set2DMode(int mode) = 5;
 }
 
diff --git a/services/vr/vr_window_manager/application.cpp b/services/vr/vr_window_manager/application.cpp
index 3dfd9f1..c7d7d50 100644
--- a/services/vr/vr_window_manager/application.cpp
+++ b/services/vr/vr_window_manager/application.cpp
@@ -112,6 +112,7 @@
 void Application::DeallocateResources() {
   if (graphics_context_)
     dvrGraphicsContextDestroy(graphics_context_);
+  graphics_context_ = nullptr;
 
   if (pose_client_)
     dvrPoseDestroy(pose_client_);
@@ -274,15 +275,13 @@
     }
     controller_data_provider_->UnlockControllerData();
     if (shmem_controller_active_) {
-      // TODO(kpschoedel): change to ALOGV or remove.
-      ALOGI("Controller shmem orientation: %f %f %f %f",
+      ALOGV("Controller shmem orientation: %f %f %f %f",
             controller_orientation_.x(), controller_orientation_.y(),
             controller_orientation_.z(), controller_orientation_.w());
       if (shmem_controller_buttons_) {
-        ALOGI("Controller shmem buttons: %017" PRIX64,
+        ALOGV("Controller shmem buttons: %017" PRIX64,
             shmem_controller_buttons_);
       }
-      return;
     }
   }
 }
diff --git a/services/vr/vr_window_manager/composer/Android.bp b/services/vr/vr_window_manager/composer/Android.bp
index 4349269..f28818a 100644
--- a/services/vr/vr_window_manager/composer/Android.bp
+++ b/services/vr/vr_window_manager/composer/Android.bp
@@ -34,6 +34,14 @@
     "libutils",
   ],
 
+  export_static_lib_headers: [
+    "libhwcomposer-client",
+  ],
+
+  export_shared_lib_headers: [
+    "android.hardware.graphics.composer@2.1",
+  ],
+
   export_include_dirs: ["."],
 
   cflags: [
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
index 684d15b..8aa2fd5 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
@@ -314,12 +314,35 @@
     return Error::BAD_CONFIG;
   }
 
+  int error = 0;
+  auto display_client = DisplayClient::Create(&error);
+  SystemDisplayMetrics metrics;
+
+  if (error) {
+    ALOGE("Could not connect to display service : %s(%d)", strerror(error),
+          error);
+  } else {
+    error = display_client->GetDisplayMetrics(&metrics);
+
+    if (error) {
+      ALOGE("Could not get display metrics from display service : %s(%d)",
+            strerror(error), error);
+    }
+  }
+
+  if (error) {
+    metrics.display_native_width = 1080;
+    metrics.display_native_height = 1920;
+    ALOGI("Setting display metrics to default : width=%d height=%d",
+          metrics.display_native_width, metrics.display_native_height);
+  }
+
   switch (attribute) {
     case IComposerClient::Attribute::WIDTH:
-      *outValue = 1080;
+      *outValue = metrics.display_native_width;
       break;
     case IComposerClient::Attribute::HEIGHT:
-      *outValue = 1920;
+      *outValue = metrics.display_native_height;
       break;
     case IComposerClient::Attribute::VSYNC_PERIOD:
       *outValue = 1000 * 1000 * 1000 / 30;  // 30fps
diff --git a/services/vr/vr_window_manager/display_view.cpp b/services/vr/vr_window_manager/display_view.cpp
index 5f1e73e..e88e7d0 100644
--- a/services/vr/vr_window_manager/display_view.cpp
+++ b/services/vr/vr_window_manager/display_view.cpp
@@ -8,8 +8,8 @@
 namespace {
 
 constexpr float kLayerScaleFactor = 3.0f;
-constexpr unsigned int kVRAppLayerCount = 2;
 constexpr unsigned int kMaximumPendingFrames = 8;
+constexpr uint32_t kSystemId = 1000;
 
 // clang-format off
 const GLfloat kVertices[] = {
@@ -99,12 +99,9 @@
 
 // Determine if ths frame should be shown or hidden.
 ViewMode CalculateVisibilityFromLayerConfig(const HwcCallback::Frame& frame,
-                                            uint32_t vr_app) {
+                                            uint32_t* appid) {
   auto& layers = frame.layers();
 
-  // TODO(achaulk): Figure out how to identify the current VR app for 2D app
-  // detection.
-
   size_t index;
   // Skip all layers that we don't know about.
   for (index = 0; index < layers.size(); index++) {
@@ -120,6 +117,11 @@
     return ViewMode::Hidden;
   }
 
+  if (layers[index].appid != *appid) {
+    *appid = layers[index].appid;
+    return ViewMode::App;
+  }
+
   // This is the VR app, ignore it.
   index++;
 
@@ -136,6 +138,7 @@
     if (!layers[i].should_skip_layer())
       return ViewMode::VR;
   }
+
   return ViewMode::Hidden;
 }
 
@@ -197,17 +200,27 @@
 }
 
 base::unique_fd DisplayView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame,
-                                     bool debug_mode, bool* showing) {
-  ViewMode visibility =
-      CalculateVisibilityFromLayerConfig(*frame.get(), current_vr_app_);
+                                     bool debug_mode, bool is_vr_active,
+                                     bool* showing) {
+  uint32_t app = current_vr_app_;
+  ViewMode visibility = CalculateVisibilityFromLayerConfig(*frame.get(), &app);
 
   if (visibility == ViewMode::Hidden && debug_mode)
     visibility = ViewMode::VR;
 
-  if (frame->layers().empty())
+  if (frame->layers().empty()) {
     current_vr_app_ = 0;
-  else
-    current_vr_app_ = frame->layers().front().appid;
+  } else if (visibility == ViewMode::App) {
+    // This is either a VR app switch or a 2D app launching.
+    // If we can have VR apps, update if it's 0.
+    if (!always_2d_ && is_vr_active && !use_2dmode_ && app != kSystemId) {
+      visibility = ViewMode::Hidden;
+      current_vr_app_ = app;
+    }
+  } else if (!current_vr_app_) {
+    // The VR app is running.
+    current_vr_app_ = app;
+  }
 
   pending_frames_.emplace_back(std::move(frame), visibility);
 
diff --git a/services/vr/vr_window_manager/display_view.h b/services/vr/vr_window_manager/display_view.h
index 0a27781..0d1355e 100644
--- a/services/vr/vr_window_manager/display_view.h
+++ b/services/vr/vr_window_manager/display_view.h
@@ -23,7 +23,7 @@
 
   // Calls to these 3 functions must be synchronized.
   base::unique_fd OnFrame(std::unique_ptr<HwcCallback::Frame> frame,
-                          bool debug_mode, bool* showing);
+                          bool debug_mode, bool is_vr_active, bool* showing);
   void AdvanceFrame();
   void UpdateReleaseFence();
 
@@ -44,6 +44,9 @@
   uint32_t id() const { return id_; }
   int touchpad_id() const { return touchpad_id_; }
 
+  void set_2dmode(bool mode) { use_2dmode_ = mode; }
+  void set_always_2d(bool mode) { always_2d_ = mode; }
+
  private:
   bool IsHit(const vec3& view_location, const vec3& view_direction,
              vec3* hit_location, vec2* hit_location_in_window_coord,
@@ -79,6 +82,8 @@
   vec2 ime_top_left_;
   vec2 ime_size_;
   bool has_ime_ = false;
+  bool use_2dmode_ = false;
+  bool always_2d_ = false;
 
   struct PendingFrame {
     PendingFrame() = default;
diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp
index a21e883..67ef5d4 100644
--- a/services/vr/vr_window_manager/shell_view.cpp
+++ b/services/vr/vr_window_manager/shell_view.cpp
@@ -4,6 +4,7 @@
 #include <GLES3/gl3.h>
 #include <android/input.h>
 #include <binder/IServiceManager.h>
+#include <dvr/graphics.h>
 #include <hardware/hwcomposer2.h>
 #include <inttypes.h>
 #include <log/log.h>
@@ -16,6 +17,8 @@
 
 namespace {
 
+constexpr uint32_t kPrimaryDisplayId = 1;
+
 const std::string kVertexShader = SHADER0([]() {
   layout(location = 0) in vec4 aPosition;
   layout(location = 1) in vec4 aTexCoord;
@@ -96,8 +99,8 @@
 }
 
 int GetTouchIdForDisplay(uint32_t display) {
-  return display == 1 ? DVR_VIRTUAL_TOUCHPAD_PRIMARY
-                      : DVR_VIRTUAL_TOUCHPAD_VIRTUAL;
+  return display == kPrimaryDisplayId ? DVR_VIRTUAL_TOUCHPAD_PRIMARY
+                                      : DVR_VIRTUAL_TOUCHPAD_VIRTUAL;
 }
 
 }  // namespace
@@ -123,6 +126,10 @@
   if (!surface_flinger_view_->Initialize(this))
     return 1;
 
+  // This is a temporary fix for now. These APIs will be changed when everything
+  // is moved into vrcore.
+  display_client_ = DisplayClient::Create();
+
   return 0;
 }
 
@@ -190,6 +197,11 @@
   result.append("\n");
 }
 
+void ShellView::Set2DMode(bool mode) {
+  if (!displays_.empty())
+    displays_[0]->set_2dmode(mode);
+}
+
 void ShellView::OnDrawFrame() {
   bool visible = false;
 
@@ -253,6 +265,9 @@
   }
 
   auto display = new DisplayView(id, GetTouchIdForDisplay(id));
+  // Virtual displays only ever have 2D apps so force it.
+  if (id != kPrimaryDisplayId)
+    display->set_always_2d(true);
   new_displays_.emplace_back(display);
   return display;
 }
@@ -268,7 +283,11 @@
 
   bool showing = false;
 
-  base::unique_fd fd(display->OnFrame(std::move(frame), debug_mode_, &showing));
+  // TODO(achaulk): change when moved into vrcore.
+  bool vr_running = display_client_->IsVrAppRunning();
+
+  base::unique_fd fd(
+      display->OnFrame(std::move(frame), debug_mode_, vr_running, &showing));
 
   if (showing)
     QueueTask(MainThreadTask::Show);
diff --git a/services/vr/vr_window_manager/shell_view.h b/services/vr/vr_window_manager/shell_view.h
index 856c8b8..d265866 100644
--- a/services/vr/vr_window_manager/shell_view.h
+++ b/services/vr/vr_window_manager/shell_view.h
@@ -2,6 +2,7 @@
 #define VR_WINDOW_MANAGER_SHELL_VIEW_H_
 
 #include <dvr/virtual_touchpad_client.h>
+#include <private/dvr/display_client.h>
 #include <private/dvr/graphics/mesh.h>
 #include <private/dvr/graphics/shader_program.h>
 
@@ -32,6 +33,8 @@
   void EnableDebug(bool debug) override;
   void VrMode(bool mode) override;
   void dumpInternal(String8& result) override;
+  void Set2DMode(bool mode) override;
+
 
  protected:
   void DrawEye(EyeType eye, const mat4& perspective, const mat4& eye_matrix,
@@ -64,6 +67,8 @@
   std::unique_ptr<SurfaceFlingerView> surface_flinger_view_;
   std::unique_ptr<Reticle> reticle_;
 
+  std::unique_ptr<DisplayClient> display_client_;
+
   struct DvrVirtualTouchpadDeleter {
     void operator()(DvrVirtualTouchpad* p) {
       dvrVirtualTouchpadDetach(p);
diff --git a/services/vr/vr_window_manager/shell_view_binder_interface.h b/services/vr/vr_window_manager/shell_view_binder_interface.h
index b58e4bd..9f77e5a 100644
--- a/services/vr/vr_window_manager/shell_view_binder_interface.h
+++ b/services/vr/vr_window_manager/shell_view_binder_interface.h
@@ -12,6 +12,7 @@
   virtual void EnableDebug(bool debug) = 0;
   virtual void VrMode(bool mode) = 0;
   virtual void dumpInternal(String8& result) = 0;
+  virtual void Set2DMode(bool mode) = 0;
 };
 
 }  // namespace dvr
diff --git a/services/vr/vr_window_manager/surface_flinger_view.cpp b/services/vr/vr_window_manager/surface_flinger_view.cpp
index 8411806..46eb880 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.cpp
+++ b/services/vr/vr_window_manager/surface_flinger_view.cpp
@@ -39,9 +39,29 @@
   vr_composer_view_->Initialize(GetComposerViewFromIComposer(
       vr_hwcomposer_.get()));
 
+  int error = 0;
+  auto display_client = DisplayClient::Create(&error);
+  SystemDisplayMetrics metrics;
+
+  if (error) {
+    ALOGE("Could not connect to display service : %s(%d)", strerror(error), error);
+  } else {
+    error = display_client->GetDisplayMetrics(&metrics);
+
+    if (error) {
+      ALOGE("Could not get display metrics from display service : %s(%d)", strerror(error), error);
+    }
+  }
+
+  if (error) {
+    metrics.display_native_height = 1920;
+    metrics.display_native_width = 1080;
+    ALOGI("Setting display metrics to default : width=%d height=%d", metrics.display_native_height, metrics.display_native_width);
+  }
+
   // TODO(alexst): Refactor ShellView to account for orientation and change this back.
-  width_ = 1920;
-  height_ = 1080;
+  width_ = metrics.display_native_height;
+  height_ = metrics.display_native_width;
   return true;
 }
 
diff --git a/services/vr/vr_window_manager/vr_window_manager_binder.cpp b/services/vr/vr_window_manager/vr_window_manager_binder.cpp
index bd3f3ee..8868588 100644
--- a/services/vr/vr_window_manager/vr_window_manager_binder.cpp
+++ b/services/vr/vr_window_manager/vr_window_manager_binder.cpp
@@ -133,6 +133,11 @@
   return binder::Status::ok();
 }
 
+binder::Status VrWindowManagerBinder::set2DMode(int32_t mode) {
+  app_.Set2DMode(static_cast<bool>(mode));
+  return binder::Status::ok();
+}
+
 status_t VrWindowManagerBinder::dump(
     int fd, const Vector<String16>& args [[gnu::unused]]) {
   String8 result;
diff --git a/services/vr/vr_window_manager/vr_window_manager_binder.h b/services/vr/vr_window_manager/vr_window_manager_binder.h
index 99ca27a..1915ffc 100644
--- a/services/vr/vr_window_manager/vr_window_manager_binder.h
+++ b/services/vr/vr_window_manager/vr_window_manager_binder.h
@@ -59,6 +59,7 @@
   ::android::binder::Status enterVrMode() override;
   ::android::binder::Status exitVrMode() override;
   ::android::binder::Status setDebugMode(int32_t mode) override;
+  ::android::binder::Status set2DMode(int32_t mode) override;
 
   // Implements BBinder::dump().
   status_t dump(int fd, const Vector<String16>& args) override;
diff --git a/services/vr/vr_window_manager/vr_wm_ctl.cpp b/services/vr/vr_window_manager/vr_wm_ctl.cpp
index c67b2eb..2e5c488 100644
--- a/services/vr/vr_window_manager/vr_wm_ctl.cpp
+++ b/services/vr/vr_window_manager/vr_wm_ctl.cpp
@@ -39,6 +39,8 @@
     exit(report(vrwm->exitVrMode()));
   } else if ((argc == 3) && (strcmp(argv[1], "debug") == 0)) {
     exit(report(vrwm->setDebugMode(atoi(argv[2]))));
+  } else if ((argc == 3) && (strcmp(argv[1], "2d") == 0)) {
+    exit(report(vrwm->set2DMode(atoi(argv[2]))));
   } else {
     usage();
     exit(2);