前言

本文所有源码均是基于安卓8.0进行分析的,安卓12对振动服务做了比较多的变动。

本文适合阅读的人群为:3-5年开发经验,有一定系统源码阅读经历的人。

安卓开发做久了,经常觉得一切都理所当然。这导致我们遇到问题时,不能很理解本质,所以我们很有必要分析系统的源码。
本文侧重调用流程,不侧重具体的实现。
如果读者对硬件实现和粗略流程感兴趣,可以分别读以下两个文章:
粗略流程
硬件实现

分析

我们先来看看安卓设备上振动的基本使用方式

Vibrator vibrator = (Vibrator)this.getSystemService(this.VIBRATOR_SERVICE);
vibrator.vibrate(1000);//振动一下long[] patter = {1000, 1000, 2000, 50};
vibrator.vibrate(patter, 0);//有不同幅度的振动vibrator.cancel();//取消振动

首先 getSystemService(this.VIBRATOR_SERVICE) 相信各位做了这么久的安卓开发,肯定知道他的内部实实现,所以我就不再赘述。

通过getSystemService,我们把拿到的Object类型强转成了Vibrator。所以接下来我们的目光就放到这个类上面。

Vibrator的包名是android.os.Vibrator,所以它在安卓源码中的位置是\frameworks\base\core\java\android\os

vibrate方法的源码如下:

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

如果参数只传入long,或者long[],int 实际上会调用另一个方法(不再展示),将他们封装为VibrationEffect,AudioAttributes

并调用此方法:

    public void vibrate(VibrationEffect vibe, AudioAttributes attributes) {vibrate(Process.myUid(), mPackageName, vibe, attributes);}

mPackageName在Vibrator类创建的时候会初始化,获得当前程序的包名

当你尝试跳转四个参数的vibrate时,你会发现它居然是abstract修饰的 !

当年在回头看Vibrator这个类的时候,会发现它居然也是abstract修饰的 !

当你使用Ctrl+Alt+B查看Vibrator的实现时,居然是红色的No Implement Found !

纳尼 难道振动的具体实现是ROM厂商写的吗?

并不是这样

我们之所以产生这样的想法,是因为我们习惯了只是使用AndroidStudio查看开放的源码。但实际上,AOSP中还有很多被@hide修饰的类。

Vibrator根本不是振动的实现,只是一个基类,在其内部只实现了对振动参数的封装。

想要知道它的具体实现,我们可以写如下代码:

Object vibrator = getSystemService(this.VIBRATOR_SERVICE);
Toast.makeText(this, vibrator.getClass().getName(), Toast.LENGTH_SHORT).show();

运行后,发现vibrator 的真身是android.os.SystemVibrator。

这个SystemVibrator是一个被@hide修饰的类,我们无法通过AndroidStudio阅读它。

它的路径为\frameworks\base\core\java\android\os

观察源码,发现这个SystemVibrator也是一个空壳,所有的函数都是通过Aidl和Binder与系统进行交互的。

合情合理,毕竟用户的进程不允许直接与硬件交互,必须通过系统的中转,不然可能会出现恶意的操控。

重新开始

安卓的系统服务都是通过SystemServer(\frameworks\base\services\java\com\android\server)创建的,然后保存到ServiceManager(\frameworks\base\core\java\android\os)中

在创建服务时,会把服务分为三类Bootstrap,Core,Other。而VibratorService正是属于最后一种。

我们可以在SystemServer中找到如下代码:

private Context mSystemContext;
private void createSystemContext() {ActivityThread activityThread = ActivityThread.systemMain();mSystemContext = activityThread.getSystemContext();}private void startOtherServices(){final Context context = mSystemContext;VibratorService vibrator = null;vibrator = new VibratorService(context);ServiceManager.addService("vibrator", vibrator);try {vibrator.systemReady();} catch (Throwable e) {reportWtf("making Vibrator Service ready", e);}}

