Merge "Dumpstate: dump HAL native traces processes."
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 4812de5..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();
 
@@ -1437,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();
     }
@@ -1799,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/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/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/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/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/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/libpdx/private/pdx/rpc/remote_method.h b/libs/vr/libpdx/private/pdx/rpc/remote_method.h
index e5c6616..3eca9e5 100644
--- a/libs/vr/libpdx/private/pdx/rpc/remote_method.h
+++ b/libs/vr/libpdx/private/pdx/rpc/remote_method.h
@@ -213,117 +213,6 @@
 }
 
 // Dispatches a method by deserializing arguments from the given Message, with
-// compile-time interface check. Overload for int return types.
-template <typename RemoteMethodType, typename Class, typename... Args,
-          typename = EnableIfNotVoidMethod<RemoteMethodType>>
-void DispatchRemoteMethod(Class& instance,
-                          int (Class::*method)(Message&, Args...),
-                          Message& message,
-                          std::size_t max_capacity = InitialBufferCapacity) {
-  using Signature = typename RemoteMethodType::template RewriteArgs<Args...>;
-  rpc::ServicePayload<ReceiveBuffer> payload(message);
-  payload.Resize(max_capacity);
-
-  auto size = message.Read(payload.Data(), payload.Size());
-  if (size < 0) {
-    RemoteMethodError(message, -size);
-    return;
-  }
-
-  payload.Resize(size);
-
-  ErrorType error;
-  auto decoder = MakeArgumentDecoder<Signature>(&payload);
-  auto arguments = decoder.DecodeArguments(&error);
-  if (error) {
-    RemoteMethodError(message, EIO);
-    return;
-  }
-
-  auto return_value =
-      UnpackArguments<Class, Signature>(instance, method, message, arguments)
-          .Invoke();
-  // Return the value to the caller unless the message was moved.
-  if (message)
-    RemoteMethodReturn<RemoteMethodType>(message, return_value);
-}
-
-// Dispatches a method by deserializing arguments from the given Message, with
-// compile-time interface check. Overload for FileHandle return types.
-template <typename RemoteMethodType, FileHandleMode Mode, typename Class,
-          typename... Args, typename = EnableIfNotVoidMethod<RemoteMethodType>>
-void DispatchRemoteMethod(Class& instance,
-                          FileHandle<Mode> (Class::*method)(Message&, Args...),
-                          Message& message,
-                          std::size_t max_capacity = InitialBufferCapacity) {
-  using Signature =
-      typename RemoteMethodType::template RewriteSignature<FileHandle<Mode>,
-                                                           Args...>;
-  rpc::ServicePayload<ReceiveBuffer> payload(message);
-  payload.Resize(max_capacity);
-
-  auto size = message.Read(payload.Data(), payload.Size());
-  if (size < 0) {
-    RemoteMethodError(message, -size);
-    return;
-  }
-
-  payload.Resize(size);
-
-  ErrorType error;
-  auto decoder = MakeArgumentDecoder<Signature>(&payload);
-  auto arguments = decoder.DecodeArguments(&error);
-  if (error) {
-    RemoteMethodError(message, EIO);
-    return;
-  }
-
-  auto return_value =
-      UnpackArguments<Class, Signature>(instance, method, message, arguments)
-          .Invoke();
-  // Return the value to the caller unless the message was moved.
-  if (message)
-    RemoteMethodReturn<RemoteMethodType>(message, return_value);
-}
-
-// Dispatches a method by deserializing arguments from the given Message, with
-// compile-time interface check. Overload for ChannelHandle return types.
-template <typename RemoteMethodType, ChannelHandleMode Mode, typename Class,
-          typename... Args, typename = EnableIfNotVoidMethod<RemoteMethodType>>
-void DispatchRemoteMethod(
-    Class& instance, ChannelHandle<Mode> (Class::*method)(Message&, Args...),
-    Message& message, std::size_t max_capacity = InitialBufferCapacity) {
-  using Signature =
-      typename RemoteMethodType::template RewriteSignature<ChannelHandle<Mode>,
-                                                           Args...>;
-  rpc::ServicePayload<ReceiveBuffer> payload(message);
-  payload.Resize(max_capacity);
-
-  auto size = message.Read(payload.Data(), payload.Size());
-  if (size < 0) {
-    RemoteMethodError(message, -size);
-    return;
-  }
-
-  payload.Resize(size);
-
-  ErrorType error;
-  auto decoder = MakeArgumentDecoder<Signature>(&payload);
-  auto arguments = decoder.DecodeArguments(&error);
-  if (error) {
-    RemoteMethodError(message, EIO);
-    return;
-  }
-
-  auto return_value =
-      UnpackArguments<Class, Signature>(instance, method, message, arguments)
-          .Invoke();
-  // Return the value to the caller unless the message was moved.
-  if (message)
-    RemoteMethodReturn<RemoteMethodType>(message, return_value);
-}
-
-// Dispatches a method by deserializing arguments from the given Message, with
 // compile-time interface signature check. Overload for generic return types.
 template <typename RemoteMethodType, typename Class, typename Return,
           typename... Args, typename = EnableIfNotVoidMethod<RemoteMethodType>>
