开发者

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::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_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

Android耳机插拔检测(framework篇)原理解析

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

Android耳机插拔检测(framework篇)原理解析

三 代码流程

第一个阶段 事件信息上报

input子系统通过inputReader开始读取事件并处理。(记住这里的InputLisenerInterface listener)

路径:/frameworks/native/services/inputflinger/reader/InputReader.cpp

InputRead构造函数如下:

Android耳机插拔检测(framework篇)原理解析

对于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)传递事件

Android耳机插拔检测(framework篇)原理解析

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()

路径:***

Android耳机插拔检测(framework篇)原理解析

根据不同的deviceIdc从mDevice中获取到对应的Device,获取到Device后,判断该Device是否合法以及是否需要被忽略,如果不是,接下来需要调用deivce->process()进行事件处理。

InputDevice,cpp->InputDevice:process()

路径:frameworks/native/services/inputflinger/reader/InputDevice.cpp

Android耳机插拔检测(framework篇)原理解析

该函数中,会依次处理同一个device产生的普通输入事件,然后通过for_each_mapper_in_subdevice()进行转换调用InputMapper.process()进行事件处理。

for_each_mapper_in_subdevice:

Android耳机插拔检测(framework篇)原理解析

路径: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

Android耳机插拔检测(framework篇)原理解析

将所有的事件信息封装成一个NotifySwitchArgs对象。所以这个getLintener()是谁??

InputMapper.h->InputMap::getListener()

路径:frameworks/native/services/inputflinger/reader/mapper/InputMapper.h

Android耳机插拔检测(framework篇)原理解析

而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

Android耳机插拔检测(framework篇)原理解析

最终将相关事件信息存放到mArgsQueue队列中。

3)传递事件

InputListener.cpp->QueuedInputListener::flush()

路径:frameworks\native\services\inputflinger\InputListener.cpp

Android耳机插拔检测(framework篇)原理解析

在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) { }

Android耳机插拔检测(framework篇)原理解析

InputManager::InputManager()

路径:frameworks/native/services/inputflinger/InputManager.cpp

Android耳机插拔检测(framework篇)原理解析

所以上面的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

Android耳机插拔检测(framework篇)原理解析

构造函数:

Android耳机插拔检测(framework篇)原理解析

可以观察在InputDispatcherPolicyInterface中是个虚函数,最终实现在NativeInputManager::notwww.devze.comifySwitch()

com_android_server_input_InputManagerService.cpp->NativeInputManager::notifySwitch()

路径:frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

Android耳机插拔检测(framework篇)原理解析

路径:frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

Android耳机插拔检测(framework篇)原理解析

全局搜索下同名函数“notifySwitch”

InputManagerService.java->InputManagerService::notifySwitch()

路径:frameworks\base\services\core\java\com\android\server\input\InputManagerService.java

Android耳机插拔检测(framework篇)原理解析

根据从xml中获取到的mUseDevInputEventForAudioJack = true,进入到

Android耳机插拔检测(framework篇)原理解析

WiredAccessoryManager.java->WiredAccessoryManager::notifyWiredAccessoryChanged()

路径:frameworks/base/services/core/java/com/android/server/WiredAccessoryManager.java

Android耳机插拔检测(framework篇)原理解析

WiredAccessoryManager.java->WiredAccessoryManager::updateLocked()

更新耳机状态,这里又分了多种耳机: usb_headset_anlg、usb_headset_dgtl 、h2w_headset

Android耳机插拔检测(framework篇)原理解析

设置outputDevice = DEVICE_OUT_WIRED_HEADPHONE = 0x8

WiredAccessoryManager.java->WiredAccessoryManager::setDeviceStateLocked

路径:frameworks\base\services\core\java\com\android\server\WiredAccessoryManager.java

Android耳机插拔检测(framework篇)原理解析

判断headphone是否带mic。

AUdioManager.java->AudioManager::setWiredDeviceConnectionState()

路径:frameworks/base/media/java/android/media/AudioManager.java

Android耳机插拔检测(framework篇)原理解析

(涉及到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()

编程

Android耳机插拔检测(framework篇)原理解析

该函数主要分为三步:

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

Android耳机插拔检测(framework篇)原理解析

如果设备已经连接了

通过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/AandroidudioPolicyManager.cpp

Android耳机插拔检测(framework篇)原理解析

先看这个**broadcastDeviceConnectionState(dev, state);**通过调用setParameters()通知所有的hardware module,有新的设备正在处理中:

Android耳机插拔检测(framework篇)原理解析

class AudioPolicyClientInterface:

路径:frameworks/av/services/audiopolicy/AudioPolicyInterface.h

Android耳机插拔检测(framework篇)原理解析

AudioPolicyClientInterface实现在AudioPolicyClientImpl.cpp中,调用到AudioPolicyService中:

AudioPolicyService.cpp->AudioPolicyService:: SET_PARAMETERS

路径:frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp

Android耳机插拔检测(framework篇)原理解析

AudioFlinger.cpp->AudioFlinger::setParameters()

路径:frameworks/av/services/audioflinger/AudioFlinger.cpp

Android耳机插拔检测(framework篇)原理解析

DeviceHalHidl.cpp->DeviceHalHidl::setParameters()

路径:frameworks/av/media/libaudiohal/impl/DeviceHalHidl.cpp

Android耳机插拔检测(framework篇)原理解析

Device.cpp->Device::halSetParameters()

路径:hardware/interfaces/audio/core/all-versions/default/Device.cpp

Android耳机插拔检测(framework篇)原理解析

audio_hw.c->audio_hal::adev_set_parameters()

Android耳机插拔检测(framework篇)原理解析

b) sendDeviceConnectionIntent()

发送intent去通知音频外设的状态变化。

路径:frameworks/base/services/core/java/com/android/server/audio/AudioDeviceInventory.java

Android耳机插拔检测(framework篇)原理解析

c)updateAudioRoutes()

更新音频路径

路径:frameworks/base/services/core/java/com/android/server/audio/AudioDeviceInventory.java

根据不同的device设置connType并和前一次的mainType进行比较是否需要更新route

Android耳机插拔检测(framework篇)原理解析

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

Android耳机插拔检测(framework篇)原理解析

MediaRouter.java->dispatchAudioRoutesChanged()

Android耳机插拔检测(framework篇)原理解析

其中的mIsBluetoothA2dpOn = mAudioService.isBluetoothA2dpOn()获取当前BT设备的状态,会调用到AudioDeviceBroker.java->isBluetoothA2dpOn()

Android耳机插拔检测(framework篇)原理解析

MediaRouter.java->updateAdphpuioRoutes()

判断路由信息是否发生了改变。

Android耳机插拔检测(framework篇)原理解析

到此这篇关于Android耳机插拔检测(framework篇)原理解析的文章就介绍到这了,更多相关Android耳机插拔检测内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新开发

开发排行榜