Android硬體服務框架例項之Vibrator(驅動到應用)

墨塵深巷發表於2018-07-30

     

      轉載於:http://www.cnblogs.com/skywang12345/p/3404808.html,內容有所修改,這篇vibrator原始碼是基於安卓7.1分析。

     系列:安卓硬體訪問服務框架

                安卓從零新增硬體服務例項(驅動到app呼叫)

     目的是想和大家分享自己對Android系統的一點認識:以馬達為代表,來考究“Android是如何一步步工作的。它從硬體設計,到Linux驅動,再到HAL,再到JNI,再到Framework,最後到被應用呼叫,這整套的流程到底是怎麼樣的!

Part 1 馬達的硬體設計

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

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

 

注:上面原理圖對應CPU是“三星A8”。不同平臺的馬達,馬達的接法和GPIO都不一樣;但原理都是類似的。

原理圖中紅線標註部分的含義:GPH3_3是馬達的GPIO。三星A8中有很多組GPIO,而馬達對應和GPH3_3連線。

 

Part 2 馬達的驅動程式碼

    知道馬達的硬體設計之後,我們就可以進行Linux Driver開發工作,也就是編寫馬達的驅動。Linux的一個非常重要的特點,一切都是檔案!而我們進行Linux Driver開發的目的,就是將硬體裝置對映成一個檔案;然後,我們可以通過操作檔案,來操作對應的硬體裝置。

    OK!理解了驅動的作用和原理之後,我們接下來開發講解馬達的驅動開發。

 

1. Datasheet中相關資訊

    我們知道,馬達是通過GPIO去控制;接下來,我們就是找到馬達對應的GPIO資訊,然後控制該GPIO即可。

    通過馬達的原理圖,我們知道馬達和GPH3_3相連線。我們查閱“三星A8 的Datasheet”,查詢GPH3_3的相關資訊。

    三星A8的Datasheet中,關於GPH3_3的資訊如下:

所謂Datasheet,就是CPU晶片的資料手冊。
   上面記載了CPU的功能特性和操作方式等資訊。任何一個廠家在釋出它的晶片時,都會提供對應的Datasheet給它的客戶;客戶根據Datasheet上面所描述的CPU的特性,就可以進行相關的開發(當然,實際開發中可能還需要晶片廠商的支援)。例如,國內手機都是採用MTK平臺,對於MTK方案開發商來說,它要開發MTK6577的產品。那麼首先,MTK原廠會提供一份MTK6577的BSP包,BSP包中包括了MTK6577的Datasheet,也就是該晶片的資料手冊。方案開發商有任何關於MTK6577的問題,都可以查閱該Datasheet。
 

說明

(01) GPH3_3對應CPU中的暫存器是GPH3CON[3]。

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

例如, 0000表示將該GPIO作為輸入,0001表示將GPIO作為輸出,1111表示將該GPIO作為中斷。

           前面,我們已經說過,操作馬達就是相當與將它作為一個開關操作。因此,我們需要將馬達的GPIO設為“輸入”型別;然後輸入1,相當於開啟馬達;輸入0,則是關閉馬達!

下面,我們需要做的就是在Driver中將GPH3_3(也就是GPH3CON[3])對映為一個檔案節點,並將它配置為“輸入”型別,即將GPH3CON[3]的暫存器值設為0000。

 

2. 馬達的驅動

    我們編寫馬達驅動(drivers/misc/misc_sysfs.c),將馬達(vibrator)註冊道platform匯流排上。原始碼如下:

 1 #include <linux/kernel.h>
  2 #include <linux/types.h>
  3 #include <linux/module.h>
  4 #include <linux/device.h>
  5 #include <linux/platform_device.h>
  6 #include <linux/delay.h>
  7 #include <linux/irq.h>
  8 #include <linux/interrupt.h>
  9 #include <linux/sysfs.h>
 10 #include <linux/input.h>
 11 #include <mach/gpio.h>
 12 
 13 // vibrator 對應的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");

說明

若您熟悉驅動開發,應該很容易理解上面的程式碼。不熟悉也不要緊,您只需要瞭解“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曾,基於Android7.1系統進行分析的。(裝置節點:/sys/class/timed_output/vibrator/enable)

 

