第十三章:LightsService
简介
LightsService
灯光服务提供了LCD背光灯、键盘灯、按键灯、警示灯、电池灯、消息通知灯、蓝牙灯、wifi灯等八种类型灯光;
常用到的地方为:PowerManager
、NotificationManager
、BatteryService
等API会调用灯光服务控制灯光显示以及颜色、时长;
涉及到代码:
调用api类:
frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
内部实现类
frameworks/base/services/core/java/com/android/server/lights/LightsManager.java
frameworks/base/services/core/java/com/android/server/lights/LightsService.java
frameworks/base/services/core/java/com/android/server/lights/Light.java
JNI层:
frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp//调用硬件抽象层ILight.h
C逻辑层:
//例如:华为nexus 6p实现 读写驱动文件
hardware/libhardware/include/hardware/lights.h //硬件库
device/huawei/angler/liblight/lights.c
硬件抽象层:
hardware/interfaces/light/2.0/ILight.hal //抽象接口
内核层:
驱动层:
//驱动文件一般位于kernel下面,根据不同的硬件厂商而有所不同。
//驱动程序会监测上面提到的所有节点文件是否被写入,如果节点文件有写入不同的值,那么驱动程序会读取该值 ,并依据具体情况设定不同的LED灯状态。驱动文件详情不再详述。
注意:linux中的所有操作都是通过文件的形式,所以LED的最终操作也是通过读写节点文件来实现的 该类中提供了操作LED灯节点文件的方法,通过向节点文件写入数据,位于kernel下面的LED灯的驱动程序会检测到文件的改动,进而对LED的状态根据写入的值进行重新设定。
灯系统架构图

