Merge "Add GLES specific setting for layers"
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index d950b7c..d6ca0bf 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -91,7 +91,12 @@
     chmod 0666 /sys/kernel/tracing/events/sync/enable
     chmod 0666 /sys/kernel/debug/tracing/events/fence/enable
     chmod 0666 /sys/kernel/tracing/events/fence/enable
-
+    chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/enable
+    chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_heap_grow/enable
+    chmod 0666 /sys/kernel/tracing/events/kmem/ion_heap_grow/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_heap_shrink/enable
+    chmod 0666 /sys/kernel/tracing/events/kmem/ion_heap_shrink/enable
 
     # disk
     chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 9d0d8ba..2e9701f 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -14,6 +14,7 @@
         "CacheItem.cpp",
         "CacheTracker.cpp",
         "InstalldNativeService.cpp",
+        "QuotaUtils.cpp",
         "dexopt.cpp",
         "globals.cpp",
         "utils.cpp",
@@ -33,6 +34,21 @@
         "libutils",
     ],
 
+    product_variables: {
+        arc: {
+            exclude_srcs: [
+                "QuotaUtils.cpp",
+            ],
+            static_libs: [
+                "libarcdiskquota",
+                "arc_services_aidl",
+            ],
+            cflags: [
+                "-DUSE_ARC",
+            ],
+        },
+    },
+
     clang: true,
 
     tidy: true,
@@ -59,6 +75,26 @@
     aidl: {
         export_aidl_headers: true,
     },
+
+    product_variables: {
+        arc: {
+            exclude_srcs: [
+                "QuotaUtils.cpp",
+            ],
+            static_libs: [
+                "libarcdiskquota",
+                "arc_services_aidl",
+            ],
+            cflags: [
+                "-DUSE_ARC",
+            ],
+        },
+    },
+}
+
+cc_library_headers {
+    name: "libinstalld_headers",
+    export_include_dirs: ["."],
 }
 
 //
@@ -73,6 +109,21 @@
     static_libs: ["libdiskusage"],
 
     init_rc: ["installd.rc"],
+
+    product_variables: {
+        arc: {
+            exclude_srcs: [
+                "QuotaUtils.cpp",
+            ],
+            static_libs: [
+                "libarcdiskquota",
+                "arc_services_aidl",
+            ],
+            cflags: [
+                "-DUSE_ARC",
+            ],
+        },
+    },
 }
 
 // OTA chroot tool
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
index a7242c3..8b868fb 100644
--- a/cmds/installd/CacheTracker.cpp
+++ b/cmds/installd/CacheTracker.cpp
@@ -19,13 +19,13 @@
 #include "CacheTracker.h"
 
 #include <fts.h>
-#include <sys/quota.h>
 #include <sys/xattr.h>
 #include <utils/Trace.h>
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 
+#include "QuotaUtils.h"
 #include "utils.h"
 
 using android::base::StringPrintf;
@@ -33,9 +33,13 @@
 namespace android {
 namespace installd {
 
-CacheTracker::CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice) :
-        cacheUsed(0), cacheQuota(0), mUserId(userId), mAppId(appId), mQuotaDevice(quotaDevice),
-        mItemsLoaded(false) {
+CacheTracker::CacheTracker(userid_t userId, appid_t appId, const std::string& uuid)
+      : cacheUsed(0),
+        cacheQuota(0),
+        mUserId(userId),
+        mAppId(appId),
+        mItemsLoaded(false),
+        mUuid(uuid) {
 }
 
 CacheTracker::~CacheTracker() {
@@ -72,26 +76,18 @@
 bool CacheTracker::loadQuotaStats() {
     int cacheGid = multiuser_get_cache_gid(mUserId, mAppId);
     int extCacheGid = multiuser_get_ext_cache_gid(mUserId, mAppId);
-    if (!mQuotaDevice.empty() && cacheGid != -1 && extCacheGid != -1) {
-        struct dqblk dq;
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), cacheGid,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            if (errno != ESRCH) {
-                PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid;
-            }
-            return false;
+    if (IsQuotaSupported(mUuid) && cacheGid != -1 && extCacheGid != -1) {
+        int64_t space;
+        if ((space = GetOccupiedSpaceForGid(mUuid, cacheGid)) != -1) {
+            cacheUsed += space;
         } else {
-            cacheUsed += dq.dqb_curspace;
+            return false;
         }
 
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), extCacheGid,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            if (errno != ESRCH) {
-                PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid;
-            }
-            return false;
+        if ((space = GetOccupiedSpaceForGid(mUuid, extCacheGid)) != -1) {
+            cacheUsed += space;
         } else {
-            cacheUsed += dq.dqb_curspace;
+            return false;
         }
         return true;
     } else {
diff --git a/cmds/installd/CacheTracker.h b/cmds/installd/CacheTracker.h
index 44359b4..b0527e7 100644
--- a/cmds/installd/CacheTracker.h
+++ b/cmds/installd/CacheTracker.h
@@ -39,7 +39,7 @@
  */
 class CacheTracker {
 public:
-    CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice);
+    CacheTracker(userid_t userId, appid_t appId, const std::string& uuid);
     ~CacheTracker();
 
     std::string toString();
@@ -61,8 +61,8 @@
 private:
     userid_t mUserId;
     appid_t mAppId;
-    std::string mQuotaDevice;
     bool mItemsLoaded;
+    const std::string& mUuid;
 
     std::vector<std::string> mDataPaths;
 
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index a475fcc..81055d8 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -31,7 +31,6 @@
 #include <sys/file.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
-#include <sys/quota.h>
 #include <sys/resource.h>
 #include <sys/stat.h>
 #include <sys/statvfs.h>
@@ -64,6 +63,7 @@
 
 #include "CacheTracker.h"
 #include "MatchExtensionGen.h"
+#include "QuotaUtils.h"
 
 #ifndef LOG_TAG
 #define LOG_TAG "installd"
@@ -257,11 +257,6 @@
         for (const auto& n : mStorageMounts) {
             out << "    " << n.first << " = " << n.second << endl;
         }
-
-        out << endl << "Quota reverse mounts:" << endl;
-        for (const auto& n : mQuotaReverseMounts) {
-            out << "    " << n.first << " = " << n.second << endl;
-        }
     }
 
     {
@@ -988,9 +983,9 @@
     CHECK_ARGUMENT_UUID(uuid);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
+    auto uuidString = uuid ? *uuid : "";
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     auto data_path = create_data_path(uuid_);
-    auto device = findQuotaDeviceForUuid(uuid);
     auto noop = (flags & FLAG_FREE_CACHE_NOOP);
 
     int64_t free = data_disk_free(data_path);
@@ -1037,7 +1032,7 @@
                         search->second->addDataPath(p->fts_path);
                     } else {
                         auto tracker = std::shared_ptr<CacheTracker>(new CacheTracker(
-                                multiuser_get_user_id(uid), multiuser_get_app_id(uid), device));
+                                multiuser_get_user_id(uid), multiuser_get_app_id(uid), uuidString));
                         tracker->addDataPath(p->fts_path);
                         {
                             std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
@@ -1202,53 +1197,26 @@
 }
 #endif
 
-static void collectQuotaStats(const std::string& device, int32_t userId,
+static void collectQuotaStats(const std::string& uuid, int32_t userId,
         int32_t appId, struct stats* stats, struct stats* extStats) {
-    if (device.empty()) return;
-
-    struct dqblk dq;
-
+    int64_t space;
     if (stats != nullptr) {
         uid_t uid = multiuser_get_uid(userId, appId);
-        if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            if (errno != ESRCH) {
-                PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
-            }
-        } else {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
-#endif
-            stats->dataSize += dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) {
+            stats->dataSize += space;
         }
 
         int cacheGid = multiuser_get_cache_gid(userId, appId);
         if (cacheGid != -1) {
-            if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), cacheGid,
-                    reinterpret_cast<char*>(&dq)) != 0) {
-                if (errno != ESRCH) {
-                    PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << cacheGid;
-                }
-            } else {
-#if MEASURE_DEBUG
-                LOG(DEBUG) << "quotactl() for GID " << cacheGid << " " << dq.dqb_curspace;
-#endif
-                stats->cacheSize += dq.dqb_curspace;
+            if ((space = GetOccupiedSpaceForGid(uuid, cacheGid)) != -1) {
+                stats->cacheSize += space;
             }
         }
 
         int sharedGid = multiuser_get_shared_gid(0, appId);
         if (sharedGid != -1) {
-            if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), sharedGid,
-                    reinterpret_cast<char*>(&dq)) != 0) {
-                if (errno != ESRCH) {
-                    PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << sharedGid;
-                }
-            } else {
-#if MEASURE_DEBUG
-                LOG(DEBUG) << "quotactl() for GID " << sharedGid << " " << dq.dqb_curspace;
-#endif
-                stats->codeSize += dq.dqb_curspace;
+            if ((space = GetOccupiedSpaceForGid(uuid, sharedGid)) != -1) {
+                stats->codeSize += space;
             }
         }
     }
@@ -1256,32 +1224,16 @@
     if (extStats != nullptr) {
         int extGid = multiuser_get_ext_gid(userId, appId);
         if (extGid != -1) {
-            if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extGid,
-                    reinterpret_cast<char*>(&dq)) != 0) {
-                if (errno != ESRCH) {
-                    PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extGid;
-                }
-            } else {
-#if MEASURE_DEBUG
-                LOG(DEBUG) << "quotactl() for GID " << extGid << " " << dq.dqb_curspace;
-#endif
-                extStats->dataSize += dq.dqb_curspace;
+            if ((space = GetOccupiedSpaceForGid(uuid, extGid)) != -1) {
+                extStats->dataSize += space;
             }
         }
 
         int extCacheGid = multiuser_get_ext_cache_gid(userId, appId);
         if (extCacheGid != -1) {
-            if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extCacheGid,
-                    reinterpret_cast<char*>(&dq)) != 0) {
-                if (errno != ESRCH) {
-                    PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extCacheGid;
-                }
-            } else {
-#if MEASURE_DEBUG
-                LOG(DEBUG) << "quotactl() for GID " << extCacheGid << " " << dq.dqb_curspace;
-#endif
-                extStats->dataSize += dq.dqb_curspace;
-                extStats->cacheSize += dq.dqb_curspace;
+            if ((space = GetOccupiedSpaceForGid(uuid, extCacheGid)) != -1) {
+                extStats->dataSize += space;
+                extStats->cacheSize += space;
             }
         }
     }
@@ -1445,10 +1397,10 @@
     memset(&stats, 0, sizeof(stats));
     memset(&extStats, 0, sizeof(extStats));
 
