InputManagerService之事件的初始化与分发
该篇⽂章接总章,来详细谈论说明InputManagerService 体系,从初始化到事件获取跟分发。咱们在进⾏前,先明确哪⼏个问题需要知道,然后看看在这篇⽂章中是否解决了这些问题。对于InputManagerService,⼤家第⼀个想知道是他起什么作⽤,这个在总章⾥⾯有详细说明,简⽽⾔之就是获得事件跟分发处理事件。那他如何或者跟其他模块配合获取事件?并且把这个事件进⾏分发?如何准确定位对应的处理事件的模块?咱们下⾯开始讨论这些问题,在这个⽂章出来的时候,android 已经到N了 ,也就是7.0。但是由于我的笔记(初稿) 在M的时候已经完成了,也就是去年。所以这篇⽂章还是基于M (6.0)来写。
InputManagerService的初始化:
跟其他模块⼀样,作为系统的核⼼服务初始化在SystemServer。基本系统的核⼼服务都是在这⾥初始化,这个可以研究下系统的启动流程,在启动的最后就是需要启动所有的核⼼服务。
代码路径: frameworks/ba/rvices/java/com/android/rver/SystemServer.java
在run ⽅法⾥⾯,M 是在startOtherService()⾥⾯初始化InputManagerService
上⾯主要是新建IMS(InputManagerService 下⾯都⽤这个替换) 对象, 然后把WindowManagerService的InputMonitor作为参数传给IMS,重点关注下InputMonitor,这个跟事件的分发有关。然后在这⾥调⽤start⽅法启动IMS,这⾥的start 实际是调⽤ native 的start ⽅法。
看下InputManagerServices的start⽅法:
代码路径:frameworks/ba/rvices/core/java/com/android/rver/input/InputManagerService.java
上⾯主要调⽤了com_android_rvice_input_InputManagerService.cpp ⾥⾯的nativeStart⽅法,Java层的start⽅法主要做了两个⼯作:⼀个⼯作就是调⽤nativeStart⽅法。另外⼀个就是point 跟 toucher 相关参数设置跟监听,对应这Input事件的主要两类:Key 跟 toucher。在nativeStart⾥⾯的mPtr对应啥呢?⾸先Java层跟 native层通信调⽤,主要通过JNI。这⾥主要是mPtr指针强制类型转换为NativeInputManager对象,看下源码:情人头像
Java层代码:
代码路径:frameworks/ba/rvices/core/java/com/android/rver/input/InputManagerService.java
// Pointer to native input manager rvice object.
private final long mPtr;
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new ().getLooper());
mUDevInputEventForAudioJack =
Slog.i(TAG, "Initializing input manager, mUDevInputEventForAudioJack="
+ mUDevInputEventForAudioJack);
//这⾥对mPtr 进⾏初始化,调⽤的还是native的⽅法,把这个rvice跟 Systemcontext 传给native对应的⽅法
mPtr = nativeInit(this, mContext, Looper().getQueue());
师范生LocalServices.addService(InputManagerInternal.class, new LocalService());
}
Native层代码:笔记本天梯
代码路径:/frameworks/ba/rvices/core/jni/com_android_rver_input_InputManagerService.cpp
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
jobject rviceObj, jobject contextObj, jobject messageQueueObj) {
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
} //这⾥把JAVA层的 Systemcontext 以及IMS⾃⼰作为参数传过来了
NativeInputManager* im = new NativeInputManager(contextObj, rviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jlong>(im);
}
这个为什么要把IMS 传给NativeInputManager呢?看下NativeInputManager的构造函数
代码路径:frameworks/ba/rvices/core/jni/com_android_rver_input_inputmanagerrvice.cpp
NativeInputManager::NativeInputManager(jobject contextObj,
jobject rviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
mContextObj = env->NewGlobalRef(contextObj);
mServiceObj = env->NewGlobalRef(rviceObj);
{
AutoMutex _l(mLock);
mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = fal;
}
mInteractive = true;
//这个是从底层读取input 信息的提供者
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}
这⾥有⼀个重要的对象就是EventHub,如总章所说这个对象是事件获取的重要的对象。在这⾥也对Native层的InputManager进⾏了初始化。前⾯解决了mPtr 是啥,nativeStart⼜⼲了啥?
InputManagerService的读取跟分发启动:
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.");
}
}
查看下InputManager的start⽅法到底⼲了什么?frameworks/native/rvices/inputFlinger/InputManager.cpp
代码路径:frameworks/native/rvices/inputFlinger/InputManager.cpp
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;
}
政治话题
嘿嘿,这⾥就真正的Input 事件 消息读取分发的⼯作启动了,从上⾯的代码就可以知道这⾥开启了两个线程,这两个线程初始化在InputManager的initialize⽅法⾥⾯。
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
这两个线程主要⼀个是读取事件,⼀个是分发事件。读取事件从哪⾥读呢?从EventHub⾥⾯读,源码说了~
代码路径:frameworks/native/rvices/inputflinger/InputReader.h
/* Reads raw events from the event hub and process them, endlessly. */ 这⾥说明了
class InputReaderThread : public Thread {
public:
InputReaderThread(const sp<InputReaderInterface>& reader);
virtual ~InputReaderThread();
private:
sp<InputReaderInterface> mReader;
virtual bool threadLoop();
};
那这个线程如何读取数据呢?
代码路径:frameworks/native/rvices/inputflinger/InputReader.cpp自卑情结
// --- InputReaderThread ---
InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
Thread(/*canCallJava*/ true), mReader(reader) {
}
InputReaderThread::~InputReaderThread() {
}
bool InputReaderThread::threadLoop() {
//调⽤loopOnce ⽅法
mReader->loopOnce();
return true;
}
InputReader 实际不直接访问设备点,⽽是通过EventHub 来完成这⼀⼯作,EventHub 通过读取/dev/input下的数据。loopOnce如何读取事件了,前⾯已经反复强调读取数据的⼯作主要是EventHub,那loopOnce⾥⾯EventHub就要⼀定要出现了。
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = fal;
Vector<InputDeviceInfo> inputDevices;
//这⾥主要是环境有关的,⽐如时间,⽐如设备的状态等等
{ // acquire lock
AutoMutex _l(mLock);
oldGeneration = mGeneration;
timeoutMillis = -1;
uint32_t changes = mConfigurationChangesToRefresh;
if (changes) {
mConfigurationChangesToRefresh = 0;
timeoutMillis = 0;
//主要刷新环境
refreshConfigurationLocked(changes);
} el if (mNextTimeout != LLONG_MAX) {
ncs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
timeoutMillis = toMillicondTimeoutDelay(now, mNextTimeout);
}
} // relea lock
//获得input 数据
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) {
ncs_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);
}
} // relea 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 becau 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 becau the
// listener is actually the input dispatcher, which calls into the window manager,
// which occasionally calls into the input reader.