From 118f6920b5c593e25808813968cdc826ec748824 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Mon, 2 Jul 2018 15:46:30 +0200 Subject: [PATCH] sdm845-common: Build our own lights HAL Change-Id: I0e0d2db5c109778b86ab54101b70f0d3856195cb --- Android.bp | 3 + common.mk | 4 + lights/Android.bp | 32 +++ lights/Light.cpp | 190 ++++++++++++++++++ lights/Light.h | 61 ++++++ ...rdware.light@2.0-service.oneplus_sdm845.rc | 4 + lights/service.cpp | 50 +++++ sepolicy/private/file_contexts | 3 + sepolicy/private/hal_light_sdm845.te | 7 + 9 files changed, 354 insertions(+) create mode 100644 Android.bp create mode 100644 lights/Android.bp create mode 100644 lights/Light.cpp create mode 100644 lights/Light.h create mode 100644 lights/android.hardware.light@2.0-service.oneplus_sdm845.rc create mode 100644 lights/service.cpp create mode 100644 sepolicy/private/hal_light_sdm845.te diff --git a/Android.bp b/Android.bp new file mode 100644 index 0000000..2c56a96 --- /dev/null +++ b/Android.bp @@ -0,0 +1,3 @@ +subdirs = [ + "lights" +] diff --git a/common.mk b/common.mk index 91f38b5..306318d 100644 --- a/common.mk +++ b/common.mk @@ -45,6 +45,10 @@ PRODUCT_PACKAGES += \ PRODUCT_PACKAGES += \ libvulkan +# Lights +PRODUCT_PACKAGES += \ + android.hardware.light@2.0-service.oneplus_sdm845 + # Net PRODUCT_PACKAGES += \ netutils-wrapper-1.0 diff --git a/lights/Android.bp b/lights/Android.bp new file mode 100644 index 0000000..b1c545c --- /dev/null +++ b/lights/Android.bp @@ -0,0 +1,32 @@ +// +// 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.oneplus_sdm845", + init_rc: ["android.hardware.light@2.0-service.oneplus_sdm845.rc"], + srcs: ["service.cpp", "Light.cpp"], + shared_libs: [ + "libbase", + "libhardware", + "libhidlbase", + "libhidltransport", + "liblog", + "libhwbinder", + "libutils", + "android.hardware.light@2.0", + ], +} diff --git a/lights/Light.cpp b/lights/Light.cpp new file mode 100644 index 0000000..f9bc48b --- /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 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 +#include +#include + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +namespace android { +namespace hardware { +namespace light { +namespace V2_0 { +namespace implementation { + +/* + * Write value to path and close file. + */ +template +static void set(const std::string& path, const T& value) { + std::ofstream file(path); + file << value; +} + +template +static T get(const std::string& path, const T& def) { + std::ifstream file(path); + T result; + + file >> result; + return file.fail() ? def : result; +} + +static int rgbToBrightness(const LightState& state) { + int color = state.color & 0x00ffffff; + return ((77 * ((color >> 16) & 0x00ff)) + + (150 * ((color >> 8) & 0x00ff)) + + (29 * (color & 0x00ff))) >> 8; +} + +Light::Light() { + mLights.emplace(Type::ATTENTION, std::bind(&Light::handleRgb, this, std::placeholders::_1, 0)); + mLights.emplace(Type::BACKLIGHT, std::bind(&Light::handleBacklight, this, std::placeholders::_1)); + mLights.emplace(Type::BATTERY, std::bind(&Light::handleRgb, this, std::placeholders::_1, 1)); + mLights.emplace(Type::NOTIFICATIONS, std::bind(&Light::handleRgb, this, std::placeholders::_1, 2)); +} + +void Light::handleBacklight(const LightState& state) { + int maxBrightness = get("/sys/class/backlight/panel0-backlight/max_brightness", -1); + if (maxBrightness < 0) { + maxBrightness = 255; + } + int sentBrightness = rgbToBrightness(state); + int brightness = sentBrightness * maxBrightness / 255; + LOG(DEBUG) << "Writing backlight brightness " << brightness + << " (orig " << sentBrightness << ")"; + set("/sys/class/backlight/panel0-backlight/brightness", brightness); +} + +void Light::handleRgb(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; + } + } + + std::map colorValues; + colorValues["red"] = (stateToUse.color >> 16) & 0xff; + colorValues["green"] = (stateToUse.color >> 8) & 0xff; + colorValues["blue"] = stateToUse.color & 0xff; + + int onMs = stateToUse.flashMode == Flash::TIMED ? stateToUse.flashOnMs : 0; + int offMs = stateToUse.flashMode == Flash::TIMED ? stateToUse.flashOffMs : 0; + + static constexpr int kRampSize = 8; + static constexpr int kBrightnessRamp[] = { 0, 12, 25, 37, 50, 72, 85, 100 }; + static constexpr int kRampStepDuration = 50; + + auto makeLedPath = [](const std::string& led, const std::string& op) -> std::string { + return "/sys/class/leds/" + led + "/" + op; + }; + auto getScaledDutyPercent = [](int brightness) -> std::string { + std::string output; + for (size_t i = 0; i < ARRAY_SIZE(kBrightnessRamp); i++) { + if (i != 0) { + output += ","; + } + output += std::to_string(kBrightnessRamp[i] * brightness / 255); + } + return output; + }; + + // Disable all blinking before starting + for (const auto& entry : colorValues) { + set(makeLedPath(entry.first, "blink"), 0); + } + + if (onMs > 0 && offMs > 0) { + int pauseHi, stepDuration; + if (kRampStepDuration * kRampSize * 2 > onMs) { + stepDuration = onMs / 2 * kRampSize; + pauseHi = 0; + } else { + stepDuration = kRampStepDuration; + pauseHi = onMs - 2 * kRampSize * stepDuration; + } + + for (const auto& entry : colorValues) { + set(makeLedPath(entry.first, "start_idx"), 0); + set(makeLedPath(entry.first, "duty_pcts"), getScaledDutyPercent(entry.second)); + set(makeLedPath(entry.first, "pause_lo"), offMs); + // The led driver is configured to ramp up then ramp + // down the lut. This effectively doubles the ramp duration. + set(makeLedPath(entry.first, "pause_hi"), pauseHi); + set(makeLedPath(entry.first, "ramp_step_ms"), stepDuration); + } + + // Start blinking + for (const auto& entry : colorValues) { + set(makeLedPath(entry.first, "blink"), entry.second); + } + } else { + for (const auto& entry : colorValues) { + set(makeLedPath(entry.first, "brightness"), entry.second); + } + } + + LOG(DEBUG) << base::StringPrintf( + "handleRgb: mode=%d, color=%08X, onMs=%d, offMs=%d", + static_cast::type>(stateToUse.flashMode), stateToUse.color, + onMs, offMs); +} + +Return 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 lock(mLock); + + it->second(state); + + return Status::SUCCESS; +} + +Return Light::getSupportedTypes(getSupportedTypes_cb _hidl_cb) { + std::vector 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..27a701a --- /dev/null +++ b/lights/Light.h @@ -0,0 +1,61 @@ +/* + * 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 +#include +#include +#include +#include + +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 setLight(Type type, const LightState& state) override; + Return getSupportedTypes(getSupportedTypes_cb _hidl_cb) override; + + private: + void handleBacklight(const LightState& state); + void handleRgb(const LightState& state, size_t index); + + std::mutex mLock; + std::unordered_map> mLights; + std::array 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.oneplus_sdm845.rc b/lights/android.hardware.light@2.0-service.oneplus_sdm845.rc new file mode 100644 index 0000000..39e2c63 --- /dev/null +++ b/lights/android.hardware.light@2.0-service.oneplus_sdm845.rc @@ -0,0 +1,4 @@ +service light-hal-2-0 /system/bin/hw/android.hardware.light@2.0-service.oneplus_sdm845 + class hal + user system + group system diff --git a/lights/service.cpp b/lights/service.cpp new file mode 100644 index 0000000..25c1b04 --- /dev/null +++ b/lights/service.cpp @@ -0,0 +1,50 @@ +/* + * Copyright 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.oneplus_sdm845" + +#include +#include + +#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::status_t; + +int main() { + android::sp service = new Light(); + + configureRpcThreadpool(1, true); + + status_t status = service->registerAsService(); + if (status != OK) { + LOG(ERROR) << "Cannot register Light HAL service."; + return 1; + } + + LOG(INFO) << "Light HAL service ready."; + + joinRpcThreadpool(); + + LOG(ERROR) << "Light HAL service failed to join thread pool."; + return 1; +} diff --git a/sepolicy/private/file_contexts b/sepolicy/private/file_contexts index 367712b..c2d5347 100644 --- a/sepolicy/private/file_contexts +++ b/sepolicy/private/file_contexts @@ -5,3 +5,6 @@ /op1(/.*)? u:object_r:op1_file:s0 /op2(/.*)? u:object_r:op2_file:s0 /persist(/.*)? u:object_r:persist_file:s0 + +# Lights +/system/bin/hw/android\.hardware\.light@2\.0-service\.oneplus_sdm845 u:object_r:hal_light_sdm845_exec:s0 diff --git a/sepolicy/private/hal_light_sdm845.te b/sepolicy/private/hal_light_sdm845.te new file mode 100644 index 0000000..93381ac --- /dev/null +++ b/sepolicy/private/hal_light_sdm845.te @@ -0,0 +1,7 @@ +type hal_light_sdm845, coredomain, domain; +hal_server_domain(hal_light_sdm845, hal_light) + +type hal_light_sdm845_exec, exec_type, file_type; +init_daemon_domain(hal_light_sdm845) + +allow hal_light_sdm845 sysfs_leds:file rw_file_perms;