+    auto uuidString = uuid ? *uuid : "";
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
-    auto device = findQuotaDeviceForUuid(uuid);
-    if (device.empty()) {
+    if (!IsQuotaSupported(uuidString)) {
         flags &= ~FLAG_USE_QUOTA;
     }
 
@@ -1468,7 +1420,7 @@
         ATRACE_END();
 
         ATRACE_BEGIN("quota");
-        collectQuotaStats(device, userId, appId, &stats, &extStats);
+        collectQuotaStats(uuidString, userId, appId, &stats, &extStats);
         ATRACE_END();
     } else {
         ATRACE_BEGIN("code");
@@ -1553,27 +1505,19 @@
     memset(&stats, 0, sizeof(stats));
     memset(&extStats, 0, sizeof(extStats));
 
+    auto uuidString = uuid ? *uuid : "";
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
-    auto device = findQuotaDeviceForUuid(uuid);
-    if (device.empty()) {
+    if (!IsQuotaSupported(uuidString)) {
         flags &= ~FLAG_USE_QUOTA;
     }
 
     if (flags & FLAG_USE_QUOTA) {
-        struct dqblk dq;
+        int64_t space;
 
         ATRACE_BEGIN("obb");
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            if (errno != ESRCH) {
-                PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << AID_MEDIA_OBB;
-            }
-        } else {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace;
-#endif
-            extStats.codeSize += dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForGid(uuidString, AID_MEDIA_OBB)) != -1) {
+            extStats.codeSize += space;
         }
         ATRACE_END();
 
@@ -1599,16 +1543,8 @@
 
         ATRACE_BEGIN("external");
         uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
-        if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            if (errno != ESRCH) {
-                PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
-            }
-        } else {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
-#endif
-            extStats.dataSize += dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForUid(uuidString, uid)) != -1) {
+            extStats.dataSize += space;
         }
         ATRACE_END();
 
@@ -1625,7 +1561,7 @@
         int64_t dataSize = extStats.dataSize;
         for (auto appId : appIds) {
             if (appId >= AID_APP_START) {
-                collectQuotaStats(device, userId, appId, &stats, &extStats);
+                collectQuotaStats(uuidString, userId, appId, &stats, &extStats);
 
 #if MEASURE_DEBUG
                 // Sleep to make sure we don't lose logs
@@ -1707,6 +1643,7 @@
     LOG(INFO) << "Measuring external " << userId;
 #endif
 
+    auto uuidString = uuid ? *uuid : "";
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
     int64_t totalSize = 0;
@@ -1716,58 +1653,33 @@
     int64_t appSize = 0;
     int64_t obbSize = 0;
 
-    auto device = findQuotaDeviceForUuid(uuid);
-    if (device.empty()) {
+    if (!IsQuotaSupported(uuidString)) {
         flags &= ~FLAG_USE_QUOTA;
     }
 
     if (flags & FLAG_USE_QUOTA) {
-        struct dqblk dq;
+        int64_t space;
 
         ATRACE_BEGIN("quota");
         uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
-        if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            if (errno != ESRCH) {
-                PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
-            }
-        } else {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
-#endif
-            totalSize = dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForUid(uuidString, uid)) != -1) {
+            totalSize = space;
         }
 
         gid_t audioGid = multiuser_get_uid(userId, AID_MEDIA_AUDIO);
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), audioGid,
-                reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for GID " << audioGid << " " << dq.dqb_curspace;
-#endif
-            audioSize = dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForGid(uuidString, audioGid)) != -1) {
+            audioSize = space;
         }
         gid_t videoGid = multiuser_get_uid(userId, AID_MEDIA_VIDEO);
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), videoGid,
-                reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for GID " << videoGid << " " << dq.dqb_curspace;
-#endif
-            videoSize = dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForGid(uuidString, videoGid)) != -1) {
+            videoSize = space;
         }
         gid_t imageGid = multiuser_get_uid(userId, AID_MEDIA_IMAGE);
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), imageGid,
-                reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for GID " << imageGid << " " << dq.dqb_curspace;
-#endif
-            imageSize = dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForGid(uuidString, imageGid)) != -1) {
+            imageSize = space;
         }
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB,
-                reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace;
-#endif
-            obbSize = dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForGid(uuidString, AID_MEDIA_OBB)) != -1) {
+            obbSize = space;
         }
         ATRACE_END();
 
@@ -1776,7 +1688,7 @@
         memset(&extStats, 0, sizeof(extStats));
         for (auto appId : appIds) {
             if (appId >= AID_APP_START) {
-                collectQuotaStats(device, userId, appId, nullptr, &extStats);
+                collectQuotaStats(uuidString, userId, appId, nullptr, &extStats);
             }
         }
         appSize = extStats.dataSize;
@@ -2564,7 +2476,12 @@
     std::lock_guard<std::recursive_mutex> lock(mMountsLock);
 
     mStorageMounts.clear();
-    mQuotaReverseMounts.clear();
+
+#if !BYPASS_QUOTA
+    if (!InvalidateQuotaMounts()) {
+        return error("Failed to read mounts");
+    }
+#endif
 
     std::ifstream in("/proc/mounts");
     if (!in.is_open()) {
@@ -2585,17 +2502,6 @@
             mStorageMounts[source] = target;
         }
 #endif
-
-#if !BYPASS_QUOTA
-        if (source.compare(0, 11, "/dev/block/") == 0) {
-            struct dqblk dq;
-            if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
-                    reinterpret_cast<char*>(&dq)) == 0) {
-                LOG(DEBUG) << "Found quota mount " << source << " at " << target;
-                mQuotaReverseMounts[target] = source;
-            }
-        }
-#endif
     }
     return ok();
 }
@@ -2613,16 +2519,10 @@
     return StringPrintf("%s/%u", resolved.c_str(), userid);
 }
 
-std::string InstalldNativeService::findQuotaDeviceForUuid(
-        const std::unique_ptr<std::string>& uuid) {
-    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
-    auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
-    return mQuotaReverseMounts[path];
-}
-
 binder::Status InstalldNativeService::isQuotaSupported(
-        const std::unique_ptr<std::string>& volumeUuid, bool* _aidl_return) {
-    *_aidl_return = !findQuotaDeviceForUuid(volumeUuid).empty();
+        const std::unique_ptr<std::string>& uuid, bool* _aidl_return) {
+    auto uuidString = uuid ? *uuid : "";
+    *_aidl_return = IsQuotaSupported(uuidString);
     return ok();
 }
 
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index cebd3f9..367f2c1 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -150,14 +150,11 @@
 
     /* Map of all storage mounts from source to target */
     std::unordered_map<std::string, std::string> mStorageMounts;
-    /* Map of all quota mounts from target to source */
-    std::unordered_map<std::string, std::string> mQuotaReverseMounts;
 
     /* Map from UID to cache quota size */
     std::unordered_map<uid_t, int64_t> mCacheQuotas;
 
     std::string findDataMediaPath(const std::unique_ptr<std::string>& uuid, userid_t userid);
-    std::string findQuotaDeviceForUuid(const std::unique_ptr<std::string>& uuid);
 };
 
 }  // namespace installd
diff --git a/cmds/installd/QuotaUtils.cpp b/cmds/installd/QuotaUtils.cpp
new file mode 100644
index 0000000..b238dd3
--- /dev/null
+++ b/cmds/installd/QuotaUtils.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2018 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 "QuotaUtils.h"
+
+#include <fstream>
+#include <unordered_map>
+
+#include <sys/quota.h>
+
+#include <android-base/logging.h>
+
+#include "utils.h"
+
+namespace android {
+namespace installd {
+
+namespace {
+
+std::recursive_mutex mMountsLock;
+
+/* Map of all quota mounts from target to source */
+std::unordered_map<std::string, std::string> mQuotaReverseMounts;
+
+std::string& FindQuotaDeviceForUuid(const std::string& uuid) {
+    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+    auto path = create_data_path(uuid.empty() ? nullptr : uuid.c_str());
+    return mQuotaReverseMounts[path];
+}
+
+} // namespace
+
+bool InvalidateQuotaMounts() {
+    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+
+    mQuotaReverseMounts.clear();
+
+    std::ifstream in("/proc/mounts");
+    if (!in.is_open()) {
+        return false;
+    }
+
+    std::string source;
+    std::string target;
+    std::string ignored;
+    while (!in.eof()) {
+        std::getline(in, source, ' ');
+        std::getline(in, target, ' ');
+        std::getline(in, ignored);
+
+        if (source.compare(0, 11, "/dev/block/") == 0) {
+            struct dqblk dq;
+            if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
+                    reinterpret_cast<char*>(&dq)) == 0) {
+                LOG(DEBUG) << "Found quota mount " << source << " at " << target;
+                mQuotaReverseMounts[target] = source;
+            }
+        }
+    }
+    return true;
+}
+
+bool IsQuotaSupported(const std::string& uuid) {
+    return !FindQuotaDeviceForUuid(uuid).empty();
+}
+
+int64_t GetOccupiedSpaceForUid(const std::string& uuid, uid_t uid) {
+    const std::string device = FindQuotaDeviceForUuid(uuid);
+    if (device == "") {
+        return -1;
+    }
+    struct dqblk dq;
+    if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
+            reinterpret_cast<char*>(&dq)) != 0) {
+        if (errno != ESRCH) {
+            PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
+        }
+        return -1;
+    } else {
+#if MEASURE_DEBUG
+        LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
+#endif
+        return dq.dqb_curspace;
+    }
+}
+
+int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid) {
+    const std::string device = FindQuotaDeviceForUuid(uuid);
+    if (device == "") {
+        return -1;
+    }
+    struct dqblk dq;
+    if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), gid,
+            reinterpret_cast<char*>(&dq)) != 0) {
+        if (errno != ESRCH) {
+            PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << gid;
+        }
+        return -1;
+    } else {
+#if MEASURE_DEBUG
+        LOG(DEBUG) << "quotactl() for GID " << gid << " " << dq.dqb_curspace;
+#endif
+        return dq.dqb_curspace;
+    }
+
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/QuotaUtils.h b/cmds/installd/QuotaUtils.h
new file mode 100644
index 0000000..9ad170f
--- /dev/null
+++ b/cmds/installd/QuotaUtils.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INSTALLD_QUOTA_UTILS_H_
+#define ANDROID_INSTALLD_QUOTA_UTILS_H_
+
+#include <memory>
+#include <string>
+
+namespace android {
+namespace installd {
+
+/* Clear and recompute the reverse mounts map */
+bool InvalidateQuotaMounts();
+
+/* Whether quota is supported in the device with the given uuid */
+bool IsQuotaSupported(const std::string& uuid);
+
+/* Get the current occupied space in bytes for a uid or -1 if fails */
+int64_t GetOccupiedSpaceForUid(const std::string& uuid, uid_t uid);
+
+/* Get the current occupied space in bytes for a gid or -1 if fails */
+int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid);
+
+}  // namespace installd
+}  // namespace android
+
+#endif  // ANDROID_INSTALLD_QUOTA_UTILS_H_
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 174ab21..b6038f9 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -2693,6 +2693,13 @@
         return false;
     }
 
