转载于:http://www.cnblogs.com/skywang12345/p/3404808.html,内容有所修改,这篇vibrator源码是基于安卓7.1分析。

     系列:安卓硬件访问服务框架

安卓从零添加硬件服务实例(驱动到app调用)

目的是想和大家分享自己对Android系统的一点认识:以马达为代表,来考究“Android是如何一步步工作的。它从硬件设计,到Linux驱动,再到HAL,再到JNI,再到Framework,最后到被应用调用,这整套的流程到底是怎么样的!

Part 1 马达的硬件设计

马达的震动原理很简单,给马达通电,马达就能震动。至于马达是如何工作,如何将电能转化为机械能,这不是我们关心的重点。但是,我们要需要了解如何控制马达的通电。在硬件上,我们是通过一个IO口(GPIO)去控制;对于马达而言,我们可以将IO理解为一个开关。当开关合上时,马达震动;开关断开,马达停止震动。

GPIO(General Purpose Input Output),称为通用输入/输出。它可以被配置为中断、输入、输出等类型,从而对各个IO进行控制。对于马达而已,GPIO就相当于一个开关。下面看看硬件原理图中的马达部分,如下图:

注:上面原理图对应CPU是“三星A8”。不同平台的马达,马达的接法和GPIO都不一样;但原理都是类似的。

原理图中红线标注部分的含义:GPH3_3是马达的GPIO。三星A8中有很多组GPIO,而马达对应和GPH3_3连接。

Part 2 马达的驱动代码

知道马达的硬件设计之后,我们就可以进行Linux Driver开发工作,也就是编写马达的驱动。Linux的一个非常重要的特点,一切都是文件!而我们进行Linux Driver开发的目的,就是将硬件设备映射成一个文件;然后,我们可以通过操作文件,来操作对应的硬件设备。

OK!理解了驱动的作用和原理之后,我们接下来开发讲解马达的驱动开发。

1. Datasheet中相关信息

我们知道,马达是通过GPIO去控制;接下来,我们就是找到马达对应的GPIO信息,然后控制该GPIO即可。

通过马达的原理图,我们知道马达和GPH3_3相连接。我们查阅“三星A8 的Datasheet”,查找GPH3_3的相关信息。

三星A8的Datasheet中,关于GPH3_3的信息如下:

所谓Datasheet,就是CPU芯片的数据手册。
   上面记载了CPU的功能特性和操作方式等信息。任何一个厂家在发布它的芯片时,都会提供对应的Datasheet给它的客户;客户根据Datasheet上面所描述的CPU的特性,就可以进行相关的开发(当然,实际开发中可能还需要芯片厂商的支持)。例如,国内手机都是采用MTK平台,对于MTK方案开发商来说,它要开发MTK6577的产品。那么首先,MTK原厂会提供一份MTK6577的BSP包,BSP包中包括了MTK6577的Datasheet,也就是该芯片的数据手册。方案开发商有任何关于MTK6577的问题,都可以查阅该Datasheet。

说明

(01) GPH3_3对应CPU中的寄存器是GPH3CON[3]。

(02) [15:12] 表示寄存器的第12~15位,一个寄存器共32 bits。而第三列的 0000, 0001, 0010, 0011, 1111表示“寄存器取不同值的时候,该GPIO的功能”。

例如, 0000表示将该GPIO作为输入,0001表示将GPIO作为输出,1111表示将该GPIO作为中断。

前面,我们已经说过,操作马达就是相当与将它作为一个开关操作。因此,我们需要将马达的GPIO设为“输入”类型;然后输入1,相当于开启马达;输入0,则是关闭马达!

下面,我们需要做的就是在Driver中将GPH3_3(也就是GPH3CON[3])映射为一个文件节点,并将它配置为“输入”类型,即将GPH3CON[3]的寄存器值设为0000。

2. 马达的驱动

