Bootstrap

Android灯光系统笔记

Android 底层与应用层之间的传递过程如下图
在这里插入图片描述
Andriod app(java)

这里表示的是一个应用程序,可以当做一个client(客户,即我们硬件访问服务器服务的对象),我们所做的一切,都是为了给client提供合适的java接口去控制硬件。当然,即使客户是上帝,也的遵循一定的规则。那么客户,需要遵循什么样的规则,才能达到他访问硬件的目的呢?
1.需要申请具体服务(getService),就好像你去酒店吃饭一样,你需要点菜,指定具体的菜名。只有菜单里存在的菜式才可以点
2.指令发送,你获得服务以后,就可以发送对硬件的操作指令了,可以申请打开或者关闭LED。类似于,上菜之后,客户可以用勺子挖着吃,也可以用筷子夹着吃。

service_manager.c

前面提到,客服get服务时,需要先查询服务,那么这些支持的服务都被罗列在哪里呢?andriod中应用了一个进程专门负责管理这些服务。可以理解为饭店的菜单,这个菜单上面有很多的菜式,service_manager(服务管理)管理着很多服务,如ledService,vibratorService,sendService等等。

SystemServer.java

饭店的菜单上的菜式有哪些呢?或者说这些菜式该怎么写呢?当然得看厨师会做什么菜,只有能做出来的菜,我们才能添加到菜单之中。我们的service_manager(服务管理)也是一样,他需要管理服务,但是他管理哪些服务,他又是怎么知道的,在andriod系统中,是通过SystemServer.java进行添加的,他会向service_manager注册服务,只有注册成功的service才能供顾客选择。这里的SystemServer.java可以理解为一个厨师总管,总管上报能做的菜式,图中的register_android_server——xxx类比如真正的厨师,可以真实提供对应的服务。

源码追踪

SDK/frameworks中的源码进行追踪。vibrator(震动器)进行讲解

该文件处于SDK/framework/sbase/services/java/com/android/server/SystemServer.java

public static void main(String[] args) {
    new SystemServer().run();
}

说明其会调用run()函数,在该函数中,可以找到如下代码

   System.loadLibrary("android_servers");

这里实质加载的是框图中的onload.cp, 那么onload.cpp做了什么我们继续查看源码:

......
register_android_server_ActivityManagerService(env);
register_android_server_PowerManagerService(env);
register_android_server_SerialService(env);
register_android_server_InputApplicationHandle(env);
register_android_server_VibratorService(env);
....

再查看下 register_android_server_VibratorService(env);

int register_android_server_VibratorService(JNIEnv *env)
{
    return jniRegisterNativeMethods(env, "com/android/server/VibratorService",
            method_table, NELEM(method_table));
}

向系统注册了 “com/android/server/VibratorService” 也是这里向系统提供了从C代码向JAVA代码提供哪些服务接口。

同时在run()函数里有如下代码

if(!isBox){
  	  traceBeginAndSlog("StartVibratorService");
	  vibrator = new VibratorService(context);
	  ServiceManager.addService("vibrator", vibrator);
	  Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}

首先new了一个VibratorService对象,然后通过ServiceManager.addService把该对象添加到ServiceManager中,让系统进程进行维护,我们右击VibratorService查看其定义,可以找到VibratorService.java文件,我们可以看到如下代码

native static boolean vibratorExists();
native static void vibratorInit();
native static void vibratorOn(long milliseconds);
native static void vibratorOff();

总结下:

static JNINativeMethod method_table[] = {
    { "init_native", "()J", (void*)init_native },
    { "finalize_native", "(J)V", (void*)finalize_native },
    { "setLight_native", "(JIIIIII)V", (void*)setLight_native },
};

int register_android_server_LightsService(JNIEnv *env)
{
    return jniRegisterNativeMethods(env, "com/android/server/lights/LightsService",
            method_table, NELEM(method_table));
}

JNI 层文件

1)承上则为JAVA层提供调用硬件控制的接口,比如上面代码的三个接口。
2)对下的话获取到HAL层提供的硬件module及设备个来为JAVA层真正的提供功能。

下面的代码通过匹配的 LIGHTS_HARDWARE_MODULE_ID 获取HAL层的LIGHTS 的module

err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);

再通过获取的module及设备定义的ID:LIGHT_ID_BACKLIGHT 来匹配相应的设备。并把其存到相依的lights功能数组里。

#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"
#define LIGHT_ID_BLUETOOTH         // "bluetooth"
#define LIGHT_ID_WIFI              // "wifi"
devices->lights[LIGHT_INDEX_BACKLIGHT]
                = get_device(module, LIGHT_ID_BACKLIGHT);

可以看到这里可以有多种设备,跟据名字来匹配。在HAL层可以提供多种的设备服务。

HAL层代码

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);
	if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) {
		set_light = set_light_backlight;
	}
	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 {
		return -EINVAL;
	}
	pthread_once (&g_init, init_globals);
	struct light_device_t *dev = malloc(sizeof (struct light_device_t));
	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;
}
static struct hw_module_methods_t lights_module_methods = {
	.open = open_lights,
};
struct hw_module_t HAL_MODULE_INFO_SYM = {
	.tag = HARDWARE_MODULE_TAG,
	.version_major = 1,
	.version_minor = 0,
	.id = LIGHTS_HARDWARE_MODULE_ID,
	.name = "GEC-3399 lights module",
	.author = "GEC-3399",
	.methods = &lights_module_methods,
};

从上面看看到JNI曾通过红色的ID来匹配module来获取HAL 层提供的Module结构体,而通过绿色的ID来匹配对应的device,获取对应device功能。

JAVA层代码

我们在手机上或是通过配置文件设置的数据值传递过程如下:

1)搜索config_notificationsBatteryLowARGB找到Config.xml文件中的

<!-- Default value for led color when battery is low on charge -->
<integer name="config_notificationsBatteryLowARGB">0xFFFF0000</integer>

2)android内部提供的机制,获取配置资源中的设置赋值给 mBatteryLowARGB这个JAVA变量

mBatteryLowARGB = context.getResources().getInteger(
         com.android.internal.R.integer.config_notificationsBatteryLowARGB);

3)可以看到 mBatteryLowARGB做给设置灯的参数使用,用来控制等的颜色。

public void updateLightsLocked() {
            final int level = mBatteryProps.batteryLevel; //获取当前电量
            /*获得电池的状态,由一下状态:正在充电,断开充电器,没有充电,满电等*/
            final int status = mBatteryProps.batteryStatus;
            /*如果电量少于设点的mLowBatteryWarningLevel*/
            if (level < mLowBatteryWarningLevel) {
            	//如果在进行充电
                if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
                    // Solid red when battery is charging
                    mBatteryLight.setColor(mBatteryLowARGB);
                } else {
                    // Flash red when battery is low and not charging
                    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) {
                    // Solid green when full or charging and nearly full
                    mBatteryLight.setColor(mBatteryFullARGB);
                } else {
                    // Solid orange when charging and halfway full
                    mBatteryLight.setColor(mBatteryMediumARGB);
                }
            } else {
                // No lights if not charging and not low
                mBatteryLight.turnOff();
            }
        }

4) 可以看到 mBatteryLight来正真设置灯的颜色,那么他是怎么获得到这种能力的呢。

mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);

通过在gtLight函数中传入参数:LightsManager.LIGHT_ID_BATTERY

在LightsManager中根据ID来匹配对应的设备,并提供该设备的功能。

;