release-request-60f55d52-4657-4714-89dc-b6443475d767-for-git_oc-release-4022373 snap-temp-L45500000065414617

Change-Id: I30862b6e3c7590389181762334ea2d7887f14355
diff --git a/Android.bp b/Android.bp
index dcf0b12..9ea8266 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,5 +1,7 @@
 // This is an autogenerated file, do not edit.
 subdirs = [
+    "displayservice/1.0",
+    "displayservice/1.0/vts/functional",
     "schedulerservice/1.0",
     "sensorservice/1.0",
     "sensorservice/1.0/vts/functional",
diff --git a/displayservice/1.0/Android.bp b/displayservice/1.0/Android.bp
new file mode 100644
index 0000000..34d7091
--- /dev/null
+++ b/displayservice/1.0/Android.bp
@@ -0,0 +1,76 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+    name: "android.frameworks.displayservice@1.0_hal",
+    srcs: [
+        "types.hal",
+        "IDisplayEventReceiver.hal",
+        "IDisplayService.hal",
+        "IEventCallback.hal",
+    ],
+}
+
+genrule {
+    name: "android.frameworks.displayservice@1.0_genc++",
+    tools: ["hidl-gen"],
+    cmd: "$(location hidl-gen) -o $(genDir) -Lc++-sources -randroid.frameworks:frameworks/hardware/interfaces -randroid.hidl:system/libhidl/transport android.frameworks.displayservice@1.0",
+    srcs: [
+        ":android.frameworks.displayservice@1.0_hal",
+    ],
+    out: [
+        "android/frameworks/displayservice/1.0/types.cpp",
+        "android/frameworks/displayservice/1.0/DisplayEventReceiverAll.cpp",
+        "android/frameworks/displayservice/1.0/DisplayServiceAll.cpp",
+        "android/frameworks/displayservice/1.0/EventCallbackAll.cpp",
+    ],
+}
+
+genrule {
+    name: "android.frameworks.displayservice@1.0_genc++_headers",
+    tools: ["hidl-gen"],
+    cmd: "$(location hidl-gen) -o $(genDir) -Lc++-headers -randroid.frameworks:frameworks/hardware/interfaces -randroid.hidl:system/libhidl/transport android.frameworks.displayservice@1.0",
+    srcs: [
+        ":android.frameworks.displayservice@1.0_hal",
+    ],
+    out: [
+        "android/frameworks/displayservice/1.0/types.h",
+        "android/frameworks/displayservice/1.0/hwtypes.h",
+        "android/frameworks/displayservice/1.0/IDisplayEventReceiver.h",
+        "android/frameworks/displayservice/1.0/IHwDisplayEventReceiver.h",
+        "android/frameworks/displayservice/1.0/BnHwDisplayEventReceiver.h",
+        "android/frameworks/displayservice/1.0/BpHwDisplayEventReceiver.h",
+        "android/frameworks/displayservice/1.0/BsDisplayEventReceiver.h",
+        "android/frameworks/displayservice/1.0/IDisplayService.h",
+        "android/frameworks/displayservice/1.0/IHwDisplayService.h",
+        "android/frameworks/displayservice/1.0/BnHwDisplayService.h",
+        "android/frameworks/displayservice/1.0/BpHwDisplayService.h",
+        "android/frameworks/displayservice/1.0/BsDisplayService.h",
+        "android/frameworks/displayservice/1.0/IEventCallback.h",
+        "android/frameworks/displayservice/1.0/IHwEventCallback.h",
+        "android/frameworks/displayservice/1.0/BnHwEventCallback.h",
+        "android/frameworks/displayservice/1.0/BpHwEventCallback.h",
+        "android/frameworks/displayservice/1.0/BsEventCallback.h",
+    ],
+}
+
+cc_library_shared {
+    name: "android.frameworks.displayservice@1.0",
+    generated_sources: ["android.frameworks.displayservice@1.0_genc++"],
+    generated_headers: ["android.frameworks.displayservice@1.0_genc++_headers"],
+    export_generated_headers: ["android.frameworks.displayservice@1.0_genc++_headers"],
+    vendor_available: true,
+    shared_libs: [
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "liblog",
+        "libutils",
+        "libcutils",
+    ],
+    export_shared_lib_headers: [
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "libutils",
+    ],
+}
diff --git a/displayservice/1.0/Android.mk b/displayservice/1.0/Android.mk
new file mode 100644
index 0000000..c272521
--- /dev/null
+++ b/displayservice/1.0/Android.mk
@@ -0,0 +1,202 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.frameworks.displayservice-V1.0-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_JAVA_LIBRARIES := \
+    android.hidl.base-V1.0-java \
+
+
+#
+# Build types.hal (Status)
+#
+GEN := $(intermediates)/android/frameworks/displayservice/V1_0/Status.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.frameworks:frameworks/hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.frameworks.displayservice@1.0::types.Status
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IDisplayEventReceiver.hal
+#
+GEN := $(intermediates)/android/frameworks/displayservice/V1_0/IDisplayEventReceiver.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IDisplayEventReceiver.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IEventCallback.hal
+$(GEN): $(LOCAL_PATH)/IEventCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.frameworks:frameworks/hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.frameworks.displayservice@1.0::IDisplayEventReceiver
+
+$(GEN): $(LOCAL_PATH)/IDisplayEventReceiver.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IDisplayService.hal
+#
+GEN := $(intermediates)/android/frameworks/displayservice/V1_0/IDisplayService.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IDisplayService.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IDisplayEventReceiver.hal
+$(GEN): $(LOCAL_PATH)/IDisplayEventReceiver.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.frameworks:frameworks/hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.frameworks.displayservice@1.0::IDisplayService
+
+$(GEN): $(LOCAL_PATH)/IDisplayService.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IEventCallback.hal
+#
+GEN := $(intermediates)/android/frameworks/displayservice/V1_0/IEventCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IEventCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.frameworks:frameworks/hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.frameworks.displayservice@1.0::IEventCallback
+
+$(GEN): $(LOCAL_PATH)/IEventCallback.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.frameworks.displayservice-V1.0-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android.hidl.base-V1.0-java-static \
+
+
+#
+# Build types.hal (Status)
+#
+GEN := $(intermediates)/android/frameworks/displayservice/V1_0/Status.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.frameworks:frameworks/hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.frameworks.displayservice@1.0::types.Status
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IDisplayEventReceiver.hal
+#
+GEN := $(intermediates)/android/frameworks/displayservice/V1_0/IDisplayEventReceiver.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IDisplayEventReceiver.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IEventCallback.hal
+$(GEN): $(LOCAL_PATH)/IEventCallback.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
+$(GEN): $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.frameworks:frameworks/hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.frameworks.displayservice@1.0::IDisplayEventReceiver
+
+$(GEN): $(LOCAL_PATH)/IDisplayEventReceiver.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IDisplayService.hal
+#
+GEN := $(intermediates)/android/frameworks/displayservice/V1_0/IDisplayService.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IDisplayService.hal
+$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IDisplayEventReceiver.hal
+$(GEN): $(LOCAL_PATH)/IDisplayEventReceiver.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.frameworks:frameworks/hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.frameworks.displayservice@1.0::IDisplayService
+
+$(GEN): $(LOCAL_PATH)/IDisplayService.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IEventCallback.hal
+#
+GEN := $(intermediates)/android/frameworks/displayservice/V1_0/IEventCallback.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IEventCallback.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.frameworks:frameworks/hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.frameworks.displayservice@1.0::IEventCallback
+
+$(GEN): $(LOCAL_PATH)/IEventCallback.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/displayservice/1.0/IDisplayEventReceiver.hal b/displayservice/1.0/IDisplayEventReceiver.hal
new file mode 100644
index 0000000..5ff0d44
--- /dev/null
+++ b/displayservice/1.0/IDisplayEventReceiver.hal
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.frameworks.displayservice@1.0;
+
+import IEventCallback;
+
+interface IDisplayEventReceiver {
+    /**
+     * Attach callback to start receiving events. Hotplug events are enabled
+     * by default. Vsync events must be enabled with setVsyncRate.
+     *
+     * @return status Must be:
+     *     SUCCESS if callback is initialized correctly.
+     *     BAD_VALUE if callback is nullptr or if this has already been called.
+     *     UNKNOWN if callback cannot be initialized.
+     */
+    init(IEventCallback callback) generates (Status status);
+
+    /**
+     * Must start (or stop) sending callbacks immediately as requested.
+     *
+     * @param count Request to be sent a callback for every <count>th event.
+     *              If zero, then only send callbacks when requestNextVsync is
+     *              called. By default, this will be zero. Must be >= 0.
+     * @return status Must be:
+     *     SUCCESS if rate is set successfully.
+     *     BAD_VALUE if count < 0 or no init.
+     *     UNKNOWN for all other errors.
+     */
+    setVsyncRate(int32_t count) generates (Status status);
+
+    /**
+     * Must have no effect if vsync rate (set with setVsyncRate) is 0.
+     *
+     * @return status Must be:
+     *     SUCCESS if request successfully processed.
+     *     BAD_VALUE if no init.
+     *     UNKNOWN for all other errors.
+     */
+    requestNextVsync() generates (Status status);
+
+    /**
+     * Server must drop all references to callback and stop sending events.
+     * Client must call this method if init was called.
+     *
+     * @return status Must be:
+     *     SUCCESS if request successfully processed.
+     *     BAD_VALUE if init has not been called.
+     *     UNKNOWN for all other errors.
+     */
+    close() generates (Status status);
+};
+
diff --git a/displayservice/1.0/IDisplayService.hal b/displayservice/1.0/IDisplayService.hal
new file mode 100644
index 0000000..9bc5a14
--- /dev/null
+++ b/displayservice/1.0/IDisplayService.hal
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.frameworks.displayservice@1.0;
+
+import IDisplayEventReceiver;
+
+interface IDisplayService {
+    /**
+     * Must create new receiver.
+     *
+     * @return receiver Receiver object.
+     */
+    getEventReceiver() generates(IDisplayEventReceiver receiver);
+};
diff --git a/displayservice/1.0/IEventCallback.hal b/displayservice/1.0/IEventCallback.hal
new file mode 100644
index 0000000..f16762f
--- /dev/null
+++ b/displayservice/1.0/IEventCallback.hal
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.frameworks.displayservice@1.0;
+
+interface IEventCallback {
+    /**
+     * @param timestamp Nanoseconds since boot.
+     * @param count Vsync count.
+     */
+    oneway onVsync(uint64_t timestamp, uint32_t count);
+
+    /**
+     * @param timestamp Nanoseconds since boot.
+     * @param connected Current state of hotplug.
+     */
+    oneway onHotplug(uint64_t timestamp, bool connected);
+};
diff --git a/displayservice/1.0/types.hal b/displayservice/1.0/types.hal
new file mode 100644
index 0000000..79f0f09
--- /dev/null
+++ b/displayservice/1.0/types.hal
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.frameworks.displayservice@1.0;
+
+enum Status : uint32_t {
+    SUCCESS,
+    BAD_VALUE,
+    UNKNOWN,
+};
diff --git a/displayservice/1.0/vts/functional/Android.bp b/displayservice/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..0597cf3
--- /dev/null
+++ b/displayservice/1.0/vts/functional/Android.bp
@@ -0,0 +1,35 @@
+//
+// 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.
+//
+
+cc_test {
+    name: "VtsFwkDisplayServiceV1_0TargetTest",
+    srcs: ["VtsFwkDisplayServiceV1_0TargetTest.cpp"],
+    shared_libs: [
+        "android.frameworks.displayservice@1.0",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+    static_libs: ["VtsHalHidlTargetTestBase"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-O0",
+        "-g",
+    ]
+}
+
diff --git a/displayservice/1.0/vts/functional/VtsFwkDisplayServiceV1_0TargetTest.cpp b/displayservice/1.0/vts/functional/VtsFwkDisplayServiceV1_0TargetTest.cpp
new file mode 100644
index 0000000..36f242f
--- /dev/null
+++ b/displayservice/1.0/vts/functional/VtsFwkDisplayServiceV1_0TargetTest.cpp
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "VtsFwkDisplayServiceV1_0TargetTest"
+
+#include <android/frameworks/displayservice/1.0/IDisplayEventReceiver.h>
+#include <android/frameworks/displayservice/1.0/IDisplayService.h>
+#include <android/frameworks/displayservice/1.0/IEventCallback.h>
+#include <log/log.h>
+#include <VtsHalHidlTargetTestBase.h>
+
+#include <atomic>
+#include <chrono>
+#include <cmath>
+#include <inttypes.h>
+#include <thread>
+
+using ::android::frameworks::displayservice::V1_0::IDisplayEventReceiver;
+using ::android::frameworks::displayservice::V1_0::IDisplayService;
+using ::android::frameworks::displayservice::V1_0::IEventCallback;
+using ::android::frameworks::displayservice::V1_0::Status;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using namespace ::std::chrono_literals;
+
+#define ASSERT_OK(ret) ASSERT_TRUE((ret).isOk())
+#define EXPECT_SUCCESS(retExpr) do { \
+        Return<Status> retVal = (retExpr); \
+        ASSERT_OK(retVal); \
+        EXPECT_EQ(Status::SUCCESS, static_cast<Status>(retVal)); \
+    } while(false)
+#define EXPECT_BAD_VALUE(retExpr) do { \
+        Return<Status> retVal = (retExpr); \
+        ASSERT_OK(retVal); \
+        EXPECT_EQ(Status::BAD_VALUE, static_cast<Status>(retVal)); \
+    } while(false)
+
+#define MAX_INACCURACY 3
+
+class TestCallback : public IEventCallback {
+public:
+    Return<void> onVsync(uint64_t timestamp, uint32_t count) override {
+        ALOGE("onVsync: timestamp=%" PRIu64 " count=%d", timestamp, count);
+
+        vsyncs++;
+        return Void();
+    }
+    Return<void> onHotplug(uint64_t timestamp, bool connected) override {
+        ALOGE("onVsync: timestamp=%" PRIu64 " connected=%s", timestamp, connected ? "true" : "false");
+
+        hotplugs++;
+        return Void();
+    }
+
+    std::atomic<int> vsyncs{0};
+    std::atomic<int> hotplugs{0};
+};
+
+class DisplayServiceTest : public ::testing::VtsHalHidlTargetTestBase {
+public:
+    ~DisplayServiceTest() {}
+
+    virtual void SetUp() override {
+        sp<IDisplayService> service = ::testing::VtsHalHidlTargetTestBase::getService<IDisplayService>();
+
+        ASSERT_NE(service, nullptr);
+
+        Return<sp<IDisplayEventReceiver>> ret = service->getEventReceiver();
+        ASSERT_OK(ret);
+
+        receiver = ret;
+        ASSERT_NE(receiver, nullptr);
+
+
+        cb = new TestCallback();
+        EXPECT_SUCCESS(receiver->init(cb));
+    }
+
+    virtual void TearDown() override {
+        EXPECT_SUCCESS(receiver->close());
+    }
+
+    sp<TestCallback> cb;
+    sp<IDisplayEventReceiver> receiver;
+};
+
+/**
+ * No vsync events should happen unless you explicitly request one.
+ */
+TEST_F(DisplayServiceTest, TestAttachRequestVsync) {
+    EXPECT_EQ(0, cb->vsyncs);
+
+    EXPECT_SUCCESS(receiver->requestNextVsync());
+
+    std::this_thread::sleep_for(100ms); // framerate is not fixed on Android devices
+    EXPECT_EQ(1, cb->vsyncs);
+}
+
+/**
+ * Vsync rate respects count.
+ */
+TEST_F(DisplayServiceTest, TestSetVsyncRate) {
+    ASSERT_EQ(0, cb->vsyncs);
+
+    EXPECT_SUCCESS(receiver->setVsyncRate(1));
+    std::this_thread::sleep_for(250ms);
+    int at1 = cb->vsyncs;
+
+    cb->vsyncs = 0;
+    EXPECT_SUCCESS(receiver->setVsyncRate(2));
+    std::this_thread::sleep_for(250ms);
+    int at2 = cb->vsyncs;
+
+    cb->vsyncs = 0;
+    EXPECT_SUCCESS(receiver->setVsyncRate(4));
+    std::this_thread::sleep_for(250ms);
+    int at4 = cb->vsyncs;
+
+    EXPECT_NE(0, at1);
+    EXPECT_NE(0, at2);
+    EXPECT_NE(0, at4);
+
+    EXPECT_LE(std::abs(at1 - 2 * at2), 2 * MAX_INACCURACY);
+    EXPECT_LE(std::abs(at1 - 4 * at4), 4 * MAX_INACCURACY);
+    EXPECT_LE(std::abs(at2 - 2 * at4), 2 * MAX_INACCURACY);
+
+    ALOGE("Vsync counts: %d %d %d", at1, at2, at4);
+}
+
+/**
+ * Open/close should return proper error results.
+ */
+TEST_F(DisplayServiceTest, TestOpenClose) {
+    EXPECT_BAD_VALUE(receiver->init(cb)); // already opened in SetUp
+    EXPECT_SUCCESS(receiver->close()); // can close what was originally opened
+    EXPECT_BAD_VALUE(receiver->close()); // can't close again
+    EXPECT_SUCCESS(receiver->init(cb)); // open so can close again in SetUp
+}
+
+/**
+ * Vsync must be given a value that is >= 0.
+ */
+TEST_F(DisplayServiceTest, TestVsync) {
+    EXPECT_SUCCESS(receiver->setVsyncRate(0));
+    EXPECT_SUCCESS(receiver->setVsyncRate(5));
+    EXPECT_SUCCESS(receiver->setVsyncRate(0));
+    EXPECT_BAD_VALUE(receiver->setVsyncRate(-1));
+    EXPECT_BAD_VALUE(receiver->setVsyncRate(-1000));
+}
+
+int main(int argc, char **argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    ALOGE("Test status = %d", status);
+    return status;
+}