Input子系统架构包括内核层与框架层详解Word格式文档下载.docx
- 文档编号:18613710
- 上传时间:2022-12-29
- 格式:DOCX
- 页数:56
- 大小:87.81KB
Input子系统架构包括内核层与框架层详解Word格式文档下载.docx
《Input子系统架构包括内核层与框架层详解Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《Input子系统架构包括内核层与框架层详解Word格式文档下载.docx(56页珍藏版)》请在冰豆网上搜索。
Looperlooper=windowManagerService.mH.getLooper();
nativeInit(mContext,mCallbacks,looper.getQueue());
在InputManger的构造函数中,调用了nativeInit这个方式,看到native开头或者结尾的函数,一般都是JNI。
在InputManager的JNI可以找到这个函数的实现。
Framework/base/services/jni/com_android_server_InputManager.java
staticJNINativeMethodgInputManagerMethods[]={
{"
nativeInit"
"
(Landroid/content/Context;
"
Lcom/android/server/wm/InputManager$Callbacks;
Landroid/os/MessageQueue;
)V"
(void*)android_server_InputManager_nativeInit},
简单介绍下JNI的代码风格,第一个引号括起来的函数就是我们java代码的函数原型,中间的引号中的就是代表java原型函数的参数。
而最后的那个函数就是在对应的函数。
一般都是c++代码。
staticvoidandroid_server_InputManager_nativeInit(JNIEnv*env,jclassclazz,
jobjectcontextObj,jobjectcallbacksObj,jobjectmessageQueueObj){
gNativeInputManager=newNativeInputManager(contextObj,callbacksObj,looper);
在JNI的代码中,又构造了一个重要的NativeInputManager类,这是个C++的本地类。
已经不在是之前了那个java的InputManager类。
接下来看看NativeInputManager的构造函数。
NativeInputManager:
:
NativeInputManager(jobjectcontextObj,
jobjectcallbacksObj,constsp<
Looper>
&
looper):
mLooper(looper){
sp<
EventHub>
eventHub=newEventHub();
mInputManager=newInputManager(eventHub,this,this);
这里new了两个类,EventHub和InputManager类。
EventHub就是Input子系统的HAL层了,负责将linux的所有的input设备打开并负责轮询读取他们的上报的数据,后面会详细介绍,这里先简单介绍一下。
InputManager类主要是负责管理inputEvent,有InputReader从EventHub读取事件,然后交给InputDispatcher进行分发。
Framework/base/services/input/InputManager.cpp
InputManager:
InputManager(
constsp<
InputReaderInterface>
reader,
InputDispatcherInterface>
dispatcher):
mReader(reader),
mDispatcher(dispatcher){
initialize();
voidInputManager:
initialize(){
mReaderThread=newInputReaderThread(mReader);
mDispatcherThread=newInputDispatcherThread(mDispatcher);
在InputManager中的initialize的初始化了两个线程。
一个是inputReaderThread,负责从EventHub中读取事件,另外一个是InputDispatcherThread线程,主要负责分发读取的事件去处理。
booleanhaveInputMethods,booleanshowBootMsgs)
在开始的时候,new了一个InputManager,然后在继续调用其start方法。
publicvoidstart(){
Slog.i(TAG,"
Startinginputmanager"
nativeStart();
registerPointerSpeedSettingObserver();
registerShowTouchesSettingObserver();
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
}
NativeStart()跑到JNI的代码中去了,跟上面的方式一样。
nativeStart"
()V"
(void*)android_server_InputManager_nativeStart},
staticvoidandroid_server_InputManager_nativeStart(JNIEnv*env,jclassclazz){
status_tresult=gNativeInputManager->
getInputManager()->
start();
在java代码中用了nativeStart(),然后JNI中又调用了NativeInputManager的start方法。
在Native的InputManager中找到start的实现。
status_tInputManager:
start(){
status_tresult=mDispatcherThread->
run("
InputDispatcher"
PRIORITY_URGENT_DISPLAY);
result=mReaderThread->
InputReader"
这个方法就是在前面InputManager中的构造函数initialize中的两个线程运行起来。
先看Input
Dispatcher线程运行的情况,然后就是InputReader线程。
Framework/base/services/input/InputDispatcher.cpp
boolInputDispatcherThread:
threadLoop(){
mDispatcher->
dispatchOnce();
returntrue;
InputDispatcher线程调用了Dispatcher的dispatchOnce的方法。
同样的InputReader线程也会调用Reader的ReaderOnce的方法。
voidInputDispatcher:
dispatchOnce(){
dispatchOnceInnerLocked(&
nextWakeupTime);
inttimeoutMillis=toMillisecondTimeoutDelay(currentTime,nextWakeupTime);
mLooper->
pollOnce(timeoutMillis);
dispatchOnceInnerLocked是处理input输入消息,mLooper->
pollOnce(timeoutMillis)是等待下次输入消息的事件。
先看下消息在dispatchOnceInnerLocked函数中是如何处理的。
dispatchOnceInnerLocked(nsecs_t*nextWakeupTime){
caseEventEntry:
TYPE_KEY
done=dispatchKeyLocked(currentTime,typedEntry,&
dropReason,nextWakeupTime);
TYPE_MOTION:
{
done=dispatchMotionLocked(currentTime,typedEntry,&
这个函数比较长,input事件在android的上层通过两个队列来保存,分别是InboundQueue和outboundQueue。
当有input事件产生时候,会判断InboundQueue是否为空,如果事件不为空的话,就从队列中取出这个input事件,然后根据input事件的类型来分发事件给不同的处理函数,比较常见的是KEY和Motion事件。
不管是Key事件也好还是Motion事件都会调用dispatchEventToCurrentInputTargetsLocked(currentTime,entry,false);
这个函数来继续处理。
dispatchEventToCurrentInputTargetsLocked(nsecs_tcurrentTime,
EventEntry*eventEntry,boolresumeWithAppendedMotionSample){
prepareDispatchCycleLocked(currentTime,connection,eventEntry,&
inputTarget,
resumeWithAppendedMotionSample);
在这个函数中会继续调用prepareDispatchCycleLocked方法来继续处理。
而在prepareDispatch
CycleLocked中又会继续调用startDispatchCycleLocked(currentTime,connection)来进一步处理。
startDispatchCycleLocked(nsecs_tcurrentTime,
Connection>
connection){
switch(eventEntry->
type){
TYPE_KEY:
status=connection->
inputPublisher.publishKeyEvent
inputPublisher.publishMotionEvent
inputPublisher.sendDispatchSignal();
这个函数主要是根据input事件的类型来分发给不同的函数去处理,如果是KEY类型的事件就调用inputPublisher类的publishKeyEvent,如果是MOTION类的事件就会调用inputPublisher类的publishMotionEvent方法。
并在最后发一个sendDispatchSignal。
Framework/base/libs/ui/InputTransport.cpp
status_tInputPublisher:
publishInputEvent(
intashmemFd=mChannel->
getAshmemFd();
intresult=ashmem_pin_region(ashmemFd,0,0);
mSemaphoreInitialized=true;
mSharedMessage->
consumed=false;
type=type;
deviceId=deviceId;
mSharedMessage->
source=source;
利用publisher中的publishInputEvent将inputevent写入共享内存。
这边产生了事件,另外一边必然会有个地方回去消费这个事件。
注意到上面的代码中,最后发送了一个sendDispatchS
ignal。
sendDispatchSignal(){
returnmChannel->
sendSignal(INPUT_SIGNAL_DISPATCH);
这个函数直接调用了inputChannel的sendSignal方法。
继续找到inputChannel的sendSignal实现。
status_tInputChannel:
sendSignal(charsignal){
do{
nWrite=:
write(mSendPipeFd,&
signal,1);
}while(nWrite==-1&
errno==EINTR);
而在注册InputChannel的时候就曾经注册了当Looper接收到了信号的一个回调函数。
status_tInputDispatcher:
registerInputChannel(constsp<
InputChannel>
inputChannel,
InputWindowHandle>
inputWindowHandle,boolmonitor){
mLooper->
addFd(receiveFd,0,ALOOPER_EVENT_INPUT,handleReceiveCallback,this);
在handleReceiveCallback中,作为回调函数然后调用InputConsumer的consume函数来消费从inputReader中读取过来的InputEvent。
Framework/base/core/jni/android_view_InputQueue.cpp
intNativeInputQueue:
handleReceiveCallback(intreceiveFd,intevents,void*data){
inputConsumer.consume(&
connection->
inputEventFactory,&
inputEvent);
回过头来看之前的InputReader线程,在inputManager的start方法被调用了,Input的线程也就开始运行了。
Framework/base/services/input/InputReader.cpp
boolInputReaderThread:
mReader->
loopOnce();
在InputReader的loopOnce中会调用EventHub的getevents方法。
这个方法会和linux内核的input子系统打交道。
voidInputReader:
loopOnce(){
size_tcount=mEventHub->
getEvents(timeoutMillis,mEventBuffer,EVENT_BUFFER_SIZE);
if(count){
processEventsLocked(mEventBuffer,count);
}
这个函数主要通过EventHub的getEvents来获取input事件。
Framework/base/services/input/EventHub.cpp
size_tEventHub:
getEvents(inttimeoutMillis,RawEvent*buffer,size_tbufferSize){
structinput_eventreadBuffer[bufferSize];
for(;
;
){
if(mNeedToScanDevices){
mNeedToScanDevices=false;
scanDevicesLocked();
mNeedToSendFinishedDeviceScan=true;
在eventHub初始化的时候mNeedToScanDevices的值是ture的,所以会直接进入到scanDevices
Locked。
而在内核里面所有的inputdevice在注册的时候都会在linux的文件系统下的/dev/input下面,所以按照一般的HAL的思想,如果要去操作这个设备,首先还是要打开这个设备节点的。
voidEventHub:
scanDevicesLocked(){
status_tres=scanDirLocked(DEVICE_PATH);
if(res<
0){
LOGE("
scandirfailedfor%s\n"
DEVICE_PATH);
status_tEventHub:
scanDirLocked(constchar*dirname)
{
openDeviceLocked(devname);
代码中的while循环会对DEVICE_PATH(/dev/input)下的所有的设备节点调用openDeviceLocked
方法。
openDeviceLocked(constchar*devicePath){
intfd=open(devicePath,O_RDWR);
Inpu
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Input 子系统 架构 包括 内核 框架 详解