我们编写马达驱动(drivers/misc/misc_sysfs.c),将马达(vibrator)注册道platform总线上。源码如下:

 1 #include <linux/kernel.h>2 #include <linux/types.h>3 #include <linux/module.h>4 #include <linux/device.h>5 #include <linux/platform_device.h>6 #include <linux/delay.h>7 #include <linux/irq.h>8 #include <linux/interrupt.h>9 #include <linux/sysfs.h>10 #include <linux/input.h>11 #include <mach/gpio.h>12 13 // vibrator 对应的GPIO14 #define  VIBRATOR_POWER_PORT (S5PV210_GPH3(3))15 16 typedef struct combo_module__t    {17     unsigned char            status_vibrator;18 }    combo_module_t    ;19 20 static combo_module_t combo_module;21 22 /*23  * vibrator初始化函数:申请GPIO,并初始化vibrator状态。24  */25 static void combo_module_init(void)26 {27     if(gpio_request(VIBRATOR_POWER_PORT, "vibrator power"))    {28         printk("misc_sysfs.c request vibrator gpio failse.\n");29     }30     gpio_pull_updown(VIBRATOR_POWER_PORT, PullDisable);31       gpio_direction_output(VIBRATOR_POWER_PORT, GPIO_LOW);    32 33     combo_module.status_vibrator  = 0;34 }35 36 /*37  * vibrator控制函数38  */39 staticvoid combo_module_control(void)40 {41     if(combo_module.status_vibrator)42     {43         gpio_direction_output(VIBRATOR_POWER_PORT, GPIO_HIGH);44     }45     else    46     {47         gpio_direction_output(VIBRATOR_POWER_PORT, GPIO_LOW);48     }49 50 }51 52 53 ///54 55 static ssize_t show_vibrator_onoff (struct device *dev, struct device_attribute *attr, char *buf)56 {57     return    sprintf(buf, "%d\n", combo_module.status_vibrator);58 }59 60 static ssize_t set_vibrator_onoff (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)61 {62      unsigned int    val;63 64     if(!(sscanf(buf, "%u\n", &val)))     return    -EINVAL;65 66     //printk("set_vibrator_onoff:%d\n",val);67 68     if(!val )    69     {70         combo_module.status_vibrator = 0;71         combo_module_control();72     }73     else        74     {75         combo_module.status_vibrator = 1;76         combo_module_control();77 78         msleep(val);79 80         combo_module.status_vibrator = 0;81         combo_module_control();82     }83     84     return count;85 }86 87 static    ssize_t show_vibrator_onoff    (struct device *dev, struct device_attribute *attr, char *buf);88 static     ssize_t set_vibrator_onoff    (struct device *dev, struct device_attribute *attr, const char *buf, size_t count);89 // 将vibrator注册到sysfs文件系统。90 // 参数说明:91 //       vibrator_onoff      : vibrator对应在sysfs下的文件节点名称92 //       S_IRWXUGO           : 文件节点的属性93 //       show_vibrator_onoff : 对应的读函数94 //       set_vibrator_onoff  : 对应的写函数95 static DEVICE_ATTR(vibrator_onoff, S_IRWXUGO, show_vibrator_onoff, set_vibrator_onoff);96 97 98 static struct attribute *control_sysfs_entries[] = {99     &dev_attr_vibrator_onoff.attr,
100     NULL
101 };
102
103 static struct attribute_group control_sysfs_attr_group = {
104     .name   = NULL,
105     .attrs  = control_sysfs_entries,
106 };
107
108 static int control_sysfs_probe(struct platform_device *pdev)
109 {
110     printk("vibrator probe");
111     combo_module_init();
112     combo_module_control();
113     return    sysfs_create_group(&pdev->dev.kobj, &control_sysfs_attr_group);
114 }
115
116 staticint control_sysfs_remove(struct platform_device *pdev)
117 {
118     sysfs_remove_group(&pdev->dev.kobj, &control_sysfs_attr_group);
119
120     return    0;
121 }
122
123 #ifdef CONFIG_PM
124 static int control_sysfs_resume(struct platform_device *dev)
125 {
126
127     combo_module_control();
128
129     return  0;
130 }
131
132 static int control_sysfs_suspend(struct platform_device *dev, pm_message_t state)
133 {
134
135     combo_module_control();
136
137     return  0;
138 }
139 #else
140 #define control_sysfs_suspend NULL
141 #define control_sysfs_resume NULL
142 #endif
143
144
145 static struct platform_driver control_sysfs_driver = {
146     .driver = {
147         .name = "misc_ctl",
148         .owner = THIS_MODULE,
149     },
150     .probe         = control_sysfs_probe,
151     .remove     = control_sysfs_remove,
152     .suspend    = control_sysfs_suspend,
153     .resume        = control_sysfs_resume,
154 };
155
156 static int __init control_sysfs_init(void)
157 {
158     // 将vibrator注册到platform总线
159     printk("vibrator init");
160     return platform_driver_register(&control_sysfs_driver);
161 }
162
163 static void __exit control_sysfs_exit(void)
164 {
165    platform_driver_unregister(&control_sysfs_driver);
166 }
167
168
169 module_init(control_sysfs_init);
170 module_exit(control_sysfs_exit);
171
172
173 MODULE_DESCRIPTION("misc control driver");
174 MODULE_AUTHOR("other");
175 MODULE_LICENSE("GPL");

说明

若您熟悉驱动开发,应该很容易理解上面的代码。不熟悉也不要紧,您只需要了解“Linux系统中,一切都是文件”,上面代码的作用是,将马达(vibrator)映射到“/sys/devices/platform/misc_ctl/vibrator_onoff”文件上,我们可以通过读写vibrator_onoff来操作马达的开启和关闭。

有了马达的源码之后,我们还需要将该源码编译到Linux内核中。这就是通过Kconfig和Makefile来完成的,关于Kconfig和Makefile的知识,这里就不过多说明了。目前您只需要了解,通过Kconfig和Makefile,我们能将马达驱动编译到内核中,该驱动会在驱动加载的时候自动运行就可以了!

马达对应的Kconfig(driver/misc/Kconfig)内容如下:

config MISC_VIBRATORtristate"misc vabrator"default y

马达对应的Makefile(driver/misc/Makefile)内容如下:

obj-$(CONFIG_MISC_VIBRATOR)   += misc_sysfs.o

至此,我们已经完成马达的驱动开发了!也就是说,我们已经成功的将马达映射到文件节点上;接下来,我们通过操作文件节点,就可以操作马达了。下面从HAL层到Framework曾,基于Android7.1系统进行分析的。(设备节点:/sys/class/timed_output/vibrator/enable)

