最近手里的xt897 震动坏了。
正好重温一下Android的Service机制和Hal实现,把震动变为LED闪烁。
11月19日:
首先找到震动打调用方法:
vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
long[] pattern = {800, 50, 400, 30}; // OFF/ON/OFF/ON...
vibrator.vibrate(pattern, 2);
VibratorService.java 在 frameworks/base/services/java/com/android/server/VibratorService.java
里面是关于震动调用打一些业务逻辑
最终会调用到
native static boolean vibratorExists();
native static void vibratorOn(long milliseconds);
native static void vibratorOff();
因为最后只是为了适配我的手机。所以怎么方便怎么改来。
如果修改VibratorService.java 要编译Android系统 显然比较麻烦。
修改native只需要编译内核。
------------JNI层----------------------------
对应的native函数在
android/frameworks/base/services/jni/
com_android_server_VibratorService.cpp
查看Android.mk ,这个需要学习一下Android.mk语法
这里的文件最终会生成libandroid_servers.so
jni层的vibratorOff 实现:
static void vibratorOn(JNIEnv *env, jobject clazz, jlong timeout_ms)
{
// LOGI("vibratorOn\n");
vibrator_on(timeout_ms);
}
vibrator_on 是Hal层的函数
-----------Hal层------------------------
目录:$A10_ANDROID_SRC_PATH/hardware/lighardware_legacy/
<vibrator/Android.mk>:
# Copyright 2006 The Android Open Source Project
LOCAL_SRC_FILES += vibrator/vibrator.c
<Android.mk>:
#这个文件有好几个Local_module 不过这个才是我们关心的
LOCAL_MODULE:= libhardware_legacy
输出:
ls /disk1/sources/cyanogenmod/source_cm11/out/target/product/xt897/system/lib/libhardware_legacy.so
实现:
static int sendit(int timeout_ms)
{
int nwr, ret, fd;
char value[20];
#ifdef QEMU_HARDWARE
if (qemu_check()) {
return qemu_control_command( "vibrator:%d", timeout_ms );
}
#endif
fd = open(THE_DEVICE, O_RDWR);
if(fd < 0)
return errno;
nwr = sprintf(value, "%d\n", timeout_ms);
ret = write(fd, value, nwr);
close(fd);
return (ret == nwr) ? 0 : -1;
}
int vibrator_on(int timeout_ms)
{
/* constant on, up to maximum allowed time */
return sendit(timeout_ms);
}
THE_DEVICE 即
#define THE_DEVICE "/sys/class/timed_output/sun4i-vibrator/enable"
想要在Hal层修改为闪烁LED 还得看LED的实现:
jni:
com_android_server_LightsService.cpp
msm8960 lights hal :
/disk1/sources/cyanogenmod/source_cm11/hardware/qcom/display/msm8960/liblight/
lights.c
不用看实现函数,看开头的几个宏就知道怎么回事了:
char const*const RED_LED_FILE
= "/sys/class/leds/red/brightness";
char const*const GREEN_LED_FILE
= "/sys/class/leds/green/brightness";
char const*const BLUE_LED_FILE
= "/sys/class/leds/blue/brightness";
char const*const WHITE_LED_FILE
= "/sys/class/leds/white/brightness";
char const*const LCD_FILE
= "/sys/class/leds/lcd-backlight/brightness";
char const*const LED_FREQ_FILE
= "/sys/class/leds/%s/device/grpfreq";
char const*const LED_PWM_FILE
= "/sys/class/leds/%s/device/grppwm";
char const*const LED_BLINK_FILE
= "/sys/class/leds/%s/device/blink";
char const*const LED_LOCK_UPDATE_FILE
= "/sys/class/leds/%s/device/lock";
搜一下RED_LED_FILE
if (rgb) {
write_int(RED_LED_FILE, (colorRGB >> 16) & 0xFF);
write_int(GREEN_LED_FILE, (colorRGB >> 8) & 0xFF);
write_int(BLUE_LED_FILE, colorRGB & 0xFF);
}
使用adb shell
echo 255 > /sys/class/leds/red/brightness
确实能亮。
那就直接回到vibrator.c 改吧:
添加 :
char const*const RED_LED_FILE
= "/sys/class/leds/red/brightness";
char const*const GREEN_LED_FILE
= "/sys/class/leds/green/brightness";
char const*const BLUE_LED_FILE
= "/sys/class/leds/blue/brightness";
char const*const BLINK_VALUE = "255";
static int write_max(int fd)
{
int ret = write(fd,BLINK_VALUE,strlen(BLINK_VALUE));
return ret;
}
static int lights_reset(int fdr,int fd_g,int fd_b){
int ret;
ret = write(fdr,"0",strlen("0"));
ret = write(fd_g,"0",strlen("0"));
ret = write(fd_b,"0",strlen("0"));
return ret;
}
#define INTERVAL 200
static int sendit(int timeout_ms){
int fd_r,fd_g,fd_b,ret,i,cur_time_ms = 0,mod,div;
fd_r = open(RED_LED_FILE,O_RDWR);
fd_g = open(GREEN_LED_FILE,O_RDWR);
fd_b = open(BLUE_LED_FILE,O_RDWR);
ret = fd_r<0?-1:(fd_g<0?-1:fd_b<0?-1:0);
if((fd_r<0)||(fd_g<0)||(fd_b<0))
return -1;
if(timeout_ms < INTERVAL){
write_max(fd_r);
write_max(fd_g);
write_max(fd_b);
for(i=0;i<timeout_ms;i++)
usleep(1000);
lights_reset(fd_r,fd_g,fd_b);
printf("!!!!timeout_ms is %d\n",timeout_ms);
return 0;
}
while(cur_time_ms<timeout_ms){
if(cur_time_ms%INTERVAL==0)
{// call once in INTERVAL ms;
div = cur_time_ms/INTERVAL;
mod = div%3;
lights_reset(fd_r,fd_g,fd_b);
if(mod==0)
write_max(fd_r);
else if(mod == 1)
write_max(fd_g);
else if(mod==2)
write_max(fd_b);
}
usleep(1000);
cur_time_ms++;
}
return 0;
}
然后
source build/envsetup.sh
breakfast xt897
cd /disk1/sources/cyanogenmod/source_cm11/hardware/libhardware_legacy
mm
[root@ libhardware_legacy]# adb push /disk1/sources/cyanogenmod/source_cm11/out/target/product/xt897/obj/lib/libhardware_legacy.so /sdcard/
[root@ libhardware_legacy]# adb shell
shell@asanti_c:/ $ su
root@asanti_c:/ # cat /sdcard/remount.sh 2>&0|sh
root@asanti_c:/ # cp /sdcard/lib
libhardware_legacy.so libs/
root@asanti_c:/ # cp /sdcard/libhardware_legacy.so /system/lib
即可.
威信设置的震动时间200ms,所以小于200ms的干脆让它常亮得了。
done