本文章分析Android系统中,灯光系统如何调用灯光服务、JNI、HAL等从而操控底层Linux驱动控制的led电池灯去闪烁或者亮不同颜色的灯来通知用户。
不扯别的,直接上图,简单描述整个调用过程:
以下是详细调用过程:
1. 首先Android系统加载后会执行init进程,然后加载SystemService.java系统服务
SystemService.java
private void startCoreServices() {
// Manages LEDs and display backlight.
mSystemServiceManager.startService(LightsService.class);
// Tracks the battery level. Requires LightService.
mSystemServiceManager.startService(BatteryService.class);
}
private void startBootstrapServices() {
/* 加载电源管理服务,灯光系统属于电源管理的一部分 */
mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService());
}
2 . mSystemServiceManager.startService(LightsService.class);
调用LightsService.java的onStart方法,开启一个LightsManager服务。
LightsManager服务用来管理所有的灯光,包括电池灯、通知灯、背光灯。当需要控制这些灯的时候就需要getLocalService获取这个服务,然后调用这个服务的getLight方法,传入对应的灯的id(参考lighs.h)就可以获取对应的灯的实例化对象,从而可以通过这个对象获取对象里面的操作各种灯的方法。
LightsService.java
//实例化多个LightImpl对象,分别对应电池灯、通知灯、背光灯,通过getLight方法传入不同的id就可以获取对应的对象
final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT];
public void onStart() {
publishBinderService("hardware", mLegacyFlashlightHack);
publishLocalService(LightsManager.class, mService);
}
private final LightsManager mService = new LightsManager() {
@Override
public com.android.server.lights.Light getLight(int id) {
if (id < LIGHT_ID_COUNT) {
return mLights[id];
}
}
};
LightImpl继承了Light这个抽象类,并实现了抽象类的setBrightness setColor setFlashing等抽象方法,这些方法最终都调用了setLightLocked方法,而setLightLocked方法最终有调用了JNI提供的接口setLight_native
private final class LightImpl extends Light {
private LightImpl(int id) {
mId = id;
}
@Override
public void setBrightness(int brightness) {
setBrightness(brightness, BRIGHTNESS_MODE_USER);
}
@Override
public void setBrightness(int brightness, int brightnessMode) {
setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
}
@Override
public void setColor(int color) {
setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, 0);
}
@Override
public void setFlashing(int color, int mode, int onMS, int offMS) {
setLightLocked(color, mode, onMS, offMS, BRIGHTNESS_MODE_USER);
}
@Override
public void turnOff() {
setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, 0);
}
private void stopFlashing() {
setLightLocked(mColor, LIGHT_FLASH_NONE, 0, 0, BRIGHTNESS_MODE_USER);
}
private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode);
}
}
2.1 JNI:
关于JNI调用HAL再调用Linux驱动的细节请参考我的博客:http://blog.youkuaiyun.com/hanp_linux/article/details/76590527
com_android_server_lights_LightsService.cpp
static JNINativeMethod method_table[] = {
{ "setLight_native", "(JIIIIII)V", (void*)setLight_native },
};
/* 从HAL获取hw_module_t结构体,在根据hw_module_t结构体获取一个battery对应的light_device_t结构体 */
hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
devices->lights[LIGHT_INDEX_BATTERY] = get_device(module, LIGHT_ID_BATTERY);
static void setLight_native(JNIEnv *env, jobject clazz, jlong ptr, jint light, jint colorARGB, jint flashMode, jint onMS, jint offMS, jint brightnessMode)
{
devices->lights[light]->set_light(devices->lights[light], &state);
}
2.2. HAL:
lights.c
if (0 == strcmp(LIGHT_ID_BATTERY, name)) {
/* 当充电时,低电量,中电量,和满分别让不同颜色的灯亮或者闪烁 */
set_light = set_light_battery;
}
static int set_light_battery (struct light_device_t *dev, struct light_state_t const* state) {
write_int (const char *path, int value) { //调用Linux底层驱动
fd = open(path, O_RDWR);
write (fd, buffer, bytes);
}
}
3 . mSystemServiceManager.startService(BatteryService.class);
此时,会调用BatteryService.java的onStart方法。
BatteryService.java
BatteryService的构造方法:
public BatteryService(Context context) {
mHandler = new Handler(true /*async*/);
/* 获取第2章分析注册的publishLocalService(LightsManager.class, mService);服务 */
mLed = new Led(context, getLocalService(LightsManager.class));
}
public Led(Context context, LightsManager lights) {
/* 获取一个电池灯,后面对电池灯的所以操作都是通过mBatteryLight来进行的 */
mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);
}
public void onStart() {
IBinder b = ServiceManager.getService("batteryproperties");
final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
IBatteryPropertiesRegistrar.Stub.asInterface(b);
/* 注册一个监听器监听电量的变化,电池的Linux驱动上报电池事件时调用batteryPropertiesChanged更新电池灯 */
batteryPropertiesRegistrar.registerListener(new BatteryListener());
publishBinderService("battery", new BinderService());
publishLocalService(BatteryManagerInternal.class, new LocalService());
}
private final class BatteryListener extends IBatteryPropertiesListener.Stub {
@Override
public void batteryPropertiesChanged(BatteryProperties props) {
final long identity = Binder.clearCallingIdentity();
BatteryService.this.update(props);
Binder.restoreCallingIdentity(identity);
}
}
private void update(BatteryProperties props) {
processValuesLocked(false);
}
private void processValuesLocked(boolean force) {
/* 发送广播ACTION_BATTERY_CHANGED,通知关心电池状态的进程,低电量提示,关机提示,状态栏图标等
* 接收广播请看 PowerManagerService.java的BatteryReceiver方法
*/
sendIntentLocked();
/* 同时更新电池灯的状态 -- 根据电量和是否在充电状态从而使闪灯或者红灯亮或黄灯亮等 */
mLed.updateLightsLocked();
}
private void sendIntentLocked() {
// Pack up the values and broadcast them to everyone
final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
mHandler.post(new Runnable() {
@Override
public void run() {
ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
}
});
}
public void updateLightsLocked() {
final int level = mBatteryProps.batteryLevel;
final int status = mBatteryProps.batteryStatus;
/* 如果电量低于警告值的话 */
if (level < mLowBatteryWarningLevel) {
/* 如果电量低于警告值,并且正在充电,则将电池灯设置为让低电量颜色的灯亮起,
如果没有在充电,则让低电量的灯闪烁 */
if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
mBatteryLight.setColor(mBatteryLowARGB);
} else {
mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED,
mBatteryLedOn, mBatteryLedOff);
}
/* 如何电量高于警告值,而且正在充电或者是满电状态,则根据电量选择让不同电量颜色的灯亮起 */
} else if (status == BatteryManager.BATTERY_STATUS_CHARGING || status ==
BatteryManager.BATTERY_STATUS_FULL) {
if (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90) {
mBatteryLight.setColor(mBatteryFullARGB);
} else {
mBatteryLight.setColor(mBatteryMediumARGB);
}
/* 如果以上状态都不是,则关闭电池灯 */
} else {
mBatteryLight.turnOff();
}
}