流程很简单,拿到系统的Context,然后创建VibratorService ,并存入ServiceManager中,最后调用systemRead完成创建。

我们再去VibratorService (\frameworks\base\services\core\java\com\android\server)

    native static boolean vibratorExists();//是否存在嵌入式的振动设备native static void vibratorInit();//初始化硬件native static void vibratorOn(long milliseconds);//开始振动,并设置持续时长native static void vibratorOff();//关闭振动native static boolean vibratorSupportsAmplitudeControl();//是否支持振动强度控制native static void vibratorSetAmplitude(int amplitude);//设置振动强度native static long vibratorPerformEffect(long effect, long strength);//effect是系统预设的振动模式,strength是振动模式VibratorService(Context context) {vibratorInit();vibratorOff();mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();mContext = context;//经过分析,这里传入的Context是SystemContextPowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");mWakeLock.setReferenceCounted(true);//通过PM拿到休眠锁,让振动的时候可以在后台运行mAppOpsService=IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE));//权限检查作用mFallbackEffects = new VibrationEffect[] { clickEffect, doubleClickEffect };}public void systemReady() {//向ServiceManager添加后会调用此方法//本质就是监听系统的设置或者振动设备是否有变化,如果有变化就调用updateVibratorsmContext.registerReceiver(new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {updateVibrators();}}, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);updateVibrators();}private void updateVibrators() {//更改锁的状态synchronized (mLock) {boolean devicesUpdated = updateInputDeviceVibratorsLocked();boolean lowPowerModeUpdated = updateLowPowerModeLocked();if (devicesUpdated || lowPowerModeUpdated) {doCancelVibrateLocked();}}}private void doCancelVibrateLocked() {mH.removeCallbacks(mVibrationEndRunnable);if (mThread != null) {mThread.cancel();mThread = null;}doVibratorOff();reportFinishVibrationLocked();//解除当前的振动}

走了这么远,我们再回头看看vibrate方法的具体实现

    @Override // 实现了IVibratorService.Stub,所以是Overridepublic void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint,IBinder token) {if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)!= PackageManager.PERMISSION_GRANTED) {throw new SecurityException("Requires VIBRATE permission");}//检查振动权限if (token == null) {Slog.e(TAG, "token must not be null");return;}//记录每次振动的token,实质上是一个IBinder对象verifyIncomingUid(uid);//认证idif (!verifyVibrationEffect(effect)) {//判断振动是否合法//这个判断实际上是调用effect本身的validate方法return;}//和上一次振动比较if (effect instanceof VibrationEffect.OneShot&& mCurrentVibration != null&& mCurrentVibration.mEffect instanceof VibrationEffect.OneShot) {VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;VibrationEffect.OneShot currentOneShot =(VibrationEffect.OneShot) mCurrentVibration.mEffect;if (mCurrentVibration.hasLongerTimeout(newOneShot.getTiming())&& newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {if (DEBUG) {Slog.e(TAG, "Ignoring incoming vibration in favor of current vibration");}return;}}Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg);//Vibration是VibratiorService的一个内部类,对vibrate方法的参数进行封装if (effect instanceof VibrationEffect.Waveform) {try {token.linkToDeath(vib, 0);//将token和本次振动的生命周期绑定到一起//这里实际上会调用binderDied} catch (RemoteException e) {return;}}long ident = Binder.clearCallingIdentity();//开始锁,并执行振动try {synchronized (mLock) {doCancelVibrateLocked();startVibrationLocked(vib);//真正执行振动的函数addToPreviousVibrationsLocked(vib);//把当前的振动数据储存起来}} finally {Binder.restoreCallingIdentity(ident);}}private void verifyIncomingUid(int uid) {//认证idif (uid == Binder.getCallingUid()) {return;}if (Binder.getCallingPid() == Process.myPid()) {return;}mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,Binder.getCallingPid(), Binder.getCallingUid(), null);}

