天天看點

Android之 看“馬達”如何貫通Android系統 (從硬體設計 --> 驅動 --> HAL --> JNI --> Framework --> Application)

 在Android 2.3(Gingerbread) 系統的時候,我寫過一篇關于“Android 震動馬達系統“的文章,當時的Linux核心還是2.6版本的。寫那篇文章的目的,是想徹底的了解從硬體到驅動,再到應用的運作流程。完成了之後,文章一直仍在草稿箱裡面沒發表;今天看到,決定整理一下,重新發表。目的是想和大家分享自己對Android系統的一點認識:以馬達為代表,來考究“Android是如何一步步工作的。它從硬體設計,到Linux驅動,再到HAL,再到JNI,再到Framework,最後到被應用調用,這整套的流程到底是怎麼樣的!”

Part 1 馬達的硬體設計

    馬達的震動原理很簡單,給馬達通電,馬達就能震動。至于馬達是如何工作,如何将電能轉化為機械能,這不是我們關心的重點。但是,我們要需要了解如何控制馬達的通電。在硬體上,我們是通過一個IO口(GPIO)去控制;對于馬達而言,我們可以将IO了解為一個開關。當開關合上時,馬達震動;開關斷開,馬達停止震動。

    GPIO(General Purpose Input Output),稱為通用輸入/輸出。它可以被配置為中斷、輸入、輸出等類型,進而對各個IO進行控制。對于馬達而已,GPIO就相當于一個開關。下面看看硬體原理圖中的馬達部分,如下圖:

Android之 看“馬達”如何貫通Android系統 (從硬體設計 --> 驅動 --> HAL --> JNI --> Framework --> Application)

注:上面原理圖對應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)

說明:

(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總線上。源碼如下:

Android之 看“馬達”如何貫通Android系統 (從硬體設計 --> 驅動 --> HAL --> JNI --> Framework --> Application)
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 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");      
Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)

說明:

若您熟悉驅動開發,應該很容易了解上面的代碼。不熟悉也不要緊,您隻需要了解“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的代碼如下:

Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)
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 int vibrator_exists()
27 {
28     int fd;
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(int timeout_ms)
44 {
45     int nwr, 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         return errno;
57 
58     nwr = sprintf(value, "%d\n", 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(int timeout_ms)
67 {
68     /* constant on, up to maximum allowed time */
69     return sendit(timeout_ms);
70 }
71 
72 int vibrator_off()
73 {
74     return sendit(0);
75 }      
Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)

在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的源碼如下:

Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)
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 namespace android
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\n");
40     vibrator_on(timeout_ms);
41 }
42 
43 static void vibratorOff(JNIEnv *env, jobject clazz)
44 {
45     // ALOGI("vibratorOff\n");
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 };      
Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)

下面,對這部分的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源碼如下:

Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)
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之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)

在“我們編譯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 的源碼如下:

Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)
LOCAL_SRC_FILES:= \
com_android_server_VibratorService.cpp \
...

LOCAL_SHARED_LIBRARIES := \
libhardware_legacy \
...


LOCAL_MODULE:= libandroid_servers

include $(BUILD_SHARED_LIBRARY)
      
Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)

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中關于馬達的代碼如下:

Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)
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 }      
Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)

從中,我們知道:

(01) SystemServer中會通過VibratorService()建立馬達服務,并将其添加到ServiceManager中。

(02) 在Android系統啟動完成之後,SystemServer會調用vibrator.systemReady()。

2 IVibratorService.aidl

在檢視VibratorService.java之前,我們先看看它對應的aidl檔案。frameworks/base/core/java/android/os/IVibratorService.aidl源碼如下:

Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)
1 package android.os;
 2 
 3 /** {@hide} */
 4 interface IVibratorService
 5 {
 6     boolean hasVibrator();
 7     void vibrate(long milliseconds, IBinder token);
 8     void vibratePattern(in long[] pattern, int repeat, IBinder token);
 9     void cancelVibrate(IBinder token);
10 }      
Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)

