分享好友 资讯首页 资讯分类 切换频道
Android手机“核心科技”---Vibrator(马达)驱动分析手机马达「Android手机“核心科技”---Vibrator(马达)驱动分析」
2025-01-12 00:01  浏览:72

我的博客已经断更很久了,因为疫情的原因没能开学,也无法去公司报道实习,在家十分的颓废,学习的时间零零散散,更是没有什么时间来写博客的@@(铁废物)。最近疫情好转,自己也来深圳这边某知名IC厂商(同样也让人喊YES的那个)实习,在手机部门做一些驱动相关内容的工作,以前有做过Linux驱动开发,安卓以前没有接触过,在公司就慢慢开始学习,自己下班回家后后也再分析分析代码,写写博客。
因为自己也是一个初学者,在分析上有什么不正确的地方也希望大家可以指正
注意:这些博客没有任何从公司电脑上拷贝的资料,参照的代码为Github的开源代码或者AOSP的代码,求生欲满满-.-

Vibrator是振动器的意思,也可以被叫做马达,马达旋转或者做直线运动会产生振动。由于小米的科普(此处应该有些掌声)我们了解了手机马达的几种类别:普通转子马达(一般用于低端机)、币型转子马达(被小米嘲讽的嗡嗡嗡)、Y轴线性马达(形状类似币型转子但是它是做Y轴的直线运动)、X轴线性马达(苹果魅族等厂商的,做X轴线性运动

马达对手机的使用体验确实有所提升,好的振动反馈是顶级手机必备特性。
对于我们底层驱动开发人员来说,马达却是一个特别好的入门模块,因为马达的控制一般分为两类:PWM控制、ldo输出控制,后者所占的比例较多,一般只是由PMIC输出电压即可,而内核驱动部分、HAL部分、JNI部分、Application Framework部分相对很标准,十分适合用来理解Android驱动框架,体会如何在APP使用JAVA调用底层用C甚至汇编编写的驱动程序。

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

  • driversmiscmediatekvibratormt6779vibrator.c
  • driversmiscmediatekvibratormt6779vibrator.h
  • driversmiscmediatekvibratorvibrator_drv.c

DTS

  • archarm64bootdtsmediatekk79v1_64.dts

在这里插入图片描述
大体的框架如上图所示,当应用操作马达时,它会调用Application Framework层实现的马达调用类,并且这些调用是通过马达服务的(可以理解为一个进程,而马达服务又需要通过aidl实现,aidl是Android进程间的通信方式。在服务中对底层的操控需要使用一些与HAL层CPP函数相映射的JAVA函数,JNI层就是完成这个映射工作的。HAL硬件描述层是在用户空间对内核空间中驱动的使用,通过对Sysfs中的设备节点的读取和写入来完成马达状态的读取和控制。内核的驱动程序中完成对设备的操作,当驱动检测到设备时会在用户空间生成设备节点,定义对设备节点中属性文件的读写操作,同时也会根据设备树中的信息完成对设备的初始化。设备树是对底层硬件的描述,通过定义一个vibrator节点,在节点中定义电压等级、最短震动时间等属性,以供驱动的读取。硬件部分使用SPI与PMIC通信,通过对PMIC的读写就可以实现输出LDO控制vibrator以及接受vibrator的过流中断等。
这是对自顶向下对驱动框架的简单介绍,接下来我们自底向上逐步分析vibrator的驱动框架

PMIC与AP使用SPI连接,马达连接在PMIC上,马达由一个LDO输出控制,输出与地之间接一个滤波电容,去除尖峰电压

设备树中的vibrator节点代码如下

 

这个包含用于与驱动匹配的compatible,以及电压等级、震动的时间限制等

kernel Driver部分包含两部分,与底层芯片相关的放在以AP命名的文件夹中,与底层实现不相关的不同平台是共用的,降低了代码维护的难度。
首先与硬件不相关的代码如下

 

这个代码还是挺长的,逐语句分析太麻烦也没有必要,代码分为以下几个重要部分

  • 驱动初始化,完成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在系统重启或者关闭的时候调用
 

硬件相关的代码主要包含几个部分

  • 设备树读取设置函数init_cust_vibrator_dtsi
  • 马达开关函数vibr_Enable_HW和vibr_Disable_HW
  • 输出电压设置函数
  • 过流中断设置函数

这个代码很简单不用做过多分析,vibr_Enable_HW中有一个3MS的延时,这就是为什么在驱动中需要使用工作队列

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

 

可以看出HAL层的代码有两种控制Vibrator的方式

  • 读写"/sys/class/timed_output/vibrator/enable"
  • 读写"/sys/class/leds/vibrator"下的属性文件

很明显我们选择了后者
这个文件中定义了控制Vibrator的函数,open、close、on、off等,和我们在做Linux驱动时的用户空间程序没什么区别

完成了HAL,接下来就是连接C和JAVA的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

 

这个代码干了以下几件事

  • 对HAL的接口再进行了一些封装
  • 使用JNINativeMethod列表将Java层和HAL层的代码联系起来

关于JNINativeMethod
结构体

 

第一个变量name是Java中函数的名字。
第二个变量signature,用字符串是描述了Java中函数的参数和返回值
第三个变量fnPtr是函数指针,指向native函数。前面都要接 (void *)
第一个变量与第三个变量是对应的,一个是java层方法名,对应着第三个参数的native方法名字

参数和返回值还有一些简写对应方式,这里就不做介绍了

JNI层提供JAVA接口以后就是Application Framework的任务了

应用层操作马达,是通过马达服务进行操作的。而马达服务是通过aidl实现的,aidl是Android进程间的通信方式
主要涉及的文件有

 

这里的代码较多,就不贴代码了,介绍一下各个文件的作用以及大致的工作流程

  • 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”
这些只是总体介绍总结的作用

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

 

我自己还没有写过JAVA APP,这是找的别人的代码来分析的

 

马达有两种控制模式

  • mVibrator.vibrate(100)直接指定震动时间
  • mVibrator.vibrate(new long[]{100,20,100,40,100,60}, 0)按照传入的数组做开启和关闭
    以上就是本篇文章【Android手机“核心科技”---Vibrator(马达)驱动分析手机马达「Android手机“核心科技”---Vibrator(马达)驱动分析」】的全部内容了,欢迎阅览 ! 文章地址:http://w.yusign.com/news/11867.html 
     资讯      企业新闻      行情      企业黄页      同类资讯      首页      网站地图      返回首页 述古往 http://w.yusign.com/mobile/ , 查看更多   
最新新闻
5999 元起,小米首款小折叠屏手机 MIX Flip 今日首销:4 英寸大外屏、第三代骁龙 8小米折叠屏手机「5999 元起,小米首款小折叠屏手机 MIX Flip 今日首销:4 英寸大外屏、第三代
7 月 23 日消息,小米 MIX Fold 4、小米 MIX Flip今天 10 点正式开售,其中 MIX Flip 是小米首款小折叠屏手机,号称“小折叠分水
arm架构虚拟手机服务器 arm服务器搭建云手机云手机服务器「arm架构虚拟手机服务器 arm服务器搭建云手机」
Firefly云手机服务器解决方案是基于ARM集群芯片和虚拟化技术的一站式解决方案,具有高性能,高集成度的特点;支持一键操控、应用
360安全中心手机360安全卫士「360安全中心」
v10.0正式版(05月22日更新) [领航版Beta] [9.7经典版] [领航版离线安装包] [网管版] [安全卫士Win10专版] [全领航版]版本:v5
android 主流分辨率是多少,android手机常用分辨率有哪些?手机分辨率「android 主流分辨率是多少,android手机常用分辨率有哪些?」
QVGA(240x320)用于1000元以下的低端Android手机,显示效果和塞班S60V3的手机一样,对软件的兼容性不好,
60年邓颖超参会,见到顾玉平愣住:20多年过去了,你竟然还活着
这些人嘲笑他:“虽然年纪大点,还是个新兵蛋子,打什么仗,还是多锻炼锻炼吧。”长征前,顾玉平被调到周恩来副主席身边担任警卫
Android是vivo的什么手机,vivo这款机型性价比实在是高,推荐入手android是什么手机「Android是vivo的什么手机,vivo这款机型性价比实在是高,推荐入手」
vivo这款机型性价比实在是高,推荐入手2020-11-02 11:29:320点赞0收藏0评论最近,许多5G手机已经在第三方平台上以降
2024版智能设备操作系统源代码购买与授权使用合同3篇.docxVIP
20XX专业合同封面COUNTRACTCOVER20XX专业合同封面COUNTRACTCOVER甲方:XXX乙方:XXXPERSONALRESUMERESUME2024版智能设备操作系统
Android开发笔记(五十五)手机设备基本操作查手机「Android开发笔记(五十五)手机设备基本操作」
手机的基本信息分两类,一类是与电话有关的信息,另一类是设备自身的信息。 与电话有关的信息可由TelephonyManager类获得,常用
2022年安卓手机跑分排名10强榜 王者初现手机跑分「2022年安卓手机跑分排名10强榜 王者初现」
2022年安卓手机跑分排名10强榜 王者出现很多人购买手机之前都是要看看这个机型是否达到自己的需求,尤其是对于一些玩家来说,因