Android之 看“马达”如何贯通Android系统 (从硬件设计 --> 驱动 --> HAL --> JNI --> Framework --> Application)

摘要:
在Android2.3(Gingerbread)系统的时候,我写过一篇关于“Android震动马达系统“的文章,当时的Linux内核还是2.6版本的。写那篇文章的目的,是想彻底的了解从硬件到驱动,再到应用的运作流程。完成了之后,文章一直仍在草稿箱里面没发表;今天看到,决定整理一下,重新发表。目的是想和大家分享自己对Android系统的一点认识:以马达为代表,来考究“Android是如何一步步工作的

在Android 2.3(Gingerbread) 系统的时候,我写过一篇关于“Android 震动马达系统“的文章,当时的Linux内核还是2.6版本的。写那篇文章的目的,是想彻底的了解从硬件到驱动,再到应用的运作流程。完成了之后,文章一直仍在草稿箱里面没发表;今天看到,决定整理一下,重新发表。目的是想和大家分享自己对Android系统的一点认识:以马达为代表,来考究“Android是如何一步步工作的。它从硬件设计,到Linux驱动,再到HAL,再到JNI,再到Framework,最后到被应用调用,这整套的流程到底是怎么样的!

转载请注明出处:http://www.cnblogs.com/skywang12345/p/3404808.html

Part 1 马达的硬件设计

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

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

Android之 看“马达”如何贯通Android系统 (从硬件设计 --> 驱动 --> HAL --> JNI --> Framework --> Application)第1张

注:上面原理图对应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的相关信息。

所谓Datasheet,就是CPU芯片的数据手册。
   上面记载了CPU的功能特性和操作方式等信息。任何一个厂家在发布它的芯片时,都会提供对应的Datasheet给它的客户;客户根据Datasheet上面所描述的CPU的特性,就可以进行相关的开发(当然,实际开发中可能还需要芯片厂商的支持)。例如,国内手机都是采用MTK平台,对于MTK方案开发商来说,它要开发MTK6577的产品。那么首先,MTK原厂会提供一份MTK6577的BSP包,BSP包中包括了MTK6577的Datasheet,也就是该芯片的数据手册。方案开发商有任何关于MTK6577的问题,都可以查阅该Datasheet。
三星A8的Datasheet中,关于GPH3_3的信息如下:
Android之 看“马达”如何贯通Android系统 (从硬件设计 --> 驱动 --> HAL --> JNI --> Framework --> Application)第2张

说明