Part 3 馬達的HAL實現

HAL (Hardware Abstraction Layer), 又稱為“硬體抽象層”。在Linux驅動中,我們已經將馬達設為對映為檔案了;而該HAL層的存在的意義,就是“對裝置檔案進行操作,從而相當於硬體進行操作”。HAL層的作用,一是操作硬體裝置,二是操作介面封裝,外界能方便的使用HAL提供的介面直接操作硬體裝置。

理解了HAL之後,我們看看Android中如何在HAL層對馬達進行操作。

在Android系統中,我們在libhardware_legacy中,實現馬達的HAL層控制。
馬達在HAL中的程式碼路徑:hardware/libhardware/modules/vibrator/vibrator.c

標頭檔案:hardware/libhardware/include/hardware/vibrator.h

vibrator.c的程式碼如下:

/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <hardware/vibrator.h>
#include <hardware/hardware.h>

#include <cutils/log.h>

#include <malloc.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <math.h>

static const char THE_DEVICE[] = "/sys/class/timed_output/vibrator/enable";

static int vibra_exists() {
    int fd;

    fd = TEMP_FAILURE_RETRY(open(THE_DEVICE, O_RDWR));
    if(fd < 0) {
        ALOGE("Vibrator file does not exist : %d", fd);
        return 0;
    }

    close(fd);
    return 1;
}

static int sendit(unsigned int timeout_ms)
{
    int to_write, written, ret, fd;

    char value[20]; /* large enough for millions of years */

    fd = TEMP_FAILURE_RETRY(open(THE_DEVICE, O_RDWR));
    if(fd < 0) {
        return -errno;
    }

    to_write = snprintf(value, sizeof(value), "%u\n", timeout_ms);
    written = TEMP_FAILURE_RETRY(write(fd, value, to_write));

    if (written == -1) {
        ret = -errno;
    } else if (written != to_write) {
        /* even though EAGAIN is an errno value that could be set
           by write() in some cases, none of them apply here.  So, this return
           value can be clearly identified when debugging and suggests the
           caller that it may try to call vibraror_on() again */
        ret = -EAGAIN;
    } else {
        ret = 0;
    }

    errno = 0;
    close(fd);

    return ret;
}

static int vibra_on(vibrator_device_t* vibradev __unused, unsigned int timeout_ms)
{
    /* constant on, up to maximum allowed time */
    return sendit(timeout_ms);
}

static int vibra_off(vibrator_device_t* vibradev __unused)
{
    return sendit(0);
}

static int vibra_close(hw_device_t *device)
{
    free(device);
    return 0;
}

static int vibra_open(const hw_module_t* module, const char* id __unused,
                      hw_device_t** device __unused) {
    if (!vibra_exists()) {
        ALOGE("Vibrator device does not exist. Cannot start vibrator");
        return -ENODEV;
    }

    vibrator_device_t *vibradev = calloc(1, sizeof(vibrator_device_t));

    if (!vibradev) {
        ALOGE("Can not allocate memory for the vibrator device");
        return -ENOMEM;
    }

    vibradev->common.tag = HARDWARE_DEVICE_TAG;
    vibradev->common.module = (hw_module_t *) module;
    vibradev->common.version = HARDWARE_DEVICE_API_VERSION(1,0);
    vibradev->common.close = vibra_close;

    vibradev->vibrator_on = vibra_on;
    vibradev->vibrator_off = vibra_off;

    *device = (hw_device_t *) vibradev;

    return 0;
}

/*===========================================================================*/
/* Default vibrator HW module interface definition                           */
/*===========================================================================*/

static struct hw_module_methods_t vibrator_module_methods = {
    .open = vibra_open,
};

struct hw_module_t HAL_MODULE_INFO_SYM = {
    .tag = HARDWARE_MODULE_TAG,
    .module_api_version = VIBRATOR_API_VERSION,
    .hal_api_version = HARDWARE_HAL_API_VERSION,
    .id = VIBRATOR_HARDWARE_MODULE_ID,
    .name = "Default vibrator HAL",
    .author = "The Android Open Source Project",
    .methods = &vibrator_module_methods,
};

      在kernel的驅動中,我們已經將馬達註冊到sys檔案系統中(/sys/devices/platform/misc_ctl/vibrator_onoff)。在vibrator.c中,我們就是通過讀寫“vibrator_onoff檔案節點”來實現對馬達的操作。

 