Part 3 马达的HAL实现

HAL (Hardware Abstraction Layer), 又称为“硬件抽象层”。在Linux驱动中,我们已经将马达设为映射为文件了;而该HAL层的存在的意义,就是“对设备文件进行操作,从而相当于硬件进行操作”。HAL层的作用,一是操作硬件设备,二是操作接口封装,外界能方便的使用HAL提供的接口直接操作硬件设备。

理解了HAL之后,我们看看Android中如何在HAL层对马达进行操作。

在Android系统中,我们在libhardware_legacy中,实现马达的HAL层控制。
马达在HAL中的代码路径:hardware/libhardware/modules/vibrator/vibrator.c

头文件:hardware/libhardware/include/hardware/vibrator.h

vibrator.c的代码如下:

/** Copyright (C) 2013 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/#include <hardware/vibrator.h>
#include <hardware/hardware.h>#include <cutils/log.h>#include <malloc.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <math.h>static const char THE_DEVICE[] = "/sys/devices/platform/misc_ctl/vibrator_onoff";static int vibra_exists() {int fd;fd = TEMP_FAILURE_RETRY(open(THE_DEVICE, O_RDWR));if(fd < 0) {ALOGE("Vibrator file does not exist : %d", fd);return 0;}close(fd);return 1;
}static int sendit(unsigned int timeout_ms)
{int to_write, written, ret, fd;char value[20]; /* large enough for millions of years */fd = TEMP_FAILURE_RETRY(open(THE_DEVICE, O_RDWR));if(fd < 0) {return -errno;}to_write = snprintf(value, sizeof(value), "%u\n", timeout_ms);written = TEMP_FAILURE_RETRY(write(fd, value, to_write));if (written == -1) {ret = -errno;} else if (written != to_write) {/* even though EAGAIN is an errno value that could be setby write() in some cases, none of them apply here.  So, this returnvalue can be clearly identified when debugging and suggests thecaller that it may try to call vibraror_on() again */ret = -EAGAIN;} else {ret = 0;}errno = 0;close(fd);return ret;
}static int vibra_on(vibrator_device_t* vibradev __unused, unsigned int timeout_ms)
{/* constant on, up to maximum allowed time */return sendit(timeout_ms);
}static int vibra_off(vibrator_device_t* vibradev __unused)
{return sendit(0);
}static int vibra_close(hw_device_t *device)
{free(device);return 0;
}static int vibra_open(const hw_module_t* module, const char* id __unused,hw_device_t** device __unused) {if (!vibra_exists()) {ALOGE("Vibrator device does not exist. Cannot start vibrator");return -ENODEV;}vibrator_device_t *vibradev = calloc(1, sizeof(vibrator_device_t));if (!vibradev) {ALOGE("Can not allocate memory for the vibrator device");return -ENOMEM;}vibradev->common.tag = HARDWARE_DEVICE_TAG;vibradev->common.module = (hw_module_t *) module;vibradev->common.version = HARDWARE_DEVICE_API_VERSION(1,0);vibradev->common.close = vibra_close;vibradev->vibrator_on = vibra_on;vibradev->vibrator_off = vibra_off;*device = (hw_device_t *) vibradev;return 0;
}/*===========================================================================*/
/* Default vibrator HW module interface definition                           */
/*===========================================================================*/static struct hw_module_methods_t vibrator_module_methods = {.open = vibra_open,
};struct hw_module_t HAL_MODULE_INFO_SYM = {.tag = HARDWARE_MODULE_TAG,.module_api_version = VIBRATOR_API_VERSION,.hal_api_version = HARDWARE_HAL_API_VERSION,.id = VIBRATOR_HARDWARE_MODULE_ID,.name = "Default vibrator HAL",.author = "The Android Open Source Project",.methods = &vibrator_module_methods,
};

在kernel的驱动中,我们已经将马达注册到sys文件系统中(/sys/devices/platform/misc_ctl/vibrator_onoff)。在vibrator.c中,我们就是通过读写“vibrator_onoff文件节点”来实现对马达的操作。

Part 4 马达的JNI部分

1 马达的JNI实现

JNI(Java Native Interface),中文是“Java本地接口”。

JNI是Java中一种技术,它存在的意义,是保证本地代码(C/C++代码)能在任何Java虚拟机下工作。简单点说,Java通过JNI接口,能够调用到C/C++代码。 关于“JNI的更多内容”,请参考“Android JNI和NDK学习系列文章”。

在了解了vibrator的HAL层实现之后,我们再来看看android是如何通过JNI将震动马达注册到android系统中。马达对应的JNI层代码路径如下:frameworks/base/services/core/jni/com_android_server_VibratorService.cpp

com_android_server_VibratorService.cpp的源码如下:

