Merge "SF: Fix mBuffer management"
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 562898d..b04543b 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -76,6 +76,7 @@
         "libdebuggerd_client",
         "libdumpstateaidl",
         "libdumpstateutil",
+        "libdumputils",
         "libhidlbase",
         "libhidltransport",
         "liblog",
@@ -119,4 +120,4 @@
         "tests/dumpstate_smoke_test.cpp",
     ],
     static_libs: ["libgmock"],
-}
\ No newline at end of file
+}
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index a89925f..022f4fc 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -48,10 +48,10 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
 #include <cutils/properties.h>
 #include <cutils/sockets.h>
 #include <debuggerd/client.h>
+#include <dumputils/dump_utils.h>
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
 
@@ -76,36 +76,6 @@
     return ds.RunCommand(title, full_command, options);
 }
 
-/* list of native processes to include in the native dumps */
-// This matches the /proc/pid/exe link instead of /proc/pid/cmdline.
-static const char* native_processes_to_dump[] = {
-        "/system/bin/audioserver",
-        "/system/bin/cameraserver",
-        "/system/bin/drmserver",
-        "/system/bin/mediadrmserver",
-        "/system/bin/mediaextractor", // media.extractor
-        "/system/bin/mediametrics", // media.metrics
-        "/system/bin/mediaserver",
-        "/system/bin/sdcard",
-	"/system/bin/statsd",
-        "/system/bin/surfaceflinger",
-        "/system/bin/vehicle_network_service",
-        "/vendor/bin/hw/android.hardware.media.omx@1.0-service", // media.codec
-        NULL,
-};
-
-/* list of hal interface to dump containing process during native dumps */
-static const char* hal_interfaces_to_dump[] {
-        "android.hardware.audio@2.0::IDevicesFactory",
-        "android.hardware.bluetooth@1.0::IBluetoothHci",
-        "android.hardware.camera.provider@2.4::ICameraProvider",
-        "android.hardware.graphics.composer@2.1::IComposer",
-        "android.hardware.media.omx@1.0::IOmx",
-        "android.hardware.sensors@1.0::ISensors",
-        "android.hardware.vr@1.0::IVr",
-        NULL,
-};
-
 // Reasonable value for max stats.
 static const int STATS_MAX_N_RUNS = 1000;
 static const long STATS_MAX_AVERAGE = 100000;
@@ -809,53 +779,6 @@
     _redirect_to_file(redirect, path, O_APPEND);
 }
 
