资讯动态

Android学习28--LED点灯(Ver2)(TODO)

发布时间:2026/8/15 4:39:54 来源:尧图企业网站定制
可以这样做但它不是“App 直接调用 HAL”。完整链路是系统 App ↓ android.hardware.lights.LightsManager Framework LightsService ↓ Binder android.hardware.light.ILights/default ↓ Lights AIDL HAL ↓ write() /sys/class/leds/user-led/brightness ↓ LED 驱动Android 14 推荐使用稳定版 AIDL Lights HAL。标准接口只有两个核心方法HwLight[] getLights(); void setLightState(int id, HwLightState state);官方接口定义见 ILights.aidl。一、先把内核驱动标准化当前节点是/sys/devices/platform/soc/soc:user-led/brightness能用但量产最好把驱动注册成 Linux LED class生成/sys/class/leds/user-led/brightness /sys/class/leds/user-led/max_brightness内核驱动大致如下#include linux/leds.h struct user_led { struct led_classdev cdev; int gpio; }; static void user_led_set( struct led_classdev *cdev, enum led_brightness value) { struct user_led *led container_of(cdev, struct user_led, cdev); gpio_set_value(led-gpio, value ! LED_OFF); } static int user_led_probe(struct platform_device *pdev) { struct user_led *led; led devm_kzalloc( pdev-dev, sizeof(*led), GFP_KERNEL); if (!led) return -ENOMEM; led-cdev.name user-led; led-cdev.max_brightness 1; led-cdev.brightness_set user_led_set; return devm_led_classdev_register( pdev-dev, led-cdev); }不过现有节点也可以先用于 HAL 验证。二、实现 Lights AIDL HAL接口来自 AOSPhardware/interfaces/light/aidlHAL 进程需要实现aidl::android::hardware::light::BnLights示意实现#include aidl/android/hardware/light/BnLights.h #include aidl/android/hardware/light/HwLight.h #include aidl/android/hardware/light/HwLightState.h #include aidl/android/hardware/light/LightType.h #include fstream using aidl::android::hardware::light::BnLights; using aidl::android::hardware::light::HwLight; using aidl::android::hardware::light::HwLightState; using aidl::android::hardware::light::LightType; using ndk::ScopedAStatus; class Lights : public BnLights { public: ScopedAStatus getLights( std::vectorHwLight* lights) override { HwLight light; light.id 10; light.ordinal 0; light.type LightType::NOTIFICATIONS; lights-clear(); lights-push_back(light); return ScopedAStatus::ok(); } ScopedAStatus setLightState( int32_t id, const HwLightState state) override { if (id ! 10) { return ScopedAStatus::fromExceptionCode( EX_UNSUPPORTED_OPERATION); } // HwLightState.color 是 ARGB。 // RGB 任一分量非零就点亮。 bool on (state.color 0x00ffffff) ! 0; std::ofstream node( /sys/class/leds/user-led/brightness); if (!node.is_open()) { return ScopedAStatus::fromServiceSpecificError( errno); } node (on ? 1 : 0); if (!node.good()) { return ScopedAStatus::fromServiceSpecificError( EIO); } return ScopedAStatus::ok(); } };如果暂时保留当前驱动路径改成/sys/devices/platform/soc/soc:user-led/brightness对于二值 LED可以只判断(state.color 0x00ffffff) ! 0如果后续换成 RGB LED则可分别解析red (color 16) 0xff; green (color 8) 0xff; blue color 0xff;三、注册 Binder 服务main.cpp#include Lights.h #include android/binder_manager.h #include android/binder_process.h int main() { ABinderProcess_setThreadPoolMaxThreadCount(0); auto service ndk::SharedRefBase::makeLights(); const std::string instance std::string(Lights::descriptor) /default; binder_status_t status AServiceManager_addService( service-asBinder().get(), instance.c_str()); if (status ! STATUS_OK) return 1; ABinderProcess_joinThreadPool(); return 0; }四、Android.bpcc_binary { name: android.hardware.light-service.userled, vendor: true, relative_install_path: hw, srcs: [ main.cpp, Lights.cpp, ], shared_libs: [ libbase, libbinder_ndk, android.hardware.light-V2-ndk, ], init_rc: [ android.hardware.light-service.userled.rc, ], vintf_fragments: [ android.hardware.light-service.userled.xml, ], }需要使用与当前 Android 14固件匹配的接口版本。当前 AOSP Lights AIDL 包定义为 vendor 可用、VINTF-stable 接口。AIDL HAL 文档、Lights AIDL Android.bp。五、init rcservice vendor.light-default \ /vendor/bin/hw/android.hardware.light-service.userled class hal user system group system是否需要disabled、oneshot要看 lazy HAL 设计。普通常驻 HAL 不加oneshot。如果采用 lazy HAL需要配合interface aidl android.hardware.light.ILights/default disabled oneshot首版建议先做普通常驻服务便于调试。六、VINTF manifestmanifest version1.0 typedevice hal formataidl nameandroid.hardware.light/name version2/version interface nameILights/name instancedefault/instance /interface /hal /manifest有些版本也使用简化形式hal formataidl nameandroid.hardware.light/name fqnameILights/default/fqname /hal实际格式要与板子当前 VINTF schema 和 AIDL 版本一致。官方默认示例可参考 lights-default.xml。七、SELinux不能继续使用chmod 0666 SELinux Permissive应该给 LED 节点单独定义类型例如type sysfs_user_led, fs_type, sysfs_type;如果使用标准 LED class可以通过genfs_contexts标记genfscon sysfs /class/leds/user-led \ u:object_r:sysfs_user_led:s0实际 sysfs 内核路径经常不是表面软链接路径需要用readlink -f /sys/class/leds/user-led确认后填写真实路径。HAL 定义独立 domaintype hal_light_userled, domain; type hal_light_userled_exec, exec_type, vendor_file_type, file_type; init_daemon_domain(hal_light_userled) allow hal_light_userled sysfs_user_led:dir { search }; allow hal_light_userled sysfs_user_led:file { open write getattr };服务二进制标签/vendor/bin/hw/android.hardware.light-service.userled \ u:object_r:hal_light_userled_exec:s0还要补充 Binder/AIDL HAL 相关宏具体宏名取决于 BSP sepolicyhal_server_domain( hal_light_userled, hal_light )最终必须在getenforce Enforcing条件下验证。八、Framework 如何连接 HALAndroid Framework 的LightsService会查找android.hardware.light.ILights/default然后调用 HALgetLights() setLightState()通常不需要修改SystemServer。只要HAL 名称正确VINTF 声明正确Binder 服务注册成功SELinux 放行Framework 与 vendor AIDL 版本兼容。就能自动接上。验证 HALadb shell service list | grep -i light adb shell dumpsys lights adb shell logcat -b all | grep -i light adb shell ps -A | grep lightAIDL vendor service也可以检查adb shell service check \ android.hardware.light.ILights/default九、App 调用 LightsManagerApp 端可使用import android.hardware.lights.Light import android.hardware.lights.LightState import android.hardware.lights.LightsManager获取灯val manager getSystemService(LightsManager::class.java) val light manager.lights.firstOrNull { it.type Light.LIGHT_TYPE_NOTIFICATIONS }打开会话并控制val session manager.openSession() val onState LightState.Builder() .setColor(0xFFFFFFFF.toInt()) .build() session.requestLights( LightsRequest.Builder() .addLight(light!!, onState) .build() )关闭val offState LightState.Builder() .setColor(0x00000000) .build() session.requestLights( LightsRequest.Builder() .addLight(light, offState) .build() )Activity 销毁时session.close()权限限制这是关键点普通第三方 App 通常不能任意控制设备灯。直接使用LightsManager.openSession()需要受保护的设备灯控制权限例如uses-permission android:nameandroid.permission.CONTROL_DEVICE_LIGHTS/该权限不是普通运行时权限通常要求受信任系统 App/平台签名。仅把 APK 放进priv-app也不一定足够还需要platform/厂商签名privapp 权限白名单Framework 权限定义允许必要时专用 SELinux App domain。所以最终 App 一般要做成厂商系统 App。十、LED 类型怎么选如果这是通知灯可以返回LightType::NOTIFICATIONS如果是产品独有的功能灯不建议冒充BACKLIGHT BATTERY CAMERA MICROPHONE因为 Framework 可能自动控制这些灯与你的 App 冲突。需要考虑两个方案让它作为NOTIFICATIONS灯由 Android 通知系统控制使用 Lights HAL 中额外的同类实例并由特权 App 根据id/ordinal选择。HwLight.id是 HAL 自定义的稳定 ID例如10ordinal用于同类型多个灯排序。如果只是业务 App 独占的一颗 LED自定义 AIDL HAL 往往比标准 Lights HAL 更清晰。Lights HAL 的语义主要是 Android 系统灯Framework 可能根据通知、充电、相机或麦克风状态主动接管。十一、当前“无源码”条件的现实限制完整实施至少需要匹配 Android 14 的 AIDL NDK 头文件和库 Lights HAL 二进制 init rc VINTF manifest vendor sepolicy App 系统签名/权限 重新制作 vendor.img/product.img只有现成 image 时可以先编译 HAL 二进制并通过 remount 做原型测试但之前已经验证过overlay 中新增.rc可能不会被 init 早期加载新增 VINTF 文件也有启动时序问题SELinux policy 不能靠普通 push 完整增加App 缺少 platform 签名权限。因此原型验证 现有启动脚本 → 启动自定义服务 → App 调用 正式量产 编入 vendor.img/product.img SELinux Enforcing对于当前板子我建议先做“小型自定义 AIDL/native daemon”验证 App→Binder→sysfs确认业务接口拿到匹配 BSP 后再决定是否迁移到标准 Lights HAL。这样风险最低也不会和 Android 自带灯光策略发生冲突。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价