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来匹配对应的设备,并提供该设备的功能。