+    // Return false for empty class path since it may otherwise return true below if profiles is
+    // empty.
+    if (classpath.empty()) {
+        PLOG(ERROR) << "Class path is empty";
+        return false;
+    }
+
     // Open and create the snapshot profile.
     unique_fd snapshot_fd = open_spnashot_profile(AID_SYSTEM, package_name, profile_name);
 
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index f216c53..eb69e78 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -143,6 +143,20 @@
     "AAAACADojmFLPcugSwoBAAAUAgAACwAYAAAAAAAAAAAAoIEAAAAAY2xhc3Nlcy5kZXhVVAUAA/Ns"
     "+ll1eAsAAQQj5QIABIgTAABQSwUGAAAAAAEAAQBRAAAATwEAAAAA";
 
+class DexoptTestEnvTest : public testing::Test {
+};
+
+TEST_F(DexoptTestEnvTest, CheckSelinux) {
+    ASSERT_EQ(1, is_selinux_enabled());
+
+    // Crude cutout for virtual devices.
+#if !defined(__i386__) && !defined(__x86_64__)
+    constexpr bool kIsX86 = false;
+#else
+    constexpr bool kIsX86 = true;
+#endif
+    ASSERT_TRUE(1 == security_getenforce() || kIsX86);
+}
 
 class DexoptTest : public testing::Test {
 protected:
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 6b9cf0d..74ad184 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -43,6 +43,7 @@
 #define DEBUG_XATTRS 0
 
 using android::base::EndsWith;
+using android::base::Fdopendir;
 using android::base::StringPrintf;
 using android::base::unique_fd;
 
@@ -1036,7 +1037,7 @@
                 continue;
             }
 
