零.写在最前
第一次尝试阅读android输入系统的代码,免不了理解错误,如有错误,欢迎指正。
一.提出问题
android是基于linux kernel的,linux的事件获取需要读/dev/input下的设备文件节点。对android系统而言,是谁在读这些设备文件节点?读到以后又是怎么把它发送给view的?
二.猜测与验证
事件是一种看不到的东西,在android下,看不见的东西一般交给service来处理,系统service在系统启动的时候注册。android的输入事件的管理,应该是在系统启动的时候,注册成为系统的服务的。系统服务的注册在framworks/base/services/java/com/android/server/SystemServer.java中,使用addService来注册,在这个文件中搜索Input,很容易就发现有个InputManagerService类,从类名上看应该是输入事件管理服务类的意思,和我猜测的差不多。进去这个类看看:
- /*
- * Wraps the C++ InputManager and provides its callbacks.
- */
- public class InputManagerService extends IInputManager.Stub
- implements Watchdog.Monitor {
/*
* Wraps the C++ InputManager and provides its callbacks.
*/
public class InputManagerService extends IInputManager.Stub
implements Watchdog.Monitor {
看一个类先看它的注释,注释中说:包装C++的inputManager 并且提供它的回调。再看这个类是继承于
IInputManager.Stub的,就大概知道它实现来远程系统调用的接口,其实所有的服务类都会继承于
IInputManager.Stub,因为stub继承自binder类,而binder是android用于进程间通信的。stub类的声明如下:
- /** Local-side IPC implementation stub class. */
- public static abstract class Stub extends android.os.Binder implements android.hardware.input.IInputManager
- {
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements android.hardware.input.IInputManager
{
回过头来,既然输入系统以服务的形式进行管理,那先看看把InputManagerService注册位服务的代码,就在SystemServer.java中往下索
InputManagerService,就会发现:
- Slog.i(TAG, "Input Manager");
- inputManager = new InputManagerService(context);
- Slog.i(TAG, "Window Manager");
- wm = WindowManagerService.main(context, inputManager,
- mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
- !mFirstBoot, mOnlyCore);
- ServiceManager.addService(Context.WINDOW_SERVICE, wm);
- ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
- mActivityManagerService.setWindowManager(wm);
- inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
- inputManager.start();
Slog.i(TAG, "Input Manager");
inputManager = new InputManagerService(context);
Slog.i(TAG, "Window Manager");
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
mActivityManagerService.setWindowManager(wm);
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
这里首先创建了一个InputManagerService的实例,然后把它传给了一个main函数,这里是个疑问,不知道是干什么的,暂时不管,然后就是重点了,可以看到调用了
ServiceManager的addService方法注册一个service.这里注册的当然是InputManagerService。注册后,给inputManager设置了一些回调函数,然后,就调用了start函数。
那当然显示从InputManagerSercie的构造函数入手了,毕竟构造函数最先杯调用。start方法暂时放置,这个方法应该很重要,从名字可以猜测它是启动事件输入框架的。
三.InputManagerService的构造函数
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
- <span style="font-family: Arial, Helvetica, sans-serif;"> public InputManagerService(Context context) {</span>
<span style="font-family: Arial, Helvetica, sans-serif;"> public InputManagerService(Context context) {</span>
- 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());
- LocalServices.addService(InputManagerInternal.class, new LocalService());
- }
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());
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
它只有一个构造函数,看起来也不是很难。首先创建了一个Handler,其次去读mUseDevInputEventForAudioJack变量的值,这个值应该实在某个地方配置好的,暂且
不管它,然后就注册了一个handler,那看下这个handler是做什么的:
- </pre><pre code_snippet_id="1720818" snippet_file_name="blog_20160618_11_1111284" name="code" class="java"> public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_DELIVER_INPUT_DEVICES_CHANGED:
- deliverInputDevicesChanged((InputDevice[])msg.obj);
- break;
- case MSG_SWITCH_KEYBOARD_LAYOUT:
- handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
- break;
- case MSG_RELOAD_KEYBOARD_LAYOUTS:
- reloadKeyboardLayouts();
- break;
- case MSG_UPDATE_KEYBOARD_LAYOUTS:
- updateKeyboardLayouts();
- break;
- case MSG_RELOAD_DEVICE_ALIASES:
- reloadDeviceAliases();
- break;
- }
</pre><pre code_snippet_id="1720818" snippet_file_name="blog_20160618_11_1111284" name="code" class="java"> public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DELIVER_INPUT_DEVICES_CHANGED:
deliverInputDevicesChanged((InputDevice[])msg.obj);
break;
case MSG_SWITCH_KEYBOARD_LAYOUT:
handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
break;
case MSG_RELOAD_KEYBOARD_LAYOUTS:
reloadKeyboardLayouts();
break;
case MSG_UPDATE_KEYBOARD_LAYOUTS:
updateKeyboardLayouts();
break;
case MSG_RELOAD_DEVICE_ALIASES:
reloadDeviceAliases();
break;
}
具体看不懂,表面上看好像是处理输入时间变动之类的东西,暂且不管,先看它的nativeInit方法,这份方法应该比较重要吧,要不然下一如看什么地方呀?先做好思想准备,nativeInit这个函数应该比较重要,可是这个方法在哪里呢?应该在一个向InputManagerService中注册方法的本地.cpp文件中,在android的framwork下搜索:
find -name *InputManagerService* 发现
base/services/core/jni/com_android_server_input_InputManagerService.cpp
进去搜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 == NULL) {
- jniThrowRuntimeException(env, "MessageQueue is not initialized.");
- return 0;
- }
- NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
- messageQueue->getLooper());
- im->incStrong(0);
- return reinterpret_cast<jlong>(im);
- }
static jlong 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<jlong>(im);
}
这里面创建了一个 NativeInputManager类的实例,并且调用了它的incStrong方法。NativeInputManager应该是InputManager的C++部分,Android系统的代码是很规范的,从名字可以猜出个一二。那先看看 NativeInputManager的构造函数吧。
三.NativeInputManager的构造函数与incStrong方法。
NativeInputManager同样定义在base/services/core/jni/com_android_server_input_InputManagerService.cpp中。
- NativeInputManager::NativeInputManager(jobject contextObj,
- jobject serviceObj, const sp<Looper>& looper) :
- mLooper(looper), mInteractive(true) {
- 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);
- }
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
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);
}
它的构造函数有个代码块,大概是做一些初始化的工作,然后创建了两个看着很重要的东西,eventHub和mInputManager,可以看到eventHub作为参数传给了
InputManager的构造函数,所以,这里着重看一下InputManager的构造函数。
四.InputManager的构造函数
- 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::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
这里又创建了
InputReader,
InputDispatcher两个类的实例,然后调用
initialize();用来初始化。代码到这里就越来越复杂了,头绪也越来越多,但是不能忘记我们的目标,也就是我们搞懂一开始提出的两个疑问,我们先想想第一个问题:“是谁在读/dev/input/下的文件节点?”,说到读,那这的InputReader是不是就是读的呢?从名字上 来看好像是的。所以,这里,我们还是要牢牢的抓住主干,先搞明白是谁在读/dev/input/下的文件节点,然后再思考其他的部分。那么,这里暂时对InputDisPatcher和initialize置之不理,着重看下InputReader到底做了什么?
五.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) {
- mQueuedListener = new QueuedInputListener(listener);
- { // acquire lock
- AutoMutex _l(mLock);
- refreshConfigurationLocked(0);
- updateGlobalMetaStateLocked();
- } // release lock
- }
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) {
mQueuedListener = new QueuedInputListener(listener);
{ // acquire lock
AutoMutex _l(mLock);
refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
} // release lock
}
这里面就调用了两个函数,首先看第一个函数:
refreshConfigurationLocked(
0
);
- void InputReader::refreshConfigurationLocked(uint32_t changes) {
- mPolicy->getReaderConfiguration(&mConfig);
- mEventHub->setExcludedDevices(mConfig.excludedDeviceNames);
- if (changes) {
- ALOGI("Reconfiguring input devices. changes=0x%08x", changes);
- nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) {
- mEventHub->requestReopenDevices();
- } else {
- for (size_t i = 0; i < mDevices.size(); i++) {
- InputDevice* device = mDevices.valueAt(i);
- device->configure(now, &mConfig, changes);
- }
- }
- }
- }
void InputReader::refreshConfigurationLocked(uint32_t changes) {
mPolicy->getReaderConfiguration(&mConfig);
mEventHub->setExcludedDevices(mConfig.excludedDeviceNames);
if (changes) {
ALOGI("Reconfiguring input devices. changes=0x%08x", changes);
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) {
mEventHub->requestReopenDevices();
} else {
for (size_t i = 0; i < mDevices.size(); i++) {
InputDevice* device = mDevices.valueAt(i);
device->configure(now, &mConfig, changes);
}
}
}
}
这个函数也是看的一脸懵逼,可以看到出现了InputDevice 这个类,从名字上看这不就是输入设备吗?然后调用了这个类的configure函数,这不就是配置一些参数吗?看来好像没错,这个类就是对/dev/input/下设备文件类进行读写的类。再看第二个函数:
- void InputReader::updateGlobalMetaStateLocked() {
- mGlobalMetaState = 0;
- for (size_t i = 0; i < mDevices.size(); i++) {
- InputDevice* device = mDevices.valueAt(i);
- mGlobalMetaState |= device->getMetaState();
- }
- }
void InputReader::updateGlobalMetaStateLocked() {
mGlobalMetaState = 0;
for (size_t i = 0; i < mDevices.size(); i++) {
InputDevice* device = mDevices.valueAt(i);
mGlobalMetaState |= device->getMetaState();
}
}
可以看到也是操作这个InputDevice。这个类到底是何方圣神,它到底是不是代表/dev/input/那些设备文件节点?
六.InputDevice
InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation, int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) : mContext(context), mId(id), mGeneration(generation), mControllerNumber(controllerNumber), mIdentifier(identifier), mClasses(classes), mSources(0), mIsExternal(false), mDropUntilNextSync(false) { }InputDevice的构造函数是空的,那看看它有什么方法:
1.int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc)--获得状态?
2.boolInputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags) --支持的按键码?
3void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) --获得设备的信息?
4. bool isKeyPressed(int32_t code) {
return getEventHub()->getScanCodeState(mId, code) == AKEY_STATE_DOWN;
} --判断按键是否按下吧?
。。。
可以看到它确实与/dev/input/下的设备文件节点密切相关。但并没有直接操作,而是借助getEventHub返回的EventHubInterface进行操作的。
七.EventHubInterface和EventHub
EventHubInterface是个虚函数,它的实现类是EventHub.
那我们想一下,要怎么读/dev/input/设备文件节点,怎么读呢?一般是多路复用吧?select,poll,epoll等,那我们在EventHub中搜搜看。
搜索的结果是select没找到,poll没出现,但是出现了epoll.搜索epoll_ctl等试试:
- if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
- mEpollFd = epoll_create(EPOLL_SIZE_HINT);
- int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
重要的三个函数都出现了,所以这里应该就是对/dev/input读写的地方了。if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) { mEpollFd = epoll_create(EPOLL_SIZE_HINT); int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
具体的代码就不继续分析了,确实看的很累,这里是不是就找到了第一个问题的答案了呢?别忘了第一个问题:“是谁在读这些设备文件节点?”。
是的,就是这个EventHub类。
仔细回想一下,现在只是根据猜测加阅读,找到了读写/dev/input/设备文件节点的位置。可以想象一下,如果是自己写这部分代码,应该要一直监听这些输入设备吧,
应该有一个线程,一直循环监听这些输入设备,有事件的时候就去处理,没有事件的时候就睡眠,等待事件的到来。那么,这部分的代码是怎么样的呢?这次的分析知识找到了
一开始猜想的第一个答案,第二个答案还没有找到。要找到第二个答案,就需要更加细致的分析前面的流程,找到更多的内容,尤其要找到一个循环监听输入设备的线程的地方,
我相信它肯定存在,至于它是在什么地方创建,怎么调用的,下一节继续分析。