基于Android P源码分析,深入理解Android 灯光系统框架。
前言 灯光系统相对比较简单,但涉及多种不同的灯光类型,包括背光灯、电池灯、呼吸灯等。
Java服务 SystemServer.java zygote 进程启动时会加载 SystemServer.main() 方法,启动系统服务,其中就包括 LightsService 和 startHidlServices。
frameworks/base/services/java/com/android/server/SystemServer.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 import com.android.server.lights.LightsService; public final class SystemServer { private static final String TAG = "SystemServer"; private void startBootstrapServices() { // Manages LEDs and display backlight so we need it to bring up the display. traceBeginAndSlog("StartLightsService"); mSystemServiceManager.startService(LightsService.class); traceEnd(); } private void run() { ... // Start services. try { traceBeginAndSlog("StartServices"); startBootstrapServices(); startCoreServices(); startOtherServices(); SystemServerInitThreadPool.shutdown(); } catch (Throwable ex) { Slog.e("System", "******************************************"); Slog.e("System", "************ Failure starting system services", ex); throw ex; } finally { traceEnd(); } } private static native void startHidlServices(); private void startOtherServices() { ... startHidlServices(); ... } /** * The main entry point from zygote. */ public static void main(String[] args) { new SystemServer().run(); } }
LightsService.java 灯光服务类的实现,包括 native 本地方法
frameworks/base/services/core/java/com/android/server/lights/LightsService.java
1 2 3 4 5 6 7 8 9 10 11 12 public class LightsService extends SystemService { static final String TAG = "LightsService"; final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT]; private final class LightImpl extends Light { ... } // native jni方法 static native void setLight_native(int light, int color, int mode, int onMS, int offMS, int brightnessMode); }
JNI实现 setLight_native 会对应用传入的参数进行有效性检测,然后调用 hal->setLight()
方法。
frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 static void setLight_native( JNIEnv* /* env */, jobject /* clazz */, jint light, jint colorARGB, jint flashMode, jint onMS, jint offMS, jint brightnessMode) { if (!validate(light, flashMode, brightnessMode)) { return; } sp<ILight> hal = LightHal::associate(); if (hal == nullptr) { return; } Type type = static_cast<Type>(light); LightState state = constructState( colorARGB, flashMode, onMS, offMS, brightnessMode); { android::base::Timer t; Return<Status> ret = hal->setLight(type, state); processReturn(ret, type, state); if (t.duration() > 50ms) ALOGD("Excessive delay setting light"); } } static const JNINativeMethod method_table[] = { { "setLight_native", "(IIIIII)V", (void*)setLight_native }, }; int register_android_server_LightsService(JNIEnv *env) { return jniRegisterNativeMethods(env, "com/android/server/lights/LightsService", method_table, NELEM(method_table)); }
HIDL客户端 ILight.hal 定义了 ILight hidl 接口方法,而 types.hal 定义了相应的类型和结构体。
hardware/interfaces/light/2.0/ILight.hal
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package android.hardware.light@2.0; interface ILight { /** * Set the provided lights to the provided values. * * @param type logical light to set * @param state describes what the light should look like. * @return status result of applying state transformation. */ setLight(Type type, LightState state) generates (Status status); /** * Discover what indicator lights are available. * * @return types list of available lights */ getSupportedTypes() generates (vec<Type> types); };
经过编译会生成对应 C++/Java 源码和相关的库文件。
out/soong/.intermediates/hardware/interfaces/light/2.0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 $ ls total 24 drwxrwxr-x 6 xujinlong xujinlong 4096 Nov 25 11:49 android.hardware.light@2.0 drwxrwxr-x 3 xujinlong xujinlong 4096 Nov 25 11:31 android.hardware.light@2.0_genc++ drwxrwxr-x 3 xujinlong xujinlong 4096 Nov 25 11:31 android.hardware.light@2.0_genc++_headers drwxrwxr-x 3 xujinlong xujinlong 4096 Nov 25 11:46 android.hardware.light-V2.0-java drwxrwxr-x 3 xujinlong xujinlong 4096 Nov 25 11:31 android.hardware.light-V2.0-java_gen_java drwxrwxr-x 4 xujinlong xujinlong 4096 Nov 25 11:45 default $ $ tree android.hardware.light@2.0_genc++_headers/ android.hardware.light@2.0_genc++_headers/ └── gen └── android └── hardware └── light └── 2.0 ├── BnHwLight.h ├── BpHwLight.h ├── BsLight.h ├── hwtypes.h ├── IHwLight.h ├── ILight.h ├── ILight.h.d └── types.h 5 directories, 8 files $ tree android.hardware.light-V2.0-java_gen_java/ android.hardware.light-V2.0-java_gen_java/ └── gen └── android └── hardware └── light └── V2_0 ├── Brightness.java ├── Flash.java ├── ILight.java ├── ILight.java.d ├── LightState.java ├── Status.java └── Type.java 5 directories, 7 files $ tree android.hardware.light@2.0_genc++ android.hardware.light@2.0_genc++ └── gen └── android └── hardware └── light └── 2.0 ├── LightAll.cpp ├── LightAll.cpp.d └── types.cpp 5 directories, 3 files
default
目录存放生成的 android.hardware.light@2.0-service
执行程序和相应的依赖库 android.hardware.light@2.0-impl.so
android.hardware.light@2.0
目录存放生成的 hidl 库 android.hardware.light@2.0.so
android.hardware.light@2.0_genc++_headers
目录存放的是生成的头文件
android.hardware.light@2.0_genc++
目录存放的是生成的 C++ 源码
android.hardware.light-V2.0-java_gen_java
目录存放的是生成的 Java 源码
android.hardware.light-V2.0-java
目录存放的是生成的 jar
生成的 LightAll.cpp 源码中实现了 BnHwLight 和 BpHwLight 接口方法,重点关注 setLight 方法的实现。
1 2 3 4 5 6 // Methods from ::android::hardware::light::V2_0::ILight follow. ::android::hardware::Return<::android::hardware::light::V2_0::Status> BpHwLight::setLight(::android::hardware::light::V2_0::Type type, const ::android::hardware::light::V2_0::LightState& state){ ::android::hardware::Return<::android::hardware::light::V2_0::Status> _hidl_out = ::android::hardware::light::V2_0::BpHwLight::_hidl_setLight(this, this, type, state); return _hidl_out; }
BpHwLight::setLight 调用 BpHwLight::_hidl_setLight 方法,然后通过 Binder 机制调用到 BnHwLight::_hidl_setLight 方法,最终调用 HIDL 服务的 setLight 方法。
1 2 3 4 5 6 7 BpHwLight::setLight BpHwLight::_hidl_setLight transact(1 /* setLight */, _hidl_data, &_hidl_reply); BnHwLight::onTransact BnHwLight::_hidl_setLight static_cast<ILight*>(_hidl_this->getImpl().get())->setLight(type, *state);
HIDL服务 查看当前系统的light相关的进程,结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # ps -ef | grep light system 3115 1 0 10:50:44 ? 00:00:00 android.hardware.light@2.0-service root 6239 6155 4 13:39:05 pts/1 00:00:00 grep light # pmap 3115 3115: /vendor/bin/hw/android.hardware.light@2.0-service aeb04000 4K r-x-- /vendor/bin/hw/android.hardware.light@2.0-service aeb05000 4K r---- /vendor/bin/hw/android.hardware.light@2.0-service aeb06000 4K rw--- [anon] f1d9e000 68K r-x-- /vendor/lib/libusb.so f1daf000 4K r---- /vendor/lib/libusb.so f1db0000 4K rw--- /vendor/lib/libusb.so f1ddc000 16K r-x-- /vendor/lib/hw/lights.default.so f1de0000 4K r---- /vendor/lib/hw/lights.default.so f1de1000 4K rw--- /vendor/lib/hw/lights.default.so f1e2e000 12K r-x-- /vendor/lib/hw/android.hardware.light@2.0-impl.so f1e31000 4K r---- /vendor/lib/hw/android.hardware.light@2.0-impl.so f1e32000 4K rw--- /vendor/lib/hw/android.hardware.light@2.0-impl.so ...
对应的启动脚本位于 vendor/etc/init/android.hardware.light@2.0-service.rc,内容如下:
1 2 3 4 5 6 7 service vendor.light-hal-2-0 /vendor/bin/hw/android.hardware.light@2.0-service interface android.hardware.light@2.0::ILight default class hal user system group system # shutting off lights while powering-off shutdown critical
参考Android.bp,确定android.hardware.light@2.0-service
进程对应的源码是 service.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 cc_binary { name: "android.hardware.light@2.0-service", relative_install_path: "hw", defaults: ["hidl_defaults"], vendor: true, init_rc: ["android.hardware.light@2.0-service.rc"], srcs: ["service.cpp"], shared_libs: [ "liblog", "libbase", "libdl", "libutils", "libhardware", "libhidlbase", "libhidltransport", "android.hardware.light@2.0", ], }
这里使用 HIDL Passthrough 接口方法,具体如下:
hardware/interfaces/light/2.0/default/service.cpp
1 2 3 int main() { return defaultPassthroughServiceImplementation<ILight>(); }
system/libhidl/transport/include/hidl/LegacySupport.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 template<class Interface> __attribute__((warn_unused_result)) status_t defaultPassthroughServiceImplementation(std::string name, size_t maxThreads = 1) { configureRpcThreadpool(maxThreads, true); status_t result = registerPassthroughServiceImplementation<Interface>(name); if (result != OK) { return result; } joinRpcThreadpool(); return UNKNOWN_ERROR; } template<class Interface> __attribute__((warn_unused_result)) status_t defaultPassthroughServiceImplementation(size_t maxThreads = 1) { return defaultPassthroughServiceImplementation<Interface>("default", maxThreads); } template<class Interface> __attribute__((warn_unused_result)) status_t registerPassthroughServiceImplementation( std::string name = "default") { sp<Interface> service = Interface::getService(name, true /* getStub */); if (service == nullptr) { ALOGE("Could not get passthrough implementation for %s/%s.", Interface::descriptor, name.c_str()); return EXIT_FAILURE; } LOG_FATAL_IF(service->isRemote(), "Implementation of %s/%s is remote!", Interface::descriptor, name.c_str()); status_t status = service->registerAsService(name); if (status == OK) { ALOGI("Registration complete for %s/%s.", Interface::descriptor, name.c_str()); } else { ALOGE("Could not register service %s/%s (%d).", Interface::descriptor, name.c_str(), status); } return status; }
而使用 Passthrough 会加载传统的 HAL 库,相关的代码如下:
hardware/interfaces/light/2.0/default/Light.h
1 2 3 4 5 6 7 8 9 10 11 12 13 struct Light : public ILight { Light(std::map<Type, light_device_t*> &&lights); Return<Status> setLight(Type type, const LightState& state) override; Return<void> getSupportedTypes(getSupportedTypes_cb _hidl_cb) override; Return<void> debug(const hidl_handle& handle, const hidl_vec<hidl_string>& options) override; private: std::map<Type, light_device_t*> mLights; }; extern "C" ILight* HIDL_FETCH_ILight(const char* name);
hardware/interfaces/light/2.0/default/Light.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 Return<Status> Light::setLight(Type type, const LightState& state) { auto it = mLights.find(type); if (it == mLights.end()) { return Status::LIGHT_NOT_SUPPORTED; } light_device_t* hwLight = it->second; light_state_t legacyState { .color = state.color, .flashMode = static_cast<int>(state.flashMode), .flashOnMS = state.flashOnMs, .flashOffMS = state.flashOffMs, .brightnessMode = static_cast<int>(state.brightnessMode), }; int ret = hwLight->set_light(hwLight, &legacyState); switch (ret) { case -ENOSYS: return Status::BRIGHTNESS_NOT_SUPPORTED; case 0: return Status::SUCCESS; default: return Status::UNKNOWN; } } light_device_t* getLightDevice(const char* name) { light_device_t* lightDevice; const hw_module_t* hwModule = NULL; int ret = hw_get_module (LIGHTS_HARDWARE_MODULE_ID, &hwModule); if (ret == 0) { ret = hwModule->methods->open(hwModule, name, reinterpret_cast<hw_device_t**>(&lightDevice)); if (ret != 0) { ALOGE("light_open %s %s failed: %d", LIGHTS_HARDWARE_MODULE_ID, name, ret); } } else { ALOGE("hw_get_module %s %s failed: %d", LIGHTS_HARDWARE_MODULE_ID, name, ret); } if (ret == 0) { return lightDevice; } else { ALOGE("Light passthrough failed to load legacy HAL."); return nullptr; } } ILight* HIDL_FETCH_ILight(const char* /* name */) { std::map<Type, light_device_t*> lights; for(auto const &pair : kLogicalLights) { Type type = pair.first; const char* name = pair.second; light_device_t* light = getLightDevice(name); if (light != nullptr) { lights[type] = light; } } if (lights.size() == 0) { // Log information, but still return new Light. // Some devices may not have any lights. ALOGI("Could not open any lights."); } return new Light(std::move(lights)); }
HAL 这里根据操作设备名称的差异,设置不同的操作方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 struct hw_module_t HAL_MODULE_INFO_SYM = { .tag = HARDWARE_MODULE_TAG, .version_major = 1, .version_minor = 0, .id = LIGHTS_HARDWARE_MODULE_ID, .name = "Rokid lights Module", .author = "<jinlong.xu@rokid.com>", .methods = &lights_module_methods, }; static struct hw_module_methods_t lights_module_methods = { .open = open_lights, }; static int open_lights( const struct hw_module_t* module, char const *name, struct hw_device_t **device ) { void* set_light; if (0 == strcmp( LIGHT_ID_BACKLIGHT, name )) { set_light = set_light_backlight; } else if (0 == strcmp( LIGHT_ID_KEYBOARD, name )) { set_light = set_light_keyboard; } else if (0 == strcmp( LIGHT_ID_BUTTONS, name )) { set_light = set_light_buttons; } else if (0 == strcmp( LIGHT_ID_BATTERY, name )) { set_light = set_light_battery; } else if (0 == strcmp( LIGHT_ID_NOTIFICATIONS, name )) { set_light = set_light_notifications; } else if (0 == strcmp( LIGHT_ID_ATTENTION, name )) { set_light = set_light_attention; } else { D( "%s: %s light isn't supported yet.", __FUNCTION__, name ); return -EINVAL; } struct light_device_t *dev = malloc( sizeof(struct light_device_t) ); if (dev == NULL) { return -EINVAL; } memset( dev, 0, sizeof(*dev) ); dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 0; dev->common.module = (struct hw_module_t*)module; dev->common.close = (int (*)(struct hw_device_t*))close_lights; dev->set_light = set_light; *device = (struct hw_device_t*)dev; return 0; }
以 LIGHT_ID_BATTERY 为例,这里操作的是 /sys/devices/platform/sysled/sysled_status_switch
设备节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #define BATTERY "/sys/devices/platform/sysled/sysled_status_switch" static int set_light_battery( struct light_device_t* dev, struct light_state_t const* state ) { int fd,nwr; int ret = -1; char wbuf[20] = {0}; int light_level; light_level = state->color; D("Set_light_battery:%d\n",light_level); if(!dev) return -1; fd = open(BATTERY, O_RDWR); if (fd > 0){ nwr = sprintf(wbuf, "%d", light_level); ret = write(fd, wbuf, nwr); close(fd); } return 0; }
Driver 设备树节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 sysled { compatible = "amlogic, sysled"; dev_name = "sysled"; status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&pwm_ao_c_pins1 &pwm_c_pins1 &pwm_f_pins1>; pwm_config = <&sysled_pwm_conf>; }; sysled_pwm_conf:sysled_pwm_conf{ red_led_conf{ pwms = <&pwm_AO_cd MESON_PWM_0 200000 0>; }; green_led_conf{ pwms = <&pwm_ef MESON_PWM_1 200000 0>; }; blue_led_conf{ pwms = <&pwm_cd MESON_PWM_0 200000 0>; }; };
drivers/amlogic/led/led_sys.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 static int aml_sysled_probe(struct platform_device *pdev) { struct aml_sysled_dev *ldev; int ret; ldev = kzalloc(sizeof(struct aml_sysled_dev), GFP_KERNEL); /* set driver data */ platform_set_drvdata(pdev, ldev); /* parse dt param */ ret = aml_sysled_dt_parse(pdev); if (ret) return ret; local_dev = ldev; ldev->dev = &pdev->dev; mutex_init(&ldev->lock); ldev->sysled_wq = create_workqueue("sysled_wq"); INIT_DELAYED_WORK(&ldev->work, sysled_work_func); queue_delayed_work(ldev->sysled_wq, &ldev->work, 0); ret = device_create_file(&pdev->dev, &dev_attr_sysled_status_switch); if (ret != 0) { dev_err(&pdev->dev, "Failed to create sysfile sysled_system_status.\n"); return ret; } ret = device_create_file(&pdev->dev, &dev_attr_sysled_led_test); if (ret != 0) { dev_err(&pdev->dev, "Failed to create sysfile sysled_led_test.\n"); return ret; } dev_info(&pdev->dev, "Amlogic Sys-Led Probe Success\n"); return 0; } static const struct of_device_id aml_sysled_dt_match[] = { { .compatible = "amlogic, sysled", }, {}, }; static struct platform_driver aml_sysled_driver = { .driver = { .name = AML_DEV_NAME, .owner = THIS_MODULE, .of_match_table = aml_sysled_dt_match, }, .probe = aml_sysled_probe, .remove = __exit_p(aml_sysled_remove), .shutdown = aml_sysled_shutdown, #ifdef CONFIG_PM .suspend = aml_sysled_suspend, .resume = aml_sysled_resume, #endif }; static int __init aml_sysled_init(void) { pr_info("module init\n"); if (platform_driver_register(&aml_sysled_driver)) { pr_err("failed to register driver\n"); return -ENODEV; } return 0; }
添加 sysfs 方式修改的驱动接口,这里就不贴代码实现细节了。
1 2 3 static DEVICE_ATTR(sysled_status_switch, 0664, sysled_status_show, sysled_status_store); static DEVICE_ATTR(sysled_led_test, 0664, sysled_test_show, sysled_test_store);
总结 通过阅读源码,简单梳理了 Android 灯光系统的流程。Android P 引入了 HIDL,使用单独的服务进程操作 HAL,并与框架层客户端进行通信。