-            DIR* subdir = fdopendir(subdir_fd);
+            DIR* subdir = Fdopendir(std::move(subdir_fd));
             if (subdir == nullptr) {
                 PLOG(WARNING) << "Could not open dir path " << local_path;
                 result = false;
diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h
index 79f666b..c541511 100644
--- a/include/android/system_fonts.h
+++ b/include/android/system_fonts.h
@@ -150,19 +150,81 @@
  * Move to the next system font.
  *
  * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
- * \return true if more system fonts are available, otherwise false.
+ * \return a font. If no more font is available, returns nullptr. You need to release the returned
+ *         font by ASystemFont_close when it is no longer needed.
  */
 ASystemFont* _Nullable ASystemFontIterator_next(ASystemFontIterator* _Nonnull iterator) __INTRODUCED_IN(29);
 
 /**
  * Close an ASystemFont returned by ASystemFontIterator_next.
  *
- * \param font a font returned by ASystemFontIterator_next. Do nothing if NULL is passed.
+ * \param font a font returned by ASystemFontIterator_next or ASystemFont_matchFamilyStyleCharacter.
+ *        Do nothing if NULL is passed.
  */
 void ASystemFont_close(ASystemFont* _Nullable font) __INTRODUCED_IN(29);
 
 
 /**
+ * Select the best font from given parameters.
+ *
+ * Only generic font families are supported.
+ * For more information about generic font families, read [W3C spec](https://www.w3.org/TR/css-fonts-4/#generic-font-families)
+ *
+ * Even if no font can render the given text, this function will return a non-null result for
+ * drawing Tofu character.
+ *
+ * Examples:
+ * <code>
+ *  // Simple font query for the ASCII character.
+ *  std::vector<uint16_t> text = { 'A' };
+ *  ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ *      "sans", 400, false, "en-US", text.data(), text.length(), &runLength);
+ *  // runLength will be 1 and the font will points a valid font file.
+ *
+ *  // Querying font for CJK characters
+ *  std::vector<uint16_t> text = { 0x9AA8 };
+ *  ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ *      "sans", 400, false, "zh-CN,ja-JP", text.data(), text.length(), &runLength);
+ *  // runLength will be 1 and the font will points a Simplified Chinese font.
+ *  ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ *      "sans", 400, false, "ja-JP,zh-CN", text.data(), text.length(), &runLength);
+ *  // runLength will be 1 and the font will points a Japanese font.
+ *
+ *  // Querying font for text/color emoji
+ *  std::vector<uint16_t> text = { 0xD83D, 0xDC68, 0x200D, 0x2764, 0xFE0F, 0x200D, 0xD83D, 0xDC68 };
+ *  ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ *      "sans", 400, false, "en-US", text.data(), text.length(), &runLength);
+ *  // runLength will be 8 and the font will points a color emoji font.
+ *
+ *  // Mixture of multiple script of characters.
+ *  // 0x05D0 is a Hebrew character and 0x0E01 is a Thai character.
+ *  std::vector<uint16_t> text = { 0x05D0, 0x0E01 };
+ *  ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ *      "sans", 400, false, "en-US", text.data(), text.length(), &runLength);
+ *  // runLength will be 1 and the font will points a Hebrew font.
+ * </code>
+ *
+ * \param familyName a null character terminated font family name
+ * \param weight a font weight value. Only from 0 to 1000 value is valid
+ * \param italic true if italic, otherwise false.
+ * \param languageTags a null character terminated comma separated IETF BCP47 compliant language
+ *                     tags.
+ * \param text a UTF-16 encoded text buffer to be rendered.
+ * \param textLength a length of the given text buffer.
+ * \param runLengthOut if not null, the font run length will be filled.
+ * \return a font to be used for given text and params. You need to release the returned font by
+ *         ASystemFont_close when it is no longer needed.
+ */
+ASystemFont* _Nonnull ASystemFont_matchFamilyStyleCharacter(
+        const char* _Nonnull familyName,
+        uint16_t weight,
+        bool italic,
+        const char* _Nonnull languageTags,
+        const uint16_t* _Nonnull text,
+        uint32_t textLength,
+        uint32_t* _Nullable runLengthOut) __INTRODUCED_IN(29);
+
+/**
  * Return an absolute path to the current font file.
  *
  * Here is a list of font formats returned by this method:
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 5461b4f..d16502f 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -38,6 +38,8 @@
         "libbinder",
         "libutils",
     ],
+
+    version_script: "libbinder_ndk.map.txt",
 }
 
 ndk_headers {
diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
index cc0a29d..e52a1d6 100644
--- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
@@ -31,6 +31,7 @@
 #include <android/binder_status.h>
 
 #include <assert.h>
+#include <unistd.h>
 
 #ifdef __cplusplus
 
@@ -113,23 +114,23 @@
 /**
  * This baseclass owns a single object, used to make various classes RAII.
  */
-template <typename T, void (*Destroy)(T*)>
+template <typename T, typename R, R (*Destroy)(T), T DEFAULT>
 class ScopedAResource {
 public:
     /**
      * Takes ownership of t.
      */
-    explicit ScopedAResource(T* t = nullptr) : mT(t) {}
+    explicit ScopedAResource(T t = DEFAULT) : mT(t) {}
 
     /**
      * This deletes the underlying object if it exists. See set.
      */
-    ~ScopedAResource() { set(nullptr); }
+    ~ScopedAResource() { set(DEFAULT); }
 
     /**
      * Takes ownership of t.
      */
-    void set(T* t) {
+    void set(T t) {
         Destroy(mT);
         mT = t;
     }
@@ -137,12 +138,12 @@
     /**
      * This returns the underlying object to be modified but does not affect ownership.
      */
-    T* get() { return mT; }
+    T get() { return mT; }
 
     /**
      * This returns the const underlying object but does not affect ownership.
      */
-    const T* get() const { return mT; }
+    const T get() const { return mT; }
 
     /**
      * This allows the value in this class to be set from beneath it. If you call this method and
@@ -156,7 +157,7 @@
      * Other usecases are discouraged.
      *
      */
-    T** getR() { return &mT; }
+    T* getR() { return &mT; }
 
     // copy-constructing, or move/copy assignment is disallowed
     ScopedAResource(const ScopedAResource&) = delete;
@@ -167,13 +168,13 @@
     ScopedAResource(ScopedAResource&&) = default;
 
 private:
-    T* mT;
+    T mT;
 };
 
 /**
  * Convenience wrapper. See AParcel.
  */
-class ScopedAParcel : public ScopedAResource<AParcel, AParcel_delete> {
+class ScopedAParcel : public ScopedAResource<AParcel*, void, AParcel_delete, nullptr> {
 public:
     /**
      * Takes ownership of a.
@@ -186,7 +187,7 @@
 /**
  * Convenience wrapper. See AStatus.
  */
-class ScopedAStatus : public ScopedAResource<AStatus, AStatus_delete> {
+class ScopedAStatus : public ScopedAResource<AStatus*, void, AStatus_delete, nullptr> {
 public:
     /**
      * Takes ownership of a.
@@ -205,7 +206,8 @@
  * Convenience wrapper. See AIBinder_DeathRecipient.
  */
 class ScopedAIBinder_DeathRecipient
-      : public ScopedAResource<AIBinder_DeathRecipient, AIBinder_DeathRecipient_delete> {
+      : public ScopedAResource<AIBinder_DeathRecipient*, void, AIBinder_DeathRecipient_delete,
+                               nullptr> {
 public:
     /**
      * Takes ownership of a.
@@ -219,7 +221,8 @@
 /**
  * Convenience wrapper. See AIBinder_Weak.
  */
-class ScopedAIBinder_Weak : public ScopedAResource<AIBinder_Weak, AIBinder_Weak_delete> {
+class ScopedAIBinder_Weak
+      : public ScopedAResource<AIBinder_Weak*, void, AIBinder_Weak_delete, nullptr> {
 public:
     /**
      * Takes ownership of a.
@@ -234,6 +237,19 @@
     SpAIBinder promote() { return SpAIBinder(AIBinder_Weak_promote(get())); }
 };
 
+/**
+ * Convenience wrapper for a file descriptor.
+ */
+class ScopedFileDescriptor : public ScopedAResource<int, int, close, -1> {
+public:
+    /**
+     * Takes ownership of a.
+     */
+    explicit ScopedFileDescriptor(int a = -1) : ScopedAResource(a) {}
+    ~ScopedFileDescriptor() {}
+    ScopedFileDescriptor(ScopedFileDescriptor&&) = default;
+};
+
 } // namespace ndk
 
 #endif // __cplusplus
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index 33c3f6c..4e0132b 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -193,6 +193,23 @@
         __INTRODUCED_IN(29);
 
 /**
+ * Writes a file descriptor to the next location in a non-null parcel. This does not take ownership
+ * of fd.
+ *
+ * This corresponds to the SDK's android.os.ParcelFileDescriptor.
+ */
+binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd);
+
+/**
+ * Reads an int from the next location in a non-null parcel.
+ *
+ * The returned fd must be closed.
+ *
+ * This corresponds to the SDK's android.os.ParcelFileDescriptor.
+ */
+binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd);
+
+/**
  * Writes an AStatus object to the next location in a non-null parcel.
  *
  * If the status is considered to be a low-level status and has no additional information other
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index f84814f..ec6587a 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -38,6 +38,7 @@
     AParcel_readInt64;
     AParcel_readInt64Array;
     AParcel_readNullableStrongBinder;
+    AParcel_readParcelFileDescriptor;
     AParcel_readStatusHeader;
     AParcel_readString;
     AParcel_readStrongBinder;
@@ -59,6 +60,7 @@
     AParcel_writeInt32Array;
     AParcel_writeInt64;
     AParcel_writeInt64Array;
+    AParcel_writeParcelFileDescriptor;
     AParcel_writeStatusHeader;
     AParcel_writeString;
     AParcel_writeStrongBinder;
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index 5ac3965..77c0558 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -23,13 +23,17 @@
 #include <limits>
 
 #include <android-base/logging.h>
+#include <android-base/unique_fd.h>
 #include <binder/Parcel.h>
+#include <binder/ParcelFileDescriptor.h>
 #include <utils/Unicode.h>
 
 using ::android::IBinder;
 using ::android::Parcel;
 using ::android::sp;
 using ::android::status_t;
+using ::android::base::unique_fd;
+using ::android::os::ParcelFileDescriptor;
 
 template <typename T>
 using ContiguousArrayAllocator = T* (*)(void* arrayData, size_t length);
@@ -210,6 +214,28 @@
     *binder = ret.get();
     return PruneStatusT(status);
 }
+
+binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd) {
+    ParcelFileDescriptor parcelFd((unique_fd(fd)));
+
+    status_t status = parcel->get()->writeParcelable(parcelFd);
+
+    // ownership is retained by caller
+    (void)parcelFd.release().release();
+
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd) {
+    ParcelFileDescriptor parcelFd;
+    // status_t status = parcelFd.readFromParcel(parcel->get());
+    status_t status = parcel->get()->readParcelable(&parcelFd);
+    if (status != STATUS_OK) return PruneStatusT(status);
+
+    *fd = parcelFd.release().release();
+    return STATUS_OK;
+}
+
 binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status) {
     return PruneStatusT(status->get()->writeToParcel(parcel->get()));
 }
diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp
index 1a7c2d3..ed773e0 100644
--- a/libs/gui/BufferHubProducer.cpp
+++ b/libs/gui/BufferHubProducer.cpp
@@ -20,7 +20,6 @@
 #include <log/log.h>
 #include <system/window.h>
 #include <ui/BufferHubBuffer.h>
-#include <ui/DetachedBufferHandle.h>
 
 namespace android {
 
@@ -276,14 +275,10 @@
               status_or_handle.error());
         return BAD_VALUE;
     }
-    std::unique_ptr<DetachedBufferHandle> handle =
-            DetachedBufferHandle::Create(status_or_handle.take());
-    if (!handle->isValid()) {
-        ALOGE("detachBuffer: Failed to create a DetachedBufferHandle at slot %zu.", slot);
-        return BAD_VALUE;
-    }
 
-    return graphic_buffer->setDetachedBufferHandle(std::move(handle));
+    // TODO(b/70912269): Reimplement BufferHubProducer::DetachBufferLocked() once GraphicBuffer can
+    // be directly backed by BufferHub.
+    return INVALID_OPERATION;
 }
 
 status_t BufferHubProducer::detachNextBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence) {
@@ -373,7 +368,7 @@
         ALOGE("attachBuffer: out_slot cannot be NULL.");
         return BAD_VALUE;
     }
-    if (buffer == nullptr || !buffer->isDetachedBuffer()) {
+    if (buffer == nullptr) {
         ALOGE("attachBuffer: invalid GraphicBuffer.");
         return BAD_VALUE;
     }
@@ -394,45 +389,9 @@
         return BAD_VALUE;
     }
 
-    // Creates a BufferProducer from the GraphicBuffer.
-    std::unique_ptr<DetachedBufferHandle> detached_handle = buffer->takeDetachedBufferHandle();
-    if (detached_handle == nullptr) {
-        ALOGE("attachBuffer: DetachedBufferHandle cannot be NULL.");
-        return BAD_VALUE;
-    }
-    std::shared_ptr<BufferProducer> buffer_producer =
-            BufferProducer::Import(std::move(detached_handle->handle()));
-    if (buffer_producer == nullptr) {
-        ALOGE("attachBuffer: Failed to import BufferProducer.");
-        return BAD_VALUE;
-    }
-
-    // Adds the BufferProducer into the Queue.
-    auto status_or_slot = queue_->InsertBuffer(buffer_producer);
-    if (!status_or_slot.ok()) {
-        ALOGE("attachBuffer: Failed to insert buffer, error=%d.", status_or_slot.error());
-        return BAD_VALUE;
-    }
-
-    size_t slot = status_or_slot.get();
-    ALOGV("attachBuffer: returning slot %zu.", slot);
-    if (slot >= static_cast<size_t>(max_buffer_count_)) {
-        ALOGE("attachBuffer: Invalid slot: %zu.", slot);
-        return BAD_VALUE;
-    }
-
-    // The just attached buffer should be in dequeued state according to IGraphicBufferProducer
-    // interface. In BufferHub's language the buffer should be in Gained state.
-    buffers_[slot].mGraphicBuffer = buffer;
-    buffers_[slot].mBufferState.attachProducer();
-    buffers_[slot].mEglFence = EGL_NO_SYNC_KHR;
-    buffers_[slot].mFence = Fence::NO_FENCE;
-    buffers_[slot].mRequestBufferCalled = true;
-    buffers_[slot].mAcquireCalled = false;
-    buffers_[slot].mNeedsReallocation = false;
-
-    *out_slot = static_cast<int>(slot);
-    return NO_ERROR;
+    // TODO(b/70912269): Reimplement BufferHubProducer::DetachBufferLocked() once GraphicBuffer can
+    // be directly backed by BufferHub.
+    return INVALID_OPERATION;
 }
 
 status_t BufferHubProducer::queueBuffer(int slot, const QueueBufferInput& input,
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index cc0a307..e66c0e5 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -565,8 +565,10 @@
         return reply.readParcelableVector(outLayers);
     }
 
-    virtual status_t getCompositionPreference(ui::Dataspace* dataSpace,
-                                              ui::PixelFormat* pixelFormat) const {
+    virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
+                                              ui::PixelFormat* defaultPixelFormat,
+                                              ui::Dataspace* wideColorGamutDataspace,
+                                              ui::PixelFormat* wideColorGamutPixelFormat) const {
         Parcel data, reply;
         status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (error != NO_ERROR) {
@@ -578,8 +580,10 @@
         }
         error = static_cast<status_t>(reply.readInt32());
         if (error == NO_ERROR) {
-            *dataSpace = static_cast<ui::Dataspace>(reply.readInt32());
-            *pixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
+            *defaultDataspace = static_cast<ui::Dataspace>(reply.readInt32());
+            *defaultPixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
+            *wideColorGamutDataspace = static_cast<ui::Dataspace>(reply.readInt32());
+            *wideColorGamutPixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
         }
         return error;
     }
@@ -925,13 +929,19 @@
         }
         case GET_COMPOSITION_PREFERENCE: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            ui::Dataspace dataSpace;
-            ui::PixelFormat pixelFormat;
-            status_t error = getCompositionPreference(&dataSpace, &pixelFormat);
+            ui::Dataspace defaultDataspace;
+            ui::PixelFormat defaultPixelFormat;
+            ui::Dataspace wideColorGamutDataspace;
+            ui::PixelFormat wideColorGamutPixelFormat;
+            status_t error =
+                    getCompositionPreference(&defaultDataspace, &defaultPixelFormat,
+                                             &wideColorGamutDataspace, &wideColorGamutPixelFormat);
             reply->writeInt32(error);
             if (error == NO_ERROR) {
-                reply->writeInt32(static_cast<int32_t>(dataSpace));
-                reply->writeInt32(static_cast<int32_t>(pixelFormat));
+                reply->writeInt32(static_cast<int32_t>(defaultDataspace));
+                reply->writeInt32(static_cast<int32_t>(defaultPixelFormat));
+                reply->writeInt32(static_cast<int32_t>(wideColorGamutDataspace));
+                reply->writeInt32(static_cast<int32_t>(wideColorGamutDataspace));
             }
             return NO_ERROR;
         }
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 7498f36..e5a2454 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -866,9 +866,12 @@
     ComposerService::getComposerService()->setPowerMode(token, mode);
 }
 
-status_t SurfaceComposerClient::getCompositionPreference(ui::Dataspace* dataSpace,
-                                                         ui::PixelFormat* pixelFormat) {
-    return ComposerService::getComposerService()->getCompositionPreference(dataSpace, pixelFormat);
+status_t SurfaceComposerClient::getCompositionPreference(
+        ui::Dataspace* defaultDataspace, ui::PixelFormat* defaultPixelFormat,
+        ui::Dataspace* wideColorGamutDataspace, ui::PixelFormat* wideColorGamutPixelFormat) {
+    return ComposerService::getComposerService()
+            ->getCompositionPreference(defaultDataspace, defaultPixelFormat,
+                                       wideColorGamutDataspace, wideColorGamutPixelFormat);
 }
 
 status_t SurfaceComposerClient::clearAnimationFrameStats() {
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 35cb3be..9316ae6 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -280,10 +280,19 @@
      */
     virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const = 0;
 
-    virtual status_t getCompositionPreference(ui::Dataspace* dataSpace,
-                                              ui::PixelFormat* pixelFormat) const = 0;
-
     virtual bool isColorManagementUsed() const = 0;
+
+    /* Gets the composition preference of the default data space and default pixel format,
+     * as well as the wide color gamut data space and wide color gamut pixel format.
+     * If the wide color gamut data space is V0_SRGB, then it implies that the platform
+     * has no wide color gamut support.
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
+                                              ui::PixelFormat* defaultPixelFormat,
+                                              ui::Dataspace* wideColorGamutDataspace,
+                                              ui::PixelFormat* wideColorGamutPixelFormat) const = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 1b4eda7..8ccee05 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -101,9 +101,15 @@
     /* Triggers screen on/off or low power mode and waits for it to complete */
     static void setDisplayPowerMode(const sp<IBinder>& display, int mode);
 
-    //
-    static status_t getCompositionPreference(ui::Dataspace* dataSpace,
-                                             ui::PixelFormat* pixelFormat);
+    /* Returns the composition preference of the default data space and default pixel format,
+     * as well as the wide color gamut data space and wide color gamut pixel format.
+     * If the wide color gamut data space is V0_SRGB, then it implies that the platform
+     * has no wide color gamut support.
+     */
+    static status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
+                                             ui::PixelFormat* defaultPixelFormat,
+                                             ui::Dataspace* wideColorGamutDataspace,
+                                             ui::PixelFormat* wideColorGamutPixelFormat);
 
     // ------------------------------------------------------------------------
     // surface creation / destruction
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index 6d03374..aef7aed 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -777,14 +777,6 @@
     ASSERT_OK(mProducer->detachBuffer(slot));
     EXPECT_OK(buffer->initCheck());
 
-    if (GetParam() == USE_BUFFER_HUB_PRODUCER) {
-        // For a GraphicBuffer backed by BufferHub, once detached from an IGBP, it should have
-        // isDetachedBuffer() set. Note that this only applies to BufferHub.
-        EXPECT_TRUE(buffer->isDetachedBuffer());
-    } else {
-        EXPECT_FALSE(buffer->isDetachedBuffer());
-    }
-
     ASSERT_OK(mProducer->disconnect(TEST_API));
 
     ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer));
@@ -801,16 +793,7 @@
     ASSERT_OK(mProducer->detachBuffer(slot));
     EXPECT_OK(buffer->initCheck());
 
-    if (GetParam() == USE_BUFFER_HUB_PRODUCER) {
-        // For a GraphicBuffer backed by BufferHub, once detached from an IGBP, it should have
-        // isDetachedBuffer() set. Note that this only applies to BufferHub.
-        EXPECT_TRUE(buffer->isDetachedBuffer());
-    } else {
-        EXPECT_FALSE(buffer->isDetachedBuffer());
-    }
-
     EXPECT_OK(mProducer->attachBuffer(&slot, buffer));
-    EXPECT_FALSE(buffer->isDetachedBuffer());
     EXPECT_OK(buffer->initCheck());
 }
 
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 25f762b..a3e9249 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -628,8 +628,10 @@
     status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* /*layers*/) const override {
         return NO_ERROR;
     }
-    status_t getCompositionPreference(ui::Dataspace* /*outDataSpace*/,
-                                      ui::PixelFormat* /*outPixelFormat*/) const override {
+    status_t getCompositionPreference(
+            ui::Dataspace* /*outDefaultDataspace*/, ui::PixelFormat* /*outDefaultPixelFormat*/,
+            ui::Dataspace* /*outWideColorGamutDataspace*/,
+            ui::PixelFormat* /*outWideColorGamutPixelFormat*/) const override {
         return NO_ERROR;
     }
 
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index a6e6d73..8cc1a4e 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -37,7 +37,6 @@
 #pragma clang diagnostic pop
 
 #include <ui/BufferHubBuffer.h>
-#include <ui/DetachedBufferHandle.h>
 
 #include <poll.h>
 
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index c50d1d0..5a1ddee 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -22,7 +22,6 @@
 
 #include <grallocusage/GrallocUsageConversion.h>
 
-#include <ui/DetachedBufferHandle.h>
 #include <ui/Gralloc2.h>
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/GraphicBufferMapper.h>
@@ -490,24 +489,6 @@
     return NO_ERROR;
 }
 
-bool GraphicBuffer::isDetachedBuffer() const {
-    return mDetachedBufferHandle && mDetachedBufferHandle->isValid();
-}
-
-status_t GraphicBuffer::setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> channel) {
-    if (isDetachedBuffer()) {
-        ALOGW("setDetachedBuffer: there is already a BufferHub channel associated with this "
-              "GraphicBuffer. Replacing the old one.");
-    }
-
-    mDetachedBufferHandle = std::move(channel);
-    return NO_ERROR;
-}
-
-std::unique_ptr<DetachedBufferHandle> GraphicBuffer::takeDetachedBufferHandle() {
-    return std::move(mDetachedBufferHandle);
-}
-
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/libs/ui/include/ui/DetachedBufferHandle.h b/libs/ui/include/ui/DetachedBufferHandle.h
deleted file mode 100644
index f3c328d..0000000
--- a/libs/ui/include/ui/DetachedBufferHandle.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
-#define ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
-
-#include <pdx/channel_handle.h>
-
-#include <memory>
-
-namespace android {
-
-// A wrapper that holds a pdx::LocalChannelHandle object. From the handle, a BufferHub buffer can be
-// created. Current implementation assumes that the underlying transport is using libpdx (thus
-// holding a pdx::LocalChannelHandle object), but future implementation can change it to a Binder
-// backend if ever needed.
-class DetachedBufferHandle {
-public:
-    static std::unique_ptr<DetachedBufferHandle> Create(pdx::LocalChannelHandle handle) {
-        return std::unique_ptr<DetachedBufferHandle>(new DetachedBufferHandle(std::move(handle)));
-    }
-
-    // Accessors to get or take the internal pdx::LocalChannelHandle.
-    pdx::LocalChannelHandle& handle() { return mHandle; }
-    const pdx::LocalChannelHandle& handle() const { return mHandle; }
-
-    // Returns whether the DetachedBufferHandle holds a BufferHub channel.
-    bool isValid() const { return mHandle.valid(); }
-
-private:
-    // Constructs a DetachedBufferHandle from a pdx::LocalChannelHandle.
-    explicit DetachedBufferHandle(pdx::LocalChannelHandle handle) : mHandle(std::move(handle)) {}
-
-    pdx::LocalChannelHandle mHandle;
-};
-
-} // namespace android
-
-#endif // ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index cc38982..e794462 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -34,7 +34,6 @@
 
 namespace android {
 
-class DetachedBufferHandle;
 class GraphicBufferMapper;
 
 // ===========================================================================
@@ -191,11 +190,6 @@
     status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
     status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
 
-    // Sets and takes DetachedBuffer. Should only be called from BufferHub.
-    bool isDetachedBuffer() const;
-    status_t setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> detachedBuffer);
-    std::unique_ptr<DetachedBufferHandle> takeDetachedBufferHandle();
-
 private:
     ~GraphicBuffer();
 
@@ -246,17 +240,6 @@
     // match the BufferQueue's internal generation number (set through
     // IGBP::setGenerationNumber), attempts to attach the buffer will fail.
     uint32_t mGenerationNumber;
-
-    // Stores a BufferHub handle that can be used to re-attach this GraphicBuffer back into a
-    // BufferHub producer/consumer set. In terms of GraphicBuffer's relationship with BufferHub,
-    // there are three different modes:
-    // 1. Legacy mode: GraphicBuffer is not backed by BufferHub and mDetachedBufferHandle must be
-    //    invalid.
-    // 2. Detached mode: GraphicBuffer is backed by BufferHub, but not part of a producer/consumer
-    //    set. In this mode, mDetachedBufferHandle must be valid.
-    // 3. Attached mode: GraphicBuffer is backed by BufferHub and it's part of a producer/consumer
-    //    set. In this mode, mDetachedBufferHandle must be invalid.
-    std::unique_ptr<DetachedBufferHandle> mDetachedBufferHandle;
 };
 
 }; // namespace android
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index e8bda67..1521e1d 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -29,13 +29,6 @@
 }
 
 cc_test {
-    name: "GraphicBuffer_test",
-    shared_libs: ["libpdx_default_transport", "libui", "libutils"],
-    srcs: ["GraphicBuffer_test.cpp"],
-    cflags: ["-Wall", "-Werror"],
-}
-
-cc_test {
     name: "BufferHubBuffer_test",
     header_libs: [
         "libbufferhub_headers",
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
deleted file mode 100644
index eb679ac..0000000
--- a/libs/ui/tests/GraphicBuffer_test.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "GraphicBufferTest"
-
-#include <ui/DetachedBufferHandle.h>
-#include <ui/GraphicBuffer.h>
-
-#include <gtest/gtest.h>
-
-namespace android {
-
-namespace {
-
-constexpr uint32_t kTestWidth = 1024;
-constexpr uint32_t kTestHeight = 1;
-constexpr uint32_t kTestFormat = HAL_PIXEL_FORMAT_BLOB;
-constexpr uint32_t kTestLayerCount = 1;
-constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN;
-
-} // namespace
-
-class GraphicBufferTest : public testing::Test {};
-
-TEST_F(GraphicBufferTest, DetachedBuffer) {
-    sp<GraphicBuffer> buffer(
-            new GraphicBuffer(kTestWidth, kTestHeight, kTestFormat, kTestLayerCount, kTestUsage));
-
-    // Currently a newly allocated GraphicBuffer is in legacy mode, i.e. not associated with
-    // BufferHub. But this may change in the future.
-    EXPECT_FALSE(buffer->isDetachedBuffer());
-
-    pdx::LocalChannelHandle channel{nullptr, 1234};
-    EXPECT_TRUE(channel.valid());
-
-    std::unique_ptr<DetachedBufferHandle> handle = DetachedBufferHandle::Create(std::move(channel));
-    EXPECT_FALSE(channel.valid());
-    EXPECT_TRUE(handle->isValid());
-    EXPECT_TRUE(handle->handle().valid());
-
-    buffer->setDetachedBufferHandle(std::move(handle));
-    EXPECT_TRUE(handle == nullptr);
-    EXPECT_TRUE(buffer->isDetachedBuffer());
-
-    handle = buffer->takeDetachedBufferHandle();
-    EXPECT_TRUE(handle != nullptr);
-    EXPECT_TRUE(handle->isValid());
-    EXPECT_FALSE(buffer->isDetachedBuffer());
-}
-
-} // namespace android
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index 18b97db..73ca69b 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -5,7 +5,6 @@
 #include <sys/epoll.h>
 #include <sys/eventfd.h>
 #include <ui/BufferHubBuffer.h>
-#include <ui/DetachedBufferHandle.h>
 
 #include <mutex>
 #include <thread>
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 1daa4d2..547a669 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -485,58 +485,29 @@
 }
 
 // Returns a list of color spaces understood by the vendor EGL driver.
-static std::vector<EGLint> getDriverColorSpaces(egl_display_ptr dp,
-                                                android_pixel_format format) {
+static std::vector<EGLint> getDriverColorSpaces(egl_display_ptr dp) {
     std::vector<EGLint> colorSpaces;
-    if (!dp->hasColorSpaceSupport) return colorSpaces;
 
-    // OpenGL drivers only support sRGB encoding with 8-bit formats.
-    // RGB_888 is never returned by getNativePixelFormat, but is included for completeness.
-    const bool formatSupportsSRGBEncoding =
-        format == HAL_PIXEL_FORMAT_RGBA_8888 || format == HAL_PIXEL_FORMAT_RGBX_8888 ||
-        format == HAL_PIXEL_FORMAT_RGB_888;
-    const bool formatIsFloatingPoint = format == HAL_PIXEL_FORMAT_RGBA_FP16;
+    // sRGB and linear are always supported when color space support is present.
+    colorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR);
+    colorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR);
 
-    if (formatSupportsSRGBEncoding) {
-        // sRGB and linear are always supported when color space support is present.
-        colorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR);
-        colorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR);
-        // DCI-P3 uses the sRGB transfer function, so it's only relevant for 8-bit formats.
-        if (findExtension(dp->disp.queryString.extensions,
-                              "EGL_EXT_gl_colorspace_display_p3")) {
-            colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT);
-        }
+    if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_display_p3")) {
+        colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT);
     }