/** Copyright (C) 2009 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/#define LOG_TAG "VibratorService"#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/vibrator.h>#include <stdio.h>namespace android
{static hw_module_t *gVibraModule = NULL;
static vibrator_device_t *gVibraDevice = NULL;static void vibratorInit(JNIEnv /* env */, jobject /* clazz */)
{if (gVibraModule != NULL) {return;}int err = hw_get_module(VIBRATOR_HARDWARE_MODULE_ID, (hw_module_t const**)&gVibraModule);if (err) {ALOGE("Couldn't load %s module (%s)", VIBRATOR_HARDWARE_MODULE_ID, strerror(-err));} else {if (gVibraModule) {vibrator_open(gVibraModule, &gVibraDevice);}}
}static jboolean vibratorExists(JNIEnv* /* env */, jobject /* clazz */)
{if (gVibraModule && gVibraDevice) {return JNI_TRUE;} else {return JNI_FALSE;}
}static void vibratorOn(JNIEnv* /* env */, jobject /* clazz */, jlong timeout_ms)
{if (gVibraDevice) {int err = gVibraDevice->vibrator_on(gVibraDevice, timeout_ms);if (err != 0) {ALOGE("The hw module failed in vibrator_on: %s", strerror(-err));}} else {ALOGW("Tried to vibrate but there is no vibrator device.");}
}static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */)
{if (gVibraDevice) {int err = gVibraDevice->vibrator_off(gVibraDevice);if (err != 0) {ALOGE("The hw module failed in vibrator_off(): %s", strerror(-err));}} else {ALOGW("Tried to stop vibrating but there is no vibrator device.");}
}static const JNINativeMethod method_table[] = {{ "vibratorExists", "()Z", (void*)vibratorExists },{ "vibratorInit", "()V", (void*)vibratorInit },{ "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));
}};

下面,对这部分的JNI代码进行简单说明。

(01) 通过 jniRegisterNativeMethods(),我们将method_table中的方法注册到 com.android.server.VibratorService.java 中。配对表格如下:

​
---------------------------------------------------++++-------------------------------------------VibratorService.java                          com_android_server_VibratorService.cpp
native static boolean vibratorExists();                static jboolean vibratorExists(JNIEnv *env, jobject clazz)
native static void vibratorInit();                      static void vibratorInit(JNIEnv /* env */, jobject /* clazz */)
native static void vibratorOn(long milliseconds);      static void vibratorOn(JNIEnv *env, jobject clazz, jlong timeout_ms)
native static void vibratorOff();                      static void vibratorOff(JNIEnv *env, jobject clazz)​

通过JNI,我们就能将Java层和HAL层的代码联系起来。
以vibratorOff()来说,我们在VibratorService.java中调用vibratorOff();实际上会调用到com_android_server_VibratorService.cpp中的vibratorOff()函数;进一步会调用到vibrator_off()函数,而vibrator_off()是我们在 “HAL层的vibrator.c中的接口”。

2 马达的JNI如何和HAL关联方式

在继续接下来的研究之前,我们先搞清楚:JNI如何和HAL层代码关联起来的。即com_android_server_VibratorService.cpp是如何调用到vibrator.c中的代码的。
实际上道理很简单,我们先将vibrator.c封装成.so库;然后在com_android_server_VibratorService.cpp中导入该库,就可以调用vibrator.c的接口了。下面,看看Android中具体是如何做到的。

(01) vibrator.c封装到vibrator.default.so中的步骤

在hardware/libhardware/modules/vibrator/Android.mk中,会将vibrator.c添加到 LOCAL_SRC_FILES 变量中。
hardware/libhardware_legacy/vibrator/Android.mk源码如下:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := vibrator.default# HAL module implementation stored in
# hw/<VIBRATOR_HARDWARE_MODULE_ID>.default.so
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_C_INCLUDES := hardware/libhardware
LOCAL_SRC_FILES := vibrator.c
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_MODULE_TAGS := optionalinclude $(BUILD_SHARED_LIBRARY)

在“我们编译Android系统”或“通过 mmm hardware/libhardware/modules/vibrator/进行模块编译”的时候,就会生成库vibrator.default.so;而且vibrator.c被包含在该库中。

(02) 在 com_android_server_VibratorService.cpp 对应的Android.mk中,会导入vibrator.default.so。
com_android_server_VibratorService.cpp 对应的frameworks/base/services/core/jni/Android.mk的源码如下:

LOCAL_SRC_FILES += \$(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \

Part 5 马达的Framework层实现

应用层操作马达,是通过马达服务进行操作的。而马达服务是通过aidl实现的,aidl是Android进程间的通信方式。关于aidl的更多说明可以参考“Android Service总结06 之AIDL”。

马达服务涉及的主要文件如下:

​
1 frameworks/base/services/java/com/android/server/SystemServer.java
2 frameworks/base/services/core/java/com/android/server/VibratorService.java
3 frameworks/base/core/java/android/os/IVibratorService.aidl
4 frameworks/base/core/java/android/os/Vibrator.java
5 frameworks/base/core/java/android/os/SystemVibrator.java​

下面,对这几个文件的功能进行简要说明。

文件1: SystemServer.java
           它是系统服务,作用是启动、管理系统服务,包括“马达服务、Wifi服务、Activity管理服务”等等。
           SystemServer是通过Zygote启动的,而Zygote又是在init中启动的,init则是kernel加载完毕之后启动的第一个进程。在这里,我们只需要知道“SystemServer是用来启动/管理马达服务即可。”

文件2: IVibratorService.aidl
           它是马达服务对应的aidl配置文件。我们在aidl中定义了其它进程可以访问的外部接口;然后再通过VibratorService.java实现这些接口。

文件3: VibratorService.java
           它是马达服务对应的aidl接口的实现程序。它实现IVibratorService.aidl的接口,从而实现马达服务;它的函数接口,是通过调用JNI层对应的马达控制函数来实现的。

文件4: Vibrator.java
           它是马达服务开放给应用层的调用类。理论上讲,我们完全可以通过aidl直接调用马达服务,而不需要Vibrator.java类。但是!既然它存在,就肯定有它的理由。事实的确如此,Google之所以这么做。有以下几个原因:
           第一,提供统一而且方便的服务调用方式。这里的“统一”,是指和所有其它的系统服务一样,我们调用服务时,需先通过getSystemService()获取服务,然后再调用服务的函数接口。这里的“方便”,是指若我们直接通过aidl调用,操作比较繁琐(若你用过aidl就会知道,需要先实现ServiceConnection接口以获取IBinder对象,然后再通过IBinder对象调用aidl的接口); 而Vibrator.java封装之后的接口,将许多细节都隐藏了,非常便于应用者调用!
          第二,基于安全的考虑。Vibrator.java封装隐藏了许多细节,而这些都是应用开发者不必要知道的。
          第三,Vibrator是抽象类。它便于我们支持不同类型的马达:包括“将马达直接映射到文件”以及“将马达注册到输入子系统”中。

文件5: SystemVibrator.java
         它是Vibrator.java的子类,实现了马达的服务接口。

下面,我们继续Read The Fucking Source Code,加深对上面知识的理解。

1 SystemServer.java

在frameworks/base/services/java/com/android/server/SystemServer.java中关于马达的代码如下:

1 {2     VibratorService vibrator = null;3 4     Slog.i(TAG, "Vibrator Service");5     vibrator = new VibratorService(context);6     ServiceManager.addService("vibrator", vibrator);7 8     ...9
10     try {
11         vibrator.systemReady();
12     } catch (Throwable e) {
13         reportWtf("making Vibrator Service ready", e);
14     }
15 }

从中,我们知道:
(01) SystemServer中会通过VibratorService()新建马达服务,并将其添加到ServiceManager中。
(02) 在Android系统启动完成之后,SystemServer会调用vibrator.systemReady()。

2 IVibratorService.aidl

在查看VibratorService.java之前,我们先看看它对应的aidl文件。frameworks/base/core/java/android/os/IVibratorService.aidl源码如下:

package android.os;/** {@hide} */
interface IVibratorService
{boolean hasVibrator();void vibrate(int uid, String opPkg, long milliseconds, int usageHint, IBinder token);void vibratePattern(int uid, String opPkg, in long[] pattern, int repeat, int usageHint, IBinder token);void cancelVibrate(IBinder token);
}

3 VibratorService.java

frameworks/base/services/java/com/android/server/VibratorService.java源码如下:

package com.android.server;public class VibratorService extends IVibratorService.Stubimplements InputManager.InputDeviceListener {......native static boolean vibratorExists();native static void vibratorOn(long milliseconds);native static void vibratorOff();......

其中,VibratorService实际上是通过“本地方法”去控制马达的。例如,hasVibratora()最终是通过vibratorExists()来判断马达是否存在的。

4 Vibrator.java

frameworks/base/core/java/android/os/Vibrator.java源码如下:

package android.os;
import android.app.ActivityThread;
import android.content.Context;
import android.media.AudioAttributes;
public abstract class Vibrator {private final String mPackageName;public Vibrator() {mPackageName = ActivityThread.currentPackageName();}protected Vibrator(Context context) {mPackageName = context.getOpPackageName();}public abstract boolean hasVibrator();public void vibrate(long milliseconds) {vibrate(milliseconds, null);}public void vibrate(long milliseconds, AudioAttributes attributes) {vibrate(Process.myUid(), mPackageName, milliseconds, attributes);}public void vibrate(long[] pattern, int repeat) {vibrate(pattern, repeat, null);}public void vibrate(long[] pattern, int repeat, AudioAttributes attributes) {vibrate(Process.myUid(), mPackageName, pattern, repeat, attributes);}public abstract void vibrate(int uid, String opPkg, long milliseconds,AudioAttributes attributes);public abstract void vibrate(int uid, String opPkg, long[] pattern, int repeat,AudioAttributes attributes);public abstract void cancel();
}

5 SystemVibrator.java

frameworks/base/core/java/android/os/SystemVibrator.java源码如下:

package android.os;import android.content.Context;
import android.media.AudioAttributes;
import android.util.Log;/*** Vibrator implementation that controls the main system vibrator.** @hide*/
public class SystemVibrator extends Vibrator {private static final String TAG = "Vibrator";private final IVibratorService mService;private final Binder mToken = new Binder();public SystemVibrator() {mService = IVibratorService.Stub.asInterface(ServiceManager.getService("vibrator"));}public SystemVibrator(Context context) {super(context);mService = IVibratorService.Stub.asInterface(ServiceManager.getService("vibrator"));}@Overridepublic boolean hasVibrator() {if (mService == null) {Log.w(TAG, "Failed to vibrate; no vibrator service.");return false;}try {return mService.hasVibrator();} catch (RemoteException e) {}return false;}/*** @hide*/@Overridepublic void vibrate(int uid, String opPkg, long milliseconds, AudioAttributes attributes) {if (mService == null) {Log.w(TAG, "Failed to vibrate; no vibrator service.");return;}try {mService.vibrate(uid, opPkg, milliseconds, usageForAttributes(attributes), mToken);} catch (RemoteException e) {Log.w(TAG, "Failed to vibrate.", e);}}/*** @hide*/@Overridepublic void vibrate(int uid, String opPkg, long[] pattern, int repeat,AudioAttributes attributes) {if (mService == null) {Log.w(TAG, "Failed to vibrate; no vibrator service.");return;}// catch this here because the server will do nothing.  pattern may// not be null, let that be checked, because the server will drop it// anywayif (repeat < pattern.length) {try {mService.vibratePattern(uid, opPkg, pattern, repeat, usageForAttributes(attributes),mToken);} catch (RemoteException e) {Log.w(TAG, "Failed to vibrate.", e);}} else {throw new ArrayIndexOutOfBoundsException();}}private static int usageForAttributes(AudioAttributes attributes) {return attributes != null ? attributes.getUsage() : AudioAttributes.USAGE_UNKNOWN;}@Overridepublic void cancel() {if (mService == null) {return;}try {mService.cancelVibrate(mToken);} catch (RemoteException e) {Log.w(TAG, "Failed to cancel vibration.", e);}}
}

说明
(01) 在构造函数SystemVibrator()中,我们通过 IVibratorService.Stub.asInterface(ServiceManager.getService("vibrator")) 获取马达服务,实际上获取的是VibratorService对象。
(02) SystemVibrator的接口都是调用VibratorService接口实现的。

在讲解“应用层如何通过getSystemService(VIBRATOR_SERVICE)获取马达服务,然后进一步的操作马达”之前,我们先看看应用层的马达操作示例!

Part 6 马达的应用示例

1 权限

调用马达服务,需要在manifest中添加相应的权限:

<!-- 震动马达权限 -->
<uses-permission android:name="android.permission.VIBRATE"/>

2 源码

源码如下:

1 package com.test;2 3 import android.app.Activity;4 import android.os.Bundle;5 import android.os.Vibrator;6 import android.view.View;7 import android.view.View.OnClickListener;8 import android.widget.Button;9 import android.widget.ToggleButton;
10 import android.util.Log;
11
12 public class VibratorTest extends Activity {
13     private static final String TAG = "skywang-->VibratorTest";
14
15     private Vibrator mVibrator;
16     private Button mOnce = null;
17     private ToggleButton mEndless = null;
18
19     @Override
20     protected void onCreate(Bundle savedInstanceState) {
21         super.onCreate(savedInstanceState);
22         setContentView(R.layout.main);
23
24         // 获取震动马达服务
25         mVibrator= (Vibrator) getSystemService(VIBRATOR_SERVICE);
26
27         mOnce = (Button) findViewById(R.id.vib_once);
28         mOnce.setOnClickListener(new View.OnClickListener() {
29
30             @Override
31             public void onClick(View view) {
32                 //震动指定时间
33                 mVibrator.vibrate(100);
34             }
35         });
36
37         mEndless = (ToggleButton) findViewById(R.id.vib_endless);
38         mEndless.setOnClickListener(new OnClickListener() {
39             @Override
40             public void onClick(View v) {
41                 if (mEndless.isChecked()) {
42                     //等待100ms后,按数组所给数值间隔震动;其后为重复次数,-1为不重复,0一直震动
43                     mVibrator.vibrate(new long[]{100,20,100,40,100,60}, 0);
44                 } else {
45                     // 取消震动
46                     mVibrator.cancel();
47                 }
48             }
49         });
50
51     }
52
53     @Override
54     protected void onStop() {
55         super.onStop();
56         if (mVibrator != null)
57             mVibrator= null;
58     }
59 }

点击下载:Android马达应用代码

Part 7 马达的应用如何调用到马达服务的

接下来,我们分析一下如何获取马达服务的:即 mVibrator= (Vibrator) getSystemService(VIBRATOR_SERVICE) 的工作原理。

1. Context.java中的getSystemService()

getSystemService()定义在frameworks/base/core/java/android/content/Context.java中,源码如下:

​
public abstract Object getSystemService(String name);​
public static final String VIBRATOR_SERVICE = "vibrator";

Context.java中的getSystemService() 是个抽象方法,它的实现在ContextImpl.java中。

2. ContextImpl.java中的getSystemService()

frameworks/base/core/java/android/app/ContextImpl.java中的 getSystemService() 源码如下:

  @Overridepublic Object getSystemService(String name) {return SystemServiceRegistry.getSystemService(this, name);}

3.  SystemServiceRegistry.java的getSystemService(ContextImpl ctx, String name)

frameworks/base/core/java/android/app/SystemServiceRegistry.java的源码如下:

  public static Object getSystemService(ContextImpl ctx, String name) {ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);return fetcher != null ? fetcher.getService(ctx) : null;}

4. SystemServiceRegistry.java中的SYSTEM_SERVICE_FETCHERS

SYSTEM_SERVICE_FETCHERS是一个HashMap对象,它的相关代码如下:

​
private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =new HashMap<String, ServiceFetcher<?>>();SYSTEM_SERVICE_FETCHERS 的初始化,是在SystemServiceRegistry.java通过static静态模块完成的。源码如下:
static {...// 注册“传感器服务”registerService(Context.SENSOR_SERVICE, SensorManager.class,new CachedServiceFetcher<SensorManager>() {@Overridepublic SensorManager createService(ContextImpl ctx) {return new SystemSensorManager(ctx.getOuterContext(),ctx.mMainThread.getHandler().getLooper());}});// 注册其它服务 ...// 注册马达服务registerService(Context.VIBRATOR_SERVICE, Vibrator.class,new CachedServiceFetcher<Vibrator>() {@Overridepublic Vibrator createService(ContextImpl ctx) {return new SystemVibrator(ctx);}});...}​

说明:在上面的static静态模块中,会通过registerService()注册一系列的服务,包括马达服务。注册服务是通过registerService()实现的,下面我们看看registerService()的定义。

private static <T> void registerService(String serviceName, Class<T> serviceClass,ServiceFetcher<T> serviceFetcher) {SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);}

从中,我们知道,在registerService()中,会通过 SYSTEM_SERVICE_FETCHERS.put(serviceName, fetcher) 将serviceName和fetcher添加到哈希表SYSTEM_SERVICE_FETCHERS中。
    对马达服务而言,添加到哈希表SYSTEM_SERVICE_FETCHERS中的key-value中的key是VIBRATOR_SERVICEvalue则是ServiceFetcher对象;而且该匿名ServiceFetcher对象的createService()方法会“通过new SystemVibrator()”返回SystemVibrator对象。而SystemVibrator我们在前面已经介绍过了,它是马达服务对外提供接口的类。

OK,接着往下看。

我们已经知道SYSTEM_SERVICE_FETCHERS是哈希表,通过SYSTEM_SERVICE_FETCHERS.get(name)返回的是ServiceFetcher对象。由于fetcher不为null,所以,getSystemService()会返回fetcher.getService(this)。我们看看ServiceFetcher中getService()源码:

    static abstract interface ServiceFetcher<T> {T getService(ContextImpl ctx);}/*** Override this class when the system service constructor needs a* ContextImpl and should be cached and retained by that context.*/static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {private final int mCacheIndex;public CachedServiceFetcher() {mCacheIndex = sServiceCacheSize++;}@Override@SuppressWarnings("unchecked")public final T getService(ContextImpl ctx) {final Object[] cache = ctx.mServiceCache;synchronized (cache) {// Fetch or create the service.Object service = cache[mCacheIndex];if (service == null) {service = createService(ctx);cache[mCacheIndex] = service;}return (T)service;}}public abstract T createService(ContextImpl ctx);}

从中,我们发现,getService()实际上返回的是“通过createService(ctx)创建的service对象”。
而在registerService()注册马达服务时,我们匿名实现了createService()方法:它实际上是通过 new SystemVibrator() 返回SystemVibrator对象。

至此,我们知道:getSystemService(VIBRATOR_SERVICE) 返回的是 SystemVibrator对象!SystemVibrator前面已经分析过,这里就不再说明了。

8. 震动器hal层到app源文件目录及重要代码:

hal:hardware/libhardware/modules/vibrator/vibrator.chardware/libhardware/include/hardware/vibrator.h./lib64/hw/vibrator.default.so
JNI:frameworks/base/services/core/jni/com_android_server_VibratorService.cppjniRegisterNativeMethods(env, "com/android/server/VibratorService",method_table, NELEM(method_table));frameworks/base/services/core/jni/onload.cppregister_android_server_VibratorService(env);framework:  frameworks/base/core/java/android/os/IVibratorService.aidlinterface IVibratorService{boolean hasVibrator();void vibrate(int uid, String opPkg, long milliseconds, int usageHint, IBinder token);void vibratePattern(int uid, String opPkg, in long[] pattern, int repeat, int usageHint, IBinder token);void cancelVibrate(IBinder token);}//震动器实际操作类,服务,通过JNI调用com_android_server_VibratorService中函数frameworks/base/services/core/java/com/android/server/VibratorService.javaVibratorService extends IVibratorService.Stubnative static boolean vibratorExists();native static void vibratorInit();native static void vibratorOn(long milliseconds);native static void vibratorOff();frameworks/base/services/java/com/android/server/SystemServer.javavibrator = new VibratorService(context);ServiceManager.addService("vibrator", vibrator);vibrator.systemReady();//这两个类client使用:frameworks/base/core/java/android/os/Vibrator.javaframeworks/base/core/java/android/os/SystemVibrator.javaSystemVibrator extends VibratorIVibratorService mService = IVibratorService.Stub.asInterface(ServiceManager.getService("vibrator"));app:Vibrator mVibrator= (Vibrator) getSystemService(VIBRATOR_SERVICE)frameworks/base/core/java/android/content/Context.javapublic abstract Object getSystemService(String name);frameworks/base/core/java/android/app/ContextImpl.java(在这个类里实现)public Object getSystemService(String name) {return SystemServiceRegistry.getSystemService(this, name);}frameworks/base/core/java/android/app/SystemServiceRegistry.javaregisterService(Context.VIBRATOR_SERVICE, Vibrator.class,new CachedServiceFetcher<Vibrator>() {@Overridepublic Vibrator createService(ContextImpl ctx) {return new SystemVibrator(ctx);}});public static Object getSystemService(ContextImpl ctx, String name) {ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);return fetcher != null ? fetcher.getService(ctx) : null;}最后返回SystemVibrator对象。

Q:  自己在源码里添加的硬件服务,eclipse或者android studio编写测试app时,需要把源码编译生成的classes.jar包导入项目或者把app源码直接放入源码编译。源码编译完成会生成许多classes.jar。我们要导入的classes.jar路径为:out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar

Android硬件服务框架实例之Vibrator(驱动到应用)相关推荐

  1. android+硬件服务,android之硬件访问服务框架

    一.硬件接口描述文件aidl 新增\frameworks\base\core\java\android\os\ILedService.aidl 二.mk编译脚本 修改vi frameworks/bas ...

  2. Android Google 服务框架相关问题

    为什么80%的码农都做不了架构师?>>>    两年没发文了~ 先说现象: 1.定制 ROM,打包时在 /system/priv-app 目录下添加了谷歌服务框架相关 apk(Gms ...

  3. android google服务框架安装

    安装google服务框架和卸载google框架 游戏无法运行?闪退?国行ROM导致Gameloft的游戏全坑爹?据说是因为没有安装"google play"和"谷歌服务框 ...

  4. Android硬件加速原理与实现

    一 概述 在手机客户端尤其是 Android 应用开发过程中,我们经常会接触到"硬件加速"这个概念.由于操作系统对底层软硬件封装非常完善,上层软件开发者往往对硬件加速的底层原理了解 ...

  5. Android系统硬件访问服务框架分析

    怎么实现硬件访问服务 1.JNI和HAL com_andorid_server_ledService.cpp (JNI文件注册JNI本地方法:供app应用程序调用) hal_led.c (C库:具体操 ...

  6. 嵌入式Android底层开发(三)硬件访问服务框架

    一.简单的Android应用程序调用硬件流程图(通过JNI接口直接访问) 但这样存在一个很大的问题:访问仅限与单一程序进行访问,如果多个APP同时访问一个硬件资源(多个APP都需要在LCD进行显示.多 ...

  7. andriod驱动之旅-在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务(8)

    我们在Android系统增加硬件服务的目的是为了让应用层的APP能够通过Java接口来访问硬件服务.那么, APP如何通过Java接口来访问Application Frameworks层提供的硬件服务 ...

  8. 基于spi接口的oled屏Android服务框架

    上一篇写了一个oled驱动,那么现在有一个问题:apk要怎么使用这个硬件,这里就需要提供一个硬件服务,apk通过这个服务就可以操作到硬件了. 基于rk3288 Android5.1 Android的硬 ...

  9. ubuntu java android_Ubuntu中为Android系统实现内置Java应用程序测试Application Frameworks层的硬件服务...

    我们在Android系统增加硬件服务的目的是为了让应用层的APP能够通过Java接口来访问硬件服务.那么, APP如何通过Java接口来访问Application Frameworks层提供的硬件服务 ...

最新文章

  1. BCELoss BCEWithLogitsLoss 多标签损失函数
  2. Intel HAXM is required to run this AVD VT-x is disabled in BIOS的处理方法
  3. asp.net开发中自定义网站的目录
  4. python代码块所属关系的语法-天元高校邦数据科学通识课【Python基础语法】答案...
  5. ASP.NET 访问共享文件夹
  6. ubuntu 中vi的使用方法
  7. Java try语句的嵌套
  8. 30个数据可视化超级工具_Python5个数据可视化工具
  9. 如何快速定位SAP CRM订单应用(Order Application)错误消息抛出的准确位置
  10. 图谱实战 | 徐美兰:深度应用驱动的医学知识图谱构建
  11. 吸猫就吸Tomcat之Pipeline-Valve巧妙设计
  12. 主板找不到SSD解决一例
  13. 通信原理ami码c语言实现,通信原理AMI码型变换实验
  14. 一些实用的小网站、小工具、软件
  15. DUL 更新2016
  16. python中if in是什么意思_if语句中“ in”的使用和含义?
  17. 一休哥的PowerBI学习之路-可控的视觉筛选器
  18. Shell 打印空行的行号/去掉空行
  19. 【SoapUI】SoapUI工具简介及安装
  20. 小程序统一服务消息_小程序客服消息接入微信教程

热门文章

  1. lab1-1 恶意代码分析实战
  2. 表单onbeforepaste事件(知识拓展)
  3. 【githubshare】人脸转漫画数据集face2comics,好玩又NFT
  4. ATDD,TDD,BDD的区别
  5. 跟小米、特斯拉分“蛋糕”的优必选要IPO
  6. kicad最小布线宽度默认是多少_智能家居装修布线详解
  7. 八股文之深拷贝和浅拷贝
  8. BIOS密码清除方法
  9. 如何用vr虚拟现实技术做线上数字展厅?
  10. MonkeyRunner 使用教程(基础教程)