Merge "vkGetDeviceQueue2: fix the NULL check"
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index e176871..5a82965 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -675,7 +675,8 @@
         run_cmd("touch " + expected_profile_content);
         run_cmd("profman --profile-file=" + cur_profile_ +
                 " --profile-file=" + ref_profile_ +
-                " --reference-profile-file=" + expected_profile_content);
+                " --reference-profile-file=" + expected_profile_content +
+                " --apk=" + apk_path_);
 
         ASSERT_TRUE(AreFilesEqual(expected_profile_content, snap_profile_));
 
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index 409c206..93d878b 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -24,6 +24,9 @@
         "libhidl-gen-utils",
         "libvintf",
     ],
+    static_libs: [
+        "libprocpartition",
+    ],
     srcs: [
         "DebugCommand.cpp",
         "HelpCommand.cpp",
@@ -45,10 +48,14 @@
     shared_libs: [
         "libbase",
         "libhidlbase",
+        "libhidl-gen-utils",
         "libhidltransport",
         "liblshal",
         "libutils",
     ],
+    static_libs: [
+        "libprocpartition",
+    ],
     cflags: ["-Wall", "-Werror"],
 }
 
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index fab13a0..b9e0139 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -25,6 +25,7 @@
 #include <sstream>
 #include <regex>
 
+#include <android-base/file.h>
 #include <android-base/parseint.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <hidl-hash/Hash.h>
@@ -32,6 +33,7 @@
 #include <private/android_filesystem_config.h>
 #include <sys/stat.h>
 #include <vintf/HalManifest.h>
+#include <vintf/parse_string.h>
 #include <vintf/parse_xml.h>
 
 #include "Lshal.h"
@@ -48,6 +50,10 @@
 namespace android {
 namespace lshal {
 
+vintf::SchemaType toSchemaType(Partition p) {
+    return (p == Partition::SYSTEM) ? vintf::SchemaType::FRAMEWORK : vintf::SchemaType::DEVICE;
+}
+
 NullableOStream<std::ostream> ListCommand::out() const {
     return mLshal.out();
 }
@@ -64,13 +70,7 @@
 }
 
 std::string ListCommand::parseCmdline(pid_t pid) const {
-    std::ifstream ifs("/proc/" + std::to_string(pid) + "/cmdline");
-    std::string cmdline;
-    if (!ifs.is_open()) {
-        return "";
-    }
-    ifs >> cmdline;
-    return cmdline;
+    return android::procpartition::getCmdline(pid);
 }
 
 const std::string &ListCommand::getCmdline(pid_t pid) {
@@ -89,6 +89,42 @@
     }), pids->end());
 }
 
+Partition ListCommand::getPartition(pid_t pid) {
+    auto it = mPartitions.find(pid);
+    if (it != mPartitions.end()) {
+        return it->second;
+    }
+    Partition partition = android::procpartition::getPartition(pid);
+    mPartitions.emplace(pid, partition);
+    return partition;
+}
+
+// Give sensible defaults when nothing can be inferred from runtime.
+// process: Partition inferred from executable location or cmdline.
+Partition ListCommand::resolvePartition(Partition process, const FQName& fqName) const {
+    if (fqName.inPackage("vendor") ||
+        fqName.inPackage("com")) {
+        return Partition::VENDOR;
+    }
+
+    if (fqName.inPackage("android.frameworks") ||
+        fqName.inPackage("android.system") ||
+        fqName.inPackage("android.hidl")) {
+        return Partition::SYSTEM;
+    }
+
+    // Some android.hardware HALs are served from system. Check the value from executable
+    // location / cmdline first.
+    if (fqName.inPackage("android.hardware")) {
+        if (process != Partition::UNKNOWN) {
+            return process;
+        }
+        return Partition::VENDOR;
+    }
+
+    return process;
+}
+
 static bool scanBinderContext(pid_t pid,
         const std::string &contextName,
         std::function<void(const std::string&)> eachLine) {
@@ -209,6 +245,9 @@
                 entry.clientCmdlines.push_back(this->getCmdline(pid));
             }
         }