-
-    // According to the spec, scRGB is only supported for floating point formats.
-    // For non-linear scRGB, the application is responsible for applying the
-    // transfer function.
-    if (formatIsFloatingPoint) {
-        if (findExtension(dp->disp.queryString.extensions,
-                  "EGL_EXT_gl_colorspace_scrgb")) {
-            colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_EXT);
-        }
-        if (findExtension(dp->disp.queryString.extensions,
-                  "EGL_EXT_gl_colorspace_scrgb_linear")) {
-            colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT);
-        }
+    if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_scrgb")) {
+        colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_EXT);
     }
-
-    // BT2020 can be used with any pixel format. PQ encoding must be applied by the
-    // application and does not affect the behavior of OpenGL.
-    if (findExtension(dp->disp.queryString.extensions,
-                          "EGL_EXT_gl_colorspace_bt2020_linear")) {
+    if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_scrgb_linear")) {
+        colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT);
+    }
+    if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_bt2020_linear")) {
         colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_LINEAR_EXT);
     }
-    if (findExtension(dp->disp.queryString.extensions,
-                          "EGL_EXT_gl_colorspace_bt2020_pq")) {
+    if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_bt2020_pq")) {
         colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT);
     }
-
-    // Linear DCI-P3 simply uses different primaries than standard RGB and thus
-    // can be used with any pixel format.
-    if (findExtension(dp->disp.queryString.extensions,
-                          "EGL_EXT_gl_colorspace_display_p3_linear")) {
+    if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_display_p3_linear")) {
         colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT);
     }
     return colorSpaces;
