InputManagerService的初始化
1.简介
Android系统的输入事件是由InputManagerService服务来监控的,而InputManagerService是由窗口管理服务WindowManagerService来启动的。WindowManagerService服务是在system_server进程中启动关键服务时启动的。
2.初始化流程
InputManagerService也是一个系统服务,在SystemServer中初始化,其初始化流程如下:
2.1 SystemServer.startOtherServices()
private void startOtherServices() {
....
inputManager = new InputManagerService(context);//构造InputManagerService服务,见2.2
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore);//将InputManagerService设置到WindowManagerService中,见2.12
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());// 将InputMonitor对象保存在InputManagerService对象中
inputManager.start();//启动InputManagerService服务,见2.13
....
}
可以看到,在SystemServer的startOtherService方法中,不但构造了InputManagerService服务,而且在启动InputManagerService之前,将其自身注入到WindowMangerService中,进行关联。
2.2 InputManagerService()
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());//初始化Handler,运行在“android.display”线程
.....
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());// 调用本地方法初始化,见2.3
......
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
nativeInit方法在com_android_server_input_InputManagerService.cpp文件中实现
2.3 nativeInit()
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
//获取InputManagerService对应的native消息队列
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
// 构造NativeInputManager,见2.4
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jlong>(im);//返回native指针,保存在InputManagerService的mPtr变量中。
}
android_os_MessageQueue_getMessageQueue方法主要是获取Java层消息队列对应的native消息队列。
sp<MessageQueue> android_os_MessageQueue_getMessageQueue(JNIEnv* env, jobject messageQueueObj) {
jlong ptr = env->GetLongField(messageQueueObj, gMessageQueueClassInfo.mPtr);//获取InputManagerService中mHanlder对应的消息队列
return reinterpret_cast<NativeMessageQueue*>(ptr);
}
2.4 NativeInputManager()
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
mContextObj = env->NewGlobalRef(contextObj);//保存InputManagerService中的Context
mServiceObj = env->NewGlobalRef(serviceObj);// 保存InputManagerService对象
{
AutoMutex _l(mLock);
mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
}
mInteractive = true;
sp<EventHub> eventHub = new EventHub();//构建EventHub,见2.5
mInputManager = new InputManager(eventHub, this, this);//构建InputManager,见2.6
}
在NativeInputManager的构造过程中,会创建一个EventHub实例,并且把这个EventHub作为参数来创建InputManager对象。EventHub类是真正执行监控键盘事件操作的地方。mLooper是指“android.display”线程的Looper。
2.5 EventHub()
EventHub::EventHub(void) :
mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
mOpeningDevices(0), mClosingDevices(0),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false), mNeedToScanDevices(true),
mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);//获取锁
mEpollFd = epoll_create(EPOLL_SIZE_HINT);//创建epoll句柄
mINotifyFd = inotify_init();
// 此处DEVICE_PATH为“/dev/input”,监听该设备路径
int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
// 构建需要监控的epoll事件
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.u32 = EPOLL_ID_INOTIFY;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);// 监控mINotifyFd文件描述符
int wakeFds[2];
result = pipe(wakeFds);//创建管道
mWakeReadPipeFd = wakeFds[0];//管道的读端
mWakeWritePipeFd = wakeFds[1];//管道的写端
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);// 将pipe的读设置为非阻塞模式
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);// 将pipe的写设置为非阻塞模式
eventItem.data.u32 = EPOLL_ID_WAKE;
// 添加管道的读端到epoll实例
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
int major, minor;
getLinuxRelease(&major, &minor);
mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);
}
在构造EventHub时,主要是通过IO多路复用机制epoll来监控输入事件是否已经准备好了。
2.6 InputManager()
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
//构建InputDispatcher对象,见2.7
mDispatcher = new InputDispatcher(dispatcherPolicy);
//构建InputReader对象,见2.8
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();//初始化操作,见2.9
}
这里主要是创建一个InputDispatcher对象和一个InputReader对象,并且分别保存在成员变量mDispatcher和mReader中。InputDispatcher类是负责把输入消息分发给当前激活的Activity窗口的,而InputReader类则是通过EventHub类来实现读取输入事件的。
这里的readerPolicy和dispatcherPolicy都是指向NativeInputManager对象,即InputDispatcher和InputReader的mPolicy成员变量都是指向NativeInputManager对象。
2.7 InputDispatcher()
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
mPolicy(policy),
mPendingEvent(NULL), mLastDropReason(DROP_REASON_NOT_DROPPED),
mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(NULL),
mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
mLooper = new Looper(false);//构建一个属于InputDispatcher的Looper对象
mKeyRepeatState.lastKeyEntry = NULL;
policy->getDispatcherConfiguration(&mConfig);
}
mPolicy变量指向NativeInputManager对象,在构建InputDispatcher时,会创建一个属于自己线程的Looper实例,在Looper会通过epoll监控唤醒事件。
2.8 InputReader()
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) :
mContext(this), mEventHub(eventHub), mPolicy(policy),
mGlobalMetaState(0), mGeneration(1),
mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
// 构建一个QueuedInputListener监听器
mQueuedListener = new QueuedInputListener(listener);
{ // acquire lock
AutoMutex _l(mLock);
refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
} // release lock
}
QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) :
mInnerListener(innerListener) {
}
mPolicy变量指向NativeInputManager对象,mQueueListener数据类型为QueuedInputListener,通过其内部成员变量mInnerListener指向InputDispatcher对象。这个mQueueListener对象便是InputDispatcher跟InputReader交互的中间枢纽。
2.9 InputManager.initialize()
void InputManager::initialize() {
// 构建InputReaderThread线程,见2.10
mReaderThread = new InputReaderThread(mReader);
// 构建InputDispatchThread线程,见2.11
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
在这个函数中,创建了一个InputDispatcherThread线程实例和InputReaderThread线程实例。这里的InputReader实例mReader就是通过这里的InputReaderThread线程实例mReaderThread来读取键盘事件的,而InputDispatcher实例mDispatcher则是通过这里的InputDispatcherThread线程实例mDispatcherThread来分发键盘消息的。
2.10 InputReaderThread()
InputReaderThread线程定义及初始化。
/* Reads raw events from the event hub and processes them, endlessly. */
class InputReaderThread : public Thread {
public:
InputReaderThread(const sp<InputReaderInterface>& reader);
virtual ~InputReaderThread();
private:
sp<InputReaderInterface> mReader;
virtual bool threadLoop();
};
// --- InputReaderThread ---
InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
Thread(/*canCallJava*/ true), mReader(reader) {
}
InputReaderThread::~InputReaderThread() {
}
bool InputReaderThread::threadLoop() {
//调用InputReader的loopOnce方法
mReader->loopOnce();
return true;
}
这里mReader变量指向InputReader对象。
2.11 InputDispatcherThread()
InputDispatcherThread定义及初始化。
/* Enqueues and dispatches input events, endlessly. */
class InputDispatcherThread : public Thread {
public:
explicit InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher);
~InputDispatcherThread();
private:
virtual bool threadLoop();
sp<InputDispatcherInterface> mDispatcher;
};
// --- InputDispatcherThread ---
InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
}
InputDispatcherThread::~InputDispatcherThread() {
}
bool InputDispatcherThread::threadLoop() {
// 调用InputDispatcher的dispatchOnce方法
mDispatcher->dispatchOnce();
return true;
}
这里mDispatcher变量指向InputDispatcher对象。
至此InputManagerService的初始化工作以及完成了,在初始化InputManager类的时候,同时也初始化了InputDispatcher、InputReader以及InputReaderThread和InputDispatcherThread。其中InputReaderThread和InputDispatcherThread是由InputManager管理的两个重要线程,其作用和具体的逻辑均与InputReader和InputDispatcher相关。接着回到2.1中WindowManagerService的初始化工作。
2.12 WindowManagerService.main()
public static WindowManagerService main(final Context context,
final InputManagerService im,
final boolean haveInputMethods, final boolean showBootMsgs,
final boolean onlyCore) {
final WindowManagerService[] holder = new WindowManagerService[1];
DisplayThread.getHandler().runWithScissors(new Runnable() {
@Override
public void run() {
holder[0] = new WindowManagerService(context, im,
haveInputMethods, showBootMsgs, onlyCore);// 构建WindowManagerService
}
}, 0);
return holder[0];
}
private WindowManagerService(Context context, InputManagerService inputManager,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
mContext = context;
.....
mInputManager = inputManager;//关联InputManagerService对象
.....
}
在构建WindowManagerService服务时,会与InputManagerService服务进行关联。在构建完WindowManagerService服务之后,会启动InputManagerService服务中的线程,调用InputManagerService的start方法。
2.13 InputManagerService.start()
public void start() {
//调用本地方法启动InputReaderThread和InputDispatcherThread线程
nativeStart(mPtr);//调用本地方法,见2.14
.....
}
这个函数主要是启动InputDispatcherThread线程和InputReaderThread线程来分别分发和读取输入事件。
2.14 InputManager.nativeStart()
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
//调用InputManager的start方法启动线程
status_t result = im->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
nativeStart方法最终调用是InputManager的start方法,启动InputReaderThread和InputDispatcherThread线程。
status_t InputManager::start() {
// 启动InputDispatcherThread线程,见2.15
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
if (result) {
ALOGE("Could not start InputDispatcher thread due to error %d.", result);
return result;
}
// 启动InputReaderThread线程,见2.17
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;
}
InputDispatcherThread和InputReaderThread线程调用他们的run方法之后,就会进入到他们的threadLoop函数中,只要threadLoop函数返回true,函数threadLoop就会一直被循环调用,于是这两个线程就起到了不断地读取和分发键盘消息的作用。
2.15 InputDispatcherThread.threadLoop()
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce(); 见2.16
return true;
}
mDispatcher变量是前面创建的InputDispatcher对象,调用它的dispatchOnce成员函数进行一次输入消息的分发操作;
2.16 InputDispatcher.dispatchOnce()
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{
AutoMutex _l(mLock);
mDispatcherIsAliveCondition.broadcast();
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);//处理输入消息
}
if (runCommandsLockedInterruptible()) {
nextWakeupTime = LONG_LONG_MIN;
}
}
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);//等待下一次输入消息
}
在该方法中,主要做了两件事情,一个将输入消息交给dispatchOnceInnerLocked函数来处理,另外一个是调用Looper的pollOnce()方法来等待下一次输入消息的到来。
在Looper类中,会创建一个管道,当调用Looper类的pollOnce函数时,如果管道中没有内容可读,那么当前线程就会进入到空闲等待状态;当有输入事件发生时,InputReader就会往这个管道中写入新的内容,这样就会唤醒前面正在等待键盘事件发生的线程。
2.17 InputReaderThread.threadLoop()
bool InputReaderThread::threadLoop() {
mReader->loopOnce(); //见2.18
return true;
}
mReader变量是前面创建的InputReader对象,调用它的loopOnce成员函数执行一次输入事件的读取操作。
2.18 InputReader.loopOnce()
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
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);//1.读取输入事件,可能阻塞
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
processEventsLocked(mEventBuffer, count);//2.处理消息
}
if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (now >= mNextTimeout) {
mNextTimeout = LLONG_MAX;
timeoutExpiredLocked(now);
}
}
if (oldGeneration != mGeneration) {
inputDevicesChanged = true;
getInputDevicesLocked(inputDevices);
}
} // release lock
if (inputDevicesChanged) {
mPolicy->notifyInputDevicesChanged(inputDevices);
}
mQueuedListener->flush();
}
在loopOnce函数中,主要通过mEventHub来负责输入事件的读取工作,该方法是阻塞的方法。如果当前有输入事件发生,或者有输入事件等待处理,则通过mEventHub的getEvent函数就可以得到这个事件。然后交由processEventsLocked函数进行处理,这个函数的主要作用是唤醒前面的InputDispatcherThread线程,通知它有新的输入事件发生了。InputDispatcherThread线程需要进行一次输入消息的分发操作。如果没有输入事件发生或者没有输入事件等待处理,那么调用mEventHub的getEvent函数时就会进入等待状态。
至此InputManagerService的初始化工作完成了。
3.总结
输入系统的主要组成部分有:
- Native层的InputReader,负责从读取出EventHub事件并处理,再交给InputDispatcher处理;
- Native层的InputDispatcher,负责接收来自InputReader的输入事件,并记录处于激活Activity的窗口信息,用于派发事件到合适的窗口;
- Java层的InputManagerService,负责跟WindowManagerService交互,WindowManagerService记录了所有的窗口信息,并同步更新到了InputManagerService中,这样InputDispatcher就可以正确派发事件到ViewRootImpl中。
输入系统的类图如下:
在初始化InputManagerService的过程中,mPtr成员变量记录了Native层的NativeInputManager对象,同时也创建了一些native对象,这些对象分别为:
- NativeInputManager
- EventHub,InputManager
- InputReader,InputDispater
- InputReaderThread,InputDispatcherThread
在初始化InputManagerService的过程中,会启动两个线程:
- InputReader线程:从EventHub读取出事件并处理,然后交给InputDispatcher线程处理;
- InputDispatcher线程:接收来自InputReader的输入事件,并分发事件到合适的窗口;
Java层的InputManagerService和JNI层的NativeInputManager都是采用“android.display”线程处理Message,他们共用一个消息队列MessageQueue。
NativeInputManager中的mLooper对象指向“android.display”线程的Looper对象。InputDispatcher对象的mLooper对象指向它自己线程的Looper对象。
输入事件的一个大致处理流程: Linux kernel ——> InputManagerService(InputReader——>InputDispatcher) ——> WindowManagerService ——> ViewRootImpl。