Part 4 馬達的JNI部分

1 馬達的JNI實現

JNI(Java Native Interface),中文是“Java本地介面”。

JNI是Java中一種技術,它存在的意義,是保證原生程式碼(C/C++程式碼)能在任何Java虛擬機器下工作。簡單點說,Java通過JNI介面,能夠呼叫到C/C++程式碼。 關於“JNI的更多內容”,請參考“Android JNI和NDK學習系列文章”。

在瞭解了vibrator的HAL層實現之後,我們再來看看android是如何通過JNI將震動馬達註冊到android系統中。馬達對應的JNI層程式碼路徑如下:frameworks/base/services/core/jni/com_android_server_VibratorService.cpp

com_android_server_VibratorService.cpp的原始碼如下:

/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "VibratorService"

#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"

#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/vibrator.h>

#include <stdio.h>

namespace android
{

static hw_module_t *gVibraModule = NULL;
static vibrator_device_t *gVibraDevice = NULL;

static void vibratorInit(JNIEnv /* env */, jobject /* clazz */)
{
    if (gVibraModule != NULL) {
        return;
    }

    int err = hw_get_module(VIBRATOR_HARDWARE_MODULE_ID, (hw_module_t const**)&gVibraModule);

    if (err) {
        ALOGE("Couldn't load %s module (%s)", VIBRATOR_HARDWARE_MODULE_ID, strerror(-err));
    } else {
        if (gVibraModule) {
            vibrator_open(gVibraModule, &gVibraDevice);
        }
    }
}

static jboolean vibratorExists(JNIEnv* /* env */, jobject /* clazz */)
{
    if (gVibraModule && gVibraDevice) {
        return JNI_TRUE;
    } else {
        return JNI_FALSE;
    }
}

static void vibratorOn(JNIEnv* /* env */, jobject /* clazz */, jlong timeout_ms)
{
    if (gVibraDevice) {
        int err = gVibraDevice->vibrator_on(gVibraDevice, timeout_ms);
        if (err != 0) {
            ALOGE("The hw module failed in vibrator_on: %s", strerror(-err));
        }
    } else {
        ALOGW("Tried to vibrate but there is no vibrator device.");
    }
}

static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */)
{
    if (gVibraDevice) {
        int err = gVibraDevice->vibrator_off(gVibraDevice);
        if (err != 0) {
            ALOGE("The hw module failed in vibrator_off(): %s", strerror(-err));
        }
    } else {
        ALOGW("Tried to stop vibrating but there is no vibrator device.");
    }
}

static const JNINativeMethod method_table[] = {
    { "vibratorExists", "()Z", (void*)vibratorExists },
    { "vibratorInit", "()V", (void*)vibratorInit },
    { "vibratorOn", "(J)V", (void*)vibratorOn },
    { "vibratorOff", "()V", (void*)vibratorOff }
};

int register_android_server_VibratorService(JNIEnv *env)
{
    return jniRegisterNativeMethods(env, "com/android/server/VibratorService",
            method_table, NELEM(method_table));
}

};

下面,對這部分的JNI程式碼進行簡單說明。

(01) 通過 jniRegisterNativeMethods(),我們將method_table中的方法註冊到 com.android.server.VibratorService.java 中。配對錶格如下:

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

​

通過JNI,我們就能將Java層和HAL層的程式碼聯絡起來。
以vibratorOff()來說,我們在VibratorService.java中呼叫vibratorOff();實際上會呼叫到com_android_server_VibratorService.cpp中的vibratorOff()函式;進一步會呼叫到vibrator_off()函式,而vibrator_off()是我們在 “HAL層的vibrator.c中的介面”。


2 馬達的JNI如何和HAL關聯方式

