Android手機“核心科技”---Vibrator(馬達)驅動分析

前言

我的博客已經斷更很久了,因爲疫情的原因沒能開學,也無法去公司報道實習,在家十分的頹廢,學習的時間零零散散,更是沒有什麼時間來寫博客的@@(鐵廢物)。最近疫情好轉,自己也來深圳這邊某知名IC廠商(同樣也讓人喊YES的那個)實習,在手機部門做一些驅動相關內容的工作,以前有做過Linux驅動開發,安卓以前沒有接觸過,在公司就慢慢開始學習,自己下班回家後後也再分析分析代碼,寫寫博客。
因爲自己也是一個初學者,在分析上有什麼不正確的地方也希望大家可以指正
注意:這些博客沒有任何從公司電腦上拷貝的資料,參照的代碼爲Github的開源代碼或者AOSP的代碼,求生欲滿滿-.-

Vibrator簡單介紹

Vibrator是振動器的意思,也可以被叫做馬達,馬達旋轉或者做直線運動會產生振動。由於小米的科普(此處應該有些掌聲)我們瞭解了手機馬達的幾種類別:普通轉子馬達(一般用於低端機)、幣型轉子馬達(被小米嘲諷的嗡嗡嗡)、Y軸線性馬達(形狀類似幣型轉子但是它是做Y軸的直線運動)、X軸線性馬達(蘋果魅族等廠商的,做X軸線性運動)

馬達對手機的使用體驗確實有所提升,好的振動反饋是頂級手機必備特性。
對於我們底層驅動開發人員來說,馬達卻是一個特別好的入門模塊,因爲馬達的控制一般分爲兩類:PWM控制、ldo輸出控制,後者所佔的比例較多,一般只是由PMIC輸出電壓即可,而內核驅動部分、HAL部分、JNI部分、Application Framework部分相對很標準,十分適合用來理解Android驅動框架,體會如何在APP使用JAVA調用底層用C甚至彙編編寫的驅動程序。

0: 驅動框架的整體介紹

代碼版本、出處及講解平臺

Kernel:mtk-t-alps-release-q0-kernel-4.9 Github地址:點我
Android:Android 10.0.0_r30 android code search地址:點我
平臺:MTK6779

相關文件

Application Framework

  • frameworks/base/core/java/android/os/SystemVibrator.java
  • frameworks/base/core/java/android/os/Vibrator.java
  • frameworks/base/services/core/java/com/android/server/VibratorService.java
  • frameworks/base/core/java/android/os/IVibratorService.aidl
  • frameworks/base/services/java/com/android/server/SystemServer.java

JNI

  • frameworks/base/services/core/jni/com_android_server_VibratorService.cpp

HAL

  • hardware/interfaces/vibrator/1.0/default/Vibrator.cpp
  • hardware/interfaces/vibrator/1.0/default/Vibrator.h
  • hardware/libhardware/modules/vibrator/vibrator.c
  • hardware/libhardware/include/hardware/vibrator.h

Kernel

  • \drivers\misc\mediatek\vibrator\mt6779\vibrator.c
  • \drivers\misc\mediatek\vibrator\mt6779\vibrator.h
  • \drivers\misc\mediatek\vibrator\vibrator_drv.c

DTS

  • \arch\arm64\boot\dts\mediatek\k79v1_64.dts

流程分析

在這裏插入圖片描述
大體的框架如上圖所示,當應用操作馬達時,它會調用Application Framework層實現的馬達調用類,並且這些調用是通過馬達服務的(可以理解爲一個進程),而馬達服務又需要通過aidl實現,aidl是Android進程間的通信方式。在服務中對底層的操控需要使用一些與HAL層CPP函數相映射的JAVA函數,JNI層就是完成這個映射工作的。HAL硬件描述層是在用戶空間對內核空間中驅動的使用,通過對Sysfs中的設備節點的讀取和寫入來完成馬達狀態的讀取和控制。內核的驅動程序中完成對設備的操作,當驅動檢測到設備時會在用戶空間生成設備節點,定義對設備節點中屬性文件的讀寫操作,同時也會根據設備樹中的信息完成對設備的初始化。設備樹是對底層硬件的描述,通過定義一個vibrator節點,在節點中定義電壓等級、最短震動時間等屬性,以供驅動的讀取。硬件部分使用SPI與PMIC通信,通過對PMIC的讀寫就可以實現輸出LDO控制vibrator以及接受vibrator的過流中斷等。
這是對自頂向下對驅動框架的簡單介紹,接下來我們自底向上逐步分析vibrator的驅動框架

1: 硬件部分

PMIC與AP使用SPI連接,馬達連接在PMIC上,馬達由一個LDO輸出控制,輸出與地之間接一個濾波電容,去除尖峯電壓

2: 設備樹部分

設備樹中的vibrator節點代碼如下

	vibrator0:vibrator@0 {
		compatible = "mediatek,vibrator";
		vib_timer = <25>;
		vib_limit = <9>;
		vib_vol= <9>;
	};

這個包含用於與驅動匹配的compatible,以及電壓等級、震動的時間限制等

3: kernel Driver部分

kernel Driver部分包含兩部分,與底層芯片相關的放在以AP命名的文件夾中,與底層實現不相關的不同平臺是共用的,降低了代碼維護的難度。
首先與硬件不相關的代碼如下

硬件不相關

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/workqueue.h>
#include <linux/leds.h>
#include <linux/hrtimer.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/jiffies.h>
#include <linux/timer.h>

#include <vibrator.h>
#include <vibrator_hal.h>
#include <mt-plat/upmu_common.h>

#define VIB_DEVICE				"mtk_vibrator"
#define VIB_TAG                                 "[vibrator]"

struct mt_vibr {
	struct workqueue_struct *vibr_queue;
	struct work_struct vibr_work;
	struct hrtimer vibr_timer;
	int ldo_state;
	int shutdown_flag;
	atomic_t vibr_dur;
	spinlock_t vibr_lock;
	atomic_t vibr_state;
};

static struct mt_vibr *g_mt_vib;