一、启动 --->(Java层分析)
启动位置
frameworks/base/services/java/com/android/server/SystemServer.java
跟其他系统服务一样, LightsService
也是继承于SystemService
并通过SystemServer
启动。
public final class SystemServer {
private void startBootstrapServices() {
.....
mSystemServiceManager.startService(LightsService.class);
.....
}
}
构造函数
创建Light 灯光对象,多种类型存放数组中;LightImpl
是Light
的具体实现;
frameworks/base/services/core/java/com/android/server/lights/LightsService.java
public class LightsService extends SystemService {
public LightsService(Context context) {
super(context);
for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) {
mLights[i] = new LightImpl(i);
}
}
}
onStart()对外开发服务
提供获取Light灯光,实现控制
@Override
public void onStart() {
publishLocalService(LightsManager.class, mService);
}
private final LightsManager mService = new LightsManager() {
@Override
public Light getLight(int id) {
if (0 <= id && id < LIGHT_ID_COUNT) {
return mLights[id];
} else {
return null;
}
}
};
LightsManager灯光管理抽象类
定义了8中灯光类型;LIGHT_ID_COUNT
记录硬件支持的灯光类型数量;
frameworks/base/services/core/java/com/android/server/lights/LightsManager.java
public abstract class LightsManager {
public static final int LIGHT_ID_BACKLIGHT = Type.BACKLIGHT;
public static final int LIGHT_ID_KEYBOARD = Type.KEYBOARD;
public static final int LIGHT_ID_BUTTONS = Type.BUTTONS;
public static final int LIGHT_ID_BATTERY = Type.BATTERY;
public static final int LIGHT_ID_NOTIFICATIONS = Type.NOTIFICATIONS;
public static final int LIGHT_ID_ATTENTION = Type.ATTENTION;
public static final int LIGHT_ID_BLUETOOTH = Type.BLUETOOTH;
public static final int LIGHT_ID_WIFI = Type.WIFI;
public static final int LIGHT_ID_COUNT = Type.COUNT;
public abstract Light getLight(int id);
}
Light灯光对象
对灯光类型进行封装抽象
frameworks/base/services/core/java/com/android/server/lights/Light.java
public abstract class Light {
public static final int LIGHT_FLASH_NONE = Flash.NONE;
public static final int LIGHT_FLASH_TIMED = Flash.TIMED;
public static final int LIGHT_FLASH_HARDWARE = Flash.HARDWARE;
/**
* Light brightness is managed by a user setting.
*/
public static final int BRIGHTNESS_MODE_USER = Brightness.USER;
/**
* Light brightness is managed by a light sensor.
*/
public static final int BRIGHTNESS_MODE_SENSOR = Brightness.SENSOR;
/**
* Low-persistence light mode.
*/
public static final int BRIGHTNESS_MODE_LOW_PERSISTENCE = Brightness.LOW_PERSISTENCE;
public abstract void setBrightness(int brightness);
public abstract void setBrightness(int brightness, int brightnessMode);
public abstract void setColor(int color);
public abstract void setFlashing(int color, int mode, int onMS, int offMS);
public abstract void pulse();
public abstract void pulse(int color, int onMS);
public abstract void turnOff();
public abstract void setVrMode(boolean enabled);
}
LightImpl 是对抽象Light 的具体实现
LightImpl
是LightsService
的内部私有类
private final class LightImpl extends Light {
@Override
public void setBrightness(int brightness, int brightnessMode) {
synchronized (this) {
// LOW_PERSISTENCE cannot be manually set
if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
Slog.w(TAG, "setBrightness with LOW_PERSISTENCE unexpected #" + mId +
": brightness=0x" + Integer.toHexString(brightness));
return;
}
int color = brightness & 0x000000ff;
color = 0xff000000 | (color << 16) | (color << 8) | color;
setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
}
}
}
这个方法是设置灯的亮度值,它最终会将这个亮度brightness(取值范围0~255)
转换成色彩值color(ARGB)
。我们知道颜色都是三基色RGB组成的,我们要控制的灯基本上都是单色的,要么是红色,要么是绿色。所以在转换过程中,是将亮度值对应的数值分别设置到RGB三色中,也就是每一个单色上都设置为跟亮度相同的数值,这样无论控制的是什么颜色的灯,都会将亮度值设置为brightness
。其中0xff000000
表示的是ARGB
模式,A
表示的是透明度。在实际操作过程中,只要亮度值大于0,设置任意数值都会起到相同的作用,都能够达到点亮灯的效果。
setLightLocked()方法
最终会通过JNI调用底层设置灯光
private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
......
mInitialized = true;
mLastColor = mColor;
mColor = color;
mMode = mode;
mOnMS = onMS;
mOffMS = offMS;
mBrightnessMode = brightnessMode;
.........
setLight_native(mId, color, mode, onMS, offMS, brightnessMode);
........
}
//JNI调用
static native void setLight_native(int light, int color, int mode,
int onMS, int offMS, int brightnessMode);
}
二、JNI调用 --->(JNI层分析)
java层对灯光的操作最终到会通过JNI调用硬件抽象层;
frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp
LightsService
调用了LightsService.cpp
的本地方法,下面看一下该类。
#define LOG_TAG "LightsService"
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
//关键引入ILight模块和types模块接口
#include <android/hardware/light/2.0/ILight.h>
#include <android/hardware/light/2.0/types.h>
#include <utils/misc.h>
#include <utils/Log.h>
#include <map>
#include <stdio.h>
namespace android {
using Brightness = ::android::hardware::light::V2_0::Brightness;
using Flash = ::android::hardware::light::V2_0::Flash;
using ILight = ::android::hardware::light::V2_0::ILight;
using LightState = ::android::hardware::light::V2_0::LightState;
using Status = ::android::hardware::light::V2_0::Status;
using Type = ::android::hardware::light::V2_0::Type;
template<typename T>
using Return = ::android::hardware::Return<T>;
class LightHal {
private:
static sp<ILight> sLight;
static bool sLightInit;
LightHal() {}
public:
static void disassociate() {
sLightInit = false;
sLight = nullptr;
}
static sp<ILight> associate() {
if ((sLight == nullptr && !sLightInit) ||
(sLight != nullptr && !sLight->ping().isOk())) {
// will return the hal if it exists the first time.
//如果硬件接口已实现,将返回硬件接口
//HAL 服务获取: HIDL 接口,从 servicemanager 中获取 Light 服务
//具体请看:https://blog.csdn.net/wangjun7121/article/details/88140862
sLight = ILight::getService();
sLightInit = true;
if (sLight == nullptr) {
ALOGE("Unable to get ILight interface.");
}
}
return sLight;
}
};
sp<ILight> LightHal::sLight = nullptr;
bool LightHal::sLightInit = false;
//检测java传入的参数是否合法
static bool validate(jint light, jint flash, jint brightness) {
bool valid = true;
//灯类型是否在有效区间内
if (light < 0 || light >= static_cast<jint>(Type::COUNT)) {
ALOGE("Invalid light parameter %d.", light);
valid = false;
}
//闪光类型是否正确 枚举类型
if (flash != static_cast<jint>(Flash::NONE) &&
flash != static_cast<jint>(Flash::TIMED) &&
flash != static_cast<jint>(Flash::HARDWARE)) {
ALOGE("Invalid flash parameter %d.", flash);
valid = false;
}
//亮度是否合法
if (brightness != static_cast<jint>(Brightness::USER) &&
brightness != static_cast<jint>(Brightness::SENSOR) &&
brightness != static_cast<jint>(Brightness::LOW_PERSISTENCE)) {
ALOGE("Invalid brightness parameter %d.", brightness);
valid = false;
}
if (brightness == static_cast<jint>(Brightness::LOW_PERSISTENCE) &&
light != static_cast<jint>(Type::BACKLIGHT)) {
ALOGE("Cannot set low-persistence mode for non-backlight device.");
valid = false;
}
return valid;
}
static LightState constructState(
jint colorARGB,
jint flashMode,
jint onMS,
jint offMS,
jint brightnessMode){
Flash flash = static_cast<Flash>(flashMode);
Brightness brightness = static_cast<Brightness>(brightnessMode);
LightState state{};
if (brightness == Brightness::LOW_PERSISTENCE) {
state.flashMode = Flash::NONE;
} else {
// Only set non-brightness settings when not in low-persistence mode
state.flashMode = flash;
state.flashOnMs = onMS;
state.flashOffMs = offMS;
}
state.color = colorARGB;
state.brightnessMode = brightness;
return state;
}
static void processReturn(
const Return<Status> &ret,
Type type,
const LightState &state) {
if (!ret.isOk()) {
ALOGE("Failed to issue set light command.");
LightHal::disassociate();
return;
}
switch (static_cast<Status>(ret)) {
case Status::SUCCESS:
break;
case Status::LIGHT_NOT_SUPPORTED:
ALOGE("Light requested not available on this device. %d", type);
break;
case Status::BRIGHTNESS_NOT_SUPPORTED:
ALOGE("Brightness parameter not supported on this device: %d",
state.brightnessMode);
break;
case Status::UNKNOWN:
default:
ALOGE("Unknown error setting light.");
}
}
//java层调用JNI方法的实现
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<>是安卓特有的智能指针(不用专门去维护内存回收);也可以说是强指针
sp<ILight> hal = LightHal::associate();
if (hal == nullptr) {
return;
}
Type type = static_cast<Type>(light);
LightState state = constructState(
colorARGB, flashMode, onMS, offMS, brightnessMode);
{
ALOGD_IF_SLOW(50, "Excessive delay setting light");
Return<Status> ret = hal->setLight(type, state);
processReturn(ret, type, state);
}
}
//注册方法表
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 接口 定义
hardware/interfaces/light/2.0/ILight.hal
hardware/interfaces/light/2.0/types.hal
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);
};
HIDL客户端与服务端通过Binder通讯实现流程图:

其实主要是就是将以前那种
Java-> Jni -> Hal -> Kernel 的
结构变成了
Java -> Jni -> Binder 客户端 ====== Binder 通信 ======> Binder 服务端 -> Hal -> Kernel
将 framework 与 Hal 之间的交互变成了 CS 结构了。
四、HIDL 服务端
hardware/interfaces/light
目录如下:

- 1.
ILight.hal
HIDL 接口文件定义 - 2.
types.hal
是HIDL定义类型、颜色等; - 3.
service.cpp
是HIDL的HAl提供服务; - 4.
Light.h
头文件,最终引用/hardware/libhardware/include/hardware/lights.h
,里面包含灯光类型定义、struct数据结构封装; - 4.
Light.cpp
是ILight.hal
HIDL 接口的实现,最终会调用
五、HAL逻辑实现
负责对驱动文件的读写操作
(这里采用华为的angler设备 Nexus 6p)
相关代码:
/hardware/libhardware/include/hardware/lights.h
/device/huawei/angler/liblight/lights.c
操作驱动文件目录:
/sys/class/leds/
总结:
调用流程
