Android耳机插拔检测(framework篇)原理解析
基本原理
在输入设备驱动(input_dev)中,一般通过轮询或者中断方式获取输入事件的原始值(raw value),经过处理后再使用input_evnet()函数上报;
android native层的input flinger会去读这个event,读到后往android java层notify,notify给InputManagerService/WiredAccessoryManager,WiredAccessoryManager在处理这个msg。
涉及到的类文件:
● InputManagerService.java
./framework/base/services/core/java/com/android/server/input/InputManagerService.java
*WiredAccessoryManager.java.
./framework/base/services/core/java/com/android/server/WiredAccessoryManager.java
● config.xml
./framework/base/core/res/res/values/config.xml
● SystemServer.java
./framework/base/services/java/com/android/server/SystemServer.java
● AudioManager.java
./base/media/java/android/media/AudioManager.java
● AudioService.java
./base/media/java/android/media/AudioService.java
InputReader.cpp->InputReader::processEventsLocked()
InputDevice.cpp->InputDevice:process()
SwitchInputMapper.cpp->SwitchInputMapper::process()
InputMapper.h->InputMap::getListener()
InputListener.cpp->mQueuedListener->notifySwitch
3)传递事件
InputListener.cpp->QueuedInputListener::flush()
NotifySwitchArgs::notify
InputClassifier::notifySwitch
InputDispatcher.cpp->InputDispatcher::notifySwitch()
com_android_server_input_InputManagerService.cpp->NativeInputManager::notifySwitch()
InputManagerService.java->InputManagerService::notifySwitch()
WiredAccessoryManager.java->WiredAccessoryManager::notifyWiredAccessoryChanged()
WiredAccessoryManager.java->WiredAccessoryManager::updateLocked()
WiredAccessoryManager.java->WiredAccessoryManager::setDeviceStateLocked
AUdioManager.java->AudioManager::setWiredDeviceConnectionState()
AudioService.java->AudioSystem::setWiredDeviceConnectionState()
AudioDeviceInventory->AudioDeviceInventory::onSetWiredDeviceConnectionState()
a)AudioDeviceInventory::handleDeviceConnection()
AudioDeviceInventory.java->AudioDeviceInventory::handleDeviceConnection()
AudioSystem.cpp->AudioSystem::setDeviceConnectionState()
AudioPolicyManager.cpp->AudioPolicyManager::setDeviceConnectionState()
class AudioPolicyClientInterface:
AudioPolicyService.cpp->AudioPolicyService:: SET_PARAMETERS
AudioFlinger.cpp->AudioFlinger::setParameters()
DeviceHalHidl.cpp->DeviceHalHidl::setParameters()
Device.cpp->Device::halSetParameters()
audio_hw.c->audio_hal::adev_set_parameters()
b) sendDeviceConnectionIntent()
c)updateAudioRoutes()
AudioDeviceBroker.java->postReportNewRoutes()
AudioDeviceInventory.java->onReportNewRoute()
MediaRouter.java->dispatchAudioRoutesChanged()
MediaRouter.java->updateAduioRoutes()
二 插拔事件上报
2.1 支持的设备类型
当前支持的具体外设设备如下:
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/1ffbd9aa88f343068239c77713363d02.png
2.2 上报方式
有两种上报插拔事件的方式,一种是输入子系统,另外一种uevent事件上报。
输入子系统(InputEvent):可以上报按键事件也可以上报开关事件,事件类型包括headset\headPhone\Lineout。对于输入设备都需要指定能产生同步类EV_SYN;switch class子系统,通过uevent向用户空间发送数据,Android中有个线程专门监听此类事件。使用switch dev子系统时,名字必须要设置为"h2w",Android系统监听 /sys/class/switch/h2s这个虚拟设备。
Android系统中最终使用哪种方式?
可以通过配置Android系统中配置文件:在Android系统中默认是使用UEvent的方式。不过一般厂商会在自己的xml文件中进行配置。
frameworks/base/core/res/res/values/config.xml或者是device/eswin/common/overlay/frameworks/base/core/res/res/values/config.xml
第二个文件会覆盖第一个文件,修改文件中的**true**变量,该值为true时使用的是tvinput子系统,false为ueven机制。
在InputManagerService.java的构造函数中,config_useDevInputEventForAudioJack的值的初始化mUseDevInputEventForAudioJack决定采用那种方式。所以最终采用的是tvinput子系统的方式。
路径:frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
三 代码流程
第一个阶段 事件信息上报
input子系统通过inputReader开始读取事件并处理。(记住这里的InputLisenerInterface listener)
路径:/frameworks/native/services/inputflinger/reader/InputReader.cpp
InputRead构造函数如下:
对于InputReadThread:
1)启动循环后执行mReader->loopOnce(),loopOnce()中会调用mEventHub→getEvents读取事件;
2)调用processEventsLocked()处理事件;
3)调用mPolicy->notifyInputDeviceChanged()用InputManagerService的代理通过Handler发送MSG_DELIVER_INPUT_DEVICES_CHANGED消息,通知输入设备发生了变化;
4)调用mQueuedListener->flush(),将事件队列中的所有事件交给在InputReader中注册过的InputDispatcher
获取事件;2)处理事件;3)传递事件
1)获取事件
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE)主要是从DEVICE_PATH = /dev/input获取kernel的event,这里的事件不仅包含了input,也包含了输入设备的add/remove。
(后续补充)
2)处理事件
通过getEvents()函数从驱动中获取到事件后,调用processEventsLocked()函数开始处理:
InputReader.cpp->InputReader::processEventsLocked()
路径:***
根据不同的deviceIdc从mDevice中获取到对应的Device,获取到Device后,判断该Device是否合法以及是否需要被忽略,如果不是,接下来需要调用deivce->process()进行事件处理。
InputDevice,cpp->InputDevice:process()
路径:frameworks/native/services/inputflinger/reader/InputDevice.cpp
该函数中,会依次处理同一个device产生的普通输入事件,然后通过for_each_mapper_in_subdevice()进行转换调用InputMapper.process()进行事件处理。
for_each_mapper_in_subdevice:
路径:frameworks/native/services/inputflinger/reader/mapper/
从该路径下的mapper类可以看出,Android将输入设备分为以下几种类型:
● CursorInputMapper :鼠标
ExternalStylusInputMapper : 触控笔
JoystickInputMapper :游戏杆
KeyboardInputMapper :键盘
KeyMouseInputMapper :通常由一个手持设备组成,具有键盘和触控板/鼠标的功能,适用于需要键盘输入和鼠标操作的情况,如在移动设备上进行文字输入和浏览。
RotaryEncoderInputMapper :旋转编码器输入设备,一种用于测量旋转运动的设备。
SwitchInputMapper : 开关
TouchInputMapper 、MultiTouchInputMapper、SingleTouchInputMapper:触摸屏
VibratorInputMapper :震动器,严格意义上是输出设备
SwitchInputMapper.cpp->SwitchInputMapper::process()
路径:frameworks/native/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
将所有的事件信息封装成一个NotifySwitchArgs对象。所以这个getLintener()是谁??
InputMapper.h->InputMap::getListener()
路径:frameworks/native/services/inputflinger/reader/mapper/InputMapper.h
而mDeviceContext又是一个InputDeviceContext类型的,可以看到:
inline InputReaderContext* getContext() { return mContext; } 实际上调用是InputReadContext中的getListener()函数
路径:frameworks\native\services\inputflinger\reader\InputReader.cpp
InputListenerInterface* InputReader::ContextImpl::getListener() {
return mReader->mQueuedListener.get();
}
所以getListener()->notifySwtch最终为mQueuedListener->notifySwitch(&args)
InputListener.cpp->mQueuedListener->notifySwitch
路径:frameworks/native/services/inputflinger/InputListener.cpp
最终将相关事件信息存放到mArgsQueue队列中。
3)传递事件
InputListener.cpp->QueuedInputListener::flush()
路径:frameworks\native\services\inputflinger\InputListener.cpp
在flush()函数中,依次取出mArgsQueue队列中的数据,调用NotifyArgs args->notify(mInnerListener)进行处理。
NotifySwitchArgs::notify
void NotifySwitchArgs::notify(const sp& listener) const { listener->notifySwitch(this); }
调用的是 listener->notifySwitch(this), 所有传入的mInnerListener是哪位??
路径:frameworks\native\services\inputflinger\InputListener.cpp
QueuedInputListener::QueuedInputListener(const sp& innerListener) : mInnerListener(innerListener) { }
InputManager::InputManager()
路径:frameworks/native/services/inputflinger/InputManager.cpp
所以上面的mInnerListener就是mClassifier,调用的是mClassifier→notifySwitch()
InputClassifier::notifySwitch
void InputClassifier::notifySwitch(const NotifySwitchArgs* args) {
// pass through
mListener->notifySwitch(args);
}
构造函数:
InputClassifier::InputClassifier(const sp& listener) : mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) {}
可以观察到,mListener(listener)还是上面带下来的参数InputDispatcher::mDispatcher,也就是mClassifier→notifySwitch()最终调用的是InputDispatcher::notifySwitch()
InputDispatcher.cpp->InputDispatcher::notifySwitch()
路径:frameworks\native\services\inputflinger\dispatcher\InputDispatcher.cpp
构造函数:
可以观察在InputDispatcherPolicyInterface中是个虚函数,最终实现在NativeInputManager::notifySwitch()
com_android_server_input_InputManagerService.cpp->NativeInputManager::notifySwitch()
路径:frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
路径:frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
全局搜索下同名函数“notifySwitch”
InputManagerService.java->InputManagerService::notifySwitch()
路径:frameworks\base\services\core\java\com\android\server\input\InputManagerService.java
根据从xml中获取到的mUseDevInputEventForAudioJack = true,进入到
WiredAccessoryManager.java->WiredAccessoryManager::notifyWiredAccessoryChanged()
路径:frameworks/base/services/core/java/com/android/server/WiredAccessoryManager.java
WiredAccessoryManager.java->WiredAccessoryManager::updateLocked()
更新耳机状态,这里又分了多种耳机: usb_headset_anlg、usb_headset_dgtl 、h2w_headset
设置outputDevice = DEVICE_OUT_WIRED_HEADPHONE = 0x8
WiredAccessoryManager.java->WiredAccessoryManager::setDeviceStateLocked
路径:frameworks\base\services\core\java\com\android\server\WiredAccessoryManager.java
判断headphone是否带mic。
AUdioManager.java->AudioManager::setWiredDeviceConnectionState()
路径:frameworks/base/media/java/android/media/AudioManager.java
(涉及到Binder通信一堆东西)
AudioService.java->AudioSystem::setWiredDeviceConnectionState()
路径:frameworks/base/services/core/java/com/android/server/audio/AudioService.java
围绕着:
frameworks/base/services/core/java/com/android/server/audio/AudioDeviceBroker.java
frameworks/base/services/core/java/com/android/server/audio/AudioDeviceInventory.java
AudioDeviceBroker::setWiredDeviceConnectionState()
->AudioDeviceInventory::setWiredDeviceConnectionState()
→AudioDeviceBroker::postSetWiredDeviceConnectionState()
→AudioDeviceInventory::onSetWiredDeviceConnectionState()
AudioDeviceInventory->AudioDeviceInventory::onSetWiredDeviceConnectionState()
该函数主要分为三步:
a)handleDeviceConnection() 确保设备连接并向下设置设备支持的参数;
b)sendDeviceConnectionIntent() 向上发送设备状态
c) updataAudioRoutes() 更新Audio路由
a)AudioDeviceInventory::handleDeviceConnection()
AudioDeviceInventory.java->AudioDeviceInventory::handleDeviceConnection()
路径:frameworks\base\services\core\java\com\android\server\audio\AudioDeviceInventory.java
如果设备已经连接了
通过final int res = mAudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName, AudioSystem.AUDIO_FORMAT_DEFAULT);
通过AudioSystemAdapter.java->AudioSystem.java->android_media_AudioSystem.cpp->AudioSystem.cpp
AudioSystem.cpp->AudioSystem::setDeviceConnectionState()
路径:frameworks/av/media/libaudioclient/AudioSystem.cpp
AudioPolicyManager.cpp->AudioPolicyManager::setDeviceConnectionState()
路径:frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
→AudioPolicyManager::setDeviceConnectionStateInt()
路径:frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
先看这个**broadcastDeviceConnectionState(dev, state);**通过调用setParameters()通知所有的hardware module,有新的设备正在处理中:
class AudioPolicyClientInterface:
路径:frameworks/av/services/audiopolicy/AudioPolicyInterface.h
AudioPolicyClientInterface实现在AudioPolicyClientImpl.cpp中,调用到AudioPolicyService中:
AudioPolicyService.cpp->AudioPolicyService:: SET_PARAMETERS
路径:frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp
AudioFlinger.cpp->AudioFlinger::setParameters()
路径:frameworks/av/services/audioflinger/AudioFlinger.cpp
DeviceHalHidl.cpp->DeviceHalHidl::setParameters()
路径:frameworks/av/media/libaudiohal/impl/DeviceHalHidl.cpp
Device.cpp->Device::halSetParameters()
路径:hardware/interfaces/audio/core/all-versions/default/Device.cpp
audio_hw.c->audio_hal::adev_set_parameters()
b) sendDeviceConnectionIntent()
发送intent去通知音频外设的状态变化。
路径:frameworks/base/services/core/java/com/android/server/audio/AudioDeviceInventory.java
c)updateAudioRoutes()
更新音频路径
路径:frameworks/base/services/core/java/com/android/server/audio/AudioDeviceInventory.java
根据不同的device设置connType并和前一次的mainType进行比较是否需要更新route
AudioDeviceBroker.java->postReportNewRoutes()
/package/ void postReportNewRoutes(boolean fromA2dp) {
sendMsgNoDelay(fromA2dp ? MSG_REPORT_NEW_ROUTES_A2DP : MSG_REPORT_NEW_ROUTES, SENDMSG_NOOP);
}
handleMessage()
case MSG_REPORT_NEW_ROUTES:
case MSG_REPORT_NEW_ROUTES_A2DP:
synchronized (mDeviceStateLock) {
mDeviceInventory.onReportNewRoutes();
}
break;
(搞不懂这里,MSG_REPORT_NEW_ROUTES和MSG_REPORT_NEW_ROUTES_A2DP处理流程走到一样,还区分两者)
AudioDeviceInventory.java->onReportNewRoute()
路径:frameworks\base\services\core\java\com\android\server\audio\AudioDeviceInventory.java
MediaRouter.java->dispatchAudioRoutesChanged()
其中的mIsBluetoothA2dpOn = mAudioService.isBluetoothA2dpOn()获取当前BT设备的状态,会调用到AudioDeviceBroker.java->isBluetoothA2dpOn()
MediaRouter.java->updateAduioRoutes()
判断路由信息是否发生了改变。
到此这篇关于Android耳机插拔检测(framework篇)原理解析的文章就介绍到这了,更多相关Android耳机插拔检测内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Android开源项目PullToRefresh下拉刷新功能详解2
这篇文章主要为大家进一步的介绍了Android开源项目PullToRefresh下拉刷新功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下2016-09-09Android自带倒计时控件Chronometer使用方法详解
这篇文章主要为大家详细介绍了Android自带倒计时控件Chronometer的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下2016-11-11
最新评论