static int vibr_Enable(void)
{
	if (!g_mt_vib->ldo_state) {
		vibr_Enable_HW();
		g_mt_vib->ldo_state = 1;
	}
	return 0;
}

static int vibr_Disable(void)
{
	if (g_mt_vib->ldo_state) {
		vibr_Disable_HW();
		g_mt_vib->ldo_state = 0;
	}
	return 0;
}

static void update_vibrator(struct work_struct *work)
{
	struct mt_vibr *vibr = container_of(work, struct mt_vibr, vibr_work);

	if (atomic_read(&vibr->vibr_state) == 0)
		vibr_Disable();
	else
		vibr_Enable();
}

static void vibrator_enable(unsigned int dur, unsigned int activate)
{
	unsigned long flags;
	struct vibrator_hw *hw = mt_get_cust_vibrator_hw();

	spin_lock_irqsave(&g_mt_vib->vibr_lock, flags);
	hrtimer_cancel(&g_mt_vib->vibr_timer);
	pr_debug(VIB_TAG "cancel hrtimer, cust:%dms, value:%u, shutdown:%d\n",
			hw->vib_timer, dur, g_mt_vib->shutdown_flag);

	if (activate == 0 || g_mt_vib->shutdown_flag == 1) {
		atomic_set(&g_mt_vib->vibr_state, 0);
	} else {
#ifdef CUST_VIBR_LIMIT
		if (dur > hw->vib_limit && dur < hw->vib_timer)
#else
		if (dur >= 10 && dur < hw->vib_timer)
#endif
			dur = hw->vib_timer;

		dur = (dur > 15000 ? 15000 : dur);
		atomic_set(&g_mt_vib->vibr_state, 1);
		hrtimer_start(&g_mt_vib->vibr_timer,
			      ktime_set(dur / 1000, (dur % 1000) * 1000000),
			      HRTIMER_MODE_REL);
	}
	spin_unlock_irqrestore(&g_mt_vib->vibr_lock, flags);
	queue_work(g_mt_vib->vibr_queue, &g_mt_vib->vibr_work);
}

static void vibrator_oc_handler(void)
{
	pr_debug(VIB_TAG "vibrator_oc_handler: disable vibr due to oc intr happened\n");
	vibrator_enable(0, 0);
}

static enum hrtimer_restart vibrator_timer_func(struct hrtimer *timer)
{
	struct mt_vibr *vibr = container_of(timer, struct mt_vibr, vibr_timer);

	atomic_set(&vibr->vibr_state, 0);
	queue_work(vibr->vibr_queue, &vibr->vibr_work);
	return HRTIMER_NORESTART;
}

static const struct of_device_id vibr_of_ids[] = {
	{ .compatible = "mediatek,vibrator", },
	{}
};

static atomic_t vib_state;

static ssize_t vibr_activate_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", atomic_read(&g_mt_vib->vibr_state));
}

static ssize_t vibr_activate_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t size)
{
	unsigned int activate, dur;
	ssize_t ret;

	ret = kstrtouint(buf, 10, &activate);
	if (ret) {
		pr_err(VIB_TAG "set activate fail\n");
		return ret;
	}
	dur = atomic_read(&g_mt_vib->vibr_dur);
	vibrator_enable(dur, activate);
	ret = size;
	return ret;
}

static ssize_t vibr_state_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", atomic_read(&vib_state));
}

static ssize_t vibr_state_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t size)
{
	unsigned int state;
	ssize_t ret;

	ret = kstrtouint(buf, 10, &state);
	if (ret) {
		pr_err(VIB_TAG "set state fail\n");
		return ret;
	}
	atomic_set(&vib_state, state);

	ret = size;
	return ret;
}
static ssize_t vibr_duration_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t size)
{
	unsigned int duration;
	ssize_t ret;

	ret = kstrtouint(buf, 10, &duration);
	if (ret) {
		pr_err(VIB_TAG "set duration fail\n");
		return ret;
	}

	atomic_set(&g_mt_vib->vibr_dur, duration);
	ret = size;
	return ret;
}

static DEVICE_ATTR(activate, 0644, vibr_activate_show, vibr_activate_store);
static DEVICE_ATTR(state, 0644, vibr_state_show, vibr_state_store);
static DEVICE_ATTR(duration, 0644, NULL, vibr_duration_store);

static struct attribute *activate_attrs[] = {
	&dev_attr_activate.attr,
	NULL,
};

static struct attribute *state_attrs[] = {
	&dev_attr_state.attr,
	NULL,
};

static struct attribute *duration_attrs[] = {
	&dev_attr_duration.attr,
	NULL,
};

static struct attribute_group activate_group = {
	.attrs = activate_attrs,
};

static struct attribute_group state_group = {
	.attrs = state_attrs,
};

static struct attribute_group duration_group = {
	.attrs = duration_attrs,
};

static const struct attribute_group *vibr_group[] = {
	&activate_group,
	&state_group,
	&duration_group,
	NULL
};

static struct led_classdev led_vibr = {
	.name		= "vibrator",
	.groups		= vibr_group,
};

