上层的对按键事件的侦听和纷发处理是通过inputmanager及其组件inputreader,inputdispatch,eventhub构成的。
在system_server被创建的时候就会创建WMS,并调用inputmanager的start方法来启动read和dispatch线程。
1. Inputmanager的创建
Systemserver的ServerThread的run函数中,会调用WMS的main方法来创建WMS
Slog.i(TAG, "WindowManager");
wm = WindowManagerService.main(context,power,
factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
再来看windowmanagerservice的main方法:
public static WindowManagerServicemain(Context context,
PowerManagerService pm, booleanhaveInputMethods) {
WMThread thr = new WMThread(context, pm, haveInputMethods);
thr.start();
synchronized (thr) {
while (thr.mService == null) {
try {
thr.wait();
} catch (InterruptedExceptione) {
}
}
}
return thr.mService;
}此方法很简单,就是创建了WMThread,然后调用了他的start方法。
继续看WMThread:它的构造函数很简单,就是给几个变量赋值,重点看看它的run函数:
public void run() {
Looper.prepare();
WindowManagerService s = new WindowManagerService(mContext, mPM,
mHaveInputMethods);
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_DISPLAY);
android.os.Process.setCanSelfBackground(false);
synchronized (this) {
mService = s;
notifyAll();
}
Looper.loop();
}
此方法创建了WMS的实例,继续跟进:
private WindowManagerService(Contextcontext, PowerManagerService pm,
boolean haveInputMethods) {
//……..省略无关代码
mInputManager = newInputManager(context, this);
//……
}
看看inputmanager的构造函数:inputmanager.java中
public InputManager(Context context,WindowManagerService windowManagerService) {
this.mContext = context;
this.mWindowManagerService =windowManagerService;
this.mCallbacks = new Callbacks();
init();
}
就是给几个变量赋值,调用了init :
private void init() {
Slog.i(TAG, "Initializing inputmanager");
nativeInit(mCallbacks);
}
调用nativeInit ,此方法对应了com_android_server_inputmanager.java中的
android_server_InputManager_nativeInit(sourceinsight搜一下即可,就是inputmanger对应的JNI的部分。)
staticvoid android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz,
jobject callbacks) {
if (gNativeInputManager == NULL) {
gNativeInputManager = new NativeInputManager(callbacks);
} else {
LOGE("Input manager alreadyinitialized.");
jniThrowRuntimeException(env,"Input manager already initialized.");
}
}此方法也是直接调用了NativeInputManager的构造函数:
NativeInputManager::NativeInputManager(jobjectcallbacksObj) :
mFilterTouchEvents(-1),mFilterJumpyTouchEvents(-1), mVirtualKeyQuietTime(-1),
mMaxEventsPerSecond(-1),
mDisplayWidth(-1), mDisplayHeight(-1),mDisplayOrientation(ROTATION_0) {
JNIEnv* env = jniEnv();
mCallbacksObj =env->NewGlobalRef(callbacksObj);
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub,this, this);
}此方法中做了两件很重要的事情,创建了EventHub并将其作为入参传入了InputManager,此处的inputmanager是native的,即是inputmanager.cpp中的。
Inputmanager.cpp
InputManager::InputManager(
const sp<EventHubInterface>&eventHub,
const sp<InputReaderPolicyInterface>&readerPolicy,
constsp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}创建了inputdispatcher和inputreader,并调用了initialize函数创建了InputReaderThread和InputDispatcherThread。
到这里,相关的组件就创建完毕了,那么这些进程是怎么跑取来的呢?
2. 关键线程的启动:
我们还是回到WMS的构造函数中:
private WindowManagerService(Contextcontext, PowerManagerService pm,
boolean haveInputMethods) {
//。。。。。。省略
mInputManager = new InputManager(context, this);
PolicyThread thr = newPolicyThread(mPolicy, this, context, pm);
thr.start();
synchronized (thr) {
while (!thr.mRunning) {
try {
thr.wait();
} catch (InterruptedExceptione) {
}
}
}
mInputManager.start();
}
创建完毕后,就会调用inputmanager的start函数,过程和creat相当的类似,都是用过JNI的调用到native的线程启动,下面依然一级一级的跟,首先是inputmanager的start:
public void start() {
Slog.i(TAG, "Starting inputmanager");
nativeStart();
}
直接调用了nativeStart,对应的是com_android_server_inputmanager.java中的
android_server_InputManager_nativeStart
staticvoid android_server_InputManager_nativeStart(JNIEnv* env, jclass clazz) {
if (checkInputManagerUnitialized(env)) {
return;
}
status_tresult = gNativeInputManager->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env,"Input manager could not be started.");
}
}
gNativeInputManager即是上面在创建的时候,通过NativeInputManager的构造函数获取的,而getInputManager的声明为:
inline sp<InputManager> getInputManager() const { returnmInputManager; }
直接返回mInputManager,而mInputManager也是在NativeInputManager的构造函数调用的。所以,实际调用的应该是native的inputmanager的start函数:
Inputmanager.cpp
status_tInputManager::start() {
status_t result = mDispatcherThread->run("InputDispatcher",PRIORITY_URGENT_DISPLAY);
if (result) {
LOGE("Could not startInputDispatcher thread due to error %d.", result);
return result;
}
result = mReaderThread->run("InputReader",PRIORITY_URGENT_DISPLAY);
if (result) {
LOGE("Could not start InputReaderthread due to error %d.", result);
mDispatcherThread->requestExit();
return result;
}
return OK;
}
到这里,这两个线程就跑起来了,mDispatcherThread负责按键事件的纷发。mReaderThread负责按键事件的获取,接下来用power键的处理作为一个例子,来过下按键事件的简单流程。
3. 按键捕获:
mReaderThread->run后会走到他的threadLoop函数:
boolInputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
调用了inputreader的looponce函数:
voidInputReader::loopOnce() {
RawEvent rawEvent;
mEventHub->getEvent(& rawEvent);
#ifDEBUG_RAW_EVENTS
LOGD("Input event: device=0x%xtype=0x%x scancode=%d keycode=%d value=%d",
rawEvent.deviceId, rawEvent.type,rawEvent.scanCode, rawEvent.keyCode,
rawEvent.value);
#endif
process(& rawEvent);
}
首先是从eventhub中获取事件,再将其传入process中,eventhub的工作机理还没搞清楚,将在下一篇中分析。
根据返回的rawevent中的类型,会做不同的处理:
voidInputReader::process(const RawEvent* rawEvent) {
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
addDevice(rawEvent->deviceId);
break;
case EventHubInterface::DEVICE_REMOVED:
removeDevice(rawEvent->deviceId);
break;
caseEventHubInterface::FINISHED_DEVICE_SCAN:
handleConfigurationChanged(rawEvent->when);
break;
default:
consumeEvent(rawEvent);
break;
}
}
如果是power键,会走到consumeEvent
voidInputReader::consumeEvent(const RawEvent* rawEvent) {
int32_t deviceId = rawEvent->deviceId;
{ // acquire device registry reader lock
RWLock::AutoRLock_rl(mDeviceRegistryLock);
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
if (deviceIndex < 0) {
LOGW("Discarding event forunknown deviceId %d.", deviceId);
return;
}
InputDevice* device =mDevices.valueAt(deviceIndex);
if (device->isIgnored()) {
//LOGD("Discarding event forignored deviceId %d.", deviceId);
return;
}
device->process(rawEvent);
} // release device registry reader lock
}通过刚刚传入的diviceid找到对应的deviceindex,而这些device的创建和销毁正是上步中的ADD/REMOVEdevice 。
最后调用device的process
voidInputDevice::process(const RawEvent* rawEvent) {
size_t numMappers = mMappers.size();
for (size_t i = 0; i < numMappers; i++){
InputMapper* mapper = mMappers[i];
mapper->process(rawEvent);
}
}调用在creatdevice时添加的mapper的process,我们这里是power键,所以应该是KeyboardInputMapper(详见creatdevice函数)
voidKeyboardInputMapper::process(const RawEvent* rawEvent) {
switch (rawEvent->type) {
case EV_KEY: {
int32_t scanCode =rawEvent->scanCode;
if (isKeyboardOrGamepadKey(scanCode)) {
processKey(rawEvent->when,rawEvent->value != 0, rawEvent->keyCode, scanCode,
rawEvent->flags);
}
break;
}
}
}
通过判断scan code,确认是否为键盘或者游戏手柄,如果是则走到processkey:
voidKeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
int32_t scanCode, uint32_t policyFlags) {
int32_t newMetaState;
nsecs_t downTime;
bool metaStateChanged = false;
{ // ……省略此处对按键的处理
getDispatcher()->notifyKey(when,getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
down ? AKEY_EVENT_ACTION_DOWN :AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM,keyCode, scanCode, newMetaState, downTime);
}
此处就会通知dispatch,有按键上报。
voidInputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source,
uint32_t policyFlags, int32_t action,int32_t flags,
int32_t keyCode, int32_t scanCode,int32_t metaState, nsecs_t downTime) {
//,,,,,….
mPolicy->interceptKeyBeforeQueueing(eventTime,deviceId, action, /*byref*/ flags,
keyCode, scanCode, /*byref*/policyFlags);
}
此处的mPolicy就是创建inputdispatch的时候传入的,可以看出,这个mPolicy就是NativeInputManager的this。(NativeInputManager::NativeInputManager创建native的inputmanager的时候传入)
所以,此处的interceptKeyBeforeQueueing实际是NativeInputManager的interceptKeyBeforeQueueing:
而在此函数中会调用WMS的interceptKeyBeforeQueueing,询问其是否会对此按键做特殊处理,实际是在phonewindowmanager中处理的,接下来的流程已经在上一篇中讲过,不再赘述,下一篇中打算将eventhub的流程,尤其是按键扫描的对应搞清楚。