+        for (TableEntry& entry : table) {
+            entry.partition = getPartition(entry.serverPid);
+        }
     });
     // use a double for loop here because lshal doesn't care about efficiency.
     for (TableEntry &packageEntry : mImplementationsTable) {
@@ -256,18 +295,10 @@
 
 void ListCommand::dumpVintf(const NullableOStream<std::ostream>& out) const {
     using vintf::operator|=;
-    out << "<!-- " << std::endl
-         << "    This is a skeleton device manifest. Notes: " << std::endl
-         << "    1. android.hidl.*, android.frameworks.*, android.system.* are not included." << std::endl
-         << "    2. If a HAL is supported in both hwbinder and passthrough transport, " << std::endl
-         << "       only hwbinder is shown." << std::endl
-         << "    3. It is likely that HALs in passthrough transport does not have" << std::endl
-         << "       <interface> declared; users will have to write them by hand." << std::endl
-         << "    4. A HAL with lower minor version can be overridden by a HAL with" << std::endl
-         << "       higher minor version if they have the same name and major version." << std::endl
-         << "-->" << std::endl;
+    using vintf::operator<<;
 
     vintf::HalManifest manifest;
+    manifest.setType(toSchemaType(mVintfPartition));
     forEachTable([this, &manifest] (const Table &table) {
         for (const TableEntry &entry : table) {
 
@@ -284,12 +315,23 @@
                      << "' is not a valid FQName." << std::endl;
                 continue;
             }
-            // Strip out system libs.
-            if (fqName.inPackage("android.hidl") ||
-                fqName.inPackage("android.frameworks") ||
-                fqName.inPackage("android.system")) {
+
+            if (fqName.package() == gIBaseFqName.package()) {
+                continue; // always remove IBase from manifest
+            }
+
+            Partition partition = resolvePartition(entry.partition, fqName);
+
+            if (partition == Partition::UNKNOWN) {
+                err() << "Warning: Cannot guess the partition of instance " << fqInstanceName
+                      << ". It is removed from the generated manifest." << std::endl;
                 continue;
             }
+
+            if (partition != mVintfPartition) {
+                continue; // strip out instances that is in a different partition.
+            }
+
             std::string interfaceName =
                     &table == &mImplementationsTable ? "" : fqName.name();
             std::string instanceName =
@@ -361,9 +403,22 @@
             }
         }
     });
+    out << "<!-- " << std::endl
+         << "    This is a skeleton " << manifest.type() << " manifest. Notes: " << std::endl
+         << INIT_VINTF_NOTES
+         << "-->" << std::endl;
     out << vintf::gHalManifestConverter(manifest, vintf::SerializeFlag::HALS_ONLY);
 }
 