static int vib_probe(struct platform_device *pdev)
{
	int ret = 0;
	struct mt_vibr *vibr;

	init_vibr_oc_handler(vibrator_oc_handler);

	vibr = devm_kzalloc(&pdev->dev, sizeof(*vibr), GFP_KERNEL);
	if (!vibr)
		return -ENOMEM;

	ret = devm_led_classdev_register(&pdev->dev, &led_vibr);
	if (ret < 0) {
		pr_err(VIB_TAG "led class register fail\n");
		return ret;
	}

	vibr->vibr_queue = create_singlethread_workqueue(VIB_DEVICE);
	if (!vibr->vibr_queue) {
		pr_err(VIB_TAG "unable to create workqueue\n");
		return -ENODATA;
	}

	INIT_WORK(&vibr->vibr_work, update_vibrator);
	spin_lock_init(&vibr->vibr_lock);
	vibr->shutdown_flag = 0;
	atomic_set(&vibr->vibr_state, 0);
	hrtimer_init(&vibr->vibr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	vibr->vibr_timer.function = vibrator_timer_func;

	dev_set_drvdata(&pdev->dev, vibr);
	g_mt_vib = vibr;
	init_cust_vibrator_dtsi(pdev);
	vibr_power_set();

	pr_debug(VIB_TAG "probe done\n");

	return 0;
}

static int vib_remove(struct platform_device *pdev)
{
	struct mt_vibr *vibr = dev_get_drvdata(&pdev->dev);

	cancel_work_sync(&vibr->vibr_work);
	hrtimer_cancel(&vibr->vibr_timer);
	devm_led_classdev_unregister(&pdev->dev, &led_vibr);

	return 0;
}

static void vib_shutdown(struct platform_device *pdev)
{
	unsigned long flags;
	struct mt_vibr *vibr = dev_get_drvdata(&pdev->dev);

	pr_debug(VIB_TAG "shutdown: enter!\n");
	spin_lock_irqsave(&vibr->vibr_lock, flags);
	vibr->shutdown_flag = 1;
	if (atomic_read(&vibr->vibr_state)) {
		pr_debug(VIB_TAG "vib_shutdown: vibrator will disable\n");
		atomic_set(&vibr->vibr_state, 0);
		spin_unlock_irqrestore(&vibr->vibr_lock, flags);
		vibr_Disable();
		return;
	}
	spin_unlock_irqrestore(&vibr->vibr_lock, flags);
}


static struct platform_driver vibrator_driver = {
	.probe = vib_probe,
	.remove = vib_remove,
	.shutdown = vib_shutdown,
	.driver = {
			.name = VIB_DEVICE,
			.owner = THIS_MODULE,
#ifdef CONFIG_OF
			.of_match_table = vibr_of_ids,
#endif
		   },
};

static int vib_mod_init(void)
{
	s32 ret;

	ret = platform_driver_register(&vibrator_driver);
	if (ret) {
		pr_err(VIB_TAG "Unable to register driver (%d)\n", ret);
		return ret;
	}
	pr_debug(VIB_TAG "init Done\n");

	return 0;
}

static void vib_mod_exit(void)
{
	pr_debug(VIB_TAG "vib_mod_exit Done\n");
}

module_init(vib_mod_init);
module_exit(vib_mod_exit);
MODULE_AUTHOR("MediaTek Inc.");
MODULE_DESCRIPTION("MTK Vibrator Driver (VIB)");
MODULE_LICENSE("GPL");

這個代碼還是挺長的,逐語句分析太麻煩也沒有必要,代碼分爲以下幾個重要部分:

  • 驅動初始化,完成platform驅動的註冊
  • 驅動、設備匹配後執行probe函數(此處是重點,後面會着重分析)
  • 設備屬性文件的生成,讀寫函數的實現與綁定
  • 與控制vibrator相關的工作隊列的任務函數,定時器回調函數
  • 驅動的remove、shutdown函數

我們首先分析probe函數,它主要工作爲

  • 定義過流中斷服務函數(該中斷會關閉vibrator)
  • 爲私有結構體分配內存
  • 註冊一個leds類的設備(原因是控制類似,歸屬一類設備,可以省去很多相似的定義,生成的設備節點會在/sys/class/leds下)
  • 定義工作隊列和工作隊列的任務
  • 初始化自旋鎖和原子量
  • 初始化hrtimer(內核提供的高精度定時器)並設置定時器回調函數
  • 將驅動的私有結構體設置到設備中
  • 讀取設備樹數據初始化PMIC

接着我們分析一下設備節點屬性文件相關內容

  • 使用DEVICE_ATTR來定義屬性文件並設置權限、讀寫函數
  • 定義attribute_group並綁定attribute_group和attribute數組
  • 定義led_classdev類型的led_vibr,並設置它的名字和屬性集(該設備將在probe函數的leds類設備註冊中使用)

當系統RUN起來後,會在/sys/class/leds/vibrator 下生成三個設備節點(其實不止三個,leds類還有一些設備節點但是對於我們vibrator來說只關注這三個即可),他們的含義如下

名稱 讀操作 寫操作
activate 獲取馬達狀態 激活馬達
state 獲取馬達狀態 未定義
duration 未定義 設置震動時長

通過對這三個屬性文件的讀寫就可獲取馬達狀態並且完成馬達的控制

我們再分析一下驅動的鎖機制

  • 驅動使用了自旋鎖和原子量來保證程序的互斥
  • 原子量是Vibrator的狀態變量
  • 自旋鎖的上鎖與解鎖使用spin_lock_irqsave和spin_unlock_irqrestore,會在加鎖的時候保護當前終端的狀態

hrtimer的分析:
對於這個內核模塊我會再寫一篇博客來分析,簡單描述下,這是一個使用紅黑樹來管理的直接操作硬件定時器中斷的可以實現ns級定時的高精度定時器,定時控制精準

關於馬達的控制流程分析:

  • 馬達的控制函數爲vibrator_enable函數傳入震動時長和是否震動
  • 首先要加鎖並且取消現有的hrtimer定時器
  • 對傳入的參數進行檢測並對震動時長進行限幅
  • 設置一個震動時長的定時器並開啓定時器,開啓震動(通過將馬達狀態切換任務加入任務隊列)
  • 當定時結束後會執行回調函數,在回調函數中會關閉震動(同上)

爲什麼使用工作隊列

  • 工作隊列是一種異步執行機制,會在合適的時間執行隊列中的任務,只需要將任務加入到隊列即可,不會長時間持有CPU,工作隊列(workqueue)在驅動開發中經常使用
  • 在打開馬達時有一個3ms的延時操作,所以需要使用工作隊列異步執行

remove和shutdown分析

  • 區別在於remove需要對資源進行釋放和shutdown只是關閉馬達
  • 原因在於這兩個函數的執行時機,remove在設備拔出或者取消匹配時調用,shutdown在系統重啓或者關閉的時候調用

硬件相關代碼

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#ifdef CONFIG_MTK_PMIC_NEW_ARCH
#include <mt-plat/upmu_common.h>
#endif
#include "vibrator.h"

#define T    "vibrator"
struct vibrator_hw *pvib_cust;

#define OC_INTR_INIT_DELAY      (3)
void vibr_Enable_HW(void)
{
#ifdef CONFIG_MTK_PMIC_NEW_ARCH
	pmic_set_register_value(PMIC_RG_LDO_VIBR_EN, 1);
	mdelay(OC_INTR_INIT_DELAY);
	pmic_enable_interrupt(INT_VIBR_OC, 1, "vibr");
#endif
}

void vibr_Disable_HW(void)
{
#ifdef CONFIG_MTK_PMIC_NEW_ARCH
	pmic_enable_interrupt(INT_VIBR_OC, 0, "vibr");
	pmic_set_register_value(PMIC_RG_LDO_VIBR_EN, 0);
#endif
}

void init_vibr_oc_handler(void (*vibr_oc_func)(void))
{
#ifdef CONFIG_MTK_PMIC_NEW_ARCH
	pmic_register_interrupt_callback(INT_VIBR_OC, vibr_oc_func);
#endif
}

/******************************************
 * Set RG_VIBR_VOSEL	 Output voltage select
 *  hw->vib_vol:  Voltage selection
 * 4'b0000 :1.2V
 * 4'b0001 :1.3V
 * 4'b0010 :1.5V
 * 4'b0100 :1.8V
 * 4'b0101 :2.0V
 * 4'b1000 :2.7V
 * 4'b1001 :2.8V
 * 4'b1011 :3.0V
 * 4'b1101 :3.3V
 * ****************************************/
void init_cust_vibrator_dtsi(struct platform_device *pdev)
{
	int ret;

	if (pvib_cust == NULL) {
		pvib_cust = kmalloc(sizeof(struct vibrator_hw), GFP_KERNEL);
		if (pvib_cust == NULL) {
			pr_debug(T "%s kmalloc fail\n", __func__);
			return;
		}
		ret = of_property_read_u32(pdev->dev.of_node, "vib_timer",
			&(pvib_cust->vib_timer));
		if (!ret)
			pr_debug(T "vib_timer:%d\n", pvib_cust->vib_timer);
		else
			pvib_cust->vib_timer = 25;
#ifdef CUST_VIBR_LIMIT
		ret = of_property_read_u32(pdev->dev.of_node, "vib_limit",
			&(pvib_cust->vib_limit));
		if (!ret)
			pr_debug(T "vib_limit : %d\n", pvib_cust->vib_limit);
		else
			pvib_cust->vib_limit = 9;
#endif

#ifdef CUST_VIBR_VOL
		ret = of_property_read_u32(pdev->dev.of_node, "vib_vol",
			&(pvib_cust->vib_vol));
		if (!ret)
			pr_debug(T "vib_vol: %d\n", pvib_cust->vib_vol);
		else
			pvib_cust->vib_vol = 0x05;
#endif
		pr_debug(T "pvib_cust = %d, %d, %d\n",
			pvib_cust->vib_timer, pvib_cust->vib_limit,
					pvib_cust->vib_vol);
	}
}

struct vibrator_hw *get_cust_vibrator_dtsi(void)
{
	if (pvib_cust == NULL)
		pr_debug(T "%s fail, pvib_cust is NULL\n", __func__);
	return pvib_cust;
}

void vibr_power_set(void)
{
#ifdef CUST_VIBR_VOL
	struct vibrator_hw *hw = get_cust_vibrator_dtsi();

	if (hw != NULL) {
		pr_debug(T "vibr_init: set voltage = %d\n", hw->vib_vol);
#ifdef CONFIG_MTK_PMIC_NEW_ARCH
		pmic_set_register_value(PMIC_RG_VIBR_VOSEL, hw->vib_vol);
#endif
	} else {
		pr_debug("vibr_init: can not get  dtsi!\n");
	}
#endif
}

struct vibrator_hw *mt_get_cust_vibrator_hw(void)
{
	struct vibrator_hw *hw = get_cust_vibrator_dtsi();
	return hw;
}

硬件相關的代碼主要包含幾個部分

  • 設備樹讀取設置函數init_cust_vibrator_dtsi
  • 馬達開關函數vibr_Enable_HW和vibr_Disable_HW
  • 輸出電壓設置函數
  • 過流中斷設置函數

這個代碼很簡單不用做過多分析,vibr_Enable_HW中有一個3MS的延時,這就是爲什麼在驅動中需要使用工作隊列

4: HAL 部分

HAL (Hardware Abstraction Layer), 又稱爲“硬件抽象層”。在Linux驅動中,我們已經將馬達設爲映射爲文件了;而該HAL層的存在的意義,就是“對設備文件進行操作,從而相當於硬件進行操作”。HAL層的作用,一是操作硬件設備,二是操作接口封裝,外界能方便的使用HAL提供的接口直接操作硬件設備。
代碼在hardware/libhardware/modules/vibrator/vibrator.c

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

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

#include <log/log.h>

#define TIMEOUT_STR_LEN         20

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

static bool device_exists(const char *file) {
    int fd;

    fd = TEMP_FAILURE_RETRY(open(file, O_RDWR));
    if(fd < 0) {
        return false;
    }

    close(fd);
    return true;
}

static bool vibra_exists() {
    return device_exists(THE_DEVICE);
}

static int write_value(const char *file, const char *value)
{
    int to_write, written, ret, fd;

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

    to_write = strlen(value) + 1;
    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 vibrator_on() again */
        ret = -EAGAIN;
    } else {
        ret = 0;
    }

    errno = 0;
    close(fd);

    return ret;
}