(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 对应的GPIO
14 #define  VIBRATOR_POWER_PORT (S5PV210_GPH3(3))
15 
16 typedef structcombo_module__t    {
17     unsigned charstatus_vibrator;
18 }    combo_module_t    ;
19 
20 staticcombo_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.
");
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
", 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 intval;
63 
64     if(!(sscanf(buf, "%u
", &val)))     return    -EINVAL;
65 
66     //printk("set_vibrator_onoff:%d
",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     returncount;
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 staticDEVICE_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");
View Code

说明

若您熟悉驱动开发,应该很容易理解上面的代码。不熟悉也不要紧,您只需要了解“Linux系统中,一切都是文件”,上面代码的作用是,

将马达(vibrator)映射到“/sys/devices/platform/misc_ctl/vibrator_onoff”文件上,我们可以通过读写vibrator_onoff来操作马达的开启和关闭。

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

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

config MISC_VIBRATOR
       tristate"misc vabrator"
       default y

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

obj-$(CONFIG_MISC_VIBRATOR)   += misc_sysfs.o

至此,我们已经完成马达的驱动开发了!也就是说,我们已经成功的将马达映射到文件节点上;接下来,我们通过操作文件节点,就可以操作马达了。下面从HAL层到Framework曾,都是基于Android4.2系统进行说明的。

Part 3 马达的HAL实现

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

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

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

vibrator.c的代码如下:

1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15  */
16 #include <hardware_legacy/vibrator.h>
17 #include "qemu.h"
18 
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 
24 #define THE_DEVICE "/sys/devices/platform/misc_ctl/vibrator_onoff"
25 
26 intvibrator_exists()
27 {
28     intfd;
29 
30 #ifdef QEMU_HARDWARE
31     if(qemu_check()) {
32         return 1;
33 }
34 #endif
35 
36     fd =open(THE_DEVICE, O_RDWR);
37     if(fd < 0)
38         return 0;
39 close(fd);
40     return 1;
41 }
42 
43 static int sendit(inttimeout_ms)
44 {
45     intnwr, ret, fd;
46     char value[20];
47 
48 #ifdef QEMU_HARDWARE
49     if(qemu_check()) {
50         return qemu_control_command( "vibrator:%d", timeout_ms );
51 }
52 #endif
53 
54     fd =open(THE_DEVICE, O_RDWR);
55     if(fd < 0)
56         returnerrno;
57 
58     nwr = sprintf(value, "%d
", timeout_ms);
59     ret =write(fd, value, nwr);
60 
61 close(fd);
62 
63     return (ret == nwr) ? 0 : -1;
64 }
65 
66 int vibrator_on(inttimeout_ms)
67 {
68     /*constant on, up to maximum allowed time */
69     returnsendit(timeout_ms);
70 }
71 
72 intvibrator_off()
73 {
74     return sendit(0);
75 }
View Code

在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/jni/com_android_server_VibratorService.cpp

com_android_server_VibratorService.cpp的源码如下:

1 /*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15  */
16 
17 #define LOG_TAG "VibratorService"
18 
19 #include "jni.h"
20 #include "JNIHelp.h"
21 #include "android_runtime/AndroidRuntime.h"
22 
23 #include <utils/misc.h>
24 #include <utils/Log.h>
25 #include <hardware_legacy/vibrator.h>
26 
27 #include <stdio.h>
28 
29 namespaceandroid
30 {
31 
32 static jboolean vibratorExists(JNIEnv *env, jobject clazz)
33 {
34     return vibrator_exists() > 0 ?JNI_TRUE : JNI_FALSE;
35 }
36 
37 static void vibratorOn(JNIEnv *env, jobject clazz, jlong timeout_ms)
38 {
39     //ALOGI("vibratorOn
");
40 vibrator_on(timeout_ms);
41 }
42 
43 static void vibratorOff(JNIEnv *env, jobject clazz)
44 {
45     //ALOGI("vibratorOff
");
46 vibrator_off();
47 }
48 
49 static JNINativeMethod method_table[] ={
50     { "vibratorExists", "()Z", (void*)vibratorExists },
51     { "vibratorOn", "(J)V", (void*)vibratorOn },
52     { "vibratorOff", "()V", (void*)vibratorOff }
53 };
54 
55 int register_android_server_VibratorService(JNIEnv *env)
56 {
57     return jniRegisterNativeMethods(env, "com/android/server/VibratorService",
58 method_table, NELEM(method_table));
59 }
60 
61 };
View Code

下面,对这部分的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 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封装到libhardware_legacy.so中的步骤

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

LOCAL_SRC_FILES += vibrator/vibrator.c

在hardware/libhardware_legacy/Android.mk中,它会调用子目录的Android.mk并将它们导入当前的Android.mk中。
hardware/libhardware_legacy/Android.mk源码如下:

legacy_modules :=power uevent vibrator wifi qemu qemu_tracing
SAVE_MAKEFILES := $(call all-named-subdir-makefiles,$(legacy_modules))
LEGACY_AUDIO_MAKEFILES := $(call all-named-subdir-makefiles,audio)
include $(SAVE_MAKEFILES)
...
LOCAL_MODULE:=libhardware_legacy
include $(BUILD_SHARED_LIBRARY)

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

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

LOCAL_SRC_FILES:= 
com_android_server_VibratorService.cpp 
...
LOCAL_SHARED_LIBRARIES := 
libhardware_legacy 
...
LOCAL_MODULE:= libandroid_servers
include $(BUILD_SHARED_LIBRARY)

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/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 = newVibratorService(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源码如下:

1 packageandroid.os;
2 
3 /**{@hide} */
4 interfaceIVibratorService
5 {
6     booleanhasVibrator();
7     void vibrate(longmilliseconds, IBinder token);
8     void vibratePattern(in long[] pattern, intrepeat, IBinder token);
9     voidcancelVibrate(IBinder token);
10 }

3 VibratorService.java

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

1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15  */
16 
17 packagecom.android.server;
18 
19 importandroid.content.BroadcastReceiver;
20 importandroid.content.Context;
21 importandroid.content.Intent;
22 importandroid.content.IntentFilter;
23 importandroid.content.pm.PackageManager;
24 importandroid.database.ContentObserver;
25 importandroid.hardware.input.InputManager;
26 importandroid.os.Handler;
27 importandroid.os.IVibratorService;
28 importandroid.os.PowerManager;
29 importandroid.os.Process;
30 importandroid.os.RemoteException;
31 importandroid.os.IBinder;
32 importandroid.os.Binder;
33 importandroid.os.SystemClock;
34 importandroid.os.UserHandle;
35 importandroid.os.Vibrator;
36 importandroid.os.WorkSource;
37 importandroid.provider.Settings;
38 importandroid.provider.Settings.SettingNotFoundException;
39 importandroid.util.Slog;
40 importandroid.view.InputDevice;
41 
42 importjava.util.ArrayList;
43 importjava.util.LinkedList;
44 importjava.util.ListIterator;
45 
46 public class VibratorService extendsIVibratorService.Stub
47         implementsInputManager.InputDeviceListener {
48     private static final String TAG = "VibratorService";
49 
50     private final LinkedList<Vibration>mVibrations;
51     privateVibration mCurrentVibration;
52     private final WorkSource mTmpWorkSource = newWorkSource();
53     private final Handler mH = newHandler();
54 
55     private finalContext mContext;
56     private finalPowerManager.WakeLock mWakeLock;
57     privateInputManager mIm;
58 
59     volatileVibrateThread mThread;
60 
61     //mInputDeviceVibrators lock should be acquired after mVibrations lock, if both are
62     //to be acquired
63     private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
64     private boolean mVibrateInputDevicesSetting; //guarded by mInputDeviceVibrators
65     private boolean mInputDeviceListenerRegistered; //guarded by mInputDeviceVibrators
66 
67     native static booleanvibratorExists();
68     native static void vibratorOn(longmilliseconds);
69     native static voidvibratorOff();
70 
71     private class Vibration implementsIBinder.DeathRecipient {
72         private finalIBinder mToken;
73         private final longmTimeout;
74         private final longmStartTime;
75         private final long[]  mPattern;
76         private final intmRepeat;
77         private final intmUid;
78 
79         Vibration(IBinder token, long millis, intuid) {
80             this(token, millis, null, 0, uid);
81 }
82 
83         Vibration(IBinder token, long[] pattern, int repeat, intuid) {
84             this(token, 0, pattern, repeat, uid);
85 }
86 
87         private Vibration(IBinder token, long millis, long[] pattern,
88                 int repeat, intuid) {
89             mToken =token;
90             mTimeout =millis;
91             mStartTime =SystemClock.uptimeMillis();
92             mPattern =pattern;
93             mRepeat =repeat;
94             mUid =uid;
95 }
96 
97         public voidbinderDied() {
98             synchronized(mVibrations) {
99                 mVibrations.remove(this);
100                 if (this ==mCurrentVibration) {
101 doCancelVibrateLocked();
102 startNextVibrationLocked();
103 }
104 }
105 }
106 
107         public boolean hasLongerTimeout(longmillis) {
108             if (mTimeout == 0) {
109                 //This is a pattern, return false to play the simple
110                 //vibration.
111                 return false;
112 }
113             if ((mStartTime +mTimeout)
114                     < (SystemClock.uptimeMillis() +millis)) {
115                 //If this vibration will end before the time passed in, let
116                 //the new vibration play.
117                 return false;
118 }
119             return true;
120 }
121 }
122 
123 VibratorService(Context context) {
124         //Reset the hardware to a default state, in case this is a runtime
125         //restart instead of a fresh boot.
126 vibratorOff();
127 
128         mContext =context;
129         PowerManager pm =(PowerManager)context.getSystemService(
130 Context.POWER_SERVICE);
131         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
132         mWakeLock.setReferenceCounted(true);
133 
134         mVibrations = new LinkedList<Vibration>();
135 
136         IntentFilter filter = newIntentFilter();
137 filter.addAction(Intent.ACTION_SCREEN_OFF);
138 context.registerReceiver(mIntentReceiver, filter);
139 }
140 
141     public voidsystemReady() {
142         mIm =(InputManager)mContext.getSystemService(Context.INPUT_SERVICE);
143 
144 mContext.getContentResolver().registerContentObserver(
145                 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES), true,
146                 newContentObserver(mH) {
147 @Override
148                     public void onChange(booleanselfChange) {
149 updateInputDeviceVibrators();
150 }
151 }, UserHandle.USER_ALL);
152 
153         mContext.registerReceiver(newBroadcastReceiver() {
154 @Override
155             public voidonReceive(Context context, Intent intent) {
156 updateInputDeviceVibrators();
157 }
158         }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
159 
160 updateInputDeviceVibrators();
161 }
162 
163     public booleanhasVibrator() {
164         returndoVibratorExists();
165 }
166 
167     public void vibrate(longmilliseconds, IBinder token) {
168         if(mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
169                 !=PackageManager.PERMISSION_GRANTED) {
170             throw new SecurityException("Requires VIBRATE permission");
171 }
172         int uid =Binder.getCallingUid();
173         //We're running in the system server so we cannot crash. Check for a
174         //timeout of 0 or negative. This will ensure that a vibration has
175         //either a timeout of > 0 or a non-null pattern.
176         if (milliseconds <= 0 || (mCurrentVibration != null
177                 &&mCurrentVibration.hasLongerTimeout(milliseconds))) {
178             //Ignore this vibration since the current vibration will play for
179             //longer than milliseconds.
180             return;
181 }
182 
183         Vibration vib = newVibration(token, milliseconds, uid);
184         synchronized(mVibrations) {
185 removeVibrationLocked(token);
186 doCancelVibrateLocked();
187             mCurrentVibration =vib;
188 startVibrationLocked(vib);
189 }
190 }
191 
192     private boolean isAll0(long[] pattern) {
193         int N =pattern.length;
194         for (int i = 0; i < N; i++) {
195             if (pattern[i] != 0) {
196                 return false;
197 }
198 }
199         return true;
200 }
201 
202     public void vibratePattern(long[] pattern, intrepeat, IBinder token) {
203         if(mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
204                 !=PackageManager.PERMISSION_GRANTED) {
205             throw new SecurityException("Requires VIBRATE permission");
206 }
207         int uid =Binder.getCallingUid();
208         //so wakelock calls will succeed
209         long identity =Binder.clearCallingIdentity();
210         try{
211             if (false) {
212                 String s = "";
213                 int N =pattern.length;
214                 for (int i=0; i<N; i++) {
215                     s += " " +pattern[i];
216 }
217                 Slog.i(TAG, "vibrating with pattern: " +s);
218 }
219 
220             //we're running in the server so we can't fail
221             if (pattern == null || pattern.length == 0
222                     ||isAll0(pattern)
223                     || repeat >= pattern.length || token == null) {
224                 return;
225 }
226 
227             Vibration vib = newVibration(token, pattern, repeat, uid);
228             try{
229                 token.linkToDeath(vib, 0);
230             } catch(RemoteException e) {
231                 return;
232 }
233 
234             synchronized(mVibrations) {
235 removeVibrationLocked(token);
236 doCancelVibrateLocked();
237                 if (repeat >= 0) {
238 mVibrations.addFirst(vib);
239 startNextVibrationLocked();
240                 } else{
241                     //A negative repeat means that this pattern is not meant
242                     //to repeat. Treat it like a simple vibration.
243                     mCurrentVibration =vib;
244 startVibrationLocked(vib);
245 }
246 }
247 }
248         finally{
249 Binder.restoreCallingIdentity(identity);
250 }
251 }
252 
253     public voidcancelVibrate(IBinder token) {
254 mContext.enforceCallingOrSelfPermission(
255 android.Manifest.permission.VIBRATE,
256                 "cancelVibrate");
257 
258         //so wakelock calls will succeed
259         long identity =Binder.clearCallingIdentity();
260         try{
261             synchronized(mVibrations) {
262                 final Vibration vib =removeVibrationLocked(token);
263                 if (vib ==mCurrentVibration) {
264 doCancelVibrateLocked();
265 startNextVibrationLocked();
266 }
267 }
268 }
269         finally{
270 Binder.restoreCallingIdentity(identity);
271 }
272 }
273 
274     private final Runnable mVibrationRunnable = newRunnable() {
275         public voidrun() {
276             synchronized(mVibrations) {
277 doCancelVibrateLocked();
278 startNextVibrationLocked();
279 }
280 }
281 };
282 
283     //Lock held on mVibrations
284     private voiddoCancelVibrateLocked() {
285         if (mThread != null) {
286             synchronized(mThread) {
287                 mThread.mDone = true;
288 mThread.notify();
289 }
290             mThread = null;
291 }
292 doVibratorOff();
293 mH.removeCallbacks(mVibrationRunnable);
294 }
295 
296     //Lock held on mVibrations
297     private voidstartNextVibrationLocked() {
298         if (mVibrations.size() <= 0) {
299             mCurrentVibration = null;
300             return;
301 }
302         mCurrentVibration =mVibrations.getFirst();
303 startVibrationLocked(mCurrentVibration);
304 }
305 
306     //Lock held on mVibrations
307     private void startVibrationLocked(finalVibration vib) {
308         if (vib.mTimeout != 0) {
309 doVibratorOn(vib.mTimeout);
310 mH.postDelayed(mVibrationRunnable, vib.mTimeout);
311         } else{
312             //mThread better be null here. doCancelVibrate should always be
313             //called before startNextVibrationLocked or startVibrationLocked.
314             mThread = newVibrateThread(vib);
315 mThread.start();
316 }
317 }
318 
319     //Lock held on mVibrations
320     privateVibration removeVibrationLocked(IBinder token) {
321         ListIterator<Vibration> iter = mVibrations.listIterator(0);
322         while(iter.hasNext()) {
323             Vibration vib =iter.next();
324             if (vib.mToken ==token) {
325 iter.remove();
326 unlinkVibration(vib);
327                 returnvib;
328 }
329 }
330         //We might be looking for a simple vibration which is only stored in
331         //mCurrentVibration.
332         if (mCurrentVibration != null && mCurrentVibration.mToken ==token) {
333 unlinkVibration(mCurrentVibration);
334             returnmCurrentVibration;
335 }
336         return null;
337 }
338 
339     private voidunlinkVibration(Vibration vib) {
340         if (vib.mPattern != null) {
341             //If Vibration object has a pattern,
342             //the Vibration object has also been linkedToDeath.
343             vib.mToken.unlinkToDeath(vib, 0);
344 }
345 }
346 
347     private voidupdateInputDeviceVibrators() {
348         synchronized(mVibrations) {
349 doCancelVibrateLocked();
350 
351             synchronized(mInputDeviceVibrators) {
352                 mVibrateInputDevicesSetting = false;
353                 try{
354                     mVibrateInputDevicesSetting =Settings.System.getIntForUser(
355 mContext.getContentResolver(),
356                             Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
357                 } catch(SettingNotFoundException snfe) {
358 }
359 
360                 if(mVibrateInputDevicesSetting) {
361                     if (!mInputDeviceListenerRegistered) {
362                         mInputDeviceListenerRegistered = true;
363                         mIm.registerInputDeviceListener(this, mH);
364 }
365                 } else{
366                     if(mInputDeviceListenerRegistered) {
367                         mInputDeviceListenerRegistered = false;
368                         mIm.unregisterInputDeviceListener(this);
369 }
370 }
371 
372 mInputDeviceVibrators.clear();
373                 if(mVibrateInputDevicesSetting) {
374                     int[] ids =mIm.getInputDeviceIds();
375                     for (int i = 0; i < ids.length; i++) {
376                         InputDevice device =mIm.getInputDevice(ids[i]);
377                         Vibrator vibrator =device.getVibrator();
378                         if(vibrator.hasVibrator()) {
379 mInputDeviceVibrators.add(vibrator);
380 }
381 }
382 }
383 }
384 
385 startNextVibrationLocked();
386 }
387 }
388 
389 @Override
390     public void onInputDeviceAdded(intdeviceId) {
391 updateInputDeviceVibrators();
392 }
393 
394 @Override
395     public void onInputDeviceChanged(intdeviceId) {
396 updateInputDeviceVibrators();
397 }
398 
399 @Override
400     public void onInputDeviceRemoved(intdeviceId) {
401 updateInputDeviceVibrators();
402 }
403 
404     private booleandoVibratorExists() {
405         //For now, we choose to ignore the presence of input devices that have vibrators
406         //when reporting whether the device has a vibrator.  Applications often use this
407         //information to decide whether to enable certain features so they expect the
408         //result of hasVibrator() to be constant.  For now, just report whether
409         //the device has a built-in vibrator.
410         //synchronized (mInputDeviceVibrators) {
411         //return !mInputDeviceVibrators.isEmpty() || vibratorExists();
412         //}
413         returnvibratorExists();
414 }
415 
416     private void doVibratorOn(longmillis) {
417         synchronized(mInputDeviceVibrators) {
418             final int vibratorCount =mInputDeviceVibrators.size();
419             if (vibratorCount != 0) {
420                 for (int i = 0; i < vibratorCount; i++) {
421 mInputDeviceVibrators.get(i).vibrate(millis);
422 }
423             } else{
424 vibratorOn(millis);
425 }
426 }
427 }
428 
429     private voiddoVibratorOff() {
430         synchronized(mInputDeviceVibrators) {
431             final int vibratorCount =mInputDeviceVibrators.size();
432             if (vibratorCount != 0) {
433                 for (int i = 0; i < vibratorCount; i++) {
434 mInputDeviceVibrators.get(i).cancel();
435 }
436             } else{
437 vibratorOff();
438 }
439 }
440 }
441 
442     private class VibrateThread extendsThread {
443         finalVibration mVibration;
444         booleanmDone;
445 
446 VibrateThread(Vibration vib) {
447             mVibration =vib;
448 mTmpWorkSource.set(vib.mUid);
449 mWakeLock.setWorkSource(mTmpWorkSource);
450 mWakeLock.acquire();
451 }
452 
453         private void delay(longduration) {
454             if (duration > 0) {
455                 long bedtime = duration +SystemClock.uptimeMillis();
456                 do{
457                     try{
458                         this.wait(duration);
459 }
460                     catch(InterruptedException e) {
461 }
462                     if(mDone) {
463                         break;
464 }
465                     duration = bedtime -SystemClock.uptimeMillis();
466                 } while (duration > 0);
467 }
468 }
469 
470         public voidrun() {
471 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
472             synchronized (this) {
473                 int index = 0;
474                 long[] pattern =mVibration.mPattern;
475                 int len =pattern.length;
476                 int repeat =mVibration.mRepeat;
477                 long duration = 0;
478 
479                 while (!mDone) {
480                     //add off-time duration to any accumulated on-time duration
481                     if (index <len) {
482                         duration += pattern[index++];
483 }
484 
485                     //sleep until it is time to start the vibrator
486 delay(duration);
487                     if(mDone) {
488                         break;
489 }
490 
491                     if (index <len) {
492                         //read on-time duration and start the vibrator
493                         //duration is saved for delay() at top of loop
494                         duration = pattern[index++];
495                         if (duration > 0) {
496                             VibratorService.this.doVibratorOn(duration);
497 }
498                     } else{
499                         if (repeat < 0) {
500                             break;
501                         } else{
502                             index =repeat;
503                             duration = 0;
504 }
505 }
506 }
507 mWakeLock.release();
508 }
509             synchronized(mVibrations) {
510                 if (mThread == this) {
511                     mThread = null;
512 }
513                 if (!mDone) {
514                     //If this vibration finished naturally, start the next
515                     //vibration.
516 mVibrations.remove(mVibration);
517 unlinkVibration(mVibration);
518 startNextVibrationLocked();
519 }
520 }
521 }
522 };
523 
524     BroadcastReceiver mIntentReceiver = newBroadcastReceiver() {
525         public voidonReceive(Context context, Intent intent) {
526             if(intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
527                 synchronized(mVibrations) {
528 doCancelVibrateLocked();
529 
530                     int size =mVibrations.size();
531                     for(int i = 0; i < size; i++) {
532 unlinkVibration(mVibrations.get(i));
533 }
534 
535 mVibrations.clear();
536 }
537 }
538 }
539 };
540 }
View Code

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

4 Vibrator.java

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

1 packageandroid.os;
2 
3 importandroid.content.Context;
4 
5 public abstract classVibrator {
6 
7     publicVibrator() {
8 }
9 
10     public abstract booleanhasVibrator();
11     
12     public abstract void vibrate(longmilliseconds);
13 
14     public abstract void vibrate(long[] pattern, intrepeat);
15 
16     public abstract voidcancel();
17 }

5 SystemVibrator.java

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

1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15  */
16 
17 packageandroid.os;
18 
19 importandroid.util.Log;
20 
21 /**
22 * Vibrator implementation that controls the main system vibrator.
23 *
24 * @hide
25  */
26 public class SystemVibrator extendsVibrator {
27     private static final String TAG = "Vibrator";
28 
29     private finalIVibratorService mService;
30     private final Binder mToken = newBinder();
31 
32     publicSystemVibrator() {
33         mService =IVibratorService.Stub.asInterface(
34                 ServiceManager.getService("vibrator"));
35 }
36 
37 @Override
38     public booleanhasVibrator() {
39         if (mService == null) {
40             Log.w(TAG, "Failed to vibrate; no vibrator service.");
41             return false;
42 }
43         try{
44             returnmService.hasVibrator();
45         } catch(RemoteException e) {
46 }
47         return false;
48 }
49 
50 @Override
51     public void vibrate(longmilliseconds) {
52         if (mService == null) {
53             Log.w(TAG, "Failed to vibrate; no vibrator service.");
54             return;
55 }
56         try{
57 mService.vibrate(milliseconds, mToken);
58         } catch(RemoteException e) {
59             Log.w(TAG, "Failed to vibrate.", e);
60 }
61 }
62 
63 @Override
64     public void vibrate(long[] pattern, intrepeat) {
65         if (mService == null) {
66             Log.w(TAG, "Failed to vibrate; no vibrator service.");
67             return;
68 }
69         //catch this here because the server will do nothing.  pattern may
70         //not be null, let that be checked, because the server will drop it
71         //anyway
72         if (repeat <pattern.length) {
73             try{
74 mService.vibratePattern(pattern, repeat, mToken);
75             } catch(RemoteException e) {
76                 Log.w(TAG, "Failed to vibrate.", e);
77 }
78         } else{
79             throw newArrayIndexOutOfBoundsException();
80 }
81 }
82 
83 @Override
84     public voidcancel() {
85         if (mService == null) {
86             return;
87 }
88         try{
89 mService.cancelVibrate(mToken);
90         } catch(RemoteException e) {
91             Log.w(TAG, "Failed to cancel vibration.", e);
92 }
93 }
94 }
View Code

说明
(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 packagecom.test;
2 
3 importandroid.app.Activity;
4 importandroid.os.Bundle;
5 importandroid.os.Vibrator;
6 importandroid.view.View;
7 importandroid.view.View.OnClickListener;
8 importandroid.widget.Button;
9 importandroid.widget.ToggleButton;
10 importandroid.util.Log;
11 
12 public class VibratorTest extendsActivity {
13     private static final String TAG = "skywang-->VibratorTest";
14 
15     privateVibrator mVibrator;
16     private Button mOnce = null;
17     private ToggleButton mEndless = null;
18 
19 @Override
20     protected voidonCreate(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(newView.OnClickListener() {
29             
30 @Override
31             public voidonClick(View view) {
32                 //震动指定时间
33                 mVibrator.vibrate(100);
34 }
35 });
36 
37         mEndless =(ToggleButton) findViewById(R.id.vib_endless);
38         mEndless.setOnClickListener(newOnClickListener() {
39 @Override
40             public voidonClick(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 voidonStop() {
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);

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

2. ContextImpl.java中的getSystemService()

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

1 @Override
2 publicObject getSystemService(String name) {
3     ServiceFetcher fetcher =SYSTEM_SERVICE_MAP.get(name);
4     return fetcher == null ? null : fetcher.getService(this);
5 }

3. ContextImpl.java中的SYSTEM_SERVICE_MAP

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

1 private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =
2         new HashMap<String, ServiceFetcher>();
3 
4 SYSTEM_SERVICE_MAP的初始化,是在ContextImpl.java通过static静态模块完成的。源码如下:
5 static{
6 
7 ...
8 
9     //注册“传感器服务”
10     registerService(SENSOR_SERVICE, newServiceFetcher() {
11             publicObject createService(ContextImpl ctx) {
12                 return newSystemSensorManager(ctx.mMainThread.getHandler().getLooper());
13 }});
14 
15     //注册其它服务 ...
16 
17     //注册马达服务
18     registerService(VIBRATOR_SERVICE, newServiceFetcher() {
19             publicObject createService(ContextImpl ctx) {
20                 return newSystemVibrator();
21 }});
22 
23 ...
24 }

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

1 private static int sNextPerContextServiceCacheIndex = 0;
2 private static voidregisterService(String serviceName, ServiceFetcher fetcher) {
3     if (!(fetcher instanceofStaticServiceFetcher)) {
4         fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
5 }
6 SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
7 }

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

OK,接着往下看。

3. ContextImpl.java中的fetcher.getService(this)

1 publicObject getSystemService(String name) {
2     ServiceFetcher fetcher =SYSTEM_SERVICE_MAP.get(name);
3     return fetcher == null ? null : fetcher.getService(this);
4 }

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

1 static classServiceFetcher {
2     int mContextCacheIndex = -1;
3 
4     publicObject getService(ContextImpl ctx) {
5         ArrayList<Object> cache =ctx.mServiceCache;
6 Object service;
7         synchronized(cache) {
8             if (cache.size() == 0) {
9 
10                 //“服务对象”缓冲
11                 for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {
12                     cache.add(null);
13 }
14             } else{
15                 service =cache.get(mContextCacheIndex);
16                 if (service != null) {
17                     returnservice;
18 }
19 }
20             service =createService(ctx);
21 cache.set(mContextCacheIndex, service);
22             returnservice;
23 }
24 }
25 
26     publicObject createService(ContextImpl ctx) {
27         throw new RuntimeException("Not implemented");
28 }
29 }

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

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

免责声明:文章转载自《Android之 看“马达”如何贯通Android系统 (从硬件设计 --&amp;gt; 驱动 --&amp;gt; HAL --&amp;gt; JNI --&amp;gt; Framework --&amp;gt; Application)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇思考:如何保证服务稳定性?linux下不用空格执行带参数的5种姿势下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Activity 的 36 个问题,你还记得几个?(转)

作者:_yuanhao 链接: https://www.jianshu.com/p/86c0a4afd28e 本文由作者授权发布。 文章包含图片很多,已经尽力让图片尽可能可以看清了,但是无奈手机屏幕太小,仍有一些模糊~ 0前言 学 Android 有一段时间了,一直都只顾着学新的东西,最近发现很多平常用的少的东西竟让都忘了,趁着这两天,打算把有关 Acti...

在Eclipse下搭建Android开发环境教程,HelloWord

本文将全程演示Android开发环境的搭建过程,无需配置环境变量。所有软件都是写该文章时最新版本,希望大家喜欢。 我们昨天向各位介绍了《在NetBeans上搭建Android SDK环境》,前不久也介绍过《在MyEclipse 8.6上搭建Android开发环境》,都受到了读者的欢迎。但是很多朋友都认为NetBeans在中国用户不多,MyEcli...

android自定义控件概述

引子:   android SDK中会提供一些基础的控件以供开发。但是大多数情况下,这些基础的控件无法满足业务需求。本文主要说明自定义控件的分类,以及提供示例代码。   本文只做入门级选手阅读,或者 加深印象 或 温故而知新,大佬大神敬请绕道。 android控件的3种方式: 1)派生控件 : 从SDK已有的控件为基础,改变其部分特征,形成符合需求的自定...

Android开发——Android中常见的4种线程池(保证你能看懂并理解)

0.前言 转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/52415337 使用线程池可以给我们带来很多好处,首先通过线程池中线程的重用,减少创建和销毁线程的性能开销。其次,能控制线程池中的并发数,否则会因为大量的线程争夺CPU资源造成阻塞。最后,线程池能够对线程进行管理,比如使用Schedu...

[原]零基础学习SDL开发之在Android使用SDL2.0渲染PNG图片

在上一篇文章我们知道了如何在android使用SDL2.0来渲染显示一张bmp图,但是如果是一张png或者一张jpg的图,那么还能显示成功么?答案是否定的 我们需要移植SDL_image库来支持除bmp之外的图片格式。 一、移植SDL_image库: 使用如下命令,从SDLMercurial获取SDL_image的源码: hg clone https://...

Android JNI和NDK学习(08)JNI实例一 传递基本类型数据

Android JNI和NDK学习(08)--JNI实例一 传递基本类型数据 本文介绍在Java和JNI之间相互传递基本数据类型的方法。 由于前面已经详细介绍搭建和建立NDK工程的完整流程(参考“静态实现流程”或“动态实现流程”),这里就不再介绍流程;而是将重点放在说明如何实现Java和JNI之间相互传递基本数据。 1 建立eclipse工程 建立工程Nd...