+std::string ListCommand::INIT_VINTF_NOTES{
+    "    1. If a HAL is supported in both hwbinder and passthrough transport, \n"
+    "       only hwbinder is shown.\n"
+    "    2. It is likely that HALs in passthrough transport does not have\n"
+    "       <interface> declared; users will have to write them by hand.\n"
+    "    3. A HAL with lower minor version can be overridden by a HAL with\n"
+    "       higher minor version if they have the same name and major version.\n"
+};
+
 static Architecture fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo::Architecture a) {
     switch (a) {
         case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_64BIT:
@@ -710,9 +765,18 @@
     // long options without short alternatives
     mOptions.push_back({'\0', "init-vintf", no_argument, v++, [](ListCommand* thiz, const char* arg) {
         thiz->mVintf = true;
+        if (thiz->mVintfPartition == Partition::UNKNOWN)
+            thiz->mVintfPartition = Partition::VENDOR;
         if (arg) thiz->mFileOutputPath = arg;
         return OK;
     }, "form a skeleton HAL manifest to specified file,\nor stdout if no file specified."});
+    mOptions.push_back({'\0', "init-vintf-partition", required_argument, v++, [](ListCommand* thiz, const char* arg) {
+        if (!arg) return USAGE;
+        thiz->mVintfPartition = android::procpartition::parsePartition(arg);
+        if (thiz->mVintfPartition == Partition::UNKNOWN) return USAGE;
+        return OK;
+    }, "Specify the partition of the HAL manifest\ngenerated by --init-vintf.\n"
+       "Valid values are 'system', 'vendor', and 'odm'. Default is 'vendor'."});
     mOptions.push_back({'\0', "sort", required_argument, v++, [](ListCommand* thiz, const char* arg) {
         if (strcmp(arg, "interface") == 0 || strcmp(arg, "i") == 0) {
             thiz->mSortColumn = TableEntry::sortByInterfaceName;
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
index 7e252fc..1e85ea0 100644
--- a/cmds/lshal/ListCommand.h
+++ b/cmds/lshal/ListCommand.h
@@ -26,6 +26,7 @@
 
 #include <android-base/macros.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
+#include <hidl-util/FQName.h>
 
 #include "Command.h"
 #include "NullableOStream.h"
@@ -75,6 +76,8 @@
     // key: value returned by getopt_long
     using RegisteredOptions = std::vector<RegisteredOption>;
 
+    static std::string INIT_VINTF_NOTES;
+
 protected:
     Status parseArgs(const Arg &arg);
     Status fetch();
@@ -104,10 +107,14 @@
     // Read and return /proc/{pid}/cmdline.
     virtual std::string parseCmdline(pid_t pid) const;
     // Return /proc/{pid}/cmdline if it exists, else empty string.
-    const std::string &getCmdline(pid_t pid);
+    const std::string& getCmdline(pid_t pid);
     // Call getCmdline on all pid in pids. If it returns empty string, the process might
     // have died, and the pid is removed from pids.
     void removeDeadProcesses(Pids *pids);
+
+    virtual Partition getPartition(pid_t pid);
+    Partition resolvePartition(Partition processPartition, const FQName& fqName) const;
+
     void forEachTable(const std::function<void(Table &)> &f);
     void forEachTable(const std::function<void(const Table &)> &f) const;
 
@@ -125,8 +132,9 @@
 
     bool mEmitDebugInfo = false;
 
-    // If true, output in VINTF format.
+    // If true, output in VINTF format. Output only entries from the specified partition.
     bool mVintf = false;
+    Partition mVintfPartition = Partition::UNKNOWN;
 
     // If true, explanatory text are not emitted.
     bool mNeat = false;
@@ -139,6 +147,9 @@
     // Cache for getPidInfo.
     std::map<pid_t, PidInfo> mCachedPidInfos;
 
+    // Cache for getPartition.
+    std::map<pid_t, Partition> mPartitions;
+
     RegisteredOptions mOptions;
     // All selected columns
     std::vector<TableColumnType> mSelectedColumns;
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index 69206cc..24ea438 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -23,11 +23,14 @@
 #include <vector>
 #include <iostream>
 
+#include <procpartition/procpartition.h>
+
 #include "TextTable.h"
 
 namespace android {
 namespace lshal {
 
+using android::procpartition::Partition;
 using Pids = std::vector<int32_t>;
 
 enum : unsigned int {
@@ -77,6 +80,7 @@
     Architecture arch{ARCH_UNKNOWN};
     // empty: unknown, all zeros: unreleased, otherwise: released
     std::string hash{};
+    Partition partition{Partition::UNKNOWN};
 
     static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) {
         return a.interfaceName < b.interfaceName;
diff --git a/cmds/lshal/libprocpartition/Android.bp b/cmds/lshal/libprocpartition/Android.bp
new file mode 100644
index 0000000..9592111
--- /dev/null
+++ b/cmds/lshal/libprocpartition/Android.bp
@@ -0,0 +1,30 @@
+// 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_static {
+    name: "libprocpartition",
+    shared_libs: [
+        "libbase",
+    ],
+    srcs: [
+        "procpartition.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    export_include_dirs: [
+        "include",
+    ]
+}
diff --git a/cmds/lshal/libprocpartition/include/procpartition/procpartition.h b/cmds/lshal/libprocpartition/include/procpartition/procpartition.h
new file mode 100644
index 0000000..7e86432
--- /dev/null
+++ b/cmds/lshal/libprocpartition/include/procpartition/procpartition.h
@@ -0,0 +1,48 @@
+/*
+ * 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 FRAMEWORK_NATIVE_CMDS_LSHAL_PROCPARTITION_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_PROCPARTITION_H_
+
+#include <sys/types.h>
+
+#include <string>
+#include <iostream>
+
+namespace android {
+namespace procpartition {
+
+enum class Partition {
+    UNKNOWN = 0,
+    SYSTEM,
+    VENDOR,
+    ODM
+};
+
+std::ostream& operator<<(std::ostream& os, Partition p);
+Partition parsePartition(const std::string& s);
+
+// Return the path that /proc/<pid>/exe points to.
+std::string getExe(pid_t pid);
+// Return the content of /proc/<pid>/cmdline.
+std::string getCmdline(pid_t pid);
+// Infer the partition of a process from /proc/<pid>/exe and /proc/<pid>/cmdline.
+Partition getPartition(pid_t pid);
+
+}  // namespace procpartition
+}  // namespace android
+
+#endif  // FRAMEWORK_NATIVE_CMDS_LSHAL_PROCPARTITION_H_
diff --git a/cmds/lshal/libprocpartition/procpartition.cpp b/cmds/lshal/libprocpartition/procpartition.cpp
new file mode 100644
index 0000000..8ca458a
--- /dev/null
+++ b/cmds/lshal/libprocpartition/procpartition.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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 <procpartition/procpartition.h>
+
+#include <android-base/file.h>
+
+namespace android {
+namespace procpartition {
+
+std::ostream& operator<<(std::ostream& os, Partition p) {
+    switch (p) {
+        case Partition::SYSTEM: return os << "system";
+        case Partition::VENDOR: return os << "vendor";
+        case Partition::ODM: return os << "odm";
+        case Partition::UNKNOWN: // fallthrough
+        default:
+            return os << "(unknown)";
+    }
+}
+
+std::string getExe(pid_t pid) {
+    std::string exe;
+    std::string real;
+    if (!android::base::Readlink("/proc/" + std::to_string(pid) + "/exe", &exe)) {
+        return "";
+    }
+    if (!android::base::Realpath(exe, &real)) {
+        return "";
+    }
+    return real;
+}
+
+std::string getCmdline(pid_t pid) {
+    std::string content;
+    if (!android::base::ReadFileToString("/proc/" + std::to_string(pid) + "/cmdline", &content,
+                                         false /* follow symlinks */)) {
+        return "";
+    }
+    return content;
+}
+
+Partition parsePartition(const std::string& s) {
+    if (s == "system") {
+        return Partition::SYSTEM;
+    }
+    if (s == "vendor") {
+        return Partition::VENDOR;
+    }
+    if (s == "odm") {
+        return Partition::ODM;
+    }
+    return Partition::UNKNOWN;
+}
+
+Partition getPartitionFromRealpath(const std::string& path) {
+    if (path == "/system/bin/app_process64" ||
+        path == "/system/bin/app_process32") {
+
+        return Partition::UNKNOWN; // cannot determine
+    }
+    size_t backslash = path.find_first_of('/', 1);
+    std::string partition = (backslash != std::string::npos) ? path.substr(1, backslash - 1) : path;
+
+    return parsePartition(partition);
+}
+
+Partition getPartitionFromCmdline(pid_t pid) {
+    const auto& cmdline = getCmdline(pid);
+    if (cmdline == "system_server") {
+        return Partition::SYSTEM;
+    }
+    if (cmdline.empty() || cmdline.front() != '/') {
+        return Partition::UNKNOWN;
+    }
+    return getPartitionFromRealpath(cmdline);
+}
+
+Partition getPartitionFromExe(pid_t pid) {
+    const auto& real = getExe(pid);
+    if (real.empty() || real.front() != '/') {
+        return Partition::UNKNOWN;
+    }
+    return getPartitionFromRealpath(real);
+}
+
+
+Partition getPartition(pid_t pid) {
+    Partition partition = getPartitionFromExe(pid);
+    if (partition == Partition::UNKNOWN) {
+        partition = getPartitionFromCmdline(pid);
+    }
+    return partition;
+}
+
+}  // namespace procpartition
+}  // namespace android
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index 9220fc0..4fa941e 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -206,6 +206,7 @@
     MOCK_METHOD0(postprocess, void());
     MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, PidInfo*));
     MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
+    MOCK_METHOD1(getPartition, Partition(pid_t));
 };
 
 class ListParseArgsTest : public ::testing::Test {
@@ -333,6 +334,7 @@
                 table.setDescription("[fake description " + std::to_string(i++) + "]");
             });
         }));