static int sendit(unsigned int timeout_ms)
{
    char value[TIMEOUT_STR_LEN]; /* large enough for millions of years */

    snprintf(value, sizeof(value), "%u", timeout_ms);
    return write_value(THE_DEVICE, value);
}

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 const char LED_DEVICE[] = "/sys/class/leds/vibrator";

static int write_led_file(const char *file, const char *value)
{
    char file_str[50];

    snprintf(file_str, sizeof(file_str), "%s/%s", LED_DEVICE, file);
    return write_value(file_str, value);
}

static bool vibra_led_exists()
{
    char file_str[50];

    snprintf(file_str, sizeof(file_str), "%s/%s", LED_DEVICE, "activate");
    return device_exists(file_str);
}

static int vibra_led_on(vibrator_device_t* vibradev __unused, unsigned int timeout_ms)
{
    int ret;
    char value[TIMEOUT_STR_LEN]; /* large enough for millions of years */

    ret = write_led_file("state", "1");
    if (ret)
        return ret;

    snprintf(value, sizeof(value), "%u\n", timeout_ms);
    ret = write_led_file("duration", value);
    if (ret)
        return ret;

    return write_led_file("activate", "1");
}

static int vibra_led_off(vibrator_device_t* vibradev __unused)
{
    return write_led_file("activate", "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) {
    bool use_led;

    if (vibra_exists()) {
        ALOGD("Vibrator using timed_output");
        use_led = false;
    } else if (vibra_led_exists()) {
        ALOGD("Vibrator using LED trigger");
        use_led = true;
    } else {
        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;

    if (use_led) {
        vibradev->vibrator_on = vibra_led_on;
        vibradev->vibrator_off = vibra_led_off;
    } else {
        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,
};

可以看出HAL層的代碼有兩種控制Vibrator的方式

  • 讀寫"/sys/class/timed_output/vibrator/enable"
  • 讀寫"/sys/class/leds/vibrator"下的屬性文件

很明顯我們選擇了後者
這個文件中定義了控制Vibrator的函數,open、close、on、off等,和我們在做Linux驅動時的用戶空間程序沒什麼區別

完成了HAL,接下來就是連接C和JAVA的JNI層了

5: JNI部分

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

JNI是Java中一種技術,它存在的意義,是保證本地代碼(C/C++代碼)能在任何Java虛擬機下工作。簡單點說,Java通過JNI接口,能夠調用到C/C++代碼。

JNI的代碼在frameworks/base/services/core/jni/com_android_server_VibratorService.cpp

#define LOG_TAG "VibratorService"

#include <android/hardware/vibrator/1.3/IVibrator.h>
#include <android/hardware/vibrator/BnVibratorCallback.h>
#include <android/hardware/vibrator/IVibrator.h>
#include <binder/IServiceManager.h>

#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include "android_runtime/AndroidRuntime.h"
#include "core_jni_helpers.h"

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

#include <inttypes.h>
#include <stdio.h>

using android::hardware::Return;
using android::hardware::Void;
using android::hardware::vibrator::V1_0::EffectStrength;
using android::hardware::vibrator::V1_0::Status;
using android::hardware::vibrator::V1_1::Effect_1_1;

namespace V1_0 = android::hardware::vibrator::V1_0;
namespace V1_1 = android::hardware::vibrator::V1_1;
namespace V1_2 = android::hardware::vibrator::V1_2;
namespace V1_3 = android::hardware::vibrator::V1_3;
namespace aidl = android::hardware::vibrator;

namespace android {

static jmethodID sMethodIdOnComplete;

static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) ==
                static_cast<uint8_t>(aidl::EffectStrength::LIGHT));
static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) ==
                static_cast<uint8_t>(aidl::EffectStrength::MEDIUM));