上述代码中,真正使得设备振动的代码在startVibrationLocked中,我们来一窥天机

    private void startVibrationLocked(final Vibration vib) {if (!isAllowedToVibrate(vib)) return;if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE &&!shouldVibrateForRingtone()) {return;}final int mode = getAppOpMode(vib);if (mode != AppOpsManager.MODE_ALLOWED) {if (mode == AppOpsManager.MODE_ERRORED) {// We might be getting calls from within system_server, so we don't actually want// to throw a SecurityException here.Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);}return;}startVibrationInnerLocked(vib);}

检查是否可以振动,然后检查权限,再通过startVibrationInnerLocked执行振动再上锁

private void startVibrationInnerLocked(Vibration vib) {mCurrentVibration = vib;if (vib.mEffect instanceof VibrationEffect.OneShot) {VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.mEffect;doVibratorOn(oneShot.getTiming(), oneShot.getAmplitude(), vib.mUid, vib.mUsageHint);mH.postDelayed(mVibrationEndRunnable, oneShot.getTiming());//1} else if (vib.mEffect instanceof VibrationEffect.Waveform) {VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.mEffect;mThread = new VibrateThread(waveform, vib.mUid, vib.mUsageHint);mThread.start();} else if (vib.mEffect instanceof VibrationEffect.Prebaked) {long timeout = doVibratorPrebakedEffectLocked(vib);if (timeout > 0) {mH.postDelayed(mVibrationEndRunnable, timeout);//2}}//因为Waveform 是一种长时间,强度多次变化的,所以使用线程振动}

留意一下注释1,2.我们在分析doVibratorOn后会分析

我们先来看一下doVibratorOn,他是核心振动方法

private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) {synchronized (mInputDeviceVibrators) {//对当前振动设备加锁if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {amplitude = mDefaultVibrationAmplitude;}final int vibratorCount = mInputDeviceVibrators.size();if (vibratorCount != 0) {final AudioAttributes attributes =new AudioAttributes.Builder().setUsage(usageHint).build();for (int i = 0; i < vibratorCount; i++) {//让所有振动设备都振动mInputDeviceVibrators.get(i).vibrate(millis, attributes);//mInputDeviceVibrators存放的是Vibrator,最终仍然会走这个doVibratorOn方法,并且所有振动设备都持有锁}} else {//调用native方法设置振动并设置强度。//安卓源码在这里有一个贴心提示,让先开启振动,再设置强度,这个排序很重要vibratorOn(millis);doVibratorSetAmplitude(amplitude);}}}private void doVibratorSetAmplitude(int amplitude) {if (mSupportsAmplitudeControl) {vibratorSetAmplitude(amplitude);}}

在回头看注释1,2。其中的mVibrationEndRunnable,会在振动结束后(通过postDaly实现)异步调用onVibrationFinished

    public void onVibrationFinished() {synchronized (mLock) {doCancelVibrateLocked();//这个方法我们已经在前面介绍过,不再赘述}}

注意一下,我们在vibrate方法中,对振动对象绑定了振动的生命周期,所以会在结束时调用Vibration对象(实现了IBinder.DeathRecipient接口)的binderDied

        public void binderDied() {synchronized (mLock) {if (this == mCurrentVibration) {doCancelVibrateLocked();}}}//即使postDaly出现了问题,也能在振动超时的时候停止

以上我们已经分析了onShot振动的实现,现在我们来看看Wave的实现

Wave振动是开启了一个类型为VibrateThread的线程,代码如下:

private class VibrateThread extends Thread {private final VibrationEffect.Waveform mWaveform;private final int mUid;private final int mUsageHint;private boolean mForceStop;VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) {mWaveform = waveform;mUid = uid;mUsageHint = usageHint;}private long delayLocked(long duration) {//延时的实现long durationRemaining = duration;if (duration > 0) {final long bedtime = duration + SystemClock.uptimeMillis();do {try {this.wait(durationRemaining);}catch (InterruptedException e) { }if (mForceStop) {break;}durationRemaining = bedtime - SystemClock.uptimeMillis();} while (durationRemaining > 0);return duration - durationRemaining;}return 0;}public void run() {mWakeLock.acquire();//拿到唤醒锁try {boolean finished = playWaveform();//阻塞式实现振动if (finished) {onVibrationFinished();}} finally {mWakeLock.release();}}public boolean playWaveform() {synchronized (this) {final long[] timings = mWaveform.getTimings();final int[] amplitudes = mWaveform.getAmplitudes();final int len = timings.length;final int repeat = mWaveform.getRepeatIndex();int index = 0;long onDuration = 0;while (!mForceStop) {if (index < len) {final int amplitude = amplitudes[index];final long duration = timings[index++];if (duration <= 0) {continue;}if (amplitude != 0) {if (onDuration <= 0) {onDuration =getTotalOnDuration(timings, amplitudes, index - 1, repeat);doVibratorOn(onDuration, amplitude, mUid, mUsageHint);} else {doVibratorSetAmplitude(amplitude);}}long waitTime = delayLocked(duration);if (amplitude != 0) {onDuration -= waitTime;}} else if (repeat < 0) {break;} else {index = repeat;}}return !mForceStop;}}public void cancel() {//强制取消//doCancelVibrateLocked方法中会调用synchronized (this) {mThread.mForceStop = true;mThread.notify();}}private long getTotalOnDuration(//获得总时长long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {int i = startIndex;long timing = 0;while(amplitudes[i] != 0) {timing += timings[i++];if (i >= timings.length) {if (repeatIndex >= 0) {i = repeatIndex;} else {break;}}if (i == startIndex) {return 1000;}}return timing;}}

实质上振动的实现还是native方法doVibratorOndoVibratorSetAmplitude

我们再简单分析一下硬件层

首先设备的载入在server.cpp(\device\google\marlin\vibrator)中

核心代码如下


static const char *ENABLE_PATH = "/sys/class/timed_output/vibrator/enable";
static const char *AMPLITUDE_PATH = "/sys/class/timed_output/vibrator/voltage_level";status_t registerVibratorService() {std::ofstream enable{ENABLE_PATH};if (!enable) {int error = errno;ALOGE("Failed to open %s (%d): %s", ENABLE_PATH, error, strerror(error));return -error;}std::ofstream amplitude{AMPLITUDE_PATH};if (!amplitude) {int error = errno;ALOGE("Failed to open %s (%d): %s", AMPLITUDE_PATH, error, strerror(error));return -error;}sp<IVibrator> vibrator = new Vibrator(std::move(enable), std::move(amplitude));vibrator->registerAsService();return OK;
}int main() {configureRpcThreadpool(1, true);status_t status = registerVibratorService();if (status != OK) {return status;}joinRpcThreadpool();
}

振动设备的配置信息在Vibrator.cpp(\device\google\marlin\vibrator)

代码如下

//振动器的强度通过电压控制
static constexpr int MAX_VOLTAGE = 3596;//最大电压
static constexpr int MIN_VOLTAGE = 116;//最小电压static constexpr uint32_t CLICK_TIMING_MS = 20;//单位持续时长Vibrator::Vibrator(std::ofstream&& enable, std::ofstream&& amplitude) :mEnable(std::move(enable)),mAmplitude(std::move(amplitude)) {}
Return<Status> Vibrator::on(uint32_t timeout_ms) {mEnable << timeout_ms << std::endl;if (!mEnable) {ALOGE("Failed to turn vibrator on (%d): %s", errno, strerror(errno));return Status::UNKNOWN_ERROR;}return Status::OK;
}Return<Status> Vibrator::off()  {mEnable << 0 << std::endl;if (!mEnable) {ALOGE("Failed to turn vibrator off (%d): %s", errno, strerror(errno));return Status::UNKNOWN_ERROR;}return Status::OK;
}Return<bool> Vibrator::supportsAmplitudeControl()  {return true;
}Return<Status> Vibrator::setAmplitude(uint8_t amplitude) {if (amplitude == 0) {return Status::BAD_VALUE;}long voltage =std::lround((amplitude - 1) / 254.0 * (MAX_VOLTAGE - MIN_VOLTAGE) + MIN_VOLTAGE);ALOGE("Setting amplitude  to: %ld", voltage);mAmplitude << voltage << std::endl;if (!mAmplitude) {ALOGE("Failed to set amplitude (%d): %s", errno, strerror(errno));return Status::UNKNOWN_ERROR;}return Status::OK;
}Return<void> Vibrator::perform(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {//系统预设的振动if (effect == Effect::CLICK) {uint8_t amplitude;switch (strength) {case EffectStrength::LIGHT:amplitude = 36;break;case EffectStrength::MEDIUM:amplitude = 128;break;case EffectStrength::STRONG:amplitude = 255;break;default:_hidl_cb(Status::UNSUPPORTED_OPERATION, 0);return Void();}on(CLICK_TIMING_MS);setAmplitude(amplitude);_hidl_cb(Status::OK, CLICK_TIMING_MS);} else {_hidl_cb(Status::UNSUPPORTED_OPERATION, 0);}return Void();
}

振动的HAL层实现在Vibrator.cpp(\hardware\interfaces\vibrator\1.0\default)

就不贴代码了,因为厂商的实现都不一样的。

至此,振动服务的调用已经从Java API层到HAL层,我们来做一个总结。

总结

  1. 首先系统在启动时,通过ZygoteInit中handleSystemServerProcess函数的最后一步,调用SystemServer的静态函数main方法。

  2. 在SystemServer的main函数中,根据service的类型分三类进行服务加载,振动服务属于Other类。

  3. 创建了VibratorService对象后,将其加入到系统服务map中。

  4. 在VibratorService中调用native方法vibratorInit,初始化硬件振动器。至此系统振动服务加载完成。

  5. 开发者通过getSystemService拿到SystemVibrator ,SystemVibrator继承自Vibrator,内部实现了对振动参数的检验和封装。

  6. 开发者调用vibrate方法,SystemVibrator将参数封装,并通过Binder与系统振动服务进行通信。

  7. 系统振动服务最终调用native的doVibratorOn与doVibratorSetAmplitude操控硬件。通过加锁和Handler的postDaly实现结束时监听。

  8. doVibratorOn与doVibratorSetAmplitude会调用厂商封装好的HAL层操作硬件设备。

【安卓Android】VibratorService分析相关推荐

  1. 【Android 性能优化】应用启动优化 ( 安卓应用启动分析 | Launcher 应用启用普通安卓应用 | 应用进程分析 )

    文章目录 一. Launcher 应用 startActivitySafely 方法分析 二. Launcher 中的 startActivity(View v, Intent intent, Obj ...

  2. Charles最新破解版苹果iphone安卓android手机抓包分析教程笔记

    Charles最新破解版苹果iphone安卓android手机抓包分析教程笔记 中间遇到各种问题导致最终没法看到抓包信息,一个坑一个坑的埋,终于成功抓包小程序. 梳理了下可以尽量减少栽坑的安装过程,如 ...

  3. java创建医生的对象_基于安卓Android的作物医生App设计开发(MySQL)(含录像)

    基于安卓Android的作物医生App设计开发(MySQL)(含录像)(毕业论文14000字,PHP程序代码,MySQL数据库) 本系统使用软件工程方法进行一系列的分析.设计.实现与测试.使用面向对象 ...

  4. 二手手机交易平台使用MYSQL的方法_安卓Android校园淘(二手交易)APP设计与实现(MySQL)...

    安卓Android校园淘(二手交易)APP设计与实现(MySQL)(任务书,开题报告,中期检查表,文献综述,外文翻译,毕业论文14000字,程序代码,MySQL数据库) 本项目就是一个基于Androi ...

  5. Android 逆向分析大全

    转载:Android 逆向分析大全:https://www.jianshu.com/p/a12d04fc748f 1. 概述 1.1 分析步骤 通用逆向分析步骤 1. 了解该模块正向编程相关方法 2. ...

  6. 安卓Android与H5双向交互MathJax展示数学公式(源码+解析)

    安卓Android与H5双向交互MathJax展示数学公式(源码+解析) 博主就今天周五又做了个需求(安卓Android与H5交互),原来上线的功能是服务器配置过来的学习报告(一个H5页面)并提供原始 ...

  7. 便签 java_基于安卓Android的便签笔记APP设计(Android studio)

    基于安卓Android的便签笔记APP设计(Android studio)(论文9000字,程序代码) 摘要:本文介绍了便签的发展史.基础操作流程以及便签的具体功能,提出了基于Android的便签AP ...

  8. java计算机毕业设计基于安卓Android/微信小程序的游泳馆管理系统APP

    项目介绍 游泳馆管理系统小程序,主要对首页.个人中心.会员管理.场馆类型管理.泳池类型管理.饮食类型管理.场馆信息管理.泳池信息管理.饮食信息管理.泳池预订管理.购买信息管理.会员等级管理.会员充值管 ...

  9. 安卓Android、iOS移动端车牌识别OCR技术原理

    核心内容:移动端车牌识别.安卓端车牌识别.Android车牌识别.iOS端车牌识别.OCR识别技术 一.安卓Android.iOS移动端车牌识别OCR技术识别流程 安卓Android.iOS移动端车牌 ...

  10. java计算机毕业设计基于安卓Android/微信小程序的校园闲置二手交易平台APP

    项目介绍 网络技术的快速发展给各行各业带来了很大的突破,也给各行各业提供了一种新的管理模式,校园二手交易平台小程序将是又一个从传统管理到智能化信息管理的典型案例,对于传统的校园二手交易,所包括的信息内 ...

最新文章

  1. Centos 下安装Docker 遇到的一些错误
  2. python跟java-还在纠结选Python还是Java?看完就有数了
  3. “约见”面试官系列之常见面试题之第九十六篇之active-class是谁的属性(建议收藏)
  4. python for everybody作业和测试答案_【计算题】编写函数,模拟 Python 内置函数 reversed() 。...
  5. sql视图查询对象无效_SQL数据分析 - 4 复杂查询
  6. VMware报错“锁定文件失败“解决方法
  7. jQuery.ajax处理继续响应:“成功:”还是“ .done”?
  8. 在Windows下编译OpenSSL(VS2005)
  9. 从闭包到 语法糖 装饰器
  10. SQL Server(三):Select语句
  11. 虚拟机服务器安装iis报错,Windows2008R2安装iis和iis下搭建web服务器(9.18 第七天)...
  12. FPGA SPI协议
  13. SOM网络(Kohonen自组织网络)学习第二篇
  14. 分布式拒绝服务(DDoS)攻击原理介绍和防范措施
  15. 《啊哈!算法》第一章 - 第三节 - 快速排序(Java实现)
  16. java 输出水仙花数
  17. MS问题汇总小结~(持续更新记录)
  18. 【LCT】[COI2009] OTOCI
  19. Docker学习-Network网络
  20. 你所需要了解的关于技术团队的要求

热门文章

  1. 《2021年IT行业项目管理调查报告》发布
  2. 黑暗森林法则和猜疑链同样存在人和人之间
  3. ⅴs2010控件名称及用方法_VS2010 用户自定义工具箱控件的制作方法
  4. 两个程序员老友的会面
  5. 蜂窝多边形密度图(GIS可视化)
  6. tensorflow目标检测--识别赵丽颖
  7. Ant Design Pro 使用Authorized组件做权限验证
  8. 色彩搭配 — 总结1
  9. spring-security实现权限管理
  10. matlab 数字和字符串转换