+        ON_CALL(*mockList, getPartition(_)).WillByDefault(Return(Partition::VENDOR));
     }
 
     void initMockServiceManager() {
@@ -418,17 +420,7 @@
 TEST_F(ListTest, DumpVintf) {
     const std::string expected =
         "<!-- \n"
-        "    This is a skeleton device manifest. Notes: \n"
-        "    1. android.hidl.*, android.frameworks.*, android.system.* are not included.\n"
-        "    2. If a HAL is supported in both hwbinder and passthrough transport, \n"
-        "       only hwbinder is shown.\n"
-        "    3. It is likely that HALs in passthrough transport does not have\n"
-        "       <interface> declared; users will have to write them by hand.\n"
-        "    4. A HAL with lower minor version can be overridden by a HAL with\n"
-        "       higher minor version if they have the same name and major version.\n"
-        "    5. sepolicy version is set to 0.0. It is recommended that the entry\n"
-        "       is removed from the manifest file and written by assemble_vintf\n"
-        "       at build time.\n"
+        "    This is a skeleton device manifest. Notes: \n" + ListCommand::INIT_VINTF_NOTES +
         "-->\n"
         "<manifest version=\"1.0\" type=\"device\">\n"
         "    <hal format=\"hidl\">\n"
@@ -477,9 +469,6 @@
         "        <transport arch=\"32\">passthrough</transport>\n"
         "        <version>6.0</version>\n"
         "    </hal>\n"
-        "    <sepolicy>\n"
-        "        <version>0.0</version>\n"
-        "    </sepolicy>\n"
         "</manifest>\n";
 
     optind = 1; // mimic Lshal::parseArg()
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index e8aa6b7..8c81e8d 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -36,7 +36,6 @@
 
 cc_test {
     srcs: [
-        "dvr_buffer_queue-test.cpp",
         "dvr_display_manager-test.cpp",
         "dvr_named_buffer-test.cpp",
     ],
@@ -53,3 +52,25 @@
     ],
     name: "dvr_api-test",
 }
+
+cc_test {
+    srcs: [
+        "dvr_buffer_queue-test.cpp",
+    ],
+
+    header_libs: [
+        "libdvr_headers",
+        "libbase_headers",
+    ],
+    shared_libs: [
+        "liblog",
+        "libnativewindow",
+    ],
+    cflags: [
+        "-DLOG_TAG=\"dvr_buffer_queue-test\"",
+        "-DTRACE=0",
+        "-O0",
+        "-g",
+    ],
+    name: "dvr_buffer_queue-test",
+}
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
index 62cd8d4..ff0588c 100644
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -1,6 +1,7 @@
+#include <android-base/unique_fd.h>
 #include <android/log.h>
 #include <android/native_window.h>
-#include <android-base/unique_fd.h>
+#include <dlfcn.h>
 #include <dvr/dvr_api.h>
 #include <dvr/dvr_buffer_queue.h>
 
@@ -13,6 +14,8 @@
 #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
 #endif
 
+#define ASSERT_NOT_NULL(x) ASSERT_TRUE((x) != nullptr)
+
 #ifndef ALOGD_IF
 #define ALOGD_IF(cond, ...) \
   ((__predict_false(cond)) ? ((void)ALOGD(__VA_ARGS__)) : (void)0)
@@ -40,11 +43,26 @@
   }
 
  protected:
+  void SetUp() override {
+    platform_handle_ = dlopen("libdvr.so", RTLD_NOW | RTLD_LOCAL);
+    ASSERT_NOT_NULL(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_EQ(dvr_get_api(&api_, sizeof(api_), /*version=*/1), 0)
+        << "Unable to find compatible Dvr API.";
+  }
+
   void TearDown() override {
     if (write_queue_ != nullptr) {
-      dvrWriteBufferQueueDestroy(write_queue_);
+      api_.WriteBufferQueueDestroy(write_queue_);
       write_queue_ = nullptr;
     }
+    if (platform_handle_ != nullptr) {
+      dlclose(platform_handle_);
+    }
   }
 
   void HandleBufferAvailable() {
@@ -61,88 +79,90 @@
   DvrWriteBufferQueue* write_queue_{nullptr};
   int buffer_available_count_{0};
   int buffer_removed_count_{0};
+  void* platform_handle_{nullptr};
+  DvrApi_v1 api_{};
 };
 
 TEST_F(DvrBufferQueueTest, WriteQueueCreateDestroy) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
 
-  dvrWriteBufferQueueDestroy(write_queue_);
+  api_.WriteBufferQueueDestroy(write_queue_);
   write_queue_ = nullptr;
 }
 
 TEST_F(DvrBufferQueueTest, WriteQueueGetCapacity) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
 
-  size_t capacity = dvrWriteBufferQueueGetCapacity(write_queue_);
+  size_t capacity = api_.WriteBufferQueueGetCapacity(write_queue_);
 
   ALOGD_IF(TRACE, "TestWrite_QueueGetCapacity, capacity=%zu", capacity);
   ASSERT_EQ(kQueueCapacity, capacity);
 }
 
 TEST_F(DvrBufferQueueTest, CreateReadQueueFromWriteQueue) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
 
   DvrReadBufferQueue* read_queue = nullptr;
-  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
 
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue);
 
-  dvrReadBufferQueueDestroy(read_queue);
+  api_.ReadBufferQueueDestroy(read_queue);
 }
 
 TEST_F(DvrBufferQueueTest, CreateReadQueueFromReadQueue) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
 
   DvrReadBufferQueue* read_queue1 = nullptr;
   DvrReadBufferQueue* read_queue2 = nullptr;
-  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
+  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
 
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue1);
 
-  ret = dvrReadBufferQueueCreateReadQueue(read_queue1, &read_queue2);
+  ret = api_.ReadBufferQueueCreateReadQueue(read_queue1, &read_queue2);
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue2);
   ASSERT_NE(read_queue1, read_queue2);
 
-  dvrReadBufferQueueDestroy(read_queue1);
-  dvrReadBufferQueueDestroy(read_queue2);
+  api_.ReadBufferQueueDestroy(read_queue1);
+  api_.ReadBufferQueueDestroy(read_queue2);
 }
 
 TEST_F(DvrBufferQueueTest, GainBuffer) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(ret, 0);
 
   DvrWriteBuffer* wb = nullptr;
-  EXPECT_FALSE(dvrWriteBufferIsValid(wb));
+  EXPECT_FALSE(api_.WriteBufferIsValid(wb));
 
   DvrNativeBufferMetadata meta;
   int fence_fd = -1;
-  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta,
-                                      &fence_fd);
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta,
+                                        &fence_fd);
   ASSERT_EQ(ret, 0);
   EXPECT_EQ(fence_fd, -1);
   EXPECT_NE(wb, nullptr);
-  EXPECT_TRUE(dvrWriteBufferIsValid(wb));
+  EXPECT_TRUE(api_.WriteBufferIsValid(wb));
 }
 
 TEST_F(DvrBufferQueueTest, AcquirePostGainRelease) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(ret, 0);