static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) ==
                static_cast<uint8_t>(aidl::EffectStrength::STRONG));

static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) ==
                static_cast<uint8_t>(aidl::Effect::CLICK));
static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) ==
                static_cast<uint8_t>(aidl::Effect::DOUBLE_CLICK));
static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) ==
                static_cast<uint8_t>(aidl::Effect::TICK));
static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) ==
                static_cast<uint8_t>(aidl::Effect::THUD));
static_assert(static_cast<uint8_t>(V1_3::Effect::POP) ==
                static_cast<uint8_t>(aidl::Effect::POP));
static_assert(static_cast<uint8_t>(V1_3::Effect::HEAVY_CLICK) ==
                static_cast<uint8_t>(aidl::Effect::HEAVY_CLICK));
static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_1) ==
                static_cast<uint8_t>(aidl::Effect::RINGTONE_1));
static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_2) ==
                static_cast<uint8_t>(aidl::Effect::RINGTONE_2));
static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) ==
                static_cast<uint8_t>(aidl::Effect::RINGTONE_15));
static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
                static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));

class VibratorCallback {
    public:
        VibratorCallback(JNIEnv *env, jobject vibration) :
        mVibration(MakeGlobalRefOrDie(env, vibration)) {}

        ~VibratorCallback() {
            JNIEnv *env = AndroidRuntime::getJNIEnv();
            env->DeleteGlobalRef(mVibration);
        }

        void onComplete() {
            auto env = AndroidRuntime::getJNIEnv();
            env->CallVoidMethod(mVibration, sMethodIdOnComplete);
        }

    private:
        jobject mVibration;
};

class AidlVibratorCallback : public aidl::BnVibratorCallback {
  public:
    AidlVibratorCallback(JNIEnv *env, jobject vibration) :
    mCb(env, vibration) {}

    binder::Status onComplete() override {
        mCb.onComplete();
        return binder::Status::ok(); // oneway, local call
    }

  private:
    VibratorCallback mCb;
};

static constexpr int NUM_TRIES = 2;

template<class R>
inline R NoneStatus() {
    using ::android::hardware::Status;
    return Status::fromExceptionCode(Status::EX_NONE);
}

template<>
inline binder::Status NoneStatus() {
    using binder::Status;
    return Status::fromExceptionCode(Status::EX_NONE);
}

// Creates a Return<R> with STATUS::EX_NULL_POINTER.
template<class R>
inline R NullptrStatus() {
    using ::android::hardware::Status;
    return Status::fromExceptionCode(Status::EX_NULL_POINTER);
}

template<>
inline binder::Status NullptrStatus() {
    using binder::Status;
    return Status::fromExceptionCode(Status::EX_NULL_POINTER);
}

