Merge "Update makefiles for logging."
diff --git a/Android.mk b/Android.mk
deleted file mode 100644
index f9e3276..0000000
--- a/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(call all-subdir-makefiles)
diff --git a/gatekeeper/1.0/Android.bp b/gatekeeper/1.0/Android.bp
new file mode 100644
index 0000000..76ee276
--- /dev/null
+++ b/gatekeeper/1.0/Android.bp
@@ -0,0 +1,53 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+genrule {
+    name: "android.hardware.gatekeeper@1.0_genc++",
+    tools: ["hidl-gen"],
+    cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces android.hardware.gatekeeper@1.0",
+    srcs: [
+        "types.hal",
+        "IGatekeeper.hal",
+    ],
+    out: [
+        "android/hardware/gatekeeper/1.0/types.cpp",
+        "android/hardware/gatekeeper/1.0/GatekeeperAll.cpp",
+    ],
+}
+
+genrule {
+    name: "android.hardware.gatekeeper@1.0_genc++_headers",
+    tools: ["hidl-gen"],
+    cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces android.hardware.gatekeeper@1.0",
+    srcs: [
+        "types.hal",
+        "IGatekeeper.hal",
+    ],
+    out: [
+        "android/hardware/gatekeeper/1.0/types.h",
+        "android/hardware/gatekeeper/1.0/IGatekeeper.h",
+        "android/hardware/gatekeeper/1.0/IHwGatekeeper.h",
+        "android/hardware/gatekeeper/1.0/BnGatekeeper.h",
+        "android/hardware/gatekeeper/1.0/BpGatekeeper.h",
+        "android/hardware/gatekeeper/1.0/BsGatekeeper.h",
+    ],
+}
+
+cc_library_shared {
+    name: "android.hardware.gatekeeper@1.0",
+    generated_sources: ["android.hardware.gatekeeper@1.0_genc++"],
+    generated_headers: ["android.hardware.gatekeeper@1.0_genc++_headers"],
+    export_generated_headers: ["android.hardware.gatekeeper@1.0_genc++_headers"],
+    shared_libs: [
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "libutils",
+        "libcutils",
+    ],
+    export_shared_lib_headers: [
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "libutils",
+    ],
+}
diff --git a/gatekeeper/1.0/IGatekeeper.hal b/gatekeeper/1.0/IGatekeeper.hal
new file mode 100644
index 0000000..999a311
--- /dev/null
+++ b/gatekeeper/1.0/IGatekeeper.hal
@@ -0,0 +1,108 @@
+package android.hardware.gatekeeper@1.0;
+
+interface IGatekeeper {
+
+/**
+ * Enrolls desiredPassword, which may be derived from a user selected pin
+ * or password, with the private key used only for enrolling authentication
+ * factor data.
+ *
+ * If there was already a password enrolled, current password handle must be
+ * passed in currentPasswordHandle, and current password must be passed in
+ * currentPassword. Valid currentPassword must verify() against
+ * currentPasswordHandle.
+ *
+ * @param uid The Android user identifier
+ *
+ * @param currentPasswordHandle The currently enrolled password handle the user
+ *    wants to replace. May be empty only if there's no currently enrolled
+ *    password. Otherwise must be non-empty.
+ *
+ * @param currentPassword The user's current password in plain text.
+ *    it MUST verify against current_password_handle if the latter is not-empty
+ *
+ * @param desiredPassword The new password the user wishes to enroll in
+ *    plaintext.
+ *
+ * @return response
+ *    On success, data buffer must contain the new password handle referencing
+ *    the password provided in desiredPassword.
+ *    This buffer can be used on subsequent calls to enroll or
+ *    verify. On error, this buffer must be empty.
+ *    response.code must always contain operation completion status.
+ *    This method may return ERROR_GENERAL_FAILURE or ERROR_RETRY_TIMEOUT on
+ *    failure. It must return STATUS_OK on success.
+ *    If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero.
+ */
+enroll(uint32_t uid,
+       vec<uint8_t> currentPasswordHandle,
+       vec<uint8_t> currentPassword,
+       vec<uint8_t> desiredPassword)
+    generates (GatekeeperResponse response);
+
+/**
+ * Verifies that providedPassword matches enrolledPasswordHandle.
+ *
+ * Implementations of this module may retain the result of this call
+ * to attest to the recency of authentication.
+ *
+ * On success, returns verification token in response.data, which shall be
+ * usable to attest password verification to other trusted services.
+ *
+ * @param uid The Android user identifier
+ *
+ * @param challenge An optional challenge to authenticate against, or 0.
+ *    Used when a separate authenticator requests password verification,
+ *    or for transactional password authentication.
+ *
+ * @param enrolledPasswordHandle The currently enrolled password handle that
+ *    user wishes to verify against. Must be non-empty.
+ *
+ * @param providedPassword The plaintext password to be verified against the
+ *    enrolledPasswordHandle
+ *
+ * @return response
+ *    On success, a non-empty data buffer containing the
+ *    authentication token resulting from this verification is returned.
+ *    On error, data buffer must be empty.
+ *    response.code must always contain operation completion status.
+ *    This method may return ERROR_GENERAL_FAILURE or ERROR_RETRY_TIMEOUT on
+ *    failure. It must return STATUS_OK on success.
+ *    If password re-enrollment is necessary, it must return STATUS_REENROLL.
+ *    If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero.
+ */
+verify(uint32_t uid, uint64_t challenge,
+       vec<uint8_t> enrolledPasswordHandle,
+       vec<uint8_t> providedPassword)
+    generates (GatekeeperResponse response);
+
+/*
+ * Deletes the enrolledPasswordHandle associated with the uid. Once deleted
+ * the user cannot be verified anymore.
+ * This is an optional method.
+ *
+ * @param uid The Android user identifier
+ *
+ * @return response
+ *    response.code must always contain operation completion status.
+ *    This method may return ERROR_GENERAL_FAILURE or ERROR_RETRY_TIMEOUT on
+ *    failure. It must return STATUS_OK on success.
+ *    If not implemented, it must return ERROR_NOT_IMPLEMENTED.
+ *    If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero.
+ */
+deleteUser(uint32_t uid) generates (GatekeeperResponse response);
+
+/*
+ * Deletes all the enrolled_password_handles for all uid's. Once called,
+ * no users must be enrolled on the device.
+ * This is an optional method.
+ *
+ * @return response
+ *    response.code must always contain operation completion status.
+ *    This method may return ERROR_GENERAL_FAILURE or ERROR_RETRY_TIMEOUT on
+ *    failure. It must return STATUS_OK on success.
+ *    If not implemented, it must return ERROR_NOT_IMPLEMENTED.
+ *    If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero.
+ */
+deleteAllUsers() generates (GatekeeperResponse response);
+};
diff --git a/gatekeeper/1.0/default/Android.mk b/gatekeeper/1.0/default/Android.mk
new file mode 100644
index 0000000..e3b7d10
--- /dev/null
+++ b/gatekeeper/1.0/default/Android.mk
@@ -0,0 +1,40 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_MODULE := android.hardware.gatekeeper@1.0-impl
+
+LOCAL_SRC_FILES := \
+    Gatekeeper.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+    android.hardware.gatekeeper@1.0 \
+    libhardware \
+    libhidlbase \
+    libhidltransport \
+    libhwbinder \
+    libutils \
+    liblog \
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_MODULE := android.hardware.gatekeeper@1.0-service
+LOCAL_INIT_RC := android.hardware.gatekeeper@1.0-service.rc
+
+LOCAL_SRC_FILES := \
+    service.cpp    \
+
+LOCAL_SHARED_LIBRARIES := \
+    android.hardware.gatekeeper@1.0 \
+    libhardware \
+    libhidlbase \
+    libhidltransport \
+    libhwbinder \
+    libutils \
+    liblog \
+
+include $(BUILD_EXECUTABLE)
diff --git a/gatekeeper/1.0/default/Gatekeeper.cpp b/gatekeeper/1.0/default/Gatekeeper.cpp
new file mode 100644
index 0000000..8fcd8ca
--- /dev/null
+++ b/gatekeeper/1.0/default/Gatekeeper.cpp
@@ -0,0 +1,149 @@
+#define LOG_TAG "android.hardware.gatekeeper@1.0-service"
+
+#include <utils/Log.h>
+#include <dlfcn.h>
+
+#include "Gatekeeper.h"
+
+namespace android {
+namespace hardware {
+namespace gatekeeper {
+namespace V1_0 {
+namespace implementation {
+
+Gatekeeper::Gatekeeper()
+{
+    int ret = hw_get_module_by_class(GATEKEEPER_HARDWARE_MODULE_ID, NULL, &module);
+    device = NULL;
+
+    if (!ret) {
+        ret = gatekeeper_open(module, &device);
+    }
+    if (ret < 0) {
+        LOG_ALWAYS_FATAL_IF(ret < 0, "Unable to open GateKeeper HAL");
+    }
+}
+
+Gatekeeper::~Gatekeeper()
+{
+    if (device != nullptr) {
+        int ret = gatekeeper_close(device);
+        if (ret < 0) {
+            ALOGE("Unable to close GateKeeper HAL");
+        }
+    }
+    dlclose(module->dso);
+}
+
+// Methods from ::android::hardware::gatekeeper::V1_0::IGatekeeper follow.
+Return<void> Gatekeeper::enroll(uint32_t uid,
+        const hidl_vec<uint8_t>& currentPasswordHandle,
+        const hidl_vec<uint8_t>& currentPassword,
+        const hidl_vec<uint8_t>& desiredPassword,
+        enroll_cb cb)
+{
+    GatekeeperResponse rsp;
+    uint8_t *enrolled_password_handle = nullptr;
+    uint32_t enrolled_password_handle_length = 0;
+
+    int ret = device->enroll(device, uid,
+            currentPasswordHandle.data(), currentPasswordHandle.size(),
+            currentPassword.data(), currentPassword.size(),
+            desiredPassword.data(), desiredPassword.size(),
+            &enrolled_password_handle, &enrolled_password_handle_length);
+    if (!ret) {
+        rsp.data.setToExternal(enrolled_password_handle,
+                               enrolled_password_handle_length,
+                               true);
+        rsp.code = GatekeeperStatusCode::STATUS_OK;
+    } else if (ret > 0) {
+        rsp.timeout = ret;
+        rsp.code = GatekeeperStatusCode::ERROR_RETRY_TIMEOUT;
+    } else {
+        rsp.code = GatekeeperStatusCode::ERROR_GENERAL_FAILURE;
+    }
+    cb(rsp);
+    return Void();
+}
+
+Return<void> Gatekeeper::verify(uint32_t uid,
+                                uint64_t challenge,
+                                const hidl_vec<uint8_t>& enrolledPasswordHandle,
+                                const hidl_vec<uint8_t>& providedPassword,
+                                verify_cb cb)
+{
+    GatekeeperResponse rsp;
+    uint8_t *auth_token = nullptr;
+    uint32_t auth_token_length = 0;
+    bool request_reenroll = false;
+
+    int ret = device->verify(device, uid, challenge,
+            enrolledPasswordHandle.data(), enrolledPasswordHandle.size(),
+            providedPassword.data(), providedPassword.size(),
+            &auth_token, &auth_token_length,
+            &request_reenroll);
+    if (!ret) {
+        rsp.data.setToExternal(auth_token, auth_token_length, true);
+        if (request_reenroll) {
+            rsp.code = GatekeeperStatusCode::STATUS_REENROLL;
+        } else {
+            rsp.code = GatekeeperStatusCode::STATUS_OK;
+        }
+    } else if (ret > 0) {
+        rsp.timeout = ret;
+        rsp.code = GatekeeperStatusCode::ERROR_RETRY_TIMEOUT;
+    } else {
+        rsp.code = GatekeeperStatusCode::ERROR_GENERAL_FAILURE;
+    }
+    cb(rsp);
+    return Void();
+}
+
+Return<void> Gatekeeper::deleteUser(uint32_t uid, deleteUser_cb cb)  {
+    GatekeeperResponse rsp;
+
+    if (device->delete_user != nullptr) {
+        int ret = device->delete_user(device, uid);
+        if (!ret) {
+            rsp.code = GatekeeperStatusCode::STATUS_OK;
+        } else if (ret > 0) {
+            rsp.timeout = ret;
+            rsp.code = GatekeeperStatusCode::ERROR_RETRY_TIMEOUT;
+        } else {
+            rsp.code = GatekeeperStatusCode::ERROR_GENERAL_FAILURE;
+        }
+    } else {
+        rsp.code = GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED;
+    }
+    cb(rsp);
+    return Void();
+}
+
+Return<void> Gatekeeper::deleteAllUsers(deleteAllUsers_cb cb)  {
+    GatekeeperResponse rsp;
+    if (device->delete_all_users != nullptr) {
+        int ret = device->delete_all_users(device);
+        if (!ret) {
+            rsp.code = GatekeeperStatusCode::STATUS_OK;
+        } else if (ret > 0) {
+            rsp.timeout = ret;
+            rsp.code = GatekeeperStatusCode::ERROR_RETRY_TIMEOUT;
+        } else {
+            rsp.code = GatekeeperStatusCode::ERROR_GENERAL_FAILURE;
+        }
+    } else {
+        rsp.code = GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED;
+    }
+    cb(rsp);
+    return Void();
+}
+
+IGatekeeper* HIDL_FETCH_IGatekeeper(const char* /* name */) {
+    return new Gatekeeper();
+}
+
+} // namespace implementation
+}  // namespace V1_0
+}  // namespace gatekeeper
+}  // namespace hardware
+}  // namespace android
diff --git a/gatekeeper/1.0/default/Gatekeeper.h b/gatekeeper/1.0/default/Gatekeeper.h
new file mode 100644
index 0000000..a2188d4
--- /dev/null
+++ b/gatekeeper/1.0/default/Gatekeeper.h
@@ -0,0 +1,57 @@
+#ifndef HIDL_GENERATED_android_hardware_gatekeeper_V1_0_Gatekeeper_H_
+#define HIDL_GENERATED_android_hardware_gatekeeper_V1_0_Gatekeeper_H_
+
+#include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include <hardware/hardware.h>
+#include <hardware/gatekeeper.h>
+
+namespace android {
+namespace hardware {
+namespace gatekeeper {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gatekeeper::V1_0::GatekeeperResponse;
+using ::android::hardware::gatekeeper::V1_0::IGatekeeper;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+class Gatekeeper : public IGatekeeper {
+public:
+    Gatekeeper();
+    ~Gatekeeper();
+
+    // Methods from ::android::hardware::gatekeeper::V1_0::IGatekeeper follow.
+    Return<void> enroll(uint32_t uid,
+                        const hidl_vec<uint8_t>& currentPasswordHandle,
+                        const hidl_vec<uint8_t>& currentPassword,
+                        const hidl_vec<uint8_t>& desiredPassword,
+                        enroll_cb _hidl_cb)  override;
+    Return<void> verify(uint32_t uid,
+                        uint64_t challenge,
+                        const hidl_vec<uint8_t>& enrolledPasswordHandle,
+                        const hidl_vec<uint8_t>& providedPassword,
+                        verify_cb _hidl_cb)  override;
+    Return<void> deleteUser(uint32_t uid, deleteUser_cb _hidl_cb)  override;
+    Return<void> deleteAllUsers(deleteAllUsers_cb _hidl_cb)  override;
+private:
+    gatekeeper_device_t *device;
+    const hw_module_t *module;
+};
+
+extern "C" IGatekeeper* HIDL_FETCH_IGatekeeper(const char* name);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gatekeeper
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HIDL_GENERATED_android_hardware_gatekeeper_V1_0_Gatekeeper_H_
diff --git a/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc b/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc
new file mode 100644
index 0000000..ac15e23
--- /dev/null
+++ b/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc
@@ -0,0 +1,4 @@
+service gatekeeper-1-0 /system/bin/hw/android.hardware.gatekeeper@1.0-service
+    class hal
+    user system
+    group system
diff --git a/gatekeeper/1.0/default/service.cpp b/gatekeeper/1.0/default/service.cpp
new file mode 100644
index 0000000..c3fc25c
--- /dev/null
+++ b/gatekeeper/1.0/default/service.cpp
@@ -0,0 +1,13 @@
+#define LOG_TAG "android.hardware.gatekeeper@1.0-service"
+
+#include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
+
+#include <hidl/LegacySupport.h>
+
+// Generated HIDL files
+using android::hardware::gatekeeper::V1_0::IGatekeeper;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+    return defaultPassthroughServiceImplementation<IGatekeeper>("gatekeeper");
+}
diff --git a/gatekeeper/1.0/types.hal b/gatekeeper/1.0/types.hal
new file mode 100644
index 0000000..9ab1152
--- /dev/null
+++ b/gatekeeper/1.0/types.hal
@@ -0,0 +1,27 @@
+package android.hardware.gatekeeper@1.0;
+
+/**
+ * Gatekeeper response codes; success >= 0; error < 0
+ */
+enum GatekeeperStatusCode : int32_t {
+  STATUS_REENROLL       =  1,  // success, but upper layers should re-enroll
+                               // the verified password due to a version change
+  STATUS_OK             =  0,  // operation is successful
+  ERROR_GENERAL_FAILURE = -1,  // operation failed
+  ERROR_RETRY_TIMEOUT   = -2,  // operation should be retried after timeout
+  ERROR_NOT_IMPLEMENTED = -3,  // operation is not implemented
+};
+
+/**
+ * Gatekeeper response to any/all requests has this structure as mandatory part
+ */
+struct GatekeeperResponse {
+    /* request completion status */
+    GatekeeperStatusCode code;
+    /* retry timeout in ms, if code == ERROR_RETRY_TIMEOUT
+     * otherwise unused (0)
+     */
+    uint32_t timeout;
+    /* optional crypto blob */
+    vec<uint8_t> data;
+};
diff --git a/gatekeeper/Android.bp b/gatekeeper/Android.bp
new file mode 100644
index 0000000..bbb3e4b
--- /dev/null
+++ b/gatekeeper/Android.bp
@@ -0,0 +1,4 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+    "1.0",
+]
diff --git a/light/2.0/vts/functional/Android.bp b/light/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..c3475a6
--- /dev/null
+++ b/light/2.0/vts/functional/Android.bp
@@ -0,0 +1,32 @@
+//
+// 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: "light_hidl_hal_test",
+    gtest: true,
+    srcs: ["light_hidl_hal_test.cpp"],
+    shared_libs: [
+        "liblog",
+        "libutils",
+        "android.hardware.light@2.0",
+    ],
+    static_libs: ["libgtest"],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
+
diff --git a/light/2.0/vts/functional/light_hidl_hal_test.cpp b/light/2.0/vts/functional/light_hidl_hal_test.cpp
new file mode 100644
index 0000000..db67467
--- /dev/null
+++ b/light/2.0/vts/functional/light_hidl_hal_test.cpp
@@ -0,0 +1,103 @@
+/*
+ * 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 "light_hidl_hal_test"
+
+#include <android-base/logging.h>
+#include <android/hardware/light/2.0/ILight.h>
+#include <android/hardware/light/2.0/types.h>
+#include <gtest/gtest.h>
+#include <unistd.h>
+
+using ::android::hardware::light::V2_0::Brightness;
+using ::android::hardware::light::V2_0::Flash;
+using ::android::hardware::light::V2_0::ILight;
+using ::android::hardware::light::V2_0::LightState;
+using ::android::hardware::light::V2_0::Status;
+using ::android::hardware::light::V2_0::Type;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+#define LIGHT_SERVICE_NAME "light"
+
+#define EXPECT_OK(ret) EXPECT_TRUE(ret.getStatus().isOk())
+
+// The main test class for VIBRATOR HIDL HAL.
+class LightHidlTest : public ::testing::Test {
+public:
+    virtual void SetUp() override {
+        light = ILight::getService(LIGHT_SERVICE_NAME);
+
+        ASSERT_NE(light, nullptr);
+        ALOGI("Test is remote: %d", light->isRemote());
+    }
+
+    virtual void TearDown() override {}
+
+    sp<ILight> light;
+};
+
+// A class for test environment setup (kept since this file is a template).
+class LightHidlEnvironment : public ::testing::Environment {
+public:
+    virtual void SetUp() {}
+    virtual void TearDown() {}
+
+private:
+};
+
+const static LightState kWhite = {
+    .color = 0xFFFFFFFF,
+    .flashMode = Flash::TIMED,
+    .flashOnMs = 100,
+    .flashOffMs = 50,
+    .brightnessMode = Brightness::USER,
+};
+
+const static LightState kOff = {
+    .color = 0x00000000,
+    .flashMode = Flash::NONE,
+    .flashOnMs = 0,
+    .flashOffMs = 0,
+    .brightnessMode = Brightness::USER,
+};
+
+/**
+ * Ensure all lights which are reported as supported work.
+ */
+TEST_F(LightHidlTest, TestSupported) {
+    EXPECT_OK(light->getSupportedTypes([this](const hidl_vec<Type> &supportedTypes) {
+        for (size_t i = 0; i < supportedTypes.size(); i++) {
+            EXPECT_OK(light->setLight(supportedTypes[i], kWhite));
+        }
+
+        usleep(500000);
+
+        for (size_t i = 0; i < supportedTypes.size(); i++) {
+            EXPECT_OK(light->setLight(supportedTypes[i], kOff));
+        }
+    }));
+}
+
+int main(int argc, char **argv) {
+    ::testing::AddGlobalTestEnvironment(new LightHidlEnvironment);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    ALOGI("Test result = %d", status);
+    return status;
+}
diff --git a/light/Android.bp b/light/Android.bp
index c12cd4f..8d2c986 100644
--- a/light/Android.bp
+++ b/light/Android.bp
@@ -1,4 +1,5 @@
 // This is an autogenerated file, do not edit.
 subdirs = [
     "2.0",
+    "2.0/vts/functional",
 ]