读书笔记备忘:通过分析查看Android Framework源码,搞清输入信息在系统中的流向。
主要通过2大部分来介绍Android输入信息的管理过程。第一部分:Android输入管理1:输入信息分发。第二部分:Android输入管理2:应用进程处理Input消息过程
本文为第一部分:Android输入管理1:输入信息分发。主要介绍输入相关的服务,相关类的初始化,输入信息的接收,输入信息的处理以及输入信息的分发过程。
相关类的简介
输入管理涉及到的类非常多。 下面介绍部分主要类的功能。
InputManagerService:输入管理服务,java类,主要输入管理的入口,初始化输入相关的类,以及启动服务。有很多native方法,会通过jni把很多输入处理转入到native层处理。对于的jni文件为com_android_server_input_InputManagerService.cpp
InputManager:native类,管理InputDispatcher,InputReader,InputDispatcherThread,InputReaderThread。
InputReaderThread:循环处理读取信息的线程,将处理过程转到InputReader类中。
InputReader:处理读取的输入信息Event。并把最终丢给InputDispatcher类分发数据。
InputDispatcherThread:用于处理事件分发的线程,最终将处理转到InputDispatcher类中。
InputDispatcher:信息分发类,InputDispatcherThread创建时,其作为参数传入。将信息处理后通过InputChannel发送出去。
EventHub: 将设备加入epoll监听中,并在epoll_wait上等待输入事件的到来,并获取输入信息。在 InputReader创建时,作为参数传入InputReader对象中。
InputManagerService的创建和启动
InputManagerService类,输入管理的入口。它的构造方法如下
//InputManagerService 的构造函数
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
mUseDevInputEventForAudioJack =
context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
+ mUseDevInputEventForAudioJack);
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
String doubleTouchGestureEnablePath = context.getResources().getString(
R.string.config_doubleTouchGestureEnableFile);
mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
new File(doubleTouchGestureEnablePath);
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
在构造方法中,根据DisplayThread线程的looper创建InputManagerHandler对象用于消息处理,然后通过mHandler.getLooper().getQueue()获取DisplayThread线程的消息队列,作为参数传给nativeInit方法。调用nativeInit方法完成初始化。nativeInit 为navtive方法。
DisplayThread类是单例类。DisplayThread线程只用于WindowManager,DisplayManager,InputManager中,提供实时快速运行系统。 以下是本地方法nativeInit代码:
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == nullptr) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jlong>(im);
}
nativeInit方法主要创建NativeInputManager对象。在NativeInputManager创建了1个InputManager对象。
//NativeInputManager 的构造函数
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
mServiceObj = env->NewGlobalRef(serviceObj);
{
AutoMutex _l(mLock);
mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
mLocked.pointerCapture = false;
mLocked.pointerDisplayId = ADISPLAY_ID_DEFAULT;
}
mInteractive = true;
mInputManager = new InputManager(this, this);
defaultServiceManager()->addService(String16("inputflinger"),
mInputManager, false);
}
NativeInputManager 的构造函数中创建了InputManager类,同时调用defaultServiceManager()的addService方法,将InputManager注册到系统服务中。 InputManager的构造函数如下:
InputManager::InputManager(
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mClassifier = new InputClassifier(mDispatcher);
mReader = createInputReader(readerPolicy, mClassifier);
initialize();
}
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
// InputReaderFactory 的createInputReader
sp<InputReaderInterface> createInputReader(
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) {
return new InputReader(new EventHub(), policy, listener);
}
而在InputManager中有创建了InputDispatcher,InputClassifier和InputReader。同时调用initialize方法创建了2个线程对象InputReaderThread和InputDispatcherThread。 其中InputReader 的创建是调用InputReaderFactory的createInputReader 方法,并在这个方法中创建了EventHub对象。 当InputManagerService等相关对象创建和初始化结束后,SystemService中会调用InputManagerService的start方法启动服务。
//InputManagerService的start方法:
public void start() {
Slog.i(TAG, "Starting input manager");
nativeStart(mPtr);
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
registerPointerSpeedSettingObserver();
registerShowTouchesSettingObserver();
registerAccessibilityLargePointerSettingObserver();
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
updateAccessibilityLargePointerFromSettings();
}
}, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
updateAccessibilityLargePointerFromSettings();
}
start方法调用本地函数nativeStart
//本地方法nativeStart
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
status_t result = im->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
//InputManager 的start方法
status_t InputManager::start() {
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
if (result) {
ALOGE("Could not start InputDispatcher thread due to error %d.", result);
return result;
}
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
if (result) {
ALOGE("Could not start InputReader thread due to error %d.", result);
mDispatcherThread->requestExit();
return result;
}
return OK;
}
本地方法nativeStart通过NativeInputManager获取InputManager对象引用,并调用InputManager的start方法。在InputManager的start方法中,启动了在初始化阶段创建的2个线程InputReaderThread和InputDispatcherThread,即调用他们的run方法。 以上即是InputManagerService服务的创建和启动过程。启动完成后,等待获取输入信息的到来,处理和分发消息。 消息是如何获取和分发的?看看下面一节
消息的获取
首先需要介绍一个重要的类EventHub。这个类的作用就是把所有这些设备产生的消息统一成一种格式,再发往上层进行处理。
EventHub::EventHub(void) :
mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
mOpeningDevices(nullptr), mClosingDevices(nullptr),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false), mNeedToScanDevices(true),
mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
//创建——个epoll句柄
mEpollFd = epoll_create1(EPOLL_CLOEXEC);
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
//创建一个inotify对象
mINotifyFd = inotify_init();
//监视/dev/input目录的变化
mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s",
DEVICE_PATH, strerror(errno));
if (isV4lScanningEnabled()) {
mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
VIDEO_DEVICE_PATH, strerror(errno));
} else {
mVideoWd = -1;
ALOGI("Video device scanning disabled");
}
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.fd = mINotifyFd;
//把inotify的句柄加入到epoll的监测中
int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno);
int wakeFds[2];
//创建匿名管道
result = pipe(wakeFds);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
// 将管道读端设成非阻塞模式
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
errno);
// 将管道写端设成非阻塞模式
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
errno);
eventItem.data.fd = mWakeReadPipeFd;
// 将管道的读端加入到epoll的监测中
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
errno);
int major, minor;
getLinuxRelease(&major, &minor);
// EPOLLWAKEUP was introduced in kernel 3.5
mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);
}
在EventHub 构造函数中做了哪些工作? 1.创建——个epoll句柄。epoll是Linux内核为处理大批量文件描述符而做了改进的poll,是Linux下多路复用IO接口select/poll的增强版本 2.创建一个inotify对象。inotify是一个Linux特性,它监控文件系统操作,比如读取、写入和创建。 3.调用inotify_add_watch监视/dev/input目录的变化。并将句柄加入到epoll的监测中。 4.创建匿名管道,将读端管道加入到epoll的监测中。
EventHub的创建在上面的代码中已经说明。即在创建InputReader对象时,作为第一个参数new EventHub 并传入到InputReader对象中。 EventHub构造函数中,并没有和具体的输入设备关联。在EventHub中有个getEvents方法,在这个方法中读取/dev/input中对应的设备,最终调用registerFdForEpoll方法,将设备加入到epoll的监测中。 那消息读取在什么地方?我来看一下InputReaderThread线程
// --- InputReaderThread ---
InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
Thread(/*canCallJava*/ true), mReader(reader) {
}
InputReaderThread::~InputReaderThread() {
}
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
上面InputManagerService启动时,start方法里面调用了InputReaderThread和InputDispatcherThread的run方法。最终导致其threadLoop被调用。threadLoop返回true,表示其会被循环调用。当返回false表示会退出循环。 mReader即是创建InputReaderThread时传入的InputReader对象。所以这里调用的是InputReader的loopOnce方法。
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
std::vector<InputDeviceInfo> inputDevices;
{ // acquire lock
AutoMutex _l(mLock);
oldGeneration = mGeneration;
timeoutMillis = -1;
uint32_t changes = mConfigurationChangesToRefresh;
if (changes) {
mConfigurationChangesToRefresh = 0;
timeoutMillis = 0;
refreshConfigurationLocked(changes);
} else if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
}
} // release lock
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
processEventsLocked(mEventBuffer, count);
}
if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (now >= mNextTimeout) {
#if DEBUG_RAW_EVENTS
ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
mNextTimeout = LLONG_MAX;
timeoutExpiredLocked(now);
}
}
if (oldGeneration != mGeneration) {
inputDevicesChanged = true;
getInputDevicesLocked(inputDevices);
}
} // release lock
// Send out a message that the describes the changed input devices.
if (inputDevicesChanged) {
mPolicy->notifyInputDevicesChanged(inputDevices);
}
// Flush queued events out to the listener.
// This must happen outside of the lock because the listener could potentially call
// back into the InputReader's methods, such as getScanCodeState, or become blocked
// on another thread similarly waiting to acquire the InputReader lock thereby
// resulting in a deadlock. This situation is actually quite plausible because the
// listener is actually the input dispatcher, which calls into the window manager,
// which occasionally calls into the input reader.
mQueuedListener->flush();
}
在loopOnce方法中调用了mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE)方法。上面介绍过,在getEvents方法中获取了/dev/input目录下对应的设备并且将其加入到epoll监听。完成这些动作后,会等待输入事件。看一下下面的主要处理代码:
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
ALOG_ASSERT(bufferSize >= 1);
AutoMutex _l(mLock);
struct input_event readBuffer[bufferSize];
RawEvent* event = buffer;
size_t capacity = bufferSize;
bool awoken = false;
for (;;) {
...
// Grab the next input event.
bool deviceChanged = false;
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
...
// This must be an input event
if (eventItem.events & EPOLLIN) {
int32_t readSize = read(device->fd, readBuffer,
sizeof(struct input_event) * capacity);
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
// Device was removed before INotify noticed.
ALOGW("could not get event, removed? (fd: %d size: %" PRId32
" bufferSize: %zu capacity: %zu errno: %d)\n",
device->fd, readSize, bufferSize, capacity, errno);
deviceChanged = true;
closeDeviceLocked(device);
} else if (readSize < 0) {
if (errno != EAGAIN && errno != EINTR) {
ALOGW("could not get event (errno=%d)", errno);
}
} else if ((readSize % sizeof(struct input_event)) != 0) {
ALOGE("could not get event (wrong size: %d)", readSize);
} else {
int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
size_t count = size_t(readSize) / sizeof(struct input_event);
for (size_t i = 0; i < count; i++) {
struct input_event& iev = readBuffer[i];
event->when = processEventTimestamp(iev);
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;
}
if (capacity == 0) {
// The result buffer is full. Reset the pending event index
// so we will try to read the device again on the next iteration.
mPendingEventIndex -= 1;
break;
}
}
} else if (eventItem.events & EPOLLHUP) {
ALOGI("Removing device %s due to epoll hang-up event.",
device->identifier.name.c_str());
deviceChanged = true;
closeDeviceLocked(device);
} else {
ALOGW("Received unexpected epoll event 0x%08x for device %s.",
eventItem.events, device->identifier.name.c_str());
}
}
// readNotify() will modify the list of devices so this must be done after
// processing all other events to ensure that we read all remaining events
// before closing the devices.
if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
mPendingINotify = false;
readNotifyLocked();
deviceChanged = true;
}
// Report added or removed devices immediately.
if (deviceChanged) {
continue;
}
// Return now if we have collected any events or if we were explicitly awoken.
if (event != buffer || awoken) {
break;
}
// Poll for events. Mind the wake lock dance!
// We hold a wake lock at all times except during epoll_wait(). This works due to some
// subtle choreography. When a device driver has pending (unread) events, it acquires
// a kernel wake lock. However, once the last pending event has been read, the device
// driver will release the kernel wake lock. To prevent the system from going to sleep
// when this happens, the EventHub holds onto its own user wake lock while the client
// is processing events. Thus the system can only sleep if there are no events
// pending or currently being processed.
//
// The timeout is advisory only. If the device is asleep, it will not wake just to
// service the timeout.
mPendingEventIndex = 0;
mLock.unlock(); // release lock before poll, must be before release_wake_lock
release_wake_lock(WAKE_LOCK_ID);
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock
if (pollResult == 0) {
// Timed out.
mPendingEventCount = 0;
break;
}
if (pollResult < 0) {
// An error occurred.
mPendingEventCount = 0;
// Sleep after errors to avoid locking up the system.
// Hopefully the error is transient.
if (errno != EINTR) {
ALOGW("poll failed (errno=%d)\n", errno);
usleep(100000);
}
} else {
// Some events occurred.
mPendingEventCount = size_t(pollResult);
}
}
// All done, return the number of events we read.
return event - buffer;
}
从上面的代码可以看到调用了epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);方法,代码会在这里等待输入事件。而且线程大部分时间都是在epoll_wait上等待。当有输入数据之后,唤醒线程,pollResult大于0,代码进入下个for循环。当有数据时for循环中的while (mPendingEventIndex < mPendingEventCount) 循环开始执行。其中int32_t readSize = read(device->fd, readBuffer, sizeof(struct input_event) * capacity); 读取数据到readBuffer中。之后将数据转换成RawEvent对象,该对象在EventHub的getEvents方法的第2个参数中传入。信息读取结束后,退出while 循环,然后判断event != buffer 退出for循环,这时getEvents函数返回。从getEvents方法返回到loopOnce后,代码继续往下执行。当返回的count大于0,则执行processEventsLocked(mEventBuffer, count);方法来处理获取到的RawEvent对象。 消息获取结束后,就需要处理它们了。 下面我们看看消息的处理分发
消息的处理
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
for (const RawEvent* rawEvent = rawEvents; count;) {
int32_t type = rawEvent->type;
size_t batchSize = 1;
if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
int32_t deviceId = rawEvent->deviceId;
while (batchSize < count) {
if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
|| rawEvent[batchSize].deviceId != deviceId) {
break;
}
batchSize += 1;
}
#if DEBUG_RAW_EVENTS
ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endif
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::DEVICE_REMOVED:
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::FINISHED_DEVICE_SCAN:
handleConfigurationChangedLocked(rawEvent->when);
break;
default:
ALOG_ASSERT(false); // can't happen
break;
}
}
count -= batchSize;
rawEvent += batchSize;
}
}
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
if (deviceIndex < 0) {
ALOGW("Discarding event for unknown deviceId %d.", deviceId);
return;
}
InputDevice* device = mDevices.valueAt(deviceIndex);
if (device->isIgnored()) {
//ALOGD("Discarding event for ignored deviceId %d.", deviceId);
return;
}
device->process(rawEvents, count);
}
processEventsLocked处理RawEvent分为2类。 1.设备发生变化的Event,包含添加,移除设备和扫描设备结束3种情况。对添加,移除设备Event处理,只需增加和删除mDevices列表中Device对象即可。扫描设备结束Event还需要调用handleConfigurationChangedLocked处理设备的配置文件。 2.设备自身产生的Event,如键盘的按键Event。从RawEvent数组中取出连续的同类Event,通过processEventsForDeviceLocked函数一起处理。processEventsForDeviceLocked根据deviceId得到InputDevice对象,然后调用它的process()函数
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
// Process all of the events in order for each mapper.
// We cannot simply ask each mapper to process them in bulk because mappers may
// have side-effects that must be interleaved. For example, joystick movement events and
// gamepad button presses are handled by different mappers but they should be dispatched
// in the order received.
for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
#if DEBUG_RAW_EVENTS
ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64,
rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
rawEvent->when);
#endif
if (mDropUntilNextSync) {
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
mDropUntilNextSync = false;
#if DEBUG_RAW_EVENTS
ALOGD("Recovered from input event buffer overrun.");
#endif
} else {
#if DEBUG_RAW_EVENTS
ALOGD("Dropped input event while waiting for next input sync.");
#endif
}
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
ALOGI("Detected input event buffer overrun for device %s.", getName().c_str());
mDropUntilNextSync = true;
reset(rawEvent->when);
} else {
for (InputMapper* mapper : mMappers) {
mapper->process(rawEvent);
}
}
--count;
}
}
InputDevice::process 函数中又调用了InputDevice中保存的所有InputMapper对象的process函数来处理RawEvent。InputMapper对象是在创建InputDevice时,根据Device类的device->classes值创建的。 InputMapper具体类型如:KeyboardInputMapper,CursorInputMapper,SingleTouchInputMapper,JoystickInputMapper等。 以KeyboardInputMapper为例:
void KeyboardInputMapper::process(const RawEvent* rawEvent) {
switch (rawEvent->type) {
case EV_KEY: {
int32_t scanCode = rawEvent->code;
int32_t usageCode = mCurrentHidUsage;
mCurrentHidUsage = 0;
if (isKeyboardOrGamepadKey(scanCode)) {
processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);
}
break;
}
case EV_MSC: {
if (rawEvent->code == MSC_SCAN) {
mCurrentHidUsage = rawEvent->value;
}
break;
}
case EV_SYN: {
if (rawEvent->code == SYN_REPORT) {
mCurrentHidUsage = 0;
}
}
}
}
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
int32_t usageCode) {
...
NotifyKeyArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
getDisplayId(), policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
getListener()->notifyKey(&args);
}
如果是按键消息KeyboardInputMapper::process调用processKey函数处理。processKey()函数的主要工作是把扫描码转换成键盘码,然后调用getListener()函数得到InputListenerInterface的指针,最后调用它的notifyKey()函数。这个InputListenerInterface指针实际指向的是QueuedlnputListener对象,它是在InputReader的构造函数中创建出来的,如下所示:
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) :
mContext(this), mEventHub(eventHub), mPolicy(policy),
mNextSequenceNum(1), mGlobalMetaState(0), mGeneration(1),
mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
mQueuedListener = new QueuedInputListener(listener);
{ // acquire lock
AutoMutex _l(mLock);
refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
} // release lock
}
//QueuedInputListener的notifyKey
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
mArgsQueue.push_back(new NotifyKeyArgs(*args));
}
QueuedInputListener的参数listener是在创建InputReader时传入的,即为InputClassifier。QueuedInputListener.notifyKey()只是把args参数放到了mArgsQueue集合中。 我们再回到InputRead的LoopOnce()函数,看看最后这个函数调用了mQueuedListener->flush()函数:
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++) {
NotifyArgs* args = mArgsQueue[i];
args->notify(mInnerListener);
delete args;
}
mArgsQueue.clear();
}
QueuedInputListener::flush将mArgsQueue中的数据一一取出,并调用每个元素的notify方法,元素的类型是NotifyArgs。NotifyArgs是基类,KeyboardInputMapper中,实际的对象类型是NotifyKeyArgs。notify函数的参数mInnerListener mInnerListener,即为创建QueuedInputListener传入的值的InputClassifier对象。
void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyKey(this);
}
void InputClassifier::notifyKey(const NotifyKeyArgs* args) {
// pass through
mListener->notifyKey(args);
}
在NotifyKeyArgs::notify中直接调用了listener的notifyKey函数,listener即InputClassifier对象。而InputClassifier的notifyKey又调用了mListener->notifyKey函数。mListener即为创建InputClassifier时传入的。在最开始的初始化代码中我们已经看到这个mListener即是InputDispatcher。所以mListener->notifyKey即是InputDispatcher的notifyKey方法:
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("notifyKey - eventTime=%" PRId64
", deviceId=%d, source=0x%x, displayId=%" PRId32 "policyFlags=0x%x, action=0x%x, "
"flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64,
args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
args->action, args->flags, args->keyCode, args->scanCode,
args->metaState, args->downTime);
#endif
if (!validateKeyEvent(args->action)) {
return;
}
uint32_t policyFlags = args->policyFlags;
int32_t flags = args->flags;
int32_t metaState = args->metaState;
// InputDispatcher tracks and generates key repeats on behalf of
// whatever notifies it, so repeatCount should always be set to 0
constexpr int32_t repeatCount = 0;
if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
policyFlags |= POLICY_FLAG_VIRTUAL;
flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
}
if (policyFlags & POLICY_FLAG_FUNCTION) {
metaState |= AMETA_FUNCTION_ON;
}
policyFlags |= POLICY_FLAG_TRUSTED;
int32_t keyCode = args->keyCode;
accelerateMetaShortcuts(args->deviceId, args->action, keyCode, metaState);
KeyEvent event;
event.initialize(args->deviceId, args->source, args->displayId, args->action,
flags, keyCode, args->scanCode, metaState, repeatCount,
args->downTime, args->eventTime);
android::base::Timer t;
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms",
std::to_string(t.duration().count()).c_str());
}
bool needWake;
{ // acquire lock
mLock.lock();
if (shouldSendKeyToInputFilterLocked(args)) {
mLock.unlock();
policyFlags |= POLICY_FLAG_FILTERED;
if (!mPolicy->filterInputEvent(&event, policyFlags)) {
return; // event was consumed by the filter
}
mLock.lock();
}
KeyEntry* newEntry = new KeyEntry(args->sequenceNum, args->eventTime,
args->deviceId, args->source, args->displayId, policyFlags,
args->action, flags, keyCode, args->scanCode,
metaState, repeatCount, args->downTime);
needWake = enqueueInboundEventLocked(newEntry);
mLock.unlock();
} // release lock
if (needWake) {
mLooper->wake();
}
}
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
bool needWake = mInboundQueue.isEmpty();
mInboundQueue.enqueueAtTail(entry);
...
}
在这个方法中,使用参数创建KeyEntry实例,然后传入enqueueInboundEventLocked函数中,在这个函数中将传入的对象加入到mInboundQueue队列里面。消息在这个队列里面等待分发, 最后调用mLooper->wake()唤醒分发线程。消息是如何被分发出去的?看看下面的过程
消息分发
在上面服务初始化部分,我们看到当InputManager::start()不仅启动了InputReaderThread,同时也调用了InputDispatcherThread的run函数,启动了InputDispatcherThread线程,最终InputDispatcherThread的threadLoop被调用,如下:
// --- InputDispatcherThread ---
InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
}
InputDispatcherThread::~InputDispatcherThread() {
}
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}
InputDispatcherThread::threadLoop调用mDispatcher->dispatchOnce(),回到上面服务的初始化过程可以看到mDispatcher即是InputDispatcherThread创建时传入的InputDispatcher对象。InputDispatcher的dispatchOnce代码如下:
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
std::scoped_lock _l(mLock);
mDispatcherIsAlive.notify_all();
// Run a dispatch loop if there are no pending commands.
// The dispatch loop might enqueue commands to run afterwards.
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
}
// Run all pending commands if there are any.
// If any commands were run then force the next poll to wake up immediately.
if (runCommandsLockedInterruptible()) {
nextWakeupTime = LONG_LONG_MIN;
}
} // release lock
// Wait for callback or timeout or wake. (make sure we round up, not down)
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
}
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
...
mPendingEvent = mInboundQueue.dequeueAtHead();
switch (mPendingEvent->type) {
...
case EventEntry::TYPE_KEY: {
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
if (isAppSwitchDue) {
if (isAppSwitchKeyEvent(typedEntry)) {
resetPendingAppSwitchLocked(true);
isAppSwitchDue = false;
} else if (dropReason == DROP_REASON_NOT_DROPPED) {
dropReason = DROP_REASON_APP_SWITCH;
}
}
if (dropReason == DROP_REASON_NOT_DROPPED
&& isStaleEvent(currentTime, typedEntry)) {
dropReason = DROP_REASON_STALE;
}
if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DROP_REASON_BLOCKED;
}
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
...
}
dispatchOnce函数中,如果haveCommandsLocked()返回false 即mCommandQueue队列不为NULL,则调用dispatchOnceInnerLocked()函数分发消息。dispatchOnceInnerLocked()函数先从mInboundQueue.dequeueAtHead()中取出消息,如果类型是EventEntry::TYPE_KEY,则调用dispatchKeyLocked()函数继续处理。 dispatchKeyLocked经过层层调用最终调用到startDispatchCycleLocked函数。
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
...
switch (eventEntry->type) {
case EventEntry::TYPE_KEY: {
KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
// Publish the key event.
status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
keyEntry->deviceId, keyEntry->source, keyEntry->displayId,
dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
keyEntry->keyCode, keyEntry->scanCode,
keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
keyEntry->eventTime);
break;
}
...
}
最终通过connection->inputPublisher.publishKeyEvent将消息分发出去。 connection是什么?先看看在InputManagerService中有个registerInputChannel()方法:
/**
* Registers an input channel so that it can be used as an input event target.
* @param inputChannel The input channel to register.
* @param inputWindowHandle The handle of the input window associated with the
* input channel, or null if none.
*/
public void registerInputChannel(InputChannel inputChannel, IBinder token) {
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null.");
}
if (token == null) {
token = new Binder();
}
inputChannel.setToken(token);
nativeRegisterInputChannel(mPtr, inputChannel, Display.INVALID_DISPLAY);
}
//nativeRegisterInputChannel在native层的代码
static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
jlong ptr, jobject inputChannelObj, jint displayId) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
if (inputChannel == nullptr) {
throwInputChannelNotInitialized(env);
return;
}
status_t status = im->registerInputChannel(env, inputChannel, displayId);
if (status) {
std::string message;
message += StringPrintf("Failed to register input channel. status=%d", status);
jniThrowRuntimeException(env, message.c_str());
return;
}
android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
handleInputChannelDisposed, im);
}
//NativeInputManager的registerInputChannel函数
status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
const sp<InputChannel>& inputChannel, int32_t displayId) {
ATRACE_CALL();
return mInputManager->getDispatcher()->registerInputChannel(
inputChannel, displayId);
}
//InputDispatcher类的registerInputChannel函数
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
int32_t displayId) {
#if DEBUG_REGISTRATION
ALOGD("channel '%s' ~ registerInputChannel - displayId=%" PRId32,
inputChannel->getName().c_str(), displayId);
#endif
{ // acquire lock
std::scoped_lock _l(mLock);
if (getConnectionIndexLocked(inputChannel) >= 0) {
ALOGW("Attempted to register already registered input channel '%s'",
inputChannel->getName().c_str());
return BAD_VALUE;
}
sp<Connection> connection = new Connection(inputChannel, false /*monitor*/);
int fd = inputChannel->getFd();
mConnectionsByFd.add(fd, connection);
mInputChannelsByToken[inputChannel->getToken()] = inputChannel;
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
// Wake the looper because some connections have changed.
mLooper->wake();
return OK;
}
上面的代码可以看到InputManagerService的registerInputChannel方法调用了native层方法nativeRegisterInputChannel函数。 在nativeRegisterInputChannel函数中调用了NativeInputManager的registerInputChannel函数,并将native层的InputChannel对象作为参数出入其中。native层的InputChannel对象,是根据java层的InputChannel生成的。 NativeInputManager的registerInputChannel函数调用mInputManager->getDispatcher()->registerInputChannel(inputChannel, displayId);函数。这个getDispatcher()获取的就是InputDispatcher对象。所以最后调用的是InputDispatcher类的registerInputChannel函数。 在InputDispatcher类的registerInputChannel函数中,创建了Connection对象,并将Connection对象加入到mConnectionsByFd队列中。然后inputChannel的句柄fd加入到Looper对象的epoll检测中。 mConnectionsByFd存在多个Connection,那么前面分发输入的消息使用的connection->inputPublisher.publishKeyEvent是哪个Connection对象? InputDispatcher::dispatchKeyLocked()函数会调用findFocusedWindowTargetsLocked函数得到当前拥有焦点的窗口的inputChannel信息,然后调用getConnectionIndexLocked函数得到mConnectionsByFd中inputChannel关联的Connection对象的index。
ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {
if (inputChannel == nullptr) {
return -1;
}
for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
sp<Connection> connection = mConnectionsByFd.valueAt(i);
if (connection->inputChannel->getToken() == inputChannel->getToken()) {
return i;
}
}
return -1;
}
//
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const std::vector<InputTarget>& inputTargets) {
ATRACE_CALL();
#if DEBUG_DISPATCH_CYCLE
ALOGD("dispatchEventToCurrentInputTargets");
#endif
ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
pokeUserActivityLocked(eventEntry);
for (const InputTarget& inputTarget : inputTargets) {
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
} else {
#if DEBUG_FOCUS
ALOGD("Dropping event delivery to target with channel '%s' because it "
"is no longer registered with the input dispatcher.",
inputTarget.inputChannel->getName().c_str());
#endif
}
}
}
getConnectionIndexLocked函数通过与inputChannel相同的token信息获取对应的Connection对象的inex。InputDispatcher::dispatchEventLocked函数中,获取到connectionIndex后,通过mConnectionsByFd.valueAt(connectionIndex)获取对应的Connection对象,传入prepareDispatchCycleLocked函数。 最终传给startDispatchCycleLocked函数,在这个函数中使用connection->inputPublisher.publishKeyEvent来分发消息。 再来看看inputPublisher.publishKeyEvent函数:
status_t InputPublisher::publishKeyEvent(
uint32_t seq,
int32_t deviceId,
int32_t source,
int32_t displayId,
int32_t action,
int32_t flags,
int32_t keyCode,
int32_t scanCode,
int32_t metaState,
int32_t repeatCount,
nsecs_t downTime,
nsecs_t eventTime) {
if (ATRACE_ENABLED()) {
std::string message = StringPrintf("publishKeyEvent(inputChannel=%s, keyCode=%" PRId32 ")",
mChannel->getName().c_str(), keyCode);
ATRACE_NAME(message.c_str());
}
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, "
"action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
"downTime=%" PRId64 ", eventTime=%" PRId64,
mChannel->getName().c_str(), seq,
deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
downTime, eventTime);
#endif
if (!seq) {
ALOGE("Attempted to publish a key event with sequence number 0.");
return BAD_VALUE;
}
InputMessage msg;
msg.header.type = InputMessage::TYPE_KEY;
msg.body.key.seq = seq;
msg.body.key.deviceId = deviceId;
msg.body.key.source = source;
msg.body.key.displayId = displayId;
msg.body.key.action = action;
msg.body.key.flags = flags;
msg.body.key.keyCode = keyCode;
msg.body.key.scanCode = scanCode;
msg.body.key.metaState = metaState;
msg.body.key.repeatCount = repeatCount;
msg.body.key.downTime = downTime;
msg.body.key.eventTime = eventTime;
return mChannel->sendMessage(&msg);
}
该函数中通过mChannel->sendMessage(&msg);将信息分发出去。mChannel即使创建Connection时传入的InputChannel对象。
总结
这个流程涉及的类较多,过程比较复杂,下面做一些简单的总结
主要过程流程图
初始化调用过程
信息读取和处理过程
信息分发过程
源码路径:
源码基于android 10.0
SystemServer: /frameworks/base/services/java/com/android/server/SystemServer.java
InputManagerService:/frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
NativeInputManager:此类在com_android_server_input_InputManagerService文件中定义
com_android_server_input_InputManagerService.cpp:/frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
InputManager.cpp: /frameworks/native/services/inputflinger/InputManager.cpp
InputReaderFactory.cpp:/frameworks/native/services/inputflinger/InputReaderFactory.cpp
InputReaderThread:此类是在InputReaderBase类中定义。
InputReaderBase:/frameworks/native/services/inputflinger/InputReaderBase.cpp
InputDevice: 此类在InputReader文件中定义
InputReader: /frameworks/native/services/inputflinger/InputReader.cpp
KeyboardInputMapper:此类在InputReader中定义
QueuedInputListener:此类在InputListener文件中定义
NotifyKeyArgs: 此类在InputListener中定义
InputListener:/frameworks/native/services/inputflinger/InputListener.cpp
Connection: 此类在InputDispatcher中定义
InputDispatcherThread: 此类在InputDispatcher中定义
InputDispatcher:/frameworks/native/services/inputflinger/InputDispatcher.cpp
InputPublisher: 此类在InputTransport中定义
InputTransport:/frameworks/native/libs/input/InputTransport.cpp
本文如有错误,欢迎留言指正。