berlna: Add lights hal

* Based on motorola sdm632

Change-Id: If4fe7a661e532de13b86b80a6dd18c0281172e7d
This commit is contained in:
Erfan Abdi 2021-04-16 03:11:08 +04:30 committed by Andrew Hexen
parent bf14f6c729
commit 217c85f5d6
No known key found for this signature in database
GPG key ID: 8A690B4B0CD461A2
17 changed files with 659 additions and 1 deletions

View file

@ -61,5 +61,8 @@ TARGET_RECOVERY_UI_MARGIN_HEIGHT := 90
# Security # Security
VENDOR_SECURITY_PATCH := 2023-01-01 VENDOR_SECURITY_PATCH := 2023-01-01
# SELinux
BOARD_SEPOLICY_DIRS += $(DEVICE_PATH)/sepolicy/vendor
# inherit from the proprietary version # inherit from the proprietary version
include vendor/motorola/berlna/BoardConfigVendor.mk include vendor/motorola/berlna/BoardConfigVendor.mk

View file

@ -31,7 +31,10 @@ PRODUCT_SHIPPING_API_LEVEL := 30
# Inherit from motorola sm7325-common # Inherit from motorola sm7325-common
$(call inherit-product, device/motorola/sm7325-common/sm7325.mk) $(call inherit-product, device/motorola/sm7325-common/sm7325.mk)
# Overlay # Overlays
DEVICE_PACKAGE_OVERLAYS += \
$(LOCAL_PATH)/overlay-lineage
PRODUCT_PACKAGES += \ PRODUCT_PACKAGES += \
FrameworksResBerlna \ FrameworksResBerlna \
LineageSystemUIBerlna \ LineageSystemUIBerlna \
@ -74,6 +77,10 @@ PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/media/media_profiles_yupik_v0.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_profiles_yupik_v0.xml \ $(LOCAL_PATH)/media/media_profiles_yupik_v0.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_profiles_yupik_v0.xml \
$(LOCAL_PATH)/media/media_profiles_yupik_v1.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_profiles_yupik_v1.xml $(LOCAL_PATH)/media/media_profiles_yupik_v1.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_profiles_yupik_v1.xml
# Lights
PRODUCT_PACKAGES += \
android.hardware.lights-service.berlna
# NFC # NFC
PRODUCT_PACKAGES += \ PRODUCT_PACKAGES += \
android.hardware.nfc@1.2.vendor \ android.hardware.nfc@1.2.vendor \

53
lights/Android.bp Normal file
View file

@ -0,0 +1,53 @@
//
// Copyright (C) 2019-2020 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 {
name: "android.hardware.light@2.0-service.berlna",
defaults: ["hidl_defaults"],
init_rc: ["hidl/android.hardware.light@2.0-service.berlna.rc"],
vintf_fragments: ["hidl/android.hardware.light@2.0-service.berlna.xml"],
srcs: [
"hidl/service.cpp",
"hidl/Light.cpp",
],
shared_libs: [
"libbase",
"libhidlbase",
"liblog",
"libutils",
"android.hardware.light@2.0",
],
relative_install_path: "hw",
vendor: true,
}
cc_binary {
name: "android.hardware.lights-service.berlna",
relative_install_path: "hw",
init_rc: ["aidl/android.hardware.lights.berlna.rc"],
vintf_fragments: ["aidl/android.hardware.lights.berlna.xml"],
vendor: true,
shared_libs: [
"libbase",
"liblog",
"libhardware",
"libbinder_ndk",
"android.hardware.light-ndk_platform",
],
srcs: [
"aidl/Lights.cpp",
"aidl/main.cpp",
],
}

160
lights/aidl/Lights.cpp Normal file
View file

