input服务的启动流程
1. android启动的时候会启动很多个service,参考SystemServer.java,会启动InputManagerService这个服务:
inputManager = new InputManagerService(context, wmHandler);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
2.InputManagerService.java中的start函数:
public void start() {
Slog.i(TAG, "Starting input manager");
nativeStart(mPtr);
//调用了本地方法,JNI对应的cpp 在server下的jni目录下
start函数在jni文件中的实现
}
3. jni NativeStart
frameworks/base/services/jni/com_android_server_input_InputManagerService.cpp中
static jint nativeInit(JNIEnv* env, jclass clazz,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jint>(im);
}
static void nativeStart(JNIEnv* env, jclass clazz, jint ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); //这个NativeInputManager 是在上面InputMangerService构造的时候调用nativeInit时new出来的
status_t result = im->getInputManager()->start(); //这里是调用了NativeInputManager中的InputManager中的start方法,同样这个InputManager是NativeInputManager构造的时候new出来的
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
NativeInputManager构造函数中的会创建EventHub和InputManager
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper) {
JNIEnv* env = jniEnv();
mContextObj = env->NewGlobalRef(contextObj);
mServiceObj = env->NewGlobalRef(serviceObj);
{
AutoMutex _l(mLock);
mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
}
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}
4. InputManager
InputManager(base/services/input/InputManager.cpp ,libinput.so)
InputManager是系统事件处理的核心,主要负责管理工作,EventHub作为参数传入。
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
InputManager创建使用两个线程:
1) InputReaderThread,它负责读取并预处理RawEvent,applies policy并且把消息送入DispatcherThead管理的队列中。
2) InputDispatcherThread,它在队列上等待新的输入事件,并且异步地把这些事件分发给应用程序。
InputReaderThread类与InputDispatcherThread类不共享内部状态,所有的通信都是单向的,从 InputReaderThread到InputDispatcherThread。两个类可以通过InputDispatchPolicy进行交互。
(InputDispatchPolicy就是com_android_server_input_InputManagerService 里的NativeInputManager, 参数会传入this)
“`C
class NativeInputManager : public virtual RefBase,
public virtual InputReaderPolicyInterface,
public virtual InputDispatcherPolicyInterface,
public virtual PointerControllerPolicyInterface
InputManager类从不与Java交互,而InputDispatchPolicy负责执行所有与系统的外部交互,包括调用DVM业务。
InputReaderThread(
mQueueListener->flush()
getListener->notifykey() )
==> 传入到Inputdispatcher.cpp
Inputdispatcher.cpp (mPolicy->interceptKeyBeforeQueueing)
==> com_android_server_input_InputManagerService.cpp (gServiceclassInfo.interceptKeyBeforeQueueing )
==>
InputManagerService.java(mWindowManagerCallbacks.interceptKeyBeforeQueueing )
==.>
InputMonitor.java (mService.mPolicy.interceptKeyBeforeQueueing )
##### 5. InputReader
/frameworks/base/services/input/InputReader.cpp
```C
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
...
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); //这里就是关键了,通过另外一个中间者EventHub 获取的input事件
...
}
<div class="se-preview-section-delimiter"></div>
InputReader从EventHub中读取原始事件数据(RawEvent),并由各个InputMapper处理之后输入对应的inputlistener.
6. EventHub
/frameworks/base/services/input/EventHub.cpp
它是系统中所有事件的中央处理站。它管理所有系统中可以识别的输入设备的输入事件,此外,当设备增加或删除时,EventHub将产生相应的输入事件给系统。
EventHub通过getEvents函数,给系统提供一个输入事件流。它也支持查询输入设备当前的状态(如哪些键当前被按下)。而且EventHub还跟踪每个输入调入的能力,比如输入设备的类别,输入设备支持哪些按键。
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
...
for (;;) {
...
scanDevicesLocked(); //这个往里走就是通过EventHub::openDeviceLocked 打开*DEVICE_PATH = "/dev/input" 这个设备 ,最终用的open,实际到kernel层就是input设备注册的open
...
int32_t readSize = read(device->fd, readBuffer, //这里的device->fd就是/dev/input/event%d这个设备文件,就是从这里读取出event的buffer
sizeof(struct input_event) * capacity);
...
}
..
}
<div class="se-preview-section-delimiter"></div>
7. InputDispatcher分发:
InputDispatcher负责把事件分发给输入目标,其中的一些功能(如识别输入目标)由独立的policy对象控制。
如何得到当前焦点窗口
InputDispatcher==>
InputMonitor==>
WMS IMS的WindowManagerCallbacks==>
InputMonitor==>
InputDispatcher
InputMonitor为WMS提供一些访问InputDispatcher的接口。
比如更新当前焦点窗口updateInputWindowsLw
<div class="se-preview-section-delimiter"></div>
InputDispatcher 如何通知应用程序窗口有按键事件的,这是跨进程的,没有用Binder机制,而是socket.
dispatchEventLocked ==>
prepareDispatchCycleLocked ==>
enqueueDispatchEntriesLocked ==>
connection->inputPublisher.publishKeyEvent ==>
mChannel->sendMessage ==>
::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL); 实际最后调用的socket发出数据了.
8. 其他的一些类
InputEvent 有两个子类KeyEvent MotionEvent
InputEvent 有接口GetDevice ,得到当前事件的硬件源, SOURCE_KEYBOARD SOURCE_MOUSE
SOURCE_GAMEPAD …