template <typename I>
sp<I> getService() {
    return I::getService();
}

template <>
sp<aidl::IVibrator> getService() {
    return waitForVintfService<aidl::IVibrator>();
}

template <typename I>
sp<I> tryGetService() {
    return I::tryGetService();
}

template <>
sp<aidl::IVibrator> tryGetService() {
    return checkVintfService<aidl::IVibrator>();
}

template <typename I>
class HalWrapper {
  public:
    static std::unique_ptr<HalWrapper> Create() {
        // Assume that if getService returns a nullptr, HAL is not available on the
        // device.
        auto hal = getService<I>();
        return hal ? std::unique_ptr<HalWrapper>(new HalWrapper(std::move(hal))) : nullptr;
    }

    // Helper used to transparently deal with the vibrator HAL becoming unavailable.
    template<class R, class... Args0, class... Args1>
    R call(R (I::* fn)(Args0...), Args1&&... args1) {
        // Return<R> doesn't have a default constructor, so make a Return<R> with
        // STATUS::EX_NONE.
        R ret{NoneStatus<R>()};

        // Note that ret is guaranteed to be changed after this loop.
        for (int i = 0; i < NUM_TRIES; ++i) {
            ret = (mHal == nullptr) ? NullptrStatus<R>()
                    : (*mHal.*fn)(std::forward<Args1>(args1)...);

            if (ret.isOk()) {
                break;
            }

            ALOGE("Failed to issue command to vibrator HAL. Retrying.");

            // Restoring connection to the HAL.
            mHal = tryGetService<I>();
        }
        return ret;
    }

  private:
    HalWrapper(sp<I> &&hal) : mHal(std::move(hal)) {}

  private:
    sp<I> mHal;
};

template <typename I>
static auto getHal() {
    static auto sHalWrapper = HalWrapper<I>::Create();
    return sHalWrapper.get();
}

template<class R, class I, class... Args0, class... Args1>
R halCall(R (I::* fn)(Args0...), Args1&&... args1) {
    auto hal = getHal<I>();
    return hal ? hal->call(fn, std::forward<Args1>(args1)...) : NullptrStatus<R>();
}

template<class R>
bool isValidEffect(jlong effect) {
    if (effect < 0) {
        return false;
    }
    R val = static_cast<R>(effect);
    auto iter = hardware::hidl_enum_range<R>();
    return val >= *iter.begin() && val <= *std::prev(iter.end());
}

static void vibratorInit(JNIEnv *env, jclass clazz)
{
    if (auto hal = getHal<aidl::IVibrator>()) {
        // IBinder::pingBinder isn't accessible as a pointer function
        // but getCapabilities can serve the same purpose
        int32_t cap;
        hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk();
    } else {
        halCall(&V1_0::IVibrator::ping).isOk();
    }
}

static jboolean vibratorExists(JNIEnv* /* env */, jclass /* clazz */)
{
    bool ok;

    if (auto hal = getHal<aidl::IVibrator>()) {
        // IBinder::pingBinder isn't accessible as a pointer function
        // but getCapabilities can serve the same purpose
        int32_t cap;
        ok = hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk();
    } else {
        ok = halCall(&V1_0::IVibrator::ping).isOk();
    }
    return ok ? JNI_TRUE : JNI_FALSE;
}

static void vibratorOn(JNIEnv* /* env */, jclass /* clazz */, jlong timeout_ms)
{
    if (auto hal = getHal<aidl::IVibrator>()) {
        auto status = hal->call(&aidl::IVibrator::on, timeout_ms, nullptr);
        if (!status.isOk()) {
            ALOGE("vibratorOn command failed: %s", status.toString8().string());
        }
    } else {
        Status retStatus = halCall(&V1_0::IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR);
        if (retStatus != Status::OK) {
            ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
        }
    }
}

static void vibratorOff(JNIEnv* /* env */, jclass /* clazz */)
{
    if (auto hal = getHal<aidl::IVibrator>()) {
        auto status = hal->call(&aidl::IVibrator::off);
        if (!status.isOk()) {
            ALOGE("vibratorOff command failed: %s", status.toString8().string());
        }
    } else {
        Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR);
        if (retStatus != Status::OK) {
            ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
        }
    }
}

static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jclass) {
    if (auto hal = getHal<aidl::IVibrator>()) {
        int32_t cap = 0;
        if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) {
            return false;
        }
        return (cap & aidl::IVibrator::CAP_AMPLITUDE_CONTROL) > 0;
    } else {
        return halCall(&V1_0::IVibrator::supportsAmplitudeControl).withDefault(false);
    }
}

static void vibratorSetAmplitude(JNIEnv*, jclass, jint amplitude) {
    if (auto hal = getHal<aidl::IVibrator>()) {
        auto status = hal->call(&aidl::IVibrator::IVibrator::setAmplitude, static_cast<float>(amplitude) / UINT8_MAX);
        if (!status.isOk()) {
            ALOGE("Failed to set vibrator amplitude: %s", status.toString8().string());
        }
    } else {
        Status status = halCall(&V1_0::IVibrator::setAmplitude, static_cast<uint32_t>(amplitude))
            .withDefault(Status::UNKNOWN_ERROR);
        if (status != Status::OK) {
            ALOGE("Failed to set vibrator amplitude (%" PRIu32 ").",
                  static_cast<uint32_t>(status));
        }
    }
}

static jboolean vibratorSupportsExternalControl(JNIEnv*, jclass) {
    if (auto hal = getHal<aidl::IVibrator>()) {
        int32_t cap = 0;
        if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) {
            return false;
        }
        return (cap & aidl::IVibrator::CAP_EXTERNAL_CONTROL) > 0;
    } else {
        return halCall(&V1_3::IVibrator::supportsExternalControl).withDefault(false);
    }
}

