振动器负责控制引动电话的振动功能,Android中的振动器系统是一个专供这方面功能的小系统,提供根据时间振动的功能。
  振动器系统包含了驱动程序、硬件抽象层、JNI部分、Java框架类等几个部分,也向Java应用程序层提供了简单的API作为平台接口。

  Android振动器系统的基本层次结构如图所示。


振动器部分的结构



  Android振动器系统自下而上包含了驱动程序、振动器系统硬件抽象层、振动器系统Java框架类、Java框架中振动器系统使用等几个部分,其结构如图所示。



自下而上,Android的振动器系统分成了以下部分。


  (1)驱动程序:特定硬件平台振动器的驱动程序,通常基于Android的Timed Output驱动框架实现
  (2)硬件抽象层
  光系统硬件抽象层接口路径为:hardware/libhardware_legacy/include/hardware_legacy/ vibrator.h
  振动器系统的硬件抽象层在Android中已经具有默认实现,代码路径:
  hardware/libhardware_legacy/vibrator/vibrator.c
  振动器的硬件抽象层通常并不需要重新实现,是libhardware_legacy.so的一部分。
  (3)JNI部分
  代码路径:frameworks/base/services/jni/com_android_server_VibratorService.cpp
  这个类是振动器的JNI部分,通过调用硬件抽象层向上层提供接口。
  (4)Java部分
  代码路径:
  frameworks/base/services/java/com/android/server/VibratorService.java
  frameworks/base/core/java/android/os/Vibrator.java

  VibratorService.java通过调用,VibratorService JNI来实现com.android.server包中的VibratorService类。这个类不是平台的API,被Android系统Java框架中的一小部分调用。

  Vibrator.java文件实现了android.os包中的Vibrator类,这是向Java层提供的API。


移植内容


  针对特定的硬件平台,振动器系统的移植有两种方法。
  第一种方法(通常情况):由于已经具有硬件抽象层,振动器系统的移植只需要实现驱动程序即可。这个驱动程序需要基于Android内核中的Timed Output驱动框架。
  第二种方法:根据自己实现的驱动程序,重新实现振动器的硬件抽象层定义接口(需要在libhardware_legacy.so库中),由于振动器硬件抽象层的接口非常简单,因此这种实现方式也不会很复杂。

驱动程序

  Vibrator的驱动程序只需要实现振动的接口即可,这是一个输出设备,需要接受振动时间作为参数。由于比较简单,因此Vibrator的驱动程序可以使用多种方式来实现。
  在Android中,推荐基于Android内核定义Timed Output驱动程序框架来实现Vibrator的驱动程序。
  Timed Output的含义为定时输出,用于定时发出某个输出。实际上,这种驱动程序依然是基于sys文件系统来完成的。
  drivers/staging/android/目录timed_output.h中定义timed_output_dev结构体,其中包含enable和get_time这两个函数指针,实现结构体后,使用timed_output_dev_register()和timed_output_dev_unregister()函数注册和注销即可。
  Timed Output驱动程序框架将为每个设备在/sys/class/timed_output/目录中建立一个子目录,设备子目录中的enable文件就是设备的控制文件。读enable文件表示获得剩余时间,写这个文件表示根据时间振动。
  Timed Output驱动的设备调试,通过sys文件系统即可。
  对于Vibrator设备,其实现的Timed Output驱动程序的名称应该为“vibrator”。因此Vibrator设备在sys文件系统中的方法如下所示:

Java代码:
# echo "10000" > /sys/class/timed_output/vibrator/enable

# cat /sys/class/timed_output/vibrator/enable

3290

# echo "0" > /sys/class/timed_output/vibrator/enable
复制代码 对于enable文件,“写”表示使能指定的时间,“读”表示获取剩余时间。

硬件抽象层的内容

  1.硬件抽象层的接口
  Vibrator硬件抽象层的接口在hardware/libhardware_legacy/include/hardware_legacy/目录的vibrator.h文件中定义:

Java代码:
int vibrator_on(int timeout_ms); // 开始振动

int vibrator_off(); // 关闭振动
复制代码
vibrator.h文件中定义两个接口,分别表示振动和关闭,振动开始以毫秒(ms)作为时间单位。  提示:Timed Output类型驱动本身有获得剩余时间的能力(读enable文件),但是在Android Vibrator硬件抽象层以上的各层接口都没有使用这个功能。

  2.标准硬件抽象层的实现
  Vibrator硬件抽象层具有标准的实现,在hardware/libhardware_legacy/vibrator/目录的vibrator.c中。
  其中实现的核心内容为sendit()函数,这个函数的内容如下所示:

Java代码:#define THE_DEVICE "/sys/class/timed_output/vibrator/enable"

