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.javaInputReader.cpp->InputReader::processEventsLocked()
InputDevice.cpp->InputDevice:process()SwitchInputMapper.cpp->SwitchInputMapper::process()InputMapper.h->InputMap::getListener()InputListener.cpp->mQueuedListener->notifySwitch3)传递事件
InputListener.cpp->QueuedInputListener::flush()NotifySwitchArgs::notifyInputClassifier::notifySwitchInputDispatcher.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::setDeviceStateLockedAUdioManager.java->AudioManager::setWiredMfJLrmoDeviceConnectionState()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_PARAMETERSAudioFlinger.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 支持的设备类型
当前支持的具体外设设备如下::可以上报按键事件也可以上报开关事件,事件类型包括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.cppInputRead构造函数如下:对于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.cppInputListenerInterface* 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::notifyvoid NotifySwitchArgs::notify(const sp& listener) const { listener->notifySwitch(this); }调用的是 listener->notifySwitch(this), 所有传入的mInnerListener是哪位??路径:frameworks\native\services\inputflinger\InputListener.cppQueuedInputListener::QueuedInputListener(const sp& innerListener) : mInnerListener(innerListener) { }InputManager::InputManager()
路径:frameworks/native/services/inputflinger/InputManager.cpp所以上面的mInnerListener就是mClassifier,调用的是mClassifier→notifySwitch()
InputClassifier::notifySwitchvoid InputClassifier::notifySwitch(const NotifySwitchArgs* args) {// pass throughmListener->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::notwww.devze.comifySwitch()
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.javaWiredAccessoryManager.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.javaframeworks/base/services/core/java/com/android/server/audio/AudioDeviceInventory.javaAudioDeviceBroker::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.cppAudioSystem.cpp->AudioSystem::setDeviceConnectionState()路径:frameworks/av/media/libaudioclient/AudioSystem.cppAudioPolicyManager.cpp->AudioPolicyManager::setDeviceConnectionState()
路径:frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp→AudioPolicyManager::setDeviceConnectionStateInt()路径:frameworks/av/services/audiopolicy/managerdefault/AandroidudioPolicyManager.cpp先看这个**broadcastDeviceConnectionState(dev, state);**通过调用setParameters()通知所有的hardware module,有新的设备正在处理中:
class AudioPolicyClientInterface:
路径:frameworks/av/services/audiopolicy/AudioPolicyInterface.hAudioPolicyClientInterface实现在AudioPolicyClientImpl.cpp中,调用到AudioPolicyService中:
AudioPolicyService.cpp->AudioPolicyService:: SET_PARAMETERS路径:frameworks/av/services/audiopolicy/service/AudioPolicyService.cppAudioFlinger.cpp->AudioFlinger::setParameters()
路径:frameworks/av/services/audioflinger/AudioFlinger.cppDeviceHalHidl.cpp->DeviceHalHidl::setParameters()
路径:frameworks/av/media/libaudiohal/impl/DeviceHalHidl.cppDevice.cpp->Device::halSetParameters()
路径:hardware/interfaces/audio/core/all-versions/default/Device.cppaudio_hw.c->audio_hal::adev_set_parameters()
b) sendDeviceConnectionIntent()
发送intent去通知音频外设的状态变化。路径:frameworks/base/services/core/java/com/android/server/audio/AudioDeviceInventory.javac)updateAudioRoutes()
更新音频路径路径:frameworks/base/services/core/java/com/android/server/audio/AudioDeviceInventory.java根据不同的device设置connType并和前一次的mainType进行比较是否需要更新routeAudioDeviceBroker.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.javaMediaRouter.java->dispatchAudioRoutesChanged()
其中的mIsBluetoothA2dpOn = mAudioService.isBluetoothA2dpOn()获取当前BT设备的状态,会调用到AudioDeviceBroker.java->isBluetoothA2dpOn()
MediaRouter.java->updateAdphpuioRoutes()
判断路由信息是否发生了改变。到此这篇关于Android耳机插拔检测(framework篇)原理解析的文章就介绍到这了,更多相关Android耳机插拔检测内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论