static void vibratorSetExternalControl(JNIEnv*, jclass, jboolean enabled) {
    if (auto hal = getHal<aidl::IVibrator>()) {
        auto status = hal->call(&aidl::IVibrator::IVibrator::setExternalControl, enabled);
        if (!status.isOk()) {
            ALOGE("Failed to set vibrator external control: %s", status.toString8().string());
        }
    } else {
        Status status = halCall(&V1_3::IVibrator::setExternalControl, static_cast<uint32_t>(enabled))
            .withDefault(Status::UNKNOWN_ERROR);
        if (status != Status::OK) {
            ALOGE("Failed to set vibrator external control (%" PRIu32 ").",
                static_cast<uint32_t>(status));
        }
    }
}

static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong strength,
                                   jobject vibration) {
    if (auto hal = getHal<aidl::IVibrator>()) {
        int32_t lengthMs;
        sp<AidlVibratorCallback> effectCallback = new AidlVibratorCallback(env, vibration);
        aidl::Effect effectType(static_cast<aidl::Effect>(effect));
        aidl::EffectStrength effectStrength(static_cast<aidl::EffectStrength>(strength));

        auto status = hal->call(&aidl::IVibrator::perform, effectType, effectStrength, effectCallback, &lengthMs);
        if (!status.isOk()) {
            if (status.exceptionCode() != binder::Status::EX_UNSUPPORTED_OPERATION) {
                ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32
                        ": %s", static_cast<int64_t>(effect), static_cast<int32_t>(strength), status.toString8().string());
            }
            return -1;
        }
        return lengthMs;
    } else {
        Status status;
        uint32_t lengthMs;
        auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) {
            status = retStatus;
            lengthMs = retLengthMs;
        };
        EffectStrength effectStrength(static_cast<EffectStrength>(strength));

        Return<void> ret;
        if (isValidEffect<V1_0::Effect>(effect)) {
            ret = halCall(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(effect),
                    effectStrength, callback);
        } else if (isValidEffect<Effect_1_1>(effect)) {
            ret = halCall(&V1_1::IVibrator::perform_1_1, static_cast<Effect_1_1>(effect),
                            effectStrength, callback);
        } else if (isValidEffect<V1_2::Effect>(effect)) {
            ret = halCall(&V1_2::IVibrator::perform_1_2, static_cast<V1_2::Effect>(effect),
                            effectStrength, callback);
        } else if (isValidEffect<V1_3::Effect>(effect)) {
            ret = halCall(&V1_3::IVibrator::perform_1_3, static_cast<V1_3::Effect>(effect),
                            effectStrength, callback);
        } else {
            ALOGW("Unable to perform haptic effect, invalid effect ID (%" PRId32 ")",
                    static_cast<int32_t>(effect));
            return -1;
        }

        if (!ret.isOk()) {
            ALOGW("Failed to perform effect (%" PRId32 ")", static_cast<int32_t>(effect));
            return -1;
        }

        if (status == Status::OK) {
            return lengthMs;
        } else if (status != Status::UNSUPPORTED_OPERATION) {
            // Don't warn on UNSUPPORTED_OPERATION, that's a normal event and just means the motor
            // doesn't have a pre-defined waveform to perform for it, so we should just give the
            // opportunity to fall back to the framework waveforms.
            ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32
                    ", error=%" PRIu32 ").", static_cast<int64_t>(effect),
                    static_cast<int32_t>(strength), static_cast<uint32_t>(status));
        }
    }

    return -1;
}

static jlong vibratorGetCapabilities(JNIEnv*, jclass) {
    if (auto hal = getHal<aidl::IVibrator>()) {
        int32_t cap = 0;
        if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) {
            return 0;
        }
        return cap;
    }

    return 0;
}

static void vibratorAlwaysOnEnable(JNIEnv* env, jclass, jlong id, jlong effect, jlong strength) {
    auto status = halCall(&aidl::IVibrator::alwaysOnEnable, id,
            static_cast<aidl::Effect>(effect), static_cast<aidl::EffectStrength>(strength));
    if (!status.isOk()) {
        ALOGE("vibratortAlwaysOnEnable command failed (%s).", status.toString8().string());
    }
}

static void vibratorAlwaysOnDisable(JNIEnv* env, jclass, jlong id) {
    auto status = halCall(&aidl::IVibrator::alwaysOnDisable, id);
    if (!status.isOk()) {
        ALOGE("vibratorAlwaysOnDisable command failed (%s).", status.toString8().string());
    }
}

static const JNINativeMethod method_table[] = {
    { "vibratorExists", "()Z", (void*)vibratorExists },
    { "vibratorInit", "()V", (void*)vibratorInit },
    { "vibratorOn", "(J)V", (void*)vibratorOn },
    { "vibratorOff", "()V", (void*)vibratorOff },
    { "vibratorSupportsAmplitudeControl", "()Z", (void*)vibratorSupportsAmplitudeControl},
    { "vibratorSetAmplitude", "(I)V", (void*)vibratorSetAmplitude},
    { "vibratorPerformEffect", "(JJLcom/android/server/VibratorService$Vibration;)J",
        (void*)vibratorPerformEffect},
    { "vibratorSupportsExternalControl", "()Z", (void*)vibratorSupportsExternalControl},
    { "vibratorSetExternalControl", "(Z)V", (void*)vibratorSetExternalControl},
    { "vibratorGetCapabilities", "()J", (void*)vibratorGetCapabilities},
    { "vibratorAlwaysOnEnable", "(JJJ)V", (void*)vibratorAlwaysOnEnable},
    { "vibratorAlwaysOnDisable", "(J)V", (void*)vibratorAlwaysOnDisable},
};

int register_android_server_VibratorService(JNIEnv *env)
{
    sMethodIdOnComplete = GetMethodIDOrDie(env,
            FindClassOrDie(env, "com/android/server/VibratorService$Vibration"),
            "onComplete", "()V");
    return jniRegisterNativeMethods(env, "com/android/server/VibratorService",
            method_table, NELEM(method_table));
}

};

這個代碼幹了以下幾件事

  • 對HAL的接口再進行了一些封裝
  • 使用JNINativeMethod列表將Java層和HAL層的代碼聯繫起來

