diff --git a/common.mk b/common.mk index 34eeb32..1533a6b 100644 --- a/common.mk +++ b/common.mk @@ -275,7 +275,7 @@ PRODUCT_PACKAGES += \ # Lights PRODUCT_PACKAGES += \ - android.hardware.light@2.0-service.sony_sdm845 \ + android.hardware.light-service.sony_sdm845 \ android.hardware.light@2.0.vendor # Media diff --git a/framework_compatibility_matrix.xml b/framework_compatibility_matrix.xml index 20627c2..22d8f03 100644 --- a/framework_compatibility_matrix.xml +++ b/framework_compatibility_matrix.xml @@ -1,12 +1,4 @@ - - android.hardware.light - 2.0 - - ILight - default - - com.fingerprints.extension 1.0 diff --git a/lights/Android.bp b/lights/Android.bp index d8287f4..98a8caa 100644 --- a/lights/Android.bp +++ b/lights/Android.bp @@ -1,31 +1,21 @@ // -// Copyright (C) 2018 The LineageOS Project +// SPDX-FileCopyrightText: 2018-2024 The LineageOS Project +// SPDX-License-Identifier: Apache-2.0 // -// 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: "android.hardware.light-service.sony_sdm845", relative_install_path: "hw", - defaults: ["hidl_defaults"], - name: "android.hardware.light@2.0-service.sony_sdm845", - init_rc: ["android.hardware.light@2.0-service.sony_sdm845.rc"], - srcs: ["service.cpp", "Light.cpp"], + init_rc: ["android.hardware.light-service.sony_sdm845.rc"], + vintf_fragments: ["android.hardware.light-service.sony_sdm845.xml"], + vendor: true, + srcs: [ + "Lights.cpp", + "service.cpp", + ], shared_libs: [ "libbase", - "libhardware", - "libhidlbase", - "liblog", - "libutils", - "android.hardware.light@2.0", + "libbinder_ndk", + "android.hardware.light-V2-ndk", ], - proprietary: true, } diff --git a/lights/Light.cpp b/lights/Light.cpp deleted file mode 100644 index d914e55..0000000 --- a/lights/Light.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - * 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 - -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, 2)); - mLights.emplace(Type::NOTIFICATIONS, std::bind(&Light::handleRgb, this, std::placeholders::_1, 1)); -} - -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; - // lower green and blue brightness to adjust for the (lower) brightness of red - colorValues["green"] = ((stateToUse.color >> 8) & 0xff) / 2; - colorValues["blue"] = (stateToUse.color & 0xff) / 2; - - int onMs = stateToUse.flashMode == Flash::TIMED ? stateToUse.flashOnMs : 0; - int offMs = stateToUse.flashMode == Flash::TIMED ? stateToUse.flashOffMs : 0; - - // LUT has 63 entries, we could theoretically use them as 3 (colors) * 21 (steps). - // However, the last LUT entries don't seem to behave correctly for unknown - // reasons, so we use 17 steps for a total of 51 LUT entries only. - static constexpr int kRampSteps = 16; - static constexpr int kRampMaxStepDurationMs = 15; - - 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 (int i = 0; i <= kRampSteps; i++) { - if (i != 0) { - output += ","; - } - output += std::to_string(i * 512 * brightness / (255 * kRampSteps)); - } - return output; - }; - - // Disable all blinking before starting - for (const auto& entry : colorValues) { - set(makeLedPath(entry.first, "blink"), 0); - } - - if (onMs > 0 && offMs > 0) { - int pauseLo, pauseHi, stepDuration, index = 0; - if (kRampMaxStepDurationMs * kRampSteps > onMs) { - stepDuration = onMs / kRampSteps; - pauseHi = 0; - pauseLo = offMs; - } else { - stepDuration = kRampMaxStepDurationMs; - pauseHi = onMs - kRampSteps * stepDuration; - pauseLo = offMs - kRampSteps * stepDuration; - } - - for (const auto& entry : colorValues) { - set(makeLedPath(entry.first, "lut_flags"), 95); - set(makeLedPath(entry.first, "start_idx"), index); - set(makeLedPath(entry.first, "duty_pcts"), getScaledDutyPercent(entry.second)); - set(makeLedPath(entry.first, "pause_lo"), pauseLo); - set(makeLedPath(entry.first, "pause_hi"), pauseHi); - set(makeLedPath(entry.first, "ramp_step_ms"), stepDuration); - index += kRampSteps + 1; - } - - // 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 deleted file mode 100644 index 27a701a..0000000 --- a/lights/Light.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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/Lights.cpp b/lights/Lights.cpp new file mode 100644 index 0000000..bc0909e --- /dev/null +++ b/lights/Lights.cpp @@ -0,0 +1,232 @@ +/* + * SPDX-FileCopyrightText: 2018-2024 The LineageOS Project + * SPDX-License-Identifier: Apache-2.0 + */ + +#define LOG_TAG "LightsService" + +#include "Lights.h" + +#include + +#include + +#define SYS_CLASS "/sys/class/" + +#define PANEL_BACKLIGHT SYS_CLASS "backlight/panel0-backlight/" +#define LEDS SYS_CLASS "leds/" + +#define RED_LED LEDS "red/" +#define GREEN_LED LEDS "green/" +#define BLUE_LED LEDS "blue/" + +#define BLINK "blink" +#define BRIGHTNESS "brightness" +#define DUTY_PCTS "duty_pcts" +#define LUT_FLAGS "lut_flags" +#define PAUSE_HI "pause_hi" +#define PAUSE_LO "pause_lo" +#define RAMP_STEP_MS "ramp_step_ms" +#define START_IDX "start_idx" + + +/* + * 8 duty percent steps. + */ +#define RAMP_STEPS 8 +/* + * Each step will stay on for 50ms by default. + */ +#define RAMP_STEP_DURATION 50 +/* + * 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}; + +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()) { + LOG(WARNING) << "failed to write " << value.c_str() << " to " << path.c_str(); + return; + } + + file << value; +} + +static void set(std::string path, int value) { + set(path, std::to_string(value)); +} + +static void handleBacklight(const HwLightState& state) { + uint32_t brightness = state.color & 0xFF; + set(PANEL_BACKLIGHT 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 HwLightState& state) { + uint32_t redBrightness, greenBrightness, blueBrightness, brightness; + + /* + * Extract brightness from AARRGGBB. + */ + redBrightness = (state.color >> 16) & 0xFF; + greenBrightness = (state.color >> 8) & 0xFF; + blueBrightness = state.color & 0xFF; + + brightness = (state.color >> 24) & 0xFF; + + /* + * Scale RGB brightness if the Alpha brightness is not 0xFF. + */ + if (brightness != 0xFF) { + redBrightness = (redBrightness * brightness) / 0xFF; + greenBrightness = (greenBrightness * brightness) / 0xFF; + blueBrightness = (blueBrightness * brightness) / 0xFF; + } + + /* Disable blinking. */ + set(RED_LED BLINK, 0); + set(GREEN_LED BLINK, 0); + set(BLUE_LED BLINK, 0); + + if (state.flashMode == FlashMode::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; + } + + /* Red */ + set(RED_LED LUT_FLAGS, 95); + set(RED_LED START_IDX, 0 * RAMP_STEPS); + set(RED_LED DUTY_PCTS, getScaledRamp(redBrightness)); + set(RED_LED PAUSE_LO, pauseLo); + set(RED_LED PAUSE_HI, pauseHi); + set(RED_LED RAMP_STEP_MS, stepDuration); + + /* Green */ + set(GREEN_LED LUT_FLAGS, 95); + set(GREEN_LED START_IDX, 1 * RAMP_STEPS); + set(GREEN_LED DUTY_PCTS, getScaledRamp(greenBrightness)); + set(GREEN_LED PAUSE_LO, pauseLo); + set(GREEN_LED PAUSE_HI, pauseHi); + set(GREEN_LED RAMP_STEP_MS, stepDuration); + + /* Blue */ + set(BLUE_LED LUT_FLAGS, 95); + set(BLUE_LED START_IDX, 2 * RAMP_STEPS); + set(BLUE_LED DUTY_PCTS, getScaledRamp(blueBrightness)); + set(BLUE_LED PAUSE_LO, pauseLo); + set(BLUE_LED PAUSE_HI, pauseHi); + set(BLUE_LED RAMP_STEP_MS, stepDuration); + + /* Enable blinking. */ + set(RED_LED BLINK, 1); + set(GREEN_LED BLINK, 1); + set(BLUE_LED BLINK, 1); + } else { + set(RED_LED BRIGHTNESS, redBrightness); + set(GREEN_LED BRIGHTNESS, greenBrightness); + set(BLUE_LED BRIGHTNESS, blueBrightness); + } +} + +static inline bool isLit(const HwLightState& state) { + return state.color & 0x00ffffff; +} + +/* Keep sorted in the order of importance. */ +static std::vector backends = { + { LightType::ATTENTION, handleNotification }, + { LightType::NOTIFICATIONS, handleNotification }, + { LightType::BATTERY, handleNotification }, + { LightType::BACKLIGHT, handleBacklight }, +}; + +} // anonymous namespace + +namespace aidl { +namespace android { +namespace hardware { +namespace light { + +ndk::ScopedAStatus Lights::setLightState(int id, const HwLightState& state) { + LightStateHandler handler = nullptr; + LightType type = static_cast(id); + + /* Lock global mutex until light state is updated. */ + std::lock_guard 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 ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + + /* 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); + return ndk::ScopedAStatus::ok(); + } + } + + /* If no type has been lit up, then turn off the hardware. */ + handler(state); + + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Lights::getLights(std::vector* lights) { + int i = 0; + + for (const LightBackend& backend : backends) { + HwLight hwLight; + hwLight.id = (int) backend.type; + hwLight.type = backend.type; + hwLight.ordinal = i; + lights->push_back(hwLight); + i++; + } + + return ndk::ScopedAStatus::ok(); +} + +} // namespace light +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/lights/Lights.h b/lights/Lights.h new file mode 100644 index 0000000..787da48 --- /dev/null +++ b/lights/Lights.h @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: 2018-2024 The LineageOS Project + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +#include +#include + +using ::aidl::android::hardware::light::BnLights; +using ::aidl::android::hardware::light::FlashMode; +using ::aidl::android::hardware::light::HwLight; +using ::aidl::android::hardware::light::HwLightState; +using ::aidl::android::hardware::light::LightType; + +typedef void (*LightStateHandler)(const HwLightState&); + +struct LightBackend { + LightType type; + HwLightState state; + LightStateHandler handler; + + LightBackend(LightType type, LightStateHandler handler) : type(type), handler(handler) { + this->state.color = 0xff000000; + } +}; + +namespace aidl { +namespace android { +namespace hardware { +namespace light { + +class Lights : public BnLights { + public: + ndk::ScopedAStatus setLightState(int id, const HwLightState& state) override; + ndk::ScopedAStatus getLights(std::vector* types) override; + + private: + std::mutex globalLock; +}; + +} // namespace light +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/lights/android.hardware.light@2.0-service.sony_sdm845.rc b/lights/android.hardware.light-service.sony_sdm845.rc similarity index 90% rename from lights/android.hardware.light@2.0-service.sony_sdm845.rc rename to lights/android.hardware.light-service.sony_sdm845.rc index 5c418be..090af4f 100644 --- a/lights/android.hardware.light@2.0-service.sony_sdm845.rc +++ b/lights/android.hardware.light-service.sony_sdm845.rc @@ -27,8 +27,7 @@ on boot chown system system /sys/class/leds/blue/ramp_step_ms chown system system /sys/class/leds/blue/start_idx -service vendor.light-hal-2-0 /vendor/bin/hw/android.hardware.light@2.0-service.sony_sdm845 - interface android.hardware.light@2.0::ILight default +service vendor.light-sony_sdm845 /vendor/bin/hw/android.hardware.light-service.sony_sdm845 class hal user system group system diff --git a/lights/android.hardware.light-service.sony_sdm845.xml b/lights/android.hardware.light-service.sony_sdm845.xml new file mode 100644 index 0000000..abdd74e --- /dev/null +++ b/lights/android.hardware.light-service.sony_sdm845.xml @@ -0,0 +1,7 @@ + + + android.hardware.light + 2 + ILights/default + + diff --git a/lights/service.cpp b/lights/service.cpp index f5efede..bf43ae4 100644 --- a/lights/service.cpp +++ b/lights/service.cpp @@ -1,50 +1,24 @@ /* - * 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. + * SPDX-FileCopyrightText: 2018-2024 The LineageOS Project + * SPDX-License-Identifier: Apache-2.0 */ -#define LOG_TAG "android.hardware.light@2.0-service.sony_sdm845" +#include "Lights.h" #include -#include +#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; +using ::aidl::android::hardware::light::Lights; int main() { - android::sp service = new Light(); + ABinderProcess_setThreadPoolMaxThreadCount(0); + std::shared_ptr lights = ndk::SharedRefBase::make(); - configureRpcThreadpool(1, true); + const std::string instance = std::string() + Lights::descriptor + "/default"; + binder_status_t status = AServiceManager_addService(lights->asBinder().get(), instance.c_str()); + CHECK_EQ(status, STATUS_OK); - 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; + ABinderProcess_joinThreadPool(); + return EXIT_FAILURE; // should not reach } diff --git a/manifest.xml b/manifest.xml index 475d423..d4cc772 100644 --- a/manifest.xml +++ b/manifest.xml @@ -89,11 +89,6 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. passthrough @2.1::IMapper/default - - android.hardware.light - hwbinder - @2.0::ILight/default - android.hardware.media.omx hwbinder diff --git a/sepolicy/vendor/file_contexts b/sepolicy/vendor/file_contexts index 1849b2d..dce6265 100644 --- a/sepolicy/vendor/file_contexts +++ b/sepolicy/vendor/file_contexts @@ -73,7 +73,7 @@ /(vendor|system/vendor)/bin/wvkbd u:object_r:wvkbd_exec:s0 # Vendor HALs -/(vendor|system/vendor)/bin/hw/android\.hardware\.light@2\.0-service\.sony_sdm845 u:object_r:hal_light_default_exec:s0 +/(vendor|system/vendor)/bin/hw/android\.hardware\.light-service\.sony_sdm845 u:object_r:hal_light_default_exec:s0 /(vendor|system/vendor)/bin/hw/fpc_fingerprint@2\.1_HIDL-service u:object_r:hal_fingerprint_default_exec:s0 /(vendor|system/vendor)/bin/hw/vendor\.semc\.hardware\.secd@1\.0-service u:object_r:hal_secd_default_exec:s0 /(vendor|system/vendor)/bin/hw/vendor\.semc\.system\.idd@1\.0-service u:object_r:hal_idd_default_exec:s0