@@ -547,18 +518,32 @@
 // unmodified.
 template <typename AttrType>
 static EGLBoolean processAttributes(egl_display_ptr dp, ANativeWindow* window,
-                                    android_pixel_format format, const AttrType* attrib_list,
-                                    EGLint* colorSpace, std::vector<AttrType>* strippedAttribList) {
+                                    const AttrType* attrib_list, EGLint* colorSpace,
+                                    std::vector<AttrType>* strippedAttribList) {
     for (const AttrType* attr = attrib_list; attr && attr[0] != EGL_NONE; attr += 2) {
         bool copyAttribute = true;
         if (attr[0] == EGL_GL_COLORSPACE_KHR) {
-            // Fail immediately if the driver doesn't have color space support at all.
-            if (!dp->hasColorSpaceSupport) return false;
+            switch (attr[1]) {
+                case EGL_GL_COLORSPACE_LINEAR_KHR:
+                case EGL_GL_COLORSPACE_SRGB_KHR:
+                case EGL_GL_COLORSPACE_DISPLAY_P3_EXT:
+                case EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT:
+                case EGL_GL_COLORSPACE_SCRGB_EXT:
+                case EGL_GL_COLORSPACE_BT2020_LINEAR_EXT:
+                case EGL_GL_COLORSPACE_BT2020_PQ_EXT:
+                case EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT:
+                    // Fail immediately if the driver doesn't have color space support at all.
+                    if (!dp->hasColorSpaceSupport) return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+                    break;
+                default:
+                    // BAD_ATTRIBUTE if attr is not any of the EGL_GL_COLORSPACE_*
+                    return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+            }
             *colorSpace = static_cast<EGLint>(attr[1]);
 
             // Strip the attribute if the driver doesn't understand it.
             copyAttribute = false;
-            std::vector<EGLint> driverColorSpaces = getDriverColorSpaces(dp, format);
+            std::vector<EGLint> driverColorSpaces = getDriverColorSpaces(dp);
             for (auto driverColorSpace : driverColorSpaces) {
                 if (static_cast<EGLint>(attr[1]) == driverColorSpace) {
                     copyAttribute = true;
@@ -585,10 +570,8 @@
 
     // If the passed color space has wide color gamut, check whether the target native window
     // supports wide color.
-    const bool colorSpaceIsNarrow =
-        *colorSpace == EGL_GL_COLORSPACE_SRGB_KHR ||
-        *colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR ||
-        *colorSpace == EGL_UNKNOWN;
+    const bool colorSpaceIsNarrow = *colorSpace == EGL_GL_COLORSPACE_SRGB_KHR ||
+            *colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR || *colorSpace == EGL_UNKNOWN;
     if (window && !colorSpaceIsNarrow) {
         bool windowSupportsWideColor = true;
         // Ordinarily we'd put a call to native_window_get_wide_color_support
@@ -606,12 +589,12 @@
             ALOGE("processAttributes: invalid window (win=%p) "
                   "failed (%#x) (already connected to another API?)",
                   window, err);
-            return false;
+            return setError(EGL_BAD_NATIVE_WINDOW, EGL_FALSE);
         }
         if (!windowSupportsWideColor) {
             // Application has asked for a wide-color colorspace but
             // wide-color support isn't available on the display the window is on.
-            return false;
+            return setError(EGL_BAD_MATCH, EGL_FALSE);
         }
     }
     return true;
@@ -695,8 +678,7 @@
                 native_window_set_buffers_smpte2086_metadata(s->getNativeWindow(), &smpteMetadata);
         s->resetSmpte2086Metadata();
         if (err != 0) {
-            ALOGE("error setting native window smpte2086 metadata: %s (%d)",
-                  strerror(-err), err);
+            ALOGE("error setting native window smpte2086 metadata: %s (%d)", strerror(-err), err);
             return EGL_FALSE;
         }
     }
@@ -706,8 +688,7 @@
                 native_window_set_buffers_cta861_3_metadata(s->getNativeWindow(), &cta8613Metadata);
         s->resetCta8613Metadata();
         if (err != 0) {
-            ALOGE("error setting native window CTS 861.3 metadata: %s (%d)",
-                  strerror(-err), err);
+            ALOGE("error setting native window CTS 861.3 metadata: %s (%d)", strerror(-err), err);
             return EGL_FALSE;
         }
     }
@@ -749,10 +730,12 @@
     // now select correct colorspace and dataspace based on user's attribute list
     EGLint colorSpace = EGL_UNKNOWN;
     std::vector<AttrType> strippedAttribList;
-    if (!processAttributes<AttrType>(dp, window, format, attrib_list, &colorSpace,
-                                     &strippedAttribList)) {
+    if (!processAttributes<AttrType>(dp, window, attrib_list, &colorSpace, &strippedAttribList)) {
         ALOGE("error invalid colorspace: %d", colorSpace);
-        return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+        if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+            native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+        }
+        return EGL_NO_SURFACE;
     }
     attrib_list = strippedAttribList.data();
 
@@ -765,13 +748,14 @@
         }
 
         android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace);
-        if (dataSpace != HAL_DATASPACE_UNKNOWN) {
-            err = native_window_set_buffers_data_space(window, dataSpace);
-            if (err != 0) {
-                ALOGE("error setting native window pixel dataSpace: %s (%d)", strerror(-err), err);
-                native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
-                return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
-            }
+        // Set dataSpace even if it could be HAL_DATASPACE_UNKNOWN.
+        // HAL_DATASPACE_UNKNOWN is the default value, but it may have changed
+        // at this point.
+        err = native_window_set_buffers_data_space(window, dataSpace);
+        if (err != 0) {
+            ALOGE("error setting native window pixel dataSpace: %s (%d)", strerror(-err), err);
+            native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+            return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
         }
     }
 
@@ -873,9 +857,8 @@
     return EGL_NO_SURFACE;
 }
 
-EGLSurface eglCreatePbufferSurfaceImpl( EGLDisplay dpy, EGLConfig config,
-                                        const EGLint *attrib_list)
-{
+EGLSurface eglCreatePbufferSurfaceImpl(EGLDisplay dpy, EGLConfig config,
+                                       const EGLint* attrib_list) {
     egl_connection_t* cnx = nullptr;
     egl_display_ptr dp = validate_display_connection(dpy, cnx);
     if (dp) {
@@ -886,35 +869,30 @@
         // Select correct colorspace based on user's attribute list
         EGLint colorSpace = EGL_UNKNOWN;
         std::vector<EGLint> strippedAttribList;
-        if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace,
-                               &strippedAttribList)) {
+        if (!processAttributes(dp, nullptr, attrib_list, &colorSpace, &strippedAttribList)) {
             ALOGE("error invalid colorspace: %d", colorSpace);
-            return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+            return EGL_NO_SURFACE;
         }
         attrib_list = strippedAttribList.data();
 
-        EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
-                dp->disp.dpy, config, attrib_list);
+        EGLSurface surface = cnx->egl.eglCreatePbufferSurface(dp->disp.dpy, config, attrib_list);
         if (surface != EGL_NO_SURFACE) {
-            egl_surface_t* s =
-                    new egl_surface_t(dp.get(), config, nullptr, surface,
-                                      getReportedColorSpace(colorSpace), cnx);
+            egl_surface_t* s = new egl_surface_t(dp.get(), config, nullptr, surface,
+                                                 getReportedColorSpace(colorSpace), cnx);
             return s;
         }
     }
     return EGL_NO_SURFACE;
 }
 