關於JNINativeMethod
結構體

typedef struct {  
    const char* name;  
    const char* signature;  
    void* fnPtr;  
} JNINativeMethod;

第一個變量name是Java中函數的名字。
第二個變量signature,用字符串是描述了Java中函數的參數和返回值
第三個變量fnPtr是函數指針,指向native函數。前面都要接 (void *)
第一個變量與第三個變量是對應的,一個是java層方法名,對應着第三個參數的native方法名字

參數和返回值還有一些簡寫對應方式,這裏就不做介紹了

JNI層提供JAVA接口以後就是Application Framework的任務了

6: Application Framework部分

應用層操作馬達,是通過馬達服務進行操作的。而馬達服務是通過aidl實現的,aidl是Android進程間的通信方式
主要涉及的文件有

frameworks/base/core/java/android/os/SystemVibrator.java
frameworks/base/core/java/android/os/Vibrator.java
frameworks/base/services/core/java/com/android/server/VibratorService.java
frameworks/base/core/java/android/os/IVibratorService.aidl
frameworks/base/services/java/com/android/server/SystemServer.java

這裏的代碼較多,就不貼代碼了,介紹一下各個文件的作用以及大致的工作流程

  • SystemServer.java
    它是系統服務,作用是啓動、管理系統服務,包括“馬達服務、Wifi服務、Activity管理服務”等等。
    SystemServer是通過Zygote啓動的,而Zygote又是在init中啓動的,init則是kernel加載完畢之後啓動的第一個進程。在這裏,我們只需要知道“SystemServer是用來啓動/管理馬達服務即可。
  • IVibratorService.aidl
    它是馬達服務對應的aidl配置文件。我們在aidl中定義了其它進程可以訪問的外部接口;然後再通過VibratorService.java實現這些接口。
  • VibratorService.java
    它是馬達服務對應的aidl接口的實現程序。它實現IVibratorService.aidl的接口,從而實現馬達服務;它的函數接口,是通過調用JNI層對應的馬達控制函數來實現的。
  • Vibrator.java
    它是馬達服務開放給應用層的調用類。理論上講,我們完全可以通過aidl直接調用馬達服務,而不需要Vibrator.java類。但是!既然它存在,就肯定有它的理由。事實的確如此,Google之所以這麼做。有以下幾個原因:
    第一,提供統一而且方便的服務調用方式。這裏的“統一”,是指和所有其它的系統服務一樣,我們調用服務時,需先通過getSystemService()獲取服務,然後再調用服務的函數接口。這裏的“方便”,是指若我們直接通過aidl調用,操作比較繁瑣(若你用過aidl就會知道,需要先實現ServiceConnection接口以獲取IBinder對象,然後再通過IBinder對象調用aidl的接口); 而Vibrator.java封裝之後的接口,將許多細節都隱藏了,非常便於應用者調用!
    第二,基於安全的考慮。Vibrator.java封裝隱藏了許多細節,而這些都是應用開發者不必要知道的。
    第三,Vibrator是抽象類。它便於我們支持不同類型的馬達:包括“將馬達直接映射到文件”以及“將馬達註冊到輸入子系統”中。
  • SystemVibrator.java
    它是Vibrator.java的子類,實現了馬達的服務接口。

以上就是這些文件的作用,當然只看這些還是遠遠不夠的,還是得“Read The Fucking Source Code”
這些只是總體介紹總結的作用

7: 應用部分

馬達權限

調用馬達服務,需要在manifest中添加相應的權限

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

我自己還沒有寫過JAVA APP,這是找的別人的代碼來分析的

package com.test;

import android.app.Activity;
import android.os.Bundle;
import android.os.Vibrator;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ToggleButton;
import android.util.Log;

public class VibratorTest extends Activity {
    private static final String TAG = "skywang-->VibratorTest";

    private Vibrator mVibrator;
    private Button mOnce = null;
    private ToggleButton mEndless = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // 獲取震動馬達服務
        mVibrator= (Vibrator) getSystemService(VIBRATOR_SERVICE);

        mOnce = (Button) findViewById(R.id.vib_once);
        mOnce.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                //震動指定時間
                mVibrator.vibrate(100);
            }
        });

        mEndless = (ToggleButton) findViewById(R.id.vib_endless);
        mEndless.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mEndless.isChecked()) {
                    //等待100ms後,按數組所給數值間隔震動;其後爲重複次數,-1爲不重複,0一直震動
                    mVibrator.vibrate(new long[]{100,20,100,40,100,60}, 0);
                } else {
                    // 取消震動
                    mVibrator.cancel();
                }
            }
        });

    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mVibrator != null)
            mVibrator= null;
    }
}

馬達有兩種控制模式

  • mVibrator.vibrate(100)直接指定震動時間
  • mVibrator.vibrate(new long[]{100,20,100,40,100,60}, 0)按照傳入的數組做開啓和關閉

總結

以上就是“核心科技”Vibrator從硬件到APP的全部內容,我對Android部分的理解還遠遠不夠了,僅是管中窺豹而已,要理解整個體系還需要下很多功夫。
Android這一整套架構其實還是很強大的,其實我們可以看到,從HAL開始的所有代碼甚至是可以不修改的,AOSP已經設計好了整個架構,常用的模塊已經寫好了HAL、JNI、Application Framework層所有的東西,如果你想做自己的手機,要做的就是內核驅動部分,按照HAL提供的框架來實現底層接口,可以說已經大大減少了工作量,只有當有特殊的要求時纔會去修改那些,好像這樣子想起來做一個手機並沒有多難嘛,設計PCB,然後照着示例的內核把驅動實現以下就可以,如果願意可以自己定製UI,如果懶得定製的話直接使用原生UI。但是當前的市場卻不是這樣的,慢慢的小公司都走向了衰落,只有大的公司才能生存下去,魅族、錘子這些小衆的品牌也曾有很不錯的軟硬件體驗但是卻越來越沒有市場,這些倒是令人想不到的,可能做手機的難點並不在系統而在於供應鏈、市場等等技術以外的東西吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章