@@ -414,41 +303,6 @@
     RemoteMethodReturn<RemoteMethodType>(message, 0);
 }
 
-// Overload for int return type.
-template <typename RemoteMethodType, typename Class,
-          typename = EnableIfVoidMethod<RemoteMethodType>>
-void DispatchRemoteMethod(Class& instance, int (Class::*method)(Message&),
-                          Message& message) {
-  const int return_value = (instance.*method)(message);
-  // Return the value to the caller unless the message was moved.
-  if (message)
-    RemoteMethodReturn<RemoteMethodType>(message, return_value);
-}
-
-// Overload for FileHandle return type.
-template <typename RemoteMethodType, typename Class, FileHandleMode Mode,
-          typename = EnableIfVoidMethod<RemoteMethodType>>
-void DispatchRemoteMethod(Class& instance,
-                          FileHandle<Mode> (Class::*method)(Message&),
-                          Message& message) {
-  FileHandle<Mode> return_value = (instance.*method)(message);
-  // Return the value to the caller unless the message was moved.
-  if (message)
-    RemoteMethodReturn<RemoteMethodType>(message, return_value);
-}
-
-// Overload for ChannelHandle return types.
-template <typename RemoteMethodType, typename Class, ChannelHandleMode Mode,
-          typename = EnableIfVoidMethod<RemoteMethodType>>
-void DispatchRemoteMethod(Class& instance,
-                          ChannelHandle<Mode> (Class::*method)(Message&),
-                          Message& message) {
-  ChannelHandle<Mode> return_value = (instance.*method)(message);
-  // Return the value to the caller unless the message was moved.
-  if (message)
-    RemoteMethodReturn<RemoteMethodType>(message, return_value);
-}
-
 // Overload for generic return type.
 template <typename RemoteMethodType, typename Class, typename Return,
           typename = EnableIfVoidMethod<RemoteMethodType>>
diff --git a/libs/vr/libpdx/service.cpp b/libs/vr/libpdx/service.cpp
index daf9af8..d2804d5 100644
--- a/libs/vr/libpdx/service.cpp
+++ b/libs/vr/libpdx/service.cpp
@@ -129,7 +129,7 @@
   PDX_TRACE_NAME("Message::PushFileHandle");
   if (auto svc = service_.lock()) {
     ErrnoGuard errno_guard;
-    return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle));
+    return svc->endpoint()->PushFileHandle(this, handle);
   } else {
     return -ESHUTDOWN;
   }
@@ -139,7 +139,7 @@
   PDX_TRACE_NAME("Message::PushFileHandle");
   if (auto svc = service_.lock()) {
     ErrnoGuard errno_guard;
-    return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle));
+    return svc->endpoint()->PushFileHandle(this, handle);
   } else {
     return -ESHUTDOWN;
   }
@@ -149,7 +149,7 @@
   PDX_TRACE_NAME("Message::PushFileHandle");
   if (auto svc = service_.lock()) {
     ErrnoGuard errno_guard;
-    return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle));
+    return svc->endpoint()->PushFileHandle(this, handle);
   } else {
     return -ESHUTDOWN;
   }
@@ -159,7 +159,7 @@
   PDX_TRACE_NAME("Message::PushChannelHandle");
   if (auto svc = service_.lock()) {
     ErrnoGuard errno_guard;
-    return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle));
+    return svc->endpoint()->PushChannelHandle(this, handle);
   } else {
     return -ESHUTDOWN;
   }
@@ -170,7 +170,7 @@
   PDX_TRACE_NAME("Message::PushChannelHandle");
   if (auto svc = service_.lock()) {
     ErrnoGuard errno_guard;
-    return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle));
+    return svc->endpoint()->PushChannelHandle(this, handle);
   } else {
     return -ESHUTDOWN;
   }
@@ -180,7 +180,7 @@
   PDX_TRACE_NAME("Message::PushChannelHandle");
   if (auto svc = service_.lock()) {
     ErrnoGuard errno_guard;
-    return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle));
+    return svc->endpoint()->PushChannelHandle(this, handle);
   } else {
     return -ESHUTDOWN;
   }
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/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/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 a63b9b4..f82b363 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2766,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) {
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index cd02b13..c26847f 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -2564,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) {
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
index 629d65b..1601c7f 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -75,6 +75,31 @@
   ],
 }
 
+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,
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/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/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;
 }