@@ -154,40 +174,40 @@
   DvrNativeBufferMetadata meta2;
   int fence_fd = -1;
 
-  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
 
   ASSERT_EQ(ret, 0);
   ASSERT_NE(read_queue, nullptr);
 
-  dvrReadBufferQueueSetBufferAvailableCallback(read_queue,
-                                               &BufferAvailableCallback, this);
+  api_.ReadBufferQueueSetBufferAvailableCallback(
+      read_queue, &BufferAvailableCallback, this);
 
   // Gain buffer for writing.
-  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta1,
-                                      &fence_fd);
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb,
+                                        &meta1, &fence_fd);
   ASSERT_EQ(ret, 0);
   ASSERT_NE(wb, nullptr);
-  ASSERT_TRUE(dvrWriteBufferIsValid(wb));
+  ASSERT_TRUE(api_.WriteBufferIsValid(wb));
   ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, gain buffer %p, fence_fd=%d",
            wb, fence_fd);
   android::base::unique_fd release_fence(fence_fd);
 
   // Post buffer to the read_queue.
   meta1.timestamp = 42;
-  ret = dvrWriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1);
+  ret = api_.WriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1);
   ASSERT_EQ(ret, 0);
-  ASSERT_FALSE(dvrWriteBufferIsValid(wb));
+  ASSERT_FALSE(api_.WriteBufferIsValid(wb));
   wb = nullptr;
 
   // Acquire buffer for reading.
-  ret = dvrReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb, &meta2,
-                                        &fence_fd);
+  ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb,
+                                          &meta2, &fence_fd);
   ASSERT_EQ(ret, 0);
   ASSERT_NE(rb, nullptr);
 
   // Dequeue is successfully, BufferAvailableCallback should be fired once.
   ASSERT_EQ(buffer_available_count_, 1);
-  ASSERT_TRUE(dvrReadBufferIsValid(rb));
+  ASSERT_TRUE(api_.ReadBufferIsValid(rb));
 
   // Metadata should be passed along from producer to consumer properly.
   ASSERT_EQ(meta1.timestamp, meta2.timestamp);
@@ -198,31 +218,31 @@
   android::base::unique_fd acquire_fence(fence_fd);
 
   // Release buffer to the write_queue.
-  ret = dvrReadBufferQueueReleaseBuffer(read_queue, rb, &meta2,
-                                        /*release_fence_fd=*/-1);
+  ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rb, &meta2,
+                                          /*release_fence_fd=*/-1);
   ASSERT_EQ(ret, 0);
-  ASSERT_FALSE(dvrReadBufferIsValid(rb));
+  ASSERT_FALSE(api_.ReadBufferIsValid(rb));
   rb = nullptr;
 
   // TODO(b/34387835) Currently buffer allocation has to happen after all queues
   // are initialized.
-  size_t capacity = dvrReadBufferQueueGetCapacity(read_queue);
+  size_t capacity = api_.ReadBufferQueueGetCapacity(read_queue);
 
   ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, capacity=%zu", capacity);
   ASSERT_EQ(kQueueCapacity, capacity);
 
-  dvrReadBufferQueueDestroy(read_queue);
+  api_.ReadBufferQueueDestroy(read_queue);
 }
 
 TEST_F(DvrBufferQueueTest, GetANativeWindow) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, write_queue_);
 
   ANativeWindow* window = nullptr;
-  ret = dvrWriteBufferQueueGetANativeWindow(write_queue_, &window);
+  ret = api_.WriteBufferQueueGetANativeWindow(write_queue_, &window);
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, window);
 
@@ -238,7 +258,7 @@
 // Before each dequeue operation, we resize the buffer queue and expect the
 // queue always return buffer with desired dimension.
 TEST_F(DvrBufferQueueTest, ResizeBuffer) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
@@ -255,37 +275,37 @@
   AHardwareBuffer* ahb3 = nullptr;
   AHardwareBuffer_Desc buffer_desc;
 
-  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
 
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue);
 
-  dvrReadBufferQueueSetBufferRemovedCallback(read_queue, &BufferRemovedCallback,
-                                             this);
+  api_.ReadBufferQueueSetBufferRemovedCallback(read_queue,
+                                               &BufferRemovedCallback, this);
 
   // Handle all pending events on the read queue.
-  ret = dvrReadBufferQueueHandleEvents(read_queue);
+  ret = api_.ReadBufferQueueHandleEvents(read_queue);
   ASSERT_EQ(0, ret);
 
