diff --git a/device.mk b/device.mk index 168daff0bac119208dd344d199e33233b07dd0bc..d1e13dfc3969e14bc6ff2150f9f0f6f9ad2cfdd0 100644 --- a/device.mk +++ b/device.mk @@ -228,9 +228,7 @@ PRODUCT_COPY_FILES += \ # Lights PRODUCT_PACKAGES += \ - android.hardware.light@2.0-impl \ - android.hardware.light@2.0-service \ - lights.msm8953 + android.hardware.light@2.0-service.onclite # LiveDisplay PRODUCT_PACKAGES += \ diff --git a/light/Android.bp b/light/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..ee181d69e10068f4d8e785447e5ff7a459a8d45c --- /dev/null +++ b/light/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.onclite", + proprietary: true, + init_rc: ["android.hardware.light@2.0-service.onclite.rc"], + srcs: ["service.cpp", "Light.cpp"], + shared_libs: [ + "libhardware", + "libhidlbase", + "libhidltransport", + "liblog", + "libhwbinder", + "libutils", + "android.hardware.light@2.0", + ], +} diff --git a/light/Light.cpp b/light/Light.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b8fbb693126633d3d2fe03dd9ac0dae86e479fdc --- /dev/null +++ b/light/Light.cpp @@ -0,0 +1,249 @@ +/* + * 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 "LightService" + +#include <log/log.h> + +#include "Light.h" + +#include <fstream> + +#define LEDS "/sys/class/leds/" + +#define LCD_LED LEDS "lcd-backlight/" +#define WHITE_LED LEDS "red/" + +#define BLINK "blink" +#define BRIGHTNESS "brightness" +#define MAX_BRIGHTNESS "max_brightness" +#define DUTY_PCTS "duty_pcts" +#define PAUSE_HI "pause_hi" +#define PAUSE_LO "pause_lo" +#define RAMP_STEP_MS "ramp_step_ms" +#define START_IDX "start_idx" + +/* + * 15 duty percent steps. + */ +#define RAMP_STEPS 15 +/* + * Each step will stay on for 150ms by default. + */ +#define RAMP_STEP_DURATION 150 +/* + * Each value represents a duty percent (0 - 100) for the led pwm. + */ +static int32_t BRIGHTNESS_RAMP[RAMP_STEPS] = {0, 12, 25, 37, 50, 72, 85, 100, 85, 72, 50, 37, 25, 12, 0}; + +namespace { +/* + * Write value to path and close file. + */ +static void set(std::string path, std::string value) { + std::ofstream file(path); + + if (!file.is_open()) { + ALOGW("failed to write %s to %s", value.c_str(), path.c_str()); + return; + } + + file << value; +} + +static void set(std::string path, int value) { + set(path, std::to_string(value)); +} + +static int get(std::string path) { + std::ifstream file(path); + int value; + + if (!file.is_open()) { + ALOGW("failed to read from %s", path.c_str()); + return 0; + } + + file >> value; + return value; +} + +static int getMaxBrightness(std::string path) { + int value = get(path); + ALOGW("Got max brightness %d", value); + return value; +} + +static uint32_t getBrightness(const LightState& state) { + uint32_t alpha, red, green, blue; + + /* + * Extract brightness from AARRGGBB. + */ + alpha = (state.color >> 24) & 0xFF; + red = (state.color >> 16) & 0xFF; + green = (state.color >> 8) & 0xFF; + blue = state.color & 0xFF; + + /* + * Scale RGB brightness if Alpha brightness is not 0xFF. + */ + if (alpha != 0xFF) { + red = red * alpha / 0xFF; + green = green * alpha / 0xFF; + blue = blue * alpha / 0xFF; + } + + return (77 * red + 150 * green + 29 * blue) >> 8; +} + +static inline uint32_t scaleBrightness(uint32_t brightness, uint32_t maxBrightness) { + return brightness * maxBrightness / 0xFF; +} + +static inline uint32_t getScaledBrightness(const LightState& state, uint32_t maxBrightness) { + return scaleBrightness(getBrightness(state), maxBrightness); +} + +static void handleBacklight(const LightState& state) { + uint32_t brightness = getScaledBrightness(state, getMaxBrightness(LCD_LED MAX_BRIGHTNESS)); + set(LCD_LED BRIGHTNESS, brightness); +} + +/* + * Scale each value of the brightness ramp according to the + * brightness of the color. + */ +static std::string getScaledRamp(uint32_t brightness) { + std::string ramp, pad; + + for (auto const& step : BRIGHTNESS_RAMP) { + ramp += pad + std::to_string(step * brightness / 0xFF); + pad = ","; + } + + return ramp; +} + +static void handleNotification(const LightState& state) { + uint32_t whiteBrightness = getScaledBrightness(state, getMaxBrightness(WHITE_LED MAX_BRIGHTNESS)); + + /* Disable blinking */ + set(WHITE_LED BLINK, 0); + + if (state.flashMode == Flash::TIMED) { + /* + * If the flashOnMs duration is not long enough to fit ramping up + * and down at the default step duration, step duration is modified + * to fit. + */ + int32_t stepDuration = RAMP_STEP_DURATION; + int32_t pauseHi = state.flashOnMs - (stepDuration * RAMP_STEPS * 2); + int32_t pauseLo = state.flashOffMs; + + if (pauseHi < 0) { + //stepDuration = state.flashOnMs / (RAMP_STEPS * 2); + pauseHi = 0; + } + + /* White */ + set(WHITE_LED START_IDX, 0 * RAMP_STEPS); + set(WHITE_LED DUTY_PCTS, getScaledRamp(whiteBrightness)); + set(WHITE_LED PAUSE_LO, pauseLo); + set(WHITE_LED PAUSE_HI, pauseHi); + set(WHITE_LED RAMP_STEP_MS, stepDuration); + + /* Enable blinking */ + set(WHITE_LED BLINK, 1); + } else { + set(WHITE_LED BRIGHTNESS, whiteBrightness); + } +} + +static inline bool isLit(const LightState& state) { + return state.color & 0x00ffffff; +} + +/* Keep sorted in the order of importance. */ +static std::vector<LightBackend> backends = { + { Type::ATTENTION, handleNotification }, + { Type::NOTIFICATIONS, handleNotification }, + { Type::BATTERY, handleNotification }, + { Type::BACKLIGHT, handleBacklight }, +}; + +} // anonymous namespace + +namespace android { +namespace hardware { +namespace light { +namespace V2_0 { +namespace implementation { + +Return<Status> Light::setLight(Type type, const LightState& state) { + LightStateHandler handler; + bool handled = false; + + /* Lock global mutex until light state is updated. */ + std::lock_guard<std::mutex> lock(globalLock); + + /* Update the cached state value for the current type. */ + for (LightBackend& backend : backends) { + if (backend.type == type) { + backend.state = state; + handler = backend.handler; + } + } + + /* If no handler has been found, then the type is not supported. */ + if (!handler) { + return Status::LIGHT_NOT_SUPPORTED; + } + + /* Light up the type with the highest priority that matches the current handler. */ + for (LightBackend& backend : backends) { + if (handler == backend.handler && isLit(backend.state)) { + handler(backend.state); + handled = true; + break; + } + } + + /* If no type has been lit up, then turn off the hardware. */ + if (!handled) { + handler(state); + } + + return Status::SUCCESS; +} + +Return<void> Light::getSupportedTypes(getSupportedTypes_cb _hidl_cb) { + std::vector<Type> types; + + for (const LightBackend& backend : backends) { + types.push_back(backend.type); + } + + _hidl_cb(types); + + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace light +} // namespace hardware +} // namespace android \ No newline at end of file diff --git a/light/Light.h b/light/Light.h new file mode 100644 index 0000000000000000000000000000000000000000..6196e541fea118128ba5fefe0fa8b5523c960ef9 --- /dev/null +++ b/light/Light.h @@ -0,0 +1,68 @@ +/* + * 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 <map> +#include <mutex> +#include <vector> + +using ::android::hardware::Return; +using ::android::hardware::Void; +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; + +typedef void (*LightStateHandler)(const LightState&); + +struct LightBackend { + Type type; + LightState state; + LightStateHandler handler; + + LightBackend(Type type, LightStateHandler handler) : type(type), handler(handler) { + this->state.color = 0xff000000; + } +}; + +namespace android { +namespace hardware { +namespace light { +namespace V2_0 { +namespace implementation { + +class Light : public ILight { + public: + Return<Status> setLight(Type type, const LightState& state) override; + Return<void> getSupportedTypes(getSupportedTypes_cb _hidl_cb) override; + + private: + std::mutex globalLock; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace light +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H \ No newline at end of file diff --git a/light/android.hardware.light@2.0-service.onclite.rc b/light/android.hardware.light@2.0-service.onclite.rc new file mode 100644 index 0000000000000000000000000000000000000000..deba2f3fadd25dba831e24b03cce506feb8236d0 --- /dev/null +++ b/light/android.hardware.light@2.0-service.onclite.rc @@ -0,0 +1,22 @@ +on boot + # leds light + chown system system /sys/class/leds/red/brightness + chown system system /sys/class/leds/red/blink + chown system system /sys/class/leds/red/duty_pcts + chown system system /sys/class/leds/red/pause_hi + chown system system /sys/class/leds/red/pause_lo + chown system system /sys/class/leds/red/ramp_step_ms + chown system system /sys/class/leds/red/start_idx + + chmod 660 /sys/class/leds/red/blink + chmod 660 /sys/class/leds/red/duty_pcts + chmod 660 /sys/class/leds/red/pause_hi + chmod 660 /sys/class/leds/red/pause_lo + chmod 660 /sys/class/leds/red/ramp_step_ms + chmod 660 /sys/class/leds/red/start_idx + +service light-hal-2-0 /vendor/bin/hw/android.hardware.light@2.0-service.onclite + class hal + user system + group system + shutdown critical diff --git a/light/service.cpp b/light/service.cpp new file mode 100644 index 0000000000000000000000000000000000000000..63b522ecbc40e7ddd07ea2a4fcbd87c80a65a252 --- /dev/null +++ b/light/service.cpp @@ -0,0 +1,50 @@ +/* + * 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.onclite" + +#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() { + sp<ILight> service = new Light(); + + configureRpcThreadpool(1, true); + + status_t status = service->registerAsService(); + if (status != OK) { + ALOGE("Cannot register Light HAL service."); + return 1; + } + + ALOGI("Light HAL service ready."); + + joinRpcThreadpool(); + + ALOGI("Light HAL service failed to join thread pool."); + return 1; +} diff --git a/rootdir/init.qcom.rc b/rootdir/init.qcom.rc index 82002b00419a847e02bdba87aca4fa22c26f75d3..21a605d37e34c177c84db2bba788f3f2bbe7edb4 100644 --- a/rootdir/init.qcom.rc +++ b/rootdir/init.qcom.rc @@ -182,14 +182,6 @@ on boot # bond0 used by FST Manager chown wifi wifi /sys/class/net/bond0/bonding/queue_id - # Notification LED - chown system system /sys/class/leds/red/blink - chown system system /sys/class/leds/green/blink - chown system system /sys/class/leds/blue/blink - chown system system /sys/class/leds/red/brightness - chown system system /sys/class/leds/green/brightness - chown system system /sys/class/leds/blue/brightness - # Allow access to emmc rawdump block partition and dload sysfs node chown root system /dev/block/bootdevice/by-name/rawdump chmod 0660 /dev/block/bootdevice/by-name/rawdump diff --git a/sepolicy/file_contexts b/sepolicy/file_contexts index 1a290203cdb14f32b34a3867e39d2b897e59379a..fe2d994fe0e42d090ca79c5db680e27294894854 100644 --- a/sepolicy/file_contexts +++ b/sepolicy/file_contexts @@ -1,6 +1,7 @@ # HALs /(vendor|system/vendor)/bin/hw/android\.hardware\.drm@1\.0-service\.widevine u:object_r:hal_drm_widevine_exec:s0 /(vendor|system/vendor)/bin/hw/android\.hardware\.drm@1\.1-service\.clearkey u:object_r:hal_drm_clearkey_exec:s0 +/(vendor|system/vendor)/bin/hw/android\.hardware\.light@2\.0-service\.onclite u:object_r:hal_light_default_exec:s0 # Input devices /(vendor|system/vendor)/usr/idc(/.*)? u:object_r:idc_file:s0