-EGLBoolean eglDestroySurfaceImpl(EGLDisplay dpy, EGLSurface surface)
-{
+EGLBoolean eglDestroySurfaceImpl(EGLDisplay dpy, EGLSurface surface) {
     const egl_display_ptr dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
     SurfaceRef _s(dp.get(), surface);
-    if (!_s.get())
-        return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+    if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
 
-    egl_surface_t * const s = get_surface(surface);
+    egl_surface_t* const s = get_surface(surface);
     EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
     if (result == EGL_TRUE) {
         _s.terminate();
@@ -922,17 +900,15 @@
     return result;
 }
 
-EGLBoolean eglQuerySurfaceImpl( EGLDisplay dpy, EGLSurface surface,
-                                EGLint attribute, EGLint *value)
-{
+EGLBoolean eglQuerySurfaceImpl(EGLDisplay dpy, EGLSurface surface, EGLint attribute,
+                               EGLint* value) {
     const egl_display_ptr dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
     SurfaceRef _s(dp.get(), surface);
-    if (!_s.get())
-        return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+    if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
 
-    egl_surface_t const * const s = get_surface(surface);
+    egl_surface_t const* const s = get_surface(surface);
     if (s->getColorSpaceAttribute(attribute, value)) {
         return EGL_TRUE;
     } else if (s->getSmpte2086Attribute(attribute, value)) {
diff --git a/opengl/libs/libEGL.map.txt b/opengl/libs/libEGL.map.txt
index fa26e33..b2d7957 100644
--- a/opengl/libs/libEGL.map.txt
+++ b/opengl/libs/libEGL.map.txt
@@ -3,23 +3,30 @@
     eglBindAPI;
     eglBindTexImage;
     eglChooseConfig;
+    eglClientWaitSync; # introduced=29
     eglClientWaitSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
     eglCopyBuffers;
     eglCreateContext;
+    eglCreateImage; # introduced=29
     eglCreateImageKHR;
     eglCreateNativeClientBufferANDROID; # introduced=24
     eglCreatePbufferFromClientBuffer;
     eglCreatePbufferSurface;
     eglCreatePixmapSurface;
+    eglCreatePlatformPixmapSurface; # introduced=29
+    eglCreatePlatformWindowSurface; # introduced=29
     eglCreateStreamFromFileDescriptorKHR; # introduced=23
     eglCreateStreamKHR; # introduced=23
     eglCreateStreamProducerSurfaceKHR; # introduced=23
+    eglCreateSync; # introduced=29
     eglCreateSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
     eglCreateWindowSurface;
     eglDestroyContext;
+    eglDestroyImage; # introduced=29
     eglDestroyImageKHR;
     eglDestroyStreamKHR; # introduced=23
     eglDestroySurface;
+    eglDestroySync; # introduced=29
     eglDestroySyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
     eglDupNativeFenceFDANDROID; # vndk
     eglGetConfigAttrib;
@@ -30,8 +37,10 @@
     eglGetDisplay;
     eglGetError;
     eglGetNativeClientBufferANDROID; # introduced=26
+    eglGetPlatformDisplay; # introduced=29
     eglGetProcAddress;
     eglGetStreamFileDescriptorKHR; # introduced=23
+    eglGetSyncAttrib; # introduced=29
     eglGetSyncAttribKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
     eglGetSystemTimeFrequencyNV; # introduced-arm=14 introduced-arm64=21 introduced-mips=14 introduced-mips64=21 introduced-x86=14 introduced-x86_64=21
     eglGetSystemTimeNV; # introduced-arm=14 introduced-arm64=21 introduced-mips=14 introduced-mips64=21 introduced-x86=14 introduced-x86_64=21
@@ -64,6 +73,7 @@
     eglWaitClient;
     eglWaitGL;
     eglWaitNative;
+    eglWaitSync; # introduced=29
     eglWaitSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
   local:
     *;
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 2cad986..2e984d9 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -2545,6 +2545,9 @@
     uint32_t policyFlags = args->policyFlags;
     int32_t flags = args->flags;
     int32_t metaState = args->metaState;
+    // InputDispatcher tracks and generates key repeats on behalf of
+    // whatever notifies it, so repeatCount should always be set to 0
+    constexpr int32_t repeatCount = 0;
     if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
         policyFlags |= POLICY_FLAG_VIRTUAL;
         flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
@@ -2560,7 +2563,7 @@
 
     KeyEvent event;
     event.initialize(args->deviceId, args->source, args->displayId, args->action,
-            flags, keyCode, args->scanCode, metaState, 0,
+            flags, keyCode, args->scanCode, metaState, repeatCount,
             args->downTime, args->eventTime);
 
     android::base::Timer t;
@@ -2585,7 +2588,6 @@
             mLock.lock();
         }
 
-        int32_t repeatCount = 0;
         KeyEntry* newEntry = new KeyEntry(args->eventTime,
                 args->deviceId, args->source, args->displayId, policyFlags,
                 args->action, flags, keyCode, args->scanCode,
@@ -2756,7 +2758,7 @@
         accelerateMetaShortcuts(keyEvent.getDeviceId(), action,
                 /*byref*/ keyCode, /*byref*/ metaState);
         keyEvent.initialize(keyEvent.getDeviceId(), keyEvent.getSource(), keyEvent.getDisplayId(),
-            action, flags, keyCode, keyEvent.getScanCode(), metaState, 0,
+            action, flags, keyCode, keyEvent.getScanCode(), metaState, keyEvent.getRepeatCount(),
             keyEvent.getDownTime(), keyEvent.getEventTime());
 
         if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) {
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 5df8ade..73098bf 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -470,8 +470,7 @@
     }
 
     // TODO(marissaw): properly support mTimeStats
-    mTimeStats.setLayerName(layerID, getName().c_str());
-    mTimeStats.setPostTime(layerID, getFrameNumber(), latchTime);
+    mTimeStats.setPostTime(layerID, getFrameNumber(), getName().c_str(), latchTime);
     mTimeStats.setAcquireFence(layerID, getFrameNumber(), getCurrentFenceTime());
     mTimeStats.setLatchTime(layerID, getFrameNumber(), latchTime);
 
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 88c3c8a..2e564e7 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1476,9 +1476,8 @@
 void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
                                      FrameEventHistoryDelta* outDelta) {
     if (newTimestamps) {
-        const int32_t layerID = getSequence();
-        mTimeStats.setLayerName(layerID, getName().c_str());
-        mTimeStats.setPostTime(layerID, newTimestamps->frameNumber, newTimestamps->postedTime);
+        mTimeStats.setPostTime(getSequence(), newTimestamps->frameNumber, getName().c_str(),
+                               newTimestamps->postedTime);
     }
 
     Mutex::Autolock lock(mFrameEventHistoryMutex);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index fc8ca54..5c31ada 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -196,8 +196,10 @@
 int SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault;
 bool SurfaceFlinger::useColorManagement;
 bool SurfaceFlinger::useContextPriority;
-Dataspace SurfaceFlinger::compositionDataSpace = Dataspace::V0_SRGB;
-ui::PixelFormat SurfaceFlinger::compositionPixelFormat = ui::PixelFormat::RGBA_8888;
+Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB;
+ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
+Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB;
+ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
 
 std::string getHwcServiceName() {
     char value[PROPERTY_VALUE_MAX] = {};
@@ -303,10 +305,13 @@
     auto surfaceFlingerConfigsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
     if (surfaceFlingerConfigsServiceV1_2) {
         surfaceFlingerConfigsServiceV1_2->getCompositionPreference(
-            [&](Dataspace tmpDataSpace, ui::PixelFormat tmpPixelFormat) {
-                compositionDataSpace = tmpDataSpace;
-                compositionPixelFormat = tmpPixelFormat;
-            });
+                [&](auto tmpDefaultDataspace, auto tmpDefaultPixelFormat,
+                    auto tmpWideColorGamutDataspace, auto tmpWideColorGamutPixelFormat) {
+                    defaultCompositionDataspace = tmpDefaultDataspace;
+                    defaultCompositionPixelFormat = tmpDefaultPixelFormat;
+                    wideColorGamutCompositionDataspace = tmpWideColorGamutDataspace;
+                    wideColorGamutCompositionPixelFormat = tmpWideColorGamutPixelFormat;
+                });
     }
 
     useContextPriority = getBool<ISurfaceFlingerConfigs,
@@ -638,8 +643,8 @@
 
     // TODO(b/77156734): We need to stop casting and use HAL types when possible.
     getBE().mRenderEngine =
-        renderengine::RenderEngine::create(static_cast<int32_t>(compositionPixelFormat),
-                                           renderEngineFeature);
+            renderengine::RenderEngine::create(static_cast<int32_t>(defaultCompositionPixelFormat),
+                                               renderEngineFeature);
     LOG_ALWAYS_FATAL_IF(getBE().mRenderEngine == nullptr, "couldn't create RenderEngine");
 
     LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
@@ -1157,10 +1162,14 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::getCompositionPreference(Dataspace* outDataSpace,
-                                                  ui::PixelFormat* outPixelFormat) const {
-    *outDataSpace = compositionDataSpace;
-    *outPixelFormat = compositionPixelFormat;
+status_t SurfaceFlinger::getCompositionPreference(
+        Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
+        Dataspace* outWideColorGamutDataspace,
+        ui::PixelFormat* outWideColorGamutPixelFormat) const {
+    *outDataspace = defaultCompositionDataspace;
+    *outPixelFormat = defaultCompositionPixelFormat;
+    *outWideColorGamutDataspace = wideColorGamutCompositionDataspace;
+    *outWideColorGamutPixelFormat = wideColorGamutCompositionPixelFormat;
     return NO_ERROR;
 }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 73c9d95..d60765c 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -294,8 +294,14 @@
     // The data space and pixel format that SurfaceFlinger expects hardware composer
     // to composite efficiently. Meaning under most scenarios, hardware composer
     // will accept layers with the data space and pixel format.
-    static ui::Dataspace compositionDataSpace;
-    static ui::PixelFormat compositionPixelFormat;
+    static ui::Dataspace defaultCompositionDataspace;
+    static ui::PixelFormat defaultCompositionPixelFormat;
+
+    // The data space and pixel format that SurfaceFlinger expects hardware composer
+    // to composite efficiently for wide color gamut surfaces. Meaning under most scenarios,
+    // hardware composer will accept layers with the data space and pixel format.
+    static ui::Dataspace wideColorGamutCompositionDataspace;
+    static ui::PixelFormat wideColorGamutCompositionPixelFormat;
 
     static char const* getServiceName() ANDROID_API {
         return "SurfaceFlinger";
@@ -460,9 +466,10 @@
     virtual status_t enableVSyncInjections(bool enable);
     virtual status_t injectVSync(nsecs_t when);
     virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const;
-    status_t getCompositionPreference(ui::Dataspace* outDataSpace,
-                                      ui::PixelFormat* outPixelFormat) const override;
     virtual bool isColorManagementUsed() const;
+    status_t getCompositionPreference(ui::Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
+                                      ui::Dataspace* outWideColorGamutDataspace,
+                                      ui::PixelFormat* outWideColorGamutPixelFormat) const override;
 
     /* ------------------------------------------------------------------------
      * DeathRecipient interface
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index c219afd..ace7c1b 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -241,25 +241,18 @@
     return std::regex_match(layerName.begin(), layerName.end(), layerNameRegex);
 }
 
-void TimeStats::setLayerName(int32_t layerID, const std::string& layerName) {
+void TimeStats::setPostTime(int32_t layerID, uint64_t frameNumber, const std::string& layerName,
+                            nsecs_t postTime) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
-    ALOGV("[%d]-[%s]", layerID, layerName.c_str());
+    ALOGV("[%d]-[%" PRIu64 "]-[%s]-PostTime[%" PRId64 "]", layerID, frameNumber, layerName.c_str(),
+          postTime);
 
     std::lock_guard<std::mutex> lock(mMutex);
     if (!mTimeStatsTracker.count(layerID) && layerNameIsValid(layerName)) {
         mTimeStatsTracker[layerID].layerName = layerName;
     }
-}
-
-void TimeStats::setPostTime(int32_t layerID, uint64_t frameNumber, nsecs_t postTime) {
-    if (!mEnabled.load()) return;
-
-    ATRACE_CALL();
-    ALOGV("[%d]-[%" PRIu64 "]-PostTime[%" PRId64 "]", layerID, frameNumber, postTime);
-
-    std::lock_guard<std::mutex> lock(mMutex);
     if (!mTimeStatsTracker.count(layerID)) return;
     LayerRecord& layerRecord = mTimeStatsTracker[layerID];
     if (layerRecord.timeRecords.size() == MAX_NUM_TIME_RECORDS) {
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index d1e554c..184bf40 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -86,8 +86,8 @@
     void incrementMissedFrames();
     void incrementClientCompositionFrames();
 
-    void setLayerName(int32_t layerID, const std::string& layerName);
-    void setPostTime(int32_t layerID, uint64_t frameNumber, nsecs_t postTime);
+    void setPostTime(int32_t layerID, uint64_t frameNumber, const std::string& layerName,
+                     nsecs_t postTime);
     void setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime);
     void setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime);
     void setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime);
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index ea9bb1f..5debd3d 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -45,7 +45,10 @@
         "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
     ],
     export_include_dirs: ["include"],
-    header_libs: ["libdvr_headers"],
+    header_libs: [
+        "libdvr_headers",
+        "libnativewindow_headers",
+    ],
     shared_libs: sharedLibraries,
     static_libs: [
         "libbufferhub",
diff --git a/services/vr/bufferhubd/buffer_channel.cpp b/services/vr/bufferhubd/buffer_channel.cpp
index a2fa0f1..589b31a 100644
--- a/services/vr/bufferhubd/buffer_channel.cpp
+++ b/services/vr/bufferhubd/buffer_channel.cpp
@@ -49,9 +49,9 @@
 
 BufferHubChannel::BufferInfo BufferChannel::GetBufferInfo() const {
   return BufferInfo(
-      buffer_id(), /*consumer_count=*/0, buffer_node_->buffer().width(),
-      buffer_node_->buffer().height(), buffer_node_->buffer().layer_count(),
-      buffer_node_->buffer().format(), buffer_node_->buffer().usage(),
+      buffer_id(), /*consumer_count=*/0, buffer_node_->buffer_desc().width,
+      buffer_node_->buffer_desc().height, buffer_node_->buffer_desc().layers,
+      buffer_node_->buffer_desc().format, buffer_node_->buffer_desc().usage,
       /*pending_count=*/0, /*state=*/0, /*signaled_mask=*/0,
       /*index=*/0);
 }
@@ -85,17 +85,17 @@
 
   // TODO(b/112057680) Move away from the GraphicBuffer-based IonBuffer.
   return BufferTraits<BorrowedHandle>{
-      /*buffer_handle=*/buffer_node_->buffer().handle(),
+      /*buffer_handle=*/buffer_node_->buffer_handle(),
       /*metadata_handle=*/buffer_node_->metadata().ashmem_handle().Borrow(),
       /*id=*/buffer_id(),
       /*client_state_mask=*/client_state_mask_,
       /*metadata_size=*/buffer_node_->metadata().metadata_size(),
-      /*width=*/buffer_node_->buffer().width(),
-      /*height=*/buffer_node_->buffer().height(),
-      /*layer_count=*/buffer_node_->buffer().layer_count(),
-      /*format=*/buffer_node_->buffer().format(),
-      /*usage=*/buffer_node_->buffer().usage(),
-      /*stride=*/buffer_node_->buffer().stride(),
+      /*width=*/buffer_node_->buffer_desc().width,
+      /*height=*/buffer_node_->buffer_desc().height,
+      /*layer_count=*/buffer_node_->buffer_desc().layers,
+      /*format=*/buffer_node_->buffer_desc().format,
+      /*usage=*/buffer_node_->buffer_desc().usage,
+      /*stride=*/buffer_node_->buffer_desc().stride,
       /*acquire_fence_fd=*/BorrowedHandle{},
       /*released_fence_fd=*/BorrowedHandle{}};
 }
diff --git a/services/vr/bufferhubd/buffer_node.cpp b/services/vr/bufferhubd/buffer_node.cpp
index 1eba4ae..31c6ef0 100644
--- a/services/vr/bufferhubd/buffer_node.cpp
+++ b/services/vr/bufferhubd/buffer_node.cpp
@@ -1,6 +1,9 @@
 #include <errno.h>
+
+#include <private/dvr/IBufferHub.h>
 #include <private/dvr/buffer_hub_defs.h>
 #include <private/dvr/buffer_node.h>
+#include <ui/GraphicBufferAllocator.h>
 
 namespace android {
 namespace dvr {
@@ -19,14 +22,26 @@
 BufferNode::BufferNode(uint32_t width, uint32_t height, uint32_t layer_count,
                        uint32_t format, uint64_t usage,
                        size_t user_metadata_size) {
-  if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
-    ALOGE(
-        "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
-        "buffer: %s",
-        strerror(-ret));
+  uint32_t out_stride = 0;
+  // graphicBufferId is not used in GraphicBufferAllocator::allocate
+  int ret = GraphicBufferAllocator::get().allocate(
+      width, height, format, layer_count, usage,
+      const_cast<const native_handle_t**>(&buffer_handle_), &out_stride,
+      /*graphicBufferId=*/0, IBufferHub::getServiceName());
+
+  if (ret != OK || buffer_handle_ == nullptr) {
+    ALOGE("BufferNode::BufferNode: Failed to allocate buffer: %s",
+          strerror(-ret));
     return;
   }
 
+  buffer_desc_.width = width;
+  buffer_desc_.height = height;
+  buffer_desc_.layers = layer_count;
+  buffer_desc_.format = format;
+  buffer_desc_.usage = usage;
+  buffer_desc_.stride = out_stride;
+
   metadata_ = BufferHubMetadata::Create(user_metadata_size);
   if (!metadata_.IsValid()) {
     ALOGE("BufferNode::BufferNode: Failed to allocate metadata.");
@@ -35,6 +50,17 @@
   InitializeMetadata();
 }
 
+// Free the handle
+BufferNode::~BufferNode() {
+  if (buffer_handle_ != nullptr) {
+    status_t ret = GraphicBufferAllocator::get().free(buffer_handle_);
+    if (ret != OK) {
+      ALOGE("BufferNode::~BufferNode: Failed to free handle; Got error: %d",
+            ret);
+    }
+  }
+}
+
 uint64_t BufferNode::GetActiveClientsBitMask() const {
   return active_clients_bit_mask_->load(std::memory_order_acquire);
 }
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_node.h b/services/vr/bufferhubd/include/private/dvr/buffer_node.h
index 4f356f0..bc0a34e 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_node.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_node.h
@@ -1,6 +1,7 @@
 #ifndef ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
 #define ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
 
+#include <android/hardware_buffer.h>
 #include <private/dvr/ion_buffer.h>
 #include <ui/BufferHubMetadata.h>
 
@@ -13,14 +14,16 @@
   BufferNode(uint32_t width, uint32_t height, uint32_t layer_count,
              uint32_t format, uint64_t usage, size_t user_metadata_size);
 
-  // Returns whether the object holds a valid graphic buffer.
-  bool IsValid() const { return buffer_.IsValid() && metadata_.IsValid(); }
+  ~BufferNode();
+
+  // Returns whether the object holds a valid metadata.
+  bool IsValid() const { return metadata_.IsValid(); }
 
   size_t user_metadata_size() const { return metadata_.user_metadata_size(); }
 
-  // Accessors of the IonBuffer.
-  IonBuffer& buffer() { return buffer_; }
-  const IonBuffer& buffer() const { return buffer_; }
+  // Accessors of the buffer description and handle
+  const native_handle_t* buffer_handle() const { return buffer_handle_; }
+  const AHardwareBuffer_Desc& buffer_desc() const { return buffer_desc_; }
 
   // Accessors of metadata.
   const BufferHubMetadata& metadata() const { return metadata_; }
@@ -48,7 +51,8 @@
   void InitializeMetadata();
 
   // Gralloc buffer handles.
-  IonBuffer buffer_;
+  native_handle_t* buffer_handle_;
+  AHardwareBuffer_Desc buffer_desc_;
 
   // Metadata in shared memory.
   BufferHubMetadata metadata_;
diff --git a/services/vr/bufferhubd/tests/Android.bp b/services/vr/bufferhubd/tests/Android.bp
index a80691f..c77d2d2 100644
--- a/services/vr/bufferhubd/tests/Android.bp
+++ b/services/vr/bufferhubd/tests/Android.bp
@@ -33,7 +33,10 @@
         "-DTRACE=0",
         "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
     ],
-    header_libs: ["libdvr_headers"],
+    header_libs: [
+        "libdvr_headers",
+        "libnativewindow_headers",
+    ],
     static_libs: [
         "libbufferhub",
         "libbufferhubd",
diff --git a/services/vr/bufferhubd/tests/buffer_node-test.cpp b/services/vr/bufferhubd/tests/buffer_node-test.cpp
index 6671e97..30ecbec 100644
--- a/services/vr/bufferhubd/tests/buffer_node-test.cpp
+++ b/services/vr/bufferhubd/tests/buffer_node-test.cpp
@@ -2,12 +2,15 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <private/dvr/buffer_node.h>
+#include <ui/GraphicBufferMapper.h>
 
 namespace android {
 namespace dvr {
 
 namespace {
 
+using testing::NotNull;
+
 const uint32_t kWidth = 640;
 const uint32_t kHeight = 480;
 const uint32_t kLayerCount = 1;
@@ -35,6 +38,16 @@
 
 TEST_F(BufferNodeTest, TestCreateBufferNode) {
   EXPECT_EQ(buffer_node->user_metadata_size(), kUserMetadataSize);
+  // Test the handle just allocated is good (i.e. able to be imported)
+  GraphicBufferMapper& mapper = GraphicBufferMapper::get();
+  const native_handle_t* outHandle;
+  status_t ret = mapper.importBuffer(
+      buffer_node->buffer_handle(), buffer_node->buffer_desc().width,
+      buffer_node->buffer_desc().height, buffer_node->buffer_desc().layers,
+      buffer_node->buffer_desc().format, buffer_node->buffer_desc().usage,
+      buffer_node->buffer_desc().stride, &outHandle);
+  EXPECT_EQ(ret, OK);
+  EXPECT_THAT(outHandle, NotNull());
 }
 
 TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_twoNewClients) {