最近项目中需要添加LED灯接口,该LED灯当作手电筒使用。
我们从驱动层到应用层的顺序逐步添加接口,具体为什么要在某一文件中添加请参考我的另外两篇文章
Android4.4 LightsService使用笔记
Android4.4移植-LED灯驱动适配
1 添加LED灯驱动
1.1 添加驱动文件
在vendor或者kernel目录下添加驱动文件,本项目中存放路径为kernel/drivers/leds/flashlight.c
具体内容后续补充
1.2 配置该驱动文件参加编译
...后续补充
2. HAL层接口适配
对于不同厂商的LED驱动,安卓进行了统一接口操作,本项目中文件目录为vendor/***/open-source/libs/liblights/lights.c
,安卓默认路径hardware/qcom/display/***/liblight/lights.c
本项目中lights.c具体修改内容如下:
//1 定义枚举类型 //all lights enum { RED_LED, GREEN_LED, FLASHLIGHT, //添加FLASHLIGHT灯的枚举 BLUE_LED, LCD_BACKLIGHT, BUTTONS_LED, NUM_LEDS, }; //2 定义节点路径 //light nodes struct led leds[NUM_LEDS] = { [RED_LED] = { .brightness = { "/sys/class/leds/red/brightness", 0}, //正常亮度 .delay_on = { "/sys/class/leds/red/delay_on", 0}, //LED闪烁熄灭时长 .delay_off = { "/sys/class/leds/red/delay_off", 0}, //LED闪烁点亮时长 .triggers = { "/sys/class/leds/red/triggers", 0}, //LED闪烁时的亮度 }, [GREEN_LED] = { .brightness = { "/sys/class/leds/green/brightness", 0}, .delay_on = { "/sys/class/leds/green/delay_on", 0}, .delay_off = { "/sys/class/leds/green/delay_off", 0}, .triggers = { "/sys/class/leds/green/triggers", 0}, }, //该路径与驱动中生成节点的路径需要一致 [FLASHLIGHT] = { .brightness = { "/sys/class/leds/flashlight/brightness", 0}, }, [BLUE_LED] = { }, [LCD_BACKLIGHT] = { .brightness = { "/sys/class/backlight/sprd_backlight/brightness", -1}, }, [BUTTONS_LED] = { .brightness = {"/sys/class/leds/keyboard-backlight/brightness", -1}, }, }; //3 添加操作函数 static int set_light_flashlight(struct light_device_t *dev, struct light_state_t const *state) { ALOGE("file:%s, func:%s, light!\n", __FILE__, __func__); int on = is_lit(state); ALOGD("file:%s, func:%s, on=%d\n", __FILE__, __func__, on); if(NULL==leds[FLASHLIGHT].brightness.filename) { ALOGE("file:%s, func:%s, unsupported light!\n", __FILE__, __func__); return -EINVAL; } pthread_mutex_lock(&g_lock); int err = write_int(&leds[FLASHLIGHT].brightness, on?(on&0xff):0); pthread_mutex_unlock(&g_lock); return err; } //5 函数指针赋值 static int open_lights(const struct hw_module_t *module, char const *name, struct hw_device_t **device) { int (*set_light)(struct light_device_t *dev, struct light_state_t const *state); ALOGV("file:%s, func:%s name=%s\n", __FILE__, __func__, name); 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_NOTIFICATIONS, name)) set_light = set_light_leds_notifications; else if (0 == strcmp(LIGHT_ID_ATTENTION, name)) set_light = set_light_leds_attention; else if (0 == strcmp(LIGHT_ID_BATTERY,name)) set_light = set_light_leds_notifications; //add flashlight,set_light函数入口指向前面定义的set_light_flashlight函数 else if (0 == strcmp(LIGHT_ID_FLASHLIGHT,name)) set_light = set_light_flashlight; else return -EINVAL; ... }
3 定义FLASHLIGHT模块
文件路径hardware/libhardware/include/hardware/lights.h
#define LIGHT_ID_BACKLIGHT "backlight" #define LIGHT_ID_KEYBOARD "keyboard" #define LIGHT_ID_BUTTONS "buttons" #define LIGHT_ID_BATTERY "battery" #define LIGHT_ID_NOTIFICATIONS "notifications" #define LIGHT_ID_ATTENTION "attention" //add flashlight--bianjb #define LIGHT_ID_FLASHLIGHT "flashlight"
4 添加JNI接口
文件路径frameworks/base/services/jni/com_android_server_LightsService.cpp
//1 定义INDEX // These values must correspond with the LIGHT_ID constants in // LightsService.java enum { LIGHT_INDEX_BACKLIGHT = 0, LIGHT_INDEX_KEYBOARD = 1, LIGHT_INDEX_BUTTONS = 2, LIGHT_INDEX_BATTERY = 3, LIGHT_INDEX_NOTIFICATIONS = 4, LIGHT_INDEX_ATTENTION = 5, LIGHT_INDEX_BLUETOOTH = 6, LIGHT_INDEX_WIFI = 7, LIGHT_INDEX_FLASHLIGHT = 8, //按顺序添加即可,注意后面LightsService.java中定义的ID值与该值一致,为8 LIGHT_COUNT }; //2 FLASHLIGHT模块初始化 static jint init_native(JNIEnv *env, jobject clazz) { int err; hw_module_t* module; Devices* devices; devices = (Devices*)malloc(sizeof(Devices)); err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); if (err == 0) { devices->lights[LIGHT_INDEX_BACKLIGHT] = get_device(module, LIGHT_ID_BACKLIGHT); devices->lights[LIGHT_INDEX_KEYBOARD] = get_device(module, LIGHT_ID_KEYBOARD); devices->lights[LIGHT_INDEX_BUTTONS] = get_device(module, LIGHT_ID_BUTTONS); devices->lights[LIGHT_INDEX_BATTERY] = get_device(module, LIGHT_ID_BATTERY); devices->lights[LIGHT_INDEX_NOTIFICATIONS] = get_device(module, LIGHT_ID_NOTIFICATIONS); devices->lights[LIGHT_INDEX_ATTENTION] = get_device(module, LIGHT_ID_ATTENTION); devices->lights[LIGHT_INDEX_BLUETOOTH] = get_device(module, LIGHT_ID_BLUETOOTH); devices->lights[LIGHT_INDEX_WIFI] = get_device(module, LIGHT_ID_WIFI); //初始化falshlight模块,当时忘记添加,导致死机 devices->lights[LIGHT_INDEX_FLASHLIGHT]//add flashlight--bianjb = get_device(module, LIGHT_ID_FLASHLIGHT); ... }
5 添加framework层java接口
文件位置frameworks/base/services/java/com/android/server/LightsService.java
//添加FLASHLIGHT定义,注意一定要与com_android_server_LightsService.cpp中定义的对应 INDEX值相同 public static final int LIGHT_ID_FLASHLIGHT = 8;
至此,接口添加完毕,下面讲如何进行调用
6 调用接口
6.1 自定义服务
LightsService是隐藏的API,该如何进行调用呢,可以添加自定义的Service类进行调用。
6.2 添加setBrightness方法
我添加了一个setBrightness方法到自定义服务中,需要修改三个地方
//1 FlyscaleService.java中添加如下方法 //0-255 public void setBrightness(int lightByte, int brightness) throws RemoteException { Log.d(TAG, "setBrightness,lightByte=" + lightByte + ",brightness=" + brightness); long l = Binder.clearCallingIdentity(); try { //getLightByType方法是我自己定义的,返回LightsService.Light对象 getLightByType(lightByte).setBrightness(brightness); } finally { Binder.restoreCallingIdentity(l); } } //2 IFlyscaleManager.aidl中添加接口方法 void setBrightness(int lightByte, int brightness); //3 FlyscaleManager.java中添加供外部调用的方法 public void setBrightness(int lightByte, int brightness) { Log.i(TAG, "setBrightness,lightByte=" + lightByte + ",brightness=" + brightness); try { this.mService.setBrightness(lightByte, brightness); } catch (RemoteException e) { e.printStackTrace(); } }
6.3 APP中进行调用
例如使用AndroidStudio开发,需要把IFlyscaleManager.aidl文件引入,同时拷贝FlyscaleManager.java到与源码中相同的包名下,即可进行开发了。