在繼續接下來的研究之前,我們先搞清楚:JNI如何和HAL層程式碼關聯起來的。即com_android_server_VibratorService.cpp是如何呼叫到vibrator.c中的程式碼的。
實際上道理很簡單,我們先將vibrator.c封裝成.so庫;然後在com_android_server_VibratorService.cpp中匯入該庫,就可以呼叫vibrator.c的介面了。下面,看看Android中具體是如何做到的。

(01) vibrator.c封裝到vibrator.default.so中的步驟

在hardware/libhardware/modules/vibrator/Android.mk中,會將vibrator.c新增到 LOCAL_SRC_FILES 變數中。
hardware/libhardware_legacy/vibrator/Android.mk原始碼如下:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := vibrator.default

# HAL module implementation stored in
# hw/<VIBRATOR_HARDWARE_MODULE_ID>.default.so
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_C_INCLUDES := hardware/libhardware
LOCAL_SRC_FILES := vibrator.c
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_MODULE_TAGS := optional

include $(BUILD_SHARED_LIBRARY)

    在“我們編譯Android系統”或“通過 mmm hardware/libhardware/modules/vibrator/進行模組編譯”的時候,就會生成庫vibrator.default.so;而且vibrator.c被包含在該庫中。

(02) 在 com_android_server_VibratorService.cpp 對應的Android.mk中,會匯入vibrator.default.so。
com_android_server_VibratorService.cpp 對應的frameworks/base/services/core/jni/Android.mk的原始碼如下:

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

Part 5 馬達的Framework層實現

應用層操作馬達,是通過馬達服務進行操作的。而馬達服務是通過aidl實現的,aidl是Android程式間的通訊方式。關於aidl的更多說明可以參考“Android Service總結06 之AIDL”。

馬達服務涉及的主要檔案如下:

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

​

下面,對這幾個檔案的功能進行簡要說明。

檔案1: SystemServer.java
           它是系統服務,作用是啟動、管理系統服務,包括“馬達服務、Wifi服務、Activity管理服務”等等。
           SystemServer是通過Zygote啟動的,而Zygote又是在init中啟動的,init則是kernel載入完畢之後啟動的第一個程式。在這裡,我們只需要知道“SystemServer是用來啟動/管理馬達服務即可。”

檔案2: IVibratorService.aidl
           它是馬達服務對應的aidl配置檔案。我們在aidl中定義了其它程式可以訪問的外部介面;然後再通過VibratorService.java實現這些介面。

檔案3: VibratorService.java
           它是馬達服務對應的aidl介面的實現程式。它實現IVibratorService.aidl的介面,從而實現馬達服務;它的函式介面,是通過呼叫JNI層對應的馬達控制函式來實現的。

檔案4: Vibrator.java
           它是馬達服務開放給應用層的呼叫類。理論上講,我們完全可以通過aidl直接呼叫馬達服務,而不需要Vibrator.java類。但是!既然它存在,就肯定有它的理由。事實的確如此,Google之所以這麼做。有以下幾個原因:
           第一,提供統一而且方便的服務呼叫方式。這裡的“統一”,是指和所有其它的系統服務一樣,我們呼叫服務時,需先通過getSystemService()獲取服務,然後再呼叫服務的函式介面。這裡的“方便”,是指若我們直接通過aidl呼叫,操作比較繁瑣(若你用過aidl就會知道,需要先實現ServiceConnection介面以獲取IBinder物件,然後再通過IBinder物件呼叫aidl的介面); 而Vibrator.java封裝之後的介面,將許多細節都隱藏了,非常便於應用者呼叫!
          第二,基於安全的考慮。Vibrator.java封裝隱藏了許多細節,而這些都是應用開發者不必要知道的。
          第三,Vibrator是抽象類。它便於我們支援不同型別的馬達:包括“將馬達直接對映到檔案”以及“將馬達註冊到輸入子系統”中。

檔案5: SystemVibrator.java
         它是Vibrator.java的子類,實現了馬達的服務介面。

下面,我們繼續Read The Fucking Source Code,加深對上面知識的理解。

1 SystemServer.java

在frameworks/base/services/java/com/android/server/SystemServer.java中關於馬達的程式碼如下:

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