-  size_t capacity = dvrReadBufferQueueGetCapacity(read_queue);
+  size_t capacity = api_.ReadBufferQueueGetCapacity(read_queue);
   ALOGD_IF(TRACE, "TestResizeBuffer, capacity=%zu", capacity);
   ASSERT_EQ(kQueueCapacity, capacity);
 
   // Resize before dequeuing.
   constexpr uint32_t w1 = 10;
-  ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w1, kBufferHeight);
+  ret = api_.WriteBufferQueueResizeBuffer(write_queue_, w1, kBufferHeight);
   ASSERT_EQ(0, ret);
 
   // Gain first buffer for writing. All buffers will be resized.
-  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb1, &meta,
-                                      &fence_fd);
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb1,
+                                        &meta, &fence_fd);
   ASSERT_EQ(0, ret);
-  ASSERT_TRUE(dvrWriteBufferIsValid(wb1));
+  ASSERT_TRUE(api_.WriteBufferIsValid(wb1));
   ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p", wb1);
   android::base::unique_fd release_fence1(fence_fd);
 
   // Check the buffer dimension.
-  ret = dvrWriteBufferGetAHardwareBuffer(wb1, &ahb1);
+  ret = api_.WriteBufferGetAHardwareBuffer(wb1, &ahb1);
   ASSERT_EQ(0, ret);
   AHardwareBuffer_describe(ahb1, &buffer_desc);
   ASSERT_EQ(w1, buffer_desc.width);
@@ -294,26 +314,26 @@
 
   // For the first resize, all buffers are reallocated.
   int expected_buffer_removed_count = kQueueCapacity;
-  ret = dvrReadBufferQueueHandleEvents(read_queue);
+  ret = api_.ReadBufferQueueHandleEvents(read_queue);
   ASSERT_EQ(0, ret);
   ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_);
 
   // Resize the queue. We are testing with blob format, keep height to be 1.
   constexpr uint32_t w2 = 20;
-  ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w2, kBufferHeight);
+  ret = api_.WriteBufferQueueResizeBuffer(write_queue_, w2, kBufferHeight);
   ASSERT_EQ(0, ret);
 
   // The next buffer we dequeued should have new width.
-  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb2, &meta,
-                                      &fence_fd);
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb2,
+                                        &meta, &fence_fd);
   ASSERT_EQ(0, ret);
-  ASSERT_TRUE(dvrWriteBufferIsValid(wb2));
+  ASSERT_TRUE(api_.WriteBufferIsValid(wb2));
   ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb2,
            fence_fd);
   android::base::unique_fd release_fence2(fence_fd);
 
   // Check the buffer dimension, should be new width
-  ret = dvrWriteBufferGetAHardwareBuffer(wb2, &ahb2);
+  ret = api_.WriteBufferGetAHardwareBuffer(wb2, &ahb2);
   ASSERT_EQ(0, ret);
   AHardwareBuffer_describe(ahb2, &buffer_desc);
   ASSERT_EQ(w2, buffer_desc.width);
@@ -321,26 +341,26 @@
 
   // For the second resize, all but one buffers are reallocated.
   expected_buffer_removed_count += (kQueueCapacity - 1);
-  ret = dvrReadBufferQueueHandleEvents(read_queue);
+  ret = api_.ReadBufferQueueHandleEvents(read_queue);
   ASSERT_EQ(0, ret);
   ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_);
 
   // Resize the queue for the third time.
   constexpr uint32_t w3 = 30;
-  ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w3, kBufferHeight);
+  ret = api_.WriteBufferQueueResizeBuffer(write_queue_, w3, kBufferHeight);
   ASSERT_EQ(0, ret);
 
   // The next buffer we dequeued should have new width.
-  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb3, &meta,
-                                      &fence_fd);
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb3,
+                                        &meta, &fence_fd);
   ASSERT_EQ(0, ret);
-  ASSERT_TRUE(dvrWriteBufferIsValid(wb3));
+  ASSERT_TRUE(api_.WriteBufferIsValid(wb3));
   ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb3,
            fence_fd);
   android::base::unique_fd release_fence3(fence_fd);
 
   // Check the buffer dimension, should be new width
-  ret = dvrWriteBufferGetAHardwareBuffer(wb3, &ahb3);
+  ret = api_.WriteBufferGetAHardwareBuffer(wb3, &ahb3);
   ASSERT_EQ(0, ret);
   AHardwareBuffer_describe(ahb3, &buffer_desc);
   ASSERT_EQ(w3, buffer_desc.width);
@@ -348,26 +368,26 @@
 
   // For the third resize, all but two buffers are reallocated.
   expected_buffer_removed_count += (kQueueCapacity - 2);
-  ret = dvrReadBufferQueueHandleEvents(read_queue);
+  ret = api_.ReadBufferQueueHandleEvents(read_queue);
   ASSERT_EQ(0, ret);
   ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_);
 