static int sendit(int timeout_ms){

int nwr, ret, fd;

char value[20];

#ifdef QEMU_HARDWARE // 使用QEMU的情况

if (qemu_check()) {

return qemu_control_command( "vibrator:%d", timeout_ms );

}

#endif

fd = open(THE_DEVICE, O_RDWR); // 读取sys文件系统中的内容

nwr = sprintf(value, "%d\n", timeout_ms);

ret = write(fd, value, nwr);

close(fd);

return (ret == nwr) ? 0 : -1;



}
复制代码
sendit()函数负责根据时间“振动”:在真实的硬件中,通过sys文件系统的文件进行控制;如果是模拟器环境则通过QEMU发送命令。  vibrator_on()调用sendit()以时间作为参数,vibrator_on()调用sendit()以0作为参数。

  上层的情况和注意事项
  frameworks/base/services/jni/目录中的com_android_server_VibratorService.cpp文件是Vibrator硬件抽象层的调用者,它同时也向Java提供JNI支持。

  其中,为JNI定义的方法列表如下所示:

Java代码:
static JNINativeMethod method_table[] = {

{ "vibratorOn", "(J)V", (void*)vibratorOn }, // 振动器开

{ "vibratorOff", "()V", (void*)vibratorOff } // 振动器关

};

int register_android_server_VibratorService(JNIEnv *env) {

return jniRegisterNativeMethods(env, "com/android/server/VibratorService",

method_table, NELEM(method_table));

}





//vibratorOn()和vibratorOff()这两个函数的实现分别如下所示:

static void vibratorOn(JNIEnv *env, jobject clazz, jlong timeout_ms){

vibrator_on(timeout_ms);

}

static void vibratorOff(JNIEnv *env, jobject clazz){

vibrator_off();

}
复制代码
frameworks/base/services/java/com/android/server/目录中的VibratorService.java通过调用VibratorService JNI来实现com.android.server包中的VibratorService类。  frameworks/base/core/java/android/os/目录中的Vibrator.java文件实现了android.os包中的Vibrator类。它通过调用vibrator的Java服务来实现(获得名称为vibrator的服务),配合同目录中的IVibratorService.aidl文件向应用程序层提供Vibrator的相关API。
  MSM的mahimahi平台中Vibrator实现是基于Timed Output驱动程序框架的驱动程序,因此不需要再实现硬件抽象层。
  Vibrator的驱动程序在内核的arch/arm/mach-msm/目录中的msm_vibrator.c文件中实现。

  msm_vibrator.c中的核心实现是set_pmic_vibrator()函数,其实现内容如下所示:

Java代码:
static void set_pmic_vibrator(int on){

static struct msm_rpc_endpoint vib_endpoint; /* 定义RPC的端点 */

struct set_vib_on_off_req {

struct rpc_request_hdr hdr;

uint32_t data;

}

req;

if (!vib_endpoint) {

vib_endpoint = msm_rpc_connect(PM_LIBPROG, PM_LIBVERS, 0);

/* ...... 省略部分内容 */

}

if (on)

req.data = cpu_to_be32(PMIC_VIBRATOR_LEVEL); /* 得到请求时间 */

else

req.data = cpu_to_be32(0);



msm_rpc_call(vib_endpoint, HTC_PROCEDURE_SET_VIB_ON_OFF, &req,

sizeof(req), 5 * HZ); /* 进行RPC调用 */

}
复制代码
set_pmic_vibrator()函数通过MSM系统的远程过程调用(RPC)实现了具体的功能,调用的指令由HTC_PROCEDURE_SET_VIB_ON_OFF指定。 
 这个驱动程序的初始化过程如下所示:

Java代码:

void __init msm_init_pmic_vibrator(void){

INIT_WORK(&vibrator_work, update_vibrator); /* 建立消息队列 */

spin_lock_init(&vibe_lock);

vibe_state = 0;

hrtimer_init(&vibe_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); /* 定时器 */

vibe_timer.function = vibrator_timer_func;

timed_output_dev_register(&pmic_vibrator); /* 注册timed_output_dev设备 */

}
复制代码
vibrator_work为work_struct类型,在队列的执行函数update_vibrator中,调用set_pmic_vibrator()函数。  pmic_vibrator是一个timed_output_dev类型的设备。其enable函数指针的实现vibrator_enable根据输入的数值开始定时器,并通过向调度队列进行输出操作。get_time函数指针的实现vibrator_get_time则只是从定时器中获取剩余时间。
  这里之所以使用定时器加队列的方式,是因为enable的调用将形成一个持续时间的效果,但是调用本身不宜阻塞,因此实现就让vibrator_enable函数退出后,通过定时器实现效果。

更多相关文章

  1. 浅谈Java中Collections.sort对List排序的两种方法
  2. python list.sort()根据多个关键字排序的方法实现
  3. 自定义控件及效果
  4. android jni
  5. Android(安卓)Accessibility(辅助功能) --实现Android应用自动安
  6. Android客户端与PC服务器实现Socket通信
  7. Android中“分享”功能的实现
  8. Android(安卓)轻松实现语音朗读
  9. android log

随机推荐

  1. Android属性动画完全解析(一)
  2. Android Uri转换成真实File路径
  3. Android(安卓)Surfaceflinger 的使用
  4. 【Android】SQLite数据库的简单使用
  5. Android自定义AlertDialog实现
  6. android仿滴滴司机端滑动接到乘客,送达乘
  7. Android 获取MIEI ISMI Sim卡串号等等信
  8. Migrating Your Android App from Eclips
  9. android launch 初探
  10. Android短信转发默认不需要转发号码修改