-static bool should_dump_hal_interface(const char* interface) {
-    for (const char** i = hal_interfaces_to_dump; *i; i++) {
-        if (!strcmp(*i, interface)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-static bool should_dump_native_traces(const char* path) {
-    for (const char** p = native_processes_to_dump; *p; p++) {
-        if (!strcmp(*p, path)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-std::set<int> get_interesting_hal_pids() {
-    using android::hidl::manager::V1_0::IServiceManager;
-    using android::sp;
-    using android::hardware::Return;
-
-    sp<IServiceManager> manager = IServiceManager::getService();
-    std::set<int> pids;
-
-    Return<void> ret = manager->debugDump([&](auto& hals) {
-        for (const auto &info : hals) {
-            if (info.pid == static_cast<int>(IServiceManager::PidConstant::NO_PID)) {
-                continue;
-            }
-
-            if (!should_dump_hal_interface(info.interfaceName.c_str())) {
-                continue;
-            }
-
-            pids.insert(info.pid);
-        }
-    });
-
-    if (!ret.isOk()) {
-        MYLOGE("Could not get list of HAL PIDs: %s\n", ret.description().c_str());
-    }
-
-    return pids; // whether it was okay or not
-}
-
 const char* DumpTraces(const std::string& traces_path);
 const char* DumpTracesTombstoned(const std::string& traces_dir);
 
@@ -876,18 +799,6 @@
     return nullptr;
 }
 
-static bool IsZygote(int pid) {
-    static const std::string kZygotePrefix = "zygote";
-
-    std::string cmdline;
-    if (!android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid),
-                                         &cmdline)) {
-        return true;
-    }
-
-    return (cmdline.find(kZygotePrefix) == 0);
-}
-
 const char* DumpTracesTombstoned(const std::string& traces_dir) {
     const std::string temp_file_pattern = traces_dir + "/dumptrace_XXXXXX";
 
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 7438d3d..739f33f 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -1,6 +1,7 @@
 // Build the unit tests for installd
 cc_test {
     name: "installd_utils_test",
+    test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_utils_test.cpp"],
     cflags: ["-Wall", "-Werror"],
@@ -18,6 +19,7 @@
 
 cc_test {
     name: "installd_cache_test",
+    test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_cache_test.cpp"],
     cflags: ["-Wall", "-Werror"],
@@ -39,6 +41,7 @@
 
 cc_test {
     name: "installd_service_test",
+    test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_service_test.cpp"],
     cflags: ["-Wall", "-Werror"],
@@ -60,6 +63,7 @@
 
 cc_test {
     name: "installd_dexopt_test",
+    test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_dexopt_test.cpp"],
     cflags: ["-Wall", "-Werror"],
@@ -81,6 +85,7 @@
 
 cc_test {
     name: "installd_otapreopt_test",
+    test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_otapreopt_test.cpp"],
     cflags: ["-Wall", "-Werror"],
diff --git a/cmds/lshal/DebugCommand.cpp b/cmds/lshal/DebugCommand.cpp
index dd8812d..0952db6 100644
--- a/cmds/lshal/DebugCommand.cpp
+++ b/cmds/lshal/DebugCommand.cpp
@@ -59,8 +59,8 @@
 
     auto pair = splitFirst(mInterfaceName, '/');
 
-    FQName fqName(pair.first);
-    if (!fqName.isValid() || fqName.isIdentifier() || !fqName.isFullyQualified()) {
+    FQName fqName;
+    if (!FQName::parse(pair.first, &fqName) || fqName.isIdentifier() || !fqName.isFullyQualified()) {
         mLshal.err() << "Invalid fully-qualified name '" << pair.first << "'\n\n";
         return USAGE;
     }
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index b9e0139..5545966 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -252,16 +252,16 @@
     // use a double for loop here because lshal doesn't care about efficiency.
     for (TableEntry &packageEntry : mImplementationsTable) {
         std::string packageName = packageEntry.interfaceName;
-        FQName fqPackageName{packageName.substr(0, packageName.find("::"))};
-        if (!fqPackageName.isValid()) {
+        FQName fqPackageName;
+        if (!FQName::parse(packageName.substr(0, packageName.find("::")), &fqPackageName)) {
             continue;
         }
         for (TableEntry &interfaceEntry : mPassthroughRefTable) {
             if (interfaceEntry.arch != ARCH_UNKNOWN) {
                 continue;
             }
-            FQName interfaceName{splitFirst(interfaceEntry.interfaceName, '/').first};
-            if (!interfaceName.isValid()) {
+            FQName interfaceName;
+            if (!FQName::parse(splitFirst(interfaceEntry.interfaceName, '/').first, &interfaceName)) {
                 continue;
             }
             if (interfaceName.getPackageAndVersion() == fqPackageName) {
@@ -308,10 +308,10 @@
                 // Quick hack to work around *'s
                 replaceAll(&fqInstanceName, '*', 'D');
             }
-            auto splittedFqInstanceName = splitFirst(fqInstanceName, '/');
-            FQName fqName(splittedFqInstanceName.first);
-            if (!fqName.isValid()) {
-                err() << "Warning: '" << splittedFqInstanceName.first
+            auto splitFqInstanceName = splitFirst(fqInstanceName, '/');
+            FQName fqName;
+            if (!FQName::parse(splitFqInstanceName.first, &fqName)) {
+                err() << "Warning: '" << splitFqInstanceName.first
                      << "' is not a valid FQName." << std::endl;
                 continue;
             }
@@ -335,7 +335,7 @@
             std::string interfaceName =
                     &table == &mImplementationsTable ? "" : fqName.name();
             std::string instanceName =
-                    &table == &mImplementationsTable ? "" : splittedFqInstanceName.second;
+                    &table == &mImplementationsTable ? "" : splitFqInstanceName.second;
 
             vintf::Version version{fqName.getPackageMajorVersion(),
                                    fqName.getPackageMinorVersion()};
diff --git a/data/etc/wearable_core_hardware.xml b/data/etc/wearable_core_hardware.xml
index d7c3730..e2ab71a 100644
--- a/data/etc/wearable_core_hardware.xml
+++ b/data/etc/wearable_core_hardware.xml
@@ -36,9 +36,6 @@
     <!-- basic system services -->
     <feature name="android.software.home_screen" />
 
-    <!-- device administration -->
-    <feature name="android.software.device_admin" />
-
     <!-- input management and third-party input method editors -->
     <feature name="android.software.input_methods" />
 
diff --git a/libs/dumputils/Android.bp b/libs/dumputils/Android.bp
new file mode 100644
index 0000000..3412e14
--- /dev/null
+++ b/libs/dumputils/Android.bp
@@ -0,0 +1,34 @@
+// 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.
+
+cc_library {
+    name: "libdumputils",
+
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+
+    srcs: ["dump_utils.cpp"],
+
+    cflags: ["-Wall", "-Werror"],
+
+    export_include_dirs: [
+        "include",
+    ],
+}
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
new file mode 100644
index 0000000..0fd2b81
--- /dev/null
+++ b/libs/dumputils/dump_utils.cpp
@@ -0,0 +1,111 @@
+/*
+ * 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 <set>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <dumputils/dump_utils.h>
+#include <log/log.h>
+
+/* list of native processes to include in the native dumps */
+// This matches the /proc/pid/exe link instead of /proc/pid/cmdline.
+static const char* native_processes_to_dump[] = {
+        "/system/bin/audioserver",
+        "/system/bin/cameraserver",
+        "/system/bin/drmserver",
+        "/system/bin/mediadrmserver",
+        "/system/bin/mediaextractor", // media.extractor
+        "/system/bin/mediametrics", // media.metrics
+        "/system/bin/mediaserver",
+        "/system/bin/sdcard",
+        "/system/bin/statsd",
+        "/system/bin/surfaceflinger",
+        "/system/bin/vehicle_network_service",
+        "/vendor/bin/hw/android.hardware.media.omx@1.0-service", // media.codec
+        NULL,
+};
+
+/* list of hal interface to dump containing process during native dumps */
+static const char* hal_interfaces_to_dump[] {
+        "android.hardware.audio@2.0::IDevicesFactory",
+        "android.hardware.bluetooth@1.0::IBluetoothHci",
+        "android.hardware.camera.provider@2.4::ICameraProvider",
+        "android.hardware.graphics.composer@2.1::IComposer",
+        "android.hardware.media.omx@1.0::IOmx",
+        "android.hardware.sensors@1.0::ISensors",
+        "android.hardware.vr@1.0::IVr",
+        NULL,
+};
+
+bool should_dump_hal_interface(const char* interface) {
+    for (const char** i = hal_interfaces_to_dump; *i; i++) {
+        if (!strcmp(*i, interface)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool should_dump_native_traces(const char* path) {
+    for (const char** p = native_processes_to_dump; *p; p++) {
+        if (!strcmp(*p, path)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+std::set<int> get_interesting_hal_pids() {
+    using android::hidl::manager::V1_0::IServiceManager;
+    using android::sp;
+    using android::hardware::Return;
+
+    sp<IServiceManager> manager = IServiceManager::getService();
+    std::set<int> pids;
+
+    Return<void> ret = manager->debugDump([&](auto& hals) {
+        for (const auto &info : hals) {
+            if (info.pid == static_cast<int>(IServiceManager::PidConstant::NO_PID)) {
+                continue;
+            }
+
+            if (!should_dump_hal_interface(info.interfaceName.c_str())) {
+                continue;
+            }
+
+            pids.insert(info.pid);
+        }
+    });
+
+    if (!ret.isOk()) {
+        ALOGE("Could not get list of HAL PIDs: %s\n", ret.description().c_str());
+    }
+
+    return pids; // whether it was okay or not
+}
+
+bool IsZygote(int pid) {
+    static const std::string kZygotePrefix = "zygote";
+
+    std::string cmdline;
+    if (!android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid),
+                                         &cmdline)) {
+        return true;
+    }
+
+    return (cmdline.find(kZygotePrefix) == 0);
+}
diff --git a/libs/dumputils/include/dumputils/dump_utils.h b/libs/dumputils/include/dumputils/dump_utils.h
new file mode 100644
index 0000000..25f7127
--- /dev/null
+++ b/libs/dumputils/include/dumputils/dump_utils.h
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DUMPUTILS_H_
+#define DUMPUTILS_H_
+
+#include <set>
+
+bool should_dump_native_traces(const char* path);
+
+std::set<int> get_interesting_hal_pids();
+
+bool IsZygote(int pid);
+
+#endif  // DUMPUTILS_H_
diff --git a/libs/gui/HdrMetadata.cpp b/libs/gui/HdrMetadata.cpp
index 299bdfa..b715e43 100644
--- a/libs/gui/HdrMetadata.cpp
+++ b/libs/gui/HdrMetadata.cpp
@@ -66,4 +66,32 @@
     return NO_ERROR;
 }
 
+bool HdrMetadata::operator==(const HdrMetadata& rhs) const {
+    if (validTypes != rhs.validTypes) return false;
+
+    if ((validTypes & SMPTE2086) == SMPTE2086) {
+        if (smpte2086.displayPrimaryRed.x != rhs.smpte2086.displayPrimaryRed.x ||
+            smpte2086.displayPrimaryRed.y != rhs.smpte2086.displayPrimaryRed.y ||
+            smpte2086.displayPrimaryGreen.x != rhs.smpte2086.displayPrimaryGreen.x ||
+            smpte2086.displayPrimaryGreen.y != rhs.smpte2086.displayPrimaryGreen.y ||
+            smpte2086.displayPrimaryBlue.x != rhs.smpte2086.displayPrimaryBlue.x ||
+            smpte2086.displayPrimaryBlue.y != rhs.smpte2086.displayPrimaryBlue.y ||
+            smpte2086.whitePoint.x != rhs.smpte2086.whitePoint.x ||
+            smpte2086.whitePoint.y != rhs.smpte2086.whitePoint.y ||
+            smpte2086.maxLuminance != rhs.smpte2086.maxLuminance ||
+            smpte2086.minLuminance != rhs.smpte2086.minLuminance) {
+            return false;
+        }
+    }
+
+    if ((validTypes & CTA861_3) == CTA861_3) {
+        if (cta8613.maxFrameAverageLightLevel != rhs.cta8613.maxFrameAverageLightLevel ||
+            cta8613.maxContentLightLevel != rhs.cta8613.maxContentLightLevel) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
 } // namespace android
diff --git a/libs/gui/include/gui/HdrMetadata.h b/libs/gui/include/gui/HdrMetadata.h
index cd01952..9800602 100644
--- a/libs/gui/include/gui/HdrMetadata.h
+++ b/libs/gui/include/gui/HdrMetadata.h
@@ -38,6 +38,8 @@
     size_t getFlattenedSize() const;
     status_t flatten(void* buffer, size_t size) const;
     status_t unflatten(void const* buffer, size_t size);
+
+    bool operator==(const HdrMetadata& rhs) const;
 };
 
 } // namespace android
diff --git a/libs/vr/libdvr/tests/dvr_api_test.h b/libs/vr/libdvr/tests/dvr_api_test.h
index 648af75..d8359e7 100644
--- a/libs/vr/libdvr/tests/dvr_api_test.h
+++ b/libs/vr/libdvr/tests/dvr_api_test.h
@@ -3,8 +3,6 @@
 
 #include <gtest/gtest.h>
 
-#define ASSERT_NOT_NULL(x) ASSERT_TRUE((x) != nullptr)
-
 /** DvrTestBase loads the libdvr.so at runtime and get the Dvr API version 1. */
 class DvrApiTest : public ::testing::Test {
  protected:
@@ -17,11 +15,11 @@
     // https://github.com/android-ndk/ndk/issues/360
     flags |= RTLD_NODELETE;
     platform_handle_ = dlopen("libdvr.so", flags);
-    ASSERT_NOT_NULL(platform_handle_) << "Dvr shared library missing.";
+    ASSERT_NE(nullptr, platform_handle_) << "Dvr shared library missing.";
 
     auto dvr_get_api = reinterpret_cast<decltype(&dvrGetApi)>(
         dlsym(platform_handle_, "dvrGetApi"));
-    ASSERT_NOT_NULL(dvr_get_api) << "Platform library missing dvrGetApi.";
+    ASSERT_NE(nullptr, dvr_get_api) << "Platform library missing dvrGetApi.";
 
     ASSERT_EQ(dvr_get_api(&api_, sizeof(api_), /*version=*/1), 0)
         << "Unable to find compatible Dvr API.";
diff --git a/libs/vr/libdvr/tests/dvr_display-test.cpp b/libs/vr/libdvr/tests/dvr_display-test.cpp
index 1165573..c72f940 100644
--- a/libs/vr/libdvr/tests/dvr_display-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_display-test.cpp
@@ -16,20 +16,58 @@
 
 class DvrDisplayTest : public DvrApiTest {
  protected:
+  void SetUp() override {
+    DvrApiTest::SetUp();
+    int ret = api_.GetNativeDisplayMetrics(sizeof(display_metrics_),
+                                           &display_metrics_);
+    ASSERT_EQ(ret, 0) << "Failed to get display metrics.";
+    ALOGD(
+        "display_width: %d, display_height: %d, display_x_dpi: %d, "
+        "display_y_dpi: %d, vsync_period_ns: %d.",
+        display_metrics_.display_width, display_metrics_.display_height,
+        display_metrics_.display_x_dpi, display_metrics_.display_y_dpi,
+        display_metrics_.vsync_period_ns);
+  }
+
   void TearDown() override {
     if (write_queue_ != nullptr) {
       api_.WriteBufferQueueDestroy(write_queue_);
       write_queue_ = nullptr;
     }
+    if (direct_surface_ != nullptr) {
+      api_.SurfaceDestroy(direct_surface_);
+      direct_surface_ = nullptr;
+    }
     DvrApiTest::TearDown();
   }
 
+  /* Convert a write buffer to an android hardware buffer and fill in
+   * color_textures evenly to the buffer.
+   * AssertionError if the width of the buffer is not equal to the input width,
+   * AssertionError if the height of the buffer is not equal to the input
+   * height.
+   */
+  void FillWriteBuffer(DvrWriteBuffer* write_buffer,
+                       const std::vector<uint32_t>& color_textures,
+                       uint32_t width, uint32_t height);
+
+  // Write buffer queue properties.
+  static constexpr uint64_t kUsage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
+                                     AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
+                                     AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+  uint32_t kFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+  static constexpr size_t kMetadataSize = 0;
+  static constexpr int kTimeoutMs = 1000;  // Time for getting buffer.
+  uint32_t kLayerCount = 1;
   DvrWriteBufferQueue* write_queue_ = nullptr;
+  DvrSurface* direct_surface_ = nullptr;
+
+  // Device display properties.
+  DvrNativeDisplayMetrics display_metrics_;
 };
 
-TEST_F(DvrDisplayTest, DisplaySingleColor) {
-  // Create direct surface.
-  DvrSurface* direct_surface = nullptr;
+TEST_F(DvrDisplayTest, DisplayWithOneBuffer) {
+  // Create a direct surface.
   std::vector<DvrSurfaceAttribute> direct_surface_attributes = {
       {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
        .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
@@ -43,73 +81,32 @@
   };
   int ret =
       api_.SurfaceCreate(direct_surface_attributes.data(),
-                         direct_surface_attributes.size(), &direct_surface);
+                         direct_surface_attributes.size(), &direct_surface_);
   ASSERT_EQ(ret, 0) << "Failed to create direct surface.";
 
-  // Get screen dimension.
-  DvrNativeDisplayMetrics display_metrics;
-  ret = api_.GetNativeDisplayMetrics(sizeof(display_metrics), &display_metrics);
-  ASSERT_EQ(ret, 0) << "Failed to get display metrics.";
-  ALOGD(
-      "display_width: %d, display_height: %d, display_x_dpi: %d, "
-      "display_y_dpi: %d, vsync_period_ns: %d.",
-      display_metrics.display_width, display_metrics.display_height,
-      display_metrics.display_x_dpi, display_metrics.display_y_dpi,
-      display_metrics.vsync_period_ns);
-
   // Create a buffer queue with the direct surface.
-  constexpr uint32_t kLayerCount = 1;
-  constexpr uint64_t kUsage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
-                              AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
-                              AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
-  constexpr uint32_t kFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
   constexpr size_t kCapacity = 1;
-  constexpr size_t kMetadataSize = 0;
-  uint32_t width = display_metrics.display_width;
-  uint32_t height = display_metrics.display_height;
+  uint32_t width = display_metrics_.display_width;
+  uint32_t height = display_metrics_.display_height;
   ret = api_.SurfaceCreateWriteBufferQueue(
-      direct_surface, width, height, kFormat, kLayerCount, kUsage, kCapacity,
+      direct_surface_, width, height, kFormat, kLayerCount, kUsage, kCapacity,
       kMetadataSize, &write_queue_);
   EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
-  ASSERT_NOT_NULL(write_queue_) << "Write buffer queue should not be null.";
+  ASSERT_NE(nullptr, write_queue_) << "Write buffer queue should not be null.";
 
   // Get buffer from WriteBufferQueue.
   DvrWriteBuffer* write_buffer = nullptr;
-  constexpr int kTimeoutMs = 1000;
   DvrNativeBufferMetadata out_meta;
   int out_fence_fd = -1;
   ret = api_.WriteBufferQueueGainBuffer(write_queue_, kTimeoutMs, &write_buffer,
                                         &out_meta, &out_fence_fd);
   EXPECT_EQ(0, ret) << "Failed to get the buffer.";
-  ASSERT_NOT_NULL(write_buffer) << "Gained buffer should not be null.";
+  ASSERT_NE(nullptr, write_buffer) << "Gained buffer should not be null.";
 
-  // Convert to an android hardware buffer.
-  AHardwareBuffer* ah_buffer{nullptr};
-  ret = api_.WriteBufferGetAHardwareBuffer(write_buffer, &ah_buffer);
-  EXPECT_EQ(0, ret) << "Failed to get a hardware buffer from the write buffer.";
-  ASSERT_NOT_NULL(ah_buffer) << "AHardware buffer should not be null.";
-
-  // Change the content of the android hardware buffer.
-  void* buffer_data{nullptr};
-  int32_t fence = -1;
-  ret = AHardwareBuffer_lock(ah_buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
-                             fence, nullptr, &buffer_data);
-  EXPECT_EQ(0, ret) << "Failed to lock the hardware buffer.";
-  ASSERT_NOT_NULL(buffer_data) << "Buffer data should not be null.";
-
-  uint32_t color_texture = 0xff0000ff;  // Red color in RGBA.
-  for (uint32_t i = 0; i < width * height; ++i) {
-    memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) +
-                                   i * sizeof(color_texture)),
-           &color_texture, sizeof(color_texture));
-  }
-
-  fence = -1;
-  ret = AHardwareBuffer_unlock(ah_buffer, &fence);
-  EXPECT_EQ(0, ret) << "Failed to unlock the hardware buffer.";
-
-  // Release the android hardware buffer.
-  AHardwareBuffer_release(ah_buffer);
+  // Color the write buffer.
+  FillWriteBuffer(write_buffer,
+                  {0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000},
+                  width, height);
 
   // Post buffer.
   int ready_fence_fd = -1;
@@ -118,4 +115,237 @@
   EXPECT_EQ(0, ret) << "Failed to post the buffer.";
 
   sleep(5);  // For visual check on the device under test.
+  // Should observe three primary colors on the screen center.
+}
+
+TEST_F(DvrDisplayTest, DisplayWithDoubleBuffering) {
+  // Create a direct surface.
+  std::vector<DvrSurfaceAttribute> direct_surface_attributes = {
+      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
+       .value.int32_value = 10},
+      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+  };
+  int ret =
+      api_.SurfaceCreate(direct_surface_attributes.data(),
+                         direct_surface_attributes.size(), &direct_surface_);
+  ASSERT_EQ(ret, 0) << "Failed to create direct surface.";
+
+  // Create a buffer queue with the direct surface.
+  constexpr size_t kCapacity = 2;
+  uint32_t width = display_metrics_.display_width;
+  uint32_t height = display_metrics_.display_height;
+  ret = api_.SurfaceCreateWriteBufferQueue(
+      direct_surface_, width, height, kFormat, kLayerCount, kUsage, kCapacity,
+      kMetadataSize, &write_queue_);
+  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
+  ASSERT_NE(nullptr, write_queue_) << "Write buffer queue should not be null.";
+
+  int num_display_cycles_in_5s = 5 / (display_metrics_.vsync_period_ns / 1e9);
+  ALOGD("The number of display cycles: %d", num_display_cycles_in_5s);
+  int bufferhub_id_prev_write_buffer = -1;
+  for (int i = 0; i < num_display_cycles_in_5s; ++i) {
+    // Get a buffer from the WriteBufferQueue.
+    DvrWriteBuffer* write_buffer = nullptr;
+    DvrNativeBufferMetadata out_meta;
+    int out_fence_fd = -1;
+    ret = api_.WriteBufferQueueGainBuffer(
+        write_queue_, kTimeoutMs, &write_buffer, &out_meta, &out_fence_fd);
+    EXPECT_EQ(0, ret) << "Failed to get the a write buffer.";
+    ASSERT_NE(nullptr, write_buffer) << "The gained buffer should not be null.";
+
+    int bufferhub_id = api_.WriteBufferGetId(write_buffer);
+    ALOGD("Display cycle: %d, bufferhub id of the write buffer: %d", i,
+          bufferhub_id);
+    EXPECT_NE(bufferhub_id_prev_write_buffer, bufferhub_id)
+        << "Double buffering should be using the two buffers in turns, not "
+           "reusing the same write buffer.";
+    bufferhub_id_prev_write_buffer = bufferhub_id;
+
+    // Color the write buffer.
+    if (i % 2) {
+      FillWriteBuffer(write_buffer, {0xffff0000, 0xff00ff00, 0xff0000ff}, width,
+                      height);
+    } else {
+      FillWriteBuffer(write_buffer, {0xff00ff00, 0xff0000ff, 0xffff0000}, width,
+                      height);
+    }
+
+    // Post the write buffer.
+    int ready_fence_fd = -1;
+    ret = api_.WriteBufferQueuePostBuffer(write_queue_, write_buffer, &out_meta,
+                                          ready_fence_fd);
+    EXPECT_EQ(0, ret) << "Failed to post the buffer.";
+  }
+  // Should observe blinking screen in secondary colors
+  // although it is actually displaying primary colors.
+}
+
+TEST_F(DvrDisplayTest, DisplayWithTwoHardwareLayers) {
+  // Create the direct_surface_0 of z order 10 and direct_surface_1 of z
+  // order 11.
+  DvrSurface* direct_surface_0 = nullptr;
+  std::vector<DvrSurfaceAttribute> direct_surface_0_attributes = {
+      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
+       .value.int32_value = 10},
+      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+  };
+  int ret =
+      api_.SurfaceCreate(direct_surface_0_attributes.data(),
+                         direct_surface_0_attributes.size(), &direct_surface_0);
+  EXPECT_EQ(ret, 0) << "Failed to create direct surface.";
+
+  DvrSurface* direct_surface_1 = nullptr;
+  std::vector<DvrSurfaceAttribute> direct_surface_1_attributes = {
+      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
+       .value.int32_value = 11},
+      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+  };
+  ret =
+      api_.SurfaceCreate(direct_surface_1_attributes.data(),
+                         direct_surface_1_attributes.size(), &direct_surface_1);
+  EXPECT_EQ(ret, 0) << "Failed to create direct surface.";
+
+  // Create a buffer queue for each of the direct surfaces.
+  constexpr size_t kCapacity = 1;
+  uint32_t width = display_metrics_.display_width;
+  uint32_t height = display_metrics_.display_height;
+
+  DvrWriteBufferQueue* write_queue_0 = nullptr;
+  ret = api_.SurfaceCreateWriteBufferQueue(
+      direct_surface_0, width, height, kFormat, kLayerCount, kUsage, kCapacity,
+      kMetadataSize, &write_queue_0);
+  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
+  EXPECT_NE(nullptr, write_queue_0) << "Write buffer queue should not be null.";
+
+  DvrWriteBufferQueue* write_queue_1 = nullptr;
+  ret = api_.SurfaceCreateWriteBufferQueue(
+      direct_surface_1, width, height, kFormat, kLayerCount, kUsage, kCapacity,
+      kMetadataSize, &write_queue_1);
+  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
+  EXPECT_NE(nullptr, write_queue_1) << "Write buffer queue should not be null.";
+
+  // Get a buffer from each of the write buffer queues.
+  DvrWriteBuffer* write_buffer_0 = nullptr;
+  DvrNativeBufferMetadata out_meta_0;
+  int out_fence_fd = -1;
+  ret = api_.WriteBufferQueueGainBuffer(
+      write_queue_0, kTimeoutMs, &write_buffer_0, &out_meta_0, &out_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to get the buffer.";
+  EXPECT_NE(nullptr, write_buffer_0) << "Gained buffer should not be null.";
+
+  DvrWriteBuffer* write_buffer_1 = nullptr;
+  DvrNativeBufferMetadata out_meta_1;
+  out_fence_fd = -1;
+  ret = api_.WriteBufferQueueGainBuffer(
+      write_queue_1, kTimeoutMs, &write_buffer_1, &out_meta_1, &out_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to get the buffer.";
+  EXPECT_NE(nullptr, write_buffer_1) << "Gained buffer should not be null.";
+
+  // Color the write buffers.
+  FillWriteBuffer(write_buffer_0, {0xffff0000, 0xff00ff00, 0xff0000ff}, width,
+                  height);
+  FillWriteBuffer(write_buffer_1, {0x7f00ff00, 0x7f0000ff, 0x7fff0000}, width,
+                  height);
+
+  // Post buffers.
+  int ready_fence_fd = -1;
+  ret = api_.WriteBufferQueuePostBuffer(write_queue_0, write_buffer_0,
+                                        &out_meta_0, ready_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to post the buffer.";
+
+  ready_fence_fd = -1;
+  ret = api_.WriteBufferQueuePostBuffer(write_queue_1, write_buffer_1,
+                                        &out_meta_1, ready_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to post the buffer.";
+
+  sleep(5);  // For visual check on the device under test.
+  // Should observe three secondary colors.
+
+  // Test finished. Clean up buffers and surfaces.
+  if (write_queue_0 != nullptr) {
+    api_.WriteBufferQueueDestroy(write_queue_0);
+    write_queue_0 = nullptr;
+  }
+  if (write_queue_1 != nullptr) {
+    api_.WriteBufferQueueDestroy(write_queue_1);
+    write_queue_1 = nullptr;
+  }
+  if (direct_surface_0 != nullptr) {
+    api_.SurfaceDestroy(direct_surface_0);
+  }
+  if (direct_surface_1 != nullptr) {
+    api_.SurfaceDestroy(direct_surface_1);
+  }
+}
+
+void DvrDisplayTest::FillWriteBuffer(
+    DvrWriteBuffer* write_buffer, const std::vector<uint32_t>& color_textures,
+    uint32_t width, uint32_t height) {
+  uint32_t num_colors = color_textures.size();
+  // Convert the first write buffer to an android hardware buffer.
+  AHardwareBuffer* ah_buffer = nullptr;
+  int ret = api_.WriteBufferGetAHardwareBuffer(write_buffer, &ah_buffer);
+  ASSERT_EQ(0, ret) << "Failed to get a hardware buffer from the write buffer.";
+  ASSERT_NE(nullptr, ah_buffer) << "AHardware buffer should not be null.";
+  AHardwareBuffer_Desc ah_buffer_describe;
+  AHardwareBuffer_describe(ah_buffer, &ah_buffer_describe);
+  ASSERT_EQ(ah_buffer_describe.format, kFormat)
+      << "The format of the android hardware buffer is wrong.";
+  ASSERT_EQ(ah_buffer_describe.layers, kLayerCount)
+      << "The obtained android hardware buffer should have 2 layers.";
+  ASSERT_EQ(ah_buffer_describe.width, width)
+      << "The obtained android hardware buffer width is wrong.";
+  ASSERT_EQ(ah_buffer_describe.height, height)
+      << "The obtained android hardware buffer height is wrong.";
+  // Change the content of the android hardware buffer.
+  void* buffer_data = nullptr;
+  int32_t fence = -1;
+  ret = AHardwareBuffer_lock(ah_buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
+                             fence, nullptr, &buffer_data);
+  ASSERT_EQ(0, ret) << "Failed to lock the hardware buffer.";
+  ASSERT_NE(nullptr, buffer_data) << "Buffer data should not be null.";
+
+  uint32_t num_pixels = width * height / num_colors;
+  for (uint32_t color_index = 0; color_index < num_colors - 1; ++color_index) {
+    uint32_t color_texture = color_textures[color_index];
+    for (uint32_t i = 0; i < num_pixels; ++i) {
+      memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) +
+                                     (i + num_pixels * color_index) *
+                                         sizeof(color_texture)),
+             &color_texture, sizeof(color_texture));
+    }
+  }
+  uint32_t color_texture = color_textures[num_colors - 1];
+  uint32_t num_colored_pixels = num_pixels * (num_colors - 1);
+  num_pixels = width * height - num_colored_pixels;
+  for (uint32_t i = 0; i < num_pixels; ++i) {
+    memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) +
+                                   (i + num_colored_pixels) *
+                                       sizeof(color_texture)),
+           &color_texture, sizeof(color_texture));
+  }
+  fence = -1;
+  ret = AHardwareBuffer_unlock(ah_buffer, &fence);
+  EXPECT_EQ(0, ret) << "Failed to unlock the hardware buffer.";
+
+  // Release the android hardware buffer.
+  AHardwareBuffer_release(ah_buffer);
 }
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index a9d473d..dec39e0 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -407,6 +407,12 @@
     for (uint32_t i = 0; i < ext_count; i++)
         FilterExtension(ext_names[i]);
 
+    // Enable device extensions that contain physical-device commands, so that
+    // vkGetInstanceProcAddr will return those physical-device commands.
+    if (is_instance_) {
+        hook_extensions_.set(ProcHook::KHR_swapchain);
+    }
+
     ext_names = extension_filter_.names;
     ext_count = extension_filter_.name_count;