Create google light interface for high brightness mode

The hardware.google.light@1.0 inherits form android.hardware.light@2.0.
And extend the method setHBM for high brightness mode.

Bug: 109762428
Change-Id: Iaed4015f8d7bd7d36eb62ba058ae234f8ae13a04
diff --git a/CleanSpec.mk b/CleanSpec.mk
new file mode 100644
index 0000000..c0ac8d6
--- /dev/null
+++ b/CleanSpec.mk
@@ -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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+$(call add-clean-step, find $(PRODUCT_OUT) -name "*vendor.google.light@1.0*" | xargs rm -rf)
+$(call add-clean-step, find $(PRODUCT_OUT) -name "*hardware.google.light@1.0*" | xargs rm -rf)
diff --git a/current.txt b/current.txt
index e55fc67..1518722 100644
--- a/current.txt
+++ b/current.txt
@@ -1,5 +1,6 @@
 # HALs released in Android P
 
+b5f3bf3382d7bddf9c22a5f132ff265168e68c4e5373db702cb260d8b20f27d8 hardware.google.light@1.0::ILight
 18d5a8fc92f66988a917ab8154f03a19ae8c172ed4000962e230d3c54c9f6ac3 hardware.google.media.c2@1.0::types
 5efedcb7df51c465bc0363debbddfb6818ce2e9a813920e7ba0353f855a08d34 hardware.google.media.c2@1.0::IComponent
 b2932a158633c93cff94f3c9b8728f9cb64db8894c9e7b818e5615f7f004b9f1 hardware.google.media.c2@1.0::IComponentInterface