@ -0,0 +1,160 @@
/*
* Copyright (C) 2019 The Android Open Source Project
* Copyright (C) 2020-2021 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.lights-service.berlna"
#include "Lights.h"
#include <android-base/file.h>
#include <android-base/logging.h>
namespace {
/* clang-format off */
#define PPCAT_NX(A, B) A/B
#define PPCAT(A, B) PPCAT_NX(A, B)
#define STRINGIFY_INNER(x) #x
#define STRINGIFY(x) STRINGIFY_INNER(x)
#define LEDS(x) PPCAT(/sys/class/leds, x)
#define WHITE_ATTR(x) STRINGIFY(PPCAT(LEDS(charging), x))
/* clang-format on */
using ::android::base::ReadFileToString;
using ::android::base::WriteStringToFile;
// Default max brightness
constexpr auto kDefaultMaxLedBrightness = 255;
// Write value to path and close file.
bool WriteToFile(const std::string& path, uint32_t content) {
return WriteStringToFile(std::to_string(content), path);
}
uint32_t RgbaToBrightness(uint32_t color) {
// Extract brightness from AARRGGBB.
uint32_t alpha = (color >> 24) & 0xFF;
// Retrieve each of the RGB colors
uint32_t red = (color >> 16) & 0xFF;
uint32_t green = (color >> 8) & 0xFF;
uint32_t blue = color & 0xFF;
// Scale RGB colors if a brightness has been applied by the user
if (alpha != 0xFF && alpha != 0) {
red = red * alpha / 0xFF;
green = green * alpha / 0xFF;
blue = blue * alpha / 0xFF;
}
return (77 * red + 150 * green + 29 * blue) >> 8;
}
inline uint32_t RgbaToBrightness(uint32_t color, uint32_t max_brightness) {
return RgbaToBrightness(color) * max_brightness / 0xFF;
}
inline bool IsLit(uint32_t color) {
return color & 0x00ffffff;
}
} // anonymous namespace
namespace aidl {
namespace android {
namespace hardware {
namespace light {
Lights::Lights() {
std::map<int, std::function<void(int id, const HwLightState&)>> lights_{
{(int)LightType::NOTIFICATIONS,
[this](auto&&... args) { setLightNotification(args...); }},
{(int)LightType::BATTERY, [this](auto&&... args) { setLightNotification(args...); }},
{(int)LightType::BACKLIGHT, {}}};
std::vector<HwLight> availableLights;
for (auto const& pair : lights_) {
int id = pair.first;
HwLight hwLight{};
hwLight.id = id;
availableLights.emplace_back(hwLight);
}
mAvailableLights = availableLights;
mLights = lights_;
std::string buf;
if (ReadFileToString(WHITE_ATTR(max_brightness), &buf)) {
max_led_brightness_ = std::stoi(buf);
} else {
max_led_brightness_ = kDefaultMaxLedBrightness;
LOG(ERROR) << "Failed to read max LED brightness, fallback to " << kDefaultMaxLedBrightness;
}
}
ndk::ScopedAStatus Lights::setLightState(int id, const HwLightState& state) {
auto it = mLights.find(id);
if (it == mLights.end()) {
LOG(ERROR) << "Light not supported";
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
it->second(id, state);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Lights::getLights(std::vector<HwLight>* lights) {
for (auto i = mAvailableLights.begin(); i != mAvailableLights.end(); i++) {
lights->push_back(*i);
}
return ndk::ScopedAStatus::ok();
}
void Lights::setLightNotification(int id, const HwLightState& state) {
bool found = false;
for (auto&& [cur_id, cur_state] : notif_states_) {
if (cur_id == id) {
cur_state = state;
}
// Fallback to battery light
if (!found && (cur_id == (int)LightType::BATTERY || IsLit(cur_state.color))) {
found = true;
LOG(DEBUG) << __func__ << ": id=" << id;
applyNotificationState(cur_state);
}
}
}
void Lights::applyNotificationState(const HwLightState& state) {
int brightness = RgbaToBrightness(state.color, max_led_brightness_);
// Turn off the leds (initially)
WriteToFile(WHITE_ATTR(breath), 0);
if (state.flashMode == FlashMode::TIMED && state.flashOnMs > 0 && state.flashOffMs > 0) {
WriteToFile(WHITE_ATTR(delay_on), static_cast<uint32_t>(state.flashOnMs));
WriteToFile(WHITE_ATTR(delay_off), static_cast<uint32_t>(state.flashOffMs));
WriteToFile(WHITE_ATTR(breath), 1);
} else {
WriteToFile(WHITE_ATTR(brightness), brightness);
}
}
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

56
lights/aidl/Lights.h Normal file
View file

@ -0,0 +1,56 @@
/*
* Copyright (C) 2020 The Android Open Source Project
* Copyright (C) 2020-2021 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.
*/
#pragma once
#include <aidl/android/hardware/light/BnLights.h>
#include <hardware/hardware.h>
#include <hardware/lights.h>
#include <map>
#include <sstream>
namespace aidl {
namespace android {
namespace hardware {
namespace light {
class Lights : public BnLights {
public:
Lights();
ndk::ScopedAStatus setLightState(int id, const HwLightState& state) override;
ndk::ScopedAStatus getLights(std::vector<HwLight>* types) override;
private:
void setLightNotification(int id, const HwLightState& state);
void applyNotificationState(const HwLightState& state);
uint32_t max_led_brightness_;
std::map<int, std::function<void(int id, const HwLightState&)>> mLights;
std::vector<HwLight> mAvailableLights;
// Keep sorted in the order of importance.
std::array<std::pair<int, HwLightState>, 2> notif_states_ = {{
{(int)LightType::NOTIFICATIONS, {}},
{(int)LightType::BATTERY, {}},
}};
};
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View file

@ -0,0 +1,17 @@
service vendor.light /vendor/bin/hw/android.hardware.lights-service.berlna
class hal
user system
group system
shutdown critical
on boot
# Change ownership and permission for leds backlight
chmod 0664 /sys/class/leds/lcd-backlight/brightness
chown system system /sys/class/leds/charging/brightness
chmod 0664 /sys/class/leds/charging/brightness
chown system system /sys/class/leds/charging/breath
chmod 660 /sys/class/leds/charging/breath
chown system system /sys/class/leds/charging/delay_off
chmod 660 /sys/class/leds/charging/delay_off
chown system system /sys/class/leds/charging/delay_on
chmod 660 /sys/class/leds/charging/delay_on

View file

@ -0,0 +1,6 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.light</name>
<fqname>ILights/default</fqname>
</hal>
</manifest>

37
lights/aidl/main.cpp Normal file
View file

@ -0,0 +1,37 @@
/*
* Copyright (C) 2020 The Android Open Source 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.
*/
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include "Lights.h"
using ::aidl::android::hardware::light::Lights;
int main() {
ABinderProcess_setThreadPoolMaxThreadCount(0);
std::shared_ptr<Lights> lights = ndk::SharedRefBase::make<Lights>();
if (!lights) {
return EXIT_FAILURE;
}
const std::string instance = std::string() + Lights::descriptor + "/default";
binder_status_t status = AServiceManager_addService(lights->asBinder().get(), instance.c_str());
CHECK(status == STATUS_OK);
ABinderProcess_joinThreadPool();
return EXIT_FAILURE; // should not reached
}

140
lights/hidl/Light.cpp Normal file
View file

@ -0,0 +1,140 @@
/*
* Copyright (C) 2017 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.berlna"
#include <log/log.h>
#include "Light.h"
#include <fstream>
namespace android {
namespace hardware {
namespace light {
namespace V2_0 {
namespace implementation {
#define LEDS "/sys/class/leds/"
#define LCD_LED LEDS "lcd-backlight/"
#define CHARGING_LED LEDS "charging/"
#define BRIGHTNESS "brightness"
#define BREATH "breath"
#define DELAY_OFF "delay_off"
#define DELAY_ON "delay_on"
/*
* Write value to path and close file.
*/
static void set(std::string path, std::string value) {
std::ofstream file(path);
if (!file.is_open()) {
ALOGE("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 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;
}
static void handleBacklight(const LightState& state) {
uint32_t brightness = rgbToBrightness(state);
set(LCD_LED BRIGHTNESS, brightness);
}
static void handleNotification(const LightState& state) {
uint32_t alpha, brightness;
/*
* Extract brightness from AARRGGBB.
*/
alpha = (state.color >> 24) & 0xFF;
brightness = rgbToBrightness(state);
/*
* Scale brightness if the Alpha brightness is not 0xFF.
*/
if (alpha != 0xFF)
brightness = (brightness * alpha) / 0xFF;
/* Disable blinking. */
set(CHARGING_LED BREATH, 0);
if (state.flashMode == Flash::TIMED) {
/* Set LED */
set(CHARGING_LED DELAY_OFF, state.flashOffMs);
set(CHARGING_LED DELAY_ON, state.flashOnMs);
/* Enable blinking. */
set(CHARGING_LED BREATH, 1);
} else {
set(CHARGING_LED BRIGHTNESS, brightness);
}
}
static std::map<Type, std::function<void(const LightState&)>> lights = {
{Type::BACKLIGHT, handleBacklight},
{Type::BATTERY, handleNotification},
{Type::NOTIFICATIONS, handleNotification},
{Type::ATTENTION, handleNotification},
};
Light::Light() {}
Return<Status> Light::setLight(Type type, const LightState& state) {
auto it = lights.find(type);
if (it == lights.end()) {
return Status::LIGHT_NOT_SUPPORTED;
}
/*
* Lock global mutex until light state is updated.
*/
std::lock_guard<std::mutex> lock(globalLock);
it->second(state);
return Status::SUCCESS;
}
Return<void> Light::getSupportedTypes(getSupportedTypes_cb _hidl_cb) {
std::vector<Type> types;
for (auto const& light : lights) types.push_back(light.first);
_hidl_cb(types);
return Void();
}
} // namespace implementation
} // namespace V2_0
} // namespace light
} // namespace hardware
} // namespace android

55
lights/hidl/Light.h Normal file
View file

@ -0,0 +1,55 @@
/*
* Copyright (C) 2017 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 <hidl/Status.h>
#include <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:
std::mutex globalLock;
};
} // namespace implementation
} // namespace V2_0
} // namespace light
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H

View file

@ -0,0 +1,16 @@
service vendor.light-hal-2-0 /vendor/bin/hw/android.hardware.light@2.0-service.berlna
class hal
user system
group system
on boot
# Change ownership and permission for leds backlight
chmod 0664 /sys/class/leds/lcd-backlight/brightness
chown system system /sys/class/leds/charging/brightness
chmod 0664 /sys/class/leds/charging/brightness
chown system system /sys/class/leds/charging/breath
chmod 660 /sys/class/leds/charging/breath
chown system system /sys/class/leds/charging/delay_off
chmod 660 /sys/class/leds/charging/delay_off
chown system system /sys/class/leds/charging/delay_on
chmod 660 /sys/class/leds/charging/delay_on

View file

@ -0,0 +1,11 @@
<manifest version="1.0" type="device">
<hal format="hidl">
<name>android.hardware.light</name>
<transport>hwbinder</transport>
<version>2.0</version>
<interface>
<name>ILight</name>
<instance>default</instance>
</interface>
</hal>
</manifest>

50
lights/hidl/service.cpp Normal file
View file

@ -0,0 +1,50 @@
/*
* Copyright 2017 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.berlna"
#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() {
android::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;
}

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2016 The CyanogenMod Project
Copyright (C) 2017 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.
-->
<resources>
<!-- All the capabilities of the LEDs on this device, stored as a bit field.
This integer should equal the sum of the corresponding value for each
of the following capabilities present:
LIGHTS_RGB_NOTIFICATION_LED = 1
LIGHTS_RGB_BATTERY_LED = 2
LIGHTS_MULTIPLE_NOTIFICATION_LED = 4 (deprecated)
LIGHTS_PULSATING_LED = 8
LIGHTS_SEGMENTED_BATTERY_LED = 16
LIGHTS_ADJUSTABLE_NOTIFICATION_LED_BRIGHTNESS = 32
LIGHTS_BATTERY_LED = 64
LIGHTS_ADJUSTABLE_BATTERY_LED_BRIGHTNESS = 128
For example, a device support pulsating, RGB notification and
battery LEDs would set this config to 11. -->
<integer name="config_deviceLightCapabilities" translatable="false">248</integer>
</resources>

3
sepolicy/vendor/file_contexts vendored Normal file
View file

@ -0,0 +1,3 @@
# HAL Services
/(vendor|system/vendor)/bin/hw/android\.hardware\.lights-service\.berlna u:object_r:hal_light_default_exec:s0
/(vendor|system/vendor)/bin/hw/android\.hardware\.light@2\.0-service\.berlna u:object_r:hal_light_default_exec:s0

2
sepolicy/vendor/genfs_contexts vendored Normal file
View file

@ -0,0 +1,2 @@
# Lights
genfscon sysfs /devices/platform/soc/c440000.qcom,spmi/spmi-0/spmi0-05/c440000.qcom,spmi:qcom,pm8150l@5:qcom,leds@d000/leds/charging u:object_r:sysfs_leds:s0

5
sepolicy/vendor/hal_light_default.te vendored Normal file
View file

@ -0,0 +1,5 @@
allow hal_light_default {
sysfs_leds
}:file rw_file_perms;
r_dir_file(hal_light_default, sysfs_leds)