從中,我們知道:
(01) SystemServer中會通過VibratorService()新建馬達服務,並將其新增到ServiceManager中。
(02) 在Android系統啟動完成之後,SystemServer會呼叫vibrator.systemReady()。

2 IVibratorService.aidl

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

package android.os;

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

3 VibratorService.java

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


 package com.android.server;

 public class VibratorService extends IVibratorService.Stub
        implements InputManager.InputDeviceListener {
       ......

      native static boolean vibratorExists();
      native static void vibratorOn(long milliseconds);
      native static void vibratorOff();
       ......

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

4 Vibrator.java

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

package android.os;
import android.app.ActivityThread;
import android.content.Context;
import android.media.AudioAttributes;
public abstract class Vibrator {

    private final String mPackageName;
    public Vibrator() {
        mPackageName = ActivityThread.currentPackageName();
    }
    protected Vibrator(Context context) {
        mPackageName = context.getOpPackageName();
    }

    public abstract boolean hasVibrator();

    public void vibrate(long milliseconds) {
        vibrate(milliseconds, null);
    }

    public void vibrate(long milliseconds, AudioAttributes attributes) {
        vibrate(Process.myUid(), mPackageName, milliseconds, attributes);
    }

    public void vibrate(long[] pattern, int repeat) {
        vibrate(pattern, repeat, null);
    }

    public void vibrate(long[] pattern, int repeat, AudioAttributes attributes) {
        vibrate(Process.myUid(), mPackageName, pattern, repeat, attributes);
    }

    public abstract void vibrate(int uid, String opPkg, long milliseconds,
            AudioAttributes attributes);

    public abstract void vibrate(int uid, String opPkg, long[] pattern, int repeat,
            AudioAttributes attributes);

    public abstract void cancel();
}

5 SystemVibrator.java

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

package android.os;

import android.content.Context;
import android.media.AudioAttributes;
import android.util.Log;

/**
 * Vibrator implementation that controls the main system vibrator.
 *
 * @hide
 */
public class SystemVibrator extends Vibrator {
    private static final String TAG = "Vibrator";

    private final IVibratorService mService;
    private final Binder mToken = new Binder();

    public SystemVibrator() {
        mService = IVibratorService.Stub.asInterface(
                ServiceManager.getService("vibrator"));
    }

    public SystemVibrator(Context context) {
        super(context);
        mService = IVibratorService.Stub.asInterface(
                ServiceManager.getService("vibrator"));
    }

    @Override
    public boolean hasVibrator() {
        if (mService == null) {
            Log.w(TAG, "Failed to vibrate; no vibrator service.");
            return false;
        }
        try {
            return mService.hasVibrator();
        } catch (RemoteException e) {
        }
        return false;
    }

    /**
     * @hide
     */
    @Override
    public void vibrate(int uid, String opPkg, long milliseconds, AudioAttributes attributes) {
        if (mService == null) {
            Log.w(TAG, "Failed to vibrate; no vibrator service.");
            return;
        }
        try {
            mService.vibrate(uid, opPkg, milliseconds, usageForAttributes(attributes), mToken);
        } catch (RemoteException e) {
            Log.w(TAG, "Failed to vibrate.", e);
        }
    }

    /**
     * @hide
     */
    @Override
    public void vibrate(int uid, String opPkg, long[] pattern, int repeat,
            AudioAttributes attributes) {
        if (mService == null) {
            Log.w(TAG, "Failed to vibrate; no vibrator service.");
            return;
        }
        // catch this here because the server will do nothing.  pattern may
        // not be null, let that be checked, because the server will drop it
        // anyway
        if (repeat < pattern.length) {
            try {
                mService.vibratePattern(uid, opPkg, pattern, repeat, usageForAttributes(attributes),
                        mToken);
            } catch (RemoteException e) {
                Log.w(TAG, "Failed to vibrate.", e);
            }
        } else {
            throw new ArrayIndexOutOfBoundsException();
        }
    }

    private static int usageForAttributes(AudioAttributes attributes) {
        return attributes != null ? attributes.getUsage() : AudioAttributes.USAGE_UNKNOWN;
    }

    @Override
    public void cancel() {
        if (mService == null) {
            return;
        }
        try {
            mService.cancelVibrate(mToken);
        } catch (RemoteException e) {
            Log.w(TAG, "Failed to cancel vibration.", e);
        }
    }
}

說明
(01) 在建構函式SystemVibrator()中,我們通過 IVibratorService.Stub.asInterface(ServiceManager.getService("vibrator")) 獲取馬達服務,實際上獲取的是VibratorService物件。
(02) SystemVibrator的介面都是呼叫VibratorService介面實現的。

在講解“應用層如何通過getSystemService(VIBRATOR_SERVICE)獲取馬達服務,然後進一步的操作馬達”之前,我們先看看應用層的馬達操作示例!

 

Part 6 馬達的應用示例

1 許可權

呼叫馬達服務,需要在manifest中新增相應的許可權:

<!-- 震動馬達許可權 -->
<uses-permission android:name="android.permission.VIBRATE"/>

2 原始碼

原始碼如下:

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

點選下載:Android馬達應用程式碼

 

Part 7 馬達的應用如何呼叫到馬達服務的

接下來,我們分析一下如何獲取馬達服務的:即 mVibrator= (Vibrator) getSystemService(VIBRATOR_SERVICE) 的工作原理。

1. Context.java中的getSystemService()

getSystemService()定義在frameworks/base/core/java/android/content/Context.java中,原始碼如下:

​
public abstract Object getSystemService(String name);

​
public static final String VIBRATOR_SERVICE = "vibrator";

Context.java中的getSystemService() 是個抽象方法,它的實現在ContextImpl.java中。

2. ContextImpl.java中的getSystemService()

frameworks/base/core/java/android/app/ContextImpl.java中的 getSystemService() 原始碼如下:

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

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

frameworks/base/core/java/android/app/SystemServiceRegistry.java的原始碼如下:

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

4. SystemServiceRegistry.java中的SYSTEM_SERVICE_FETCHERS

SYSTEM_SERVICE_FETCHERS是一個HashMap物件,它的相關程式碼如下:

​
private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new HashMap<String, ServiceFetcher<?>>();

SYSTEM_SERVICE_FETCHERS 的初始化,是在SystemServiceRegistry.java通過static靜態模組完成的。原始碼如下:
static {
  
      ...
  
      // 註冊“感測器服務”
      registerService(Context.SENSOR_SERVICE, SensorManager.class,
                new CachedServiceFetcher<SensorManager>() {
            @Override
            public SensorManager createService(ContextImpl ctx) {
                return new SystemSensorManager(ctx.getOuterContext(),
                  ctx.mMainThread.getHandler().getLooper());
            }});
 
     // 註冊其它服務 ...
 
     // 註冊馬達服務
    registerService(Context.VIBRATOR_SERVICE, Vibrator.class,
                new CachedServiceFetcher<Vibrator>() {
            @Override
            public Vibrator createService(ContextImpl ctx) {
                return new SystemVibrator(ctx);
            }});
 
     ...
 }

​

說明:在上面的static靜態模組中,會通過registerService()註冊一系列的服務,包括馬達服務。註冊服務是通過registerService()實現的,下面我們看看registerService()的定義。

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

    從中,我們知道,在registerService()中,會通過 SYSTEM_SERVICE_FETCHERS.put(serviceName, fetcher) 將serviceName和fetcher新增到雜湊表SYSTEM_SERVICE_FETCHERS中。
    對馬達服務而言,新增到雜湊表SYSTEM_SERVICE_FETCHERS中的key-value中的key是VIBRATOR_SERVICEvalue則是ServiceFetcher物件;而且該匿名ServiceFetcher物件的createService()方法會“通過new SystemVibrator()”返回SystemVibrator物件。而SystemVibrator我們在前面已經介紹過了,它是馬達服務對外提供介面的類。

OK,接著往下看。

我們已經知道SYSTEM_SERVICE_FETCHERS是雜湊表,通過SYSTEM_SERVICE_FETCHERS.get(name)返回的是ServiceFetcher物件。由於fetcher不為null,所以,getSystemService()會返回fetcher.getService(this)。我們看看ServiceFetcher中getService()原始碼:

    static abstract interface ServiceFetcher<T> {
        T getService(ContextImpl ctx);
    }

    /**
     * Override this class when the system service constructor needs a
     * ContextImpl and should be cached and retained by that context.
     */
    static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {
        private final int mCacheIndex;

        public CachedServiceFetcher() {
            mCacheIndex = sServiceCacheSize++;
        }

        @Override
        @SuppressWarnings("unchecked")
        public final T getService(ContextImpl ctx) {
            final Object[] cache = ctx.mServiceCache;
            synchronized (cache) {
                // Fetch or create the service.
                Object service = cache[mCacheIndex];
                if (service == null) {
                    service = createService(ctx);
                    cache[mCacheIndex] = service;
                }
                return (T)service;
            }
        }

        public abstract T createService(ContextImpl ctx);
    }

從中,我們發現,getService()實際上返回的是“通過createService(ctx)建立的service物件”。
而在registerService()註冊馬達服務時,我們匿名實現了createService()方法:它實際上是通過 new SystemVibrator() 返回SystemVibrator物件。

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

8. 震動器hal層到app原始檔目錄及重要程式碼:  

hal:
 hardware/libhardware/modules/vibrator/vibrator.c
 hardware/libhardware/include/hardware/vibrator.h
		./lib64/hw/vibrator.default.so
JNI:
 frameworks/base/services/core/jni/com_android_server_VibratorService.cpp
	jniRegisterNativeMethods(env, "com/android/server/VibratorService",method_table, NELEM(method_table));
 frameworks/base/services/core/jni/onload.cpp
	register_android_server_VibratorService(env);

framework:	
 frameworks/base/core/java/android/os/IVibratorService.aidl
	interface IVibratorService
	{
		boolean hasVibrator();
		void vibrate(int uid, String opPkg, long milliseconds, int usageHint, IBinder token);
		void vibratePattern(int uid, String opPkg, in long[] pattern, int repeat, int usageHint, IBinder token);
		void cancelVibrate(IBinder token);
	}

//震動器實際操作類,服務,通過JNI呼叫com_android_server_VibratorService中函式
  frameworks/base/services/core/java/com/android/server/VibratorService.java
	VibratorService extends IVibratorService.Stub
	native static boolean vibratorExists();
    native static void vibratorInit();
    native static void vibratorOn(long milliseconds);
    native static void vibratorOff();
	
  frameworks/base/services/java/com/android/server/SystemServer.java
	vibrator = new VibratorService(context);
    ServiceManager.addService("vibrator", vibrator);

		vibrator.systemReady();

//這兩個類client使用:
  frameworks/base/core/java/android/os/Vibrator.java
  frameworks/base/core/java/android/os/SystemVibrator.java
	SystemVibrator extends Vibrator
	IVibratorService mService = IVibratorService.Stub.asInterface(ServiceManager.getService("vibrator"));
	
app:
	Vibrator mVibrator= (Vibrator) getSystemService(VIBRATOR_SERVICE)
	frameworks/base/core/java/android/content/Context.java
		public abstract Object getSystemService(String name);
		frameworks/base/core/java/android/app/ContextImpl.java(在這個類裡實現)
			public Object getSystemService(String name) {
				return SystemServiceRegistry.getSystemService(this, name);
			}
			frameworks/base/core/java/android/app/SystemServiceRegistry.java
				registerService(Context.VIBRATOR_SERVICE, Vibrator.class,
                new CachedServiceFetcher<Vibrator>() {
				@Override
				public Vibrator createService(ContextImpl ctx) {
					return new SystemVibrator(ctx);
				}});
				public static Object getSystemService(ContextImpl ctx, String name) {
					ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
					return fetcher != null ? fetcher.getService(ctx) : null;
				}
			最後返回SystemVibrator物件。

 

 Q:  自己在原始碼裡新增的硬體服務,eclipse或者android studio編寫測試app時,需要把原始碼編譯生成的classes.jar包匯入專案或者把app原始碼直接放入原始碼編譯。原始碼編譯完成會生成許多classes.jar。我們要匯入的classes.jar路徑為:out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar

 

 

相關文章