diff --git a/light/1.0/Android.bp b/light/1.0/Android.bp
new file mode 100644
index 0000000..560b3d1
--- /dev/null
+++ b/light/1.0/Android.bp
@@ -0,0 +1,13 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "hardware.google.light@1.0",
+    root: "hardware.google",
+    srcs: [
+        "ILight.hal",
+    ],
+    interfaces: [
+        "android.hardware.light@2.0",
+        "android.hidl.base@1.0",
+    ],
+}
diff --git a/light/1.0/ILight.hal b/light/1.0/ILight.hal
new file mode 100644
index 0000000..d857a5a
--- /dev/null
+++ b/light/1.0/ILight.hal
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package hardware.google.light@1.0;
+
+import android.hardware.light@2.0::ILight;
+import android.hardware.light@2.0::Status;
+
+interface ILight extends android.hardware.light@2.0::ILight {
+
+    /**
+     * Set High Brightness Mode state to light.
+     *
+     * @param  on/off state
+     * @return status result of applying state transformation.
+     */
+    setHbm(bool state) generates (Status status);
+};
diff --git a/light/1.0/default/Android.bp b/light/1.0/default/Android.bp
new file mode 100644
index 0000000..1dc781c
--- /dev/null
+++ b/light/1.0/default/Android.bp
@@ -0,0 +1,39 @@
+//
+// 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_binary {
+    name: "hardware.google.light@1.0-service",
+    relative_install_path: "hw",
+    defaults: ["hidl_defaults"],
+    init_rc: ["hardware.google.light@1.0-service.rc"],
+    vendor: true,
+    srcs: [
+        "Light.cpp",
+        "LightExt.cpp",
+        "service.cpp",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libbase",
+        "libutils",
+        "libhardware",
+        "libhidlbase",
+        "libhidltransport",
+        "android.hardware.light@2.0",
+        "hardware.google.light@1.0",
+    ],
+}
diff --git a/light/1.0/default/Light.cpp b/light/1.0/default/Light.cpp
new file mode 100644
index 0000000..902b082
--- /dev/null
+++ b/light/1.0/default/Light.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2016-2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "light"
+
+#include <log/log.h>
+
+#include <stdio.h>
+
+#include "Light.h"
+
+namespace android {
+namespace hardware {
+namespace light {
+namespace V2_0 {
+namespace implementation {
+
+static_assert(LIGHT_FLASH_NONE == static_cast<int>(Flash::NONE),
+              "Flash::NONE must match legacy value.");
+static_assert(LIGHT_FLASH_TIMED == static_cast<int>(Flash::TIMED),
+              "Flash::TIMED must match legacy value.");
+static_assert(LIGHT_FLASH_HARDWARE == static_cast<int>(Flash::HARDWARE),
+              "Flash::HARDWARE must match legacy value.");
+
+static_assert(BRIGHTNESS_MODE_USER == static_cast<int>(Brightness::USER),
+              "Brightness::USER must match legacy value.");
+static_assert(BRIGHTNESS_MODE_SENSOR == static_cast<int>(Brightness::SENSOR),
+              "Brightness::SENSOR must match legacy value.");
+static_assert(BRIGHTNESS_MODE_LOW_PERSISTENCE ==
+                  static_cast<int>(Brightness::LOW_PERSISTENCE),
+              "Brightness::LOW_PERSISTENCE must match legacy value.");
+
+Light::Light(std::map<Type, light_device_t*>&& lights)
+    : mLights(std::move(lights)) {}
+
+// Methods from ::android::hardware::light::V2_0::ILight follow.
+Return<Status> Light::setLight(Type type, const LightState& state) {
+  auto it = mLights.find(type);
+
+  if (it == mLights.end()) return Status::LIGHT_NOT_SUPPORTED;
+
+  light_device_t* hwLight = it->second;
+
+  light_state_t legacyState{
+      .color = state.color,
+      .flashMode = static_cast<int>(state.flashMode),
+      .flashOnMS = state.flashOnMs,
+      .flashOffMS = state.flashOffMs,
+      .brightnessMode = static_cast<int>(state.brightnessMode),
+  };
+
+  int ret = hwLight->set_light(hwLight, &legacyState);
+
+  switch (ret) {
+    case -ENOSYS:
+      return Status::BRIGHTNESS_NOT_SUPPORTED;
+    case 0:
+      return Status::SUCCESS;
+    default:
+      return Status::UNKNOWN;
+  }
+}
+
+Return<void> Light::getSupportedTypes(getSupportedTypes_cb _hidl_cb) {
+  std::vector<Type> types(mLights.size());
+
+  int idx = 0;
+  for (const auto& pair : mLights) {
+    types[idx++] = pair.first;
+  }
+
+  hidl_vec<Type> hidl_types{};
+  hidl_types.setToExternal(types.data(), types.size());
+
+  _hidl_cb(hidl_types);
+
+  return Void();
+}
+
+static const std::map<Type, const char*> kLogicalLights = {
+    {Type::BACKLIGHT, LIGHT_ID_BACKLIGHT},
+    {Type::KEYBOARD, LIGHT_ID_KEYBOARD},
+    {Type::BUTTONS, LIGHT_ID_BUTTONS},
+    {Type::BATTERY, LIGHT_ID_BATTERY},
+    {Type::NOTIFICATIONS, LIGHT_ID_NOTIFICATIONS},
+    {Type::ATTENTION, LIGHT_ID_ATTENTION},
+    {Type::BLUETOOTH, LIGHT_ID_BLUETOOTH},
+    {Type::WIFI, LIGHT_ID_WIFI}};
+
+Return<void> Light::debug(const hidl_handle& handle,
+                          const hidl_vec<hidl_string>& /* options */) {
+  if (handle == nullptr || handle->numFds < 1) {
+    ALOGE("debug called with no handle\n");
+    return Void();
+  }
+
+  int fd = handle->data[0];
+  if (fd < 0) {
+    ALOGE("invalid FD: %d\n", handle->data[0]);
+    return Void();
+  }
+
+  dprintf(fd, "The following lights are registered: ");
+  for (const auto& pair : mLights) {
+    const Type type = pair.first;
+    dprintf(fd, "%s,", kLogicalLights.at(type));
+  }
+  dprintf(fd, ".\n");
+  fsync(fd);
+  return Void();
+}
+
+light_device_t* getLightDevice(const char* name) {
+  light_device_t* lightDevice;
+  const hw_module_t* hwModule = NULL;
+
+  int ret = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, &hwModule);
+  if (ret == 0) {
+    ret = hwModule->methods->open(
+        hwModule, name, reinterpret_cast<hw_device_t**>(&lightDevice));
+    if (ret != 0)
+      ALOGE("light_open %s %s failed: %d", LIGHTS_HARDWARE_MODULE_ID, name,
+            ret);
+  } else {
+    ALOGE("hw_get_module %s %s failed: %d", LIGHTS_HARDWARE_MODULE_ID, name,
+          ret);
+  }
+
+  if (ret == 0) {
+    return lightDevice;
+  } else {
+    ALOGE("Light passthrough failed to load legacy HAL.");
+    return nullptr;
+  }
+}
+
+ILight* HIDL_FETCH_ILight(const char* /* name */) {
+  std::map<Type, light_device_t*> lights;
+
+  for (const auto& pair : kLogicalLights) {
+    Type type = pair.first;
+    const char* name = pair.second;
+
+    light_device_t* light = getLightDevice(name);
+
+    if (light != nullptr) lights[type] = light;
+  }
+
+  if (lights.size() == 0) {
+    // Log information, but still return new Light.
+    // Some devices may not have any lights.
+    ALOGI("Could not open any lights.");
+  }
+
+  return new Light(std::move(lights));
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace light
+}  // namespace hardware
+}  // namespace android
diff --git a/light/1.0/default/Light.h b/light/1.0/default/Light.h
new file mode 100644
index 0000000..9c8e3bc
--- /dev/null
+++ b/light/1.0/default/Light.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016-2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H
+#define ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H
+
+#include <android/hardware/light/2.0/ILight.h>
+#include <hardware/hardware.h>
+#include <hardware/lights.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <map>
+
+namespace android {
+namespace hardware {
+namespace light {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+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;
+
+struct Light : public ILight {
+  Light(std::map<Type, light_device_t*>&& lights);
+
+  Return<Status> setLight(Type type, const LightState& state) override;
+  Return<void> getSupportedTypes(getSupportedTypes_cb _hidl_cb) override;
+
+  Return<void> debug(const hidl_handle& handle,
+                     const hidl_vec<hidl_string>& options) override;
+
+ private:
+  std::map<Type, light_device_t*> mLights;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace light
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H
diff --git a/light/1.0/default/LightExt.cpp b/light/1.0/default/LightExt.cpp
new file mode 100644
index 0000000..ee8790c
--- /dev/null
+++ b/light/1.0/default/LightExt.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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 <android-base/file.h>
+#include <hardware/lights.h>
+#include <log/log.h>
+
+#include "LightExt.h"
+
+namespace hardware {
+namespace google {
+namespace light {
+namespace V1_0 {
+namespace implementation {
+using ::android::hardware::light::V2_0::Brightness;
+
+Return<Status> LightExt::applyHBM(bool on) {
+  if (!mHasHbmNode) return Status::UNKNOWN;
+
+  /* skip if no change */
+  if (mRegHBM == mCurHBM) return Status::SUCCESS;
+
+  if (!android::base::WriteStringToFile((on ? "1" : "0"),
+                                        kHighBrightnessModeNode)) {
+    ALOGE("write HBM failed!");
+    return Status::UNKNOWN;
+  }
+
+  mCurHBM = on;
+  ALOGI("Set HBM to %d", on);
+  return Status::SUCCESS;
+}
+
+// Methods from ::android::hardware::light::V2_0::ILight follow.
+Return<Status> LightExt::setLight(Type type, const LightState& state) {
+  if (type == Type::BACKLIGHT) {
+    if (state.brightnessMode == Brightness::LOW_PERSISTENCE) {
+      applyHBM(false);
+      mVRMode = true;
+    } else {
+      applyHBM(mRegHBM);
+      mVRMode = false;
+    }
+  }
+  return mLight->setLight(type, state);
+}
+
+// Methods from ::hardware::google::light::V1_0::ILight follow.
+Return<Status> LightExt::setHbm(bool on) {
+  /* save the request state */
+  mRegHBM = on;
+
+  if (mVRMode) return Status::UNKNOWN;
+
+  Status status = applyHBM(mRegHBM);
+
+  return status;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace light
+}  // namespace google
+}  // namespace hardware
diff --git a/light/1.0/default/LightExt.h b/light/1.0/default/LightExt.h
new file mode 100644
index 0000000..aca3b2a
--- /dev/null
+++ b/light/1.0/default/LightExt.h
@@ -0,0 +1,68 @@
+/*
+ * 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 HARDWARE_GOOGLE_LIGHT_V1_0_LIGHT_H
+#define HARDWARE_GOOGLE_LIGHT_V1_0_LIGHT_H
+
+#include <hidl/Status.h>
+#include <string>
+
+#include <hidl/MQDescriptor.h>
+#include <hardware/google/light/1.0/ILight.h>
+#include "Light.h"
+
+namespace hardware {
+namespace google {
+namespace light {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::light::V2_0::LightState;
+using ::android::hardware::light::V2_0::Status;
+using ::android::hardware::light::V2_0::Type;
+using HwILight = ::android::hardware::light::V2_0::ILight;
+
+constexpr const char kHighBrightnessModeNode[] =
+    "/sys/class/backlight/panel0-backlight/hbm_mode";
+
+struct LightExt : public ::hardware::google::light::V1_0::ILight {
+  LightExt(HwILight*&& light) : mLight(light) {
+    mHasHbmNode = !access(kHighBrightnessModeNode, F_OK);
+  };
+  // Methods from ::android::hardware::light::V2_0::ILight follow.
+  Return<Status> setLight(Type type, const LightState& state) override;
+  Return<void> getSupportedTypes(getSupportedTypes_cb _hidl_cb) override {
+    return mLight->getSupportedTypes(_hidl_cb);
+  }
+
+  // Methods from ::hardware::google::light::V1_0::ILight follow.
+  Return<Status> setHbm(bool on) override;
+
+ private:
+  std::unique_ptr<HwILight> mLight;
+  Return<Status> applyHBM(bool on);
+  bool mVRMode = 0;
+  bool mRegHBM = 0;
+  bool mCurHBM = 0;
+  bool mHasHbmNode = false;
+};
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace light
+}  // namespace google
+}  // namespace hardware
+
+#endif  // HARDWARD_GOOGLE_LIGHT_V1_0_LIGHT_H
diff --git a/light/1.0/default/hardware.google.light@1.0-service.rc b/light/1.0/default/hardware.google.light@1.0-service.rc
new file mode 100644
index 0000000..a30eb5e
--- /dev/null
+++ b/light/1.0/default/hardware.google.light@1.0-service.rc
@@ -0,0 +1,7 @@
+service vendor.light-1-0 /vendor/bin/hw/hardware.google.light@1.0-service
+    interface hardware.google.light@1.0::ILight default
+    class hal
+    user system
+    group system
+    # shutting off lights while powering-off
+    shutdown critical
diff --git a/light/1.0/default/service.cpp b/light/1.0/default/service.cpp
new file mode 100644
index 0000000..31bf202
--- /dev/null
+++ b/light/1.0/default/service.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "hardware.google.light@1.0-service"
+
+#include <hardware/lights.h>
+#include <hidl/LegacySupport.h>
+#include <hardware/google/light/1.0/ILight.h>
+#include "LightExt.h"
+
+namespace android {
+namespace hardware {
+namespace light {
+namespace V2_0 {
+namespace implementation {
+
+extern ILight* HIDL_FETCH_ILight(const char* /* name */);
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace light
+}  // namespace hardware
+}  // namespace android
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using hardware::google::light::V1_0::implementation::LightExt;
+using hwLight = hardware::google::light::V1_0::ILight;
+
+int main() {
+  configureRpcThreadpool(1, true /*willJoinThreadpool*/);
+
+  android::sp<hwLight> light = new LightExt{
+      android::hardware::light::V2_0::implementation::HIDL_FETCH_ILight(
+          nullptr)};
+  auto ret = light->registerAsService();
+  if (ret != android::OK) {
+    ALOGE("open light servie failed, ret=%d", ret);
+    return 1;
+  }
+  joinRpcThreadpool();
+  return 1;
+}