zenfone6: Import binderized lights HAL

* Remove blue led support

Change-Id: Ibac971507e6e95ad9d558a3eb45c4edf5c37552d
diff --git a/device.mk b/device.mk
index 0d46c67..317f9a1 100755
--- a/device.mk
+++ b/device.mk
@@ -112,6 +112,10 @@
     VisualizationWallpapers \
     librs_jni
 
+# Lights
+PRODUCT_PACKAGES += \
+    android.hardware.light@2.0-service.asus_msmnile
+
 # Media
 PRODUCT_COPY_FILES += \
     $(LOCAL_PATH)/configs/media_profiles_vendor.xml:system/etc/media_profiles_vendor.xml
diff --git a/lights/.clang-format b/lights/.clang-format
new file mode 100644
index 0000000..ae4a451
--- /dev/null
+++ b/lights/.clang-format
@@ -0,0 +1,11 @@
+BasedOnStyle: Google
+AccessModifierOffset: -2
+AllowShortFunctionsOnASingleLine: Inline
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+UseTab: Never
+PenaltyExcessCharacter: 32
diff --git a/lights/Android.bp b/lights/Android.bp
new file mode 100644
index 0000000..30e9a1e
--- /dev/null
+++ b/lights/Android.bp
@@ -0,0 +1,31 @@
+// Copyright (C) 2018 The LineageOS 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 {
+    relative_install_path: "hw",
+    defaults: ["hidl_defaults"],
+    name: "android.hardware.light@2.0-service.asus_msmnile",
+    init_rc: ["android.hardware.light@2.0-service.asus_msmnile.rc"],
+    srcs: ["service.cpp", "Light.cpp"],
+    shared_libs: [
+        "android.hardware.light@2.0",
+        "libbase",
+        "libhardware",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "liblog",
+        "libutils",
+    ],
+}
diff --git a/lights/Light.cpp b/lights/Light.cpp
new file mode 100644
index 0000000..e4178e7
--- /dev/null
+++ b/lights/Light.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2014, 2017-2018 The  Linux Foundation. All rights reserved.
+ * Not a contribution
+ * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2018-2019 The LineageOS 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 "LightsService"
+
+#include "Light.h"
+#include <android-base/logging.h>
+#include <fstream>
+
+namespace {
+/*
+ * Write value to path and close file.
+ */
+template <typename T>
+static void set(const std::string& path, const T& value) {
+    std::ofstream file(path);
+
+    if (!file.is_open()) {
+        LOG(DEBUG) << "failed to open path " << path;
+        return;
+    }
+
+    file << value;
+
+    if (file.fail()) {
+        LOG(DEBUG) << "failed to write " << value
+                   << "to " << path;
+    }
+}
+
+/*
+ * Read from path and close file.
+ * Return def in case of any failure.
+ */
+template <typename T>
+static T get(const std::string& path, const T& def) {
+    std::ifstream file(path);
+    T result;
+
+    if (!file.is_open()) {
+        LOG(DEBUG) << "failed to open path " << path;
+        return def;
+    }
+
+    file >> result;
+
+    if (file.fail()) {
+        LOG(DEBUG) << "failed to read from " << path;
+        return def;
+    }
+
+    return result;
+}
+}  // anonymous namespace
+
+namespace android {
+namespace hardware {
+namespace light {
+namespace V2_0 {
+namespace implementation {
+
+static constexpr int kDefaultMaxBrightness = 255;
+static constexpr char kBreath[] = "breath";
+static constexpr char kBrightness[] = "brightness";
+static constexpr char kDelayOff[] = "delay_off";
+static constexpr char kDelayOn[] = "delay_on";
+
+static uint32_t rgbToBrightness(const LightState& state) {
+    uint32_t color = state.color & 0x00ffffff;
+    return ((77 * ((color >> 16) & 0xff))
+            + (150 * ((color >> 8) & 0xff))
+            + (29 * (color & 0xff))) >> 8;
+}
+
+Light::Light() {
+    mLights.emplace(Type::ATTENTION, std::bind(&Light::handleNotification, this, std::placeholders::_1, 0));
+    mLights.emplace(Type::BACKLIGHT, std::bind(&Light::handleBacklight, this, std::placeholders::_1));
+    mLights.emplace(Type::BATTERY, std::bind(&Light::handleNotification, this, std::placeholders::_1, 1));
+    mLights.emplace(Type::NOTIFICATIONS, std::bind(&Light::handleNotification, this, std::placeholders::_1, 2));
+}
+
+void Light::handleBacklight(const LightState& state) {
+    uint32_t maxBrightness = get("/sys/class/backlight/panel0-backlight/max_brightness", kDefaultMaxBrightness);
+    uint32_t sentBrightness = rgbToBrightness(state);
+    uint32_t brightness = sentBrightness * maxBrightness / kDefaultMaxBrightness;
+    LOG(DEBUG) << "Writing backlight brightness " << brightness
+               << " (orig " << sentBrightness << ")";
+    set("/sys/class/backlight/panel0-backlight/brightness", brightness);
+}
+
+void Light::handleNotification(const LightState& state, size_t index) {
+    mLightStates.at(index) = state;
+
+    LightState stateToUse = mLightStates.front();
+    for (const auto& lightState : mLightStates) {
+        if (lightState.color & 0xffffff) {
+            stateToUse = lightState;
+            break;
+        }
+    }
+
+    // Extract brightness from AARRGG
+    uint32_t alpha = (stateToUse.color >> 24) & 0xff;
+
+    std::map<std::string, int> colorValues;
+    colorValues["red"] = (stateToUse.color >> 16) & 0xff;
+    colorValues["green"] = (stateToUse.color >> 8) & 0xff;
+
+    // Scale RG colors if a brightness has been applied by the user
+    if (alpha != 0xff) {
+        for (auto& entry : colorValues) {
+            // For more exact scaling divide by half
+            entry.second = ((entry.second * alpha) / 0xff) / 2;
+        }
+    }
+
+    auto makeLedPath = [](const std::string& led, const char op[]) -> std::string {
+        return "/sys/class/leds/" + led + "/" + op;
+    };
+
+    // Disable all blinking before starting
+    for (const auto& entry : colorValues) {
+        set(makeLedPath(entry.first, kBreath), 0);
+    }
+
+    if (state.flashMode == Flash::TIMED) {
+        for (const auto& entry : colorValues) {
+            set(makeLedPath(entry.first, kDelayOff), state.flashOffMs);
+            set(makeLedPath(entry.first, kDelayOn), state.flashOnMs);
+        }
+
+        // Start blinking
+        for (const auto& entry : colorValues) {
+            set(makeLedPath(entry.first, kBreath), entry.second);
+        }
+    } else {
+        for (const auto& entry : colorValues) {
+            set(makeLedPath(entry.first, kBrightness), entry.second);
+        }
+    }
+}
+
+Return<Status> Light::setLight(Type type, const LightState& state) {
+    auto it = mLights.find(type);
+
+    if (it == mLights.end()) {
+        return Status::LIGHT_NOT_SUPPORTED;
+    }
+
+    // Lock global mutex until light state is updated.
+    std::lock_guard<std::mutex> lock(mLock);
+
+    it->second(state);
+
+    return Status::SUCCESS;
+}
+
+Return<void> Light::getSupportedTypes(getSupportedTypes_cb _hidl_cb) {
+    std::vector<Type> types;
+
+    for (auto const& light : mLights) {
+        types.push_back(light.first);
+    }
+
+    _hidl_cb(types);
+
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace light
+}  // namespace hardware
+}  // namespace android
diff --git a/lights/Light.h b/lights/Light.h
new file mode 100644
index 0000000..a19d6e6
--- /dev/null
+++ b/lights/Light.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 The LineageOS 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/lights.h>
+#include <hidl/Status.h>
+#include <unordered_map>
+#include <mutex>
+
+namespace android {
+namespace hardware {
+namespace light {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+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;
+
+class Light : public ILight {
+  public:
+    Light();
+
+    Return<Status> setLight(Type type, const LightState& state) override;
+    Return<void> getSupportedTypes(getSupportedTypes_cb _hidl_cb) override;
+
+  private:
+    void handleBacklight(const LightState& state);
+    void handleNotification(const LightState& state, size_t index);
+
+    std::mutex mLock;
+    std::unordered_map<Type, std::function<void(const LightState&)>> mLights;
+    std::array<LightState, 3> mLightStates;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace light
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H
diff --git a/lights/android.hardware.light@2.0-service.asus_msmnile.rc b/lights/android.hardware.light@2.0-service.asus_msmnile.rc
new file mode 100644
index 0000000..22e6708
--- /dev/null
+++ b/lights/android.hardware.light@2.0-service.asus_msmnile.rc
@@ -0,0 +1,7 @@
+service vendor.light-hal-2-0 /system/bin/hw/android.hardware.light@2.0-service.asus_msmnile
+    interface android.hardware.light@2.0::ILight default
+    class hal
+    user system
+    group system
+    # shutting off lights while powering-off
+    shutdown critical
diff --git a/lights/service.cpp b/lights/service.cpp
new file mode 100644
index 0000000..423263d
--- /dev/null
+++ b/lights/service.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 The LineageOS 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 "android.hardware.light@2.0-service.asus_msmnile"
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "Light.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+using android::hardware::light::V2_0::ILight;
+using android::hardware::light::V2_0::implementation::Light;
+
+using android::OK;
+using android::sp;
+using android::status_t;
+
+int main() {
+    status_t status;
+    sp<ILight> service = nullptr;
+
+    LOG(INFO) << "Light HAL service 2.0 is starting.";
+
+    service = new Light();
+    if (service == nullptr) {
+        LOG(ERROR) << "Can not create an instance of Light HAL Iface, exiting.";
+        goto shutdown;
+    }
+
+    configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+    status = service->registerAsService();
+    if (status != OK) {
+        LOG(ERROR) << "Could not register service for Light HAL Iface (" << status << ")";
+        goto shutdown;
+    }
+
+    LOG(INFO) << "Light HAL service is ready.";
+    joinRpcThreadpool();
+    // Should not pass this line
+
+shutdown:
+    // In normal operation, we don't expect the thread pool to exit
+    LOG(ERROR) << "Light HAL service is shutting down.";
+    return 1;
+}
diff --git a/sepolicy/private/file.te b/sepolicy/private/file.te
index 28fcbe5..df8c2d3 100644
--- a/sepolicy/private/file.te
+++ b/sepolicy/private/file.te
@@ -4,6 +4,10 @@
 type voucher_file, file_type;
 type xrom_file, file_type;
 
+# Lights
+type sysfs_rg_led, sysfs_type, fs_type;
+type sysfs_graphics, sysfs_type, fs_type;
+
 # Offscreen Gestures
 type sysfs_gesture, sysfs_type, fs_type;
 type sysfs_touchscreen, sysfs_type, fs_type;
diff --git a/sepolicy/private/file_contexts b/sepolicy/private/file_contexts
index 983ceba..b52c919 100644
--- a/sepolicy/private/file_contexts
+++ b/sepolicy/private/file_contexts
@@ -15,5 +15,8 @@
 /proc/driver/swipeup                          u:object_r:sysfs_gesture:s0
 /sys/devices/platform/soc/soc:asustek_googlekey/googlekey_enable          u:object_r:sysfs_gesture:s0
 
+# HALs
+/system/bin/hw/android\.hardware\.light@2\.0-service\.asus_msmnile      u:object_r:hal_light_msmnile_exec:s0
+
 # Modules
 /system/lib/modules/wlan\.ko                  u:object_r:system_file:s0
diff --git a/sepolicy/private/hal_light_msmnile.te b/sepolicy/private/hal_light_msmnile.te
new file mode 100644
index 0000000..140f1e2
--- /dev/null
+++ b/sepolicy/private/hal_light_msmnile.te
@@ -0,0 +1,20 @@
+type hal_light_msmnile, coredomain, domain;
+
+# Allow a base set of permissions required for a domain to offer a
+# HAL implementation of the specified type over HwBinder.
+typeattribute hal_light_msmnile halclientdomain;
+typeattribute hal_light_msmnile hal_light_client;
+
+# HwBinder IPC from client to server, and callbacks
+binder_call(hal_light_client, hal_light_server)
+binder_call(hal_light_server, hal_light_client)
+
+add_hwservice(hal_light_server, hal_light_hwservice)
+allow hal_light_client hal_light_hwservice:hwservice_manager find;
+
+type hal_light_msmnile_exec, exec_type, file_type;
+init_daemon_domain(hal_light_msmnile)
+
+allow hal_light_msmnile { sysfs_graphics sysfs_rg_led }:lnk_file read;
+allow hal_light_msmnile { sysfs_graphics sysfs_rg_led }:file rw_file_perms;
+allow hal_light_msmnile { sysfs_graphics sysfs_leds sysfs_rg_led }:dir r_dir_perms;