Input子系统架构包括内核层与框架层详解.docx
《Input子系统架构包括内核层与框架层详解.docx》由会员分享,可在线阅读,更多相关《Input子系统架构包括内核层与框架层详解.docx(56页珍藏版)》请在冰豆网上搜索。
Input子系统架构包括内核层与框架层详解
AndroidInput子系统架构
Input服务的启动
在Android的开机过程中,系统中的服务很多都是由SystemServer中启动的。
SystemServer的代码中有这么一句话。
Framework/base/services/java/com/android/server/SystemServer.java
Slog.i(TAG,"WindowManager");
wm=WindowManagerService.main(context,power,
factoryTest!
=SystemServer.FACTORY_TEST_LOW_LEVEL,!
firstBoot);
在这里new了一个WindowManagerService的类,我们找到这个类的构造函数。
Framework/base/services/java/com/android/server/wm/WindowManagerServer.java
privateWindowManagerService(Contextcontext,PowerManagerServicepm,
booleanhaveInputMethods,booleanshowBootMsgs){
……
mInputManager=newInputManager(context,this);
……
mInputManager.start();
……
}
在WindowManagerService的构造函数中又new了一个InputManager类。
InputManager类是整个android的input的上层代码最重要的类,就是通过这个类繁衍出了整个复杂的Android的input子系统。
作用就好像Zygote的孕育着Android的各个服务,而InputManager就是负责将整个android的Input子系统。
Framework/base/services/java/com/android/server/wm/WindowManagerServer.java
publicInputManager(Contextcontext,WindowManagerServicewindowManagerService){
……
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++代码。
Framework/base/services/jni/com_android_server_InputManager.java
staticvoidandroid_server_InputManager_nativeInit(JNIEnv*env,jclassclazz,
jobjectcontextObj,jobjectcallbacksObj,jobjectmessageQueueObj){
……
gNativeInputManager=newNativeInputManager(contextObj,callbacksObj,looper);
……
}
在JNI的代码中,又构造了一个重要的NativeInputManager类,这是个C++的本地类。
已经不在是之前了那个java的InputManager类。
接下来看看NativeInputManager的构造函数。
Framework/base/services/jni/com_android_server_InputManager.java
NativeInputManager:
:
NativeInputManager(jobjectcontextObj,
jobjectcallbacksObj,constsp&looper):
mLooper(looper){
……
speventHub=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&reader,
constsp&dispatcher):
mReader(reader),
mDispatcher(dispatcher){
initialize();
}
voidInputManager:
:
initialize(){
mReaderThread=newInputReaderThread(mReader);
mDispatcherThread=newInputDispatcherThread(mDispatcher);
}
在InputManager中的initialize的初始化了两个线程。
一个是inputReaderThread,负责从EventHub中读取事件,另外一个是InputDispatcherThread线程,主要负责分发读取的事件去处理。
Framework/base/services/java/com/android/server/wm/WindowManagerServer.java
privateWindowManagerService(Contextcontext,PowerManagerServicepm,
booleanhaveInputMethods,booleanshowBootMsgs)
mInputManager.start();
……
}
在开始的时候,new了一个InputManager,然后在继续调用其start方法。
Framework/base/services/java/com/android/server/wm/WindowManagerServer.java
publicvoidstart(){
Slog.i(TAG,"Startinginputmanager");
nativeStart();
registerPointerSpeedSettingObserver();
registerShowTouchesSettingObserver();
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
}
NativeStart()跑到JNI的代码中去了,跟上面的方式一样。
Framework/base/services/jni/com_android_server_InputManager.java
staticJNINativeMethodgInputManagerMethods[]={
……
{"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的实现。
Framework/base/services/input/InputManager.cpp
status_tInputManager:
:
start(){
status_tresult=mDispatcherThread->run("InputDispatcher",PRIORITY_URGENT_DISPLAY);
……
result=mReaderThread->run("InputReader",PRIORITY_URGENT_DISPLAY);
……
}
这个方法就是在前面InputManager中的构造函数initialize中的两个线程运行起来。
先看Input
Dispatcher线程运行的情况,然后就是InputReader线程。
Framework/base/services/input/InputDispatcher.cpp
boolInputDispatcherThread:
:
threadLoop(){
mDispatcher->dispatchOnce();
returntrue;
}
InputDispatcher线程调用了Dispatcher的dispatchOnce的方法。
同样的InputReader线程也会调用Reader的ReaderOnce的方法。
Framework/base/services/input/InputDispatcher.cpp
voidInputDispatcher:
:
dispatchOnce(){
……
dispatchOnceInnerLocked(&nextWakeupTime);
……
inttimeoutMillis=toMillisecondTimeoutDelay(currentTime,nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
}
dispatchOnceInnerLocked是处理input输入消息,mLooper->pollOnce(timeoutMillis)是等待下次输入消息的事件。
先看下消息在dispatchOnceInnerLocked函数中是如何处理的。
Framework/base/services/input/InputDispatcher.cpp
voidInputDispatcher:
:
dispatchOnceInnerLocked(nsecs_t*nextWakeupTime){
……
caseEventEntry:
:
TYPE_KEY
……
done=dispatchKeyLocked(currentTime,typedEntry,&dropReason,nextWakeupTime);
caseEventEntry:
:
TYPE_MOTION:
{
……
done=dispatchMotionLocked(currentTime,typedEntry,&dropReason,nextWakeupTime);
……
}
这个函数比较长,input事件在android的上层通过两个队列来保存,分别是InboundQueue和outboundQueue。
当有input事件产生时候,会判断InboundQueue是否为空,如果事件不为空的话,就从队列中取出这个input事件,然后根据input事件的类型来分发事件给不同的处理函数,比较常见的是KEY和Motion事件。
不管是Key事件也好还是Motion事件都会调用dispatchEventToCurrentInputTargetsLocked(currentTime,entry,false);这个函数来继续处理。
Framework/base/services/input/InputDispatcher.cpp
voidInputDispatcher:
:
dispatchEventToCurrentInputTargetsLocked(nsecs_tcurrentTime,
EventEntry*eventEntry,boolresumeWithAppendedMotionSample){
……
prepareDispatchCycleLocked(currentTime,connection,eventEntry,&inputTarget,
resumeWithAppendedMotionSample);
……
}
在这个函数中会继续调用prepareDispatchCycleLocked方法来继续处理。
而在prepareDispatch
CycleLocked中又会继续调用startDispatchCycleLocked(currentTime,connection)来进一步处理。
Framework/base/services/input/InputDispatcher.cpp
voidInputDispatcher:
:
startDispatchCycleLocked(nsecs_tcurrentTime,
constsp&connection){
……
switch(eventEntry->type){
caseEventEntry:
:
TYPE_KEY:
{
status=connection->inputPublisher.publishKeyEvent
caseEventEntry:
:
TYPE_MOTION:
{
……
status=connection->inputPublisher.publishMotionEvent
……
status=connection->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;
mSharedMessage->type=type;
mSharedMessage->deviceId=deviceId;
mSharedMessage->source=source;
……
}
利用publisher中的publishInputEvent将inputevent写入共享内存。
这边产生了事件,另外一边必然会有个地方回去消费这个事件。
注意到上面的代码中,最后发送了一个sendDispatchS
ignal。
Framework/base/libs/ui/InputTransport.cpp
status_tInputPublisher:
:
sendDispatchSignal(){
……
returnmChannel->sendSignal(INPUT_SIGNAL_DISPATCH);
……
}
这个函数直接调用了inputChannel的sendSignal方法。
继续找到inputChannel的sendSignal实现。
Framework/base/libs/ui/InputTransport.cpp
status_tInputChannel:
:
sendSignal(charsignal){
……
do{
nWrite=:
:
write(mSendPipeFd,&signal,1);
}while(nWrite==-1&&errno==EINTR);
……
}
而在注册InputChannel的时候就曾经注册了当Looper接收到了信号的一个回调函数。
Framework/base/services/input/InputDispatcher.cpp
status_tInputDispatcher:
:
registerInputChannel(constsp&inputChannel,
constsp&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){
……
status=connection->inputConsumer.consume(&connection->inputEventFactory,&inputEvent);
……
}
回过头来看之前的InputReader线程,在inputManager的start方法被调用了,Input的线程也就开始运行了。
Framework/base/services/input/InputReader.cpp
boolInputReaderThread:
:
threadLoop(){
mReader->loopOnce();
returntrue;
}
在InputReader的loopOnce中会调用EventHub的getevents方法。
这个方法会和linux内核的input子系统打交道。
Framework/base/services/input/InputReader.cpp
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的思想,如果要去操作这个设备,首先还是要打开这个设备节点的。
Framework/base/services/input/EventHub.cpp
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
方法。
Framework/base/services/input/EventHub.cpp
status_tEventHub:
:
openDeviceLocked(constchar*devicePath){
……
intfd=open(devicePath,O_RDWR);
……
Inpu