Merge "ledflasher: Use lights HAL if it is available."
diff --git a/src/ledflasher/ledflasher.cpp b/src/ledflasher/ledflasher.cpp
index 3c5fed1..4d43df2 100644
--- a/src/ledflasher/ledflasher.cpp
+++ b/src/ledflasher/ledflasher.cpp
@@ -189,7 +189,9 @@
     {"_ledflasher._status", status_},
     {"_ledflasher._leds", leds},
   };
-  CHECK(device_->SetStateProperties(state_change, nullptr));
+  // TODO: Come up with a design for ledflasher.cpp such that this call never
+  // fails.
+  device_->SetStateProperties(state_change, nullptr);
 }
 
 int main(int argc, char* argv[]) {
diff --git a/src/ledservice/Android.mk b/src/ledservice/Android.mk
index e739232..492211c 100644
--- a/src/ledservice/Android.mk
+++ b/src/ledservice/Android.mk
@@ -32,9 +32,11 @@
 	libchrome \
 	libchrome-dbus \
 	libdbus \
+	libhardware \
+	libutils \
 
 LOCAL_C_INCLUDES := external/gtest/include
-LOCAL_CFLAGS := -Wall -Werror -Wno-sign-promo
+LOCAL_CFLAGS := -Wall -Werror -Wno-sign-promo -Wno-missing-field-initializers
 LOCAL_RTTI_FLAG := -frtti
 
 include $(BUILD_EXECUTABLE)
diff --git a/src/ledservice/ledstatus.cpp b/src/ledservice/ledstatus.cpp
index 5fac42c..a51ea2a 100644
--- a/src/ledservice/ledstatus.cpp
+++ b/src/ledservice/ledstatus.cpp
@@ -47,7 +47,61 @@
 
 }  // anonymous namespace
 
+LedStatus::LedStatus() {
+  // Try to open the lights hal.
+  int ret = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, &lights_hal_);
+  if (ret) {
+    LOG(ERROR) << "Failed to load the lights HAL.";
+    return;
+  }
+  CHECK(lights_hal_);
+  LOG(INFO) << "Loaded lights HAL.";
+
+  // If we can open the hal, then we map each number from 1 - 4 to one of the
+  // leds available on the board. Note, multiple numbers could be mapped to the
+  // same led.
+  const std::initializer_list<const char*> kLogicalLights = {
+    LIGHT_ID_BACKLIGHT, LIGHT_ID_KEYBOARD, LIGHT_ID_BUTTONS, LIGHT_ID_BATTERY,
+    LIGHT_ID_NOTIFICATIONS, LIGHT_ID_ATTENTION, LIGHT_ID_BLUETOOTH,
+    LIGHT_ID_WIFI};
+  size_t led_index = 0;
+  for (const char* light_name : kLogicalLights) {
+    light_device_t* light_device = nullptr;
+    ret = lights_hal_->methods->open(
+        lights_hal_, light_name,
+        reinterpret_cast<hw_device_t**>(&light_device));
+    // If a given light device couldn't be opened, don't map it to a number.
+    if (ret || !light_device) {
+      continue;
+    }
+    hal_led_map_.emplace(led_index, light_name);
+    led_index++;
+    if (led_index == num_leds) {
+      // We have already mapped all num_leds LEDs.
+      break;
+    }
+  }
+
+  // If the size of the map is zero, then the lights hal doesn't have any valid
+  // leds.
+  if (hal_led_map_.empty()) {
+    LOG(ERROR) << "Unable to open any light devices using the hal.";
+    lights_hal_ = nullptr;
+    return;
+  }
+
+  // If not all 4 numbers have been mapped, then we map them to the first led
+  // mapped.
+  for (size_t i = hal_led_map_.size(); i < num_leds; i++) {
+    hal_led_map_.emplace(i, hal_led_map_[0]);
+  }
+  hal_led_status_.resize(num_leds);
+}
+
 std::vector<bool> LedStatus::GetStatus() const {
+  if (lights_hal_)
+    return hal_led_status_;
+
   std::vector<bool> leds(num_leds);
   for (size_t index = 0; index < num_leds; index++)
     leds[index] = IsLedOn(index);
@@ -75,6 +129,37 @@
 }
 
 void LedStatus::SetLedStatus(size_t index, bool on) {
+  if (lights_hal_) {
+    light_state_t state = {};
+    state.color = on;
+    state.flashMode = LIGHT_FLASH_NONE;
+    state.flashOnMS = 0;
+    state.flashOffMS = 0;
+    state.brightnessMode = BRIGHTNESS_MODE_USER;
+    light_device_t* light_device = nullptr;
+    int rc = lights_hal_->methods->open(
+        lights_hal_, hal_led_map_[index].c_str(),
+        reinterpret_cast<hw_device_t**>(&light_device));
+    if (rc) {
+      LOG(ERROR) << "Unable to open " << hal_led_map_[index];
+      return;
+    }
+    CHECK(light_device);
+    rc = light_device->set_light(light_device, &state);
+    if (rc) {
+      LOG(ERROR) << "Unable to set " << hal_led_map_[index];
+      return;
+    }
+    hal_led_status_[index] = on;
+    light_device->common.close(
+        reinterpret_cast<hw_device_t*>(light_device));
+    if (rc) {
+      LOG(ERROR) << "Unable to close " << hal_led_map_[index];
+      return;
+    }
+    return;
+  }
+
   brillo::StreamPtr stream = GetLEDDataStream(index, true);
   if (!stream)
     return;
diff --git a/src/ledservice/ledstatus.h b/src/ledservice/ledstatus.h
index f12e958..dc9a472 100644
--- a/src/ledservice/ledstatus.h
+++ b/src/ledservice/ledstatus.h
@@ -17,13 +17,15 @@
 #ifndef LEDFLASHER_SRC_LEDSERVICE_LEDSTATUS_H_
 #define LEDFLASHER_SRC_LEDSERVICE_LEDSTATUS_H_
 
+#include <map>
 #include <vector>
 
 #include <base/macros.h>
+#include <hardware/lights.h>
 
 class LedStatus final {
  public:
-  LedStatus() = default;
+  LedStatus();
 
   std::vector<bool> GetStatus() const;
   bool IsLedOn(size_t index) const;
@@ -32,6 +34,13 @@
   static const size_t num_leds = 4;
 
  private:
+  const hw_module_t* lights_hal_{nullptr};
+  // Maps the lights available to the hal to numbers 1 - 4. It is possible for
+  // multiple numbers to be mapped to the same led on the board.
+  std::map<size_t, std::string> hal_led_map_;
+  // Since the hal doesn't have a way to track the led status, we maintain that
+  // info here.
+  std::vector<bool> hal_led_status_;
 
   DISALLOW_COPY_AND_ASSIGN(LedStatus);
 };