3 VibratorService.java

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

Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)
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 package com.android.server;
 18 
 19 import android.content.BroadcastReceiver;
 20 import android.content.Context;
 21 import android.content.Intent;
 22 import android.content.IntentFilter;
 23 import android.content.pm.PackageManager;
 24 import android.database.ContentObserver;
 25 import android.hardware.input.InputManager;
 26 import android.os.Handler;
 27 import android.os.IVibratorService;
 28 import android.os.PowerManager;
 29 import android.os.Process;
 30 import android.os.RemoteException;
 31 import android.os.IBinder;
 32 import android.os.Binder;
 33 import android.os.SystemClock;
 34 import android.os.UserHandle;
 35 import android.os.Vibrator;
 36 import android.os.WorkSource;
 37 import android.provider.Settings;
 38 import android.provider.Settings.SettingNotFoundException;
 39 import android.util.Slog;
 40 import android.view.InputDevice;
 41 
 42 import java.util.ArrayList;
 43 import java.util.LinkedList;
 44 import java.util.ListIterator;
 45 
 46 public class VibratorService extends IVibratorService.Stub
 47         implements InputManager.InputDeviceListener {
 48     private static final String TAG = "VibratorService";
 49 
 50     private final LinkedList<Vibration> mVibrations;
 51     private Vibration mCurrentVibration;
 52     private final WorkSource mTmpWorkSource = new WorkSource();
 53     private final Handler mH = new Handler();
 54 
 55     private final Context mContext;
 56     private final PowerManager.WakeLock mWakeLock;
 57     private InputManager mIm;
 58 
 59     volatile VibrateThread 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 boolean vibratorExists();
 68     native static void vibratorOn(long milliseconds);
 69     native static void vibratorOff();
 70 
 71     private class Vibration implements IBinder.DeathRecipient {
 72         private final IBinder mToken;
 73         private final long    mTimeout;
 74         private final long    mStartTime;
 75         private final long[]  mPattern;
 76         private final int     mRepeat;
 77         private final int     mUid;
 78 
 79         Vibration(IBinder token, long millis, int uid) {
 80             this(token, millis, null, 0, uid);
 81         }
 82 
 83         Vibration(IBinder token, long[] pattern, int repeat, int uid) {
 84             this(token, 0, pattern, repeat, uid);
 85         }
 86 
 87         private Vibration(IBinder token, long millis, long[] pattern,
 88                 int repeat, int uid) {
 89             mToken = token;
 90             mTimeout = millis;
 91             mStartTime = SystemClock.uptimeMillis();
 92             mPattern = pattern;
 93             mRepeat = repeat;
 94             mUid = uid;
 95         }
 96 
 97         public void binderDied() {
 98             synchronized (mVibrations) {
 99                 mVibrations.remove(this);
100                 if (this == mCurrentVibration) {
101                     doCancelVibrateLocked();
102                     startNextVibrationLocked();
103                 }
104             }
105         }
106 
107         public boolean hasLongerTimeout(long millis) {
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 = new IntentFilter();
137         filter.addAction(Intent.ACTION_SCREEN_OFF);
138         context.registerReceiver(mIntentReceiver, filter);
139     }
140 
141     public void systemReady() {
142         mIm = (InputManager)mContext.getSystemService(Context.INPUT_SERVICE);
143 
144         mContext.getContentResolver().registerContentObserver(
145                 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES), true,
146                 new ContentObserver(mH) {
147                     @Override
148                     public void onChange(boolean selfChange) {
149                         updateInputDeviceVibrators();
150                     }
151                 }, UserHandle.USER_ALL);
152 
153         mContext.registerReceiver(new BroadcastReceiver() {
154             @Override
155             public void onReceive(Context context, Intent intent) {
156                 updateInputDeviceVibrators();
157             }
158         }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
159 
160         updateInputDeviceVibrators();
161     }
162 
163     public boolean hasVibrator() {
164         return doVibratorExists();
165     }
166 
167     public void vibrate(long milliseconds, 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 = new Vibration(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, int repeat, 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 = new Vibration(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 void cancelVibrate(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 = new Runnable() {
275         public void run() {
276             synchronized (mVibrations) {
277                 doCancelVibrateLocked();
278                 startNextVibrationLocked();
279             }
280         }
281     };
282 
283     // Lock held on mVibrations
284     private void doCancelVibrateLocked() {
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 void startNextVibrationLocked() {
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(final Vibration 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 = new VibrateThread(vib);
315             mThread.start();
316         }
317     }
318 
319     // Lock held on mVibrations
320     private Vibration 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                 return vib;
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             return mCurrentVibration;
335         }
336         return null;
337     }
338 
339     private void unlinkVibration(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 void updateInputDeviceVibrators() {
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(int deviceId) {
391         updateInputDeviceVibrators();
392     }
393 
394     @Override
395     public void onInputDeviceChanged(int deviceId) {
396         updateInputDeviceVibrators();
397     }
398 
399     @Override
400     public void onInputDeviceRemoved(int deviceId) {
401         updateInputDeviceVibrators();
402     }
403 
404     private boolean doVibratorExists() {
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         return vibratorExists();
414     }
415 
416     private void doVibratorOn(long millis) {
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 void doVibratorOff() {
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 extends Thread {
443         final Vibration mVibration;
444         boolean mDone;
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(long duration) {
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 void run() {
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 = new BroadcastReceiver() {
525         public void onReceive(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 }      
Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)

其中,VibratorService實際上是通過“本地方法”去控制馬達的。例如,hasVibratora()最終是通過vibratorExists()來判斷馬達是否存在的。

4 Vibrator.java

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

Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)
1 package android.os;
 2 
 3 import android.content.Context;
 4 
 5 public abstract class Vibrator {
 6 
 7     public Vibrator() {
 8     }
 9 
10     public abstract boolean hasVibrator();
11     
12     public abstract void vibrate(long milliseconds);
13 
14     public abstract void vibrate(long[] pattern, int repeat);
15 
16     public abstract void cancel();
17 }      
Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)

5 SystemVibrator.java

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

Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)
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 package android.os;
18 
19 import android.util.Log;
20 
21 /**
22  * Vibrator implementation that controls the main system vibrator.
23  *
24  * @hide
25  */
26 public class SystemVibrator extends Vibrator {
27     private static final String TAG = "Vibrator";
28 
29     private final IVibratorService mService;
30     private final Binder mToken = new Binder();
31 
32     public SystemVibrator() {
33         mService = IVibratorService.Stub.asInterface(
34                 ServiceManager.getService("vibrator"));
35     }
36 
37     @Override
38     public boolean hasVibrator() {
39         if (mService == null) {
40             Log.w(TAG, "Failed to vibrate; no vibrator service.");
41             return false;
42         }
43         try {
44             return mService.hasVibrator();
45         } catch (RemoteException e) {
46         }
47         return false;
48     }
49 
50     @Override
51     public void vibrate(long milliseconds) {
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, int repeat) {
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 new ArrayIndexOutOfBoundsException();
80         }
81     }
82 
83     @Override
84     public void cancel() {
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 }      
Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)

說明:

(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 源碼

源碼如下:

Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)
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之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)
點選下載下傳: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 public Object 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對象,它的相關代碼如下:

Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)
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, new ServiceFetcher() {
11             public Object createService(ContextImpl ctx) {
12                 return new SystemSensorManager(ctx.mMainThread.getHandler().getLooper());
13             }});
14 
15     // 注冊其它服務 ...
16 
17     // 注冊馬達服務
18     registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
19             public Object createService(ContextImpl ctx) {
20                 return new SystemVibrator();
21             }});
22 
23     ...
24 }      
Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)

說明:在上面的static靜态子產品中,會通過registerService()注冊一系列的服務,包括馬達服務。注冊服務是通過registerService()實作的,下面我們看看registerService()的定義。

Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)
1 private static int sNextPerContextServiceCacheIndex = 0;
2 private static void registerService(String serviceName, ServiceFetcher fetcher) {
3     if (!(fetcher instanceof StaticServiceFetcher)) {
4         fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
5     }
6     SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
7 }      
Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)

    從中,我們知道,在registerService()中,會通過 SYSTEM_SERVICE_MAP.put(serviceName, fetcher) 将serviceName和fetcher添加到哈希表SYSTEM_SERVICE_MAP中。

    對馬達服務而言,添加到哈希表SYSTEM_SERVICE_MAP中的key-value中的key是VIBRATOR_SERVICE,value則是ServiceFetcher對象;而且該匿名ServiceFetcher對象的createService()方法會“通過new SystemVibrator()”傳回SystemVibrator對象。而SystemVibrator我們在前面已經介紹過了,它是馬達服務對外提供接口的類。

OK,接着往下看。

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

1 public Object 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()源碼:

Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)
1 static class ServiceFetcher {
 2     int mContextCacheIndex = -1;
 3 
 4     public Object 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                     return service;
18                 }
19             }
20             service = createService(ctx);
21             cache.set(mContextCacheIndex, service);
22             return service;
23         }
24     }
25 
26     public Object createService(ContextImpl ctx) {
27         throw new RuntimeException("Not implemented");
28     }
29 }      
Android之 看“馬達”如何貫通Android系統 (從硬體設計 --&gt; 驅動 --&gt; HAL --&gt; JNI --&gt; Framework --&gt; Application)

從中,我們發現,getService()實際上傳回的是“通過createService(ctx)建立的service對象”。

而在registerService()注冊馬達服務時,我們匿名實作了createService()方法:它實際上是通過 new SystemVibrator() 傳回SystemVibrator對象。

至此,我們知道:getSystemService(VIBRATOR_SERVICE) 傳回的是 SystemVibrator對象!SystemVibrator前面已經分析過,這裡就不再說明了。

轉載請注明出處:http://www.cnblogs.com/skywang12345/p/3404808.html

繼續閱讀