-  dvrReadBufferQueueDestroy(read_queue);
+  api_.ReadBufferQueueDestroy(read_queue);
 }
 
 TEST_F(DvrBufferQueueTest, ReadQueueEventFd) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
 
   DvrReadBufferQueue* read_queue = nullptr;
-  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
 
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue);
 
-  int event_fd = dvrReadBufferQueueGetEventFd(read_queue);
+  int event_fd = api_.ReadBufferQueueGetEventFd(read_queue);
   ASSERT_GT(event_fd, 0);
 }
 
@@ -375,14 +395,14 @@
 // Dvr{Read,Write}Buffer(s) during their lifecycles. And for the same buffer_id,
 // the corresponding AHardwareBuffer handle stays the same.
 TEST_F(DvrBufferQueueTest, StableBufferIdAndHardwareBuffer) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
 
   int fence_fd = -1;
   DvrReadBufferQueue* read_queue = nullptr;
-  EXPECT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
+  EXPECT_EQ(0, api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
 
   // Read buffers.
   std::array<DvrReadBuffer*, kQueueCapacity> rbs;
@@ -400,16 +420,16 @@
   // This test runs the following operations many many times. Thus we prefer to
   // use ASSERT_XXX rather than EXPECT_XXX to avoid spamming the output.
   std::function<void(size_t i)> Gain = [&](size_t i) {
-    int ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/10,
-                                            &wbs[i], &metas[i], &fence_fd);
+    int ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/10,
+                                              &wbs[i], &metas[i], &fence_fd);
     ASSERT_EQ(ret, 0);
     ASSERT_LT(fence_fd, 0);  // expect invalid fence.
-    ASSERT_TRUE(dvrWriteBufferIsValid(wbs[i]));
-    int buffer_id = dvrWriteBufferGetId(wbs[i]);
+    ASSERT_TRUE(api_.WriteBufferIsValid(wbs[i]));
+    int buffer_id = api_.WriteBufferGetId(wbs[i]);
     ASSERT_GT(buffer_id, 0);
 
     AHardwareBuffer* hb = nullptr;
-    ASSERT_EQ(0, dvrWriteBufferGetAHardwareBuffer(wbs[i], &hb));
+    ASSERT_EQ(0, api_.WriteBufferGetAHardwareBuffer(wbs[i], &hb));
 
     auto whb_it = whbs.find(buffer_id);
     if (whb_it == whbs.end()) {
@@ -425,26 +445,26 @@
   };
 
   std::function<void(size_t i)> Post = [&](size_t i) {
-    ASSERT_TRUE(dvrWriteBufferIsValid(wbs[i]));
+    ASSERT_TRUE(api_.WriteBufferIsValid(wbs[i]));
 
     metas[i].timestamp++;
-    int ret = dvrWriteBufferQueuePostBuffer(write_queue_, wbs[i], &metas[i],
-                                            /*fence=*/-1);
+    int ret = api_.WriteBufferQueuePostBuffer(write_queue_, wbs[i], &metas[i],
+                                              /*fence=*/-1);
     ASSERT_EQ(ret, 0);
   };
 
   std::function<void(size_t i)> Acquire = [&](size_t i) {
-    int ret = dvrReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10,
-                                              &rbs[i], &metas[i], &fence_fd);
+    int ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10,
+                                                &rbs[i], &metas[i], &fence_fd);
     ASSERT_EQ(ret, 0);
     ASSERT_LT(fence_fd, 0);  // expect invalid fence.
-    ASSERT_TRUE(dvrReadBufferIsValid(rbs[i]));
+    ASSERT_TRUE(api_.ReadBufferIsValid(rbs[i]));
 
-    int buffer_id = dvrReadBufferGetId(rbs[i]);
+    int buffer_id = api_.ReadBufferGetId(rbs[i]);
     ASSERT_GT(buffer_id, 0);
 
     AHardwareBuffer* hb = nullptr;
-    ASSERT_EQ(0, dvrReadBufferGetAHardwareBuffer(rbs[i], &hb));
+    ASSERT_EQ(0, api_.ReadBufferGetAHardwareBuffer(rbs[i], &hb));
 
     auto rhb_it = rhbs.find(buffer_id);
     if (rhb_it == rhbs.end()) {
@@ -460,10 +480,10 @@
   };
 
   std::function<void(size_t i)> Release = [&](size_t i) {
-    ASSERT_TRUE(dvrReadBufferIsValid(rbs[i]));
+    ASSERT_TRUE(api_.ReadBufferIsValid(rbs[i]));
 
-    int ret = dvrReadBufferQueueReleaseBuffer(read_queue, rbs[i], &metas[i],
-                                              /*release_fence_fd=*/-1);
+    int ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rbs[i], &metas[i],
+                                                /*release_fence_fd=*/-1);
     ASSERT_EQ(ret, 0);
   };